X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fformat.c;h=17afda6162b4f3bba021ebdad00660ff2fae25a9;hb=refs%2Fheads%2Fctables17;hp=a4c52b788ebd811541b9e3ac7d0e25beab016d81;hpb=cb08510bbbab7646bc1031427243489024d22a3b;p=pspp diff --git a/src/data/format.c b/src/data/format.c index a4c52b788e..17afda6162 100644 --- a/src/data/format.c +++ b/src/data/format.c @@ -101,26 +101,38 @@ fmt_settings_get_style (const struct fmt_settings *settings, #define OPPOSITE(C) ((C) == ',' ? '.' : ',') #define AFFIX(S) { .s = (char *) (S), .width = sizeof (S) - 1 } -#define NS(PREFIX, SUFFIX, DECIMAL, GROUPING) { \ +#define NS(PREFIX, SUFFIX, DECIMAL, GROUPING, INCLUDE_LEADING_ZERO) { \ .neg_prefix = AFFIX ("-"), \ .prefix = AFFIX (PREFIX), \ .suffix = AFFIX (SUFFIX), \ .neg_suffix = AFFIX (""), \ .decimal = DECIMAL, \ .grouping = GROUPING, \ + .include_leading_zero = INCLUDE_LEADING_ZERO \ } -#define ANS(DECIMAL, GROUPING) { \ - [FMT_F] = NS( "", "", DECIMAL, 0), \ - [FMT_E] = NS( "", "", DECIMAL, 0), \ - [FMT_COMMA] = NS( "", "", DECIMAL, GROUPING), \ - [FMT_DOT] = NS( "", "", GROUPING, DECIMAL), \ - [FMT_DOLLAR] = NS("$", "", DECIMAL, GROUPING), \ - [FMT_PCT] = NS( "", "%", DECIMAL, 0), \ +#define ANS(DECIMAL, GROUPING, INCLUDE_LEADING_ZERO) { \ + [FMT_F] = NS( "", "", DECIMAL, 0, INCLUDE_LEADING_ZERO), \ + [FMT_E] = NS( "", "", DECIMAL, 0, INCLUDE_LEADING_ZERO), \ + [FMT_COMMA] = NS( "", "", DECIMAL, GROUPING, INCLUDE_LEADING_ZERO), \ + [FMT_DOT] = NS( "", "", GROUPING, DECIMAL, INCLUDE_LEADING_ZERO), \ + [FMT_DOLLAR] = NS("$", "", DECIMAL, GROUPING, false), \ + [FMT_PCT] = NS( "", "%", DECIMAL, 0, false), \ } +#define ANS2(DECIMAL, GROUPING) { \ + ANS(DECIMAL, GROUPING, false), \ + ANS(DECIMAL, GROUPING, true), \ + } + + /* First index: 0 for ',' decimal point, 1 for '.' decimal point. + Second index: 0 for no leading zero, 1 for leading zero. + Third index: TYPE. + */ + static const struct fmt_number_style styles[2][2][6] = { + ANS2 (',', '.'), + ANS2 ('.', ','), + }; - static const struct fmt_number_style period_styles[6] = ANS ('.', ','); - static const struct fmt_number_style comma_styles[6] = ANS (',', '.'); - static const struct fmt_number_style default_style = NS ("", "", '.', 0); + static const struct fmt_number_style default_style = NS ("", "", '.', 0, false); switch (type) { @@ -130,9 +142,11 @@ fmt_settings_get_style (const struct fmt_settings *settings, case FMT_DOLLAR: case FMT_PCT: case FMT_E: - return (settings->decimal == '.' - ? &period_styles[type] - : &comma_styles[type]); + { + int decimal_idx = settings->decimal == '.'; + int leadzero_idx = settings->include_leading_zero; + return &styles[decimal_idx][leadzero_idx][type]; + } case FMT_CCA: case FMT_CCB: @@ -184,10 +198,7 @@ fmt_settings_set_cc (struct fmt_settings *settings, enum fmt_type type, struct fmt_spec fmt_for_input (enum fmt_type type, int w, int d) { - struct fmt_spec f; - f.type = type; - f.w = w; - f.d = d; + struct fmt_spec f = { .type = type, .w = w, .d = d }; assert (fmt_check_input (&f)); return f; } @@ -197,10 +208,7 @@ fmt_for_input (enum fmt_type type, int w, int d) struct fmt_spec fmt_for_output (enum fmt_type type, int w, int d) { - struct fmt_spec f; - f.type = type; - f.w = w; - f.d = d; + struct fmt_spec f = { .type = type, .w = w, .d = d }; assert (fmt_check_output (&f)); return f; } @@ -340,74 +348,128 @@ fmt_default_for_width (int width) : fmt_for_output (FMT_A, width, 0)); } -/* Checks whether SPEC is valid for USE and returns nonzero if so. - Otherwise, emits an error message and returns zero. */ -bool -fmt_check (const struct fmt_spec *spec, enum fmt_use use) +/* Checks whether SPEC is valid for USE and returns NULL if so. Otherwise, + returns a malloc()'d string that describes the error. The caller must + eventually free() the string. */ +char * +fmt_check__ (const struct fmt_spec *spec, enum fmt_use use) { - const char *io_fmt; char str[FMT_STRING_LEN_MAX + 1]; int min_w, max_w, max_d; assert (is_fmt_type (spec->type)); fmt_to_string (spec, str); - io_fmt = use == FMT_FOR_INPUT ? _("Input format") : _("Output format"); if (use == FMT_FOR_INPUT && !fmt_usable_for_input (spec->type)) - { - msg (SE, _("Format %s may not be used for input."), str); - return false; - } + return xasprintf (_("Format %s may not be used for input."), str); if (spec->w % fmt_step_width (spec->type)) { assert (fmt_step_width (spec->type) == 2); - msg (SE, _("%s specifies width %d, but %s requires an even width."), - str, spec->w, fmt_name (spec->type)); - return false; + return (use == FMT_FOR_INPUT + ? xasprintf (_("Input format %s specifies width %d, " + "but %s requires an even width."), + str, spec->w, fmt_name (spec->type)) + : xasprintf (_("Output format %s specifies width %d, " + "but %s requires an even width."), + str, spec->w, fmt_name (spec->type))); } min_w = fmt_min_width (spec->type, use); max_w = fmt_max_width (spec->type, use); if (spec->w < min_w || spec->w > max_w) - { - msg (SE, _("%s %s specifies width %d, but " - "%s requires a width between %d and %d."), - io_fmt, str, spec->w, fmt_name (spec->type), min_w, max_w); - return false; - } + return (use == FMT_FOR_INPUT + ? xasprintf (_("Input format %s specifies width %d, but " + "%s requires a width between %d and %d."), + str, spec->w, fmt_name (spec->type), min_w, max_w) + : xasprintf (_("Output format %s specifies width %d, but " + "%s requires a width between %d and %d."), + str, spec->w, fmt_name (spec->type), min_w, max_w)); max_d = fmt_max_decimals (spec->type, spec->w, use); if (!fmt_takes_decimals (spec->type) && spec->d != 0) - { - msg (SE, ngettext ("%s %s specifies %d decimal place, but " - "%s does not allow any decimals.", - "%s %s specifies %d decimal places, but " - "%s does not allow any decimals.", - spec->d), - io_fmt, str, spec->d, fmt_name (spec->type)); - return false; - } + return (use == FMT_FOR_INPUT + ? xasprintf (ngettext ( + "Input format %s specifies %d decimal " + "place, but %s does not allow any decimals.", + "Input format %s specifies %d decimal " + "places, but %s does not allow any " + "decimals.", + spec->d), + str, spec->d, fmt_name (spec->type)) + : xasprintf (ngettext ( + "Output format %s specifies %d decimal " + "place, but %s does not allow any decimals.", + "Output format %s specifies %d decimal places, but " + "%s does not allow any decimals.", + spec->d), + str, spec->d, fmt_name (spec->type))); else if (spec->d > max_d) { if (max_d > 0) - msg (SE, ngettext ("%s %s specifies %d decimal place, but " - "the given width allows at most %d decimals.", - "%s %s specifies %d decimal places, but " - "the given width allows at most %d decimals.", - spec->d), - io_fmt, str, spec->d, max_d); + return (use == FMT_FOR_INPUT + ? xasprintf (ngettext ( + "Input format %s specifies %d decimal place, " + "but the given width allows at most " + "%d decimals.", + "Input format %s specifies %d decimal places, " + "but the given width allows at most " + "%d decimals.", + spec->d), + str, spec->d, max_d) + : xasprintf (ngettext ( + "Output format %s specifies %d decimal place, " + "but the given width allows at most " + "%d decimals.", + "Output format %s specifies %d decimal places, " + "but the given width allows at most " + "%d decimals.", + spec->d), + str, spec->d, max_d)); else - msg (SE, ngettext ("%s %s specifies %d decimal place, but " - "the given width does not allow for any decimals.", - "%s %s specifies %d decimal places, but " - "the given width does not allow for any decimals.", - spec->d), - io_fmt, str, spec->d); + return (use == FMT_FOR_INPUT + ? xasprintf (ngettext ( + "Input format %s specifies %d decimal place, " + "but the given width does not allow " + "for any decimals.", + "Input format %s specifies %d decimal places, " + "but the given width does not allow " + "for any decimals.", + spec->d), + str, spec->d) + : xasprintf (ngettext ( + "Output format %s specifies %d decimal place, " + "but the given width does not allow " + "for any decimals.", + "Output format %s specifies %d decimal places, " + "but the given width does not allow " + "for any decimals.", + spec->d), + str, spec->d)); + } + + return NULL; +} + +static bool +fmt_emit_and_free_error (char *error) +{ + if (error) + { + msg (SE, "%s", error); + free (error); return false; } + else + return true; +} - return true; +/* Checks whether SPEC is valid for USE and returns nonzero if so. Otherwise, + emits an error message for the current source location and returns zero. */ +bool +fmt_check (const struct fmt_spec *spec, enum fmt_use use) +{ + return fmt_emit_and_free_error (fmt_check__ (spec, use)); } /* Checks whether SPEC is valid as an input format and returns @@ -427,23 +489,52 @@ fmt_check_output (const struct fmt_spec *spec) return fmt_check (spec, FMT_FOR_OUTPUT); } +/* Checks that FORMAT is appropriate for a variable of the given VAR_TYPE and + returns NULL if so. Otherwise returns a malloc()'d error message that the + calelr must eventually free(). */ +char * +fmt_check_type_compat__ (const struct fmt_spec *format, enum val_type var_type) +{ + assert (val_type_is_valid (var_type)); + if ((var_type == VAL_STRING) != (fmt_is_string (format->type) != 0)) + { + char str[FMT_STRING_LEN_MAX + 1]; + return xasprintf (_("%s variables are not compatible with %s format %s."), + var_type == VAL_STRING ? _("String") : _("Numeric"), + var_type == VAL_STRING ? _("numeric") : _("string"), + fmt_to_string (format, str)); + } + return NULL; +} + /* Checks that FORMAT is appropriate for a variable of the given VAR_TYPE and returns true if so. Otherwise returns false and emits an error message. */ bool fmt_check_type_compat (const struct fmt_spec *format, enum val_type var_type) { - assert (val_type_is_valid (var_type)); - if ((var_type == VAL_STRING) != (fmt_is_string (format->type) != 0)) + return fmt_emit_and_free_error (fmt_check_type_compat__ (format, var_type)); +} + +/* Checks that FORMAT is appropriate for a variable of the given WIDTH and + returns NULL if so. Otherwise returns a malloc()'d error message that the + calelr must eventually free(). */ +char * +fmt_check_width_compat__ (const struct fmt_spec *format, int width) +{ + char *error = fmt_check_type_compat__ (format, val_type_from_width (width)); + if (error) + return error; + + if (fmt_var_width (format) != width) { char str[FMT_STRING_LEN_MAX + 1]; - msg (SE, _("%s variables are not compatible with %s format %s."), - var_type == VAL_STRING ? _("String") : _("Numeric"), - var_type == VAL_STRING ? _("numeric") : _("string"), - fmt_to_string (format, str)); - return false; + return xasprintf (_("String variable with width %d is not compatible " + "with format %s."), + width, fmt_to_string (format, str)); } - return true; + + return NULL; } /* Checks that FORMAT is appropriate for a variable of the given @@ -452,17 +543,7 @@ fmt_check_type_compat (const struct fmt_spec *format, enum val_type var_type) bool fmt_check_width_compat (const struct fmt_spec *format, int width) { - if (!fmt_check_type_compat (format, val_type_from_width (width))) - return false; - if (fmt_var_width (format) != width) - { - char str[FMT_STRING_LEN_MAX + 1]; - msg (SE, _("String variable with width %d is not compatible with " - "format %s."), - width, fmt_to_string (format, str)); - return false; - } - return true; + return fmt_emit_and_free_error (fmt_check_width_compat__ (format, width)); } /* Returns the width corresponding to FORMAT. The return value @@ -1144,12 +1225,8 @@ fmt_clamp_width (struct fmt_spec *fmt, enum fmt_use use) static void fmt_clamp_decimals (struct fmt_spec *fmt, enum fmt_use use) { - int max_d; - - max_d = fmt_max_decimals (fmt->type, fmt->w, use); - if (fmt->d < 0) - fmt->d = 0; - else if (fmt->d > max_d) + int max_d = fmt_max_decimals (fmt->type, fmt->w, use); + if (fmt->d > max_d) fmt->d = max_d; } @@ -1166,7 +1243,7 @@ fmt_affix_clone (const struct fmt_affix *old) static void fmt_affix_free (struct fmt_affix *affix) { - if (affix->s[0]) + if (affix->s) free (affix->s); } @@ -1235,6 +1312,7 @@ fmt_number_style_from_string (const char *s) .neg_suffix = neg_suffix, .decimal = grouping == '.' ? ',' : '.', .grouping = grouping, + .include_leading_zero = false, .extra_bytes = extra_bytes, }; return style; @@ -1334,7 +1412,7 @@ get_fmt_desc (enum fmt_type type) return &formats[type]; } -const struct fmt_spec F_8_0 = {FMT_F, 8, 0}; -const struct fmt_spec F_8_2 = {FMT_F, 8, 2}; -const struct fmt_spec F_4_3 = {FMT_F, 4, 3}; -const struct fmt_spec F_5_1 = {FMT_F, 5, 1}; +const struct fmt_spec F_8_0 = { .type = FMT_F, .w = 8, .d = 0 }; +const struct fmt_spec F_8_2 = { .type = FMT_F, .w = 8, .d = 2 }; +const struct fmt_spec F_4_3 = { .type = FMT_F, .w = 4, .d = 3 }; +const struct fmt_spec F_5_1 = { .type = FMT_F, .w = 5, .d = 1 };