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=335f6d86523e1892fecf2bc8cd88169d6594dbcd;hpb=f5c108becd49d78f4898cab11352291f5689d24e;p=pspp diff --git a/src/data/data-out.c b/src/data/data-out.c index 335f6d8652..3f3611f00d 100644 --- a/src/data/data-out.c +++ b/src/data/data-out.c @@ -1,24 +1,22 @@ -/* PSPP - computes sample statistics. - Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. +/* PSPP - a program for statistical analysis. + 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 the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. + 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 + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. */ + along with this program. If not, see . */ #include -#include "data-out.h" +#include "data/data-out.h" #include #include @@ -26,23 +24,24 @@ #include #include #include -#include - -#include "calendar.h" -#include "format.h" -#include "settings.h" -#include "value.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "minmax.h" +#include + +#include "data/calendar.h" +#include "data/format.h" +#include "data/settings.h" +#include "data/value.h" +#include "libpspp/assertion.h" +#include "libpspp/cast.h" +#include "libpspp/float-format.h" +#include "libpspp/i18n.h" +#include "libpspp/integer-format.h" +#include "libpspp/message.h" +#include "libpspp/misc.h" +#include "libpspp/pool.h" +#include "libpspp/str.h" + +#include "gl/minmax.h" +#include "gl/c-snprintf.h" #include "gettext.h" #define _(msgid) gettext (msgid) @@ -65,12 +64,6 @@ static int rounder_width (const struct rounder *, int decimals, static void rounder_format (const struct rounder *, int decimals, char *output); -/* Format of integers in output (SET WIB). */ -static enum integer_format output_integer_format = INTEGER_NATIVE; - -/* Format of reals in output (SET WRB). */ -static enum float_format output_float_format = FLOAT_NATIVE_DOUBLE; - typedef void data_out_converter_func (const union value *, const struct fmt_spec *, char *); @@ -94,52 +87,148 @@ static void output_binary_integer (uint64_t, int bytes, enum integer_format, char *); static void output_hex (const void *, size_t bytes, char *); -/* Converts the INPUT value into printable form in the exactly - FORMAT->W characters in OUTPUT according to format - specification FORMAT. No null terminator is appended to the - buffer. */ -void -data_out (const union value *input, const struct fmt_spec *format, - char *output) -{ - static data_out_converter_func *const converters[FMT_NUMBER_OF_FORMATS] = + +static data_out_converter_func *const converters[FMT_NUMBER_OF_FORMATS] = { #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) output_##METHOD, #include "format.def" }; - assert (fmt_check_output (format)); +/* Converts the INPUT value, encoded in INPUT_ENCODING, according to format + specification FORMAT, appending the output to OUTPUT in OUTPUT_ENCODING. + However, binary formats (FMT_P, FMT_PK, FMT_IB, FMT_PIB, FMT_RB) yield the + binary results, which may not be properly encoded for OUTPUT_ENCODING. - converters[format->type] (input, format, output); + VALUE must be the correct width for FORMAT, that is, its width must be + fmt_var_width(FORMAT). + + INPUT_ENCODING can normally be obtained by calling dict_get_encoding() on + the dictionary with which INPUT is associated. ENCODING is only important + when FORMAT's type is FMT_A. */ +void +data_out_recode (const union value *input, const char *input_encoding, + const struct fmt_spec *format, + struct string *output, const char *output_encoding) +{ + assert (fmt_check_output (format)); + if (format->type == FMT_A) + { + char *in = CHAR_CAST (char *, value_str (input, format->w)); + char *out = recode_string (output_encoding, input_encoding, + in, format->w); + ds_put_cstr (output, out); + free (out); + } + else if (fmt_get_category (format->type) == FMT_CAT_BINARY) + converters[format->type] (input, format, + ds_put_uninit (output, format->w)); + else + { + char *utf8_encoded = data_out (input, input_encoding, format); + char *output_encoded = recode_string (output_encoding, UTF8, + utf8_encoded, -1); + ds_put_cstr (output, output_encoded); + free (output_encoded); + free (utf8_encoded); + } } -/* Returns the current output integer format. */ -enum integer_format -data_out_get_integer_format (void) +static char * +binary_to_utf8 (const char *in, struct pool *pool) { - return output_integer_format; + uint8_t *out = pool_alloc_unaligned (pool, strlen (in) * 2 + 1); + uint8_t *p = out; + + while (*in != '\0') + { + uint8_t byte = *in++; + int mblen = u8_uctomb (p, byte, 2); + assert (mblen > 0); + p += mblen; + } + *p = '\0'; + + return CHAR_CAST (char *, out); } -/* Sets the output integer format to INTEGER_FORMAT. */ -void -data_out_set_integer_format (enum integer_format integer_format) +/* Converts the INPUT value into a UTF-8 encoded string, according to format + specification FORMAT. + + VALUE must be the correct width for FORMAT, that is, its width must be + fmt_var_width(FORMAT). + + ENCODING must be the encoding of INPUT. Normally this can be obtained by + calling dict_get_encoding() on the dictionary with which INPUT is + associated. ENCODING is only important when FORMAT's type is FMT_A. + + The return value is dynamically allocated, and must be freed by the caller. + If POOL is non-null, then the return value is allocated on that pool. */ +char * +data_out_pool (const union value *input, const char *encoding, + const struct fmt_spec *format, struct pool *pool) { - output_integer_format = integer_format; + assert (fmt_check_output (format)); + if (format->type == FMT_A) + { + char *in = CHAR_CAST (char *, value_str (input, format->w)); + return recode_string_pool (UTF8, encoding, in, format->w, pool); + } + else if (fmt_get_category (format->type) == FMT_CAT_BINARY) + { + char tmp[16]; + + assert (format->w + 1 <= sizeof tmp); + converters[format->type] (input, format, tmp); + return binary_to_utf8 (tmp, pool); + } + else + { + const struct fmt_number_style *style = settings_get_style (format->type); + size_t size = format->w + style->extra_bytes + 1; + char *output; + + output = pool_alloc_unaligned (pool, size); + converters[format->type] (input, format, output); + return output; + } } -/* Returns the current output float format. */ -enum float_format -data_out_get_float_format (void) +/* 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) { - return output_float_format; + + 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); } -/* Sets the output float format to FLOAT_FORMAT. */ -void -data_out_set_float_format (enum float_format float_format) +char * +data_out (const union value *input, const char *encoding, const struct fmt_spec *format) { - output_float_format = float_format; + return data_out_pool (input, encoding, format, NULL); } + /* Main conversion functions. */ @@ -153,7 +242,7 @@ output_number (const union value *input, const struct fmt_spec *format, if (number == SYSMIS) output_missing (format, output); - else if (!gsl_finite (number)) + else if (!isfinite (number)) output_infinite (number, format, output); else { @@ -186,11 +275,13 @@ 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); } + + output[format->w] = '\0'; } /* Outputs Z format. */ @@ -202,11 +293,9 @@ output_Z (const union value *input, const struct fmt_spec *format, char buf[128]; if (input->f == SYSMIS) output_missing (format, output); - else if (fabs (number) >= power10 (format->w) - || sprintf (buf, "%0*.0f", format->w, - fabs (round (number))) != format->w) - output_overflow (format, output); - else + else if (fabs (number) < power10 (format->w) + && c_snprintf (buf, 128, "%0*.0f", format->w, + fabs (round (number))) == format->w) { if (number < 0 && strspn (buf, "0") < format->w) { @@ -214,7 +303,10 @@ output_Z (const union value *input, const struct fmt_spec *format, *p = "}JKLMNOPQR"[*p - '0']; } memcpy (output, buf, format->w); + output[format->w] = '\0'; } + else + output_overflow (format, output); } /* Outputs P format. */ @@ -253,9 +345,12 @@ output_IB (const union value *input, const struct fmt_spec *format, uint64_t integer = fabs (number); if (number < 0) integer = -integer; - output_binary_integer (integer, format->w, output_integer_format, + output_binary_integer (integer, format->w, + settings_get_output_integer_format (), output); } + + output[format->w] = '\0'; } /* Outputs PIB format. */ @@ -268,7 +363,10 @@ output_PIB (const union value *input, const struct fmt_spec *format, || number < 0 || number >= power256 (format->w)) memset (output, 0, format->w); else - output_binary_integer (number, format->w, output_integer_format, output); + output_binary_integer (number, format->w, + settings_get_output_integer_format (), output); + + output[format->w] = '\0'; } /* Outputs PIBHEX format. */ @@ -287,6 +385,7 @@ output_PIBHEX (const union value *input, const struct fmt_spec *format, output_binary_integer (number, format->w / 2, INTEGER_MSB_FIRST, tmp); output_hex (tmp, format->w / 2, output); } + } /* Outputs RB format. */ @@ -296,6 +395,8 @@ output_RB (const union value *input, const struct fmt_spec *format, { double d = input->f; memcpy (output, &d, format->w); + + output[format->w] = '\0'; } /* Outputs RBHEX format. */ @@ -304,6 +405,7 @@ output_RBHEX (const union value *input, const struct fmt_spec *format, char *output) { double d = input->f; + output_hex (&d, format->w / 2, output); } @@ -316,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; @@ -340,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) @@ -359,7 +460,7 @@ output_date (const union value *input, const struct fmt_spec *format, p += sprintf (p, "%02d", month); else { - static const char *months[12] = + static const char *const months[12] = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC", @@ -368,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); @@ -379,7 +480,8 @@ output_date (const union value *input, const struct fmt_spec *format, } else { - int offset = year - get_epoch (); + int epoch = settings_get_epoch (); + int offset = year - epoch; if (offset < 0 || offset > 99) goto overflow; p += sprintf (p, "%02d", abs (year) % 100); @@ -395,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': @@ -418,19 +520,16 @@ 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); - if (fmt_decimal_char (FMT_F) != '.') + c_snprintf (p, 64, ":%0*.*f", w, d, number); + if (settings_get_decimal_char (FMT_F) != '.') { char *cp = strchr (p, '.'); if (cp != NULL) - *cp = fmt_decimal_char (FMT_F); + *cp = settings_get_decimal_char (FMT_F); } p += strlen (p); } - break; - case 'X': - *p++ = ' '; - break; + goto done; default: assert (count == 1); *p++ = ch; @@ -438,7 +537,9 @@ output_date (const union value *input, const struct fmt_spec *format, } } - buf_copy_lpad (output, format->w, tmp, p - tmp); + done: + buf_copy_lpad (output, format->w, tmp, p - tmp, ' '); + output[format->w] = '\0'; return; overflow: @@ -455,20 +556,25 @@ static void output_WKDAY (const union value *input, const struct fmt_spec *format, char *output) { - static const char *weekdays[7] = + static const char *const weekdays[7] = { "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", }; if (input->f >= 1 && input->f < 8) - buf_copy_str_rpad (output, format->w, weekdays[(int) input->f - 1]); + { + buf_copy_str_rpad (output, format->w, + weekdays[(int) input->f - 1], ' '); + output[format->w] = '\0'; + } else { if (input->f != SYSMIS) msg (ME, _("Weekday number %f is not between 1 and 7."), input->f); output_missing (format, output); } + } /* Outputs MONTH format. */ @@ -476,28 +582,32 @@ static void output_MONTH (const union value *input, const struct fmt_spec *format, char *output) { - static const char *months[12] = + static const char *const months[12] = { "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER", }; if (input->f >= 1 && input->f < 13) - buf_copy_str_rpad (output, format->w, months[(int) input->f - 1]); + { + buf_copy_str_rpad (output, format->w, months[(int) input->f - 1], ' '); + output[format->w] = '\0'; + } else { if (input->f != SYSMIS) msg (ME, _("Month number %f is not between 1 and 12."), input->f); output_missing (format, output); } + } /* Outputs A format. */ static void -output_A (const union value *input, const struct fmt_spec *format, - char *output) +output_A (const union value *input UNUSED, + const struct fmt_spec *format UNUSED, char *output UNUSED) { - memcpy (output, input->s, format->w); + NOT_REACHED (); } /* Outputs AHEX format. */ @@ -505,7 +615,7 @@ static void output_AHEX (const union value *input, const struct fmt_spec *format, char *output) { - output_hex (input->s, format->w, output); + output_hex (value_str (input, format->w / 2), format->w / 2, output); } /* Decimal and scientific formatting. */ @@ -536,7 +646,9 @@ static bool output_decimal (const struct rounder *r, const struct fmt_spec *format, bool require_affixes, char *output) { - const struct fmt_number_style *style = fmt_get_style (format->type); + const struct fmt_number_style *style = + settings_get_style (format->type); + int decimals; for (decimals = format->d; decimals >= 0; decimals--) @@ -565,9 +677,9 @@ output_decimal (const struct rounder *r, const struct fmt_spec *format, the negative suffix, plus (if negative) the negative prefix. */ width = rounder_width (r, decimals, &integer_digits, &add_neg_prefix); - width += ss_length (style->neg_suffix); + width += style->neg_suffix.width; if (add_neg_prefix) - width += ss_length (style->neg_prefix); + width += style->neg_prefix.width; if (width > format->w) continue; @@ -597,10 +709,9 @@ output_decimal (const struct rounder *r, const struct fmt_spec *format, if (format->w > width) p = mempset (p, ' ', format->w - width); if (add_neg_prefix) - p = mempcpy (p, ss_data (style->neg_prefix), - ss_length (style->neg_prefix)); + p = stpcpy (p, style->neg_prefix.s); if (add_affixes) - p = mempcpy (p, ss_data (style->prefix), ss_length (style->prefix)); + p = stpcpy (p, style->prefix.s); if (!add_grouping) p = mempcpy (p, magnitude, integer_digits); else @@ -619,13 +730,15 @@ output_decimal (const struct rounder *r, const struct fmt_spec *format, p = mempcpy (p, &magnitude[integer_digits + 1], decimals); } if (add_affixes) - p = mempcpy (p, ss_data (style->suffix), ss_length (style->suffix)); + p = stpcpy (p, style->suffix.s); if (add_neg_prefix) - p = mempcpy (p, ss_data (style->neg_suffix), - ss_length (style->neg_suffix)); + p = stpcpy (p, style->neg_suffix.s); else - p = mempset (p, ' ', ss_length (style->neg_suffix)); - assert (p == output + format->w); + p = mempset (p, ' ', style->neg_suffix.width); + + assert (p >= output + format->w); + assert (p <= output + format->w + style->extra_bytes); + *p = '\0'; return true; } @@ -638,16 +751,17 @@ static bool output_scientific (double number, const struct fmt_spec *format, bool require_affixes, char *output) { - const struct fmt_number_style *style = fmt_get_style (format->type); + const struct fmt_number_style *style = + settings_get_style (format->type); int width; int fraction_width; bool add_affixes; - char buf[64], *p; + char *p; /* Allocate minimum required space. */ - width = 6 + ss_length (style->neg_suffix); + width = 6 + style->neg_suffix.width; if (number < 0) - width += ss_length (style->neg_prefix); + width += style->neg_prefix.width; if (width > format->w) return false; @@ -659,25 +773,24 @@ 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; width += fraction_width; /* Format (except suffix). */ - p = buf; + p = output; if (width < format->w) p = mempset (p, ' ', format->w - width); if (number < 0) - p = mempcpy (p, ss_data (style->neg_prefix), - ss_length (style->neg_prefix)); + p = stpcpy (p, style->neg_prefix.s); if (add_affixes) - p = mempcpy (p, ss_data (style->prefix), ss_length (style->prefix)); + 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. */ @@ -692,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); } @@ -700,29 +813,19 @@ output_scientific (double number, const struct fmt_spec *format, /* Add suffixes. */ p = strchr (p, '\0'); if (add_affixes) - p = mempcpy (p, ss_data (style->suffix), ss_length (style->suffix)); + p = stpcpy (p, style->suffix.s); if (number < 0) - p = mempcpy (p, ss_data (style->neg_suffix), - ss_length (style->neg_suffix)); + p = stpcpy (p, style->neg_suffix.s); else - p = mempset (p, ' ', ss_length (style->neg_suffix)); + p = mempset (p, ' ', style->neg_suffix.width); - assert (p == buf + format->w); - memcpy (output, buf, format->w); + assert (p >= output + format->w); + assert (p <= output + format->w + style->extra_bytes); + *p = '\0'; return true; } -#ifndef HAVE_ROUND -/* Return X rounded to the nearest integer, - rounding ties away from zero. */ -static double -round (double x) -{ - return x >= 0.0 ? floor (x + .5) : ceil (x - .5); -} -#endif /* !HAVE_ROUND */ - /* Returns true if the magnitude represented by R should be rounded up when chopped off at DECIMALS decimal places, false if it should be rounded down. */ @@ -747,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 { @@ -774,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; @@ -782,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)); } } @@ -792,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; } @@ -951,7 +1056,7 @@ power256 (int x) static void output_infinite (double number, const struct fmt_spec *format, char *output) { - assert (!gsl_finite (number)); + assert (!isfinite (number)); if (format->w >= 3) { @@ -964,10 +1069,12 @@ output_infinite (double number, const struct fmt_spec *format, char *output) else s = "Unknown"; - buf_copy_str_lpad (output, format->w, s); + buf_copy_str_lpad (output, format->w, s, ' '); } else output_overflow (format, output); + + output[format->w] = '\0'; } /* Formats OUTPUT as a missing value for the given FORMAT. */ @@ -985,6 +1092,8 @@ output_missing (const struct fmt_spec *format, char *output) } else output[format->w - 1] = '.'; + + output[format->w] = '\0'; } /* Formats OUTPUT for overflow given FORMAT. */ @@ -992,6 +1101,7 @@ static void output_overflow (const struct fmt_spec *format, char *output) { memset (output, '*', format->w); + output[format->w] = '\0'; } /* Converts the integer part of NUMBER to a packed BCD number @@ -1006,10 +1116,12 @@ output_bcd_integer (double number, int digits, char *output) char decimal[64]; assert (digits < sizeof decimal); + + output[DIV_RND_UP (digits, 2)] = '\0'; 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; @@ -1055,4 +1167,5 @@ output_hex (const void *data_, size_t bytes, char *output) *output++ = hex_digits[data[i] >> 4]; *output++ = hex_digits[data[i] & 15]; } + *output = '\0'; }