Change license from GPLv2+ to GPLv3+.
[pspp-builds.git] / src / data / format.c
index 3ce41ee0a3089cd9940b9ed048eed6049c14354b..069ec3afba4b5b6f334d78d0d2407a553ac72f62 100644 (file)
@@ -1,21 +1,18 @@
-/* PSPP - computes sample statistics.
+/* PSPP - a program for statistical analysis.
    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
-   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>
 
@@ -26,6 +23,7 @@
 
 #include <data/identifier.h>
 #include <data/settings.h>
+#include <data/value.h>
 #include <data/variable.h>
 #include <libpspp/assertion.h>
 #include <libpspp/compiler.h>
@@ -60,10 +58,15 @@ fmt_init (void)
     }
 }
 
+static struct fmt_number_style *styles[FMT_NUMBER_OF_FORMATS];
+
 /* Deinitialize the format module. */
 void
 fmt_done (void)
 {
+  int t;
+  for (t = 0 ; t < FMT_NUMBER_OF_FORMATS ; ++t )
+         fmt_number_style_destroy (styles[t]);
 }
 
 /* Returns an input format specification with type TYPE, width W,
@@ -295,15 +298,15 @@ fmt_check_output (const struct fmt_spec *spec)
    TYPE and returns true if so.  Otherwise returns false and
    emits an error message. */
 bool
-fmt_check_type_compat (const struct fmt_spec *format, int var_type)
+fmt_check_type_compat (const struct fmt_spec *format, enum var_type var_type)
 {
-  assert (var_type == NUMERIC || var_type == ALPHA);
-  if ((var_type == ALPHA) != (fmt_is_string (format->type) != 0))
+  assert (var_type_is_valid (var_type));
+  if ((var_type == VAR_STRING) != (fmt_is_string (format->type) != 0))
     {
       char str[FMT_STRING_LEN_MAX + 1];
       msg (SE, _("%s variables are not compatible with %s format %s."),
-           var_type == ALPHA ? _("String") : _("Numeric"),
-           var_type == ALPHA ? _("numeric") : _("string"),
+           var_type == VAR_STRING ? _("String") : _("Numeric"),
+           var_type == VAR_STRING ? _("numeric") : _("string"),
            fmt_to_string (format, str));
       return false;
     }
@@ -316,7 +319,7 @@ fmt_check_type_compat (const struct fmt_spec *format, int var_type)
 bool
 fmt_check_width_compat (const struct fmt_spec *format, int width)
 {
-  if (!fmt_check_type_compat (format, width != 0 ? ALPHA : NUMERIC))
+  if (!fmt_check_type_compat (format, var_type_from_width (width)))
     return false;
   if (fmt_var_width (format) != width)
     {
@@ -357,6 +360,14 @@ fmt_to_string (const struct fmt_spec *f, char buffer[FMT_STRING_LEN_MAX + 1])
               "%s%d", fmt_name (f->type), f->w);
   return buffer;
 }
+
+/* Returns true if A and B are identical formats,
+   false otherwise. */
+bool
+fmt_equal (const struct fmt_spec *a, const struct fmt_spec *b)
+{
+  return a->type == b->type && a->w == b->w && a->d == b->d;
+}
 \f
 /* Describes a display format. */
 struct fmt_desc
@@ -456,7 +467,7 @@ fmt_max_output_decimals (enum fmt_type type, int width)
 int
 fmt_step_width (enum fmt_type type)
 {
-  return fmt_get_category (type) & FMT_CAT_HEXADECIMAL ? 2 : 1;
+  return fmt_get_category (type) == FMT_CAT_HEXADECIMAL ? 2 : 1;
 }
 
 /* Returns true if TYPE is used for string fields,
@@ -464,7 +475,7 @@ fmt_step_width (enum fmt_type type)
 bool
 fmt_is_string (enum fmt_type type)
 {
-  return fmt_get_category (type) & FMT_CAT_STRING;
+  return fmt_get_category (type) == FMT_CAT_STRING;
 }
 
 /* Returns true if TYPE is used for numeric fields,
@@ -481,7 +492,7 @@ fmt_is_numeric (enum fmt_type type)
    category.  Thus, the return value may be tested for equality
    or compared bitwise against a mask of FMT_CAT_* values. */
 enum fmt_category
-fmt_get_category (enum fmt_type type) 
+fmt_get_category (enum fmt_type type)
 {
   return get_fmt_desc (type)->category;
 }
@@ -491,10 +502,19 @@ fmt_get_category (enum fmt_type type)
 enum fmt_type
 fmt_input_to_output (enum fmt_type type)
 {
-  enum fmt_category category = fmt_get_category (type);
-  return (category & FMT_CAT_STRING ? FMT_A
-          : category & (FMT_CAT_BASIC | FMT_CAT_HEXADECIMAL) ? FMT_F
-          : type);
+  switch (fmt_get_category (type))
+    {
+    case FMT_CAT_STRING:
+      return FMT_A;
+
+    case FMT_CAT_LEGACY:
+    case FMT_CAT_BINARY:
+    case FMT_CAT_HEXADECIMAL:
+      return FMT_F;
+
+    default:
+      return type;
+    }
 }
 
 /* Returns the SPSS format type corresponding to the given PSPP
@@ -503,7 +523,7 @@ int
 fmt_to_io (enum fmt_type type)
 {
   return get_fmt_desc (type)->io;
-};
+}
 
 /* Determines the PSPP format corresponding to the given SPSS
    format type.  If successful, sets *FMT_TYPE to the PSPP format
@@ -551,19 +571,49 @@ fmt_date_template (enum fmt_type type)
     case FMT_QYR:
       return "q Q yy";
     case FMT_MOYR:
-      return "mmm yy";
+      return "mmmXyy";
     case FMT_WKYR:
       return "ww WK yy";
     case FMT_DATETIME:
       return "dd-mmm-yyyy HH:MM";
     case FMT_TIME:
-      return "h:MM";
+      return "H:MM";
     case FMT_DTIME:
       return "D HH:MM";
     default:
       NOT_REACHED ();
     }
 }
+
+/* Returns a string of the form "$#,###.##" according to FMT,
+   which must be of type FMT_DOLLAR.  The caller must free the
+   string. */
+char *
+fmt_dollar_template (const struct fmt_spec *fmt)
+{
+  struct string s = DS_EMPTY_INITIALIZER;
+  int c;
+
+  assert (fmt->type == FMT_DOLLAR);
+
+  ds_put_char (&s, '$');
+  for (c = MAX (fmt->w - fmt->d - 1, 0); c > 0; )
+    {
+      ds_put_char (&s, '#');
+      if (--c % 4 == 0 && c > 0)
+        {
+          ds_put_char (&s, fmt_grouping_char (fmt->type));
+          --c;
+        }
+    }
+  if (fmt->d > 0)
+    {
+      ds_put_char (&s, fmt_decimal_char (fmt->type));
+      ds_put_char_multiple (&s, '#', fmt->d);
+    }
+
+  return ds_cstr (&s);
+}
 \f
 /* Returns true if TYPE is a valid format type,
    false otherwise. */
@@ -736,7 +786,6 @@ max_digits_for_bytes (int bytes)
   return map[bytes - 1];
 }
 \f
-static struct fmt_number_style *styles[FMT_NUMBER_OF_FORMATS];
 
 /* Creates and returns a new struct fmt_number_style,
    initializing all affixes to empty strings. */
@@ -886,22 +935,6 @@ fmt_set_decimal (char decimal)
   init_style (FMT_CCE, "", "", decimal, grouping);
 }
 \f
-/* Returns true if M is a valid variable measurement level,
-   false otherwise. */
-bool
-measure_is_valid (enum measure m)
-{
-  return m > 0 && m < n_MEASURES;
-}
-
-/* Returns true if A is a valid alignment,
-   false otherwise. */
-bool
-alignment_is_valid (enum alignment a)
-{
-  return a < n_ALIGN;
-}
-\f
 /* Returns the struct fmt_desc for the given format TYPE. */
 static const struct fmt_desc *
 get_fmt_desc (enum fmt_type type)