Completely rewrite src/data/format.[ch], to achieve better
[pspp-builds.git] / src / data / data-out.c
index 79c7042446abb453c2c1722b118303805dd5b217..74f97188a66f7da86a50126e729f979c0feb181a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - computes sample statistics.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
    Written by Ben Pfaff <blp@gnu.org>.
 
    This program is free software; you can redistribute it and/or
@@ -25,6 +25,7 @@
 #include <stdlib.h>
 #include <time.h>
 #include "calendar.h"
+#include <libpspp/assertion.h>
 #include <libpspp/message.h>
 #include "format.h"
 #include <libpspp/magic.h>
@@ -36,8 +37,6 @@
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
-
-#include <libpspp/debug-print.h>
 \f
 /* Public functions. */
 
@@ -59,17 +58,17 @@ static string_converter convert_A, convert_AHEX;
 bool
 data_out (char *s, const struct fmt_spec *fp, const union value *v)
 {
-  int cat = formats[fp->type].cat;
   int ok;
 
-  assert (check_output_specifier (fp, 0));
-  if (!(cat & FCAT_STRING)) 
+  assert (fmt_check_output (fp));
+  if (fmt_is_numeric (fp->type)) 
     {
-      /* Numeric formatting. */
+      enum fmt_category category = fmt_get_category (fp->type);
       double number = v->f;
 
       /* Handle SYSMIS turning into blanks. */
-      if ((cat & FCAT_BLANKS_SYSMIS) && number == SYSMIS)
+      if (!(category & (FMT_CAT_CUSTOM | FMT_CAT_BINARY | FMT_CAT_HEXADECIMAL))
+          && number == SYSMIS)
         {
           memset (s, ' ', fp->w);
           s[fp->w - fp->d - 1] = '.';
@@ -77,7 +76,9 @@ data_out (char *s, const struct fmt_spec *fp, const union value *v)
         }
 
       /* Handle decimal shift. */
-      if ((cat & FCAT_SHIFT_DECIMAL) && number != SYSMIS && fp->d)
+      if ((category & (FMT_CAT_LEGACY | FMT_CAT_BINARY))
+          && number != SYSMIS
+          && fp->d)
         number *= pow (10.0, fp->d);
 
       switch (fp->type) 
@@ -103,12 +104,10 @@ data_out (char *s, const struct fmt_spec *fp, const union value *v)
           break;
 
         case FMT_A:
-          assert (0);
-          abort ();
+          NOT_REACHED ();
 
         case FMT_AHEX:
-          assert (0);
-          abort ();
+          NOT_REACHED ();
 
         case FMT_IB:
           ok = convert_IB (s, fp, number);
@@ -161,8 +160,7 @@ data_out (char *s, const struct fmt_spec *fp, const union value *v)
           break;
 
         default:
-          assert (0);
-          abort ();
+          NOT_REACHED ();
         }
     }
   else 
@@ -181,8 +179,7 @@ data_out (char *s, const struct fmt_spec *fp, const union value *v)
           break;
 
         default:
-          assert (0);
-          abort ();
+          NOT_REACHED ();
         }
     }
 
@@ -192,15 +189,6 @@ data_out (char *s, const struct fmt_spec *fp, const union value *v)
   
   return ok;
 }
-
-/* Converts V into S in F format with width W and D decimal places,
-   then deletes trailing zeros.  S is not null-terminated. */
-void
-num_to_string (double v, char *s, int w, int d)
-{
-  struct fmt_spec f = make_output_format (FMT_F, w, d);
-  convert_F (s, &f, v);
-}
 \f
 /* Main conversion functions. */
 
@@ -324,12 +312,11 @@ convert_E (char *dst, const struct fmt_spec *fp, double number)
 
   /* The C locale always uses a period `.' as a decimal point.
      Translate to comma if necessary. */
-  if ((get_decimal() == ',' && fp->type != FMT_DOT)
-      || (get_decimal() == '.' && fp->type == FMT_DOT))
+  if (fmt_decimal_char (fp->type) != '.')
     {
       char *cp = strchr (buf, '.');
       if (cp)
-       *cp = ',';
+       *cp = fmt_decimal_char (fp->type);
     }
 
   memcpy (dst, buf, fp->w);
@@ -353,7 +340,7 @@ convert_F_plus (char *dst, const struct fmt_spec *fp, double number)
 static int
 convert_Z (char *dst, const struct fmt_spec *fp, double number)
 {
-  static int warned = 0;
+  static bool warned = false;
 
   if (!warned)
     {
@@ -397,7 +384,7 @@ convert_Z (char *dst, const struct fmt_spec *fp, double number)
 static int
 convert_A (char *dst, const struct fmt_spec *fp, const char *string)
 {
-  memcpy (dst, string, fp->w);
+  memcpy(dst, string, fp->w);
   return 1;
 }
 
@@ -753,7 +740,7 @@ convert_date (char *dst, const struct fmt_spec *fp, double number)
       }
       break;
     default:
-      assert (0);
+      NOT_REACHED ();
     }
 
   if (buf[0] == 0)
@@ -939,7 +926,7 @@ insert_commas (char *dst, const char *src, const struct fmt_spec *fp)
       if (i % 3 == 0 && n_digits > i && n_items > n_reserved)
        {
          n_items--;
-         *dst++ = fp->type == FMT_COMMA ? get_grouping() : get_decimal();
+         *dst++ = fmt_grouping_char (fp->type);
        }
       *dst++ = *sp++;
     }
@@ -965,7 +952,7 @@ year4 (int year)
 static int
 try_CCx (char *dst, const struct fmt_spec *fp, double number)
 {
-  const struct custom_currency *cc = get_cc(fp->type - FMT_CCA);
+  const struct fmt_number_style *style = fmt_get_style (fp->type);
 
   struct fmt_spec f;
 
@@ -975,10 +962,10 @@ try_CCx (char *dst, const struct fmt_spec *fp, double number)
 
   /* Determine length available, decimal character for number
      proper. */
-  f.type = cc->decimal == get_decimal () ? FMT_COMMA : FMT_DOT;
-  f.w = fp->w - strlen (cc->prefix) - strlen (cc->suffix);
+  f.type = style->decimal == fmt_decimal_char (FMT_COMMA) ? FMT_COMMA : FMT_DOT;
+  f.w = fp->w - fmt_affix_width (style);
   if (number < 0)
-    f.w -= strlen (cc->neg_prefix) + strlen (cc->neg_suffix) - 1;
+    f.w -= fmt_neg_affix_width (style) - 1;
   else
     /* Convert -0 to +0. */
     number = fabs (number);
@@ -996,8 +983,9 @@ try_CCx (char *dst, const struct fmt_spec *fp, double number)
   /* Postprocess back into buf. */
   cp = buf;
   if (number < 0)
-    cp = stpcpy (cp, cc->neg_prefix);
-  cp = stpcpy (cp, cc->prefix);
+    cp = mempcpy (cp, ss_data (style->neg_prefix),
+                  ss_length (style->neg_prefix));
+  cp = mempcpy (cp, ss_data (style->prefix), ss_length (style->prefix));
   {
     char *bp = buf2;
     while (*bp == ' ')
@@ -1010,9 +998,10 @@ try_CCx (char *dst, const struct fmt_spec *fp, double number)
     memcpy (cp, bp, f.w - (bp - buf2));
     cp += f.w - (bp - buf2);
   }
-  cp = stpcpy (cp, cc->suffix);
+  cp = mempcpy (cp, ss_data (style->suffix), ss_length (style->suffix));
   if (number < 0)
-    cp = stpcpy (cp, cc->neg_suffix);
+    cp = mempcpy (cp, ss_data (style->neg_suffix),
+                  ss_length (style->neg_suffix));
 
   /* Copy into dst. */
   assert (cp - buf <= fp->w);
@@ -1065,6 +1054,7 @@ try_F (char *dst, const struct fmt_spec *fp, double number)
                  avoids wasting too much time formatting more
                  decimal places on the first try. */
               int result = format_and_round (dst, number, fp, fp->d + 2);
+
               if (result >= 0)
                 return result;
 
@@ -1145,7 +1135,7 @@ format_and_round (char *dst, double number, const struct fmt_spec *fp,
          digits of the fraction.
          Right-justify the integer part and sign. */
       dst[0] = ' ';
-      memcpy (dst + 1, buf, fp->w);
+      memcpy (dst + 1, buf, fp->w - 1);
       return 1;
     }