Subcommand to export a model as a C function
[pspp-builds.git] / src / vfm.c
index 6d7e526bf1a5d66a015eb3658e4dd22184f2264b..3d8f03ae56b97f27ef2c01fb1c8cbf0d1c195d6b 100644 (file)
--- a/src/vfm.c
+++ b/src/vfm.c
@@ -30,8 +30,9 @@
 #include "alloc.h"
 #include "case.h"
 #include "casefile.h"
+#include "command.h"
 #include "dictionary.h"
-#include "do-ifP.h"
+#include "ctl-stack.h"
 #include "error.h"
 #include "expressions/public.h"
 #include "misc.h"
@@ -79,7 +80,7 @@ struct case_sink *vfm_sink;
 static int compaction_necessary;
 
 /* Time at which vfm was last invoked. */
-time_t last_vfm_invocation;
+static time_t last_vfm_invocation;
 
 /* Lag queue. */
 int n_lag;                     /* Number of cases to lag. */
@@ -89,11 +90,12 @@ static struct ccase *lag_queue; /* Array of n_lag ccase * elements. */
 
 static void internal_procedure (int (*proc_func) (struct ccase *, void *),
                                 void *aux);
+static void update_last_vfm_invocation (void);
 static void create_trns_case (struct ccase *, struct dictionary *);
 static void open_active_file (void);
 static int write_case (struct write_case_data *wc_data);
 static int execute_transformations (struct ccase *c,
-                                    struct trns_header **trns,
+                                    struct transformation *trns,
                                     int first_idx, int last_idx,
                                     int case_num);
 static int filter_case (const struct ccase *c, int case_num);
@@ -103,6 +105,15 @@ static void close_active_file (void);
 \f
 /* Public functions. */
 
+/* Returns the last time the data was read. */
+time_t
+vfm_last_invocation (void) 
+{
+  if (last_vfm_invocation == 0)
+    update_last_vfm_invocation ();
+  return last_vfm_invocation;
+}
+
 /* Reads the data from the input program and writes it to a new
    active file.  For each case we read from the input program, we
    do the following
@@ -135,6 +146,7 @@ procedure (int (*proc_func) (struct ccase *, void *), void *aux)
       && n_trns == 0)
     {
       /* Nothing to do. */
+      update_last_vfm_invocation ();
       return;
     }
 
@@ -161,7 +173,7 @@ internal_procedure (int (*proc_func) (struct ccase *, void *), void *aux)
   case_create (&wc_data.sink_case, dict_get_next_value_idx (default_dict));
   wc_data.cases_written = 0;
 
-  last_vfm_invocation = time (NULL);
+  update_last_vfm_invocation ();
 
   if (vfm_source != NULL) 
     vfm_source->class->read (vfm_source,
@@ -174,6 +186,13 @@ internal_procedure (int (*proc_func) (struct ccase *, void *), void *aux)
   assert (--recursive_call == 0);
 }
 
+/* Updates last_vfm_invocation. */
+static void
+update_last_vfm_invocation (void) 
+{
+  last_vfm_invocation = time (NULL);
+}
+
 /* Creates and returns a case, initializing it from the vectors
    that say which `value's need to be initialized just once, and
    which ones need to be re-initialized before every case. */
@@ -226,13 +245,13 @@ open_active_file (void)
   
       lag_count = 0;
       lag_head = 0;
-      lag_queue = xmalloc (n_lag * sizeof *lag_queue);
+      lag_queue = xnmalloc (n_lag, sizeof *lag_queue);
       for (i = 0; i < n_lag; i++)
         case_nullify (&lag_queue[i]);
     }
 
   /* Close any unclosed DO IF or LOOP constructs. */
-  discard_ctl_stack ();
+  ctl_stack_clear ();
 }
 
 /* Transforms trns_case and writes it to the replacement active
@@ -298,7 +317,7 @@ write_case (struct write_case_data *wc_data)
    transformations, nonzero otherwise. */
 static int
 execute_transformations (struct ccase *c,
-                         struct trns_header **trns,
+                         struct transformation *trns,
                          int first_idx, int last_idx,
                          int case_num) 
 {
@@ -306,7 +325,8 @@ execute_transformations (struct ccase *c,
 
   for (idx = first_idx; idx != last_idx; )
     {
-      int retval = trns[idx]->proc (trns[idx], c, case_num);
+      struct transformation *t = &trns[idx];
+      int retval = t->proc (t->private, c, case_num);
       switch (retval)
         {
         case -1:
@@ -602,15 +622,24 @@ lagged_case (int n_before)
 /* Appends TRNS to t_trns[], the list of all transformations to be
    performed on data as it is read from the active file. */
 void
-add_transformation (struct trns_header * trns)
+add_transformation (trns_proc_func *proc, trns_free_func *free, void *private)
 {
+  struct transformation *trns;
   if (n_trns >= m_trns)
-    {
-      m_trns += 16;
-      t_trns = xrealloc (t_trns, sizeof *t_trns * m_trns);
-    }
-  t_trns[n_trns] = trns;
-  trns->index = n_trns++;
+    t_trns = x2nrealloc (t_trns, &m_trns, sizeof *t_trns);
+  trns = &t_trns[n_trns++];
+  trns->proc = proc;
+  trns->free = free;
+  trns->private = private;
+}
+
+/* Returns the index number that the next transformation added by
+   add_transformation() will receive.  A trns_proc_func that
+   returns this index causes control flow to jump to it. */
+size_t
+next_transformation (void) 
+{
+  return n_trns;
 }
 
 /* Cancels all active transformations, including any transformations
@@ -618,12 +647,12 @@ add_transformation (struct trns_header * trns)
 void
 cancel_transformations (void)
 {
-  int i;
+  size_t i;
   for (i = 0; i < n_trns; i++)
     {
-      if (t_trns[i]->free)
-       t_trns[i]->free (t_trns[i]);
-      free (t_trns[i]);
+      struct transformation *t = &t_trns[i];
+      if (t->free != NULL)
+       t->free (t->private);
     }
   n_trns = f_trns = 0;
   free (t_trns);
@@ -907,3 +936,32 @@ multipass_split_output (struct multipass_split_aux_data *aux)
   casefile_destroy (aux->casefile);
   aux->casefile = NULL;
 }
+
+
+/* Discards all the current state in preparation for a data-input
+   command like DATA LIST or GET. */
+void
+discard_variables (void)
+{
+  dict_clear (default_dict);
+  default_handle = NULL;
+
+  n_lag = 0;
+  
+  if (vfm_source != NULL)
+    {
+      free_case_source (vfm_source);
+      vfm_source = NULL;
+    }
+
+  cancel_transformations ();
+
+  ctl_stack_clear ();
+
+  expr_free (process_if_expr);
+  process_if_expr = NULL;
+
+  cancel_temporary ();
+
+  pgm_state = STATE_INIT;
+}