Change enum legacy_encoding to const char *.
[pspp-builds.git] / src / data / data-out.c
index ffc79ecc51be62d9ce9b5e1d317ffc03978b28f2..fa8d59e74ced3dd4df1c0977a5f25b6d70fe76c9 100644 (file)
@@ -1,21 +1,18 @@
-/* PSPP - computes sample statistics.
-   Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
-   Written by Ben Pfaff <blp@gnu.org>.
+/* 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 <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
 
 #include <stdlib.h>
 #include <time.h>
 
-#include "calendar.h"
-#include "format.h"
-#include "settings.h"
-#include "variable.h"
+#include <data/calendar.h>
+#include <data/format.h>
+#include <data/settings.h>
+#include <data/value.h>
 
 #include <libpspp/assertion.h>
 #include <libpspp/float-format.h>
 #include <libpspp/integer-format.h>
-#include <libpspp/magic.h>
 #include <libpspp/message.h>
 #include <libpspp/misc.h>
-#include <libpspp/misc.h>
 #include <libpspp/str.h>
 
 #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);
 \f
-/* 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 *);
 \f
-/* 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;
-}
 \f
 /* 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);
 }
 \f
 /* 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;
 }
 \f
-#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;