X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fdata-out.c;h=df447a6a12cac594c38937725030767c44d7999e;hb=7235f7f42b61c2b111174c3ee5ca72aac8815cd5;hp=38f50fafbd0ed6007058c7d722b67d95de6a0d1a;hpb=480a0746507ce73d26f528b56dc3ed80195096e0;p=pspp
diff --git a/src/data/data-out.c b/src/data/data-out.c
index 38f50fafbd..df447a6a12 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 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,23 @@
#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 "gettext.h"
#define _(msgid) gettext (msgid)
@@ -65,12 +63,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 +86,118 @@ 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).
-/* Returns the current output integer format. */
-enum integer_format
-data_out_get_integer_format (void)
+ 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)
{
- return output_integer_format;
+ 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);
+ }
}
-/* Sets the output integer format to INTEGER_FORMAT. */
-void
-data_out_set_integer_format (enum integer_format integer_format)
+static char *
+binary_to_utf8 (const char *in, struct pool *pool)
{
- output_integer_format = 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);
}
-/* Returns the current output float format. */
-enum float_format
-data_out_get_float_format (void)
+/* 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)
{
- return output_float_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;
+ }
}
-/* 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,11 +211,11 @@ 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
+ 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);
@@ -191,6 +249,8 @@ output_N (const union value *input, const struct fmt_spec *format,
else
output_overflow (format, output);
}
+
+ output[format->w] = '\0';
}
/* Outputs Z format. */
@@ -202,19 +262,20 @@ 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)
+ && sprintf (buf, "%0*.0f", format->w,
+ fabs (round (number))) == format->w)
{
- 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);
+ output[format->w] = '\0';
}
+ else
+ output_overflow (format, output);
}
/* Outputs P format. */
@@ -253,9 +314,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 +332,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 +354,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 +364,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 +374,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);
}
@@ -327,7 +398,7 @@ 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;
@@ -342,10 +413,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 +430,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':
@@ -392,16 +464,16 @@ output_date (const union value *input, const struct fmt_spec *format,
p += sprintf (p, "%2d", (yday - 1) / 7 + 1);
break;
case 'D':
- if (number < 0)
+ if (number < 0)
*p++ = '-';
- number = fabs (number);
+ number = fabs (number);
p += sprintf (p, "%*.0f", count, floor (number / 60. / 60. / 24.));
number = fmod (number, 60. * 60. * 24.);
break;
case 'H':
if (number < 0)
*p++ = '-';
- number = fabs (number);
+ number = fabs (number);
p += sprintf (p, "%0*.0f", count, floor (number / 60. / 60.));
number = fmod (number, 60. * 60.);
break;
@@ -409,7 +481,7 @@ output_date (const union value *input, const struct fmt_spec *format,
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))
@@ -419,11 +491,11 @@ 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) != '.')
+ 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);
}
@@ -434,11 +506,12 @@ output_date (const union value *input, const struct fmt_spec *format,
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, ' ');
+ output[format->w] = '\0';
return;
overflow:
@@ -455,20 +528,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 +554,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 +587,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. */
@@ -517,7 +599,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;
@@ -536,10 +618,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];
@@ -565,9 +649,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;
@@ -578,7 +662,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
@@ -591,16 +675,15 @@ 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)
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
@@ -611,7 +694,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)
{
@@ -619,13 +702,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 +723,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;
@@ -662,18 +748,17 @@ output_scientific (double number, const struct fmt_spec *format,
# 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)
- fraction_width = 0;
+ 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));
else
@@ -692,7 +777,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);
}
@@ -700,34 +785,24 @@ 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. */
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');
@@ -741,7 +816,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.
@@ -749,10 +824,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
@@ -760,13 +835,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
@@ -785,8 +860,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.");
@@ -809,7 +884,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;
@@ -822,28 +897,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;
@@ -854,23 +929,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;
@@ -879,14 +954,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);
@@ -894,18 +969,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';
}
}
}
@@ -914,7 +989,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[] =
{
@@ -929,9 +1004,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,8 +1026,8 @@ 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)
{
const char *s;
@@ -964,10 +1039,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
+ else
output_overflow (format, output);
+
+ output[format->w] = '\0';
}
/* Formats OUTPUT as a missing value for the given FORMAT. */
@@ -976,22 +1053,25 @@ 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] = '.';
+
+ output[format->w] = '\0';
}
/* 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);
+ output[format->w] = '\0';
}
/* Converts the integer part of NUMBER to a packed BCD number
@@ -1001,11 +1081,13 @@ 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];
assert (digits < sizeof decimal);
+
+ output[DIV_RND_UP (digits, 2)] = '\0';
if (number != SYSMIS
&& number >= 0.
&& number < power10 (digits)
@@ -1014,21 +1096,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, DIV_RND_UP (digits, 2));
- return false;
+ return false;
}
}
@@ -1036,7 +1118,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);
}
@@ -1044,7 +1126,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;
@@ -1055,4 +1137,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';
}