DO IF, LOOP cleanup.
[pspp] / src / recode.c
index 34342a1e185895df394e55f17ab48e127fc491b1..394e9be14fbd0ef45b249d65c6de6d52a84c3d16 100644 (file)
 
    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., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA. */
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
 
 #include <config.h>
-#include <assert.h>
+#include "error.h"
 #include <ctype.h>
 #include <math.h>
 #include <stdlib.h>
 #include "alloc.h"
+#include "case.h"
 #include "command.h"
+#include "dictionary.h"
 #include "error.h"
 #include "lexer.h"
 #include "magic.h"
 #include "str.h"
 #include "var.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
 \f
 /* Definitions. */
 
@@ -64,19 +69,18 @@ struct rcd_var
 
     struct variable *src;      /* Source variable. */
     struct variable *dest;     /* Destination variable. */
-    char dest_name[9];         /* Name of dest variable if we're creating it. */
+    char dest_name[LONG_NAME_LEN + 1];         /* Name of dest variable if we're creating it. */
 
     int has_sysmis;            /* Do we recode for SYSMIS? */
     union value sysmis;                /* Coding for SYSMIS (if src is numeric). */
 
     struct coding *map;                /* Coding for other values. */
-    int nmap, mmap;            /* Length of map, max capacity of map. */
+    size_t nmap, mmap;         /* Length of map, max capacity of map. */
   };
 
 /* RECODE transformation. */
 struct recode_trns
   {
-    struct trns_header h;
     struct rcd_var *codings;
   };
 
@@ -100,12 +104,12 @@ struct recode_trns
 #define RCD_MISC_MISSING       0100u   /* Encountered MISSING or SYSMIS in
                                           this input spec. */
 
-static int parse_dest_spec (struct rcd_var * rcd, union value *v,
+static int parse_dest_spec (struct rcd_var *rcd, union value *v,
                            size_t *max_dst_width);
-static int parse_src_spec (struct rcd_var * rcd, int type, size_t max_src_width);
+static int parse_src_spec (struct rcd_var *rcd, int type, size_t max_src_width);
 static trns_proc_func recode_trns_proc;
 static trns_free_func recode_trns_free;
-static double convert_to_double (char *, int);
+static double convert_to_double (const char *, int);
 \f
 /* Parser. */
 
@@ -113,7 +117,7 @@ static double convert_to_double (char *, int);
 int
 cmd_recode (void)
 {
-  int i;
+  size_t i;
 
   /* Transformation that we're constructing. */
   struct rcd_var *rcd;
@@ -140,9 +144,7 @@ cmd_recode (void)
 
   /* Variables in the current part of the recoding. */
   struct variable **v;
-  int nv;
-
-  lex_match_id ("RECODE");
+  size_t nv;
 
   /* Parses each specification between slashes. */
   head = rcd = xmalloc (sizeof *rcd);
@@ -187,7 +189,7 @@ cmd_recode (void)
       for (;;) 
        {
          /* Get the input value (before the `='). */
-         int mark = rcd->nmap;
+         size_t mark = rcd->nmap;
          int code = parse_src_spec (rcd, type, max_src_width);
          if (!code)
            goto lossage;
@@ -234,7 +236,7 @@ cmd_recode (void)
              else
                {
                  for (i = mark; i < rcd->nmap; i++)
-                   rcd->map[i].t.c = xstrdup (output.c);
+                   rcd->map[i].t.c = output.c ? xstrdup (output.c) : NULL;
                  free (output.c);
                }
            }
@@ -268,7 +270,7 @@ cmd_recode (void)
       if (lex_match_id ("INTO"))
        {
          char **names;
-         int nnames;
+         size_t nnames;
 
          int success = 0;
 
@@ -280,10 +282,10 @@ cmd_recode (void)
              for (i = 0; i < nnames; i++)
                free (names[i]);
              free (names);
-             msg (SE, _("%d variable(s) cannot be recoded into "
-                        "%d variable(s).  Specify the same number "
+             msg (SE, _("%u variable(s) cannot be recoded into "
+                        "%u variable(s).  Specify the same number "
                         "of variables as input and output variables."),
-                  nv, nnames);
+                  (unsigned) nv, (unsigned) nnames);
              goto lossage;
            }
 
@@ -295,18 +297,20 @@ cmd_recode (void)
                if (!v)
                  {
                    msg (SE, _("There is no string variable named "
-                        "%s.  (All string variables specified "
-                        "on INTO must already exist.  Use the "
-                        "STRING command to create a string "
-                        "variable.)"), names[i]);
+                               "%s.  (All string variables specified "
+                               "on INTO must already exist.  Use the "
+                               "STRING command to create a string "
+                               "variable.)"),
+                         names[i]);
                    goto INTO_fail;
                  }
                if (v->type != ALPHA)
                  {
                    msg (SE, _("Type mismatch between input and output "
-                        "variables.  Output variable %s is not "
-                        "a string variable, but all the input "
-                        "variables are string variables."), v->name);
+                               "variables.  Output variable %s is not "
+                               "a string variable, but all the input "
+                               "variables are string variables."),
+                         v->name);
                    goto INTO_fail;
                  }
                if (v->width > (int) max_dst_width)
@@ -378,7 +382,7 @@ cmd_recode (void)
                    /* The NULL is only really necessary for the
                       debugging code. */
                    char *repl = xmalloc (max_dst_width + 1);
-                   st_pad_copy (repl, cp->t.c, max_dst_width + 1);
+                   str_copy_rpad (repl, max_dst_width + 1, cp->t.c);
                    free (cp->t.c);
                    cp->t.c = repl;
                  }
@@ -390,14 +394,14 @@ cmd_recode (void)
          
        }
 
+      free (v);
+      v = NULL;
+
       if (!lex_match ('/'))
        break;
       while (rcd->next)
        rcd = rcd->next;
       rcd = rcd->next = xmalloc (sizeof *rcd);
-
-      free (v);
-      v = NULL;
     }
 
   if (token != '.')
@@ -412,7 +416,7 @@ cmd_recode (void)
        rcd->dest = dict_create_var (default_dict, rcd->dest_name, 0);
        if (!rcd->dest)
          {
-           /* FIXME: This can occur if a destname is duplicated.
+           /* FIXME: This can fail if a destname is duplicated.
               We could give an error at parse time but I don't
               care enough. */
            rcd->dest = dict_lookup_var_assert (default_dict, rcd->dest_name);
@@ -420,10 +424,8 @@ cmd_recode (void)
       }
 
   trns = xmalloc (sizeof *trns);
-  trns->h.proc = recode_trns_proc;
-  trns->h.free = recode_trns_free;
   trns->codings = head;
-  add_transformation ((struct trns_header *) trns);
+  add_transformation (recode_trns_proc, recode_trns_free, trns);
 
   return CMD_SUCCESS;
 
@@ -433,19 +435,19 @@ cmd_recode (void)
     struct recode_trns t;
 
     t.codings = head;
-    recode_trns_free ((struct trns_header *) &t);
+    recode_trns_free (&t);
     return CMD_FAILURE;
   }
 }
 
 static int
-parse_dest_spec (struct rcd_var * rcd, union value * v, size_t *max_dst_width)
+parse_dest_spec (struct rcd_var *rcd, union value *v, size_t *max_dst_width)
 {
   int flags;
 
   v->c = NULL;
 
-  if (token == T_NUM)
+  if (lex_is_number ())
     {
       v->f = tokval;
       lex_get ();
@@ -463,7 +465,7 @@ parse_dest_spec (struct rcd_var * rcd, union value * v, size_t *max_dst_width)
       if (toklen > max)
        max = toklen;
       v->c = xmalloc (max + 1);
-      st_pad_copy (v->c, ds_value (&tokstr), max + 1);
+      str_copy_rpad (v->c, max + 1, ds_c_str (&tokstr));
       flags = RCD_DEST_STRING;
       *max_dst_width = max;
       lex_get ();
@@ -510,16 +512,16 @@ parse_dest_spec (struct rcd_var * rcd, union value * v, size_t *max_dst_width)
    but with CONVERT as the keyword; 3 for success but with ELSE as the
    keyword. */
 static int
-parse_src_spec (struct rcd_var * rcd, int type, size_t max_src_width)
+parse_src_spec (struct rcd_var *rcd, int type, size_t max_src_width)
 {
   struct coding *c;
 
   for (;;)
     {
-      if (rcd->nmap >= rcd->mmap - 1)
+      if (rcd->nmap + 1 >= rcd->mmap)
        {
          rcd->mmap += 16;
-         rcd->map = xrealloc (rcd->map, rcd->mmap * sizeof *rcd->map);
+         rcd->map = xnrealloc (rcd->map, rcd->mmap, sizeof *rcd->map);
        }
 
       c = &rcd->map[rcd->nmap];
@@ -540,7 +542,7 @@ parse_src_spec (struct rcd_var * rcd, int type, size_t max_src_width)
                    return 0;
                  if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
                    c->type = RCD_ELSE;
-                 else if (token == T_NUM)
+                 else if (lex_is_number ())
                    {
                      c->type = RCD_LOW;
                      c->f1.f = tokval;
@@ -568,7 +570,7 @@ parse_src_spec (struct rcd_var * rcd, int type, size_t max_src_width)
                  return 0;
                }
            }
-         else if (token == T_NUM)
+         else if (lex_is_number ())
            {
              c->f1.f = tokval;
              lex_get ();
@@ -576,7 +578,7 @@ parse_src_spec (struct rcd_var * rcd, int type, size_t max_src_width)
                {
                  if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
                    c->type = RCD_HIGH;
-                 else if (token == T_NUM)
+                 else if (lex_is_number ())
                    {
                      c->type = RCD_RANGE;
                      c->f2.f = tokval;
@@ -626,7 +628,7 @@ parse_src_spec (struct rcd_var * rcd, int type, size_t max_src_width)
              if (!lex_force_string ())
                return 0;
              c->f1.c = xmalloc (max_src_width + 1);
-             st_pad_copy (c->f1.c, ds_value (&tokstr), max_src_width + 1);
+             str_copy_rpad (c->f1.c, max_src_width + 1, ds_c_str (&tokstr));
              lex_get ();
            }
        }
@@ -644,12 +646,13 @@ parse_src_spec (struct rcd_var * rcd, int type, size_t max_src_width)
 /* Data transformation. */
 
 static void
-recode_trns_free (struct trns_header * t)
+recode_trns_free (void *t_)
 {
-  int i;
+  struct recode_trns *t = t_;
+  size_t i;
   struct rcd_var *head, *next;
 
-  head = ((struct recode_trns *) t)->codings;
+  head = t->codings;
   while (head)
     {
       if (head->map && !(head->flags & RCD_MISC_DUPLICATE))
@@ -684,12 +687,13 @@ recode_trns_free (struct trns_header * t)
       free (head);
       head = next;
     }
+  free (t);
 }
 
 static inline struct coding *
-find_src_numeric (struct rcd_var * v, struct ccase * c)
+find_src_numeric (struct rcd_var *v, struct ccase *c)
 {
-  double cmp = c->data[v->src->fv].f;
+  double cmp = case_num (c, v->src->fv);
   struct coding *cp;
 
   if (cmp == SYSMIS)
@@ -697,9 +701,9 @@ find_src_numeric (struct rcd_var * v, struct ccase * c)
       if (v->sysmis.f != -SYSMIS)
        {
          if ((v->flags & RCD_DEST_MASK) == RCD_DEST_NUMERIC)
-           c->data[v->dest->fv].f = v->sysmis.f;
+            case_data_rw (c, v->dest->fv)->f = v->sysmis.f;
          else
-           memcpy (c->data[v->dest->fv].s, v->sysmis.c,
+           memcpy (case_data_rw (c, v->dest->fv)->s, v->sysmis.s,
                    v->dest->width);
        }
       return NULL;
@@ -711,7 +715,7 @@ find_src_numeric (struct rcd_var * v, struct ccase * c)
       case RCD_END:
        return NULL;
       case RCD_USER:
-       if (is_num_user_missing (cmp, v->src))
+       if (mv_is_num_user_missing (&v->src->miss, cmp))
          return cp;
        break;
       case RCD_SINGLE:
@@ -738,9 +742,9 @@ find_src_numeric (struct rcd_var * v, struct ccase * c)
 }
 
 static inline struct coding *
-find_src_string (struct rcd_var * v, struct ccase * c)
+find_src_string (struct rcd_var *v, struct ccase *c)
 {
-  char *cmp = c->data[v->src->fv].s;
+  const char *cmp = case_str (c, v->src->fv);
   int w = v->src->width;
   struct coding *cp;
 
@@ -760,7 +764,7 @@ find_src_string (struct rcd_var * v, struct ccase * c)
          double f = convert_to_double (cmp, w);
          if (f != -SYSMIS)
            {
-             c->data[v->dest->fv].f = f;
+              case_data_rw (c, v->dest->fv)->f = f;
              return NULL;
            }
          break;
@@ -771,12 +775,13 @@ find_src_string (struct rcd_var * v, struct ccase * c)
 }
 
 static int
-recode_trns_proc (struct trns_header * t, struct ccase * c,
-                  int case_num UNUSED)
+recode_trns_proc (void *t_, struct ccase *c,
+                  int case_idx UNUSED)
 {
+  struct recode_trns *t = t_;
   struct rcd_var *v;
 
-  for (v = ((struct recode_trns *) t)->codings; v; v = v->next)
+  for (v = t->codings; v; v = v->next)
     {
       struct coding *cp;
 
@@ -790,6 +795,7 @@ recode_trns_proc (struct trns_header * t, struct ccase * c,
          break;
         default:
           assert (0);
+          abort ();
        }
       if (!cp)
        continue;
@@ -798,20 +804,24 @@ recode_trns_proc (struct trns_header * t, struct ccase * c,
       if ((v->flags & RCD_DEST_MASK) == RCD_DEST_NUMERIC)
        {
          double val = cp->t.f;
+          double *out = &case_data_rw (c, v->dest->fv)->f;
          if (val == -SYSMIS)
-           c->data[v->dest->fv].f = c->data[v->src->fv].f;
+           *out = case_num (c, v->src->fv);
          else
-           c->data[v->dest->fv].f = val;
+           *out = val;
        }
       else
        {
          char *val = cp->t.c;
-         if (val == NULL)
-           st_bare_pad_len_copy (c->data[v->dest->fv].s,
-                                 c->data[v->src->fv].c,
-                                 v->dest->width, v->src->width);
+         if (val == NULL) 
+            {
+              if (v->dest->fv != v->src->fv)
+                buf_copy_rpad (case_data_rw (c, v->dest->fv)->s,
+                               v->dest->width,
+                               case_str (c, v->src->fv), v->src->width); 
+            }
          else
-           memcpy (c->data[v->dest->fv].s, cp->t.c, v->dest->width);
+           memcpy (case_data_rw (c, v->dest->fv)->s, cp->t.c, v->dest->width);
        }
     }
 
@@ -823,14 +833,14 @@ recode_trns_proc (struct trns_header * t, struct ccase * c,
    first character after the number into *ENDPTR.  From the GNU C
    library. */
 static long int
-string_to_long (char *nptr, int width, char **endptr)
+string_to_long (const char *nptr, int width, const char **endptr)
 {
   int negative;
-  register unsigned long int cutoff;
-  register unsigned int cutlim;
-  register unsigned long int i;
-  register char *s;
-  register unsigned char c;
+  unsigned long int cutoff;
+  unsigned int cutlim;
+  unsigned long int i;
+  const char *s;
+  unsigned char c;
   const char *save;
 
   s = nptr;
@@ -899,9 +909,9 @@ string_to_long (char *nptr, int width, char **endptr)
    found, or -SYSMIS if there was no valid number in s.  WIDTH is the
    length of string S.  From the GNU C library. */
 static double
-convert_to_double (char *s, int width)
+convert_to_double (const char *s, int width)
 {
-  register const char *end = &s[width];
+  const char *end = &s[width];
 
   short int sign;