1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2010, 2011, 2012 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
25 #include "data/identifier.h"
26 #include "data/settings.h"
27 #include "data/value.h"
28 #include "data/variable.h"
29 #include "libpspp/assertion.h"
30 #include "libpspp/cast.h"
31 #include "libpspp/compiler.h"
32 #include "libpspp/message.h"
33 #include "libpspp/misc.h"
34 #include "libpspp/str.h"
36 #include "gl/c-strcase.h"
37 #include "gl/minmax.h"
38 #include "gl/xalloc.h"
41 #define _(msgid) gettext (msgid)
45 struct fmt_number_style styles[FMT_NUMBER_OF_FORMATS];
48 bool is_fmt_type (enum fmt_type);
50 static bool valid_width (enum fmt_type, int width, enum fmt_use);
52 static int max_digits_for_bytes (int bytes);
53 static void fmt_clamp_width (struct fmt_spec *, enum fmt_use);
54 static void fmt_clamp_decimals (struct fmt_spec *, enum fmt_use);
56 static void fmt_affix_set (struct fmt_affix *, const char *);
57 static void fmt_affix_free (struct fmt_affix *);
59 static void fmt_number_style_init (struct fmt_number_style *);
60 static void fmt_number_style_clone (struct fmt_number_style *,
61 const struct fmt_number_style *);
62 static void fmt_number_style_destroy (struct fmt_number_style *);
64 /* Creates and returns a new struct fmt_settings with default format styles. */
66 fmt_settings_create (void)
68 struct fmt_settings *settings;
71 settings = xzalloc (sizeof *settings);
72 for (t = 0 ; t < FMT_NUMBER_OF_FORMATS ; ++t )
73 fmt_number_style_init (&settings->styles[t]);
74 fmt_settings_set_decimal (settings, '.');
79 /* Destroys SETTINGS. */
81 fmt_settings_destroy (struct fmt_settings *settings)
87 for (t = 0 ; t < FMT_NUMBER_OF_FORMATS ; ++t )
88 fmt_number_style_destroy (&settings->styles[t]);
90 free (settings->styles);
94 /* Returns a copy of SETTINGS. */
96 fmt_settings_clone (const struct fmt_settings *old)
98 struct fmt_settings *new;
101 new = xmalloc (sizeof *new);
102 for (t = 0 ; t < FMT_NUMBER_OF_FORMATS ; ++t )
103 fmt_number_style_clone (&new->styles[t], &old->styles[t]);
108 /* Returns the number formatting style associated with the given
110 const struct fmt_number_style *
111 fmt_settings_get_style (const struct fmt_settings *settings,
114 assert (is_fmt_type (type));
115 return &settings->styles[type];
118 /* Sets the number style for TYPE to have the given DECIMAL and GROUPING
119 characters, negative prefix NEG_PREFIX, prefix PREFIX, suffix SUFFIX, and
120 negative suffix NEG_SUFFIX. All of the strings are UTF-8 encoded. */
122 fmt_settings_set_style (struct fmt_settings *settings, enum fmt_type type,
123 char decimal, char grouping,
124 const char *neg_prefix, const char *prefix,
125 const char *suffix, const char *neg_suffix)
127 struct fmt_number_style *style = &settings->styles[type];
128 int total_bytes, total_width;
130 assert (grouping == '.' || grouping == ',' || grouping == 0);
131 assert (decimal == '.' || decimal == ',');
132 assert (decimal != grouping);
134 fmt_number_style_destroy (style);
136 fmt_affix_set (&style->neg_prefix, neg_prefix);
137 fmt_affix_set (&style->prefix, prefix);
138 fmt_affix_set (&style->suffix, suffix);
139 fmt_affix_set (&style->neg_suffix, neg_suffix);
140 style->decimal = decimal;
141 style->grouping = grouping;
143 total_bytes = (strlen (neg_prefix) + strlen (prefix)
144 + strlen (suffix) + strlen (neg_suffix));
145 total_width = (style->neg_prefix.width + style->prefix.width
146 + style->suffix.width + style->neg_suffix.width);
147 style->extra_bytes = MAX (0, total_bytes - total_width);
150 /* Sets the decimal point character for the settings in S to DECIMAL.
152 This has no effect on custom currency formats. */
154 fmt_settings_set_decimal (struct fmt_settings *s, char decimal)
156 int grouping = decimal == '.' ? ',' : '.';
157 assert (decimal == '.' || decimal == ',');
159 fmt_settings_set_style (s, FMT_F, decimal, 0, "-", "", "", "");
160 fmt_settings_set_style (s, FMT_E, decimal, 0, "-", "", "", "");
161 fmt_settings_set_style (s, FMT_COMMA, decimal, grouping, "-", "", "", "");
162 fmt_settings_set_style (s, FMT_DOT, grouping, decimal, "-", "", "", "");
163 fmt_settings_set_style (s, FMT_DOLLAR, decimal, grouping, "-", "$", "", "");
164 fmt_settings_set_style (s, FMT_PCT, decimal, 0, "-", "", "%", "");
167 /* Returns an input format specification with type TYPE, width W,
170 fmt_for_input (enum fmt_type type, int w, int d)
176 assert (fmt_check_input (&f));
180 /* Returns an output format specification with type TYPE, width
181 W, and D decimals. */
183 fmt_for_output (enum fmt_type type, int w, int d)
189 assert (fmt_check_output (&f));
193 /* Returns the output format specifier corresponding to input
194 format specifier INPUT. */
196 fmt_for_output_from_input (const struct fmt_spec *input)
198 struct fmt_spec output;
200 assert (fmt_check_input (input));
202 output.type = fmt_input_to_output (input->type);
204 if (output.w > fmt_max_output_width (output.type))
205 output.w = fmt_max_output_width (output.type);
206 else if (output.w < fmt_min_output_width (output.type))
207 output.w = fmt_min_output_width (output.type);
224 const struct fmt_number_style *style =
225 settings_get_style (input->type);
227 output.w += fmt_affix_width (style);
228 if (style->grouping != 0 && input->w - input->d >= 3)
229 output.w += (input->w - input->d - 1) / 3;
241 output.d = MAX (input->d, 3);
242 output.w = MAX (input->w, output.d + 7);
246 output.w = max_digits_for_bytes (input->w / 2) + 1;
257 output.w = 2 * input->w + (input->d > 0);
262 output.w = max_digits_for_bytes (input->w) + 1;
278 output.w = input->w / 2;
298 output.w = MAX (input->w, input->d + 6);
303 output.w = MAX (input->w, input->d + 20);
310 if (output.w > fmt_max_output_width (output.type))
311 output.w = fmt_max_output_width (output.type);
313 assert (fmt_check_output (&output));
317 /* Returns the default format for the given WIDTH: F8.2 format
318 for a numeric value, A format for a string value. */
320 fmt_default_for_width (int width)
323 ? fmt_for_output (FMT_F, 8, 2)
324 : fmt_for_output (FMT_A, width, 0));
327 /* Checks whether SPEC is valid for USE and returns nonzero if so.
328 Otherwise, emits an error message and returns zero. */
330 fmt_check (const struct fmt_spec *spec, enum fmt_use use)
333 char str[FMT_STRING_LEN_MAX + 1];
334 int min_w, max_w, max_d;
336 assert (is_fmt_type (spec->type));
337 fmt_to_string (spec, str);
339 io_fmt = use == FMT_FOR_INPUT ? _("Input format") : _("Output format");
340 if (use == FMT_FOR_INPUT && !fmt_usable_for_input (spec->type))
342 msg (SE, _("Format %s may not be used for input."), str);
346 if (spec->w % fmt_step_width (spec->type))
348 assert (fmt_step_width (spec->type) == 2);
349 msg (SE, _("%s specifies width %d, but %s requires an even width."),
350 str, spec->w, fmt_name (spec->type));
354 min_w = fmt_min_width (spec->type, use);
355 max_w = fmt_max_width (spec->type, use);
356 if (spec->w < min_w || spec->w > max_w)
358 msg (SE, _("%s %s specifies width %d, but "
359 "%s requires a width between %d and %d."),
360 io_fmt, str, spec->w, fmt_name (spec->type), min_w, max_w);
364 max_d = fmt_max_decimals (spec->type, spec->w, use);
365 if (!fmt_takes_decimals (spec->type) && spec->d != 0)
367 msg (SE, ngettext ("%s %s specifies %d decimal place, but "
368 "%s does not allow any decimals.",
369 "%s %s specifies %d decimal places, but "
370 "%s does not allow any decimals.",
372 io_fmt, str, spec->d, fmt_name (spec->type));
375 else if (spec->d > max_d)
378 msg (SE, ngettext ("%s %s specifies %d decimal place, but "
379 "the given width allows at most %d decimals.",
380 "%s %s specifies %d decimal places, but "
381 "the given width allows at most %d decimals.",
383 io_fmt, str, spec->d, max_d);
385 msg (SE, ngettext ("%s %s specifies %d decimal place, but "
386 "the given width does not allow for any decimals.",
387 "%s %s specifies %d decimal places, but "
388 "the given width does not allow for any decimals.",
390 io_fmt, str, spec->d);
397 /* Checks whether SPEC is valid as an input format and returns
398 nonzero if so. Otherwise, emits an error message and returns
401 fmt_check_input (const struct fmt_spec *spec)
403 return fmt_check (spec, FMT_FOR_INPUT);
406 /* Checks whether SPEC is valid as an output format and returns
407 true if so. Otherwise, emits an error message and returns false. */
409 fmt_check_output (const struct fmt_spec *spec)
411 return fmt_check (spec, FMT_FOR_OUTPUT);
414 /* Checks that FORMAT is appropriate for a variable of the given
415 VAR_TYPE and returns true if so. Otherwise returns false and
416 emits an error message. */
418 fmt_check_type_compat (const struct fmt_spec *format, enum val_type var_type)
420 assert (val_type_is_valid (var_type));
421 if ((var_type == VAL_STRING) != (fmt_is_string (format->type) != 0))
423 char str[FMT_STRING_LEN_MAX + 1];
424 msg (SE, _("%s variables are not compatible with %s format %s."),
425 var_type == VAL_STRING ? _("String") : _("Numeric"),
426 var_type == VAL_STRING ? _("numeric") : _("string"),
427 fmt_to_string (format, str));
433 /* Checks that FORMAT is appropriate for a variable of the given
434 WIDTH and returns true if so. Otherwise returns false and
435 emits an error message. */
437 fmt_check_width_compat (const struct fmt_spec *format, int width)
439 if (!fmt_check_type_compat (format, val_type_from_width (width)))
441 if (fmt_var_width (format) != width)
443 char str[FMT_STRING_LEN_MAX + 1];
444 msg (SE, _("String variable with width %d is not compatible with "
446 width, fmt_to_string (format, str));
452 /* Returns the width corresponding to FORMAT. The return value
453 is the width of the `union value's required by FORMAT. */
455 fmt_var_width (const struct fmt_spec *format)
457 return (format->type == FMT_AHEX ? format->w / 2
458 : format->type == FMT_A ? format->w
462 /* Converts F to its string representation (for instance, "F8.2")
463 in BUFFER. Returns BUFFER.
465 If F has decimals, they are included in the output string,
466 even if F's format type does not allow decimals, to allow
467 accurately presenting incorrect formats to the user. */
469 fmt_to_string (const struct fmt_spec *f, char buffer[FMT_STRING_LEN_MAX + 1])
471 if (fmt_takes_decimals (f->type) || f->d > 0)
472 snprintf (buffer, FMT_STRING_LEN_MAX + 1,
473 "%s%d.%d", fmt_name (f->type), f->w, f->d);
475 snprintf (buffer, FMT_STRING_LEN_MAX + 1,
476 "%s%d", fmt_name (f->type), f->w);
480 /* Returns true if A and B are identical formats,
483 fmt_equal (const struct fmt_spec *a, const struct fmt_spec *b)
485 return a->type == b->type && a->w == b->w && a->d == b->d;
488 /* Adjusts FMT to be valid for a value of the given WIDTH if necessary.
489 If nothing needed to be changed the return value is false
492 fmt_resize (struct fmt_spec *fmt, int width)
494 if ((width > 0) != fmt_is_string (fmt->type))
496 /* Changed from numeric to string or vice versa. Set to
497 default format for new width. */
498 *fmt = fmt_default_for_width (width);
502 /* Changed width of string. Preserve format type, adjust
504 fmt->w = fmt->type == FMT_AHEX ? width * 2 : width;
514 /* Adjusts FMT's width and decimal places to be valid for USE. */
516 fmt_fix (struct fmt_spec *fmt, enum fmt_use use)
518 /* Clamp width to those allowed by format. */
519 fmt_clamp_width (fmt, use);
521 /* If FMT has more decimal places than allowed, attempt to increase FMT's
522 width until that number of decimal places can be achieved. */
523 if (fmt->d > fmt_max_decimals (fmt->type, fmt->w, use)
524 && fmt_takes_decimals (fmt->type))
526 int max_w = fmt_max_width (fmt->type, use);
527 for (; fmt->w < max_w; fmt->w++)
528 if (fmt->d <= fmt_max_decimals (fmt->type, fmt->w, use))
532 /* Clamp decimals to those allowed by format and width. */
533 fmt_clamp_decimals (fmt, use);
536 /* Adjusts FMT's width and decimal places to be valid for an
539 fmt_fix_input (struct fmt_spec *fmt)
541 fmt_fix (fmt, FMT_FOR_INPUT);
544 /* Adjusts FMT's width and decimal places to be valid for an
547 fmt_fix_output (struct fmt_spec *fmt)
549 fmt_fix (fmt, FMT_FOR_OUTPUT);
552 /* Sets FMT's width to WIDTH (or the nearest width allowed by FMT's type) and
553 reduces its decimal places as necessary (if necessary) for that width. */
555 fmt_change_width (struct fmt_spec *fmt, int width, enum fmt_use use)
558 fmt_clamp_width (fmt, use);
559 fmt_clamp_decimals (fmt, use);
562 /* Sets FMT's decimal places to DECIMALS (or the nearest number of decimal
563 places allowed by FMT's type) and increases its width as necessary (if
564 necessary) for that number of decimal places. */
566 fmt_change_decimals (struct fmt_spec *fmt, int decimals, enum fmt_use use)
572 /* Describes a display format. */
576 int min_input_width, min_output_width;
578 enum fmt_category category;
581 static const struct fmt_desc *get_fmt_desc (enum fmt_type type);
583 /* Returns the name of the given format TYPE. */
585 fmt_name (enum fmt_type type)
587 return get_fmt_desc (type)->name;
590 /* Tries to parse NAME as a format type.
591 If successful, stores the type in *TYPE and returns true.
592 On failure, returns false. */
594 fmt_from_name (const char *name, enum fmt_type *type)
598 for (i = 0; i < FMT_NUMBER_OF_FORMATS; i++)
599 if (!c_strcasecmp (name, get_fmt_desc (i)->name))
607 /* Returns true if TYPE accepts decimal places,
610 fmt_takes_decimals (enum fmt_type type)
612 return fmt_max_output_decimals (type, fmt_max_output_width (type)) > 0;
615 /* Returns the minimum width of the given format TYPE for the given USE. */
617 fmt_min_width (enum fmt_type type, enum fmt_use use)
619 return (use == FMT_FOR_INPUT
620 ? fmt_min_input_width (type)
621 : fmt_min_output_width (type));
624 /* Returns the maximum width of the given format TYPE,
625 for input if FOR_INPUT is true,
626 for output otherwise. */
628 fmt_max_width (enum fmt_type type, enum fmt_use use UNUSED)
630 /* Maximum width is actually invariant of whether the format is
631 for input or output, so FOR_INPUT is unused. */
632 assert (is_fmt_type (type));
650 return 2 * MAX_STRING;
657 /* Returns the maximum number of decimal places allowed for the
658 given format TYPE with a width of WIDTH places, for the given USE. */
660 fmt_max_decimals (enum fmt_type type, int width, enum fmt_use use)
669 max_d = use == FMT_FOR_INPUT ? width : width - 1;
674 max_d = use == FMT_FOR_INPUT ? width : width - 2;
678 max_d = use == FMT_FOR_INPUT ? width : width - 7;
686 assert (use == FMT_FOR_OUTPUT);
696 max_d = width * 2 - 1;
705 max_d = max_digits_for_bytes (width);
766 /* Returns the minimum acceptable width for an input field
767 formatted with the given TYPE. */
769 fmt_min_input_width (enum fmt_type type)
771 return get_fmt_desc (type)->min_input_width;
774 /* Returns the maximum acceptable width for an input field
775 formatted with the given TYPE. */
777 fmt_max_input_width (enum fmt_type type)
779 return fmt_max_width (type, FMT_FOR_INPUT);
782 /* Returns the maximum number of decimal places allowed in an
783 input field of the given TYPE and WIDTH. */
785 fmt_max_input_decimals (enum fmt_type type, int width)
787 assert (valid_width (type, width, true));
788 return fmt_max_decimals (type, width, FMT_FOR_INPUT);
791 /* Returns the minimum acceptable width for an output field
792 formatted with the given TYPE. */
794 fmt_min_output_width (enum fmt_type type)
796 return get_fmt_desc (type)->min_output_width;
799 /* Returns the maximum acceptable width for an output field
800 formatted with the given TYPE. */
802 fmt_max_output_width (enum fmt_type type)
804 return fmt_max_width (type, FMT_FOR_OUTPUT);
807 /* Returns the maximum number of decimal places allowed in an
808 output field of the given TYPE and WIDTH. */
810 fmt_max_output_decimals (enum fmt_type type, int width)
812 assert (valid_width (type, width, false));
813 return fmt_max_decimals (type, width, FMT_FOR_OUTPUT);
816 /* Returns the width step for a field formatted with the given
817 TYPE. Field width must be a multiple of the width step. */
819 fmt_step_width (enum fmt_type type)
821 return (fmt_get_category (type) == FMT_CAT_HEXADECIMAL || type == FMT_AHEX
825 /* Returns true if TYPE is used for string fields,
826 false if it is used for numeric fields. */
828 fmt_is_string (enum fmt_type type)
830 return fmt_get_category (type) == FMT_CAT_STRING;
833 /* Returns true if TYPE is used for numeric fields,
834 false if it is used for string fields. */
836 fmt_is_numeric (enum fmt_type type)
838 return !fmt_is_string (type);
841 /* Returns the format TYPE's category.
842 Each format type is in exactly one category,
843 and each category's value is bitwise disjoint from every other
844 category. Thus, the return value may be tested for equality
845 or compared bitwise against a mask of FMT_CAT_* values. */
847 fmt_get_category (enum fmt_type type)
849 return get_fmt_desc (type)->category;
852 /* Returns the output format selected by default when TYPE is
853 used as an input format. */
855 fmt_input_to_output (enum fmt_type type)
857 switch (fmt_get_category (type))
864 case FMT_CAT_HEXADECIMAL:
872 /* Returns the SPSS format type corresponding to the given PSPP
875 fmt_to_io (enum fmt_type type)
877 return get_fmt_desc (type)->io;
880 /* Determines the PSPP format corresponding to the given SPSS
881 format type. If successful, sets *FMT_TYPE to the PSPP format
882 and returns true. On failure, return false. */
884 fmt_from_io (int io, enum fmt_type *fmt_type)
888 #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) \
890 *fmt_type = FMT_##NAME; \
892 #include "format.def"
898 /* Translate U32, which is in the form found in SAV and SPV files, into a
899 format specification, and stores the new specification in *F.
901 If LOOSE is false, checks that the format specification is appropriate as an
902 output format for a variable with the given WIDTH and reports an error if
903 not. If LOOSE is true, instead adjusts the format's width and decimals as
904 necessary to be suitable.
906 Return true if successful, false if there was an error.. */
908 fmt_from_u32 (uint32_t u32, int width, bool loose, struct fmt_spec *f)
910 uint8_t raw_type = u32 >> 16;
911 uint8_t w = u32 >> 8;
917 bool ok = fmt_from_io (raw_type, &f->type);
923 ok = fmt_check_output (f);
926 ok = fmt_check_width_compat (f, width);
932 /* Returns true if TYPE may be used as an input format,
935 fmt_usable_for_input (enum fmt_type type)
937 assert (is_fmt_type (type));
938 return fmt_get_category (type) != FMT_CAT_CUSTOM;
941 /* For time and date formats, returns a template used for input and output in a
942 field of the given WIDTH.
944 WIDTH only affects whether a 2-digit year or a 4-digit year is used, that
945 is, whether the returned string contains "yy" or "yyyy", and whether seconds
946 are include, that is, whether the returned string contains ":SS". A caller
947 that doesn't care whether the returned string contains "yy" or "yyyy" or
948 ":SS" can just specify 0 to omit them. */
950 fmt_date_template (enum fmt_type type, int width)
997 s1 = "dd-mmm-yyyy HH:MM";
998 s2 = "dd-mmm-yyyy HH:MM:SS";
1002 s1 = "yyyy-mm-dd HH:MM";
1003 s2 = "yyyy-mm-dd HH:MM:SS";
1025 return width >= strlen (s2) ? s2 : s1;
1028 /* Returns a string representing the format TYPE for use in a GUI dialog. */
1030 fmt_gui_name (enum fmt_type type)
1035 return _("Numeric");
1044 return _("Scientific");
1077 return fmt_name (type);
1081 /* Returns true if TYPE is a valid format type,
1084 is_fmt_type (enum fmt_type type)
1086 return type < FMT_NUMBER_OF_FORMATS;
1089 /* Returns true if WIDTH is a valid width for the given format
1090 TYPE, for the given USE. */
1092 valid_width (enum fmt_type type, int width, enum fmt_use use)
1094 return (width >= fmt_min_width (type, use)
1095 && width <= fmt_max_width (type, use));
1098 /* Returns the maximum number of decimal digits in an unsigned
1099 binary number that is BYTES bytes long. */
1101 max_digits_for_bytes (int bytes)
1103 int map[8] = {3, 5, 8, 10, 13, 15, 17, 20};
1104 assert (bytes > 0 && bytes <= sizeof map / sizeof *map);
1105 return map[bytes - 1];
1108 /* Clamp FMT's width to the range and values allowed by FMT's type. */
1110 fmt_clamp_width (struct fmt_spec *fmt, enum fmt_use use)
1115 min_w = fmt_min_width (fmt->type, use);
1116 max_w = fmt_max_width (fmt->type, use);
1119 else if (fmt->w > max_w)
1122 /* Round width to step. */
1123 step = fmt_step_width (fmt->type);
1124 fmt->w = ROUND_DOWN (fmt->w, step);
1127 /* Clamp FMT's decimal places to the range allowed by FMT's type and width. */
1129 fmt_clamp_decimals (struct fmt_spec *fmt, enum fmt_use use)
1133 max_d = fmt_max_decimals (fmt->type, fmt->w, use);
1136 else if (fmt->d > max_d)
1140 /* Sets AFFIX's string value to S, a UTF-8 encoded string. */
1142 fmt_affix_set (struct fmt_affix *affix, const char *s)
1144 affix->s = s[0] == '\0' ? CONST_CAST (char *, "") : xstrdup (s);
1145 affix->width = u8_strwidth (CHAR_CAST (const uint8_t *, s), "UTF-8");
1148 /* Frees data in AFFIX. */
1150 fmt_affix_free (struct fmt_affix *affix)
1157 fmt_number_style_init (struct fmt_number_style *style)
1159 fmt_affix_set (&style->neg_prefix, "");
1160 fmt_affix_set (&style->prefix, "");
1161 fmt_affix_set (&style->suffix, "");
1162 fmt_affix_set (&style->neg_suffix, "");
1163 style->decimal = '.';
1164 style->grouping = 0;
1168 fmt_number_style_clone (struct fmt_number_style *new,
1169 const struct fmt_number_style *old)
1171 fmt_affix_set (&new->neg_prefix, old->neg_prefix.s);
1172 fmt_affix_set (&new->prefix, old->prefix.s);
1173 fmt_affix_set (&new->suffix, old->suffix.s);
1174 fmt_affix_set (&new->neg_suffix, old->neg_suffix.s);
1175 new->decimal = old->decimal;
1176 new->grouping = old->grouping;
1177 new->extra_bytes = old->extra_bytes;
1180 /* Destroys a struct fmt_number_style. */
1182 fmt_number_style_destroy (struct fmt_number_style *style)
1186 fmt_affix_free (&style->neg_prefix);
1187 fmt_affix_free (&style->prefix);
1188 fmt_affix_free (&style->suffix);
1189 fmt_affix_free (&style->neg_suffix);
1193 /* Returns the total width of the standard prefix and suffix for STYLE, in
1194 display columns (e.g. as returned by u8_strwidth()). */
1196 fmt_affix_width (const struct fmt_number_style *style)
1198 return style->prefix.width + style->suffix.width;
1201 /* Returns the total width of the negative prefix and suffix for STYLE, in
1202 display columns (e.g. as returned by u8_strwidth()). */
1204 fmt_neg_affix_width (const struct fmt_number_style *style)
1206 return style->neg_prefix.width + style->neg_suffix.width;
1209 /* Returns the struct fmt_desc for the given format TYPE. */
1210 static const struct fmt_desc *
1211 get_fmt_desc (enum fmt_type type)
1213 static const struct fmt_desc formats[FMT_NUMBER_OF_FORMATS] =
1215 #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) \
1216 {#NAME, IMIN, OMIN, IO, CATEGORY},
1217 #include "format.def"
1220 assert (is_fmt_type (type));
1221 return &formats[type];
1224 const struct fmt_spec F_8_0 = {FMT_F, 8, 0};
1225 const struct fmt_spec F_8_2 = {FMT_F, 8, 2};
1226 const struct fmt_spec F_4_3 = {FMT_F, 4, 3};
1227 const struct fmt_spec F_5_1 = {FMT_F, 5, 1};