X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fdata-out.c;h=3f3611f00da2c032587c53971403e73ff502e35f;hb=32ea29485bdd610b7d05dd806c5f06f68da0f0fe;hp=df447a6a12cac594c38937725030767c44d7999e;hpb=81579d9e9f994fb2908f50af41c3eb033d216e58;p=pspp diff --git a/src/data/data-out.c b/src/data/data-out.c index df447a6a12..3f3611f00d 100644 --- a/src/data/data-out.c +++ b/src/data/data-out.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006, 2009, 2011 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 2009, 2011, 2012, 2013, 2014 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -41,6 +41,7 @@ #include "libpspp/str.h" #include "gl/minmax.h" +#include "gl/c-snprintf.h" #include "gettext.h" #define _(msgid) gettext (msgid) @@ -192,6 +193,36 @@ data_out_pool (const union value *input, const char *encoding, } } +/* Like data_out_pool(), except that for basic numeric formats (F, COMMA, DOT, + COLLAR, PCT, E) and custom currency formats are formatted as wide as + necessary to fully display the selected number of decimal places. */ +char * +data_out_stretchy (const union value *input, const char *encoding, + const struct fmt_spec *format, struct pool *pool) +{ + + if (fmt_get_category (format->type) & (FMT_CAT_BASIC | FMT_CAT_CUSTOM)) + { + const struct fmt_number_style *style = settings_get_style (format->type); + struct fmt_spec wide_format; + char tmp[128]; + size_t size; + + wide_format.type = format->type; + wide_format.w = 40; + wide_format.d = format->d; + + size = format->w + style->extra_bytes + 1; + if (size <= sizeof tmp) + { + output_number (input, &wide_format, tmp); + return pool_strdup (pool, tmp + strspn (tmp, " ")); + } + } + + return data_out_pool (input, encoding, format, pool); +} + char * data_out (const union value *input, const char *encoding, const struct fmt_spec *format) { @@ -244,7 +275,7 @@ output_N (const union value *input, const struct fmt_spec *format, char buf[128]; number = fabs (round (number)); if (number < power10 (format->w) - && sprintf (buf, "%0*.0f", format->w, number) == format->w) + && c_snprintf (buf, 128, "%0*.0f", format->w, number) == format->w) memcpy (output, buf, format->w); else output_overflow (format, output); @@ -263,7 +294,7 @@ output_Z (const union value *input, const struct fmt_spec *format, if (input->f == SYSMIS) output_missing (format, output); else if (fabs (number) < power10 (format->w) - && sprintf (buf, "%0*.0f", format->w, + && c_snprintf (buf, 128, "%0*.0f", format->w, fabs (round (number))) == format->w) { if (number < 0 && strspn (buf, "0") < format->w) @@ -387,14 +418,11 @@ output_date (const union value *input, const struct fmt_spec *format, double number = input->f; int year, month, day, yday; - const char *template = fmt_date_template (format->type); - size_t template_width = strlen (template); - int excess_width = format->w - template_width; + const char *template = fmt_date_template (format->type, format->w); char tmp[64]; char *p = tmp; - assert (format->w >= template_width); if (number == SYSMIS) goto missing; @@ -411,6 +439,8 @@ output_date (const union value *input, const struct fmt_spec *format, while (*template != '\0') { + int excess_width; + int ch = *template; int count = 1; while (template[count] == ch) @@ -439,7 +469,7 @@ output_date (const union value *input, const struct fmt_spec *format, } break; case 'y': - if (count >= 4 || excess_width >= 2) + if (count >= 4) { if (year <= 9999) p += sprintf (p, "%04d", year); @@ -467,14 +497,14 @@ output_date (const union value *input, const struct fmt_spec *format, if (number < 0) *p++ = '-'; number = fabs (number); - p += sprintf (p, "%*.0f", count, floor (number / 60. / 60. / 24.)); + p += c_snprintf (p, 64, "%*.0f", count, floor (number / 60. / 60. / 24.)); number = fmod (number, 60. * 60. * 24.); break; case 'H': if (number < 0) *p++ = '-'; number = fabs (number); - p += sprintf (p, "%0*.0f", count, floor (number / 60. / 60.)); + p += c_snprintf (p, 64, "%0*.0f", count, floor (number / 60. / 60.)); number = fmod (number, 60. * 60.); break; case 'M': @@ -490,7 +520,7 @@ output_date (const union value *input, const struct fmt_spec *format, { int d = MIN (format->d, excess_width - 4); int w = d + 3; - sprintf (p, ":%0*.*f", w, d, number); + c_snprintf (p, 64, ":%0*.*f", w, d, number); if (settings_get_decimal_char (FMT_F) != '.') { char *cp = strchr (p, '.'); @@ -499,10 +529,7 @@ output_date (const union value *input, const struct fmt_spec *format, } p += strlen (p); } - break; - case 'X': - *p++ = ' '; - break; + goto done; default: assert (count == 1); *p++ = ch; @@ -510,6 +537,7 @@ output_date (const union value *input, const struct fmt_spec *format, } } + done: buf_copy_lpad (output, format->w, tmp, p - tmp, ' '); output[format->w] = '\0'; return; @@ -587,7 +615,7 @@ static void output_AHEX (const union value *input, const struct fmt_spec *format, char *output) { - output_hex (value_str (input, format->w), format->w / 2, output); + output_hex (value_str (input, format->w / 2), format->w / 2, output); } /* Decimal and scientific formatting. */ @@ -745,7 +773,7 @@ output_scientific (double number, const struct fmt_spec *format, /* Figure out number of characters we can use for the fraction, if any. (If that turns out to be 1, then we'll output a decimal point without any digits following; that's what the - # flag does in the call to sprintf, below.) */ + # flag does in the call to c_snprintf, below.) */ fraction_width = MIN (MIN (format->d + 1, format->w - width), 16); if (format->type != FMT_E && fraction_width == 1) fraction_width = 0; @@ -760,9 +788,9 @@ output_scientific (double number, const struct fmt_spec *format, if (add_affixes) p = stpcpy (p, style->prefix.s); if (fraction_width > 0) - sprintf (p, "%#.*E", fraction_width - 1, fabs (number)); + c_snprintf (p, 64, "%#.*E", fraction_width - 1, fabs (number)); else - sprintf (p, "%.0E", fabs (number)); + c_snprintf (p, 64, "%.0E", fabs (number)); /* The C locale always uses a period `.' as a decimal point. Translate to comma if necessary. */ @@ -777,7 +805,7 @@ output_scientific (double number, const struct fmt_spec *format, { char *cp = strchr (p, 'E') + 1; long int exponent = strtol (cp, NULL, 10); - if (abs (exponent) > 999) + if (labs (exponent) > 999) return false; sprintf (cp, "%+04ld", exponent); } @@ -822,7 +850,7 @@ rounder_init (struct rounder *r, double number, int max_decimals) We append ".00" to the integer representation because round_up assumes that fractional digits are present. */ - sprintf (r->string, "%.0f.00", fabs (round (number))); + c_snprintf (r->string, 64, "%.0f.00", fabs (round (number))); } else { @@ -849,7 +877,7 @@ rounder_init (struct rounder *r, double number, int max_decimals) numbers does not hint how to do what we want, and it's not obvious how to change their algorithms to do so. It would also be a lot of work. */ - sprintf (r->string, "%.*f", max_decimals + 2, fabs (number)); + c_snprintf (r->string, 64, "%.*f", max_decimals + 2, fabs (number)); if (!strcmp (r->string + strlen (r->string) - 2, "50")) { int binary_exponent, decimal_exponent, format_decimals; @@ -857,7 +885,7 @@ rounder_init (struct rounder *r, double number, int max_decimals) decimal_exponent = binary_exponent * 3 / 10; format_decimals = (DBL_DIG + 1) - decimal_exponent; if (format_decimals > max_decimals + 2) - sprintf (r->string, "%.*f", format_decimals, fabs (number)); + c_snprintf (r->string, 64, "%.*f", format_decimals, fabs (number)); } } @@ -867,6 +895,8 @@ rounder_init (struct rounder *r, double number, int max_decimals) r->leading_zeros = strspn (r->string, "0."); r->leading_nines = strspn (r->string, "9."); r->integer_digits = strchr (r->string, '.') - r->string; + assert (r->integer_digits < 64); + assert (r->integer_digits >= 0); r->negative = number < 0; } @@ -1091,7 +1121,7 @@ output_bcd_integer (double number, int digits, char *output) if (number != SYSMIS && number >= 0. && number < power10 (digits) - && sprintf (decimal, "%0*.0f", digits, round (number)) == digits) + && c_snprintf (decimal, 64, "%0*.0f", digits, round (number)) == digits) { const char *src = decimal; int i;