Implemented long variable names a la spss V12.
[pspp-builds.git] / src / val-labs.c
index ae9ac296fa425136512f2f68e79e98b36dc08afd..12817700dabab5b03b6d4367440e4afe1a0f7fd3 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include "alloc.h"
-#include "avl.h"
 #include "command.h"
 #include "error.h"
+#include "hash.h"
 #include "lexer.h"
 #include "str.h"
+#include "value-labels.h"
 #include "var.h"
 \f
 /* Declarations. */
 
-#undef DEBUGGING
-/*#define DEBUGGING 1 */
-#include "debug-print.h"
-
-/* Variable list. */
-static struct variable **v;
-
-/* Number of variables. */
-static int nv;
-
 static int do_value_labels (int);
-static int verify_val_labs (int erase);
-static int get_label (void);
-
-#if DEBUGGING
-static void debug_print (void);
-#endif
+static int verify_val_labs (struct variable **vars, int var_cnt);
+static void erase_labels (struct variable **vars, int var_cnt);
+static int get_label (struct variable **vars, int var_cnt);
 \f
 /* Stubs. */
 
-static void
-init (void)
-{
-  v = NULL;
-}
-
-static void
-done (void)
-{
-  free (v);
-}
-
 int
 cmd_value_labels (void)
 {
-  int code;
-  init ();
-  lex_match_id ("VALUE");
-  lex_match_id ("LABELS");
-  code = do_value_labels (1);
-  done ();
-  return code;
+  return do_value_labels (1);
 }
 
 int
 cmd_add_value_labels (void)
 {
-  int code;
-  lex_match_id ("ADD");
-  lex_match_id ("VALUE");
-  lex_match_id ("LABELS");
-  code = do_value_labels (0);
-  done ();
-  return code;
+  return do_value_labels (0);
 }
 \f
 /* Do it. */
@@ -91,23 +55,38 @@ cmd_add_value_labels (void)
 static int
 do_value_labels (int erase)
 {
+  struct variable **vars; /* Variable list. */
+  int var_cnt;            /* Number of variables. */
+  int parse_err=0;        /* true if error parsing variables */
+
   lex_match ('/');
   
   while (token != '.')
     {
-      parse_variables (NULL, &v, &nv, PV_SAME_TYPE);
-      if (!verify_val_labs (erase))
-       return CMD_PART_SUCCESS_MAYBE;
+      parse_err = !parse_variables (default_dict, &vars, &var_cnt, 
+                                   PV_SAME_TYPE) ;
+      if (var_cnt < 1)
+       {
+         free(vars);
+         return CMD_FAILURE;
+       }
+      if (!verify_val_labs (vars, var_cnt))
+        goto lossage;
+      if (erase)
+        erase_labels (vars, var_cnt);
       while (token != '/' && token != '.')
-       if (!get_label ())
-         return CMD_PART_SUCCESS_MAYBE;
+       if (!get_label (vars, var_cnt))
+          goto lossage;
 
       if (token != '/')
+       {
+       free (vars);
        break;
+       }
+
       lex_get ();
 
-      free (v);
-      v = NULL;
+      free (vars);
     }
 
   if (token != '.')
@@ -116,92 +95,81 @@ do_value_labels (int erase)
       return CMD_TRAILING_GARBAGE;
     }
 
-#if DEBUGGING
-  debug_print ();
-#endif
-  return CMD_SUCCESS;
+  return parse_err ? CMD_PART_SUCCESS_MAYBE : CMD_SUCCESS;
+
+ lossage:
+  free (vars);
+  return CMD_PART_SUCCESS_MAYBE;
 }
 
+/* Verifies that none of the VAR_CNT variables in VARS are long
+   string variables. */
 static int
-verify_val_labs (int erase)
+verify_val_labs (struct variable **vars, int var_cnt)
 {
   int i;
 
-  if (!nv)
-    return 1;
-
-  for (i = 0; i < nv; i++)
+  for (i = 0; i < var_cnt; i++)
     {
-      struct variable *vp = v[i];
+      struct variable *vp = vars[i];
 
-      if (vp->type == ALPHA && vp->width > 8)
+      if (vp->type == ALPHA && vp->width > MAX_SHORT_STRING)
        {
          msg (SE, _("It is not possible to assign value labels to long "
                     "string variables such as %s."), vp->name);
          return 0;
        }
-
-      if (erase && v[i]->val_lab)
-       {
-         avl_destroy (vp->val_lab, free_val_lab);
-         vp->val_lab = NULL;
-       }
     }
   return 1;
 }
 
-/* Parse all the labels for a particular set of variables and add the
-   specified labels to those variables. */
-static int
-get_label (void)
+/* Erases all the labels for the VAR_CNT variables in VARS. */
+static void
+erase_labels (struct variable **vars, int var_cnt) 
 {
   int i;
 
-  /* Make sure there's some variables. */
-  if (!nv)
-    {
-      if (token != T_STRING && token != T_NUM)
-       return 0;
-      lex_get ();
-      return 1;
-    }
+  /* Erase old value labels if desired. */
+  for (i = 0; i < var_cnt; i++)
+    val_labs_clear (vars[i]->val_labs);
+}
 
+/* Parse all the labels for the VAR_CNT variables in VARS and add
+   the specified labels to those variables.  */
+static int
+get_label (struct variable **vars, int var_cnt)
+{
   /* Parse all the labels and add them to the variables. */
   do
     {
-      struct value_label *label;
+      union value value;
+      char *label;
+      int i;
 
-      /* Allocate label. */
-      label = xmalloc (sizeof *label);
-#if __CHECKER__
-      memset (&label->v, 0, sizeof label->v);
-#endif
-      label->ref_count = nv;
-
-      /* Set label->v. */
-      if (v[0]->type == ALPHA)
+      /* Set value. */
+      if (vars[0]->type == ALPHA)
        {
          if (token != T_STRING)
            {
-             msg (SE, _("String expected for value."));
+              lex_error (_("expecting string"));
              return 0;
            }
-         st_bare_pad_copy (label->v.s, ds_value (&tokstr), MAX_SHORT_STRING);
+         st_bare_pad_copy (value.s, ds_c_str (&tokstr), MAX_SHORT_STRING);
        }
       else
        {
-         if (token != T_NUM)
+         if (!lex_is_number ())
            {
-             msg (SE, _("Number expected for value."));
+             lex_error (_("expecting integer"));
              return 0;
            }
-         if (!lex_integer_p ())
+         if (!lex_is_integer ())
            msg (SW, _("Value label `%g' is not integer."), tokval);
-         label->v.f = tokval;
+         value.f = tokval;
        }
-
-      /* Set label->s. */
       lex_get ();
+
+      /* Set label. */
       if (!lex_force_string ())
        return 0;
       if (ds_length (&tokstr) > 60)
@@ -209,22 +177,10 @@ get_label (void)
          msg (SW, _("Truncating value label to 60 characters."));
          ds_truncate (&tokstr, 60);
        }
-      label->s = xstrdup (ds_value (&tokstr));
+      label = ds_c_str (&tokstr);
 
-      for (i = 0; i < nv; i++)
-       {
-         if (!v[i]->val_lab)
-           v[i]->val_lab = avl_create (NULL, val_lab_cmp,
-                                       (void *) (v[i]->width));
-         
-         {
-           struct value_label *old;
-           
-           old = avl_replace (v[i]->val_lab, label);
-           if (old)
-             free_value_label (old);
-         }
-       }
+      for (i = 0; i < var_cnt; i++)
+        val_labs_replace (vars[i]->val_labs, value, label);
 
       lex_get ();
     }
@@ -232,75 +188,3 @@ get_label (void)
 
   return 1;
 }
-
-#if DEBUGGING
-static void
-debug_print ()
-{
-  int i;
-
-  puts (_("Value labels:"));
-  for (i = 0; i < nvar; i++)
-    {
-      AVLtraverser *t = NULL;
-      struct value_label *val;
-
-      printf ("  %s\n", var[i]->name);
-      if (var[i]->val_lab)
-       if (var[i]->type == NUMERIC)
-         for (val = avltrav (var[i]->val_lab, &t);
-              val; val = avltrav (var[i]->val_lab, &t))
-           printf ("    %g:  `%s'\n", val->v.f, val->s);
-       else
-         for (val = avltrav (var[i]->val_lab, &t);
-              val; val = avltrav (var[i]->val_lab, &t))
-           printf ("    `%.8s':  `%s'\n", val->v.s, val->s);
-      else
-       printf (_("    (no value labels)\n"));
-    }
-}
-#endif /* DEBUGGING */
-
-/* Compares two value labels and returns a strcmp()-type result. */
-int
-val_lab_cmp (const void *a, const void *b, void *param)
-{
-  if ((int) param)
-    return strncmp (((struct value_label *) a)->v.s,
-                   ((struct value_label *) b)->v.s,
-                   (int) param);
-  else
-    {
-      int temp = (((struct value_label *) a)->v.f
-                 - ((struct value_label *) b)->v.f);
-      if (temp > 0)
-       return 1;
-      else if (temp < 0)
-       return -1;
-      else
-       return 0;
-    }
-}
-
-/* Callback function to increment the reference count for a value
-   label. */
-void *
-inc_ref_count (void *pv, void *param unused)
-{
-  ((struct value_label *) pv)->ref_count++;
-  return pv;
-}
-
-/* Copy the avl tree of value labels and return a pointer to the
-   copy. */
-avl_tree *
-copy_value_labels (avl_tree *src)
-{
-  avl_tree *dest;
-
-  if (src == NULL)
-    return NULL;
-  dest = avl_copy (NULL, src, inc_ref_count);
-
-  return dest;
-}