Fix memory leaks.
[pspp-builds.git] / src / dictionary.c
index 9b69c89844a347e041269e783f0a54a9af366e95..20d64bc525b56e5b271d76612809177d6ef5f933 100644 (file)
    02111-1307, USA. */
 
 #include <config.h>
-#include <assert.h>
+#include "error.h"
 #include <stdlib.h>
 #include "algorithm.h"
 #include "alloc.h"
+#include "case.h"
 #include "hash.h"
 #include "misc.h"
 #include "str.h"
@@ -236,7 +237,7 @@ dict_create_var (struct dictionary *d, const char *name, int width)
   v->fv = d->next_value_idx;
   v->nv = width == 0 ? 1 : DIV_RND_UP (width, 8);
   v->init = 1;
-  v->reinit = name[0] != '#';
+  v->reinit = dict_class_from_id (name) != DC_SCRATCH;
   v->miss_type = MISSING_NONE;
   if (v->type == NUMERIC)
     {
@@ -321,6 +322,7 @@ dict_rename_var (struct dictionary *d, struct variable *v,
   assert (v != NULL);
   assert (new_name != NULL);
   assert (strlen (new_name) >= 1 && strlen (new_name) <= 8);
+  assert (dict_contains_var (d, v));
 
   if (!strcmp (v->name, new_name))
     return;
@@ -367,7 +369,7 @@ dict_contains_var (const struct dictionary *d, const struct variable *v)
   assert (d != NULL);
   assert (v != NULL);
 
-  return dict_lookup_var (d, v->name) == v;
+  return v->index >= 0 && v->index < d->var_cnt && d->var[v->index] == v;
 }
 
 /* Compares two double pointers to variables, which should point
@@ -557,11 +559,14 @@ dict_get_weight (const struct dictionary *d)
   return d->weight;
 }
 
-/* Returns the value of D's weighting variable in case C, except
-   that a negative weight is returned as 0.  Returns 1 if the
-   dictionary is unweighted. */
+/* Returns the value of D's weighting variable in case C, except that a
+   negative weight is returned as 0.  Returns 1 if the dictionary is
+   unweighted. Will warn about missing, negative, or zero values if
+   warn_on_invalid is nonzero. The function will set warn_on_invalid to zero
+   if an invalid weight is found. */
 double
-dict_get_case_weight (const struct dictionary *d, const struct ccase *c)
+dict_get_case_weight (const struct dictionary *d, const struct ccase *c, 
+                     int *warn_on_invalid)
 {
   assert (d != NULL);
   assert (c != NULL);
@@ -570,9 +575,15 @@ dict_get_case_weight (const struct dictionary *d, const struct ccase *c)
     return 1.0;
   else 
     {
-      double w = c->data[d->weight->fv].f;
-      if (w < 0.0)
+      double w = case_num (c, d->weight->fv);
+      if ( w < 0.0 || w == SYSMIS || is_num_user_missing(w, d->weight) )
         w = 0.0;
+      if ( w == 0.0 && *warn_on_invalid ) {
+         *warn_on_invalid = 0;
+         msg (SW, _("At least one case in the data file had a weight value "
+                    "that was user-missing, system-missing, zero, or "
+                    "negative.  These case(s) were ignored."));
+      }
       return w;
     }
 }
@@ -653,21 +664,70 @@ dict_get_case_size (const struct dictionary *d)
   return sizeof (union value) * dict_get_next_value_idx (d);
 }
 
-/* Reassigns values in dictionary D so that fragmentation is
-   eliminated. */
+/* Deletes scratch variables in dictionary D and reassigns values
+   so that fragmentation is eliminated. */
 void
 dict_compact_values (struct dictionary *d) 
 {
   size_t i;
 
   d->next_value_idx = 0;
+  for (i = 0; i < d->var_cnt; )
+    {
+      struct variable *v = d->var[i];
+
+      if (dict_class_from_id (v->name) != DC_SCRATCH) 
+        {
+          v->fv = d->next_value_idx;
+          d->next_value_idx += v->nv;
+          i++;
+        }
+      else
+        dict_delete_var (default_dict, v);
+    }
+}
+
+/* Returns the number of values that would be used by a case if
+   dict_compact_values() were called. */
+size_t
+dict_get_compacted_value_cnt (const struct dictionary *d) 
+{
+  size_t i;
+  size_t cnt;
+
+  cnt = 0;
+  for (i = 0; i < d->var_cnt; i++)
+    if (dict_class_from_id (d->var[i]->name) != DC_SCRATCH) 
+      cnt += d->var[i]->nv;
+  return cnt;
+}
+
+/* Creates and returns an array mapping from a dictionary index
+   to the `fv' that the corresponding variable will have after
+   calling dict_compact_values().  Scratch variables receive -1
+   for `fv' because dict_compact_values() will delete them. */
+int *
+dict_get_compacted_idx_to_fv (const struct dictionary *d) 
+{
+  size_t i;
+  size_t next_value_idx;
+  int *idx_to_fv;
+  
+  idx_to_fv = xmalloc (d->var_cnt * sizeof *idx_to_fv);
+  next_value_idx = 0;
   for (i = 0; i < d->var_cnt; i++)
     {
       struct variable *v = d->var[i];
 
-      v->fv = d->next_value_idx;
-      d->next_value_idx += v->nv;
+      if (dict_class_from_id (v->name) != DC_SCRATCH) 
+        {
+          idx_to_fv[i] = next_value_idx;
+          next_value_idx += v->nv;
+        }
+      else 
+        idx_to_fv[i] = -1;
     }
+  return idx_to_fv;
 }
 
 /* Returns the SPLIT FILE vars (see cmd_split_file()).  Call