Continue reforming procedure execution. In this phase, get rid of
authorBen Pfaff <blp@gnu.org>
Thu, 4 May 2006 06:19:02 +0000 (06:19 +0000)
committerBen Pfaff <blp@gnu.org>
Thu, 4 May 2006 06:19:02 +0000 (06:19 +0000)
many global variables, consolidating procedure execution in
procedure.c.  Encapsulate transformations in new "struct trns_chain".
Also, change implementation of N OF CASES, FILTER, and PROCESS IF from
special cases to transformations.

56 files changed:
TODO
src/ChangeLog
src/data/ChangeLog
src/data/automake.mk
src/data/dictionary.c
src/data/transformations.c [new file with mode: 0644]
src/data/transformations.h [new file with mode: 0644]
src/data/variable.h
src/language/control/ChangeLog
src/language/control/do-if.c
src/language/control/loop.c
src/language/control/repeat.c
src/language/control/temporary.c
src/language/data-io/ChangeLog
src/language/data-io/data-list.c
src/language/data-io/get.c
src/language/data-io/inpt-pgm.c
src/language/data-io/matrix-data.c
src/language/data-io/print.c
src/language/dictionary/apply-dictionary.c
src/language/dictionary/formats.c
src/language/dictionary/missing-values.c
src/language/dictionary/modify-variables.c
src/language/dictionary/numeric.c
src/language/dictionary/rename-variables.c
src/language/dictionary/split-file.c
src/language/dictionary/sys-file-info.c
src/language/dictionary/value-labels.c
src/language/dictionary/variable-display.c
src/language/dictionary/variable-label.c
src/language/dictionary/vector.c
src/language/dictionary/weight.c
src/language/expressions/parse.c
src/language/lexer/variable-parser.c
src/language/stats/ChangeLog
src/language/stats/aggregate.c
src/language/stats/autorecode.c
src/language/stats/correlations.q
src/language/stats/descriptives.c
src/language/stats/flip.c
src/language/stats/means.q
src/language/stats/rank.q
src/language/stats/regression.q
src/language/stats/sort-cases.c
src/language/utilities/set.q
src/language/xforms/compute.c
src/language/xforms/count.c
src/language/xforms/recode.c
src/language/xforms/sample.c
src/language/xforms/select-if.c
src/math/ChangeLog
src/math/sort.c
src/procedure.c
src/procedure.h
src/ui/terminal/ChangeLog
src/ui/terminal/main.c

diff --git a/TODO b/TODO
index 8d1c99f88edda923530153110e6d7b2b0fae1d1a..13f839f08f8bc3f34637db7db2514846c4d09dcc 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,4 +1,18 @@
-Time-stamp: <2006-04-26 15:15:36 blp>
+Time-stamp: <2006-05-03 22:28:57 blp>
+
+Procedure processing:
+
+* Should not need temporary casefile in the common case.
+
+* All of the procedure_*() variants can (and should) be implemented in terms of
+  a variant that provides "proc_func" plus an "end_func" called after all
+  processing is complete.
+
+* The "split" variants should not dump the splits to the output file
+  automatically.  There is no need for the procedure code to talk to the output
+  manager.
+
+* LAG need not be as much of a special case.
 
 Get rid of need for GNU diff in `make check'.
 
index 604fb254d9229e299d19e7461fb69418dafa22bc..0fded64c13f6bdbac2011853221a2bc679f56c9a 100644 (file)
@@ -1,3 +1,70 @@
+Wed May  3 22:24:34 2006  Ben Pfaff  <blp@gnu.org>
+
+       Continue reforming procedure execution.  In this phase, get rid of
+       many global variables, consolidating procedure execution in
+       procedure.c.  Encapsulate transformations in new "struct
+       trns_chain".  Also, change implementation of N OF CASES, FILTER,
+       and PROCESS IF from special cases to transformations.
+        
+       * procedure.c: (global var vfm_source) Make static.  Changed
+       external references to use in_input_program(), proc_set_source(),
+       or proc_capture_output() instead.
+       (global var vfm_sink) Make static.  Changed external references to
+       use proc_set_sink() instead.
+       (global var default_dict) Move here from data/dictionary.c.
+       (static var permanent_trns_chain) New var.
+       (static var temp_dict) Renamed permanent_dict, updated references.
+       (static var temporary_trns_chain) New var.
+       (static var cur_trns_chain) New var.
+       (static var in_procedure) Removed.
+       (global var t_trns) Removed.
+       (global var n_trns) Removed.
+       (global var m_trns) Removed.
+       (global var f_trns) Removed.
+       (procedure) Even if there's "nothing to do" we need to clear
+       PROCESS IF, N OF CASES, vector state.  (This should be
+       abstracted.)
+       (multipass_callback) New function.
+       (multipass_procedure) New function.
+       (open_active_file) Add N OF CASES, FILTER, PROCESS IF
+       transformations.  Finalize transformations.  No need to call
+       ctl_stack_clear() anymore because finalizers will do that.
+       (write_case) Simplify and rewrite.
+       (execute_transformations) Removed.
+       (filter_case) Removed.
+       (close_active_file) Use proc_cancel_temporary_transformations().
+       No need to clear PROCESS IF, N OF CASES here anymore because
+       helpers do that.
+       (multipass_procedure_with_splits) Keep track of success.
+       (multipass_split_callback) Ditto.
+       (multipass_split_output) Ditto.
+       (discard_variables) No need to call ctl_stack_clear() anymore
+       because finalizers will do that.
+       (proc_capture_transformations) New function.
+       (add_transformation) Rewrite in terms of trns_chain_append().
+       (add_transformation_with_finalizer) New function.
+       (next_transformation) Rewrite in terms of trns_chain_next().
+       (proc_in_temporary_transformations) New function.
+       (proc_start_temporary_transformations) New function.
+       (proc_make_temporary_transformations_permanent) New function.
+       (proc_cancel_temporary_transformations) New function.
+       (cancel_transformations) Rename proc_cancel_all_transformations(),
+       rewrite in terms of trns_chain_destroy().
+       (proc_init) New function.
+       (proc_done) New function.
+       (proc_set_sink) New function.
+       (proc_set_source) New function.
+       (proc_has_source) New function.
+       (proc_capture_output) New function.
+       (add_case_limit_trns) New function.
+       (case_limit_trns_proc) New function.
+       (case_limit_trns_free) New function.
+       (add_filter_trns) New function.
+       (filter_trns_proc) New function.
+       (add_process_if_trns) New function.
+       (process_if_trns_proc) New function.
+       (process_if_trns_free) New function.
+
 Wed Apr 26 20:00:00 2006  Ben Pfaff  <blp@gnu.org>
 
        * procedure.c (create_trns_case): Fix inverted decision on whether
index 63bdd402d1a5675aa667344e55c028cbca1e8fb3..49c1af84e19bbf8be7e1c7df90c1437cc85f1a38 100644 (file)
@@ -1,3 +1,20 @@
+Wed May  3 22:42:12 2006  Ben Pfaff  <blp@gnu.org>
+
+       Continue reforming procedure execution.  In this phase, get rid of
+       many global variables, consolidating procedure execution in
+       procedure.c.  Encapsulate transformations in new "struct
+       trns_chain".  Also, change implementation of N OF CASES, FILTER,
+       and PROCESS IF from special cases to transformations.
+        
+       * automake.mk: (src_data_libdata_a_SOURCES) Add transformations.c,
+       transformations.h.
+
+       * dictionary.c: (global variable default_dict) Move to
+       src/procedure.c.
+
+       * variable.h: (TRNS_*) Move to transformations.h.
+       (struct transformation) Move to transformations.c.
+
 Thu May  4 13:47:06 WST 2006 John Darrington <john@darrington.wattle.id.au>
 
        * sys-file-reader.c: Fixed invalid read problems.
index 459ea2fa972fed4940536be6d8088537d089821a..2084e4f61f66158a7bcb3e33a16b842927c53714 100644 (file)
@@ -57,6 +57,8 @@ src_data_libdata_a_SOURCES = \
        src/data/sys-file-reader.h \
        src/data/sys-file-writer.c \
        src/data/sys-file-writer.h \
+       src/data/transformations.c \
+       src/data/transformations.h \
        src/data/value.h \
        src/data/value-labels.c \
        src/data/value-labels.h \
index c8840f302beebc06d8ccc0ec8abc37aeb502550e..e9a5a01450363bbdc8055abf7a760731de12facf 100644 (file)
@@ -59,9 +59,6 @@ struct dictionary
     size_t vector_cnt;          /* Number of vectors. */
   };
 
-/* Active file dictionary. */
-struct dictionary *default_dict;
-
 /* Creates and returns a new dictionary. */
 struct dictionary *
 dict_create (void) 
diff --git a/src/data/transformations.c b/src/data/transformations.c
new file mode 100644 (file)
index 0000000..e5542b8
--- /dev/null
@@ -0,0 +1,211 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
+   Written by Ben Pfaff <blp@gnu.org>.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
+
+#include <config.h>
+
+#include <data/transformations.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <libpspp/str.h>
+#include <procedure.h>
+
+#include "xalloc.h"
+
+/* A single transformation. */
+struct transformation
+  {
+    /* Offset to add to EXECUTE's return value, if it returns a
+       transformation index.  Normally 0 but set to the starting
+       index of a spliced chain after splicing. */
+    int idx_ofs;                        
+    trns_finalize_func *finalize;       /* Finalize proc. */
+    trns_proc_func *execute;            /* Executes the transformation. */
+    trns_free_func *free;               /* Garbage collector proc. */
+    void *aux;                          /* Auxiliary data. */
+  };
+
+/* A chain of transformations. */
+struct trns_chain 
+  {
+    struct transformation *trns;        /* Array of transformations. */
+    size_t trns_cnt;                    /* Number of transformations. */
+    size_t trns_cap;                    /* Allocated capacity. */
+    bool finalized;                     /* Finalize functions called? */
+  };
+
+/* Allocates and returns a new transformation chain. */
+struct trns_chain *
+trns_chain_create (void) 
+{
+  struct trns_chain *chain = xmalloc (sizeof *chain);
+  chain->trns = NULL;
+  chain->trns_cnt = 0;
+  chain->trns_cap = 0;
+  chain->finalized = false;
+  return chain;
+}
+
+/* Finalizes all the transformations in CHAIN.
+   A chain is only finalized once; afterward, calling this
+   function is a no-op.
+   Finalizers may add transformations to CHAIN, but after
+   finalization the chain's contents are fixed, so that no more
+   transformations may be added afterward. */
+void
+trns_chain_finalize (struct trns_chain *chain) 
+{
+  if (!chain->finalized) 
+    {
+      size_t i;
+
+      for (i = 0; i < chain->trns_cnt; i++) 
+        {
+          struct transformation *trns = &chain->trns[i];
+          if (trns->finalize != NULL)
+            trns->finalize (trns->aux); 
+        }
+      chain->finalized = true;
+    }
+}
+
+/* Destroys CHAIN, finalizing it in the process if it has not
+   already been finalized. */
+bool
+trns_chain_destroy (struct trns_chain *chain) 
+{
+  bool ok = true;
+
+  if (chain != NULL) 
+    {
+      size_t i;
+      
+      /* Needed to ensure that the control stack gets cleared. */
+      trns_chain_finalize (chain);
+      
+      for (i = 0; i < chain->trns_cnt; i++) 
+        {
+          struct transformation *trns = &chain->trns[i];
+          if (trns->free != NULL) 
+            ok = trns->free (trns->aux) && ok;
+        }
+      free (chain);
+    }
+  
+  return ok;
+}
+
+/* Returns true if CHAIN contains any transformations,
+   false otherwise. */
+bool
+trns_chain_is_empty (const struct trns_chain *chain) 
+{
+  return chain->trns_cnt == 0;
+}
+
+/* Adds a transformation to CHAIN with finalize function
+   FINALIZE, execute function EXECUTE, free function FREE, and
+   auxiliary data AUX. */
+void
+trns_chain_append (struct trns_chain *chain, trns_finalize_func *finalize,
+                   trns_proc_func *execute, trns_free_func *free,
+                   void *aux) 
+{
+  struct transformation *trns;
+
+  assert (!chain->finalized);
+
+  if (chain->trns_cnt == chain->trns_cap)
+    chain->trns = x2nrealloc (chain->trns, &chain->trns_cap,
+                              sizeof *chain->trns);
+
+  trns = &chain->trns[chain->trns_cnt++];
+  trns->idx_ofs = 0;
+  trns->finalize = finalize;
+  trns->execute = execute;
+  trns->free = free;
+  trns->aux = aux;
+}
+
+/* Appends the transformations in SRC to those in DST,
+   and destroys SRC.
+   Both DST and SRC must already be finalized. */
+void
+trns_chain_splice (struct trns_chain *dst, struct trns_chain *src) 
+{
+  size_t i;
+  
+  assert (dst->finalized);
+  assert (src->finalized);
+
+  if (dst->trns_cnt + src->trns_cnt > dst->trns_cap) 
+    {
+      dst->trns_cap = dst->trns_cnt + src->trns_cnt;
+      dst->trns = xnrealloc (dst->trns, dst->trns_cap, sizeof *dst->trns);
+    }
+
+  for (i = 0; i < src->trns_cnt; i++) 
+    {
+      struct transformation *d = &dst->trns[i + dst->trns_cnt];
+      const struct transformation *s = &src->trns[i];
+      *d = *s;
+      d->idx_ofs += src->trns_cnt; 
+    }
+  dst->trns_cnt += src->trns_cnt;
+
+  trns_chain_destroy (src);
+}
+
+/* Returns the index that a transformation execution function may
+   return to "jump" to the next transformation to be added. */
+size_t
+trns_chain_next (struct trns_chain *chain) 
+{
+  return chain->trns_cnt;
+}
+
+/* Executes the given CHAIN of transformations on C,
+   passing *CASE_NR as the case number.
+   If a transformation modifies *CASE_NR, it will affect the case
+   number passed to following transformations.
+   Returns the result code that caused the transformations to
+   terminate, or TRNS_CONTINUE if the transformations finished
+   due to "falling off the end" of the set of transformations. */
+enum trns_result
+trns_chain_execute (struct trns_chain *chain, struct ccase *c,
+                    const size_t *case_nr) 
+{
+  size_t i;
+
+  assert (chain->finalized);
+  for (i = 0; i < chain->trns_cnt; )
+    {
+      struct transformation *trns = &chain->trns[i];
+      int retval = trns->execute (trns->aux, c, *case_nr);
+      if (retval == TRNS_CONTINUE)
+        i++;
+      else if (retval >= 0)
+        i = retval + trns->idx_ofs;
+      else
+        return retval; 
+    }
+
+  return TRNS_CONTINUE;
+}
diff --git a/src/data/transformations.h b/src/data/transformations.h
new file mode 100644 (file)
index 0000000..196f65d
--- /dev/null
@@ -0,0 +1,57 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
+   Written by Ben Pfaff <blp@gnu.org>.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
+
+#ifndef TRANSFORMATIONS_H
+#define TRANSFORMATIONS_H 1
+
+#include <stdbool.h>
+#include <stddef.h>
+
+/* trns_proc_func return values. */
+enum trns_result 
+  {
+    TRNS_CONTINUE = -1,         /* Continue to next transformation. */
+    TRNS_DROP_CASE = -2,        /* Drop this case. */
+    TRNS_ERROR = -3,            /* A serious error, so stop the procedure. */
+    TRNS_NEXT_CASE = -4,        /* Skip to next case.  INPUT PROGRAM only. */
+    TRNS_END_FILE = -5          /* End of input.  INPUT PROGRAM only. */
+  };
+
+struct ccase;
+typedef void trns_finalize_func (void *);
+typedef int trns_proc_func (void *, struct ccase *, int);
+typedef bool trns_free_func (void *);
+\f
+/* Transformation chains. */
+
+struct trns_chain *trns_chain_create (void);
+void trns_chain_finalize (struct trns_chain *);
+bool trns_chain_destroy (struct trns_chain *);
+
+bool trns_chain_is_empty (const struct trns_chain *);
+
+void trns_chain_append (struct trns_chain *, trns_finalize_func *,
+                        trns_proc_func *, trns_free_func *, void *);
+size_t trns_chain_next (struct trns_chain *);
+enum trns_result trns_chain_execute (struct trns_chain *, struct ccase *,
+                                     const size_t *case_nr);
+
+void trns_chain_splice (struct trns_chain *, struct trns_chain *);
+
+#endif /* transformations.h */
index 2dfe56482b4224b3ad79953a63af6c28ca709d47..0f5bb26dbc1c1d5dc55901f4d4b67691fea7fb89 100644 (file)
@@ -28,8 +28,6 @@
 #include "format.h"
 #include "missing-values.h"
 
-/* Script variables. */
-
 /* Variable type. */
 enum var_type
   {
@@ -128,71 +126,15 @@ struct vector
     int cnt;                   /* Number of variables. */
   };
 \f
-void discard_variables (void);
-
-/* This is the active file dictionary. */
-extern struct dictionary *default_dict;
-\f
-/* Transformation state. */
-
 /* PROCESS IF expression. */
 extern struct expression *process_if_expr;
 \f
-/* TEMPORARY support. */
-
-/* 1=TEMPORARY has been executed at some point. */
-extern int temporary;
-
-/* If temporary!=0, the saved dictionary. */
-extern struct dictionary *temp_dict;
-
-/* If temporary!=0, index into t_trns[] (declared far below) that
-   gives the point at which data should be written out.  -1 means that
-   the data shouldn't be changed since all transformations are
-   temporary. */
-extern size_t temp_trns;
-
-void cancel_temporary (void);
-\f
 struct ccase;
 void dump_split_vars (const struct ccase *);
 \f
-/* Transformations. */
-
-/* trns_proc_func return values. */
-#define TRNS_CONTINUE   -1 /* Continue to next transformation. */
-#define TRNS_DROP_CASE  -2 /* Drop this case. */
-#define TRNS_ERROR      -3 /* A serious error, so stop the procedure. */
-#define TRNS_NEXT_CASE  -4 /* Skip to next case.  INPUT PROGRAM only. */
-#define TRNS_END_FILE   -5 /* End of input.  INPUT PROGRAM only. */
-
-typedef int trns_proc_func (void *, struct ccase *, int);
-typedef bool trns_free_func (void *);
-
-/* A transformation. */
-struct transformation
-  {
-    trns_proc_func *proc;       /* Transformation proc. */
-    trns_free_func *free;       /* Garbage collector proc. */
-    void *private;              /* Private data. */
-  };
-
-/* Array of transformations */
-extern struct transformation *t_trns;
-
-/* Number of transformations, maximum number in array currently. */
-extern size_t n_trns, m_trns;
-
-/* Index of first transformation that is really a transformation.  Any
-   transformations before this belong to INPUT PROGRAM. */
-extern size_t f_trns;
-
-void add_transformation (trns_proc_func *, trns_free_func *, void *);
-size_t next_transformation (void);
-bool cancel_transformations (void);
-\f
 struct var_set;
 
+struct dictionary;
 struct var_set *var_set_create_from_dict (const struct dictionary *d);
 struct var_set *var_set_create_from_array (struct variable *const *var,
                                            size_t);
index 4a96aeb941a9479876c7386203e97d30fc102f8b..82404832224497e88e0c15c34fee34be85427cf8 100644 (file)
@@ -1,3 +1,30 @@
+Wed May  3 22:45:41 2006  Ben Pfaff  <blp@gnu.org>
+
+       Continue reforming procedure execution.  In this phase, get rid of
+       many global variables, consolidating procedure execution in
+       procedure.c.  Encapsulate transformations in new "struct
+       trns_chain".  Also, change implementation of N OF CASES, FILTER,
+       and PROCESS IF from special cases to transformations.
+        
+       * do-if.c: (cmd_do_if) Use finalizer to ensure control stack gets
+       cleared.
+       (do_if_finalize_func) New function.
+
+       * loop.c: (create_loop_trns) Use finalizer to ensure control stack gets
+       cleared.
+       (loop_trns_finalize) New function.
+
+       * temporary.c: (global var temporary) Removed.  Changed references
+       to use proc_make_temporary_transformations_permanent() or
+       proc_in_temporary_transformations().
+       (global var temp_dict) Removed.
+       (global var temp_trns) Removed.
+       (cmd_temporary) Reimplement in terms of
+       proc_in_temporary_transformations() and
+       proc_start_temporary_transformations().
+       (cancel_temporary) Moved to procedure.c, renamed
+       proc_cancel_temporary_transformations().
+               
 Thu Mar  2 08:40:33 WST 2006 John Darrington <john@darrington.wattle.id.au>
        
        * Moved files from src directory
index c16fca926f6702dd06e30147e24aa86883d508b2..0c0ead940b744124af9a4830ce18a4f3cb80cbe4 100644 (file)
 #include <stdlib.h>
 
 #include "control-stack.h"
-#include <libpspp/message.h>
-#include <libpspp/alloc.h>
+#include <procedure.h>
+#include <data/transformations.h>
+#include <data/variable.h>
 #include <language/command.h>
-#include <libpspp/compiler.h>
-#include <libpspp/message.h>
 #include <language/expressions/public.h>
 #include <language/lexer/lexer.h>
+#include <libpspp/alloc.h>
+#include <libpspp/compiler.h>
+#include <libpspp/message.h>
+#include <libpspp/message.h>
 #include <libpspp/str.h>
-#include <data/variable.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -89,6 +91,7 @@ static bool has_else (struct do_if_trns *);
 static bool must_not_have_else (struct do_if_trns *);
 static void close_do_if (void *do_if);
 
+static trns_finalize_func do_if_finalize_func;
 static trns_proc_func do_if_trns_proc, break_trns_proc;
 static trns_free_func do_if_trns_free;
 
@@ -101,7 +104,8 @@ cmd_do_if (void)
   do_if->clause_cnt = 0;
 
   ctl_stack_push (&do_if_class, do_if);
-  add_transformation (do_if_trns_proc, do_if_trns_free, do_if);
+  add_transformation_with_finalizer (do_if_finalize_func,
+                                     do_if_trns_proc, do_if_trns_free, do_if);
 
   return parse_clause (do_if);
 }
@@ -219,6 +223,17 @@ add_clause (struct do_if_trns *do_if,
   clause->target_index = target_index;
 }
 
+/* Finalizes DO IF by clearing the control stack, thus ensuring
+   that all open DO IFs are closed. */ 
+static void
+do_if_finalize_func (void *do_if_ UNUSED) 
+{
+  /* This will be called multiple times if multiple DO IFs were
+     executed, which is slightly unclean, but at least it's
+     idempotent. */
+  ctl_stack_clear ();
+}
+
 /* DO IF transformation procedure.
    Checks each clause and jumps to the appropriate
    transformation. */
index 80a4d2147e363acc86ea8375296da5ca1b49c9d1..abbc44675841afe3dfef4454504091ee7792eace 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
-#include <libpspp/message.h>
-#include <libpspp/alloc.h>
+
+#include "control-stack.h"
 #include <data/case.h>
-#include <language/command.h>
-#include <libpspp/compiler.h>
 #include <data/dictionary.h>
-#include "control-stack.h"
-#include <libpspp/message.h>
+#include <procedure.h>
+#include <data/settings.h>
+#include <data/transformations.h>
+#include <data/variable.h>
+#include <language/command.h>
 #include <language/expressions/public.h>
 #include <language/lexer/lexer.h>
+#include <libpspp/alloc.h>
+#include <libpspp/compiler.h>
+#include <libpspp/message.h>
 #include <libpspp/misc.h>
 #include <libpspp/pool.h>
-#include <data/settings.h>
 #include <libpspp/str.h>
-#include <data/variable.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -79,6 +81,7 @@ struct loop_trns
 
 static struct ctl_class loop_class;
 
+static trns_finalize_func loop_trns_finalize;
 static trns_proc_func loop_trns_proc, end_loop_trns_proc, break_trns_proc;
 static trns_free_func loop_trns_free;
 
@@ -248,7 +251,8 @@ create_loop_trns (void)
   loop->first_expr = loop->by_expr = loop->last_expr = NULL;
   loop->loop_condition = loop->end_loop_condition = NULL;
 
-  add_transformation (loop_trns_proc, loop_trns_free, loop);
+  add_transformation_with_finalizer (loop_trns_finalize,
+                                     loop_trns_proc, loop_trns_free, loop);
   loop->past_LOOP_index = next_transformation ();
 
   ctl_stack_push (&loop_class, loop);
@@ -256,6 +260,17 @@ create_loop_trns (void)
   return loop;
 }
 
+/* Finalizes LOOP by clearing the control stack, thus ensuring
+   that all open LOOPs are closed. */ 
+static void
+loop_trns_finalize (void *do_if_ UNUSED) 
+{
+  /* This will be called multiple times if multiple LOOPs were
+     executed, which is slightly unclean, but at least it's
+     idempotent. */
+  ctl_stack_clear ();
+}
+
 /* Sets up LOOP for the first pass. */
 static int
 loop_trns_proc (void *loop_, struct ccase *c, int case_num)
index 933c9134bfcb5c8c37bdbd8d651737b07d002655..ec37382b56caa0f27bc5a93273458233f259c3ba 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
+
 #include "repeat.h"
-#include <libpspp/message.h>
+
 #include <ctype.h>
 #include <math.h>
 #include <stdlib.h>
-#include <libpspp/alloc.h>
-#include <language/command.h>
+
 #include <data/dictionary.h>
-#include "intprops.h"
-#include <libpspp/message.h>
-#include <language/line-buffer.h>
+#include <procedure.h>
+#include <data/settings.h>
+#include <language/command.h>
 #include <language/lexer/lexer.h>
+#include <language/line-buffer.h>
+#include <libpspp/alloc.h>
+#include <libpspp/message.h>
+#include <libpspp/message.h>
 #include <libpspp/misc.h>
 #include <libpspp/pool.h>
-#include <data/settings.h>
 #include <libpspp/str.h>
 #include <data/variable.h>
 
+#include "intprops.h"
+
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
index c4b2532daee73e6dda0f382eb9d5d47b2e0869ce..2424c2551de8e552025b9b132a05af227bc6daa5 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
-#include <libpspp/message.h>
+
 #include <stddef.h>
 #include <stdlib.h>
-#include <libpspp/alloc.h>
-#include <language/command.h>
-#include <data/dictionary.h>
+
 #include "control-stack.h"
-#include <libpspp/message.h>
-#include <libpspp/hash.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/str.h>
+#include <data/dictionary.h>
+#include <procedure.h>
+#include <data/transformations.h>
 #include <data/value-labels.h>
 #include <data/variable.h>
+#include <language/command.h>
+#include <language/lexer/lexer.h>
+#include <libpspp/alloc.h>
+#include <libpspp/hash.h>
+#include <libpspp/message.h>
+#include <libpspp/message.h>
+#include <libpspp/str.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-int temporary;
-struct dictionary *temp_dict;
-size_t temp_trns;
-
 /* Parses the TEMPORARY command. */
 int
 cmd_temporary (void)
 {
-  /* TEMPORARY is not allowed inside DO IF or LOOP. */
-  if (!ctl_stack_is_empty ())
-    {
-      msg (SE, _("This command is not valid inside DO IF or LOOP."));
-      return CMD_FAILURE;
-    }
-
-  /* TEMPORARY can only appear once! */
-  if (temporary)
-    {
-      msg (SE, _("This command may only appear once between "
-          "procedures and procedure-like commands."));
-      return CMD_FAILURE;
-    }
-
-  /* Make a copy of the current dictionary. */
-  temporary = 1;
-  temp_dict = dict_clone (default_dict);
-  temp_trns = n_trns;
-
+  if (!proc_in_temporary_transformations ())
+    proc_start_temporary_transformations ();
+  else
+    msg (SE, _("This command may only appear once between "
+               "procedures and procedure-like commands."));
   return lex_end_of_command ();
 }
-
-/* Cancels the temporary transformation, if any. */
-void
-cancel_temporary (void)
-{
-  if (temporary)
-    {
-      if (temp_dict) 
-        {
-          dict_destroy (temp_dict);
-          temp_dict = NULL; 
-        }
-      temporary = 0;
-      temp_trns = 0;
-    }
-}
index ee9949b24529a5dab29137dd691c3c15cc8000f6..ba70c3f3bc9050d85976a41184ad7a59cbcf7a34 100644 (file)
@@ -1,3 +1,23 @@
+Wed May  3 23:00:17 2006  Ben Pfaff  <blp@gnu.org>
+
+       Continue reforming procedure execution.  In this phase, get rid of
+       many global variables, consolidating procedure execution in
+       procedure.c.  Encapsulate transformations in new "struct
+       trns_chain".  Also, change implementation of N OF CASES, FILTER,
+       and PROCESS IF from special cases to transformations.
+        
+       * data-list.c: (data_list_trns_proc) Return TRNS_END_FILE at end
+       of file.  (Why didn't we do this before?)
+       (cmd_match_files) Direct procedure output to null sink.
+       Use discard_variables() instead of indirect version.
+
+       * inpt-pgm.c: Use transformation chain.
+       (struct input_program_pgm) Add trns_chain member.
+       (cmd_input_program) Initialize trns_chain member and capture
+       transformations with proc_capture_transformations().
+       (input_program_source_read) Use trns_chain_execute().
+       (destroy_input_program) Destroy input chain.
+
 Tue May  2 10:39:56 WST 2006 John Darrington <john@darrington.wattle.id.au>
 
        * list.q Changed from using fixed length char buffers to struct 
index 16d29c522c5c1a2fd43b2437393df76dd7d1e613..a778b5d8b166c55f91b25e8b6c14a4cf39a113a4 100644 (file)
 
 #include <data/case-source.h>
 #include <data/case.h>
+#include <data/case-source.h>
 #include <data/data-in.h>
 #include <data/dictionary.h>
 #include <data/format.h>
 #include <data/settings.h>
+#include <data/transformations.h>
 #include <data/variable.h>
 #include <language/command.h>
 #include <language/data-io/data-reader.h>
@@ -101,6 +103,7 @@ static void dump_fixed_table (const struct dls_var_spec *,
 static void dump_free_table (const struct data_list_pgm *,
                              const struct file_handle *);
 static void destroy_dls_var_spec (struct dls_var_spec *);
+
 static trns_free_func data_list_trns_free;
 static trns_proc_func data_list_trns_proc;
 
@@ -255,10 +258,10 @@ cmd_data_list (void)
   if (dls->reader == NULL)
     goto error;
 
-  if (vfm_source != NULL)
+  if (in_input_program ())
     add_transformation (data_list_trns_proc, data_list_trns_free, dls);
   else 
-    vfm_source = create_case_source (&data_list_source_class, dls);
+    proc_set_source (create_case_source (&data_list_source_class, dls));
 
   return CMD_SUCCESS;
 
@@ -534,7 +537,7 @@ fixed_parse_compatible (struct fixed_parsing_state *fx,
       else
        {
          v = dict_lookup_var_assert (default_dict, fx->name[i]);
-         if (vfm_source == NULL)
+         if (!in_input_program ())
            {
              msg (SE, _("%s is a duplicate variable name."), fx->name[i]);
              return 0;
@@ -1228,7 +1231,7 @@ data_list_trns_proc (void *dls_, struct ccase *c, int case_num UNUSED)
       retval = TRNS_ERROR;
     }
   else
-    retval = TRNS_DROP_CASE;
+    retval = TRNS_END_FILE;
   
   /* If there was an END subcommand handle it. */
   if (dls->end != NULL) 
@@ -1237,7 +1240,7 @@ data_list_trns_proc (void *dls_, struct ccase *c, int case_num UNUSED)
       if (retval == TRNS_DROP_CASE)
         {
           *end = 1.0;
-          retval = TRNS_CONTINUE;
+          retval = TRNS_END_FILE;
         }
       else
         *end = 0.0;
index b73a2bda6fdc076e243ca171ecb69412d4e33a74..b9634b1942d645ba1d86aad729fca50b19e9ca2c 100644 (file)
@@ -31,6 +31,7 @@
 #include <data/settings.h>
 #include <data/storage-stream.h>
 #include <data/sys-file-writer.h>
+#include <data/transformations.h>
 #include <data/value-labels.h>
 #include <data/variable.h>
 #include <language/command.h>
@@ -147,7 +148,7 @@ parse_read_command (enum reader_command type)
   dict_destroy (default_dict);
   default_dict = dict;
 
-  vfm_source = create_case_source (&case_reader_source_class, pgm);
+  proc_set_source (create_case_source (&case_reader_source_class, pgm));
 
   return CMD_SUCCESS;
 
@@ -887,21 +888,18 @@ cmd_match_files (void)
             }
           used_active_file = true;
 
-          if (vfm_source == NULL)
+          if (!proc_has_source ())
             {
               msg (SE, _("Cannot specify the active file since no active "
                          "file has been defined."));
               goto error;
             }
 
-          if (temporary != 0)
-            {
-              msg (SE,
-                   _("MATCH FILES may not be used after TEMPORARY when "
-                     "the active file is an input source.  "
-                     "Temporary transformations will be made permanent."));
-              cancel_temporary (); 
-            }
+          if (proc_make_temporary_transformations_permanent ())
+            msg (SE,
+                 _("MATCH FILES may not be used after TEMPORARY when "
+                   "the active file is an input source.  "
+                   "Temporary transformations will be made permanent."));
 
           file->dict = default_dict;
         }
@@ -1134,17 +1132,18 @@ cmd_match_files (void)
     goto error;
 
   if (used_active_file) 
-    ok = procedure (mtf_processing, &mtf) && mtf_processing_finish (&mtf);
+    {
+      proc_set_sink (create_case_sink (&null_sink_class, default_dict, NULL));
+      ok = procedure (mtf_processing, &mtf) && mtf_processing_finish (&mtf); 
+    }
   else
     ok = mtf_processing_finish (&mtf);
 
-  free_case_source (vfm_source);
-  vfm_source = NULL;
+  discard_variables ();
 
-  dict_destroy (default_dict);
   default_dict = mtf.dict;
   mtf.dict = NULL;
-  vfm_source = mtf.sink->class->make_source (mtf.sink);
+  proc_set_source (mtf.sink->class->make_source (mtf.sink));
   free_case_sink (mtf.sink);
   
   if (!mtf_free (&mtf))
index 0581249a841e6edd4ba8a15257a2ab2a29979ed3..fbf1d3422d940c0667dda3f295cd3d6d690ef895 100644 (file)
@@ -28,6 +28,7 @@
 #include <data/case.h>
 #include <data/case-source.h>
 #include <data/dictionary.h>
+#include <data/transformations.h>
 #include <data/variable.h>
 #include <language/command.h>
 #include <language/data-io/data-reader.h>
@@ -64,6 +65,8 @@ enum value_init_type
 
 struct input_program_pgm 
   {
+    struct trns_chain *trns_chain;
+
     size_t case_nr;             /* Incremented by END CASE transformation. */
     write_case_func *write_case;/* Called by END CASE. */
     write_case_data wc_data;    /* Aux data used by END CASE. */
@@ -110,6 +113,7 @@ cmd_input_program (void)
     return lex_end_of_command ();
 
   inp = xmalloc (sizeof *inp);
+  inp->trns_chain = NULL;
   inp->init = NULL;
   
   inside_input_program = true;
@@ -147,9 +151,8 @@ cmd_input_program (void)
       return CMD_FAILURE;
     }
   
-  /* Mark the boundary between INPUT PROGRAM transformations and
-     ordinary transformations. */
-  f_trns = n_trns;
+  inp->trns_chain = proc_capture_transformations ();
+  trns_chain_finalize (inp->trns_chain);
 
   /* Figure out how to initialize each input case. */
   inp->init_cnt = dict_get_next_value_idx (default_dict);
@@ -172,8 +175,7 @@ cmd_input_program (void)
     assert (inp->init[i] != -1);
   inp->case_size = dict_get_case_size (default_dict);
 
-  /* Create vfm_source. */
-  vfm_source = create_case_source (&input_program_source_class, inp);
+  proc_set_source (create_case_source (&input_program_source_class, inp));
 
   return CMD_SUCCESS;
 }
@@ -248,38 +250,12 @@ input_program_source_read (struct case_source *source,
   inp->wc_data = wc_data;
   for (init_case (inp, c); ; clear_case (inp, c))
     {
-      int i;
-      
-      /* Perform transformations on `blank' case. */
-      for (i = 0; i < f_trns; )
-       {
-          int code;
-
-         code = t_trns[i].proc (t_trns[i].private, c, inp->case_nr);
-         switch (code)
-           {
-           case TRNS_CONTINUE:
-             i++;
-             break;
-
-            case TRNS_DROP_CASE:
-              break;
-
-            case TRNS_ERROR:
-              return false;
-
-           case TRNS_NEXT_CASE:
-             goto next_case;
-
-           case TRNS_END_FILE:
-              return true;
-
-           default:
-             i = code;
-             break;
-           }
-       }
-    next_case: ;
+      enum trns_result result = trns_chain_execute (inp->trns_chain, c,
+                                                    &inp->case_nr);
+      if (result == TRNS_ERROR)
+        return false;
+      else if (result == TRNS_END_FILE)
+        return true;
     }
 }
 
@@ -288,6 +264,7 @@ destroy_input_program (struct input_program_pgm *pgm)
 {
   if (pgm != NULL) 
     {
+      trns_chain_destroy (pgm->trns_chain);
       free (pgm->init);
       free (pgm);
     }
index eb2d226f29341bbe4933f3219f8ca005c98bd941..ff008caa412c60532cae4b5e363d93f703bf616c 100644 (file)
@@ -972,7 +972,8 @@ read_matrices_without_rowtype (struct matrix_data_pgm *mx)
   nr.split_values = xnmalloc (dict_get_split_cnt (default_dict),
                               sizeof *nr.split_values);
 
-  vfm_source = create_case_source (&matrix_data_without_rowtype_source_class, &nr);
+  proc_set_source (create_case_source (
+                     &matrix_data_without_rowtype_source_class, &nr));
   
   ok = procedure (NULL, NULL);
 
@@ -1512,8 +1513,8 @@ read_matrices_with_rowtype (struct matrix_data_pgm *mx)
   wr.current = NULL;
   mx->cells = 0;
 
-  vfm_source = create_case_source (&matrix_data_with_rowtype_source_class,
-                                   &wr);
+  proc_set_source (create_case_source (&matrix_data_with_rowtype_source_class,
+                                       &wr));
   ok = procedure (NULL, NULL);
 
   free (wr.split_values);
index 2479b7c13f404b553504f437d9a229793ef384da..f6633652a6847baaf244241144c3161e5e29ba0f 100644 (file)
 /* FIXME: seems like a lot of code duplication with data-list.c. */
 
 #include <config.h>
-#include <libpspp/message.h>
+
 #include <stdlib.h>
-#include <libpspp/alloc.h>
+
 #include <data/case.h>
+#include <procedure.h>
+#include <data/transformations.h>
+#include <data/variable.h>
 #include <language/command.h>
-#include <libpspp/compiler.h>
 #include <language/data-io/data-writer.h>
-#include <libpspp/message.h>
-#include <language/expressions/public.h>
 #include <language/data-io/file-handle.h>
+#include <language/expressions/public.h>
 #include <language/lexer/lexer.h>
+#include <libpspp/alloc.h>
+#include <libpspp/compiler.h>
+#include <libpspp/message.h>
+#include <libpspp/message.h>
 #include <libpspp/misc.h>
 #include <output/manager.h>
 #include <output/table.h>
-#include <data/variable.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index 217f0f8928a5a7dedaaa0896cade2edee68432ab..87b71eee03ad1599ff87db765a4d8277f0a6f6a3 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
+
 #include <stdlib.h>
+
 #include <data/any-reader.h>
-#include <language/command.h>
 #include <data/dictionary.h>
-#include <libpspp/message.h>
-#include <language/data-io/file-handle.h>
 #include <data/file-handle-def.h>
-#include <libpspp/hash.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/str.h>
+#include <procedure.h>
 #include <data/value-labels.h>
 #include <data/variable.h>
+#include <language/command.h>
+#include <language/data-io/file-handle.h>
+#include <language/lexer/lexer.h>
+#include <libpspp/hash.h>
+#include <libpspp/message.h>
+#include <libpspp/str.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index c325b4082e40a897980d123217e0fcf4323aa3a9..2d5e1c354dfadbbae4d9f9a0a4898426d3083757 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
+
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
+
+#include <procedure.h>
+#include <data/variable.h>
 #include <language/command.h>
-#include <libpspp/message.h>
 #include <language/lexer/lexer.h>
+#include <libpspp/message.h>
 #include <libpspp/misc.h>
 #include <libpspp/str.h>
-#include <data/variable.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index 6b25cb072d8ac175427847fcfa07dc40c9562c0c..0757fb1dc1def6fca52d0d6590cc87ef9d0d6642 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
-#include <libpspp/message.h>
+
 #include <stdlib.h>
-#include <language/command.h>
+
 #include <data/data-in.h>
-#include <libpspp/message.h>
+#include <procedure.h>
+#include <data/variable.h>
+#include <language/command.h>
 #include <language/lexer/lexer.h>
-#include <libpspp/magic.h>
 #include <language/lexer/range-parser.h>
+#include <libpspp/magic.h>
+#include <libpspp/message.h>
+#include <libpspp/message.h>
 #include <libpspp/str.h>
-#include <data/variable.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index 7b8d5681fba57f8ed72cbaae1dd2f152a1d04eec..ad6a48e49962ba142d8a313ee5bd83addf75ebe9 100644 (file)
@@ -88,12 +88,9 @@ cmd_modify_vars (void)
 
   size_t i;
 
-  if (temporary != 0)
-    {
-      msg (SE, _("MODIFY VARS may not be used after TEMPORARY.  "
-                 "Temporary transformations will be made permanent."));
-      cancel_temporary (); 
-    }
+  if (proc_make_temporary_transformations_permanent ())
+    msg (SE, _("MODIFY VARS may not be used after TEMPORARY.  "
+               "Temporary transformations will be made permanent."));
 
   vm.reorder_vars = NULL;
   vm.reorder_cnt = 0;
index 9d94cf3f7e45350ae49b3e4092d7e0c7f350d359..f946e74a4808e61696f4bdcb563fb582904b1ceb 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
-#include <libpspp/message.h>
+
 #include <stdlib.h>
-#include <language/command.h>
+
 #include <data/dictionary.h>
-#include <libpspp/message.h>
+#include <procedure.h>
+#include <data/variable.h>
+#include <language/command.h>
 #include <language/lexer/lexer.h>
+#include <libpspp/message.h>
+#include <libpspp/message.h>
 #include <libpspp/str.h>
-#include <data/variable.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index 9ba6630281877fd779f8f43898bed72da42f399f..eedc84d4c2543f0871c96c1ad3357a3b21d2b0a4 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
+
 #include <stdlib.h>
-#include <libpspp/message.h>
-#include <libpspp/alloc.h>
-#include <language/command.h>
+
 #include <data/dictionary.h>
-#include <libpspp/message.h>
-#include <libpspp/hash.h>
+#include <procedure.h>
+#include <data/variable.h>
+#include <language/command.h>
 #include <language/lexer/lexer.h>
+#include <libpspp/alloc.h>
+#include <libpspp/hash.h>
+#include <libpspp/message.h>
 #include <libpspp/str.h>
-#include <data/variable.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -44,12 +46,9 @@ cmd_rename_variables (void)
 
   int status = CMD_CASCADING_FAILURE;
 
-  if (temporary != 0)
-    {
-      msg (SE, _("RENAME VARS may not be used after TEMPORARY.  "
-                 "Temporary transformations will be made permanent."));
-      cancel_temporary (); 
-    }
+  if (proc_make_temporary_transformations_permanent ())
+    msg (SE, _("RENAME VARS may not be used after TEMPORARY.  "
+               "Temporary transformations will be made permanent."));
 
   do
     {
index 4239ac33325e4ae31434c457205a36e7099a34e4..149523d36df741f0fcbf013496622624b51207f4 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
+
 #include <stdlib.h>
-#include <libpspp/alloc.h>
-#include <language/command.h>
+
 #include <data/dictionary.h>
-#include <libpspp/message.h>
+#include <procedure.h>
+#include <data/variable.h>
+#include <language/command.h>
 #include <language/lexer/lexer.h>
+#include <libpspp/alloc.h>
+#include <libpspp/message.h>
 #include <libpspp/str.h>
-#include <data/variable.h>
 
 int
 cmd_split_file (void)
index d3414cb23b82a091922fa495854364e1aaf1027f..97bf3df58a9c2035151f01cff8bcb27794e16f70 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
-#include <libpspp/message.h>
+
 #include <ctype.h>
 #include <stdlib.h>
-#include <libpspp/array.h>
-#include <libpspp/alloc.h>
-#include <language/command.h>
+
 #include <data/dictionary.h>
-#include <libpspp/message.h>
 #include <data/file-handle-def.h>
+#include <procedure.h>
+#include <data/sys-file-reader.h>
+#include <data/value-labels.h>
+#include <data/variable.h>
+#include <language/command.h>
 #include <language/data-io/file-handle.h>
-#include <libpspp/hash.h>
 #include <language/lexer/lexer.h>
+#include <libpspp/alloc.h>
+#include <libpspp/array.h>
+#include <libpspp/hash.h>
 #include <libpspp/magic.h>
+#include <libpspp/message.h>
+#include <libpspp/message.h>
 #include <libpspp/misc.h>
-#include <output/output.h>
-#include <data/sys-file-reader.h>
 #include <output/manager.h>
+#include <output/output.h>
 #include <output/table.h>
-#include <data/value-labels.h>
-#include <data/variable.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index 8479fe7fa74218feeb0c462aed2e86fa1c5df692..a9d3d8751799d5fc6bc1d4ea0e2184ae28858982 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
+
 #include <stdio.h>
 #include <stdlib.h>
-#include <libpspp/alloc.h>
+
+#include <procedure.h>
+#include <data/value-labels.h>
+#include <data/variable.h>
 #include <language/command.h>
-#include <libpspp/message.h>
-#include <libpspp/hash.h>
 #include <language/lexer/lexer.h>
+#include <libpspp/alloc.h>
+#include <libpspp/hash.h>
+#include <libpspp/message.h>
 #include <libpspp/str.h>
-#include <data/value-labels.h>
-#include <data/variable.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index 2632ce9e8975a5d5798c53f20a33b390831271e6..ef43c5313e4aed91b860648a8233331f780f5ab1 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
+
 #include <stdio.h>
 #include <stdlib.h>
-#include <libpspp/alloc.h>
+
+#include <procedure.h>
+#include <data/variable.h>
 #include <language/command.h>
-#include <libpspp/message.h>
 #include <language/lexer/lexer.h>
+#include <libpspp/alloc.h>
+#include <libpspp/message.h>
 #include <libpspp/str.h>
-#include <data/variable.h>
 
 /* Set variables' alignment
    This is the alignment for GUI display only.
@@ -42,7 +45,6 @@ cmd_variable_alignment (void)
       size_t i;
       enum alignment align;
 
-
       if (!parse_variables (default_dict, &v, &nv, PV_NONE))
         return CMD_FAILURE;
 
index a663dc9ddb458db614e204f43f01ec11f4148796..3692a6c4c2d532b2f7c8431c5a897f3bd4a294e0 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
+
 #include <stdio.h>
 #include <stdlib.h>
-#include <libpspp/alloc.h>
+
+#include <procedure.h>
+#include <data/variable.h>
 #include <language/command.h>
-#include <libpspp/message.h>
 #include <language/lexer/lexer.h>
+#include <libpspp/alloc.h>
+#include <libpspp/message.h>
 #include <libpspp/str.h>
-#include <data/variable.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index 7553ba2c86f193f99d9b5961e0303c3c703b19c0..90f245c85f4b84b9ca54490667fa7fd751aeadd9 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
-#include <libpspp/message.h>
+
 #include <stdlib.h>
-#include <libpspp/alloc.h>
-#include <language/command.h>
+
+#include <procedure.h>
 #include <data/dictionary.h>
-#include <libpspp/message.h>
+#include <data/variable.h>
+#include <language/command.h>
 #include <language/lexer/lexer.h>
+#include <libpspp/alloc.h>
+#include <libpspp/message.h>
 #include <libpspp/misc.h>
 #include <libpspp/str.h>
-#include <data/variable.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index 6528141f8e81f4127f1a29f804d891189502712c..121728b68e454b8d371e750f91cbb093eb4ab9a1 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
-#include <libpspp/message.h>
+
 #include <stdio.h>
-#include <language/command.h>
+
+#include <procedure.h>
 #include <data/dictionary.h>
-#include <libpspp/message.h>
+#include <data/variable.h>
+#include <language/command.h>
 #include <language/lexer/lexer.h>
+#include <libpspp/message.h>
 #include <libpspp/str.h>
-#include <data/variable.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index fdd460824e6b5c9d0435c38d9a97665c8bc7c7b7..b6c8076ce4a1fbb3b2fbdf33ce270dd8ec121b07 100644 (file)
@@ -1222,7 +1222,7 @@ parse_function (struct expression *e)
       msg (SE, _("%s is not yet implemented."), f->prototype);
       goto fail;
     }
-  if ((f->flags & OPF_PERM_ONLY) && temporary != 0
+  if ((f->flags & OPF_PERM_ONLY) && proc_in_temporary_transformations ()
     {
       msg (SE, _("%s may not appear after TEMPORARY."), f->prototype);
       goto fail;
index 7037ccbf44ece95a87fa8e37037d573ee8bec1cf..6475caf4eb951d092125f172642bdacbb81b1101 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
-#include <data/variable.h>
+
 #include <ctype.h>
 #include <stdbool.h>
 #include <stdlib.h>
+
+#include "lexer.h"
+#include <data/dictionary.h>
+#include <procedure.h>
+#include <data/variable.h>
 #include <libpspp/alloc.h>
 #include <libpspp/bit-vector.h>
-#include <data/dictionary.h>
-#include <libpspp/message.h>
 #include <libpspp/hash.h>
-#include "lexer.h"
+#include <libpspp/message.h>
 #include <libpspp/misc.h>
 #include <libpspp/pool.h>
-#include "size_max.h"
 #include <libpspp/str.h>
 
 #include "gettext.h"
index 6f7c271f141832fc12d5447a157ebe2f7bc11dfa..46c216512ecf0bca7c6f8b03248a705b471cc6e1 100644 (file)
@@ -1,3 +1,14 @@
+Wed May  3 23:05:31 2006  Ben Pfaff  <blp@gnu.org>
+
+       Continue reforming procedure execution.  In this phase, get rid of
+       many global variables, consolidating procedure execution in
+       procedure.c.  Encapsulate transformations in new "struct
+       trns_chain".  Also, change implementation of N OF CASES, FILTER,
+       and PROCESS IF from special cases to transformations.
+        
+       * aggregate.c (cmd_aggregate) Use discard_variables().
+       
+
 2006-04-28  Jason Stover  <jhs@math.gcsu.edu>
 
        * regression.q (regression_trns_resid_proc): Pass only the
index a0887e3b2c0877123fbcfa7c3072dbb8d9dee99f..e51a5a6a13724cea3a1a85357a46ffbc6e895c8a 100644 (file)
@@ -27,6 +27,7 @@
 #include <data/casefile.h>
 #include <data/dictionary.h>
 #include <data/file-handle-def.h>
+#include <procedure.h>
 #include <data/settings.h>
 #include <data/storage-stream.h>
 #include <data/sys-file-writer.h>
@@ -260,7 +261,7 @@ cmd_aggregate (void)
     {
       /* The active file will be replaced by the aggregated data,
          so TEMPORARY is moot. */
-      cancel_temporary ();
+      proc_cancel_temporary_transformations ();
 
       if (agr.sort != NULL && !presorted) 
         {
@@ -271,7 +272,7 @@ cmd_aggregate (void)
       agr.sink = create_case_sink (&storage_sink_class, agr.dict, NULL);
       if (agr.sink->class->open != NULL)
         agr.sink->class->open (agr.sink);
-      vfm_sink = create_case_sink (&null_sink_class, default_dict, NULL);
+      proc_set_sink (create_case_sink (&null_sink_class, default_dict, NULL));
       if (!procedure (agr_to_active_file, &agr))
         goto error;
       if (agr.case_cnt > 0) 
@@ -280,10 +281,10 @@ cmd_aggregate (void)
           if (!agr.sink->class->write (agr.sink, &agr.agr_case))
             goto error;
         }
-      dict_destroy (default_dict);
+      discard_variables ();
       default_dict = agr.dict;
       agr.dict = NULL;
-      vfm_source = agr.sink->class->make_source (agr.sink);
+      proc_set_source (agr.sink->class->make_source (agr.sink));
       free_case_sink (agr.sink);
     }
   else
index 8b7d9aaa5aeda8b021e6ee81fe56467c91e287fe..a4177be8e2a18ef4975b2a1a0a208a015244cc18 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
-#include <libpspp/message.h>
 #include <stdlib.h>
-#include <libpspp/alloc.h>
+
 #include <data/case.h>
+#include <data/dictionary.h>
+#include <data/transformations.h>
+#include <data/variable.h>
 #include <language/command.h>
+#include <language/lexer/lexer.h>
+#include <libpspp/alloc.h>
 #include <libpspp/compiler.h>
-#include <data/dictionary.h>
-#include <libpspp/message.h>
 #include <libpspp/hash.h>
-#include <language/lexer/lexer.h>
+#include <libpspp/message.h>
+#include <libpspp/message.h>
 #include <libpspp/pool.h>
 #include <libpspp/str.h>
-#include <data/variable.h>
 #include <procedure.h>
 
 #include "gettext.h"
index cf2300676823c886f6db2ebd84def0039a69094e..68d55635e36d92132822632d940a1c34f4125845 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
+
 #include <stdlib.h>
-#include <libpspp/alloc.h>
-#include <libpspp/compiler.h>
+
 #include <data/dictionary.h>
 #include <data/file-handle-def.h>
-#include <language/data-io/file-handle.h>
+#include <procedure.h>
+#include <data/variable.h>
 #include <language/command.h>
+#include <language/data-io/file-handle.h>
 #include <language/lexer/lexer.h>
-#include <data/variable.h>
+#include <libpspp/alloc.h>
+#include <libpspp/compiler.h>
+
 /* (headers) */
 
 struct cor_set
index 62c0ede0d9a12cd0111bebbeae0cd6fcabf75ff3..b72371488d226fa14ed31ea17c3bda8e08e4ac9e 100644 (file)
 /* FIXME: Many possible optimizations. */
 
 #include <config.h>
-#include <libpspp/message.h>
+
 #include <limits.h>
 #include <math.h>
 #include <stdlib.h>
-#include <libpspp/array.h>
-#include <libpspp/alloc.h>
+
 #include <data/case.h>
 #include <data/casefile.h>
-#include <language/command.h>
-#include <libpspp/compiler.h>
 #include <data/dictionary.h>
+#include <data/transformations.h>
+#include <data/variable.h>
+#include <language/command.h>
 #include <language/lexer/lexer.h>
-#include <libpspp/message.h>
+#include <libpspp/alloc.h>
+#include <libpspp/array.h>
+#include <libpspp/compiler.h>
 #include <libpspp/magic.h>
+#include <libpspp/message.h>
 #include <math/moments.h>
 #include <output/manager.h>
 #include <output/table.h>
-#include <data/variable.h>
 #include <procedure.h>
 
 #include "gettext.h"
index f3286107ea525b1744aa3c7a7645cd2019dce9d6..02c764b57202ab73dc616d2d329d098266a10528 100644 (file)
@@ -32,6 +32,7 @@
 #include <data/case-source.h>
 #include <data/case.h>
 #include <data/dictionary.h>
+#include <procedure.h>
 #include <data/settings.h>
 #include <data/value.h>
 #include <data/variable.h>
@@ -91,14 +92,12 @@ int
 cmd_flip (void)
 {
   struct flip_pgm *flip;
+  struct case_sink *sink;
   bool ok;
 
-  if (temporary != 0)
-    {
-      msg (SW, _("FLIP ignores TEMPORARY.  "
-                 "Temporary transformations will be made permanent."));
-      cancel_temporary (); 
-    }
+  if (proc_make_temporary_transformations_permanent ())
+    msg (SW, _("FLIP ignores TEMPORARY.  "
+               "Temporary transformations will be made permanent."));
 
   flip = pool_create_container (struct flip_pgm, pool);
   flip->var = NULL;
@@ -150,10 +149,11 @@ cmd_flip (void)
 
   /* Read the active file into a flip_sink. */
   flip->case_cnt = 0;
-  temp_trns = temporary = 0;
-  vfm_sink = flip_sink_create (flip);
-  if (vfm_sink == NULL)
+  proc_make_temporary_transformations_permanent ();
+  sink = flip_sink_create (flip);
+  if (sink == NULL)
     goto error;
+  proc_set_sink (sink);
   flip->new_names_tail = NULL;
   ok = procedure (NULL, NULL);
 
@@ -174,7 +174,7 @@ cmd_flip (void)
   flip->case_size = dict_get_case_size (default_dict);
 
   /* Set up flipped data for reading. */
-  vfm_source = flip_source_create (flip);
+  proc_set_source (flip_source_create (flip));
 
   return ok ? lex_end_of_command () : CMD_CASCADING_FAILURE;
 
index 96c1d703e32f2924f74e5450510e5ac22e4cbe8d..7fc176f78913c20682f1bac007b1e4cc2ff61446 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
+
 #include <stdlib.h>
 #include <stdio.h>
+
 #include <data/dictionary.h>
-#include <libpspp/message.h>
-#include <libpspp/alloc.h>
+#include <procedure.h>
+#include <data/variable.h>
 #include <language/command.h>
-#include <libpspp/hash.h>
 #include <language/lexer/lexer.h>
-#include <libpspp/message.h>
+#include <libpspp/alloc.h>
+#include <libpspp/hash.h>
 #include <libpspp/magic.h>
-#include <data/variable.h>
+#include <libpspp/message.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index dcd7dae60106c4be66e8c81c8185e4cc03f2e640..d3ac8edd6eb502a895992189d08fe03a8452142f 100644 (file)
@@ -19,14 +19,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 02110-1301, USA. */
 
 #include <config.h>
+
+#include "sort-criteria.h"
+#include <data/dictionary.h>
+#include <procedure.h>
+#include <data/variable.h>
 #include <language/command.h>
 #include <language/stats/sort-criteria.h>
 #include <libpspp/compiler.h>
-#include <data/dictionary.h>
 #include <math/sort.h>
-#include <data/variable.h>
-
-#include "sort-criteria.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index 793d8325662de50bb5a174285022ba54ac80b6f5..b5dabb1577ffd924e5c125541e89f5484b6bdf7a 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
-#include <stdlib.h>
+
 #include <gsl/gsl_cdf.h>
-#include <gsl/gsl_vector.h>
 #include <gsl/gsl_matrix.h>
+#include <gsl/gsl_vector.h>
 #include <math.h>
-#include <libpspp/alloc.h>
+#include <stdlib.h>
+
+#include "regression-export.h"
 #include <data/case.h>
 #include <data/casefile.h>
-#include <data/category.h>
 #include <data/cat-routines.h>
-#include <language/command.h>
-#include <libpspp/compiler.h>
-#include <math/design-matrix.h>
+#include <data/category.h>
 #include <data/dictionary.h>
-#include <libpspp/message.h>
+#include <data/missing-values.h>
+#include <data/transformations.h>
+#include <data/value-labels.h>
+#include <data/variable.h>
+#include <language/command.h>
 #include <language/data-io/file-handle.h>
-#include "gettext.h"
 #include <language/lexer/lexer.h>
-#include <math/linreg/linreg.h>
+#include <libpspp/alloc.h>
+#include <libpspp/compiler.h>
+#include <libpspp/message.h>
+#include <math/design-matrix.h>
 #include <math/linreg/coefficient.h>
-#include <data/missing-values.h>
-#include "regression-export.h"
+#include <math/linreg/linreg.h>
 #include <output/table.h>
-#include <data/value-labels.h>
-#include <data/variable.h>
 #include <procedure.h>
 
+#include "gettext.h"
+
 #define REG_LARGE_DATA 1000
 
 /* (headers) */
index dd0387418ac30a9c92b25ba84aa1ed4e2bc25bf5..156c5b42ad92de4f2e1cd920e9b04971c497d235 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
-#include <sys/types.h>
+
 #include <assert.h>
 #include <stdlib.h>
 #include <limits.h>
-#include <libpspp/alloc.h>
+
+#include "sort-criteria.h"
+#include <procedure.h>
+#include <data/settings.h>
+#include <data/variable.h>
 #include <language/command.h>
-#include <libpspp/message.h>
 #include <language/lexer/lexer.h>
-#include <data/settings.h>
-#include "sort-criteria.h"
+#include <libpspp/alloc.h>
+#include <libpspp/message.h>
 #include <math/sort.h>
-#include <data/variable.h>
+#include <sys/types.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index 55913dc09c58941c3324d06b72fdfd1081f093ee..2ad52b77a31a53cf0cd6312e7d4cbfd10aec7afc 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
-#include <data/settings.h>
-#include <libpspp/message.h>
+
 #include <stdio.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <time.h>
-#include <libpspp/alloc.h>
-#include <language/command.h>
-#include <libpspp/compiler.h>
+
 #include <data/dictionary.h>
-#include <language/line-buffer.h>
+#include <data/format.h>
+#include <procedure.h>
+#include <data/settings.h>
+#include <data/variable.h>
+#include <language/command.h>
 #include <language/lexer/lexer.h>
-#include <libpspp/message.h>
+#include <language/line-buffer.h>
+#include <libpspp/alloc.h>
+#include <libpspp/compiler.h>
+#include <libpspp/copyleft.h>
 #include <libpspp/magic.h>
-#include <output/output.h>
+#include <libpspp/message.h>
 #include <math/random.h>
-#include <data/variable.h>
-#include <data/format.h>
-#include <libpspp/copyleft.h>
-#include <data/variable.h>
-
+#include <output/output.h>
 
 #if HAVE_LIBTERMCAP
 #if HAVE_TERMCAP_H
index e6a17553377703096ecdb5b0ca57a59c52c909c6..0a399285604e7da5fc967d77fd767d205d9cbaa4 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
-#include <libpspp/message.h>
+
 #include <stdlib.h>
-#include <libpspp/alloc.h>
+
 #include <data/case.h>
-#include <language/command.h>
 #include <data/dictionary.h>
-#include <libpspp/message.h>
+#include <procedure.h>
+#include <data/transformations.h>
+#include <data/variable.h>
+#include <language/command.h>
 #include <language/expressions/public.h>
 #include <language/lexer/lexer.h>
+#include <libpspp/alloc.h>
+#include <libpspp/message.h>
+#include <libpspp/message.h>
 #include <libpspp/misc.h>
 #include <libpspp/str.h>
-#include <data/variable.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index e3f8f35805970ec579a537a98414f4eeab374c6d..a8a208b3a4df4ab4371a91b26fbc6292d12906fc 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
-#include <libpspp/message.h>
+
 #include <stdlib.h>
-#include <libpspp/alloc.h>
+
 #include <data/case.h>
+#include <data/dictionary.h>
+#include <procedure.h>
+#include <data/transformations.h>
+#include <data/variable.h>
 #include <language/command.h>
+#include <language/lexer/lexer.h>
+#include <language/lexer/range-parser.h>
+#include <libpspp/alloc.h>
 #include <libpspp/compiler.h>
-#include <data/dictionary.h>
 #include <libpspp/message.h>
-#include <language/lexer/lexer.h>
+#include <libpspp/message.h>
 #include <libpspp/pool.h>
-#include <language/lexer/range-parser.h>
 #include <libpspp/str.h>
-#include <data/variable.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index b89071a3f3ff11b88bda381f339a9c8c576fae63..c9cb203961071d556cbb2a279838fe42f36e8bb0 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
-#include <libpspp/message.h>
+
 #include <ctype.h>
 #include <math.h>
 #include <stdlib.h>
-#include <libpspp/alloc.h>
+
 #include <data/case.h>
-#include <language/command.h>
-#include <libpspp/compiler.h>
 #include <data/data-in.h>
 #include <data/dictionary.h>
-#include <libpspp/message.h>
+#include <procedure.h>
+#include <data/transformations.h>
+#include <data/variable.h>
+#include <language/command.h>
 #include <language/lexer/lexer.h>
+#include <language/lexer/range-parser.h>
+#include <libpspp/alloc.h>
+#include <libpspp/compiler.h>
 #include <libpspp/magic.h>
+#include <libpspp/message.h>
+#include <libpspp/message.h>
 #include <libpspp/pool.h>
-#include <language/lexer/range-parser.h>
 #include <libpspp/str.h>
-#include <data/variable.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index fd5bd5ec40e2d2358541caa006090c2eae7030f5..830c981e703aeef1513d27dbf6989aafff2f98fd 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
+
 #include <gsl/gsl_rng.h>
 #include <limits.h>
 #include <stdio.h>
 #include <math.h>
-#include <libpspp/alloc.h>
+
+#include <data/variable.h>
 #include <language/command.h>
+#include <language/lexer/lexer.h>
+#include <libpspp/alloc.h>
 #include <libpspp/compiler.h>
 #include <libpspp/message.h>
-#include <language/lexer/lexer.h>
-#include <math/random.h>
 #include <libpspp/str.h>
-#include <data/variable.h>
+#include <math/random.h>
+#include <procedure.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index e83abcdb4ab67a6cce0de970543c1a7af8ba97b3..f6be43c26a58b8c9bf802d5b44870d2c0821e9fc 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
+
 #include <stdlib.h>
-#include <libpspp/alloc.h>
-#include <language/command.h>
+
 #include <data/dictionary.h>
-#include <libpspp/message.h>
+#include <data/transformations.h>
+#include <procedure.h>
+#include <data/variable.h>
+#include <language/command.h>
 #include <language/expressions/public.h>
 #include <language/lexer/lexer.h>
+#include <libpspp/alloc.h>
+#include <libpspp/message.h>
 #include <libpspp/str.h>
-#include <data/variable.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index 0c834cb026ae18768d693447573ca86c115dbe7f..c78f51a858d1c59051a8b16e14c5cbfa1fed2d44 100644 (file)
@@ -1,3 +1,21 @@
+Wed May  3 23:06:43 2006  Ben Pfaff  <blp@gnu.org>
+
+       Continue reforming procedure execution.  In this phase, get rid of
+       many global variables, consolidating procedure execution in
+       procedure.c.  Encapsulate transformations in new "struct
+       trns_chain".  Also, change implementation of N OF CASES, FILTER,
+       and PROCESS IF from special cases to transformations.
+        
+       * sort.c: (prepare_to_sort_active_file) Don't run a procedure
+       here.
+       (sort_active_file_in_place) Rewrite to run a procedure, capture
+       the output, sort the output, and set that as the source for the
+       next procedure.
+       (struct sort_to_casefile_cb_data) New structure.
+       (sort_to_casefile_callback) New function.
+       (sort_active_file_to_casefile) Rewrite to use
+       multipass_procedure().
+
 Sat Apr 29 11:09:33 WST 2006 John Darrington <john@darrington.wattle.id.au>
 
        * removed unused variable.
index 9725da80a1a9896149636905599319f9e5d9c229..8ce955384b674eb4599f98a2b072e83eaa76c64b 100644 (file)
@@ -57,24 +57,13 @@ static struct casefile *do_internal_sort (struct casereader *,
 static struct casefile *do_external_sort (struct casereader *,
                                           const struct sort_criteria *);
 
-/* Gets ready to sort the active file, either in-place or to a
-   separate casefile. */
-static bool
+/* Get ready to sort the active file. */
+static void
 prepare_to_sort_active_file (void) 
 {
-  bool ok;
-  
-  /* Cancel temporary transformations and PROCESS IF. */
-  if (temporary != 0)
-    cancel_temporary (); 
+  proc_cancel_temporary_transformations (); 
   expr_free (process_if_expr);
   process_if_expr = NULL;
-
-  /* Make sure source cases are in a storage source. */
-  ok = procedure (NULL, NULL);
-  assert (case_source_is_class (vfm_source, &storage_source_class));
-
-  return ok;
 }
 
 /* Sorts the active file in-place according to CRITERIA.
@@ -82,21 +71,35 @@ prepare_to_sort_active_file (void)
 int
 sort_active_file_in_place (const struct sort_criteria *criteria) 
 {
-  struct casefile *src, *dst;
+  struct casefile *in, *out;
+
+  prepare_to_sort_active_file ();
+  if (!procedure (NULL, NULL))
+    return 0;
   
-  if (!prepare_to_sort_active_file ())
+  in = proc_capture_output ();
+  out = sort_execute (casefile_get_destructive_reader (in), criteria);
+  if (out == NULL) 
     return 0;
 
-  src = storage_source_get_casefile (vfm_source);
-  dst = sort_execute (casefile_get_destructive_reader (src), criteria);
-  free_case_source (vfm_source);
-  vfm_source = NULL;
+  proc_set_source (storage_source_create (out));
+  return 1;
+}
 
-  if (dst == NULL) 
-    return 0;
+/* Data passed to sort_to_casefile_callback(). */
+struct sort_to_casefile_cb_data 
+  {
+    const struct sort_criteria *criteria;
+    struct casefile *output;
+  };
 
-  vfm_source = storage_source_create (dst);
-  return 1;
+/* Sorts casefile CF according to the criteria in CB_DATA. */
+static bool
+sort_to_casefile_callback (const struct casefile *cf, void *cb_data_) 
+{
+  struct sort_to_casefile_cb_data *cb_data = cb_data_;
+  cb_data->output = sort_execute (casefile_get_reader (cf), cb_data->criteria);
+  return cb_data->output != NULL;
 }
 
 /* Sorts the active file to a separate casefile.  If successful,
@@ -105,13 +108,15 @@ sort_active_file_in_place (const struct sort_criteria *criteria)
 struct casefile *
 sort_active_file_to_casefile (const struct sort_criteria *criteria) 
 {
-  struct casefile *src;
+  struct sort_to_casefile_cb_data cb_data;
   
-  if (!prepare_to_sort_active_file ())
-    return NULL;
+  prepare_to_sort_active_file ();
+
+  cb_data.criteria = criteria;
+  cb_data.output = NULL;
+  multipass_procedure (sort_to_casefile_callback, &cb_data);
 
-  src = storage_source_get_casefile (vfm_source);
-  return sort_execute (casefile_get_reader (src), criteria);
+  return cb_data.output;
 }
 
 
index 67f22c5c0dfca5a0e0442feb0a8888973bd222a1..9b94da01910e4743c3cc58955d7024e5ef2637b9 100644 (file)
@@ -35,9 +35,9 @@
 #include <data/file-handle-def.h>
 #include <data/settings.h>
 #include <data/storage-stream.h>
+#include <data/transformations.h>
 #include <data/value-labels.h>
 #include <data/variable.h>
-#include <language/control/control-stack.h>
 #include <libpspp/alloc.h>
 #include <libpspp/message.h>
 #include <libpspp/misc.h>
@@ -71,32 +71,40 @@ struct write_case_data
     size_t cases_analyzed;      /* Cases passed to procedure so far. */
   };
 
-/* The current active file, from which cases are read. */
-struct case_source *vfm_source;
-
-/* The replacement active file, to which cases are written. */
-struct case_sink *vfm_sink;
-
-/* The compactor used to compact a compact, if necessary;
+/* Cases are read from vfm_source,
+   pass through permanent_trns_chain (which transforms them into
+   the format described by permanent_dict),
+   are written to vfm_sink,
+   pass through temporary_trns_chain (which transforms them into
+   the format described by default_dict),
+   and are finally passed to the procedure. */
+static struct case_source *vfm_source;
+static struct trns_chain *permanent_trns_chain;
+static struct dictionary *permanent_dict;
+static struct case_sink *vfm_sink;
+static struct trns_chain *temporary_trns_chain;
+struct dictionary *default_dict;
+
+/* The transformation chain that the next transformation will be
+   added to. */
+static struct trns_chain *cur_trns_chain;
+
+/* The compactor used to compact a case, if necessary;
    otherwise a null pointer. */
 static struct dict_compactor *compactor;
 
 /* Time at which vfm was last invoked. */
 static time_t last_vfm_invocation;
 
-/* Whether we're inside a procedure.
-   For debugging purposes only. */
-static bool in_procedure;
-
 /* Lag queue. */
 int n_lag;                     /* Number of cases to lag. */
 static int lag_count;          /* Number of cases in lag_queue so far. */
 static int lag_head;           /* Index where next case will be added. */
 static struct ccase *lag_queue; /* Array of n_lag ccase * elements. */
 
-/* Active transformations. */
-struct transformation *t_trns;
-size_t n_trns, m_trns, f_trns;
+static void add_case_limit_trns (void);
+static void add_filter_trns (void);
+static void add_process_if_trns (void);
 
 static bool internal_procedure (bool (*proc_func) (struct ccase *, void *),
                                 void *aux);
@@ -104,11 +112,6 @@ static void update_last_vfm_invocation (void);
 static void create_trns_case (struct ccase *, struct dictionary *);
 static void open_active_file (void);
 static bool write_case (struct write_case_data *wc_data);
-static int execute_transformations (struct ccase *c,
-                                    struct transformation *trns,
-                                    int first_idx, int last_idx,
-                                    int case_num);
-static int filter_case (const struct ccase *c, int case_num);
 static void lag_case (const struct ccase *c);
 static void clear_case (struct ccase *c);
 static bool close_active_file (void);
@@ -126,26 +129,17 @@ time_of_last_procedure (void)
 
 /* 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
+   do the following:
 
    1. Execute permanent transformations.  If these drop the case,
       start the next case from step 1.
 
-   2. N OF CASES.  If we have already written N cases, start the
-      next case from step 1.
-   
-   3. Write case to replacement active file.
+   2. Write case to replacement active file.
    
-   4. Execute temporary transformations.  If these drop the case,
+   3. Execute temporary transformations.  If these drop the case,
       start the next case from step 1.
       
-   5. FILTER, PROCESS IF.  If these drop the case, start the next
-      case from step 1.
-   
-   6. Post-TEMPORARY N OF CASES.  If we have already analyzed N
-      cases, start the next case from step 1.
-      
-   7. Pass case to PROC_FUNC, passing AUX as auxiliary data.
+   4. Pass case to PROC_FUNC, passing AUX as auxiliary data.
 
    Returns true if successful, false if an I/O error occurred. */
 bool
@@ -154,10 +148,14 @@ procedure (bool (*proc_func) (struct ccase *, void *), void *aux)
   if (proc_func == NULL
       && case_source_is_class (vfm_source, &storage_source_class)
       && vfm_sink == NULL
-      && !temporary
-      && n_trns == 0)
+      && temporary_trns_chain == NULL
+      && trns_chain_is_empty (permanent_trns_chain))
     {
-      /* Nothing to do. */
+      expr_free (process_if_expr);
+      process_if_expr = NULL;
+      dict_set_case_limit (default_dict, 0);
+      dict_clear_vectors (default_dict);
+
       update_last_vfm_invocation ();
       return true;
     }
@@ -167,8 +165,57 @@ procedure (bool (*proc_func) (struct ccase *, void *), void *aux)
       
       open_active_file ();
       ok = internal_procedure (proc_func, aux);
-      if (!close_active_file ())
-        ok = false;
+      ok = close_active_file () && ok;
+
+      return ok;
+    }
+}
+
+/* Callback function for multipass_procedure(). */
+static bool
+multipass_callback (struct ccase *c, void *cf_) 
+{
+  struct casefile *cf = cf_;
+  return casefile_append (cf, c);
+}
+
+/* Procedure that allows multiple passes over the input data.
+   The entire active file is passed to PROC_FUNC, with the given
+   AUX as auxiliary data, as a unit. */
+bool
+multipass_procedure (bool (*proc_func) (const struct casefile *, void *aux),
+                     void *aux) 
+{
+  if (case_source_is_class (vfm_source, &storage_source_class)
+      && vfm_sink == NULL
+      && temporary_trns_chain == NULL
+      && trns_chain_is_empty (permanent_trns_chain))
+    {
+      proc_func (storage_source_get_casefile (vfm_source), aux);
+
+      expr_free (process_if_expr);
+      process_if_expr = NULL;
+      dict_set_case_limit (default_dict, 0);
+      dict_clear_vectors (default_dict);
+
+      update_last_vfm_invocation ();
+      return true;
+    }
+  else 
+    {
+      struct casefile *cf;
+      bool ok;
+
+      assert (proc_func != NULL);
+
+      cf = casefile_create (dict_get_next_value_idx (default_dict));
+
+      open_active_file ();
+      ok = internal_procedure (multipass_callback, cf);
+      ok = proc_func (cf, aux) && ok;
+      ok = close_active_file () && ok;
+
+      casefile_destroy (cf);
 
       return ok;
     }
@@ -237,25 +284,26 @@ create_trns_case (struct ccase *trns_case, struct dictionary *dict)
 static void
 open_active_file (void)
 {
-  assert (!in_procedure);
-  in_procedure = true;
+  add_case_limit_trns ();
+  add_filter_trns ();
+  add_process_if_trns ();
 
-  /* Make temp_dict refer to the dictionary right before data
-     reaches the sink */
-  if (!temporary)
-    {
-      temp_trns = n_trns;
-      temp_dict = default_dict;
-    }
+  /* Finalize transformations. */
+  trns_chain_finalize (cur_trns_chain);
+
+  /* Make permanent_dict refer to the dictionary right before
+     data reaches the sink. */
+  if (permanent_dict == NULL)
+    permanent_dict = default_dict;
 
   /* Figure out compaction. */
-  compactor = (dict_needs_compaction (temp_dict)
-               ? dict_make_compactor (temp_dict)
+  compactor = (dict_needs_compaction (permanent_dict)
+               ? dict_make_compactor (permanent_dict)
                : NULL);
 
   /* Prepare sink. */
   if (vfm_sink == NULL)
-    vfm_sink = create_case_sink (&storage_sink_class, temp_dict, NULL);
+    vfm_sink = create_case_sink (&storage_sink_class, permanent_dict, NULL);
   if (vfm_sink->class->open != NULL)
     vfm_sink->class->open (vfm_sink);
 
@@ -270,9 +318,6 @@ open_active_file (void)
       for (i = 0; i < n_lag; i++)
         case_nullify (&lag_queue[i]);
     }
-
-  /* Close any unclosed DO IF or LOOP constructs. */
-  ctl_stack_clear ();
 }
 
 /* Transforms trns_case and writes it to the replacement active
@@ -282,25 +327,22 @@ open_active_file (void)
 static bool
 write_case (struct write_case_data *wc_data)
 {
-  int retval;
+  enum trns_result retval;
+  size_t case_nr;
   
   /* Execute permanent transformations.  */
-  retval = execute_transformations (&wc_data->trns_case, t_trns, f_trns,
-                                    temp_trns, wc_data->cases_written + 1);
-  if (retval != 1)
+  case_nr = wc_data->cases_written + 1;
+  retval = trns_chain_execute (permanent_trns_chain,
+                               &wc_data->trns_case, &case_nr);
+  if (retval != TRNS_CONTINUE)
     goto done;
 
-  /* N OF CASES. */
-  if (dict_get_case_limit (default_dict)
-      && wc_data->cases_written >= dict_get_case_limit (default_dict))
-    goto done;
-  wc_data->cases_written++;
-
   /* Write case to LAG queue. */
   if (n_lag)
     lag_case (&wc_data->trns_case);
 
   /* Write case to replacement active file. */
+  wc_data->cases_written++;
   if (vfm_sink->class->write != NULL) 
     {
       if (compactor != NULL) 
@@ -314,94 +356,24 @@ write_case (struct write_case_data *wc_data)
     }
   
   /* Execute temporary transformations. */
-  retval = execute_transformations (&wc_data->trns_case, t_trns, temp_trns,
-                                    n_trns, wc_data->cases_written);
-  if (retval != 1)
-    goto done;
-  
-  /* FILTER, PROCESS IF, post-TEMPORARY N OF CASES. */
-  if (filter_case (&wc_data->trns_case, wc_data->cases_written)
-      || (dict_get_case_limit (temp_dict)
-          && wc_data->cases_analyzed >= dict_get_case_limit (temp_dict)))
-    goto done;
-  wc_data->cases_analyzed++;
+  if (temporary_trns_chain != NULL) 
+    {
+      retval = trns_chain_execute (temporary_trns_chain,
+                                   &wc_data->trns_case,
+                                   &wc_data->cases_written);
+      if (retval != TRNS_CONTINUE)
+        goto done;
+    }
 
   /* Pass case to procedure. */
+  wc_data->cases_analyzed++;
   if (wc_data->proc_func != NULL)
     if (!wc_data->proc_func (&wc_data->trns_case, wc_data->aux))
-      retval = -1;
+      retval = TRNS_ERROR;
 
  done:
   clear_case (&wc_data->trns_case);
-  return retval != -1;
-}
-
-/* Transforms case C using the transformations in TRNS[] with
-   indexes FIRST_IDX through LAST_IDX, exclusive.  Case C will
-   become case CASE_NUM (1-based) in the output file.  Returns 1
-   if the case was successfully transformed, 0 if it was filtered
-   out by one of the transformations, or -1 if the procedure
-   should be abandoned due to a fatal error. */
-static int
-execute_transformations (struct ccase *c,
-                         struct transformation *trns,
-                         int first_idx, int last_idx,
-                         int case_num) 
-{
-  int idx;
-
-  for (idx = first_idx; idx != last_idx; )
-    {
-      struct transformation *t = &trns[idx];
-      int retval = t->proc (t->private, c, case_num);
-      switch (retval)
-        {
-        case TRNS_CONTINUE:
-          idx++;
-          break;
-          
-        case TRNS_DROP_CASE:
-          return 0;
-
-        case TRNS_ERROR:
-          return -1;
-
-        case TRNS_NEXT_CASE:
-          abort ();
-
-        case TRNS_END_FILE:
-          abort ();
-          
-        default:
-          idx = retval;
-          break;
-        }
-    }
-
-  return 1;
-}
-
-/* Returns nonzero if case C with case number CASE_NUM should be
-   excluded as specified on FILTER or PROCESS IF, otherwise
-   zero. */
-static int
-filter_case (const struct ccase *c, int case_idx)
-{
-  /* FILTER. */
-  struct variable *filter_var = dict_get_filter (default_dict);
-  if (filter_var != NULL) 
-    {
-      double f = case_num (c, filter_var->fv);
-      if (f == 0.0 || mv_is_num_missing (&filter_var->miss, f))
-        return 1;
-    }
-
-  /* PROCESS IF. */
-  if (process_if_expr != NULL
-      && expr_evaluate_num (process_if_expr, c, case_idx) != 1.0)
-    return 1;
-
-  return 0;
+  return retval != TRNS_ERROR;
 }
 
 /* Add C to the lag queue. */
@@ -452,13 +424,8 @@ close_active_file (void)
       n_lag = 0;
     }
   
-  /* Dictionary from before TEMPORARY becomes permanent.. */
-  if (temporary)
-    {
-      dict_destroy (default_dict);
-      default_dict = temp_dict;
-      temp_dict = NULL;
-    }
+  /* Dictionary from before TEMPORARY becomes permanent. */
+  proc_cancel_temporary_transformations ();
 
   /* Finish compaction. */
   if (compactor != NULL) 
@@ -479,16 +446,9 @@ close_active_file (void)
 
   /* Cancel TEMPORARY, PROCESS IF, FILTER, N OF CASES, vectors,
      and get rid of all the transformations. */
-  cancel_temporary ();
-  expr_free (process_if_expr);
-  process_if_expr = NULL;
-  dict_set_case_limit (default_dict, 0);
   dict_clear_vectors (default_dict);
-
-  assert (in_procedure);
-  in_procedure = false;
-
-  return cancel_transformations ();
+  permanent_dict = NULL;
+  return proc_cancel_all_transformations ();
 }
 \f
 /* Returns a pointer to the lagged case from N_BEFORE cases before the
@@ -509,56 +469,6 @@ lagged_case (int n_before)
   else
     return NULL;
 }
-   
-/* 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 (trns_proc_func *proc, trns_free_func *free, void *private)
-{
-  struct transformation *trns;
-
-  assert (!in_procedure);
-
-  if (n_trns >= m_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
-   created by the input program.
-   Returns true if successful, false if an I/O error occurred. */
-bool
-cancel_transformations (void)
-{
-  bool ok = true;
-  size_t i;
-  for (i = 0; i < n_trns; i++)
-    {
-      struct transformation *t = &t_trns[i];
-      if (t->free != NULL) 
-        {
-          if (!t->free (t->private))
-            ok = false; 
-        }
-    }
-  n_trns = f_trns = 0;
-  free (t_trns);
-  t_trns = NULL;
-  m_trns = 0;
-  return ok;
-}
 \f
 /* Represents auxiliary data for handling SPLIT FILE. */
 struct split_aux_data 
@@ -714,7 +624,7 @@ struct multipass_split_aux_data
   };
 
 static bool multipass_split_callback (struct ccase *c, void *aux_);
-static void multipass_split_output (struct multipass_split_aux_data *);
+static bool multipass_split_output (struct multipass_split_aux_data *);
 
 /* Returns true if successful, false if an I/O error occurred. */
 bool
@@ -736,7 +646,7 @@ multipass_procedure_with_splits (bool (*split_func) (const struct casefile *,
 
   ok = internal_procedure (multipass_split_callback, &aux);
   if (aux.casefile != NULL)
-    multipass_split_output (&aux);
+    ok = multipass_split_output (&aux) && ok;
   case_destroy (&aux.prev_case);
 
   if (!close_active_file ())
@@ -750,13 +660,14 @@ static bool
 multipass_split_callback (struct ccase *c, void *aux_)
 {
   struct multipass_split_aux_data *aux = aux_;
+  bool ok = true;
 
   /* Start a new series if needed. */
   if (aux->casefile == NULL || !equal_splits (c, &aux->prev_case))
     {
       /* Pass any cases to split_func. */
       if (aux->casefile != NULL)
-        multipass_split_output (aux);
+        ok = multipass_split_output (aux);
 
       /* Start a new casefile. */
       aux->casefile = casefile_create (dict_get_next_value_idx (default_dict));
@@ -767,18 +678,21 @@ multipass_split_callback (struct ccase *c, void *aux_)
       case_clone (&aux->prev_case, c);
     }
 
-  return casefile_append (aux->casefile, c);
+  return casefile_append (aux->casefile, c) && ok;
 }
 
-static void
+static bool
 multipass_split_output (struct multipass_split_aux_data *aux)
 {
+  bool ok;
+  
   assert (aux->casefile != NULL);
-  aux->split_func (aux->casefile, aux->func_aux);
+  ok = aux->split_func (aux->casefile, aux->func_aux);
   casefile_destroy (aux->casefile);
   aux->casefile = NULL;
-}
 
+  return ok;
+}
 
 /* Discards all the current state in preparation for a data-input
    command like DATA LIST or GET. */
@@ -796,12 +710,307 @@ discard_variables (void)
       vfm_source = NULL;
     }
 
-  cancel_transformations ();
-
-  ctl_stack_clear ();
+  proc_cancel_all_transformations ();
 
   expr_free (process_if_expr);
   process_if_expr = NULL;
 
-  cancel_temporary ();
+  proc_cancel_temporary_transformations ();
+}
+\f
+/* Returns the current set of permanent transformations,
+   and clears the permanent transformations.
+   For use by INPUT PROGRAM. */
+struct trns_chain *
+proc_capture_transformations (void) 
+{
+  struct trns_chain *chain;
+  
+  assert (temporary_trns_chain == NULL);
+  chain = permanent_trns_chain;
+  cur_trns_chain = permanent_trns_chain = trns_chain_create ();
+  return chain;
+}
+
+/* Adds a transformation that processes a case with PROC and
+   frees itself with FREE to the current set of transformations.
+   The functions are passed AUX as auxiliary data. */
+void
+add_transformation (trns_proc_func *proc, trns_free_func *free, void *aux)
+{
+  trns_chain_append (cur_trns_chain, NULL, proc, free, aux);
+}
+
+/* Adds a transformation that processes a case with PROC and
+   frees itself with FREE to the current set of transformations.
+   When parsing of the block of transformations is complete,
+   FINALIZE will be called.
+   The functions are passed AUX as auxiliary data. */
+void
+add_transformation_with_finalizer (trns_finalize_func *finalize,
+                                   trns_proc_func *proc,
+                                   trns_free_func *free, void *aux)
+{
+  trns_chain_append (cur_trns_chain, finalize, proc, free, aux);
+}
+
+/* Returns the index of the next transformation.
+   This value can be returned by a transformation procedure
+   function to indicate a "jump" to that transformation. */
+size_t
+next_transformation (void) 
+{
+  return trns_chain_next (cur_trns_chain);
+}
+
+/* Returns true if the next call to add_transformation() will add
+   a temporary transformation, false if it will add a permanent
+   transformation. */
+bool
+proc_in_temporary_transformations (void) 
+{
+  return temporary_trns_chain != NULL;
+}
+
+/* Marks the start of temporary transformations.
+   Further calls to add_transformation() will add temporary
+   transformations. */
+void
+proc_start_temporary_transformations (void) 
+{
+  if (!proc_in_temporary_transformations ())
+    {
+      add_case_limit_trns ();
+
+      permanent_dict = dict_clone (default_dict);
+      trns_chain_finalize (permanent_trns_chain);
+      temporary_trns_chain = cur_trns_chain = trns_chain_create ();
+    }
+}
+
+/* Converts all the temporary transformations, if any, to
+   permanent transformations.  Further transformations will be
+   permanent.
+   Returns true if anything changed, false otherwise. */
+bool
+proc_make_temporary_transformations_permanent (void) 
+{
+  if (proc_in_temporary_transformations ()) 
+    {
+      trns_chain_finalize (temporary_trns_chain);
+      trns_chain_splice (permanent_trns_chain, temporary_trns_chain);
+      temporary_trns_chain = NULL;
+
+      dict_destroy (permanent_dict);
+      permanent_dict = NULL;
+
+      return true;
+    }
+  else
+    return false;
+}
+
+/* Cancels all temporary transformations, if any.  Further
+   transformations will be permanent.
+   Returns true if anything changed, false otherwise. */
+bool
+proc_cancel_temporary_transformations (void) 
+{
+  if (proc_in_temporary_transformations ()) 
+    {
+      dict_destroy (default_dict);
+      default_dict = permanent_dict;
+      permanent_dict = NULL;
+
+      trns_chain_destroy (temporary_trns_chain);
+      temporary_trns_chain = NULL;
+
+      return true;
+    }
+  else
+    return false;
+}
+
+/* Cancels all transformations, if any.
+   Returns true if successful, false on I/O error. */
+bool
+proc_cancel_all_transformations (void)
+{
+  bool ok;
+  ok = trns_chain_destroy (permanent_trns_chain);
+  ok = trns_chain_destroy (temporary_trns_chain) && ok;
+  permanent_trns_chain = cur_trns_chain = trns_chain_create ();
+  temporary_trns_chain = NULL;
+  return ok;
+}
+\f
+/* Initializes procedure handling. */
+void
+proc_init (void) 
+{
+  default_dict = dict_create ();
+  proc_cancel_all_transformations ();
+}
+
+/* Finishes up procedure handling. */
+void
+proc_done (void)
+{
+  discard_variables ();
+}
+
+/* Sets SINK as the destination for procedure output from the
+   next procedure. */
+void
+proc_set_sink (struct case_sink *sink) 
+{
+  assert (vfm_sink == NULL);
+  vfm_sink = sink;
+}
+
+/* Sets SOURCE as the source for procedure input for the next
+   procedure. */
+void
+proc_set_source (struct case_source *source) 
+{
+  assert (vfm_source == NULL);
+  vfm_source = source;
+}
+
+/* Returns true if a source for the next procedure has been
+   configured, false otherwise. */
+bool
+proc_has_source (void) 
+{
+  return vfm_source != NULL;
+}
+
+/* Returns the output from the previous procedure.
+   For use only immediately after executing a procedure.
+   The returned casefile is owned by the caller; it will not be
+   automatically used for the next procedure's input. */
+struct casefile *
+proc_capture_output (void) 
+{
+  struct casefile *casefile;
+
+  /* Try to make sure that this function is called immediately
+     after procedure() or a similar function. */
+  assert (vfm_source != NULL);
+  assert (case_source_is_class (vfm_source, &storage_source_class));
+  assert (trns_chain_is_empty (permanent_trns_chain));
+  assert (!proc_in_temporary_transformations ());
+
+  casefile = storage_source_decapsulate (vfm_source);
+  vfm_source = NULL;
+
+  return casefile;
+}
+\f
+static trns_proc_func case_limit_trns_proc;
+static trns_free_func case_limit_trns_free;
+
+/* Adds a transformation that limits the number of cases that may
+   pass through, if default_dict has a case limit. */
+static void
+add_case_limit_trns (void) 
+{
+  size_t case_limit = dict_get_case_limit (default_dict);
+  if (case_limit != 0)
+    {
+      size_t *cases_remaining = xmalloc (sizeof *cases_remaining);
+      *cases_remaining = case_limit;
+      add_transformation (case_limit_trns_proc, case_limit_trns_free,
+                          cases_remaining);
+      dict_set_case_limit (default_dict, 0);
+    }
+}
+
+/* Limits the maximum number of cases processed to
+   *CASES_REMAINING. */
+static int
+case_limit_trns_proc (void *cases_remaining_,
+                      struct ccase *c UNUSED, int case_nr UNUSED) 
+{
+  size_t *cases_remaining = cases_remaining_;
+  if (*cases_remaining > 0) 
+    {
+      *cases_remaining--;
+      return TRNS_CONTINUE;
+    }
+  else
+    return TRNS_DROP_CASE;
+}
+
+/* Frees the data associated with a case limit transformation. */
+static bool
+case_limit_trns_free (void *cases_remaining_) 
+{
+  size_t *cases_remaining = cases_remaining_;
+  free (cases_remaining);
+  return true;
+}
+\f
+static trns_proc_func filter_trns_proc;
+
+/* Adds a temporary transformation to filter data according to
+   the variable specified on FILTER, if any. */
+static void
+add_filter_trns (void) 
+{
+  struct variable *filter_var = dict_get_filter (default_dict);
+  if (filter_var != NULL) 
+    {
+      proc_start_temporary_transformations ();
+      add_transformation (filter_trns_proc, NULL, filter_var);
+    }
+}
+
+/* FILTER transformation. */
+static int
+filter_trns_proc (void *filter_var_,
+                  struct ccase *c UNUSED, int case_nr UNUSED) 
+  
+{
+  struct variable *filter_var = filter_var_;
+  double f = case_num (c, filter_var->fv);
+  return (f != 0.0 && !mv_is_num_missing (&filter_var->miss, f)
+          ? TRNS_CONTINUE : TRNS_DROP_CASE);
+}
+\f
+static trns_proc_func process_if_trns_proc;
+static trns_free_func process_if_trns_free;
+
+/* Adds a temporary transformation to filter data according to
+   the expression specified on PROCESS IF, if any. */
+static void
+add_process_if_trns (void) 
+{
+  if (process_if_expr != NULL) 
+    {
+      proc_start_temporary_transformations ();
+      add_transformation (process_if_trns_proc, process_if_trns_free,
+                          process_if_expr);
+      process_if_expr = NULL;
+    }
+}
+
+/* PROCESS IF transformation. */
+static int
+process_if_trns_proc (void *expression_,
+                      struct ccase *c UNUSED, int case_nr UNUSED) 
+  
+{
+  struct expression *expression = expression_;
+  return (expr_evaluate_num (expression, c, case_nr) == 1.0
+          ? TRNS_CONTINUE : TRNS_DROP_CASE);
+}
+
+/* Frees a PROCESS IF transformation. */
+static bool
+process_if_trns_free (void *expression_) 
+{
+  struct expression *expression = expression_;
+  expr_free (expression);
+  return true;
 }
index f9f43f490b30056ab0e0d3dd1db19803b48bbfe5..5a1968782cb9fa462aaf29351cbd7ed8a0a48e61 100644 (file)
 
 #include <time.h>
 #include <stdbool.h>
+#include <data/transformations.h>
 
 struct ccase;
 struct casefile;
+struct case_sink;
+struct case_source;
 
-/* The current active file, from which cases are read. */
-extern struct case_source *vfm_source;
+/* Dictionary produced by permanent and temporary transformations
+   on data from the source. */
+extern struct dictionary *default_dict;
+\f
+/* Transformations. */
 
-/* The replacement active file, to which cases are written. */
-extern struct case_sink *vfm_sink;
+void add_transformation (trns_proc_func *, trns_free_func *, void *);
+void add_transformation_with_finalizer (trns_finalize_func *,
+                                        trns_proc_func *,
+                                        trns_free_func *, void *);
+size_t next_transformation (void);
+
+void discard_variables (void);
+
+bool proc_cancel_all_transformations (void);
+struct trns_chain *proc_capture_transformations (void);
+
+void proc_start_temporary_transformations (void);
+bool proc_in_temporary_transformations (void);
+bool proc_make_temporary_transformations_permanent (void);
+bool proc_cancel_temporary_transformations (void);
+\f
+/* Procedures. */
+
+void proc_init (void);
+void proc_done (void);
+
+void proc_set_source (struct case_source *);
+bool proc_has_source (void);
+
+void proc_set_sink (struct case_sink *);
+struct casefile *proc_capture_output (void);
 
 bool procedure (bool (*proc_func) (struct ccase *, void *aux), void *aux);
 bool procedure_with_splits (void (*begin_func) (void *aux),
                             bool (*proc_func) (struct ccase *, void *aux),
                             void (*end_func) (void *aux),
                             void *aux);
+bool multipass_procedure (bool (*proc_func) (const struct casefile *,
+                                             void *aux),
+                          void *aux);
 bool multipass_procedure_with_splits (bool (*) (const struct casefile *,
                                                 void *),
                                       void *aux);
 time_t time_of_last_procedure (void);
-
+\f
 /* Number of cases to lag. */
 extern int n_lag;
 
index 1d08101057104aeafb0bc547dfe5266650138fe7..330d94abc0e36f1402efac75d00f9224549a5585 100644 (file)
@@ -1,3 +1,14 @@
+Wed May  3 23:09:37 2006  Ben Pfaff  <blp@gnu.org>
+
+       Continue reforming procedure execution.  In this phase, get rid of
+       many global variables, consolidating procedure execution in
+       procedure.c.  Encapsulate transformations in new "struct
+       trns_chain".  Also, change implementation of N OF CASES, FILTER,
+       and PROCESS IF from special cases to transformations.
+        
+       * main.c: (main) Use proc_init().
+       (terminate) Use proc_done().
+
 Wed Apr 26 13:34:54 2006  Ben Pfaff  <blp@gnu.org>
 
        Improve command name completion in readline.
index 2600a04883796c8870b63eb0ea3868dc7c465dba..7560dcfe0d3d2b424e37d7efb37cf62f1775a108 100644 (file)
@@ -19,6 +19,9 @@
 
 #include <config.h>
 
+#include <signal.h>
+#include <stdio.h>
+
 #include "command-line.h"
 #include "msg-ui.h"
 #include "progname.h"
@@ -39,9 +42,7 @@
 #include <libpspp/version.h>
 #include <math/random.h>
 #include <output/output.h>
-#include <signal.h>
-#include <stdio.h>
-
+#include <procedure.h>
 
 #if HAVE_FPU_CONTROL_H
 #include <fpu_control.h>
@@ -93,8 +94,7 @@ main (int argc, char **argv)
   readln_initialize ();
   settings_init ();
   random_init ();
-
-  default_dict = dict_create ();
+  proc_init ();
 
   if (parse_command_line (argc, argv)) 
     {
@@ -135,7 +135,8 @@ execute_command (void)
      Any lines read after the first token must be continuation
      lines. */
   getl_set_prompt_style (GETL_PROMPT_LATER);
-  return cmd_parse (vfm_source != NULL ? CMD_STATE_DATA : CMD_STATE_INITIAL);
+  return cmd_parse (proc_has_source ()
+                    ? CMD_STATE_DATA : CMD_STATE_INITIAL);
 }
 \f
 static void
@@ -197,8 +198,7 @@ terminate (bool success)
     {
       terminating = true;
 
-      cancel_transformations ();
-      dict_destroy (default_dict);
+      proc_done ();
 
       random_done ();
       settings_done ();