Fixed a bug causing pspp to crash when computed variables had no format
[pspp-builds.git] / src / vfm.c
index 45d9c28e8b436284bc795bd033b4479cf8a62433..42e6b7ccd29dfef5e2b5792cbe16c705fdceaec9 100644 (file)
--- a/src/vfm.c
+++ b/src/vfm.c
@@ -28,7 +28,6 @@
 #include <unistd.h>    /* Required by SunOS4. */
 #endif
 #include "alloc.h"
 #include <unistd.h>    /* Required by SunOS4. */
 #endif
 #include "alloc.h"
-#include "approx.h"
 #include "do-ifP.h"
 #include "error.h"
 #include "expr.h"
 #include "do-ifP.h"
 #include "error.h"
 #include "expr.h"
@@ -71,17 +70,6 @@ struct stream_info vfm_source_info;
 /* Information about the data sink. */
 struct stream_info vfm_sink_info;
 
 /* Information about the data sink. */
 struct stream_info vfm_sink_info;
 
-/* Filter variable and  `value' index. */
-static struct variable *filter_var;
-static int filter_index;
-
-#define FILTERED                                                       \
-       (filter_index != -1                                             \
-        && (temp_case->data[filter_index].f == 0.0                     \
-            || temp_case->data[filter_index].f == SYSMIS               \
-            || is_num_user_missing (temp_case->data[filter_index].f,   \
-                                    filter_var)))
-
 /* Nonzero if the case needs to have values deleted before being
    stored, zero otherwise. */
 int compaction_necessary;
 /* Nonzero if the case needs to have values deleted before being
    stored, zero otherwise. */
 int compaction_necessary;
@@ -117,12 +105,13 @@ static void finish_compaction (void);
 static void lag_case (void);
 static int procedure_write_case (struct write_case_data *);
 static void clear_temp_case (void);
 static void lag_case (void);
 static int procedure_write_case (struct write_case_data *);
 static void clear_temp_case (void);
+static int exclude_this_case (void);
 \f
 /* Public functions. */
 
 /* Reads all the cases from the active file, transforms them by
    the active set of transformations, calls PROCFUNC with CURCASE
 \f
 /* Public functions. */
 
 /* Reads all the cases from the active file, transforms them by
    the active set of transformations, calls PROCFUNC with CURCASE
-   set to the case , and writes them to a new active file.
+   set to the case, and writes them to a new active file.
 
    Divides the active file into zero or more series of one or more
    cases each.  BEGINFUNC is called before each series.  ENDFUNC is
 
    Divides the active file into zero or more series of one or more
    cases each.  BEGINFUNC is called before each series.  ENDFUNC is
@@ -136,9 +125,13 @@ procedure (void (*beginfunc) (void *),
           void (*endfunc) (void *),
            void *aux)
 {
           void (*endfunc) (void *),
            void *aux)
 {
+  static int recursive_call;
+
   struct write_case_data procedure_write_data;
   struct write_case_data split_file_data;
 
   struct write_case_data procedure_write_data;
   struct write_case_data split_file_data;
 
+  assert (++recursive_call == 1);
+
   if (dict_get_split_cnt (default_dict) == 0) 
     {
       /* Normally we just use the data passed by the user. */
   if (dict_get_split_cnt (default_dict) == 0) 
     {
       /* Normally we just use the data passed by the user. */
@@ -166,6 +159,8 @@ procedure (void (*beginfunc) (void *),
   open_active_file ();
   vfm_source->read (procedure_write_case, &procedure_write_data);
   close_active_file (&procedure_write_data);
   open_active_file ();
   vfm_source->read (procedure_write_case, &procedure_write_data);
   close_active_file (&procedure_write_data);
+
+  assert (--recursive_call == 0);
 }
 \f
 /* Active file processing support.  Subtly different semantics from
 }
 \f
 /* Active file processing support.  Subtly different semantics from
@@ -242,10 +237,7 @@ process_active_file_write_case (struct write_case_data *data)
     lag_case ();
          
   /* Call the procedure if FILTER and PROCESS IF don't prohibit it. */
     lag_case ();
          
   /* Call the procedure if FILTER and PROCESS IF don't prohibit it. */
-  if (not_canceled
-      && !FILTERED
-      && (process_if_expr == NULL ||
-         expr_evaluate (process_if_expr, temp_case, NULL) == 1.0))
+  if (not_canceled && !exclude_this_case ())
     not_canceled = data->procfunc (temp_case, data->aux);
   
   case_count++;
     not_canceled = data->procfunc (temp_case, data->aux);
   
   case_count++;
@@ -288,10 +280,8 @@ prepare_for_writing (void)
      file--it's just a waste of time and space. */
 
   vfm_sink_info.ncases = 0;
      file--it's just a waste of time and space. */
 
   vfm_sink_info.ncases = 0;
-  vfm_sink_info.nval = dict_get_value_cnt (default_dict);
-  vfm_sink_info.case_size = (sizeof (struct ccase)
-                            + ((dict_get_value_cnt (default_dict) - 1)
-                                * sizeof (union value)));
+  vfm_sink_info.nval = dict_get_next_value_idx (default_dict);
+  vfm_sink_info.case_size = dict_get_case_size (default_dict);
   
   if (vfm_sink == NULL)
     {
   
   if (vfm_sink == NULL)
     {
@@ -331,14 +321,17 @@ arrange_compaction (void)
             count_values += v->nv;
           } 
       }
             count_values += v->nv;
           } 
       }
-    assert (temporary == 2 || count_values <= dict_get_value_cnt (temp_dict));
+    assert (temporary == 2
+            || count_values <= dict_get_next_value_idx (temp_dict));
   }
   
   /* Compaction is only necessary if the number of `value's to output
      differs from the number already present. */
   compaction_nval = count_values;
   }
   
   /* Compaction is only necessary if the number of `value's to output
      differs from the number already present. */
   compaction_nval = count_values;
-  compaction_necessary = (temporary == 2
-                          || count_values != dict_get_value_cnt (temp_dict));
+  if (temporary == 2 || count_values != dict_get_next_value_idx (temp_dict))
+    compaction_necessary = 1;
+  else
+    compaction_necessary = 0;
   
   if (vfm_sink->init)
     vfm_sink->init ();
   
   if (vfm_sink->init)
     vfm_sink->init ();
@@ -399,21 +392,6 @@ vector_initialization (void)
     }
 }
 
     }
 }
 
-/* Sets filter_index to an appropriate value. */
-static void
-setup_filter (void)
-{
-  filter_var = dict_get_filter (default_dict);
-  
-  if (filter_var != NULL)
-    {
-      assert (filter_var->type == NUMERIC);
-      filter_index = filter_var->index;
-    } else {
-      filter_index = -1;
-    }
-}
-
 /* Sets all the lag-related variables based on value of n_lag. */
 static void
 setup_lag (void)
 /* Sets all the lag-related variables based on value of n_lag. */
 static void
 setup_lag (void)
@@ -427,8 +405,7 @@ setup_lag (void)
   lag_head = 0;
   lag_queue = xmalloc (n_lag * sizeof *lag_queue);
   for (i = 0; i < n_lag; i++)
   lag_head = 0;
   lag_queue = xmalloc (n_lag * sizeof *lag_queue);
   for (i = 0; i < n_lag; i++)
-    lag_queue[i] = xmalloc (dict_get_value_cnt (temp_dict)
-                            * sizeof **lag_queue);
+    lag_queue[i] = xmalloc (dict_get_case_size (temp_dict));
 }
 
 /* There is a lot of potential confusion in the vfm and related
 }
 
 /* There is a lot of potential confusion in the vfm and related
@@ -489,7 +466,6 @@ open_active_file (void)
   make_temp_case ();
   vector_initialization ();
   discard_ctl_stack ();
   make_temp_case ();
   vector_initialization ();
   discard_ctl_stack ();
-  setup_filter ();
   setup_lag ();
 
   /* Debug output. */
   setup_lag ();
 
   /* Debug output. */
@@ -564,7 +540,7 @@ close_active_file (struct write_case_data *data)
   process_if_expr = NULL;
 
   /* Cancel FILTER if temporary. */
   process_if_expr = NULL;
 
   /* Cancel FILTER if temporary. */
-  if (filter_var != NULL && !FILTER_before_TEMPORARY)
+  if (dict_get_filter (default_dict) != NULL && !FILTER_before_TEMPORARY)
     dict_set_filter (default_dict, NULL);
 
   /* Cancel transformations. */
     dict_set_filter (default_dict, NULL);
 
   /* Cancel transformations. */
@@ -910,7 +886,7 @@ lag_case (void)
   if (lag_count < n_lag)
     lag_count++;
   memcpy (lag_queue[lag_head], temp_case,
   if (lag_count < n_lag)
     lag_count++;
   memcpy (lag_queue[lag_head], temp_case,
-          sizeof (union value) * dict_get_value_cnt (temp_dict));
+          dict_get_case_size (temp_dict));
   if (++lag_head >= n_lag)
     lag_head = 0;
 }
   if (++lag_head >= n_lag)
     lag_head = 0;
 }
@@ -1000,10 +976,7 @@ procedure_write_case (write_case_data wc_data)
 
   /* Call the procedure if there is one and FILTER and PROCESS IF
      don't prohibit it. */
 
   /* Call the procedure if there is one and FILTER and PROCESS IF
      don't prohibit it. */
-  if (wc_data->procfunc != NULL
-      && !FILTERED
-      && (process_if_expr == NULL ||
-         expr_evaluate (process_if_expr, temp_case, NULL) == 1.0))
+  if (wc_data->procfunc != NULL && !exclude_this_case ())
     wc_data->procfunc (temp_case, wc_data->aux);
 
   case_count++;
     wc_data->procfunc (temp_case, wc_data->aux);
 
   case_count++;
@@ -1040,6 +1013,28 @@ clear_temp_case (void)
     }
 }
 
     }
 }
 
+/* Returns nonzero if this case should be exclude as specified on
+   FILTER or PROCESS IF, otherwise zero. */
+static int
+exclude_this_case (void)
+{
+  /* FILTER. */
+  struct variable *filter_var = dict_get_filter (default_dict);
+  if (filter_var != NULL) 
+    {
+      double f = temp_case->data[filter_var->fv].f;
+      if (f == 0.0 || f == SYSMIS || is_num_user_missing (f, filter_var))
+        return 1;
+    }
+
+  /* PROCESS IF. */
+  if (process_if_expr != NULL
+      && expr_evaluate (process_if_expr, temp_case, NULL) != 1.0)
+    return 1;
+
+  return 0;
+}
+
 /* Appends TRNS to t_trns[], the list of all transformations to be
    performed on data as it is read from the active file. */
 void
 /* Appends TRNS to t_trns[], the list of all transformations to be
    performed on data as it is read from the active file. */
 void
@@ -1101,12 +1096,7 @@ dump_splits (struct ccase *c)
       assert (v->type == NUMERIC || v->type == ALPHA);
       tab_text (t, 0, i + 1, TAB_LEFT | TAT_PRINTF, "%s", v->name);
       
       assert (v->type == NUMERIC || v->type == ALPHA);
       tab_text (t, 0, i + 1, TAB_LEFT | TAT_PRINTF, "%s", v->name);
       
-      {
-       union value val = c->data[v->fv];
-       if (v->type == ALPHA)
-         val.c = c->data[v->fv].s;
-       data_out (temp_buf, &v->print, &val);
-      }
+      data_out (temp_buf, &v->print, &c->data[v->fv]);
       
       temp_buf[v->print.w] = 0;
       tab_text (t, 1, i + 1, TAT_PRINTF, "%.*s", v->print.w, temp_buf);
       
       temp_buf[v->print.w] = 0;
       tab_text (t, 1, i + 1, TAT_PRINTF, "%.*s", v->print.w, temp_buf);
@@ -1158,7 +1148,7 @@ SPLIT_FILE_procfunc (struct ccase *c, void *data_)
       switch (v->type)
        {
        case NUMERIC:
       switch (v->type)
        {
        case NUMERIC:
-         if (approx_ne (c->data[v->fv].f, prev_case->data[v->fv].f))
+         if (c->data[v->fv].f != prev_case->data[v->fv].f)
            goto not_equal;
          break;
        case ALPHA:
            goto not_equal;
          break;
        case ALPHA: