Remove "Written by Ben Pfaff <blp@gnu.org>" lines everywhere.
[pspp-builds.git] / src / language / xforms / recode.c
index b89071a3f3ff11b88bda381f339a9c8c576fae63..4fdb57194b87aefc3677cceac4a6cc6a26549d7e 100644 (file)
@@ -1,6 +1,5 @@
 /* PSPP - computes sample statistics.
    Copyright (C) 1997-9, 2000 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
    02110-1301, USA. */
 
 #include <config.h>
-#include <libpspp/message.h>
+
 #include <ctype.h>
 #include <math.h>
 #include <stdlib.h>
-#include <libpspp/alloc.h>
+
 #include <data/case.h>
-#include <language/command.h>
-#include <libpspp/compiler.h>
 #include <data/data-in.h>
 #include <data/dictionary.h>
-#include <libpspp/message.h>
+#include <data/procedure.h>
+#include <data/transformations.h>
+#include <data/variable.h>
+#include <language/command.h>
 #include <language/lexer/lexer.h>
+#include <language/lexer/variable-parser.h>
+#include <language/lexer/range-parser.h>
+#include <libpspp/alloc.h>
+#include <libpspp/assertion.h>
+#include <libpspp/compiler.h>
 #include <libpspp/magic.h>
+#include <libpspp/message.h>
+#include <libpspp/message.h>
 #include <libpspp/pool.h>
-#include <language/lexer/range-parser.h>
 #include <libpspp/str.h>
-#include <data/variable.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -52,18 +57,25 @@ enum map_in_type
     MAP_CONVERT                        /* "123" => 123. */
   };
 
+/* A value involved in a RECODE mapping. */
+union recode_value 
+  {
+    double f;                   /* Numeric. */
+    char *c;                    /* Short or long string. */
+  };
+
 /* Describes input values to be mapped. */
 struct map_in
   {
     enum map_in_type type;      /* One of MAP_*. */
-    union value x, y;           /* Source values. */
+    union recode_value x, y;    /* Source values. */
   };
 
 /* Describes the value used as output from a mapping. */
 struct map_out 
   {
     bool copy_input;            /* If true, copy input to output. */
-    union value value;          /* If copy_input false, recoded value. */
+    union recode_value value;   /* If copy_input false, recoded value. */
     int width;                  /* If copy_input false, output value width. */ 
   };
 
@@ -95,27 +107,27 @@ struct recode_trns
     size_t map_cnt;             /* Number of mappings. */
   };
 
-static bool parse_src_vars (struct recode_trns *);
-static bool parse_mappings (struct recode_trns *);
-static bool parse_dst_vars (struct recode_trns *);
+static bool parse_src_vars (struct lexer *, struct recode_trns *, const struct dictionary *dict);
+static bool parse_mappings (struct lexer *, struct recode_trns *);
+static bool parse_dst_vars (struct lexer *, struct recode_trns *, const struct dictionary *dict);
 
 static void add_mapping (struct recode_trns *,
                          size_t *map_allocated, const struct map_in *);
 
-static bool parse_map_in (struct map_in *, struct pool *,
+static bool parse_map_in (struct lexer *lexer, struct map_in *, struct pool *,
                           enum var_type src_type, size_t max_src_width);
 static void set_map_in_generic (struct map_in *, enum map_in_type);
 static void set_map_in_num (struct map_in *, enum map_in_type, double, double);
 static void set_map_in_str (struct map_in *, struct pool *,
                             const struct string *, size_t width);
 
-static bool parse_map_out (struct pool *, struct map_out *);
+static bool parse_map_out (struct lexer *lexer, struct pool *, struct map_out *);
 static void set_map_out_num (struct map_out *, double);
 static void set_map_out_str (struct map_out *, struct pool *,
                              const struct string *);
 
 static void enlarge_dst_widths (struct recode_trns *);
-static void create_dst_vars (struct recode_trns *);
+static void create_dst_vars (struct recode_trns *, struct dictionary *);
 
 static trns_proc_func recode_trns_proc;
 static trns_free_func recode_trns_free;
@@ -124,7 +136,7 @@ static trns_free_func recode_trns_free;
 
 /* Parses the RECODE transformation. */
 int
-cmd_recode (void)
+cmd_recode (struct lexer *lexer, struct dataset *ds)
 {
   do
     {
@@ -134,9 +146,9 @@ cmd_recode (void)
       /* Parse source variable names,
          then input to output mappings,
          then destintation variable names. */
-      if (!parse_src_vars (trns)
-          || !parse_mappings (trns)
-          || !parse_dst_vars (trns))
+      if (!parse_src_vars (lexer, trns, dataset_dict (ds) )
+          || !parse_mappings (lexer, trns)
+          || !parse_dst_vars (lexer, trns, dataset_dict (ds)))
         {
           recode_trns_free (trns);
           return CMD_FAILURE;
@@ -144,34 +156,36 @@ cmd_recode (void)
 
       /* Ensure that all the output strings are at least as wide
          as the widest destination variable. */
-      if (trns->dst_type == ALPHA)
+      if (trns->dst_type == VAR_STRING)
         enlarge_dst_widths (trns);
 
       /* Create destination variables, if needed.
          This must be the final step; otherwise we'd have to
          delete destination variables on failure. */
       if (trns->src_vars != trns->dst_vars)
-        create_dst_vars (trns);
+        create_dst_vars (trns, dataset_dict (ds));
 
       /* Done. */
-      add_transformation (recode_trns_proc, recode_trns_free, trns);
+      add_transformation (ds, 
+                         recode_trns_proc, recode_trns_free, trns);
     }
-  while (lex_match ('/'));
+  while (lex_match (lexer, '/'));
   
-  return lex_end_of_command ();
+  return lex_end_of_command (lexer);
 }
 
 /* Parses a set of variables to recode into TRNS->src_vars and
    TRNS->var_cnt.  Sets TRNS->src_type.  Returns true if
    successful, false on parse error. */
 static bool
-parse_src_vars (struct recode_trns *trns) 
+parse_src_vars (struct lexer *lexer, 
+               struct recode_trns *trns, const struct dictionary *dict) 
 {
-  if (!parse_variables (default_dict, &trns->src_vars, &trns->var_cnt,
+  if (!parse_variables (lexer, dict, &trns->src_vars, &trns->var_cnt,
                         PV_SAME_TYPE))
     return false;
   pool_register (trns->pool, free, trns->src_vars);
-  trns->src_type = trns->src_vars[0]->type;
+  trns->src_type = var_get_type (trns->src_vars[0]);
   return true;
 }
 
@@ -179,7 +193,7 @@ parse_src_vars (struct recode_trns *trns)
    into TRNS->mappings and TRNS->map_cnt.  Sets TRNS->dst_type.
    Returns true if successful, false on parse error. */
 static bool
-parse_mappings (struct recode_trns *trns) 
+parse_mappings (struct lexer *lexer, struct recode_trns *trns) 
 {
   size_t max_src_width;
   size_t map_allocated;
@@ -187,10 +201,10 @@ parse_mappings (struct recode_trns *trns)
   size_t i;
   
   /* Find length of longest source variable. */
-  max_src_width = trns->src_vars[0]->width;
+  max_src_width = var_get_width (trns->src_vars[0]);
   for (i = 1; i < trns->var_cnt; i++) 
     {
-      size_t var_width = trns->src_vars[i]->width;
+      size_t var_width = var_get_width (trns->src_vars[i]);
       if (var_width > max_src_width)
         max_src_width = var_width;
     }
@@ -200,13 +214,13 @@ parse_mappings (struct recode_trns *trns)
   trns->map_cnt = 0;
   map_allocated = 0;
   have_dst_type = false;
-  if (!lex_force_match ('('))
+  if (!lex_force_match (lexer, '('))
     return false;
   do
     {
       enum var_type dst_type;
 
-      if (!lex_match_id ("CONVERT")) 
+      if (!lex_match_id (lexer, "CONVERT")) 
         {
           struct map_out out;
           size_t first_map_idx;
@@ -218,17 +232,17 @@ parse_mappings (struct recode_trns *trns)
           do
             {
               struct map_in in;
-              if (!parse_map_in (&in, trns->pool,
+              if (!parse_map_in (lexer, &in, trns->pool,
                                  trns->src_type, max_src_width))
                 return false;
               add_mapping (trns, &map_allocated, &in);
-              lex_match (',');
+              lex_match (lexer, ',');
             }
-          while (!lex_match ('='));
+          while (!lex_match (lexer, '='));
 
-          if (!parse_map_out (trns->pool, &out))
+          if (!parse_map_out (lexer, trns->pool, &out))
             return false;
-          dst_type = out.width == 0 ? NUMERIC : ALPHA;
+          dst_type = var_type_from_width (out.width);
           if (have_dst_type && dst_type != trns->dst_type)
             {
               msg (SE, _("Inconsistent target variable types.  "
@@ -247,9 +261,9 @@ parse_mappings (struct recode_trns *trns)
           set_map_in_generic (&in, MAP_CONVERT);
           add_mapping (trns, &map_allocated, &in);
               
-          dst_type = NUMERIC;
-          if (trns->src_type != ALPHA
-              || (have_dst_type && trns->dst_type != NUMERIC)) 
+          dst_type = VAR_NUMERIC;
+          if (trns->src_type != VAR_STRING
+              || (have_dst_type && trns->dst_type != VAR_NUMERIC)) 
             {
               msg (SE, _("CONVERT requires string input values and "
                          "numeric output values."));
@@ -259,10 +273,10 @@ parse_mappings (struct recode_trns *trns)
       trns->dst_type = dst_type;
       have_dst_type = true;
 
-      if (!lex_force_match (')'))
+      if (!lex_force_match (lexer, ')'))
         return false; 
     }
-  while (lex_match ('('));
+  while (lex_match (lexer, '('));
 
   return true;
 }
@@ -273,31 +287,31 @@ parse_mappings (struct recode_trns *trns)
    be provided in MAX_SRC_WIDTH.  Returns true if successful,
    false on parse error. */
 static bool
-parse_map_in (struct map_in *in, struct pool *pool,
+parse_map_in (struct lexer *lexer, struct map_in *in, struct pool *pool,
               enum var_type src_type, size_t max_src_width)
 {
-  if (lex_match_id ("ELSE"))
+  if (lex_match_id (lexer, "ELSE"))
     set_map_in_generic (in, MAP_ELSE);
-  else if (src_type == NUMERIC)
+  else if (src_type == VAR_NUMERIC)
     {
-      if (lex_match_id ("MISSING"))
+      if (lex_match_id (lexer, "MISSING"))
         set_map_in_generic (in, MAP_MISSING);
-      else if (lex_match_id ("SYSMIS"))
+      else if (lex_match_id (lexer, "SYSMIS"))
         set_map_in_generic (in, MAP_SYSMIS);
       else 
         {
           double x, y;
-          if (!parse_num_range (&x, &y, NULL))
+          if (!parse_num_range (lexer, &x, &y, NULL))
             return false;
           set_map_in_num (in, x == y ? MAP_SINGLE : MAP_RANGE, x, y);
         }
     }
   else
     {
-      if (!lex_force_string ())
+      if (!lex_force_string (lexer))
         return false;
-      set_map_in_str (in, pool, &tokstr, max_src_width);
-      lex_get ();
+      set_map_in_str (in, pool, lex_tokstr (lexer), max_src_width);
+      lex_get (lexer);
     }
 
   return true;
@@ -351,25 +365,25 @@ set_map_in_str (struct map_in *in, struct pool *pool,
 /* Parses a mapping output value into OUT, allocating memory from
    POOL.  Returns true if successful, false on parse error. */
 static bool
-parse_map_out (struct pool *pool, struct map_out *out)
+parse_map_out (struct lexer *lexer, struct pool *pool, struct map_out *out)
 {
-  if (lex_is_number ())
+  if (lex_is_number (lexer))
     {
-      set_map_out_num (out, lex_number ());
-      lex_get ();
+      set_map_out_num (out, lex_number (lexer));
+      lex_get (lexer);
     }
-  else if (lex_match_id ("SYSMIS"))
+  else if (lex_match_id (lexer, "SYSMIS"))
     set_map_out_num (out, SYSMIS);
-  else if (token == T_STRING)
+  else if (lex_token (lexer) == T_STRING)
     {
-      set_map_out_str (out, pool, &tokstr);
-      lex_get ();
+      set_map_out_str (out, pool, lex_tokstr (lexer));
+      lex_get (lexer);
     }
-  else if (lex_match_id ("COPY"))
+  else if (lex_match_id (lexer, "COPY"))
     out->copy_input = true;
   else 
     {
-      lex_error (_("expecting output value"));
+      lex_error (lexer, _("expecting output value"));
       return false;
     }
   return true; 
@@ -401,16 +415,18 @@ set_map_out_str (struct map_out *out, struct pool *pool,
 /* Parses a set of target variables into TRNS->dst_vars and
    TRNS->dst_names. */
 static bool
-parse_dst_vars (struct recode_trns *trns) 
+parse_dst_vars (struct lexer *lexer, struct recode_trns *trns, 
+               const struct dictionary *dict) 
 {
   size_t i;
   
-  if (lex_match_id ("INTO"))
+  if (lex_match_id (lexer, "INTO"))
     {
       size_t name_cnt;
       size_t i;
 
-      if (!parse_mixed_vars_pool (trns->pool, &trns->dst_names, &name_cnt,
+      if (!parse_mixed_vars_pool (lexer, dict, trns->pool, 
+                                 &trns->dst_names, &name_cnt,
                                   PV_NONE))
         return false;
 
@@ -428,9 +444,8 @@ parse_dst_vars (struct recode_trns *trns)
       for (i = 0; i < trns->var_cnt; i++)
         {
           struct variable *v;
-          v = trns->dst_vars[i] = dict_lookup_var (default_dict,
-                                                  trns->dst_names[i]);
-          if (v == NULL && trns->dst_type == ALPHA) 
+          v = trns->dst_vars[i] = dict_lookup_var (dict, trns->dst_names[i]);
+          if (v == NULL && trns->dst_type == VAR_STRING) 
             {
               msg (SE, _("There is no variable named "
                          "%s.  (All string variables specified "
@@ -449,8 +464,8 @@ parse_dst_vars (struct recode_trns *trns)
         {
           msg (SE, _("INTO is required with %s input values "
                      "and %s output values."),
-               var_type_adj (trns->src_type),
-               var_type_adj (trns->dst_type));
+               trns->src_type == VAR_NUMERIC ? _("numeric") : _("string"),
+               trns->dst_type == VAR_NUMERIC ? _("numeric") : _("string"));
           return false;
         }
     }
@@ -458,13 +473,13 @@ parse_dst_vars (struct recode_trns *trns)
   for (i = 0; i < trns->var_cnt; i++)
     {
       struct variable *v = trns->dst_vars[i];
-      if (v != NULL && v->type != trns->dst_type)
+      if (v != NULL && var_get_type (v) != trns->dst_type)
         {
           msg (SE, _("Type mismatch.  Cannot store %s data in "
                      "%s variable %s."),
-               trns->dst_type == ALPHA ? _("string") : _("numeric"),
-               v->type == ALPHA ? _("string") : _("numeric"),
-               v->name);
+               trns->dst_type == VAR_STRING ? _("string") : _("numeric"),
+               var_is_alpha (v) ? _("string") : _("numeric"),
+               var_get_name (v));
           return false;
         }
     }
@@ -484,8 +499,8 @@ enlarge_dst_widths (struct recode_trns *trns)
   for (i = 0; i < trns->var_cnt; i++)
     {
       struct variable *v = trns->dst_vars[i];
-      if (v->width > max_dst_width)
-        max_dst_width = v->width;
+      if (var_get_width (v) > max_dst_width)
+        max_dst_width = var_get_width (v);
     }
 
   for (i = 0; i < trns->map_cnt; i++)
@@ -502,7 +517,7 @@ enlarge_dst_widths (struct recode_trns *trns)
 
 /* Creates destination variables that don't already exist. */
 static void
-create_dst_vars (struct recode_trns *trns)
+create_dst_vars (struct recode_trns *trns, struct dictionary *dict)
 {
   size_t i;
 
@@ -511,10 +526,10 @@ create_dst_vars (struct recode_trns *trns)
       struct variable **var = &trns->dst_vars[i];
       const char *name = trns->dst_names[i];
           
-      *var = dict_lookup_var (default_dict, name);
+      *var = dict_lookup_var (dict, name);
       if (*var == NULL)
-        *var = dict_create_var_assert (default_dict, name, 0);
-      assert ((*var)->type == trns->dst_type);
+        *var = dict_create_var_assert (dict, name, 0);
+      assert (var_get_type (*var) == trns->dst_type);
     }
 }
 \f
@@ -539,7 +554,7 @@ find_src_numeric (struct recode_trns *trns, double value, struct variable *v)
           match = value == in->x.f;
           break;
         case MAP_MISSING:
-          match = mv_is_num_user_missing (&v->miss, value);
+          match = var_is_num_user_missing (v, value);
           break;
         case MAP_RANGE:
           match = value >= in->x.f && value <= in->y.f;
@@ -548,7 +563,7 @@ find_src_numeric (struct recode_trns *trns, double value, struct variable *v)
           match = true;
           break;
         default:
-          abort ();
+          NOT_REACHED ();
         }
 
       if (match)
@@ -581,21 +596,16 @@ find_src_string (struct recode_trns *trns, const char *value, int width)
           break;
         case MAP_CONVERT:
           {
-            struct data_in di;
-
-            di.s = value;
-            di.e = value + width;
-            di.v = &out->value;
-            di.flags = DI_IGNORE_ERROR;
-            di.f1 = di.f2 = 0;
-            di.format.type = FMT_F;
-            di.format.w = width;
-            di.format.d = 0;
-            match = data_in (&di);
+            union value uv;
+
+            msg_disable ();
+            match = data_in (ss_buffer (value, width), FMT_F, 0, 0, &uv, 0);
+            msg_enable ();
+            out->value.f = uv.f;
             break;
           }
         default:
-          abort ();
+          NOT_REACHED ();
         }
 
       if (match)
@@ -607,7 +617,7 @@ find_src_string (struct recode_trns *trns, const char *value, int width)
 
 /* Performs RECODE transformation. */
 static int
-recode_trns_proc (void *trns_, struct ccase *c, int case_idx UNUSED)
+recode_trns_proc (void *trns_, struct ccase *c, casenumber case_idx UNUSED)
 {
   struct recode_trns *trns = trns_;
   size_t i;
@@ -617,17 +627,17 @@ recode_trns_proc (void *trns_, struct ccase *c, int case_idx UNUSED)
       struct variable *src_var = trns->src_vars[i];
       struct variable *dst_var = trns->dst_vars[i];
 
-      const union value *src_data = case_data (c, src_var->fv);
-      union value *dst_data = case_data_rw (c, dst_var->fv);
+      const union value *src_data = case_data (c, src_var);
+      union value *dst_data = case_data_rw (c, dst_var);
 
       const struct map_out *out;
 
-      if (trns->src_type == NUMERIC) 
+      if (trns->src_type == VAR_NUMERIC) 
           out = find_src_numeric (trns, src_data->f, src_var);
       else
-          out = find_src_string (trns, src_data->s, src_var->width);
+          out = find_src_string (trns, src_data->s, var_get_width (src_var));
 
-      if (trns->dst_type == NUMERIC) 
+      if (trns->dst_type == VAR_NUMERIC) 
         {
           if (out != NULL)
             dst_data->f = !out->copy_input ? out->value.f : src_data->f; 
@@ -639,13 +649,13 @@ recode_trns_proc (void *trns_, struct ccase *c, int case_idx UNUSED)
           if (out != NULL)
             {
               if (!out->copy_input) 
-                memcpy (dst_data->s, out->value.c, dst_var->width); 
+                memcpy (dst_data->s, out->value.c, var_get_width (dst_var)); 
               else if (trns->src_vars != trns->dst_vars)
-                buf_copy_rpad (dst_data->s, dst_var->width,
-                               src_data->s, src_var->width); 
+                buf_copy_rpad (dst_data->s, var_get_width (dst_var),
+                               src_data->s, var_get_width (src_var)); 
             }
           else if (trns->src_vars != trns->dst_vars)
-            memset (dst_data->s, ' ', dst_var->width);
+            memset (dst_data->s, ' ', var_get_width (dst_var));
         }
     }