X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?p=pspp-builds.git;a=blobdiff_plain;f=src%2Fdata%2Fdata-out.c;h=fa8d59e74ced3dd4df1c0977a5f25b6d70fe76c9;hp=ffc79ecc51be62d9ce9b5e1d317ffc03978b28f2;hb=9254d30d06a0565c89daccedd93a94c4c6086004;hpb=8acca2de53c1852f38726f70fc6516b34732a79f diff --git a/src/data/data-out.c b/src/data/data-out.c index ffc79ecc..fa8d59e7 100644 --- a/src/data/data-out.c +++ b/src/data/data-out.c @@ -1,21 +1,18 @@ -/* PSPP - computes sample statistics. - Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. - Written by Ben Pfaff . +/* PSPP - a program for statistical analysis. + Copyright (C) 1997-9, 2000, 2006, 2009 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 @@ -28,18 +25,16 @@ #include #include -#include "calendar.h" -#include "format.h" -#include "settings.h" -#include "variable.h" +#include +#include +#include +#include #include #include #include -#include #include #include -#include #include #include "minmax.h" @@ -65,12 +60,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,15 +83,13 @@ 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. */ +/* Same as data_out, and additionally recodes the output from + native form into the given legacy character ENCODING. */ void -data_out (const union value *input, const struct fmt_spec *format, - char *output) +data_out_legacy (const union value *input, const char *encoding, + 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" @@ -111,35 +98,25 @@ data_out (const union value *input, const struct fmt_spec *format, assert (fmt_check_output (format)); converters[format->type] (input, format, output); + if (0 != strcmp (encoding, LEGACY_NATIVE) + && fmt_get_category (format->type) != FMT_CAT_BINARY) + legacy_recode (LEGACY_NATIVE, output, encoding, output, format->w); } -/* Returns the current output integer format. */ -enum integer_format -data_out_get_integer_format (void) -{ - return output_integer_format; -} +/* 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. -/* Sets the output integer format to INTEGER_FORMAT. */ + VALUE must be the correct width for FORMAT, that is, its + width must be fmt_var_width(FORMAT). */ void -data_out_set_integer_format (enum integer_format integer_format) -{ - output_integer_format = integer_format; -} - -/* Returns the current output float format. */ -enum float_format -data_out_get_float_format (void) +data_out (const union value *input, const struct fmt_spec *format, + char *output) { - return output_float_format; + return data_out_legacy (input, LEGACY_NATIVE, format, output); } -/* Sets the output float format to FLOAT_FORMAT. */ -void -data_out_set_float_format (enum float_format float_format) -{ - output_float_format = float_format; -} /* Main conversion functions. */ @@ -155,9 +132,9 @@ output_number (const union value *input, const struct fmt_spec *format, output_missing (format, output); else if (!isfinite (number)) output_infinite (number, format, output); - else + else { - if (format->type != FMT_E && fabs (number) < 1.5 * power10 (format->w)) + if (format->type != FMT_E && fabs (number) < 1.5 * power10 (format->w)) { struct rounder r; rounder_init (&r, number, format->d); @@ -208,12 +185,12 @@ output_Z (const union value *input, const struct fmt_spec *format, output_overflow (format, output); else { - if (number < 0 && strspn (buf, "0") < format->w) + if (number < 0 && strspn (buf, "0") < format->w) { char *p = &buf[format->w - 1]; *p = "}JKLMNOPQR"[*p - '0']; } - memcpy (output, buf, format->w); + memcpy (output, buf, format->w); } } @@ -253,7 +230,8 @@ 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); } } @@ -268,7 +246,8 @@ 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); } /* Outputs PIBHEX format. */ @@ -314,7 +293,6 @@ output_date (const union value *input, const struct fmt_spec *format, char *output) { double number = input->f; - double magnitude = fabs (number); int year, month, day, yday; const char *template = fmt_date_template (format->type); @@ -328,12 +306,13 @@ output_date (const union value *input, const struct fmt_spec *format, if (number == SYSMIS) goto missing; - if (fmt_get_category (format->type) == FMT_CAT_DATE) + if (fmt_get_category (format->type) == FMT_CAT_DATE) { if (number <= 0) goto missing; calendar_offset_to_gregorian (number / 60. / 60. / 24., &year, &month, &day, &yday); + number = fmod (number, 60. * 60. * 24.); } else year = month = day = yday = 0; @@ -342,10 +321,10 @@ output_date (const union value *input, const struct fmt_spec *format, { int ch = *template; int count = 1; - while (template[count] == ch) + while (template[count] == ch) count++; template += count; - + switch (ch) { case 'd': @@ -359,30 +338,31 @@ 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", }; - p = stpcpy (p, months[month - 1]); + p = stpcpy (p, months[month - 1]); } break; case 'y': - if (count >= 4 || excess_width >= 2) + if (count >= 4 || excess_width >= 2) { if (year <= 9999) p += sprintf (p, "%04d", year); else if (format->type == FMT_DATETIME) p = stpcpy (p, "****"); else - goto overflow; + goto overflow; } - else + 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); + p += sprintf (p, "%02d", abs (year) % 100); } break; case 'q': @@ -394,48 +374,51 @@ output_date (const union value *input, const struct fmt_spec *format, case 'D': if (number < 0) *p++ = '-'; - p += sprintf (p, "%.0f", floor (magnitude / 60. / 60. / 24.)); + number = fabs (number); + p += sprintf (p, "%*.0f", count, floor (number / 60. / 60. / 24.)); + number = fmod (number, 60. * 60. * 24.); break; - case 'h': + case 'H': if (number < 0) *p++ = '-'; - p += sprintf (p, "%.0f", floor (magnitude / 60. / 60.)); - break; - case 'H': - p += sprintf (p, "%02d", - (int) fmod (floor (magnitude / 60. / 60.), 24.)); + number = fabs (number); + p += sprintf (p, "%0*.0f", count, floor (number / 60. / 60.)); + number = fmod (number, 60. * 60.); break; case 'M': - p += sprintf (p, "%02d", - (int) fmod (floor (magnitude / 60.), 60.)); + p += sprintf (p, "%02d", (int) floor (number / 60.)); + number = fmod (number, 60.); excess_width = format->w - (p - tmp); - if (excess_width < 0) + if (excess_width < 0) goto overflow; if (excess_width == 3 || excess_width == 4 || (excess_width >= 5 && format->d == 0)) - p += sprintf (p, ":%02d", (int) fmod (magnitude, 60.)); + p += sprintf (p, ":%02d", (int) number); else if (excess_width >= 5) { int d = MIN (format->d, excess_width - 4); int w = d + 3; - sprintf (p, ":%0*.*f", w, d, fmod (magnitude, 60.)); - if (fmt_decimal_char (FMT_F) != '.') + sprintf (p, ":%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; default: assert (count == 1); *p++ = ch; - break; + break; } } - buf_copy_lpad (output, format->w, tmp, p - tmp); + buf_copy_lpad (output, format->w, tmp, p - tmp, ' '); return; overflow: @@ -452,14 +435,14 @@ 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], ' '); else { if (input->f != SYSMIS) @@ -473,14 +456,14 @@ 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], ' '); else { if (input->f != SYSMIS) @@ -494,7 +477,7 @@ static void output_A (const union value *input, const struct fmt_spec *format, char *output) { - memcpy (output, input->s, format->w); + memcpy (output, value_str (input, format->w), format->w); } /* Outputs AHEX format. */ @@ -502,7 +485,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), format->w / 2, output); } /* Decimal and scientific formatting. */ @@ -514,7 +497,7 @@ static bool allocate_space (int request, int max_width, int *width) { assert (*width <= max_width); - if (request + *width <= max_width) + if (request + *width <= max_width) { *width += request; return true; @@ -533,10 +516,12 @@ 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--) + for (decimals = format->d; decimals >= 0; decimals--) { /* Formatted version of magnitude of NUMBER. */ char magnitude[64]; @@ -575,7 +560,7 @@ output_decimal (const struct rounder *r, const struct fmt_spec *format, format->w, &width); if (!add_affixes && require_affixes) continue; - + /* Check whether we should include grouping characters. We need room for a complete set or we don't insert any at all. We don't include grouping characters if decimal places were @@ -588,7 +573,7 @@ output_decimal (const struct rounder *r, const struct fmt_spec *format, /* Format the number's magnitude. */ rounder_format (r, decimals, magnitude); - + /* Assemble number. */ p = output; if (format->w > width) @@ -608,7 +593,7 @@ output_decimal (const struct rounder *r, const struct fmt_spec *format, if (i > 0 && (integer_digits - i) % 3 == 0) *p++ = style->grouping; *p++ = magnitude[i]; - } + } } if (decimals > 0) { @@ -635,7 +620,8 @@ 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; @@ -658,10 +644,8 @@ output_scientific (double number, const struct fmt_spec *format, decimal point without any digits following; that's what the # flag does in the call to sprintf, below.) */ fraction_width = MIN (MIN (format->d + 1, format->w - width), 16); - if (format->type != FMT_E - && (fraction_width == 1 - || format->w - width + (style->grouping == 0 && number < 0) <= 2)) - fraction_width = 0; + if (format->type != FMT_E && fraction_width == 1) + fraction_width = 0; width += fraction_width; /* Format (except suffix). */ @@ -691,7 +675,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 (abs (exponent) > 999) return false; sprintf (cp, "%+04ld", exponent); } @@ -707,26 +691,16 @@ output_scientific (double number, const struct fmt_spec *format, p = mempset (p, ' ', ss_length (style->neg_suffix)); assert (p == buf + format->w); + memcpy (output, buf, format->w); - buf_copy_str_lpad (output, format->w, buf); 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. */ static bool -should_round_up (const struct rounder *r, int decimals) +should_round_up (const struct rounder *r, int decimals) { int digit = r->string[r->integer_digits + decimals + 1]; assert (digit >= '0' && digit <= '9'); @@ -740,7 +714,7 @@ rounder_init (struct rounder *r, double number, int max_decimals) { assert (fabs (number) < 1e41); assert (max_decimals >= 0 && max_decimals <= 16); - if (max_decimals == 0) + if (max_decimals == 0) { /* Fast path. No rounding needed. @@ -748,10 +722,10 @@ rounder_init (struct rounder *r, double number, int max_decimals) round_up assumes that fractional digits are present. */ sprintf (r->string, "%.0f.00", fabs (round (number))); } - else + else { /* Slow path. - + This is more difficult than it really should be because we have to make sure that numbers that are exactly halfway between two representations are always rounded @@ -759,13 +733,13 @@ rounder_init (struct rounder *r, double number, int max_decimals) (usually it rounds to even), so we have to fake it as best we can, by formatting with extra precision and then doing the rounding ourselves. - + We take up to two rounds to format numbers. In the first round, we obtain 2 digits of precision beyond those requested by the user. If those digits are exactly "50", then in a second round we format with as many digits as are significant in a "double". - + It might be better to directly implement our own floating-point formatting routine instead of relying on the system's sprintf implementation. But the classic @@ -784,8 +758,8 @@ rounder_init (struct rounder *r, double number, int max_decimals) sprintf (r->string, "%.*f", format_decimals, fabs (number)); } } - - if (r->string[0] == '0') + + if (r->string[0] == '0') memmove (r->string, &r->string[1], strlen (r->string)); r->leading_zeros = strspn (r->string, "0."); @@ -808,7 +782,7 @@ rounder_init (struct rounder *r, double number, int max_decimals) *NEGATIVE is set to true; otherwise, it is set to false. */ static int rounder_width (const struct rounder *r, int decimals, - int *integer_digits, bool *negative) + int *integer_digits, bool *negative) { /* Calculate base measures. */ int width = r->integer_digits; @@ -821,28 +795,28 @@ rounder_width (const struct rounder *r, int decimals, if (should_round_up (r, decimals)) { /* Rounding up leading 9s adds a new digit (a 1). */ - if (r->leading_nines >= width) + if (r->leading_nines >= width) { width++; - ++*integer_digits; + ++*integer_digits; } } else { /* Rounding down. */ - if (r->leading_zeros >= width) + if (r->leading_zeros >= width) { /* All digits that remain after rounding are zeros. Therefore we drop the negative sign. */ *negative = false; - if (r->integer_digits == 0 && decimals == 0) + if (r->integer_digits == 0 && decimals == 0) { /* No digits at all are left. We need to display at least a single digit (a zero). */ assert (width == 0); width++; *integer_digits = 1; - } + } } } return width; @@ -853,23 +827,23 @@ rounder_width (const struct rounder *r, int decimals, indicated by rounder_width are written. No terminating null is appended. */ static void -rounder_format (const struct rounder *r, int decimals, char *output) +rounder_format (const struct rounder *r, int decimals, char *output) { int base_width = r->integer_digits + (decimals > 0 ? decimals + 1 : 0); - if (should_round_up (r, decimals)) + if (should_round_up (r, decimals)) { - if (r->leading_nines < base_width) + if (r->leading_nines < base_width) { /* Rounding up. This is the common case where rounding up doesn't add an extra digit. */ char *p; memcpy (output, r->string, base_width); - for (p = output + base_width - 1; ; p--) + for (p = output + base_width - 1; ; p--) { assert (p >= output); if (*p == '9') *p = '0'; - else if (*p >= '0' && *p <= '8') + else if (*p >= '0' && *p <= '8') { (*p)++; break; @@ -878,14 +852,14 @@ rounder_format (const struct rounder *r, int decimals, char *output) assert (*p == '.'); } } - else + else { /* Rounding up leading 9s causes the result to be a 1 followed by a number of 0s, plus a decimal point. */ char *p = output; *p++ = '1'; p = mempset (p, '0', r->integer_digits); - if (decimals > 0) + if (decimals > 0) { *p++ = '.'; p = mempset (p, '0', decimals); @@ -893,18 +867,18 @@ rounder_format (const struct rounder *r, int decimals, char *output) assert (p == output + base_width + 1); } } - else + else { /* Rounding down. */ - if (r->integer_digits != 0 || decimals != 0) + if (r->integer_digits != 0 || decimals != 0) { /* Common case: just copy the digits. */ - memcpy (output, r->string, base_width); + memcpy (output, r->string, base_width); } - else + else { /* No digits remain. The output is just a zero. */ - output[0] = '0'; + output[0] = '0'; } } } @@ -913,7 +887,7 @@ rounder_format (const struct rounder *r, int decimals, char *output) /* Returns 10**X. */ static double PURE_FUNCTION -power10 (int x) +power10 (int x) { static const double p[] = { @@ -928,9 +902,9 @@ power10 (int x) /* Returns 256**X. */ static double PURE_FUNCTION -power256 (int x) +power256 (int x) { - static const double p[] = + static const double p[] = { 1.0, 256.0, @@ -951,7 +925,7 @@ static void output_infinite (double number, const struct fmt_spec *format, char *output) { assert (!isfinite (number)); - + if (format->w >= 3) { const char *s; @@ -963,9 +937,9 @@ 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 + else output_overflow (format, output); } @@ -975,12 +949,12 @@ output_missing (const struct fmt_spec *format, char *output) { memset (output, ' ', format->w); - if (format->type != FMT_N) + if (format->type != FMT_N) { int dot_ofs = (format->type == FMT_PCT ? 2 : format->type == FMT_E ? 5 : 1); - output[MAX (0, format->w - format->d - dot_ofs)] = '.'; + output[MAX (0, format->w - format->d - dot_ofs)] = '.'; } else output[format->w - 1] = '.'; @@ -988,7 +962,7 @@ output_missing (const struct fmt_spec *format, char *output) /* Formats OUTPUT for overflow given FORMAT. */ static void -output_overflow (const struct fmt_spec *format, char *output) +output_overflow (const struct fmt_spec *format, char *output) { memset (output, '*', format->w); } @@ -1000,7 +974,7 @@ output_overflow (const struct fmt_spec *format, char *output) representable. On failure, OUTPUT is cleared to all zero bytes. */ static bool -output_bcd_integer (double number, int digits, char *output) +output_bcd_integer (double number, int digits, char *output) { char decimal[64]; @@ -1013,21 +987,21 @@ output_bcd_integer (double number, int digits, char *output) const char *src = decimal; int i; - for (i = 0; i < digits / 2; i++) + for (i = 0; i < digits / 2; i++) { int d0 = *src++ - '0'; int d1 = *src++ - '0'; - *output++ = (d0 << 4) + d1; + *output++ = (d0 << 4) + d1; } if (digits % 2) *output = (*src - '0') << 4; - + return true; } - else + else { - memset (output, 0, digits); - return false; + memset (output, 0, DIV_RND_UP (digits, 2)); + return false; } } @@ -1035,7 +1009,7 @@ output_bcd_integer (double number, int digits, char *output) given INTEGER_FORMAT. */ static void output_binary_integer (uint64_t value, int bytes, - enum integer_format integer_format, char *output) + enum integer_format integer_format, char *output) { integer_put (value, integer_format, output, bytes); } @@ -1043,7 +1017,7 @@ output_binary_integer (uint64_t value, int bytes, /* Converts the BYTES bytes in DATA to twice as many hexadecimal digits in OUTPUT. */ static void -output_hex (const void *data_, size_t bytes, char *output) +output_hex (const void *data_, size_t bytes, char *output) { const uint8_t *data = data_; size_t i;