Fix up potential overflows in size calculations by replacing instances
[pspp] / src / vars-prs.c
index dbc147556622cff81a4b9ee396d701556486c558..920f8c9147ad2dee992b69588e929b90af399052 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 "var.h"
 #include <ctype.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include "alloc.h"
 #include "bitvector.h"
 #include "hash.h"
 #include "lexer.h"
 #include "misc.h"
+#include "size_max.h"
 #include "str.h"
 
-/* Parses a name as a variable within VS and returns the
-   variable's index if successful.  On failure emits an error
-   message and returns a null pointer. */
-static int
-parse_vs_variable_idx (const struct var_set *vs)
-{
-  int idx;
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
 
+/* Parses a name as a variable within VS.  Sets *IDX to the
+   variable's index and returns true if successful.  On failure
+   emits an error message and returns false. */
+static bool
+parse_vs_variable_idx (const struct var_set *vs, size_t *idx)
+{
+  assert (idx != NULL);
+  
   if (token != T_ID)
     {
       lex_error (_("expecting variable name"));
-      return -1;
+      return false;
+    }
+  else if (var_set_lookup_var_idx (vs, tokid, idx)) 
+    {
+      lex_get ();
+      return true;
+    }
+  else 
+    {
+      msg (SE, _("%s is not a variable name."), tokid);
+      return false;
     }
-
-  idx = var_set_lookup_var_idx (vs, tokid);
-  if (idx < 0)
-    msg (SE, _("%s is not a variable name."), tokid);
-  lex_get ();
-
-  return idx;
 }
 
 /* Parses a name as a variable within VS and returns the variable
@@ -58,8 +66,8 @@ parse_vs_variable_idx (const struct var_set *vs)
 static struct variable *
 parse_vs_variable (const struct var_set *vs)
 {
-  int idx = parse_vs_variable_idx (vs);
-  return idx >= 0 ? var_set_get_var (vs, idx) : NULL;
+  size_t idx;
+  return parse_vs_variable_idx (vs, &idx) ? var_set_get_var (vs, idx) : NULL;
 }
 
 /* Parses a variable name in dictionary D and returns the
@@ -83,41 +91,6 @@ parse_variable (void)
   return parse_dict_variable (default_dict);
 }
 
-/* Returns the dictionary class corresponding to a variable named
-   NAME. */
-enum dict_class
-dict_class_from_id (const char *name) 
-{
-  assert (name != NULL);
-
-  switch (name[0]) 
-    {
-    default:
-      return DC_ORDINARY;
-    case '$':
-      return DC_SYSTEM;
-    case '#':
-      return DC_SCRATCH;
-    }
-}
-
-/* Returns the name of dictionary class DICT_CLASS. */
-const char *
-dict_class_to_name (enum dict_class dict_class) 
-{
-  switch (dict_class) 
-    {
-    case DC_ORDINARY:
-      return _("ordinary");
-    case DC_SYSTEM:
-      return _("system");
-    case DC_SCRATCH:
-      return _("scratch");
-    default:
-      assert (0);
-      abort ();
-    }
-}
 
 /* Parses a set of variables from dictionary D given options
    OPTS.  Resulting list of variables stored in *VAR and the
@@ -125,7 +98,7 @@ dict_class_to_name (enum dict_class dict_class)
    successful. */
 int
 parse_variables (const struct dictionary *d, struct variable ***var,
-                 int *cnt, int opts) 
+                 size_t *cnt, int opts) 
 {
   struct var_set *vs;
   int success;
@@ -134,7 +107,6 @@ parse_variables (const struct dictionary *d, struct variable ***var,
   assert (var != NULL);
   assert (cnt != NULL);
 
   vs = var_set_create_from_dict (d);
   success = parse_var_set_vars (vs, var, cnt, opts);
   if ( success == 0 )
@@ -148,11 +120,10 @@ parse_variables (const struct dictionary *d, struct variable ***var,
    dictionary class, and returns nonzero.  Returns zero on
    failure. */
 static int
-parse_var_idx_class (const struct var_set *vs, int *idx,
+parse_var_idx_class (const struct var_set *vs, size_t *idx,
                      enum dict_class *class)
 {
-  *idx = parse_vs_variable_idx (vs);
-  if (*idx < 0)
+  if (!parse_vs_variable_idx (vs, idx))
     return 0;
 
   *class = dict_class_from_id (var_set_get_var (vs, *idx)->name);
@@ -165,9 +136,9 @@ parse_var_idx_class (const struct var_set *vs, int *idx,
    PV_OPTS, which also affects what variables are allowed in
    appropriate ways. */
 static void
-add_variable (struct variable ***v, int *nv, int *mv,
+add_variable (struct variable ***v, size_t *nv, size_t *mv,
               char *included, int pv_opts,
-              const struct var_set *vs, int idx)
+              const struct var_set *vs, size_t idx)
 {
   struct variable *add = var_set_get_var (vs, idx);
 
@@ -193,7 +164,7 @@ add_variable (struct variable ***v, int *nv, int *mv,
       if (*nv >= *mv)
         {
           *mv = 2 * (*nv + 1);
-          *v = xrealloc (*v, *mv * sizeof **v);
+          *v = xnrealloc (*v, *mv, sizeof **v);
         }
 
       if ((pv_opts & PV_DUPLICATE) || !included[idx])
@@ -211,12 +182,12 @@ add_variable (struct variable ***v, int *nv, int *mv,
    duplicates if indicated by PV_OPTS, which also affects what
    variables are allowed in appropriate ways. */
 static void
-add_variables (struct variable ***v, int *nv, int *mv, char *included,
+add_variables (struct variable ***v, size_t *nv, size_t *mv, char *included,
                int pv_opts,
                const struct var_set *vs, int first_idx, int last_idx,
                enum dict_class class) 
 {
-  int i;
+  size_t i;
   
   for (i = first_idx; i <= last_idx; i++)
     if (dict_class_from_id (var_set_get_var (vs, i)->name) == class)
@@ -228,10 +199,10 @@ add_variables (struct variable ***v, int *nv, int *mv, char *included,
    nonzero and *v is non-NULL. */
 int
 parse_var_set_vars (const struct var_set *vs, 
-                    struct variable ***v, int *nv,
+                    struct variable ***v, size_t *nv,
                     int pv_opts)
 {
-  int mv;
+  size_t mv;
   char *included;
 
   assert (vs != NULL);
@@ -258,16 +229,16 @@ parse_var_set_vars (const struct var_set *vs,
 
   if (!(pv_opts & PV_DUPLICATE))
     {
-      int i;
+      size_t i;
       
-      included = xcalloc (var_set_get_cnt (vs));
+      included = xcalloc (var_set_get_cnt (vs), sizeof *included);
       for (i = 0; i < *nv; i++)
         included[(*v)[i]->index] = 1;
     }
   else
     included = NULL;
 
-if (lex_match (T_ALL))
+  if (lex_match (T_ALL))
     add_variables (v, nv, &mv, included, pv_opts,
                    vs, 0, var_set_get_cnt (vs) - 1, DC_ORDINARY);
   else 
@@ -275,17 +246,16 @@ if (lex_match (T_ALL))
       do
         {
           enum dict_class class;
-          int first_idx;
+          size_t first_idx;
           
           if (!parse_var_idx_class (vs, &first_idx, &class))
             goto fail;
 
           if (!lex_match (T_TO))
-            add_variable (v, nv, &mv, included, pv_opts,
-                          vs, first_idx);
+            add_variable (v, nv, &mv, included, pv_opts, vs, first_idx);
           else 
             {
-              int last_idx;
+              size_t last_idx;
               enum dict_class last_class;
               struct variable *first_var, *last_var;
 
@@ -303,6 +273,7 @@ if (lex_match (T_ALL))
                        first_var->name, last_var->name);
                   goto fail;
                 }
+
               if (class != last_class)
                 {
                   msg (SE, _("When using the TO keyword to specify several "
@@ -385,14 +356,14 @@ extract_num (char *s, char *r, int *n, int *d)
 /* Parses a list of variable names according to the DATA LIST version
    of the TO convention.  */
 int
-parse_DATA_LIST_vars (char ***names, int *nnames, int pv_opts)
+parse_DATA_LIST_vars (char ***names, size_t *nnames, int pv_opts)
 {
   int n1, n2;
   int d1, d2;
   int n;
-  int nvar, mvar;
-  char *name1, *name2;
-  char *root1, *root2;
+  size_t nvar, mvar;
+  char name1[LONG_NAME_LEN + 1], name2[LONG_NAME_LEN + 1];
+  char root1[LONG_NAME_LEN + 1], root2[LONG_NAME_LEN + 1];
   int success = 0;
 
   assert (names != NULL);
@@ -409,10 +380,6 @@ parse_DATA_LIST_vars (char ***names, int *nnames, int pv_opts)
       *names = NULL;
     }
 
-  name1 = xmalloc (4 * (SHORT_NAME_LEN + 1));
-  name2 = &name1[1 * SHORT_NAME_LEN + 1];
-  root1 = &name1[2 * SHORT_NAME_LEN + 1];
-  root2 = &name1[3 * SHORT_NAME_LEN + 1];
   do
     {
       if (token != T_ID)
@@ -443,7 +410,7 @@ parse_DATA_LIST_vars (char ***names, int *nnames, int pv_opts)
              || !extract_num (name2, root2, &n2, &d2))
            goto fail;
 
-         if (strcmp (root1, root2))
+         if (strcasecmp (root1, root2))
            {
              msg (SE, _("Prefixes don't match in use of TO convention."));
              goto fail;
@@ -459,13 +426,14 @@ parse_DATA_LIST_vars (char ***names, int *nnames, int pv_opts)
          if (mvar < nvar + (n2 - n1 + 1))
            {
              mvar += ROUND_UP (n2 - n1 + 1, 16);
-             *names = xrealloc (*names, mvar * sizeof **names);
+             *names = xnrealloc (*names, mvar, sizeof **names);
            }
 
          for (n = n1; n <= n2; n++)
            {
-             (*names)[nvar] = xmalloc (SHORT_NAME_LEN + 1);
-             sprintf ((*names)[nvar], "%s%0*d", root1, d1, n);
+              char name[LONG_NAME_LEN + 1];
+             sprintf (name, "%s%0*d", root1, d1, n);
+             (*names)[nvar] = xstrdup (name);
              nvar++;
            }
        }
@@ -474,7 +442,7 @@ parse_DATA_LIST_vars (char ***names, int *nnames, int pv_opts)
          if (nvar >= mvar)
            {
              mvar += 16;
-             *names = xrealloc (*names, mvar * sizeof **names);
+             *names = xnrealloc (*names, mvar, sizeof **names);
            }
          (*names)[nvar++] = xstrdup (name1);
        }
@@ -489,7 +457,6 @@ parse_DATA_LIST_vars (char ***names, int *nnames, int pv_opts)
 
 fail:
   *nnames = nvar;
-  free (name1);
   if (!success)
     {
       int i;
@@ -506,9 +473,9 @@ fail:
    existing and the rest are to be created.  Same args as
    parse_DATA_LIST_vars(). */
 int
-parse_mixed_vars (char ***names, int *nnames, int pv_opts)
+parse_mixed_vars (char ***names, size_t *nnames, int pv_opts)
 {
-  int i;
+  size_t i;
 
   assert (names != NULL);
   assert (nnames != NULL);
@@ -524,11 +491,11 @@ parse_mixed_vars (char ***names, int *nnames, int pv_opts)
       if (token == T_ALL || dict_lookup_var (default_dict, tokid) != NULL)
        {
          struct variable **v;
-         int nv;
+         size_t nv;
 
          if (!parse_variables (default_dict, &v, &nv, PV_NONE))
            goto fail;
-         *names = xrealloc (*names, (*nnames + nv) * sizeof **names);
+         *names = xnrealloc (*names, *nnames + nv, sizeof **names);
          for (i = 0; i < nv; i++)
            (*names)[*nnames + i] = xstrdup (v[i]->name);
          free (v);
@@ -553,7 +520,7 @@ struct var_set
   {
     size_t (*get_cnt) (const struct var_set *);
     struct variable *(*get_var) (const struct var_set *, size_t idx);
-    int (*lookup_var_idx) (const struct var_set *, const char *);
+    bool (*lookup_var_idx) (const struct var_set *, const char *, size_t *);
     void (*destroy) (struct var_set *);
     void *aux;
   };
@@ -583,20 +550,23 @@ var_set_get_var (const struct var_set *vs, size_t idx)
 struct variable *
 var_set_lookup_var (const struct var_set *vs, const char *name) 
 {
-  int idx = var_set_lookup_var_idx (vs, name);
-  return idx >= 0 ? var_set_get_var (vs, idx) : NULL;
+  size_t idx;
+  return (var_set_lookup_var_idx (vs, name, &idx)
+          ? var_set_get_var (vs, idx)
+          : NULL);
 }
 
-/* Returns the index in VS of the variable named NAME, or -1 if
-   VS contains no variable with that name. */
-int
-var_set_lookup_var_idx (const struct var_set *vs, const char *name) 
+/* If VS contains a variable named NAME, sets *IDX to its index
+   and returns true.  Otherwise, returns false. */
+bool
+var_set_lookup_var_idx (const struct var_set *vs, const char *name,
+                        size_t *idx)
 {
   assert (vs != NULL);
   assert (name != NULL);
-  assert (strlen (name) <= LONG_NAME_LEN );
+  assert (strlen (name) <= LONG_NAME_LEN);
 
-  return vs->lookup_var_idx (vs, name);
+  return vs->lookup_var_idx (vs, name, idx);
 }
 
 /* Destroys VS. */
@@ -626,14 +596,21 @@ dict_var_set_get_var (const struct var_set *vs, size_t idx)
   return dict_get_var (d, idx);
 }
 
-/* Returns the index of the variable in VS named NAME, or -1 if
-   VS contains no variable with that name. */
-static int
-dict_var_set_lookup_var_idx (const struct var_set *vs, const char *name) 
+/* If VS contains a variable named NAME, sets *IDX to its index
+   and returns true.  Otherwise, returns false. */
+static bool
+dict_var_set_lookup_var_idx (const struct var_set *vs, const char *name,
+                             size_t *idx) 
 {
   struct dictionary *d = vs->aux;
   struct variable *v = dict_lookup_var (d, name);
-  return v != NULL ? v->index : -1;
+  if (v != NULL) 
+    {
+      *idx = v->index;
+      return true;
+    }
+  else
+    return false;
 }
 
 /* Destroys VS. */
@@ -662,7 +639,6 @@ struct array_var_set
     struct variable *const *var;/* Array of variables. */
     size_t var_cnt;             /* Number of elements in var. */
     struct hsh_table *name_tab; /* Hash from variable names to variables. */
-    struct hsh_table *longname_tab; /* Hash of short names indexed by long names */
   };
 
 /* Returns the number of variables in VS. */
@@ -684,34 +660,25 @@ array_var_set_get_var (const struct var_set *vs, size_t idx)
   return (struct variable *) avs->var[idx];
 }
 
-/* Returns the index of the variable in VS named NAME, or -1 if
-   VS contains no variable with that name. */
-static int
-array_var_set_lookup_var_idx (const struct var_set *vs, const char *name) 
+/* If VS contains a variable named NAME, sets *IDX to its index
+   and returns true.  Otherwise, returns false. */
+static bool
+array_var_set_lookup_var_idx (const struct var_set *vs, const char *name,
+                              size_t *idx) 
 {
-  char *short_name ;
   struct array_var_set *avs = vs->aux;
   struct variable v, *vp, *const *vpp;
 
-  struct name_table_entry key;
-  key.longname = name;
-
-  struct name_table_entry *nte;
-
-  assert (avs->longname_tab);
-
-
-  nte = hsh_find (avs->longname_tab, &key);
-
-  if (!nte)
-    return -1;
-
-  short_name = nte->name;
-
-  strcpy (v.name, short_name);
+  strcpy (v.name, name);
   vp = &v;
   vpp = hsh_find (avs->name_tab, &vp);
-  return vpp != NULL ? vpp - avs->var : -1;
+  if (vpp != NULL) 
+    {
+      *idx = vpp - avs->var;
+      return true;
+    }
+  else
+    return false;
 }
 
 /* Destroys VS. */
@@ -721,7 +688,6 @@ array_var_set_destroy (struct var_set *vs)
   struct array_var_set *avs = vs->aux;
 
   hsh_destroy (avs->name_tab);
-  hsh_destroy (avs->longname_tab);
   free (avs);
   free (vs);
 }
@@ -744,35 +710,14 @@ var_set_create_from_array (struct variable *const *var, size_t var_cnt)
   avs->var = var;
   avs->var_cnt = var_cnt;
   avs->name_tab = hsh_create (2 * var_cnt,
-                              compare_var_ptr_names, hash_var_ptr_name, 
-                             NULL, NULL);
-
-  avs->longname_tab = hsh_create (2 * var_cnt, 
-                                  compare_long_names, hash_long_name, 
-                                  NULL, NULL);
-  
+                              compare_var_ptr_names, hash_var_ptr_name, NULL,
+                              NULL);
   for (i = 0; i < var_cnt; i++)
-    {
-      struct name_table_entry *nte ;
-
-      if (hsh_insert (avs->name_tab, &var[i]) != NULL) 
-       {
-         var_set_destroy (vs);
-         return NULL;
-       }
-
-      nte = xmalloc (sizeof (*nte));
-      nte->name = strdup(var[i]->name);
-      nte->longname = strdup(var[i]->longname);
-
-      if (hsh_insert (avs->longname_tab, nte) != NULL) 
-       {
-         var_set_destroy (vs);
-         free (nte);
-         return NULL;
-       }
-
-    }
-
+    if (hsh_insert (avs->name_tab, (void *) &var[i]) != NULL) 
+      {
+        var_set_destroy (vs);
+        return NULL;
+      }
+  
   return vs;
 }