* recode.c (enlarge_dst_widths): Source isn't null-terminated, so
[pspp-builds.git] / src / language / xforms / recode.c
index 7fc187a7cf35dcc4137d388480119543ca88bf40..e7fa44d3f4e2d73a2ae0ad05b5ea10cd8c999129 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
@@ -98,8 +97,8 @@ struct recode_trns
     enum var_type dst_type;     /* dst_vars[*]->type. */
 
     /* Variables. */
-    struct variable **src_vars;        /* Source variables. */
-    struct variable **dst_vars;        /* Destination variables. */
+    const struct variable **src_vars;  /* Source variables. */
+    const struct variable **dst_vars;  /* Destination variables. */
     char **dst_names;          /* Name of dest variables, if they're new. */
     size_t var_cnt;             /* Number of variables. */
 
@@ -157,7 +156,7 @@ cmd_recode (struct lexer *lexer, struct dataset *ds)
 
       /* 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.
@@ -182,11 +181,11 @@ static bool
 parse_src_vars (struct lexer *lexer, 
                struct recode_trns *trns, const struct dictionary *dict) 
 {
-  if (!parse_variables (lexer, dict, &trns->src_vars, &trns->var_cnt,
+  if (!parse_variables_const (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;
 }
 
@@ -202,10 +201,10 @@ parse_mappings (struct lexer *lexer, 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;
     }
@@ -243,7 +242,7 @@ parse_mappings (struct lexer *lexer, struct recode_trns *trns)
 
           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.  "
@@ -262,9 +261,9 @@ parse_mappings (struct lexer *lexer, 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."));
@@ -293,7 +292,7 @@ parse_map_in (struct lexer *lexer, struct map_in *in, struct pool *pool,
 {
   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 (lexer, "MISSING"))
         set_map_in_generic (in, MAP_MISSING);
@@ -444,9 +443,9 @@ parse_dst_vars (struct lexer *lexer, struct recode_trns *trns,
                                     trns->var_cnt, sizeof *trns->dst_vars);
       for (i = 0; i < trns->var_cnt; i++)
         {
-          struct variable *v;
+          const struct variable *v;
           v = trns->dst_vars[i] = dict_lookup_var (dict, trns->dst_names[i]);
-          if (v == NULL && trns->dst_type == ALPHA
+          if (v == NULL && trns->dst_type == VAR_STRING
             {
               msg (SE, _("There is no variable named "
                          "%s.  (All string variables specified "
@@ -465,22 +464,22 @@ parse_dst_vars (struct lexer *lexer, 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;
         }
     }
 
   for (i = 0; i < trns->var_cnt; i++)
     {
-      struct variable *v = trns->dst_vars[i];
-      if (v != NULL && v->type != trns->dst_type)
+      const struct variable *v = trns->dst_vars[i];
+      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;
         }
     }
@@ -499,9 +498,9 @@ enlarge_dst_widths (struct recode_trns *trns)
   max_dst_width = 0;
   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;
+      const struct variable *v = trns->dst_vars[i];
+      if (var_get_width (v) > max_dst_width)
+        max_dst_width = var_get_width (v);
     }
 
   for (i = 0; i < trns->map_cnt; i++)
@@ -510,7 +509,7 @@ enlarge_dst_widths (struct recode_trns *trns)
       if (!out->copy_input && out->width < max_dst_width) 
         {
           char *s = pool_alloc_unaligned (trns->pool, max_dst_width + 1);
-          str_copy_rpad (s, max_dst_width + 1, out->value.c);
+          buf_copy_rpad (s, max_dst_width + 1, out->value.c, out->width);
           out->value.c = s;
         }
     }
@@ -524,13 +523,13 @@ create_dst_vars (struct recode_trns *trns, struct dictionary *dict)
 
   for (i = 0; i < trns->var_cnt; i++) 
     {
-      struct variable **var = &trns->dst_vars[i];
+      const struct variable **var = &trns->dst_vars[i];
       const char *name = trns->dst_names[i];
           
       *var = dict_lookup_var (dict, name);
       if (*var == NULL)
         *var = dict_create_var_assert (dict, name, 0);
-      assert ((*var)->type == trns->dst_type);
+      assert (var_get_type (*var) == trns->dst_type);
     }
 }
 \f
@@ -539,7 +538,7 @@ create_dst_vars (struct recode_trns *trns, struct dictionary *dict)
 /* Returns the output mapping in TRNS for an input of VALUE on
    variable V, or a null pointer if there is no mapping. */
 static const struct map_out *
-find_src_numeric (struct recode_trns *trns, double value, struct variable *v)
+find_src_numeric (struct recode_trns *trns, double value, const struct variable *v)
 {
   struct mapping *m;
 
@@ -555,11 +554,14 @@ 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_missing (v, value, MV_ANY);
           break;
         case MAP_RANGE:
           match = value >= in->x.f && value <= in->y.f;
           break;
+        case MAP_SYSMIS:
+          match = value == SYSMIS;
+          break;
         case MAP_ELSE:
           match = true;
           break;
@@ -598,17 +600,10 @@ find_src_string (struct recode_trns *trns, const char *value, int width)
         case MAP_CONVERT:
           {
             union value uv;
-            struct data_in di;
-
-            di.s = value;
-            di.e = value + width;
-            di.v = &uv;
-            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);
+
+            msg_disable ();
+            match = data_in (ss_buffer (value, width), FMT_F, 0, 0, &uv, 0);
+            msg_enable ();
             out->value.f = uv.f;
             break;
           }
@@ -632,20 +627,20 @@ recode_trns_proc (void *trns_, struct ccase *c, casenumber case_idx UNUSED)
 
   for (i = 0; i < trns->var_cnt; i++) 
     {
-      struct variable *src_var = trns->src_vars[i];
-      struct variable *dst_var = trns->dst_vars[i];
+      const struct variable *src_var = trns->src_vars[i];
+      const 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) 
-          out = find_src_numeric (trns, src_data->f, src_var);
+      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; 
@@ -657,13 +652,13 @@ recode_trns_proc (void *trns_, struct ccase *c, casenumber 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));
         }
     }