Start working to eliminate VFM dependence on static variables.
authorBen Pfaff <blp@gnu.org>
Thu, 4 Mar 2004 03:57:16 +0000 (03:57 +0000)
committerBen Pfaff <blp@gnu.org>
Thu, 4 Mar 2004 03:57:16 +0000 (03:57 +0000)
28 files changed:
src/ChangeLog
src/aggregate.c
src/algorithm.h
src/autorecode.c
src/compute.c
src/count.c
src/data-list.c
src/data-list.h
src/descript.q
src/do-if.c
src/expr-evl.c
src/expr.h
src/file-type.c
src/flip.c
src/get.c
src/inpt-pgm.c
src/loop.c
src/main.c
src/matrix-data.c
src/print.c
src/recode.c
src/sample.c
src/sel-if.c
src/sort.c
src/var.h
src/vfm.c
src/vfm.h
src/vfmP.h

index eb405c3516cce83d6602c25234aea103947657ee..57862a16cd348f1134a2fd241860516400e1a761 100644 (file)
@@ -1,3 +1,104 @@
+Wed Mar  3 09:30:09 2004  Ben Pfaff  <blp@gnu.org>
+
+       * main.c: (main) sigaction()'s sa_flags member was uninitialized.
+       Just use signal() instead.
+
+Wed Mar  3 09:26:30 2004  Ben Pfaff  <blp@gnu.org>
+
+       Get rid of vfm_sink_info and vfm_source_info.
+       
+       * aggregate.c: (agr_00x_end_func) Don't increment
+       sfm_sink_info.ncases.
+
+       * sort.c: (do_internal_sort) Get case count from
+       vfm_source->class->count().
+       (struct external_sort) Add `case_size' member.
+       (do_external_sort) Initialize case_size.
+       (struct initial_run_state) Add `case_size' member.
+       (write_initial_runs) Initialize case_size.
+       (sort_sink_write) Use case_size.
+       (read_external_sort_output) Use case_size.  Get case_cnt from
+       initial_runs.
+
+       * vfm.c: (struct write_case_data) Add underscores to existing arg
+       names, all references updated.  Renamed `aux' as `func_aux', all
+       references updated.  Added new `aux' member.
+       (global var vfm_source_info) Removed.
+       (global var vfm_sink_info) Removed.
+       (struct procedure_aux_data) New.
+       (struct split_aux_data) New.
+       (procedure) Use `aux' fields for procedure_aux_data,
+       split_aux_data.
+       (process_active_file_write_case) Pass case_count + 1 to
+       transformation procedures, exclude_this_case().
+       (process_active_file_output_case) Don't increment
+       vfm_sink_info.ncases.
+       (prepare_for_writing) Don't initialize vfm_sink_info.  Don't try
+       to send data to disk early.
+       (make_temp_case) Don't use vfm_sink_info.case_size.
+       (close_active_file) Don't initialize vfm_source_info.
+       (struct disk_stream_info) New, to allow for case_cnt and case_size fields.
+       (disk_sink_create) Initialize and/or update disk_stream_info.
+       (disk_sink_write) Ditto.
+       (disk_sink_destroy) Ditto.
+       (disk_sink_make_source) Ditto.
+       (disk_source_read) Ditto.
+       (disk_source_destroy) Ditto.
+       (global var disk_source_class) Add disk_source_count().
+       (disk_source_count) New function.
+       (struct memory_sink_info) Add `case_cnt', `case_size' members.
+       (struct memory_source_info) Ditto.
+       (memory_sink_create) Deal with case_cnt, case_size.
+       (memory_sink_write) Ditto.
+       (memory_sink_make_source) Ditto.
+       (memory_source_read) Ditto.
+       (memory_source_count) New function.
+       (memory_source_class) Add memory_source_count().
+       (procedure_write_case) Don't use vfm_sink_info.ncases.  Do use
+       proc_aux->cases_written, and pass it to transformation procedures
+       and exclude_this_case ().
+       (exclude_this_case) Add case_num parameter.  Pass it to
+       expr_evaluate().
+       (SPLIT_FILE_procfunc) Use split_aux->prev_case instead of static
+       variable.
+
+       * vfm.h: (struct case_source_class) Add `count' member.
+
+       * vfmP.h: (struct stream_info) Removed.
+       (global variable vfm_source_info) Removed.
+       (global variable vfm_sink_info) Removed.
+       
+Tue Mar  2 23:38:17 2004  Ben Pfaff  <blp@gnu.org>
+
+       * var.h: (typedef trns_proc_func) New typedef.
+       (trns_free_func) New typedef.
+       (struct trns_header) Change `proc' to type trns_proc_func, `free'
+       to type trns_free_func.  This only changes the actual type of
+       trns_proc_func, adding a `case_num' parameter.  Updated all
+       implementations to use the typedefs instead.
+
+       * compute.c: (compute_num) Pass case_num to expr_evaluate().
+       (compute_num_vec) Ditto.
+       (compute_str) Ditto.
+       (compute_str_vec) Ditto.
+
+       * do-if.c: (do_if_trns_proc) Ditto.
+
+       * expr-evl.c: (expr_evaluate) Add new case_num parameter, use for
+       OP_CASENUM.
+
+       * inpt-pgm.c: (input_program_source_read) Maintain case count,
+       pass to transformation functions.
+       (reread_trns_proc) Pass case_num arg to expr_evaluate().
+
+       * loop.c: (loop_1_trns_proc) Ditto.
+       (loop_2_trns_proc) Ditto.
+       (loop_3_trns_proc) Ditto.
+
+       * print.c: (print_space_trns_proc) Ditto.
+
+       * sel-if.c: (select_if_proc) Ditto.
+
 Tue Mar  2 11:36:52 2004  Ben Pfaff  <blp@gnu.org>
 
        * frequencies.q: (cleanup_freq_tab) Avoid memory leak by
index 0c274c4b3b644e16381d5005411af69593c499b0..e8568419f61b7903b65ff6641e12e012807d2296 100644 (file)
@@ -144,10 +144,9 @@ static void free_aggregate_functions (void);
 static int aggregate_single_case (struct ccase *input, struct ccase *output);
 static int create_sysfile (void);
 
-static int agr_00x_trns_proc (struct trns_header *, struct ccase *);
-static void agr_00x_end_func (void *);
-static int agr_10x_trns_proc (struct trns_header *, struct ccase *);
-static void agr_10x_trns_free (struct trns_header *);
+static trns_proc_func agr_00x_trns_proc, agr_10x_trns_proc;
+static trns_free_func agr_10x_trns_free;
+static void agr_00x_end_func (void *aux);
 static void agr_10x_end_func (void *);
 static int agr_11x_func (write_case_data);
 
@@ -1196,7 +1195,8 @@ initialize_aggregate_info (void)
 /* Aggregate each case as it comes through.  Cases which aren't needed
    are dropped. */
 static int
-agr_00x_trns_proc (struct trns_header *h UNUSED, struct ccase *c)
+agr_00x_trns_proc (struct trns_header *h UNUSED, struct ccase *c,
+                   int case_num UNUSED)
 {
   int code = aggregate_single_case (c, compaction_case);
   debug_printf (("%d ", code));
@@ -1213,7 +1213,6 @@ agr_00x_end_func (void *aux UNUSED)
   /* Ensure that info for the last break group gets written to the
      active file. */
   dump_aggregate_info (compaction_case);
-  vfm_sink_info.ncases++;
   vfm_sink->class->write (vfm_sink, temp_case);
 }
 
@@ -1253,7 +1252,8 @@ write_case_to_sfm (void)
 /* Aggregate the current case and output it if we passed a
    breakpoint. */
 static int
-agr_10x_trns_proc (struct trns_header *h UNUSED, struct ccase *c)
+agr_10x_trns_proc (struct trns_header *h UNUSED, struct ccase *c,
+                   int case_num UNUSED)
 {
   int code = aggregate_single_case (c, buf_1xx);
 
index f8f2b84d877dd8c43ea5a01055ce587a71aefe2c..707acf28145486b8c56d0c36d9c70fda387aee91 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef SORT_ALGO_H
-#define SORT_ALGO_H 1
+#ifndef ALGORITHM_H
+#define ALGORITHM_H 1
 
 #include <stddef.h>
 
@@ -190,4 +190,4 @@ int is_heap (const void *array, size_t count, size_t size,
              algo_compare_func *compare, void *aux);
 
 
-#endif /* sort-algo.h */
+#endif /* algorithm.h */
index 8d15ce63ba3b55fe858cf10e593cd47c9c9f1486..27fe0db2ded776f463442aa0fe8c6eaaf235409d 100644 (file)
@@ -74,8 +74,8 @@ static struct pool *hash_pool;
 static int descend;
 static int print;
 
-static int autorecode_trns_proc (struct trns_header *, struct ccase *);
-static void autorecode_trns_free (struct trns_header *);
+static trns_proc_func autorecode_trns_proc;
+static trns_free_func autorecode_trns_free;
 static int autorecode_proc_func (struct ccase *, void *);
 static hsh_compare_func compare_alpha_value, compare_numeric_value;
 static hsh_hash_func hash_alpha_value, hash_numeric_value;
@@ -235,7 +235,8 @@ recode (void)
 }
 
 static int
-autorecode_trns_proc (struct trns_header * trns, struct ccase * c)
+autorecode_trns_proc (struct trns_header * trns, struct ccase * c,
+                      int case_num UNUSED)
 {
   struct autorecode_trns *t = (struct autorecode_trns *) trns;
   int i;
index aed443853d9a0d65800be651c7ebc80e2d368630..60c99ad825b7dde1295a75dd9d558417ee093b2a 100644 (file)
@@ -105,26 +105,28 @@ cmd_compute (void)
 /* Transformation functions. */
 
 static int
-compute_num (struct trns_header *compute_, struct ccase *c)
+compute_num (struct trns_header *compute_, struct ccase *c,
+             int case_num)
 {
   struct compute_trns *compute = (struct compute_trns *) compute_;
 
   if (compute->test == NULL
-      || expr_evaluate (compute->test, c, NULL) == 1.0) 
+      || expr_evaluate (compute->test, c, case_num, NULL) == 1.0) 
     {
-      expr_evaluate (compute->rvalue, c, &c->data[compute->fv]); 
+      expr_evaluate (compute->rvalue, c, case_num, &c->data[compute->fv]); 
     }
   
   return -1;
 }
 
 static int
-compute_num_vec (struct trns_header *compute_, struct ccase *c)
+compute_num_vec (struct trns_header *compute_, struct ccase *c,
+                 int case_num)
 {
   struct compute_trns *compute = (struct compute_trns *) compute_;
 
   if (compute->test == NULL
-      || expr_evaluate (compute->test, c, NULL) == 1.0) 
+      || expr_evaluate (compute->test, c, case_num, NULL) == 1.0) 
     {
       /* Index into the vector. */
       union value index;
@@ -132,7 +134,7 @@ compute_num_vec (struct trns_header *compute_, struct ccase *c)
       /* Rounded index value. */
       int rindx;
 
-      expr_evaluate (compute->element, c, &index);
+      expr_evaluate (compute->element, c, case_num, &index);
       rindx = floor (index.f + EPSILON);
       if (index.f == SYSMIS || rindx < 1 || rindx > compute->vector->cnt)
         {
@@ -145,7 +147,7 @@ compute_num_vec (struct trns_header *compute_, struct ccase *c)
                  index.f, compute->vector->name);
           return -1;
         }
-      expr_evaluate (compute->rvalue, c,
+      expr_evaluate (compute->rvalue, c, case_num,
                      &c->data[compute->vector->var[rindx - 1]->fv]); 
     }
   
@@ -153,17 +155,18 @@ compute_num_vec (struct trns_header *compute_, struct ccase *c)
 }
 
 static int
-compute_str (struct trns_header *compute_, struct ccase *c)
+compute_str (struct trns_header *compute_, struct ccase *c,
+             int case_num)
 {
   struct compute_trns *compute = (struct compute_trns *) compute_;
 
   if (compute->test == NULL
-      || expr_evaluate (compute->test, c, NULL) == 1.0) 
+      || expr_evaluate (compute->test, c, case_num, NULL) == 1.0) 
     {
       /* Temporary storage for string expression return value. */
       union value v;
 
-      expr_evaluate (compute->rvalue, c, &v);
+      expr_evaluate (compute->rvalue, c, case_num, &v);
       st_bare_pad_len_copy (c->data[compute->fv].s, &v.c[1], compute->width,
                             v.c[0]); 
     }
@@ -172,12 +175,13 @@ compute_str (struct trns_header *compute_, struct ccase *c)
 }
 
 static int
-compute_str_vec (struct trns_header *compute_, struct ccase *c)
+compute_str_vec (struct trns_header *compute_, struct ccase *c,
+                 int case_num)
 {
   struct compute_trns *compute = (struct compute_trns *) compute_;
 
   if (compute->test == NULL
-      || expr_evaluate (compute->test, c, NULL) == 1.0) 
+      || expr_evaluate (compute->test, c, case_num, NULL) == 1.0) 
     {
       /* Temporary storage for string expression return value. */
       union value v;
@@ -191,7 +195,7 @@ compute_str_vec (struct trns_header *compute_, struct ccase *c)
       /* Variable reference by indexed vector. */
       struct variable *vr;
 
-      expr_evaluate (compute->element, c, &index);
+      expr_evaluate (compute->element, c, case_num, &index);
       rindx = floor (index.f + EPSILON);
       if (index.f == SYSMIS || rindx < 1 || rindx > compute->vector->cnt)
         {
@@ -206,7 +210,7 @@ compute_str_vec (struct trns_header *compute_, struct ccase *c)
           return -1;
         }
 
-      expr_evaluate (compute->rvalue, c, &v);
+      expr_evaluate (compute->rvalue, c, case_num, &v);
       vr = compute->vector->var[rindx - 1];
       st_bare_pad_len_copy (c->data[vr->fv].s, &v.c[1], vr->width, v.c[0]); 
     }
index 3b9a0ac098c752593f7b68f99ff9bf5955627e61..4cdf90ecbd083e85e88d8477240e70c68f409936 100644 (file)
@@ -128,8 +128,8 @@ static struct cnt_var_info *head;
 \f
 /* Parser. */
 
-static int count_trns_proc (struct trns_header *, struct ccase *);
-static void count_trns_free (struct trns_header *);
+static trns_proc_func count_trns_proc;
+static trns_free_func count_trns_free;
 
 static int parse_numeric_criteria (struct counting *);
 static int parse_string_criteria (struct counting *);
@@ -490,7 +490,8 @@ count_string (struct counting * cnt, struct ccase * c)
 
 /* Performs the COUNT transformation T on case C. */
 static int
-count_trns_proc (struct trns_header * trns, struct ccase * c)
+count_trns_proc (struct trns_header * trns, struct ccase * c,
+                 int case_num UNUSED)
 {
   struct cnt_var_info *info;
   struct counting *cnt;
index d0287b6a064a192b5d86c1d3ad6c01f8e97f1562..d987a2f7461ffd2d14a8a1b0133a450a775a61b7 100644 (file)
@@ -95,8 +95,8 @@ static void dump_fixed_table (const struct dls_var_spec *specs,
                               const struct file_handle *handle, int nrec);
 static void dump_free_table (const struct data_list_pgm *);
 static void destroy_dls_var_spec (struct dls_var_spec *);
-static void destroy_dls (struct trns_header *);
-static int read_one_case (struct trns_header *, struct ccase *);
+static trns_free_func destroy_dls;
+static trns_proc_func read_one_case;
 
 /* Message title for REPEATING DATA. */
 #define RPD_ERR "REPEATING DATA: "
@@ -1175,7 +1175,8 @@ destroy_dls (struct trns_header *pgm)
 /* Note that since this is exclusively an input program, C is
    guaranteed to be temp_case. */
 static int
-read_one_case (struct trns_header *t, struct ccase *c UNUSED)
+read_one_case (struct trns_header *t, struct ccase *c UNUSED,
+               int case_num UNUSED)
 {
   struct data_list_pgm *dls = (struct data_list_pgm *) t;
   data_list_read_func *read_func;
@@ -1250,6 +1251,7 @@ data_list_source_destroy (struct case_source *source)
 const struct case_source_class data_list_source_class = 
   {
     "DATA LIST",
+    NULL,
     data_list_source_read,
     data_list_source_destroy,
   };
@@ -1287,8 +1289,7 @@ struct repeating_data_trns
     write_case_data wc_data;
   };
 
-int repeating_data_trns_proc (struct trns_header *, struct ccase *);
-void repeating_data_trns_free (struct trns_header *);
+static trns_free_func repeating_data_trns_free;
 static int parse_num_or_var (struct rpd_num_or_var *, const char *);
 static int parse_repeating_data (struct dls_var_spec **,
                                  struct dls_var_spec **);
@@ -1830,7 +1831,8 @@ rpd_parse_record (const struct rpd_parse_info *info)
    elements in the REPEATING DATA structure.  Returns -1 on success,
    -2 on end of file or on failure. */
 int
-repeating_data_trns_proc (struct trns_header *trns, struct ccase *c)
+repeating_data_trns_proc (struct trns_header *trns, struct ccase *c,
+                          int case_num UNUSED)
 {
   struct repeating_data_trns *t = (struct repeating_data_trns *) trns;
     
index 736d2a50672b4c4aa82073e0174c6c7753fcb0ad..494c2ee5a412c4b22c5c6b6520c4e8d38a95d830 100644 (file)
@@ -26,7 +26,7 @@
 #include "var.h"
 #include "vfm.h"
 
-int repeating_data_trns_proc (struct trns_header *, struct ccase *);
+trns_proc_func repeating_data_trns_proc;
 void repeating_data_set_write_case (struct trns_header *,
                                     write_case_func *, write_case_data);
 
index 3a3f7da79ad8c77ce5fedd6b1b624ad9231c1b63..72d5bba4bc35834932b3aa1706a38df2da12c419 100644 (file)
@@ -476,7 +476,8 @@ dump_z_table (void)
 
 /* Transformation function to calculate Z-scores. */
 static int
-descriptives_trns_proc (struct trns_header * trns, struct ccase * c)
+descriptives_trns_proc (struct trns_header * trns, struct ccase * c,
+                        int case_num UNUSED)
 {
   struct descriptives_trns *t = (struct descriptives_trns *) trns;
   struct dsc_z_score *z;
index b0014484f0b6d04ee0c0d9ae78942844863dc5c3..339710696326035de2bf4ec760a9b05dedfe246f 100644 (file)
@@ -76,9 +76,8 @@
 
 static struct do_if_trns *parse_do_if (void);
 static void add_ELSE_IF (struct do_if_trns *);
-static int goto_trns_proc (struct trns_header *, struct ccase *);
-static int do_if_trns_proc (struct trns_header *, struct ccase *);
-static void do_if_trns_free (struct trns_header *);
+static trns_proc_func goto_trns_proc, do_if_trns_proc;
+static trns_free_func do_if_trns_free;
 
 /* Parse DO IF. */
 int
@@ -276,18 +275,20 @@ parse_do_if (void)
 
 /* Executes a goto transformation. */
 static int 
-goto_trns_proc (struct trns_header * t, struct ccase * c UNUSED)
+goto_trns_proc (struct trns_header * t, struct ccase * c UNUSED,
+                int case_num UNUSED)
 {
   return ((struct goto_trns *) t)->dest;
 }
 
 static int 
-do_if_trns_proc (struct trns_header * trns, struct ccase * c)
+do_if_trns_proc (struct trns_header * trns, struct ccase * c,
+                 int case_num UNUSED)
 {
   struct do_if_trns *t = (struct do_if_trns *) trns;
   union value bool;
 
-  expr_evaluate (t->cond, c, &bool);
+  expr_evaluate (t->cond, c, case_num, &bool);
   if (bool.f == 1.0)
     {
       debug_printf ((_("DO IF %d: true\n"), t->h.index));
index a1b540e4974d984f78036eb8305be6ed285c5682..34bbd6ac3d52315c2216ff4af6ebb5c73d760f26 100644 (file)
@@ -51,7 +51,8 @@
 #include "vfmP.h"
 
 double
-expr_evaluate (struct expression *e, struct ccase *c, union value *v)
+expr_evaluate (struct expression *e, struct ccase *c, int case_num,
+               union value *v)
 {
   unsigned char *op = e->op;
   double *dbl = e->num;
@@ -1275,7 +1276,7 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
          break;
        case OP_CASENUM:
          sp++;
-         sp->f = vfm_sink_info.ncases + 1;
+         sp->f = case_num;
          break;
 
        case OP_SENTINEL:
index 30824966cd46f09c50de278471efdf284637df96..909cf87f1761606857a5480897e9271bde43ff45 100644 (file)
@@ -38,7 +38,8 @@ struct ccase;
 union value;
 
 struct expression *expr_parse (int flags);
-double expr_evaluate (struct expression *, struct ccase *, union value *);
+double expr_evaluate (struct expression *, struct ccase *, int case_num,
+                      union value *);
 void expr_free (struct expression *);
 
 #endif /* expr.h */
index fee98518557bb80ae0ad6021f51081b8be623054..ea0bb332d679040e1031ff84ebf2fd4ee1ddf86b 100644 (file)
@@ -726,6 +726,7 @@ file_type_source_destroy (struct case_source *source)
 const struct case_source_class file_type_source_class =
   {
     "FILE TYPE",
+    NULL,
     file_type_source_read,
     file_type_source_destroy,
   };
index 4ff7045ee2ead1e0d3c70156ea3fe27efea65155..8ae4ac4ee8a699a79dbcb4a6230de105b5d0b95f 100644 (file)
@@ -520,6 +520,7 @@ flip_source_destroy (struct case_source *source)
 static const struct case_source_class flip_source_class = 
   {
     "FLIP",
+    NULL,
     flip_source_read,
     flip_source_destroy
   };
index 8cd3cf783edc45f3649f3b9f3637229afdb5e542..be1c09a2988443b90327f938853e69b4d9e5b5a3 100644 (file)
--- a/src/get.c
+++ b/src/get.c
@@ -56,8 +56,8 @@ struct save_trns
 
 static int trim_dictionary (struct dictionary * dict, int *options);
 static int save_write_case_func (struct ccase *, void *);
-static int save_trns_proc (struct trns_header *, struct ccase *);
-static void save_trns_free (struct trns_header *);
+static trns_proc_func save_trns_proc;
+static trns_free_func save_trns_free;
 
 #if DEBUGGING
 void dump_dict_variables (struct dictionary *);
@@ -254,7 +254,7 @@ save_write_case_func (struct ccase * c, void *aux UNUSED)
 }
 
 static int
-save_trns_proc (struct trns_header *h, struct ccase * c)
+save_trns_proc (struct trns_header *h, struct ccase * c, int case_num UNUSED)
 {
   struct save_trns *t = (struct save_trns *) h;
   do_write_case (t, c);
@@ -500,6 +500,7 @@ get_source_read (struct case_source *source,
 const struct case_source_class get_source_class =
   {
     "GET",
+    NULL,
     get_source_read,
     get_source_destroy,
   };
@@ -1430,6 +1431,7 @@ import_source_read (struct case_source *source,
 const struct case_source_class import_source_class =
   {
     "IMPORT",
+    NULL,
     import_source_read,
     get_source_destroy,
   };
index 5acf2df4143b4c48acdcc0763974c8f00099d9e6..697d7f5ba59726120f77492504eeeb603dc35c83 100644 (file)
@@ -52,10 +52,8 @@ struct input_program_pgm
     size_t init_cnt;            /* Number of elements in inp_init. */
   };
 
-static int end_case_trns_proc (struct trns_header *, struct ccase *);
-static int end_file_trns_proc (struct trns_header * t, struct ccase * c);
-static int reread_trns_proc (struct trns_header *, struct ccase *);
-static void reread_trns_free (struct trns_header *);
+static trns_proc_func end_case_trns_proc, reread_trns_proc, end_file_trns_proc;
+static trns_free_func reread_trns_free;
 
 int
 cmd_input_program (void)
@@ -185,6 +183,12 @@ input_program_source_read (struct case_source *source,
      cases. */
   int end_case = 0;
 
+  /* FIXME?  This is the number of cases sent out of the input
+     program, not the number of cases written to the procedure.
+     The difference should only show up in $CASENUM in COMPUTE.
+     We should check behavior against SPSS. */
+  int cases_written = 0;
+
   assert (inp != NULL);
   
   /* Figure end_case. */
@@ -220,6 +224,7 @@ input_program_source_read (struct case_source *source,
 
           if (t_trns[i]->proc == end_case_trns_proc) 
             {
+              cases_written++;
               if (!write_case (wc_data))
                 return;
               clear_case (inp);
@@ -227,7 +232,7 @@ input_program_source_read (struct case_source *source,
               continue;
             }
 
-         code = t_trns[i]->proc (t_trns[i], temp_case);
+         code = t_trns[i]->proc (t_trns[i], temp_case, cases_written + 1);
          switch (code)
            {
            case -1:
@@ -276,6 +281,7 @@ input_program_source_destroy (struct case_source *source)
 const struct case_source_class input_program_source_class =
   {
     "INPUT PROGRAM",
+    NULL,
     input_program_source_read,
     input_program_source_destroy,
   };
@@ -304,7 +310,8 @@ cmd_end_case (void)
 }
 
 int
-end_case_trns_proc (struct trns_header *t UNUSED, struct ccase * c UNUSED)
+end_case_trns_proc (struct trns_header *t UNUSED, struct ccase * c UNUSED,
+                    int case_num UNUSED)
 {
   assert (0);
 }
@@ -387,7 +394,8 @@ cmd_reread (void)
 }
 
 static int
-reread_trns_proc (struct trns_header * pt, struct ccase * c)
+reread_trns_proc (struct trns_header * pt, struct ccase * c,
+                  int case_num)
 {
   struct reread_trns *t = (struct reread_trns *) pt;
 
@@ -397,7 +405,7 @@ reread_trns_proc (struct trns_header * pt, struct ccase * c)
     {
       union value column;
 
-      expr_evaluate (t->column, c, &column);
+      expr_evaluate (t->column, c, case_num, &column);
       if (!finite (column.f) || column.f < 1)
        {
          msg (SE, _("REREAD: Column numbers must be positive finite "
@@ -441,7 +449,8 @@ cmd_end_file (void)
 }
 
 static int
-end_file_trns_proc (struct trns_header * t UNUSED, struct ccase * c UNUSED)
+end_file_trns_proc (struct trns_header * t UNUSED, struct ccase * c UNUSED,
+                    int case_num UNUSED)
 {
 #if DEBUGGING
   printf ("END FILE\n");
index e9bb674749bf9626f2dfcf0b2f3719b5e2f6a3ef..1989a0748a6964a10593e0639eda0b79993a6c74 100644 (file)
@@ -140,13 +140,9 @@ static struct loop_3_trns *thr;
 
 static int internal_cmd_loop (void);
 static int internal_cmd_end_loop (void);
-static int break_trns_proc (struct trns_header *, struct ccase *);
-static int loop_1_trns_proc (struct trns_header *, struct ccase *);
-static void loop_1_trns_free (struct trns_header *);
-static int loop_2_trns_proc (struct trns_header *, struct ccase *);
-static void loop_2_trns_free (struct trns_header *);
-static int loop_3_trns_proc (struct trns_header *, struct ccase *);
-static void loop_3_trns_free (struct trns_header *);
+static trns_proc_func break_trns_proc;
+static trns_proc_func loop_1_trns_proc, loop_2_trns_proc, loop_3_trns_proc;
+static trns_free_func loop_1_trns_free, loop_2_trns_free, loop_3_trns_free;
 static void pop_ctl_stack (void);
 \f
 /* LOOP. */
@@ -349,7 +345,8 @@ internal_cmd_end_loop (void)
 
 /* Performs transformation 1. */
 static int
-loop_1_trns_proc (struct trns_header * trns, struct ccase * c)
+loop_1_trns_proc (struct trns_header * trns, struct ccase * c,
+                  int case_num)
 {
   struct loop_1_trns *one = (struct loop_1_trns *) trns;
   struct loop_2_trns *two = one->two;
@@ -359,12 +356,12 @@ loop_1_trns_proc (struct trns_header * trns, struct ccase * c)
     {
       union value t1, t2, t3;
 
-      expr_evaluate (one->init, c, &t1);
+      expr_evaluate (one->init, c, case_num, &t1);
       if (one->incr)
-       expr_evaluate (one->incr, c, &t2);
+       expr_evaluate (one->incr, c, case_num, &t2);
       else
        t2.f = 1.0;
-      expr_evaluate (one->term, c, &t3);
+      expr_evaluate (one->term, c, case_num, &t3);
 
       /* Even if the loop is never entered, force the index variable
          to assume the initial value. */
@@ -415,7 +412,8 @@ loop_1_trns_free (struct trns_header * trns)
 
 /* Performs transformation 2. */
 static int
-loop_2_trns_proc (struct trns_header * trns, struct ccase * c)
+loop_2_trns_proc (struct trns_header * trns, struct ccase * c,
+                  int case_num UNUSED)
 {
   struct loop_2_trns *two = (struct loop_2_trns *) trns;
 
@@ -456,7 +454,7 @@ loop_2_trns_proc (struct trns_header * trns, struct ccase * c)
 
   /* Conditional clause limiter. */
   if ((two->flags & LPC_COND)
-      && expr_evaluate (two->cond, c, NULL) != 1.0)
+      && expr_evaluate (two->cond, c, case_num, NULL) != 1.0)
     return two->loop_term;
 
   return -1;
@@ -473,13 +471,14 @@ loop_2_trns_free (struct trns_header * trns)
 
 /* Performs transformation 3. */
 static int
-loop_3_trns_proc (struct trns_header * trns, struct ccase * c)
+loop_3_trns_proc (struct trns_header * trns, struct ccase * c,
+                  int case_num)
 {
   struct loop_3_trns *thr = (struct loop_3_trns *) trns;
 
   /* Note that it breaks out of the loop if the expression is true *or
      missing*.  This is conformant. */
-  if (thr->cond && expr_evaluate (two->cond, c, NULL) != 0.0)
+  if (thr->cond && expr_evaluate (two->cond, c, case_num, NULL) != 0.0)
     return -1;
 
   return thr->loop_start;
@@ -532,7 +531,8 @@ cmd_break (void)
 }
 
 static int
-break_trns_proc (struct trns_header * trns, struct ccase * c UNUSED)
+break_trns_proc (struct trns_header * trns, struct ccase * c UNUSED,
+                 int case_num UNUSED)
 {
   return ((struct break_trns *) trns)->loop_term;
 }
index c747287c715fededddc1250a247d02e3acf1e01c..d69e661d74422f0960aedf698c76b745a10a01eb 100644 (file)
@@ -60,10 +60,7 @@ int start_interactive;
 int
 main (int argc, char **argv)
 {
-  struct sigaction bug ;
-  bug.sa_handler = bug_handler;
-
-  sigaction(SIGSEGV, &bug,0);
+  signal (SIGSEGV, bug_handler);
 
   /* Initialization. */
   if (!outp_init ())
index 7c3411bcabc04468b71297cbe7b5ee46eb53a2b2..1532d1a1c784f7d07b3a766245f97dc1ad3715b0 100644 (file)
@@ -2023,6 +2023,7 @@ wr_read_indeps (struct matrix_data_pgm *mx)
 static const struct case_source_class matrix_data_with_rowtype_source_class = 
   {
     "MATRIX DATA",
+    NULL,
     matrix_data_read_with_rowtype,
     NULL,
   };
@@ -2031,6 +2032,7 @@ static const struct case_source_class
 matrix_data_without_rowtype_source_class =
   {
     "MATRIX DATA",
+    NULL,
     matrix_data_read_without_rowtype,
     NULL,
   };
index 2fa40ae6e31a365222131f3f0d4afa11e807f1b0..9c4b63b20aa395eecbc2d6e8408d909cea39e767 100644 (file)
@@ -96,8 +96,8 @@ static struct prt_out_spec *next;
 static int nrec;
 
 static int internal_cmd_print (int flags);
-static int print_trns_proc (struct trns_header *, struct ccase *);
-static void print_trns_free (struct trns_header *);
+static trns_proc_func print_trns_proc;
+static trns_free_func print_trns_free;
 static int parse_specs (void);
 static void dump_table (void);
 static void append_var_spec (struct prt_out_spec *spec);
@@ -900,7 +900,8 @@ alloc_line (void)
 
 /* Performs the transformation inside print_trns T on case C. */
 static int
-print_trns_proc (struct trns_header * trns, struct ccase * c)
+print_trns_proc (struct trns_header * trns, struct ccase * c,
+                 int case_num UNUSED)
 {
   /* Transformation. */
   struct print_trns *t = (struct print_trns *) trns;
@@ -1015,8 +1016,8 @@ struct print_space_trns
 }
 print_space_trns;
 
-static int print_space_trns_proc (struct trns_header *, struct ccase *);
-static void print_space_trns_free (struct trns_header *);
+static trns_proc_func print_space_trns_proc;
+static trns_free_func print_space_trns_free;
 
 int
 cmd_print_space (void)
@@ -1075,7 +1076,8 @@ cmd_print_space (void)
 }
 
 static int
-print_space_trns_proc (struct trns_header * trns, struct ccase * c)
+print_space_trns_proc (struct trns_header * trns, struct ccase * c,
+                       int case_num UNUSED)
 {
   struct print_space_trns *t = (struct print_space_trns *) trns;
   int n;
@@ -1084,7 +1086,7 @@ print_space_trns_proc (struct trns_header * trns, struct ccase * c)
     {
       union value v;
 
-      expr_evaluate (t->e, c, &v);
+      expr_evaluate (t->e, c, case_num, &v);
       n = v.f;
       if (n < 0)
        {
index 543e45ada4618ef69e602d5440e0af76eb66e994..523dcaa6442d850f971a0155e54fedc3722ca443 100644 (file)
@@ -104,8 +104,8 @@ struct recode_trns
 static int parse_dest_spec (struct rcd_var * rcd, union value *v,
                            size_t *max_dst_width);
 static int parse_src_spec (struct rcd_var * rcd, int type, size_t max_src_width);
-static int recode_trns_proc (struct trns_header *, struct ccase *);
-static void recode_trns_free (struct trns_header *);
+static trns_proc_func recode_trns_proc;
+static trns_free_func recode_trns_free;
 static double convert_to_double (char *, int);
 
 #if DEBUGGING
@@ -772,7 +772,8 @@ find_src_string (struct rcd_var * v, struct ccase * c)
 }
 
 static int
-recode_trns_proc (struct trns_header * t, struct ccase * c)
+recode_trns_proc (struct trns_header * t, struct ccase * c,
+                  int case_num UNUSED)
 {
   struct rcd_var *v;
   struct coding *cp;
index 8a5406d14299daacb7806a5022f0c9cfb34617a6..ce5d18d8131de8a12e0fc5de27f5508356ec0e59 100644 (file)
@@ -48,7 +48,7 @@ struct sample_trns
     unsigned frac;              /* TYPE_FRACTION: a fraction of UINT_MAX. */
   };
 
-int sample_trns_proc (struct trns_header *, struct ccase *);
+static trns_proc_func sample_trns_proc;
 
 int
 cmd_sample (void)
@@ -118,8 +118,9 @@ cmd_sample (void)
   return lex_end_of_command ();
 }
 
-int
-sample_trns_proc (struct trns_header * trns, struct ccase *c UNUSED)
+static int
+sample_trns_proc (struct trns_header * trns, struct ccase *c UNUSED,
+                  int case_num UNUSED)
 {
   struct sample_trns *t = (struct sample_trns *) trns;
   double U;
index 07fe318f114b578991aee80a73235f46d5fee1f7..514c44711a78bd5df5af762d74054876ab29edfd 100644 (file)
@@ -33,8 +33,8 @@ struct select_if_trns
     struct expression *e;      /* Test expression. */
   };
 
-static int select_if_proc (struct trns_header *, struct ccase *);
-static void select_if_free (struct trns_header *);
+static trns_proc_func select_if_proc;
+static trns_free_func select_if_free;
 
 /* Parses the SELECT IF transformation. */
 int
@@ -68,9 +68,11 @@ cmd_select_if (void)
 
 /* Performs the SELECT IF transformation T on case C. */
 static int
-select_if_proc (struct trns_header * t, struct ccase * c)
+select_if_proc (struct trns_header * t, struct ccase * c,
+                int case_num)
 {
-  return (expr_evaluate (((struct select_if_trns *) t)->e, c, NULL) == 1.0) - 2;
+  return (expr_evaluate (((struct select_if_trns *) t)->e, c,
+                         case_num, NULL) == 1.0) - 2;
 }
 
 /* Frees SELECT IF transformation T. */
index 399823ef76d561e436227af6f5be0437ed4711b2..99d850ad9345c354de71b39b3f33d75b857e3a9a 100644 (file)
@@ -216,11 +216,11 @@ do_internal_sort (struct sort_cases_pgm *scp, int separate)
        {
           struct case_list *case_list;
           struct case_list **case_array;
-          size_t case_cnt;
+          int case_cnt;
           int i;
 
-          case_cnt = vfm_source_info.ncases;
-         if (case_cnt == 0)
+          case_cnt = vfm_source->class->count (vfm_source);
+         if (case_cnt <= 0)
             return isrt;
 
           if (case_cnt > set_max_workspace / sizeof *case_array)
@@ -327,6 +327,7 @@ struct external_sort
     size_t run_cnt, run_cap;          /* Number of runs, allocated capacity. */
     char *temp_dir;                   /* Temporary file directory name. */
     int next_file_idx;                /* Lowest unused file index. */
+    size_t case_size;                 /* Number of bytes in case. */
   };
 
 /* Prototypes for helper functions. */
@@ -350,6 +351,7 @@ do_external_sort (struct sort_cases_pgm *scp, int separate)
 
   xsrt = xmalloc (sizeof *xsrt);
   xsrt->scp = scp;
+  xsrt->case_size = sizeof (union value) * compaction_nval;
   if (!init_external_sort (xsrt))
     goto done;
   if (!write_initial_runs (xsrt, separate))
@@ -614,6 +616,7 @@ struct initial_run_state
     /* Run currently being output. */
     int file_idx;               /* Temporary file number. */
     size_t case_cnt;            /* Number of cases so far. */
+    size_t case_size;           /* Number of bytes in a case. */
     FILE *output_file;          /* Output file. */
     struct case_list *last_output;/* Record last output. */
 
@@ -648,6 +651,7 @@ write_initial_runs (struct external_sort *xsrt, int separate)
   irs->last_output = NULL;
   irs->file_idx = 0;
   irs->case_cnt = 0;
+  irs->case_size = dict_get_case_size (default_dict);
   irs->okay = 1;
   if (!allocate_cases (irs)) 
     goto done;
@@ -690,7 +694,7 @@ sort_sink_write (struct case_sink *sink, struct ccase *c)
   assert (irs->record_cnt < irs->record_cap);
   new_record_run = irs->records + irs->record_cnt++;
   new_record_run->record = grab_case (irs);
-  memcpy (new_record_run->record->c.data, c->data, vfm_sink_info.case_size);
+  memcpy (new_record_run->record->c.data, c->data, irs->case_size);
   new_record_run->run = irs->file_idx;
   if (irs->last_output != NULL
       && compare_record (c->data, irs->last_output->c.data,
@@ -1308,7 +1312,7 @@ read_external_sort_output (struct external_sort *xsrt,
 {
   FILE *file;
   int file_idx;
-  int i;
+  size_t i;
 
   assert (xsrt->run_cnt == 1);
   file_idx = xsrt->initial_runs[0].file_idx;
@@ -1320,10 +1324,10 @@ read_external_sort_output (struct external_sort *xsrt,
       return;
     }
 
-  for (i = 0; i < vfm_source_info.ncases; i++)
+  for (i = 0; i < xsrt->initial_runs[0].case_cnt; i++)
     {
       if (!read_temp_file (xsrt, file_idx, file,
-                          temp_case, vfm_source_info.case_size))
+                          temp_case, xsrt->case_size))
        {
           err_failure ();
           break;
@@ -1345,6 +1349,7 @@ sort_source_destroy (struct case_source *source)
 const struct case_source_class sort_source_class =
   {
     "SORT CASES",
+    NULL, /* FIXME */
     sort_source_read,
     sort_source_destroy,
   };
index bf2e4d5082c7c27af2151508e8d3553f68956366..11add5b0daa99ecc7600c0e1bcb1207b3ee80469 100644 (file)
--- a/src/var.h
+++ b/src/var.h
@@ -415,17 +415,16 @@ void copy_missing_values (struct variable *dest, const struct variable *src);
 \f
 /* Transformations. */
 
+struct trns_header;
+typedef int trns_proc_func (struct trns_header *, struct ccase *, int);
+typedef void trns_free_func (struct trns_header *);
+
 /* Header for all transformations. */
 struct trns_header
   {
-    /* Index into t_trns[]. */
-    int index;
-
-    /* Transformation proc. */
-    int (*proc) (struct trns_header *, struct ccase *);
-
-    /* Garbage collector proc. */
-    void (*free) (struct trns_header *);
+    int index;                  /* Index into t_trns[]. */
+    trns_proc_func *proc;       /* Transformation proc. */
+    trns_free_func *free;       /* Garbage collector proc. */
   };
 
 /* Array of transformations */
index 82af200015d6aa40dc19f4fb6215d8a7c0480201..a847ea65f25d5285e714eb881eab9f82faa2711c 100644 (file)
--- a/src/vfm.c
+++ b/src/vfm.c
    then deleted and the data sink becomes the data source for the
    next procedure. */
 
-#include "debug-print.h"
-
 /* Procedure execution data. */
 struct write_case_data
   {
-    void (*beginfunc) (void *);
-    int (*procfunc) (struct ccase *, void *);
-    void (*endfunc) (void *);
+    /* Functions to call... */
+    void (*begin_func) (void *);               /* ...before data. */
+    int (*proc_func) (struct ccase *, void *); /* ...with data. */
+    void (*end_func) (void *);                 /* ...after data. */
+    void *func_aux;                            /* Auxiliary data. */ 
+
+    /* Extra auxiliary data. */
     void *aux;
   };
 
@@ -66,18 +68,11 @@ struct case_source *vfm_source;
 /* The replacement active file, to which cases are written. */
 struct case_sink *vfm_sink;
 
-/* Information about the data source. */
-struct stream_info vfm_source_info;
-
-/* Information about the data sink. */
-struct stream_info vfm_sink_info;
-
 /* Nonzero if the case needs to have values deleted before being
    stored, zero otherwise. */
 int compaction_necessary;
 
-/* Number of values after compaction, or the same as
-   vfm_sink_info.nval, if compaction is not necessary. */
+/* Number of values after compaction. */
 int compaction_nval;
 
 /* Temporary case buffer with enough room for `compaction_nval'
@@ -104,58 +99,74 @@ static struct ccase **lag_queue; /* Array of n_lag ccase * elements. */
 
 static void open_active_file (void);
 static void close_active_file (struct write_case_data *);
-static int SPLIT_FILE_procfunc (struct ccase *, void *);
+static int SPLIT_FILE_proc_func (struct ccase *, void *);
 static void finish_compaction (void);
 static void lag_case (void);
 static int procedure_write_case (struct write_case_data *);
 static void clear_temp_case (void);
-static int exclude_this_case (void);
+static int exclude_this_case (int case_num);
 \f
 /* Public functions. */
 
+struct procedure_aux_data 
+  {
+    size_t cases_written;       /* Number of cases written so far. */
+  };
+
+struct split_aux_data 
+  {
+    struct ccase *prev_case;    /* Data in previous case. */
+  };
+
 /* Reads all the cases from the active file, transforms them by
-   the active set of transformations, calls PROCFUNC with CURCASE
+   the active set of transformations, calls PROC_FUNC with CURCASE
    set to the case, and writes them to a new active file.
 
    Divides the active file into zero or more series of one or more
-   cases each.  BEGINFUNC is called before each series.  ENDFUNC is
+   cases each.  BEGIN_FUNC is called before each series.  END_FUNC is
    called after each series.
 
-   Arbitrary user-specified data AUX is passed to BEGINFUNC,
-   PROCFUNC, and ENDFUNC as auxiliary data. */
+   Arbitrary user-specified data AUX is passed to BEGIN_FUNC,
+   PROC_FUNC, and END_FUNC as auxiliary data. */
 void
-procedure (void (*beginfunc) (void *),
-          int (*procfunc) (struct ccase *curcase, void *),
-          void (*endfunc) (void *),
-           void *aux)
+procedure (void (*begin_func) (void *),
+          int (*proc_func) (struct ccase *curcase, void *),
+          void (*end_func) (void *),
+           void *func_aux)
 {
   static int recursive_call;
 
   struct write_case_data procedure_write_data;
+  struct procedure_aux_data proc_aux;
+
   struct write_case_data split_file_data;
+  struct split_aux_data split_aux;
+  int split;
 
   assert (++recursive_call == 1);
 
-  if (dict_get_split_cnt (default_dict) == 0) 
-    {
-      /* Normally we just use the data passed by the user. */
-      procedure_write_data.beginfunc = beginfunc;
-      procedure_write_data.procfunc = procfunc;
-      procedure_write_data.endfunc = endfunc;
-      procedure_write_data.aux = aux;
-    }
-  else
+  proc_aux.cases_written = 0;
+
+  /* Normally we just use the data passed by the user. */
+  procedure_write_data.begin_func = begin_func;
+  procedure_write_data.proc_func = proc_func;
+  procedure_write_data.end_func = end_func;
+  procedure_write_data.func_aux = func_aux;
+  procedure_write_data.aux = &proc_aux;
+
+  /* Under SPLIT FILE, we add a layer of indirection. */
+  split = dict_get_split_cnt (default_dict) > 0;
+  if (split) 
     {
-      /* Under SPLIT FILE, we add a layer of indirection. */
-      procedure_write_data.beginfunc = NULL;
-      procedure_write_data.procfunc = SPLIT_FILE_procfunc;
-      procedure_write_data.endfunc = endfunc;
-      procedure_write_data.aux = &split_file_data;
-
-      split_file_data.beginfunc = beginfunc;
-      split_file_data.procfunc = procfunc;
-      split_file_data.endfunc = endfunc;
-      split_file_data.aux = aux;
+      split_file_data = procedure_write_data;
+      split_file_data.aux = &split_aux;
+
+      split_aux.prev_case = xmalloc (dict_get_case_size (default_dict));
+
+      procedure_write_data.begin_func = NULL;
+      procedure_write_data.proc_func = SPLIT_FILE_proc_func;
+      procedure_write_data.end_func = end_func;
+      procedure_write_data.func_aux = &split_file_data;
     }
 
   last_vfm_invocation = time (NULL);
@@ -166,6 +177,9 @@ procedure (void (*beginfunc) (void *),
                              procedure_write_case, &procedure_write_data);
   close_active_file (&procedure_write_data);
 
+  if (split)
+    free (split_aux.prev_case);
+
   assert (--recursive_call == 0);
 }
 \f
@@ -179,35 +193,32 @@ static int not_canceled;
 
 /* Reads all the cases from the active file and passes them one-by-one
    to CASEFUNC in temp_case.  Before any cases are passed, calls
-   BEGINFUNC.  After all the cases have been passed, calls ENDFUNC.
-   BEGINFUNC, CASEFUNC, and ENDFUNC can write temp_case to the output
+   BEGIN_FUNC.  After all the cases have been passed, calls END_FUNC.
+   BEGIN_FUNC, CASEFUNC, and END_FUNC can write temp_case to the output
    file by calling process_active_file_output_case().
 
    process_active_file() ignores TEMPORARY, SPLIT FILE, and N. */
 void
-process_active_file (void (*beginfunc) (void *),
+process_active_file (void (*begin_func) (void *),
                     int (*casefunc) (struct ccase *curcase, void *),
-                    void (*endfunc) (void *),
-                     void *aux)
+                    void (*end_func) (void *),
+                     void *func_aux)
 {
   struct write_case_data process_active_write_data;
 
-  process_active_write_data.beginfunc = beginfunc;
-  process_active_write_data.procfunc = casefunc;
-  process_active_write_data.endfunc = endfunc;
-  process_active_write_data.aux = aux;
+  process_active_write_data.begin_func = begin_func;
+  process_active_write_data.proc_func = casefunc;
+  process_active_write_data.end_func = end_func;
+  process_active_write_data.func_aux = func_aux;
 
   not_canceled = 1;
 
   open_active_file ();
-  beginfunc (aux);
-  
-  /* There doesn't necessarily need to be an active file. */
+  begin_func (func_aux);
   if (vfm_source != NULL)
     vfm_source->class->read (vfm_source, process_active_file_write_case,
                              &process_active_write_data);
-  
-  endfunc (aux);
+  end_func (func_aux);
   close_active_file (&process_active_write_data);
 }
 
@@ -222,7 +233,8 @@ process_active_file_write_case (struct write_case_data *data)
     {
       int code;
        
-      code = t_trns[cur_trns]->proc (t_trns[cur_trns], temp_case);
+      code = t_trns[cur_trns]->proc (t_trns[cur_trns], temp_case,
+                                     case_count + 1);
       switch (code)
        {
        case -1:
@@ -243,8 +255,8 @@ process_active_file_write_case (struct write_case_data *data)
     lag_case ();
          
   /* Call the procedure if FILTER and PROCESS IF don't prohibit it. */
-  if (not_canceled && !exclude_this_case ())
-    not_canceled = data->procfunc (temp_case, data->aux);
+  if (not_canceled && !exclude_this_case (case_count + 1))
+    not_canceled = data->proc_func (temp_case, data->func_aux);
   
   case_count++;
   
@@ -258,7 +270,6 @@ process_active_file_write_case (struct write_case_data *data)
 void
 process_active_file_output_case (void)
 {
-  vfm_sink_info.ncases++;
   vfm_sink->class->write (vfm_sink, temp_case);
 }
 \f
@@ -285,24 +296,8 @@ prepare_for_writing (void)
      So, in this case, we shouldn't have to replace the active
      file--it's just a waste of time and space. */
 
-  vfm_sink_info.ncases = 0;
-  vfm_sink_info.nval = dict_get_next_value_idx (default_dict);
-  vfm_sink_info.case_size = dict_get_case_size (default_dict);
-  
   if (vfm_sink == NULL)
     {
-      if (vfm_sink_info.case_size * vfm_source_info.ncases > set_max_workspace
-         && !workspace_overflow)
-       {
-         msg (MW, _("Workspace overflow predicted.  Max workspace is "
-                    "currently set to %d KB (%d cases at %d bytes each).  "
-                    "Writing active file to disk."),
-              set_max_workspace / 1024, set_max_workspace / vfm_sink_info.case_size,
-              vfm_sink_info.case_size);
-         
-         workspace_overflow = 1;
-       }
-
       if (workspace_overflow)
         vfm_sink = create_case_sink (&disk_sink_class, NULL);
       else
@@ -350,7 +345,7 @@ arrange_compaction (void)
 static void
 make_temp_case (void)
 {
-  temp_case = xmalloc (vfm_sink_info.case_size);
+  temp_case = xmalloc (dict_get_case_size (default_dict));
 
   if (compaction_necessary)
     compaction_case = xmalloc (sizeof (struct ccase)
@@ -422,34 +417,23 @@ setup_lag (void)
    Here is each nval count, with explanation, as set up by
    open_active_file():
 
-   vfm_source_info.nval: Number of `value's in the cases returned by
-   the source stream.  This value turns out not to be very useful, but
-   we maintain it anyway.
-
-   vfm_sink_info.nval: Number of `value's in the cases after all
-   transformations have been performed.  Never less than
-   vfm_source_info.nval.
-
    temp_dict->nval: Number of `value's in the cases after the
-   transformations leading up to TEMPORARY have been performed.  If
-   TEMPORARY was not specified, this is equal to vfm_sink_info.nval.
-   Never less than vfm_sink_info.nval.
+   transformations leading up to TEMPORARY have been performed.
 
    compaction_nval: Number of `value's in the cases after the
-   transformations leading up to TEMPORARY have been performed and the
-   case has been compacted by compact_case(), if compaction is
-   necessary.  This the number of `value's in the cases saved by the
-   sink stream.  (However, note that the cases passed to the sink
-   stream have not yet been compacted.  It is the responsibility of
-   the data sink to call compact_case().)  This may be less than,
-   greater than, or equal to vfm_source_info.nval.  `compaction'
-   becomes the new value of default_dict.nval after the procedure is
-   completed.
-
-   default_dict.nval: This is often an alias for temp_dict->nval.  As
-   such it can really have no separate existence until the procedure
-   is complete.  For this reason it should *not* be referenced inside
-   the execution of a procedure. */
+   transformations leading up to TEMPORARY have been performed
+   and the case has been compacted by compact_case(), if
+   compaction is necessary.  This the number of `value's in the
+   cases saved by the sink stream.  (However, note that the cases
+   passed to the sink stream have not yet been compacted.  It is
+   the responsibility of the data sink to call compact_case().)
+   `compaction' becomes the new value of default_dict.nval after
+   the procedure is completed.
+
+   default_dict.nval: This is often an alias for temp_dict->nval.
+   As such it can really have no separate existence until the
+   procedure is complete.  For this reason it should *not* be
+   referenced inside the execution of a procedure. */
 /* Makes all preparations for reading from the data source and writing
    to the data sink. */
 static void
@@ -476,15 +460,6 @@ open_active_file (void)
   vector_initialization ();
   discard_ctl_stack ();
   setup_lag ();
-
-  /* Debug output. */
-  debug_printf (("vfm: reading from %s source, writing to %s sink.\n",
-                vfm_source->name, vfm_sink->name));
-  debug_printf (("vfm: vfm_source_info.nval=%d, vfm_sink_info.nval=%d, "
-                "temp_dict->nval=%d, compaction_nval=%d, "
-                "default_dict.nval=%d\n",
-                vfm_source_info.nval, vfm_sink_info.nval, temp_dict->nval,
-                compaction_nval, default_dict.nval));
 }
 \f
 /* Closes the active file. */
@@ -492,8 +467,8 @@ static void
 close_active_file (struct write_case_data *data)
 {
   /* Close the current case group. */
-  if (case_count && data->endfunc != NULL)
-    data->endfunc (data->aux);
+  if (case_count && data->end_func != NULL)
+    data->end_func (data->func_aux);
 
   /* Stop lagging (catch up?). */
   if (n_lag)
@@ -528,10 +503,6 @@ close_active_file (struct write_case_data *data)
     }
 
   vfm_source = vfm_sink->class->make_source (vfm_sink);
-  vfm_source_info.ncases = vfm_sink_info.ncases;
-  vfm_source_info.nval = compaction_nval;
-  vfm_source_info.case_size = (sizeof (struct ccase)
-                              + (compaction_nval - 1) * sizeof (union value));
 
   /* Old data sink is gone now. */
   free (vfm_sink);
@@ -563,18 +534,28 @@ close_active_file (struct write_case_data *data)
 
   /* Clear VECTOR vectors. */
   dict_clear_vectors (default_dict);
-
-  debug_printf (("vfm: procedure complete\n\n"));
 }
 \f
 /* Disk case stream. */
 
+/* Information about disk sink or source. */
+struct disk_stream_info 
+  {
+    FILE *file;                 /* Output file. */
+    size_t case_cnt;            /* Number of cases written so far. */
+    size_t case_size;           /* Number of bytes in case. */
+  };
+
 /* Initializes the disk sink. */
 static void
 disk_sink_create (struct case_sink *sink)
 {
-  sink->aux = tmpfile ();
-  if (!sink->aux)
+  struct disk_stream_info *info = xmalloc (sizeof *info);
+  info->file = tmpfile ();
+  info->case_cnt = 0;
+  info->case_size = compaction_nval;
+  sink->aux = info;
+  if (info->file == NULL)
     {
       msg (ME, _("An error occurred attempting to create a temporary "
                 "file for use as the active file: %s."),
@@ -587,7 +568,7 @@ disk_sink_create (struct case_sink *sink)
 static void
 disk_sink_write (struct case_sink *sink, struct ccase *c)
 {
-  FILE *file = sink->aux;
+  struct disk_stream_info *info = sink->aux;
   union value *src_case;
 
   if (compaction_necessary)
@@ -597,7 +578,9 @@ disk_sink_write (struct case_sink *sink, struct ccase *c)
     }
   else src_case = c->data;
 
-  if (fwrite (src_case, sizeof *src_case * compaction_nval, 1, file) != 1)
+  info->case_cnt++;
+  if (fwrite (src_case, sizeof *src_case * compaction_nval, 1,
+              info->file) != 1)
     {
       msg (ME, _("An error occurred while attempting to write to a "
                 "temporary file used as the active file: %s."),
@@ -610,9 +593,9 @@ disk_sink_write (struct case_sink *sink, struct ccase *c)
 static void
 disk_sink_destroy (struct case_sink *sink)
 {
-  FILE *file = sink->aux;
-  if (file != NULL)
-    fclose (file);
+  struct disk_stream_info *info = sink->aux;
+  if (info->file != NULL)
+    fclose (info->file);
 }
 
 /* Closes and destroys the sink and returns a disk source to read
@@ -620,11 +603,11 @@ disk_sink_destroy (struct case_sink *sink)
 static struct case_source *
 disk_sink_make_source (struct case_sink *sink) 
 {
-  FILE *file = sink->aux;
-  
+  struct disk_stream_info *info = sink->aux;
+    
   /* Rewind the file. */
-  assert (file != NULL);
-  if (fseek (file, 0, SEEK_SET) != 0)
+  assert (info->file != NULL);
+  if (fseek (info->file, 0, SEEK_SET) != 0)
     {
       msg (ME, _("An error occurred while attempting to rewind a "
                 "temporary file used as the active file: %s."),
@@ -632,7 +615,7 @@ disk_sink_make_source (struct case_sink *sink)
       err_failure ();
     }
   
-  return create_case_source (&disk_source_class, file);
+  return create_case_source (&disk_source_class, info);
 }
 
 /* Disk sink. */
@@ -647,18 +630,28 @@ const struct case_sink_class disk_sink_class =
 \f
 /* Disk source. */
 
+/* Returns the number of cases that will be read by
+   disk_source_read(). */
+static int
+disk_source_count (const struct case_source *source) 
+{
+  struct disk_stream_info *info = source->aux;
+
+  return info->case_cnt;
+}
+
 /* Reads all cases from the disk source and passes them one by one to
    write_case(). */
 static void
 disk_source_read (struct case_source *source,
                   write_case_func *write_case, write_case_data wc_data)
 {
-  FILE *file = source->aux;
+  struct disk_stream_info *info = source->aux;
   int i;
 
-  for (i = 0; i < vfm_source_info.ncases; i++)
+  for (i = 0; i < info->case_cnt; i++)
     {
-      if (!fread (temp_case, vfm_source_info.case_size, 1, file))
+      if (!fread (temp_case, info->case_size, 1, info->file))
        {
          msg (ME, _("An error occurred while attempting to read from "
               "a temporary file created for the active file: %s."),
@@ -676,15 +669,17 @@ disk_source_read (struct case_source *source,
 static void
 disk_source_destroy (struct case_source *source)
 {
-  FILE *file = source->aux;
-  if (file != NULL)
-    fclose (file);
+  struct disk_stream_info *info = source->aux;
+  if (info->file != NULL)
+    fclose (info->file);
+  free (info);
 }
 
 /* Disk source. */
 const struct case_source_class disk_source_class = 
   {
     "disk",
+    disk_source_count,
     disk_source_read,
     disk_source_destroy,
   };
@@ -694,6 +689,8 @@ const struct case_source_class disk_source_class =
 /* Memory sink data. */
 struct memory_sink_info
   {
+    size_t case_cnt;            /* Number of cases. */
+    size_t case_size;           /* Case size in bytes. */
     int max_cases;              /* Maximum cases before switching to disk. */
     struct case_list *head;     /* First case in list. */
     struct case_list *tail;     /* Last case in list. */
@@ -702,6 +699,8 @@ struct memory_sink_info
 /* Memory source data. */
 struct memory_source_info 
   {
+    size_t case_cnt;            /* Number of cases. */
+    size_t case_size;           /* Case size in bytes. */
     struct case_list *cases;    /* List of cases. */
   };
 
@@ -713,7 +712,9 @@ memory_sink_create (struct case_sink *sink)
   sink->aux = info = xmalloc (sizeof *info);
 
   assert (compaction_nval > 0);
-  info->max_cases = set_max_workspace / (sizeof (union value) * compaction_nval);
+  info->case_cnt = 0;
+  info->case_size = compaction_nval * sizeof (union value);
+  info->max_cases = set_max_workspace / info->case_size;
   info->head = info->tail = NULL;
 }
 
@@ -729,8 +730,10 @@ memory_sink_write (struct case_sink *sink, struct ccase *c)
   new_case = malloc (case_size);
 
   /* If we've got memory to spare then add it to the linked list. */
-  if (vfm_sink_info.ncases <= info->max_cases && new_case != NULL)
+  if (info->case_cnt <= info->max_cases && new_case != NULL)
     {
+      info->case_cnt++;
+
       /* Append case to linked list. */
       new_case->next = NULL;
       if (info->head != NULL)
@@ -852,6 +855,8 @@ memory_sink_make_source (struct case_sink *sink)
   struct memory_source_info *source_info;
 
   source_info = xmalloc (sizeof *source_info);
+  source_info->case_cnt = sink_info->case_cnt;
+  source_info->case_size = sink_info->case_size;
   source_info->cases = sink_info->head;
 
   free (sink_info);
@@ -868,6 +873,15 @@ const struct case_sink_class memory_sink_class =
     memory_sink_make_source,
   };
 
+/* Returns the number of cases in the source. */
+static int
+memory_source_count (const struct case_source *source) 
+{
+  struct memory_source_info *info = source->aux;
+
+  return info->case_cnt;
+}
+
 /* Reads the case stream from memory and passes it to write_case(). */
 static void
 memory_source_read (struct case_source *source,
@@ -879,7 +893,7 @@ memory_source_read (struct case_source *source,
     {
       struct case_list *iter = info->cases;
       info->cases = iter->next;
-      memcpy (temp_case, &iter->c, vfm_source_info.case_size);
+      memcpy (temp_case, &iter->c, info->case_size);
       free (iter);
       
       if (!write_case (wc_data))
@@ -923,12 +937,11 @@ memory_source_set_cases (const struct case_source *source,
 const struct case_source_class memory_source_class = 
   {
     "memory",
+    memory_source_count,
     memory_source_read,
     memory_source_destroy,
   };
 \f
-#include "debug-print.h"
-
 /* Add temp_case to the lag queue. */
 static void
 lag_case (void)
@@ -965,44 +978,43 @@ lagged_case (int n_before)
 int
 procedure_write_case (write_case_data wc_data)
 {
+  struct procedure_aux_data *proc_aux = wc_data->aux;
+
   /* Index of current transformation. */
   int cur_trns;
 
   /* Return value: whether it's reasonable to write any more cases. */
   int more_cases = 1;
 
-  debug_printf ((_("transform: ")));
-
   cur_trns = f_trns;
   for (;;)
     {
       /* Output the case if this is temp_trns. */
       if (cur_trns == temp_trns)
        {
-         debug_printf (("REC"));
+          int case_limit;
 
          if (n_lag)
            lag_case ();
          
-         vfm_sink_info.ncases++;
          vfm_sink->class->write (vfm_sink, temp_case);
 
-         if (dict_get_case_limit (default_dict))
-           more_cases = (vfm_sink_info.ncases
-                          < dict_get_case_limit (default_dict));
+          proc_aux->cases_written++;
+          case_limit = dict_get_case_limit (default_dict);
+         if (case_limit != 0 && proc_aux->cases_written >= case_limit)
+            more_cases = 0;
        }
 
       /* Are we done? */
       if (cur_trns >= n_trns)
        break;
       
-      debug_printf (("$%d", cur_trns));
-
       /* Decide which transformation should come next. */
       {
        int code;
        
-       code = t_trns[cur_trns]->proc (t_trns[cur_trns], temp_case);
+       code = t_trns[cur_trns]->proc (t_trns[cur_trns], temp_case,
+                                       proc_aux->cases_written + 1);
        switch (code)
          {
          case -1:
@@ -1021,19 +1033,18 @@ procedure_write_case (write_case_data wc_data)
     }
 
   /* Call the beginning of group function. */
-  if (!case_count && wc_data->beginfunc != NULL)
-    wc_data->beginfunc (wc_data->aux);
+  if (!case_count && wc_data->begin_func != NULL)
+    wc_data->begin_func (wc_data->func_aux);
 
   /* Call the procedure if there is one and FILTER and PROCESS IF
      don't prohibit it. */
-  if (wc_data->procfunc != NULL && !exclude_this_case ())
-    wc_data->procfunc (temp_case, wc_data->aux);
+  if (wc_data->proc_func != NULL
+      && !exclude_this_case (proc_aux->cases_written + 1))
+    wc_data->proc_func (temp_case, wc_data->func_aux);
 
   case_count++;
   
 done:
-  debug_putc ('\n', stdout);
-
   clear_temp_case ();
   
   /* Return previously determined value. */
@@ -1063,10 +1074,11 @@ clear_temp_case (void)
     }
 }
 
-/* Returns nonzero if this case should be exclude as specified on
-   FILTER or PROCESS IF, otherwise zero. */
+/* Returns nonzero if this case (numbered CASE_NUM) should be
+   exclude as specified on FILTER or PROCESS IF, otherwise
+   zero. */
 static int
-exclude_this_case (void)
+exclude_this_case (int case_num)
 {
   /* FILTER. */
   struct variable *filter_var = dict_get_filter (default_dict);
@@ -1079,7 +1091,7 @@ exclude_this_case (void)
 
   /* PROCESS IF. */
   if (process_if_expr != NULL
-      && expr_evaluate (process_if_expr, temp_case, NULL) != 1.0)
+      && expr_evaluate (process_if_expr, temp_case, case_num, NULL) != 1.0)
     return 1;
 
   return 0;
@@ -1159,14 +1171,14 @@ dump_splits (struct ccase *c)
   tab_submit (t);
 }
 
-/* This procfunc is substituted for the user-supplied procfunc when
+/* This proc_func is substituted for the user-supplied proc_func when
    SPLIT FILE is active.  This function forms a wrapper around that
-   procfunc by dividing the input into series. */
+   proc_func by dividing the input into series. */
 static int
-SPLIT_FILE_procfunc (struct ccase *c, void *data_)
+SPLIT_FILE_proc_func (struct ccase *c, void *data_)
 {
   struct write_case_data *data = data_;
-  static struct ccase *prev_case;
+  struct split_aux_data *split_aux = data->aux;
   struct variable *const *split;
   size_t split_cnt;
   size_t i;
@@ -1175,16 +1187,13 @@ SPLIT_FILE_procfunc (struct ccase *c, void *data_)
      preserve the values of the case for later comparison. */
   if (case_count == 0)
     {
-      if (prev_case)
-       free (prev_case);
-      prev_case = xmalloc (vfm_sink_info.case_size);
-      memcpy (prev_case, c, vfm_sink_info.case_size);
+      memcpy (split_aux->prev_case, c, dict_get_case_size (default_dict));
 
       dump_splits (c);
-      if (data->beginfunc != NULL)
-       data->beginfunc (data->aux);
+      if (data->begin_func != NULL)
+       data->begin_func (data->func_aux);
       
-      return data->procfunc (c, data->aux);
+      return data->proc_func (c, data->func_aux);
     }
 
   /* Compare the value of each SPLIT FILE variable to the values on
@@ -1198,30 +1207,31 @@ SPLIT_FILE_procfunc (struct ccase *c, void *data_)
       switch (v->type)
        {
        case NUMERIC:
-         if (c->data[v->fv].f != prev_case->data[v->fv].f)
+         if (c->data[v->fv].f != split_aux->prev_case->data[v->fv].f)
            goto not_equal;
          break;
        case ALPHA:
-         if (memcmp (c->data[v->fv].s, prev_case->data[v->fv].s, v->width))
+         if (memcmp (c->data[v->fv].s,
+                      split_aux->prev_case->data[v->fv].s, v->width))
            goto not_equal;
          break;
        default:
          assert (0);
        }
     }
-  return data->procfunc (c, data->aux);
+  return data->proc_func (c, data->func_aux);
   
 not_equal:
   /* The values of the SPLIT FILE variable are different from the
      values on the previous case.  That means that it's time to begin
      a new series. */
-  if (data->endfunc != NULL)
-    data->endfunc (data->aux);
+  if (data->end_func != NULL)
+    data->end_func (data->func_aux);
   dump_splits (c);
-  if (data->beginfunc != NULL)
-    data->beginfunc (data->aux);
-  memcpy (prev_case, c, vfm_sink_info.case_size);
-  return data->procfunc (c, data->aux);
+  if (data->begin_func != NULL)
+    data->begin_func (data->func_aux);
+  memcpy (split_aux->prev_case, c, dict_get_case_size (default_dict));
+  return data->proc_func (c, data->func_aux);
 }
 \f
 /* Case compaction. */
@@ -1304,7 +1314,6 @@ case_source_is_class (const struct case_source *source,
                       const struct case_source_class *class) 
 {
   return source != NULL && source->class == class;
-
 }
 
 struct case_sink *
index f50b45ee38b5306337808d5059d33b3714f292c2..186dd6f1d09ca17721f0524630346c28d92881d3 100644 (file)
--- a/src/vfm.h
+++ b/src/vfm.h
@@ -46,6 +46,10 @@ struct case_source_class
   {
     const char *name;                   /* Identifying name. */
     
+    /* Returns the exact number of cases that READ will pass to
+       WRITE_CASE, if known, or -1 otherwise. */
+    int (*count) (const struct case_source *);
+
     /* Reads all the cases and calls WRITE_CASE passing the given
        AUX data for each one. */
     void (*read) (struct case_source *, write_case_func *, write_case_data);
index eb52f0ed9697a726462cdd17c348863a5c839175..d29200ea0545fd00fa7254770cdbf991e66e4650 100644 (file)
 
 #include "var.h"
 
-/* Describes a data stream, either a source or a sink. */
-struct stream_info
-  {
-    int case_size;             /* Size of one case in bytes. */
-    int ncases;                        /* Number of cases. */
-    int nval;                  /* Number of `value' elements per case. */
-  };
-
-/* Information about the data source. */
-extern struct stream_info vfm_source_info;
-
-/* Information about the data sink. */
-extern struct stream_info vfm_sink_info;
-
 /* Nonzero if the case needs to have values deleted before being
    stored, zero otherwise. */
 extern int compaction_necessary;
 
-/* Number of values after compaction, or the same as
-   vfm_sink_info.nval, if compaction is not necessary. */
+/* Number of values after compaction. */
 extern int compaction_nval;
 
 /* Temporary case buffer with enough room for `compaction_nval'