Eliminate temp_case, and a few other cleanups.
authorBen Pfaff <blp@gnu.org>
Wed, 10 Mar 2004 07:40:03 +0000 (07:40 +0000)
committerBen Pfaff <blp@gnu.org>
Wed, 10 Mar 2004 07:40:03 +0000 (07:40 +0000)
31 files changed:
TODO
doc/ChangeLog
doc/pspp.texi
src/ChangeLog
src/aggregate.c
src/compute.c
src/data-list.c
src/expr-evl.c
src/expr.h
src/file-type.c
src/flip.c
src/format.c
src/format.h
src/frequencies.q
src/get.c
src/glob.c
src/inpt-pgm.c
src/loop.c
src/matrix-data.c
src/pfm-read.c
src/postscript.c
src/print.c
src/recode.c
src/sample.c
src/sfm-read.c
src/sort.c
src/sort.h
src/vars-prs.c
src/vfm.c
src/vfm.h
src/weight.c

diff --git a/TODO b/TODO
index 9eba34965b903668d9a6127c6dcddeff90a607ad..a4c5c7c25ee20a61c1d6fb3ae98480ed39427944 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,8 +1,10 @@
-Time-stamp: <2004-02-24 19:22:15 blp>
+Time-stamp: <2004-03-05 15:22:29 blp>
 
 TODO
 ----
 
+In debug mode hash table code should verify that collisions are reasonably low.
+
 Use posix_fadvise(POSIX_FADV_SEQUENTIAL) where available.
 
 random.c should not know about set_seed.
index b9cf67aa25abb389377597bdfa464c0181c211ad..dbf6547fb7d6b3c7b821966b11c759e31259768d 100644 (file)
@@ -1,3 +1,7 @@
+Tue Mar  9 22:34:17 2004  Ben Pfaff  <blp@gnu.org>
+
+       * Updated.
+
 Wed Feb 18 18:15:48 2004  Ben Pfaff  <blp@gnu.org>
 
        * Improve CROSSTABS description
index aceaf8a5ce98fc88bd4b1eedc978bda1e7b4da83..564e36ec7d6e7d9d34235d96f57a4fe189f9d13e 100644 (file)
@@ -5806,6 +5806,11 @@ columns that the identifier will occupy, followed by an equals sign
 (@samp{=}) and the identifier variable name.  The variable must already
 have been declared with @cmd{NUMERIC} or another command.
 
+@cmd{REPEATING DATA} should be the last command given within an
+@cmd{INPUT PROGRAM}.  It should not be enclosed within a @cmd{LOOP}
+structure (@pxref{LOOP}).  Use @cmd{DATA LIST} before, not after,
+@cmd{REPEATING DATA}.
+
 @node WRITE,  , REPEATING DATA, Data Input and Output
 @section WRITE
 @vindex WRITE
index 0dcff3dc5c2f881c80bce348595d74501d2b3d02..5e7f0c1a3757b1b36a3c27479cd8479bc817cef5 100644 (file)
@@ -1,3 +1,143 @@
+Tue Mar  9 23:10:41 2004  Ben Pfaff  <blp@gnu.org>
+
+       * format.c: (global array translate_fmt[]) Removed.
+       (translate_fmt) New function as replacement.
+       (parse_format_specifier_name) Rewrite.
+
+       * pfm-read.c: (convert_format) Use translate_fmt() instead of
+       translate_fmt[].
+
+       * sfm-read.c: (parse_format_spec) Ditto.
+
+       * postscript.c: (text) Fix handling of fonts with missing
+       ligatures.
+
+       * sort.c: (struct external_sort) Add temp_name member.
+       (destroy_external_sort) Free temp_dir, temp_name members.
+       (init_external_sort) Allocate temp_name.
+       (get_temp_file_name) Change prototype.
+       (open_temp_file) Deal with change to get_temp_file_name().
+       (close_temp_file) Ditto.
+       (remove_temp_file) Ditto.
+       (write_temp_file) Ditto.
+       (read_temp_file) Ditto.
+       (sort_sink_destroy) Removed.
+       (sort_sink_class) Change destroy member to null.
+
+Tue Mar  9 22:36:34 2004  Ben Pfaff  <blp@gnu.org>
+
+       Eliminate temp_case.
+
+       * aggregate.c: (cmd_aggregate) No need to save/restore temp_case
+       anymore.  Use agr_11x_finish().
+       (aggregate_single_case) Make first param const.
+       (accumulate_aggregate_info) Ditto.
+       (agr_00x_end_func) Use compaction_case, not temp_case.
+       (agr_11x_func) Break into agr_11x_read(), agr_11x_finish().
+
+       * data-list.c: (struct data_list_pgm) Add `case_size' member.
+       (cmd_data_list) Initialize case_size.
+       (read_from_data_list_fixed) Add struct ccase * param, use instead
+       of temp_case.
+       (read_from_data_list_free) Ditto.
+       (read_from_data_list_list) Ditto.
+       (read_one_case) Rename data_list_trns_proc(), all references
+       updated.  Add argument in calling above functions.  Use c
+       argument instead of temp_case.
+       (destroy_dls) Rename data_list_trns_free(), all references
+       updated.
+
+       * expr-evl.c: (expr_evaluate) Make second parameter const.
+
+       * file-type.c: (struct file_type_pgm) Add `case_size' member.
+       (cmd_end_file_type) Initialize `case_size'.
+       (file_type_source_read) Add struct ccase * parameter.  Use instead
+       of temp_case.
+
+       * flip.c: Rewritten.
+
+       * get.c: (struct get_pgm) New structure to keep track of
+       case_size.
+       (cmd_get) Initialize case_size.
+       (cmd_import) Ditto.
+       (get_source) Deal with struct get_pgm.
+       (get_source_read) Add struct ccase * parameter, use instead of
+       temp_case.
+       (import_source_read) Ditto.
+
+       * get.c: Use a null pointer instead of temp_case to represent the
+       "current case" in a struct mtf_file's input member.
+       (mtf_processing_finish) Pass null to mtf_processing(), not
+       temp_case.
+       (mtf_read_nonactive_records) Don't set iter->input to temp_case.
+       (mtf_compare_BY_values) Add extra arg, use instead of null input
+       members.
+       (mtf_processing) Use c parameter instead of temp_case.  Pass
+       compaction_case to process_active_file_output_case().
+       
+       * glob.c: (global variable temp_case) Removed.
+
+       * inpt-pgm.c: (struct input_program_pgm) Add `case_size' member.
+       (cmd_input_program) Initialize case_size.  Set
+       vfm_source->value_cnt.
+       (init_case) Add struct ccase * parameter, use instead of
+       temp_case.
+       (clear_case) Ditto.
+       (input_program_source_read) Ditto.
+
+       * matrix-data.c: (matrix_data_read_without_rowtype) Ditto.
+       (dump_cell_content) Ditto.
+       (nr_output_data) Ditto.
+       (read_matrices_without_rowtype) Ditto.
+       (matrix_data_read_with_rowtype) Ditto.
+       (wr_read_splits) Ditto.
+       (wr_output_data) Ditto.
+
+       * sort.h: (struct sort_cases_pgm) New member `case_size'.
+       
+       * sort.c: (sort_cases) Initialize scp->case_size.
+       (struct external_sort) Remove `case_size' member.
+       (write_initial_runs) Only call vfm_sink->class_destroy if
+       non-null.
+       (struct sort_source_aux) New structure.
+       (sort_source_read_helper) New function.
+       (sort_source_read) Use sort_source_read_helper().
+       (read_sort_output) Change interface to be more reasonable.
+       (read_internal_sort_output) Ditto.
+       (read_external_sort_output) Ditto.
+
+       * vars-prs.c: (dict_class_to_name) Pass return value through
+       gettext.
+
+       * vfm.c: (struct procedure_aux_data) Add `trns_case' member.
+       (procedure) Initialize trns_case.
+       (procedure) Pass trns_case to vfm_source->class->read().
+       Free trns_case.
+       (process_active_file) Start using struct procedure_aux_data.
+       (process_active_file_write_case) Pass trns_case to
+       transformations, lag_case(), clear_case().
+       (process_active_file_output_case) Add struct ccase * parameter.
+       (create_trns_case) New function.
+       (make_temp_case) Removed.
+       (vector_initialization) Removed.
+       (close_active_file) Only call make_source if non-null, otherwise
+       set vfm_source to null pointer.  Don't free temp_case.
+       (disk_source_read) Add struct ccase * parameter, use instead of
+       temp_case.
+       (memory_source_read) Ditto.
+       (lag_case) Add const struct ccase * member.
+       (procedure_write_case) Use trns_case instead of temp_case.
+       (clear_case) Add struct ccase * member, use instead of temp_case.
+       (exclude_this_case) Ditto.
+       (create_case_source) Add struct dictionary * parameter, use to
+       initialize source->value_cnt.
+
+       * vfm.h: (struct case_source) Add `value_cnt' member.
+       (struct case_source_class) Add struct ccase * parameter to `read'
+       member function pointer.
+       (struct case_sink_class) Make struct ccase * parameter const in
+       `write' member function pointer.
+       
 Wed Mar  3 20:44:37 2004  Ben Pfaff  <blp@gnu.org>
 
        Fix a lot of "possibly uninitialized variable" warnings.  Some of
index 880a713a3e6481e18c86a9298578b7816647fa84..4d00a34ad2cbb7404548762a0096f94b22f9e409 100644 (file)
@@ -141,14 +141,16 @@ static void initialize_aggregate_info (void);
 /* Prototypes. */
 static int parse_aggregate_functions (void);
 static void free_aggregate_functions (void);
-static int aggregate_single_case (struct ccase *input, struct ccase *output);
+static int aggregate_single_case (const struct ccase *input,
+                                  struct ccase *output);
 static int create_sysfile (void);
 
 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);
+static read_sort_output_func agr_11x_read;
+static void agr_11x_finish (void);
 
 #if DEBUGGING
 static void debug_print (int flags);
@@ -367,20 +369,14 @@ cmd_aggregate (void)
        }
          
       case 6:
-      case 7:
+      case 7: 
        sort_cases (sort, 1);
        
        if (!create_sysfile ())
          goto lossage;
-       read_sort_output (sort, agr_11x_func, NULL);
-       
-       {
-         struct ccase *save_temp_case = temp_case;
-         temp_case = NULL;
-         agr_11x_func (NULL);
-         temp_case = save_temp_case;
-       }
-       
+       read_sort_output (sort, agr_11x_read, NULL);
+        agr_11x_finish ();
+
        break;
 
       default:
@@ -762,7 +758,7 @@ free_aggregate_functions (void)
 \f
 /* Execution. */
 
-static void accumulate_aggregate_info (struct ccase *input);
+static void accumulate_aggregate_info (const struct ccase *input);
 static void dump_aggregate_info (struct ccase *output);
 
 /* Processes a single case INPUT for aggregation.  If output is
@@ -772,7 +768,7 @@ static void dump_aggregate_info (struct ccase *output);
 /* The code in this function has an eerie similarity to
    vfm.c:SPLIT_FILE_procfunc()... */
 static int
-aggregate_single_case (struct ccase *input, struct ccase *output)
+aggregate_single_case (const struct ccase *input, struct ccase *output)
 {
   /* The first case always begins a new break group.  We also need to
      preserve the values of the case for later comparison. */
@@ -877,7 +873,7 @@ not_equal:
 
 /* Accumulates aggregation data from the case INPUT. */
 static void 
-accumulate_aggregate_info (struct ccase *input)
+accumulate_aggregate_info (const struct ccase *input)
 {
   struct agr_var *iter;
   double weight;
@@ -887,7 +883,7 @@ accumulate_aggregate_info (struct ccase *input)
   for (iter = agr_first; iter; iter = iter->next)
     if (iter->src)
       {
-       union value *v = &input->data[iter->src->fv];
+       const union value *v = &input->data[iter->src->fv];
 
        if ((!iter->include_missing && is_missing (v, iter->src))
            || (iter->include_missing && iter->src->type == NUMERIC
@@ -1214,7 +1210,7 @@ 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->class->write (vfm_sink, temp_case);
+  vfm_sink->class->write (vfm_sink, compaction_case);
 }
 
 /* Transform the aggregate case buf_1xx, in internal format, to system
@@ -1280,31 +1276,30 @@ agr_10x_end_func (void *aux UNUSED)
   write_case_to_sfm ();
 }
 
-/* When called with temp_case non-NULL (the normal case), runs the
-   case through the aggregater and outputs it to the system file if
-   appropriate.  If temp_case is NULL, finishes up writing the last
-   case if necessary. */
+/* Runs case C through the aggregater and outputs it to the
+   system file if appropriate.  */
 static int
-agr_11x_func (write_case_data wc_data UNUSED)
+agr_11x_read (const struct ccase *c, void *aux UNUSED)
 {
-  if (temp_case != NULL)
-    {
-      int code = aggregate_single_case (temp_case, buf_1xx);
+  int code = aggregate_single_case (c, buf_1xx);
       
-      assert (code == -2 || code == -1);
-      if (code == -1)
-       write_case_to_sfm ();
-    }
-  else
+  assert (code == -2 || code == -1);
+  if (code == -1)
+    write_case_to_sfm ();
+
+  return 1;
+}
+
+/* Finishes up writing the last case if necessary. */
+static void
+agr_11x_finish (void) 
+{
+  if (case_count)
     {
-      if (case_count)
-       {
-         dump_aggregate_info (buf_1xx);
-         write_case_to_sfm ();
-       }
-      fh_close_handle (outfile);
+      dump_aggregate_info (buf_1xx);
+      write_case_to_sfm ();
     }
-  return 1;
+  fh_close_handle (outfile);
 }
 \f
 /* Debugging. */
index 60c99ad825b7dde1295a75dd9d558417ee093b2a..9c20e0ee781f1999922790eaa421807d01115b72 100644 (file)
@@ -104,6 +104,7 @@ cmd_compute (void)
 \f
 /* Transformation functions. */
 
+/* Handle COMPUTE or IF with numeric target variable. */
 static int
 compute_num (struct trns_header *compute_, struct ccase *c,
              int case_num)
@@ -119,6 +120,8 @@ compute_num (struct trns_header *compute_, struct ccase *c,
   return -1;
 }
 
+/* Handle COMPUTE or IF with numeric vector element target
+   variable. */
 static int
 compute_num_vec (struct trns_header *compute_, struct ccase *c,
                  int case_num)
@@ -154,6 +157,7 @@ compute_num_vec (struct trns_header *compute_, struct ccase *c,
   return -1;
 }
 
+/* Handle COMPUTE or IF with string target variable. */
 static int
 compute_str (struct trns_header *compute_, struct ccase *c,
              int case_num)
@@ -174,6 +178,8 @@ compute_str (struct trns_header *compute_, struct ccase *c,
   return -1;
 }
 
+/* Handle COMPUTE or IF with string vector element target
+   variable. */
 static int
 compute_str_vec (struct trns_header *compute_, struct ccase *c,
                  int case_num)
@@ -317,6 +323,7 @@ compute_trns_free (struct trns_header *compute_)
   expr_free (compute->rvalue);
 }
 \f
+/* COMPUTE or IF target variable or vector element. */
 struct lvalue
   {
     char var_name[9];            /* Destination variable name, or "". */
@@ -324,6 +331,8 @@ struct lvalue
     struct expression *element;  /* Destination vector element, or NULL. */
   };
 
+/* Parses the target variable or vector elector into a new
+   `struct lvalue', which is returned. */
 static struct lvalue *
 lvalue_parse (void) 
 {
@@ -371,6 +380,8 @@ lvalue_parse (void)
   return NULL;
 }
 
+/* Returns the type (NUMERIC or ALPHA) of the target variable or
+   vector in LVALUE. */
 static int
 lvalue_get_type (const struct lvalue *lvalue) 
 {
@@ -387,12 +398,15 @@ lvalue_get_type (const struct lvalue *lvalue)
     return lvalue->vector->var[0]->type;
 }
 
+/* Returns nonzero if LVALUE has a vector as its target. */
 static int
 lvalue_is_vector (const struct lvalue *lvalue) 
 {
   return lvalue->vector != NULL;
 }
 
+/* Finalizes making LVALUE the target of COMPUTE, by creating the
+   target variable if necessary and setting fields in COMPUTE. */
 static void
 lvalue_finalize (struct lvalue *lvalue,
                  struct compute_trns *compute) 
@@ -407,8 +421,6 @@ lvalue_finalize (struct lvalue *lvalue,
       compute->fv = compute->variable->fv;
       compute->width = compute->variable->width;
 
-      
-
       /* Goofy behavior, but compatible: Turn off LEAVE. */
       if (dict_class_from_id (compute->variable->name) != DC_SCRATCH)
         compute->variable->reinit = 1;
@@ -423,6 +435,7 @@ lvalue_finalize (struct lvalue *lvalue,
   lvalue_destroy (lvalue);
 }
 
+/* Destroys LVALUE. */
 static void 
 lvalue_destroy (struct lvalue *lvalue) 
 {
index 11b7f9c7068a44ad5eac04f2f4854e48bfaaaba1..de50b437990fdf16a88ca6b7a98646a4e9182a1d 100644 (file)
@@ -79,14 +79,15 @@ enum
 struct data_list_pgm
   {
     struct trns_header h;
+
     struct dls_var_spec *first, *last; /* Variable parsing specifications. */
     struct file_handle *handle;        /* Input file, never NULL. */
-    /* Do not reorder preceding fields. */
 
     int type;                  /* A DLS_* constant. */
     struct variable *end;      /* Variable specified on END subcommand. */
     int eof;                   /* End of file encountered. */
     int nrec;                  /* Number of records. */
+    size_t case_size;           /* Case size in bytes. */
   };
 
 static int parse_fixed (struct data_list_pgm *);
@@ -95,8 +96,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 trns_free_func destroy_dls;
-static trns_proc_func read_one_case;
+static trns_free_func data_list_trns_free;
+static trns_proc_func data_list_trns_proc;
 
 /* Message title for REPEATING DATA. */
 #define RPD_ERR "REPEATING DATA: "
@@ -207,6 +208,7 @@ cmd_data_list (void)
        }
     }
 
+  dls->case_size = dict_get_case_size (default_dict);
   default_handle = dls->handle;
 
   if (dls->type == -1)
@@ -239,15 +241,16 @@ cmd_data_list (void)
     {
       struct data_list_pgm *new_pgm;
 
-      dls->h.proc = read_one_case;
-      dls->h.free = destroy_dls;
+      dls->h.proc = data_list_trns_proc;
+      dls->h.free = data_list_trns_free;
 
       new_pgm = xmalloc (sizeof *new_pgm);
       memcpy (new_pgm, &dls, sizeof *new_pgm);
       add_transformation (&new_pgm->h);
     }
   else 
-    vfm_source = create_case_source (&data_list_source_class, dls);
+    vfm_source = create_case_source (&data_list_source_class,
+                                     default_dict, dls);
 
   return CMD_SUCCESS;
 
@@ -257,6 +260,8 @@ cmd_data_list (void)
   return CMD_FAILURE;
 }
 
+/* Adds SPEC to the linked list with head at FIRST and tail at
+   LAST. */
 static void
 append_var_spec (struct dls_var_spec **first, struct dls_var_spec **last,
                  struct dls_var_spec *spec)
@@ -281,9 +286,7 @@ struct fmt_list
     struct fmt_list *down;
   };
 
-/* Used as "local" variables among the fixed-format parsing funcs.  If
-   it were guaranteed that PSPP were going to be compiled by gcc,
-   I'd make all these functions a single set of nested functions. */
+/* State of parsing DATA LIST. */
 struct fixed_parsing_state
   {
     char **name;               /* Variable names. */
@@ -301,6 +304,8 @@ static int fixed_parse_fortran (struct fixed_parsing_state *,
                                 struct dls_var_spec **,
                                 struct dls_var_spec **);
 
+/* Parses all the variable specifications for DATA LIST FIXED,
+   storing them into DLS.  Returns nonzero if successful. */
 static int
 parse_fixed (struct data_list_pgm *dls)
 {
@@ -384,6 +389,9 @@ fail:
   return 0;
 }
 
+/* Parses a variable specification in the form 1-10 (A) based on
+   FX and adds specifications to the linked list with head at
+   FIRST and tail at LAST. */
 static int
 fixed_parse_compatible (struct fixed_parsing_state *fx,
                         struct dls_var_spec **first, struct dls_var_spec **last)
@@ -558,7 +566,8 @@ fixed_parse_compatible (struct fixed_parsing_state *fx,
   return 1;
 }
 
-/* Destroy a format list and, optionally, all its sublists. */
+/* Destroy format list F and, if RECURSE is nonzero, all its
+   sublists. */
 static void
 destroy_fmt_list (struct fmt_list *f, int recurse)
 {
@@ -574,9 +583,10 @@ destroy_fmt_list (struct fmt_list *f, int recurse)
 }
 
 /* Takes a hierarchically structured fmt_list F as constructed by
-   fixed_parse_fortran(), and flattens it into a linear list of
-   dls_var_spec's.  NAME_IDX is used to take values from the list
-   of names in FX; it should initially point to a value of 0. */
+   fixed_parse_fortran(), and flattens it, adding the variable
+   specifications to the linked list with head FIRST and tail
+   LAST.  NAME_IDX is used to take values from the list of names
+   in FX; it should initially point to a value of 0. */
 static int
 dump_fmt_list (struct fixed_parsing_state *fx, struct fmt_list *f,
                struct dls_var_spec **first, struct dls_var_spec **last,
@@ -646,10 +656,10 @@ dump_fmt_list (struct fixed_parsing_state *fx, struct fmt_list *f,
   return 1;
 }
 
-/* Recursively parses a FORTRAN-like format specification.  LEVEL
-   is the level of recursion, starting from 0.  Returns the
-   parsed specification if successful, or a null pointer on
-   failure.  */
+/* Recursively parses a FORTRAN-like format specification into
+   the linked list with head FIRST and tail TAIL.  LEVEL is the
+   level of recursion, starting from 0.  Returns the parsed
+   specification if successful, or a null pointer on failure.  */
 static struct fmt_list *
 fixed_parse_fortran_internal (struct fixed_parsing_state *fx,
                               struct dls_var_spec **first,
@@ -707,8 +717,9 @@ fail:
   return NULL;
 }
 
-/* Parses a FORTRAN-like format specification.  Returns nonzero
-   if successful. */
+/* Parses a FORTRAN-like format specification into the linked
+   list with head FIRST and tail LAST.  Returns nonzero if
+   successful. */
 static int
 fixed_parse_fortran (struct fixed_parsing_state *fx,
                      struct dls_var_spec **first, struct dls_var_spec **last)
@@ -792,6 +803,9 @@ dump_fixed_table (const struct dls_var_spec *specs,
 \f
 /* Free-format parsing. */
 
+/* Parses variable specifications for DATA LIST FREE and adds
+   them to the linked list with head FIRST and tail LAST.
+   Returns nonzero only if successful. */
 static int
 parse_free (struct dls_var_spec **first, struct dls_var_spec **last)
 {
@@ -976,7 +990,7 @@ cut_field (const struct data_list_pgm *dls, char **ret_cp, int *ret_len)
   }
 }
 
-typedef int data_list_read_func (const struct data_list_pgm *);
+typedef int data_list_read_func (const struct data_list_pgm *, struct ccase *);
 static data_list_read_func read_from_data_list_fixed;
 static data_list_read_func read_from_data_list_free;
 static data_list_read_func read_from_data_list_list;
@@ -990,26 +1004,24 @@ get_data_list_read_func (const struct data_list_pgm *dls)
     {
     case DLS_FIXED:
       return read_from_data_list_fixed;
-      break;
 
     case DLS_FREE:
       return read_from_data_list_free;
-      break;
 
     case DLS_LIST:
       return read_from_data_list_list;
-      break;
 
     default:
       assert (0);
     }
 }
 
-/* Reads a case from the data file and parses it according to
-   fixed-format syntax rules.  Returns -1 on success, -2 at end
-   of file. */
+/* Reads a case from the data file into C, parsing it according
+   to fixed-format syntax rules in DLS.  Returns -1 on success,
+   -2 at end of file. */
 static int
-read_from_data_list_fixed (const struct data_list_pgm *dls)
+read_from_data_list_fixed (const struct data_list_pgm *dls,
+                           struct ccase *c)
 {
   struct dls_var_spec *var_spec = dls->first;
   int i;
@@ -1034,7 +1046,7 @@ read_from_data_list_fixed (const struct data_list_pgm *dls)
          struct data_in di;
 
          data_in_finite_line (&di, line, len, var_spec->fc, var_spec->lc);
-         di.v = &temp_case->data[var_spec->fv];
+         di.v = &c->data[var_spec->fv];
          di.flags = 0;
          di.f1 = var_spec->fc;
          di.format = var_spec->input;
@@ -1048,11 +1060,12 @@ read_from_data_list_fixed (const struct data_list_pgm *dls)
   return -1;
 }
 
-/* Reads a case from the data file and parses it according to
-   free-format syntax rules.  Returns -1 on success, -2 at end of
-   file. */
+/* Reads a case from the data file into C, parsing it according
+   to free-format syntax rules in DLS.  Returns -1 on success,
+   -2 at end of file. */
 static int
-read_from_data_list_free (const struct data_list_pgm *dls)
+read_from_data_list_free (const struct data_list_pgm *dls,
+                          struct ccase *c)
 {
   struct dls_var_spec *var_spec;
   char *field;
@@ -1085,7 +1098,7 @@ read_from_data_list_free (const struct data_list_pgm *dls)
 
        di.s = field;
        di.e = field + len;
-       di.v = &temp_case->data[var_spec->fv];
+       di.v = &c->data[var_spec->fv];
        di.flags = 0;
        di.f1 = column;
        di.format = var_spec->input;
@@ -1099,7 +1112,8 @@ read_from_data_list_free (const struct data_list_pgm *dls)
    list-format syntax rules.  Returns -1 on success, -2 at end of
    file. */
 static int
-read_from_data_list_list (const struct data_list_pgm *dls)
+read_from_data_list_list (const struct data_list_pgm *dls,
+                          struct ccase *c)
 {
   struct dls_var_spec *var_spec;
   char *field;
@@ -1124,9 +1138,9 @@ read_from_data_list_list (const struct data_list_pgm *dls)
             {
               int width = get_format_var_width (&var_spec->input);
               if (width == 0)
-                temp_case->data[var_spec->fv].f = SYSMIS;
+                c->data[var_spec->fv].f = SYSMIS;
               else
-                memset (temp_case->data[var_spec->fv].s, ' ', width); 
+                memset (c->data[var_spec->fv].s, ' ', width); 
             }
          break;
        }
@@ -1136,7 +1150,7 @@ read_from_data_list_list (const struct data_list_pgm *dls)
 
        di.s = field;
        di.e = field + len;
-       di.v = &temp_case->data[var_spec->fv];
+       di.v = &c->data[var_spec->fv];
        di.flags = 0;
        di.f1 = column;
        di.format = var_spec->input;
@@ -1164,7 +1178,7 @@ destroy_dls_var_spec (struct dls_var_spec *spec)
 
 /* Destroys DATA LIST transformation PGM. */
 static void
-destroy_dls (struct trns_header *pgm)
+data_list_trns_free (struct trns_header *pgm)
 {
   struct data_list_pgm *dls = (struct data_list_pgm *) pgm;
   destroy_dls_var_spec (dls->first);
@@ -1172,11 +1186,10 @@ destroy_dls (struct trns_header *pgm)
   free (pgm);
 }
 
-/* Note that since this is exclusively an input program, C is
-   guaranteed to be temp_case. */
+/* Handle DATA LIST transformation T, parsing data into C. */
 static int
-read_one_case (struct trns_header *t, struct ccase *c UNUSED,
-               int case_num UNUSED)
+data_list_trns_proc (struct trns_header *t, struct ccase *c,
+                     int case_num UNUSED)
 {
   struct data_list_pgm *dls = (struct data_list_pgm *) t;
   data_list_read_func *read_func;
@@ -1185,7 +1198,7 @@ read_one_case (struct trns_header *t, struct ccase *c UNUSED,
   dfm_push (dls->handle);
 
   read_func = get_data_list_read_func (dls);
-  retval = read_func (dls);
+  retval = read_func (dls, c);
 
   /* Handle end of file. */
   if (retval == -2)
@@ -1211,11 +1224,11 @@ read_one_case (struct trns_header *t, struct ccase *c UNUSED,
     {
       if (retval == -2)
         {
-          temp_case->data[dls->end->fv].f = 1.0;
+          c->data[dls->end->fv].f = 1.0;
           retval = -1;
         }
       else
-        temp_case->data[dls->end->fv].f = 0.0;
+        c->data[dls->end->fv].f = 0.0;
     }
   
   dfm_pop (dls->handle);
@@ -1227,13 +1240,14 @@ read_one_case (struct trns_header *t, struct ccase *c UNUSED,
    write_case(). */
 static void
 data_list_source_read (struct case_source *source,
+                       struct ccase *c,
                        write_case_func *write_case, write_case_data wc_data)
 {
   struct data_list_pgm *dls = source->aux;
   data_list_read_func *read_func = get_data_list_read_func (dls);
 
   dfm_push (dls->handle);
-  while (read_func (dls) != -2)
+  while (read_func (dls, c) != -2)
     if (!write_case (wc_data))
       break;
   dfm_pop (dls->handle);
@@ -1245,7 +1259,7 @@ data_list_source_read (struct case_source *source,
 static void
 data_list_source_destroy (struct case_source *source)
 {
-  destroy_dls (source->aux);
+  data_list_trns_free (source->aux);
 }
 
 const struct case_source_class data_list_source_class = 
@@ -1568,10 +1582,9 @@ cmd_repeating_data (void)
   return CMD_FAILURE;
 }
 
-/* Because of the way that DATA LIST is structured, it's not trivial
-   to determine what input format is associated with a given variable.
-   This function finds the input format specification for variable V
-   and puts it in SPEC. */
+/* Finds the input format specification for variable V and puts
+   it in SPEC.  Because of the way that DATA LIST is structured,
+   this is nontrivial. */
 static void 
 find_variable_input_spec (struct variable *v, struct fmt_spec *spec)
 {
@@ -1581,7 +1594,7 @@ find_variable_input_spec (struct variable *v, struct fmt_spec *spec)
     {
       struct data_list_pgm *pgm = (struct data_list_pgm *) t_trns[i];
       
-      if (pgm->h.proc == read_one_case)
+      if (pgm->h.proc == data_list_trns_proc)
        {
          struct dls_var_spec *iter;
 
@@ -1634,8 +1647,9 @@ parse_num_or_var (struct rpd_num_or_var *value, const char *message)
   return 1;
 }
 
-/* Parses data specifications for repeating data groups.  Taken from
-   parse_fixed().  Returns nonzero only if successful.  */
+/* Parses data specifications for repeating data groups, adding
+   them to the linked list with head FIRST and tail LAST.
+   Returns nonzero only if successful.  */
 static int
 parse_repeating_data (struct dls_var_spec **first, struct dls_var_spec **last)
 {
@@ -1827,9 +1841,9 @@ rpd_parse_record (const struct rpd_parse_info *info)
   return occurrences;
 }
 
-/* Analogous to read_one_case; reads one set of repetitions of the
-   elements in the REPEATING DATA structure.  Returns -1 on success,
-   -2 on end of file or on failure. */
+/* Reads one set of repetitions of the 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,
                           int case_num UNUSED)
@@ -1983,6 +1997,7 @@ repeating_data_trns_proc (struct trns_header *trns, struct ccase *c,
   return -3;
 }
 
+/* Frees a REPEATING DATA transformation. */
 void
 repeating_data_trns_free (struct trns_header *rpd_) 
 {
@@ -1993,10 +2008,8 @@ repeating_data_trns_free (struct trns_header *rpd_)
   free (rpd->id_value);
 }
 
-/* This is a kluge.  It is only here until I have more time
-   tocome up with something better.  It lets
-   repeating_data_trns_proc() know how to write the cases that it
-   composes. */
+/* Lets repeating_data_trns_proc() know how to write the cases
+   that it composes.  Not elegant. */
 void
 repeating_data_set_write_case (struct trns_header *trns,
                                write_case_func *write_case,
index 34bbd6ac3d52315c2216ff4af6ebb5c73d760f26..62a9f6b2eae6b9768c6d990111f829fb7ff40932 100644 (file)
@@ -51,7 +51,7 @@
 #include "vfmP.h"
 
 double
-expr_evaluate (struct expression *e, struct ccase *c, int case_num,
+expr_evaluate (struct expression *e, const struct ccase *c, int case_num,
                union value *v)
 {
   unsigned char *op = e->op;
index 909cf87f1761606857a5480897e9271bde43ff45..5a1da2aef94f9b9ff28cf2b0f2dac6378af0ebd7 100644 (file)
@@ -38,7 +38,7 @@ struct ccase;
 union value;
 
 struct expression *expr_parse (int flags);
-double expr_evaluate (struct expression *, struct ccase *, int case_num,
+double expr_evaluate (struct expression *, const struct ccase *, int case_num,
                       union value *);
 void expr_free (struct expression *);
 
index ea0bb332d679040e1031ff84ebf2fd4ee1ddf86b..e5e3d81e9fde266feb938c8637abadcc4b598bb8 100644 (file)
@@ -86,6 +86,7 @@ struct file_type_pgm
                                   DATA LIST. */
     struct record_type *recs_head;     /* List of record types. */
     struct record_type *recs_tail;     /* Last in list of record types. */
+    size_t case_size;           /* Case size in bytes. */
   };
 
 static int parse_col_spec (struct col_spec *, const char *);
@@ -271,10 +272,10 @@ cmd_file_type (void)
 
   default_handle = fty->handle;
 
-  vfm_source = create_case_source (&file_type_source_class, fty);
   create_col_var (&fty->record);
   if (fty->case_sbc.name[0])
     create_col_var (&fty->case_sbc);
+  vfm_source = create_case_source (&file_type_source_class, default_dict, fty);
 
   return CMD_SUCCESS;
 
@@ -579,6 +580,7 @@ cmd_end_file_type (void)
       return CMD_FAILURE;
     }
   fty = vfm_source->aux;
+  fty->case_size = dict_get_case_size (default_dict);
 
   lex_match_id ("TYPE");
 
@@ -616,10 +618,11 @@ cmd_end_file_type (void)
    static void read_from_file_type_grouped(void);
    static void read_from_file_type_nested(void); */
 
-/* Reads any number of cases into temp_case and calls write_case() for
-   each one.  Compare data-list.c:read_from_data_list. */
+/* Reads any number of cases into case C and calls write_case()
+   for each one.  Compare data-list.c:read_from_data_list. */
 static void
 file_type_source_read (struct case_source *source,
+                       struct ccase *c,
                        write_case_func *write_case UNUSED,
                        write_case_data wc_data UNUSED)
 {
@@ -644,7 +647,7 @@ file_type_source_read (struct case_source *source,
        {
          struct data_in di;
          
-         v.c = temp_case->data[fty->record.v->fv].s;
+         v.c = c->data[fty->record.v->fv].s;
 
          data_in_finite_line (&di, line, len,
                               fty->record.fc, fty->record.fc + fty->record.nc);
@@ -677,7 +680,7 @@ file_type_source_read (struct case_source *source,
          di.format = format;
          data_in (&di);
 
-         memcpy (&temp_case->data[fty->record.v->fv].f, &v.f, sizeof v.f);
+         memcpy (&c->data[fty->record.v->fv].f, &v.f, sizeof v.f);
          for (iter = fty->recs_head; iter; iter = iter->next)
            {
              if (iter->flags & RCT_OTHER)
index 8ae4ac4ee8a699a79dbcb4a6230de105b5d0b95f..7bf59104f7fca2fe5da4abb137c48ffa435e2a8d 100644 (file)
@@ -17,8 +17,6 @@
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
    02111-1307, USA. */
 
-/* FIXME: does this work with long string variables? */
-
 #include <config.h>
 #include <assert.h>
 #include <ctype.h>
@@ -47,18 +45,25 @@ struct varname
 struct flip_pgm 
   {
     struct variable **var;      /* Variables to transpose. */
-    int var_cnt;                /* Number of variables. */
-    struct variable *newnames;  /* Variable containing new variable names. */
-    struct varname *new_names_head, *new_names_tail;
-                                /* New variable names. */
-    int case_count;             /* Number of cases. */
+    int var_cnt;                /* Number of elements in `var'. */
+    int case_cnt;               /* Pre-flip case count. */
+    size_t case_size;           /* Post-flip bytes per case. */
+
+    struct variable *new_names; /* Variable containing new variable names. */
+    struct varname *new_names_head; /* First new variable. */
+    struct varname *new_names_tail; /* Last new variable. */
 
+    FILE *file;                 /* Temporary file containing data. */
   };
 
-static void destroy_flip_pgm (struct flip_pgm *flip);
+static void destroy_flip_pgm (struct flip_pgm *);
 static struct case_sink *flip_sink_create (struct flip_pgm *);
+static struct case_source *flip_source_create (struct flip_pgm *);
+static void flip_file (struct flip_pgm *);
+static int build_dictionary (struct flip_pgm *);
+
 static const struct case_source_class flip_source_class;
-static int build_dictionary (struct flip_pgm *flip);
+static const struct case_sink_class flip_sink_class;
 
 /* Parses and executes FLIP. */
 int
@@ -69,9 +74,11 @@ cmd_flip (void)
   flip = xmalloc (sizeof *flip);
   flip->var = NULL;
   flip->var_cnt = 0;
-  flip->newnames = NULL;
-  flip->new_names_head = flip->new_names_tail = NULL;
-  flip->case_count = 0;
+  flip->case_cnt = 0;
+  flip->new_names = NULL;
+  flip->new_names_head = NULL;
+  flip->new_names_tail = NULL;
+  flip->file = NULL;
 
   lex_match_id ("FLIP");
   lex_match ('/');
@@ -89,19 +96,19 @@ cmd_flip (void)
   if (lex_match_id ("NEWNAMES"))
     {
       lex_match ('=');
-      flip->newnames = parse_variable ();
-      if (!flip->newnames)
+      flip->new_names = parse_variable ();
+      if (!flip->new_names)
         goto error;
     }
   else
-    flip->newnames = dict_lookup_var (default_dict, "CASE_LBL");
+    flip->new_names = dict_lookup_var (default_dict, "CASE_LBL");
 
-  if (flip->newnames)
+  if (flip->new_names)
     {
       int i;
       
       for (i = 0; i < flip->var_cnt; i++)
-       if (flip->var[i] == flip->newnames)
+       if (flip->var[i] == flip->new_names)
          {
            memmove (&flip->var[i], &flip->var[i + 1], sizeof *flip->var * (flip->var_cnt - i - 1));
            flip->var_cnt--;
@@ -109,18 +116,27 @@ cmd_flip (void)
          }
     }
 
-  flip->case_count = 0;
+  /* Read the active file into a flip_sink. */
+  flip->case_cnt = 0;
   temp_trns = temporary = 0;
   vfm_sink = flip_sink_create (flip);
   flip->new_names_tail = NULL;
   procedure (NULL, NULL, NULL, NULL);
 
+  /* Flip the data we read. */
+  flip_file (flip);
+
+  /* Flip the dictionary. */
   dict_clear (default_dict);
   if (!build_dictionary (flip))
     {
       discard_variables ();
       goto error;
     }
+  flip->case_size = dict_get_case_size (default_dict);
+
+  /* Set up flipped data for reading. */
+  vfm_source = flip_source_create (flip);
 
   return lex_end_of_command ();
 
@@ -129,6 +145,7 @@ cmd_flip (void)
   return CMD_FAILURE;
 }
 
+/* Destroys FLIP. */
 static void
 destroy_flip_pgm (struct flip_pgm *flip) 
 {
@@ -140,6 +157,8 @@ destroy_flip_pgm (struct flip_pgm *flip)
       next = iter->next;
       free (iter);
     }
+  if (flip->file != NULL)
+    fclose (flip->file);
   free (flip);
 }
 
@@ -202,13 +221,13 @@ build_dictionary (struct flip_pgm *flip)
     {
       int i;
       
-      if (flip->case_count > 99999)
+      if (flip->case_cnt > 99999)
        {
          msg (SE, _("Cannot create more than 99999 variable names."));
          return 0;
        }
       
-      for (i = 0; i < flip->case_count; i++)
+      for (i = 0; i < flip->case_cnt; i++)
        {
           struct variable *v;
          char s[9];
@@ -233,77 +252,52 @@ build_dictionary (struct flip_pgm *flip)
 struct flip_sink_info 
   {
     struct flip_pgm *flip;              /* FLIP program. */
-    int internal;                      /* Internal or external flip. */
-    char *old_names;                    /* Old variable names. */
-    unsigned long case_cnt;             /* Number of cases. */
-    FILE *file;                         /* Temporary file. */
-  };
-
-/* Source: Cases after transposition. */
-struct flip_source_info 
-  {
-    struct flip_pgm *flip;              /* FLIP program. */
-    char *old_names;                   /* Old variable names. */
-    unsigned long case_cnt;            /* Number of cases. */
-    FILE *file;                         /* Temporary file. */
+    union value *output_buf;            /* Case output buffer. */
   };
 
-static const struct case_sink_class flip_sink_class;
-
-static FILE *flip_file (struct flip_sink_info *info);
-
-/* Creates a flip sink based on FLIP, of which it takes
-   ownership. */
+/* Creates a flip sink based on FLIP. */
 static struct case_sink *
 flip_sink_create (struct flip_pgm *flip) 
 {
   struct flip_sink_info *info = xmalloc (sizeof *info);
+  int i;
 
   info->flip = flip;
-  info->case_cnt = 0;
-  
-  {
-    size_t n = flip->var_cnt;
-    char *p;
-    int i;
-    
-    for (i = 0; i < flip->var_cnt; i++)
-      n += strlen (flip->var[i]->name);
-    p = info->old_names = xmalloc (n);
-    for (i = 0; i < flip->var_cnt; i++)
-      p = stpcpy (p, flip->var[i]->name) + 1;
-  }
+  info->output_buf = xmalloc (sizeof *info->output_buf * flip->var_cnt);
 
-  return create_case_sink (&flip_sink_class, info);
-}
+  flip->file = tmpfile ();
+  if (!flip->file)
+    msg (FE, _("Could not create temporary file for FLIP."));
 
-/* Open the FLIP sink. */
-static void
-flip_sink_open (struct case_sink *sink) 
-{
-  struct flip_sink_info *info = sink->aux;
+  /* Write variable names as first case. */
+  for (i = 0; i < flip->var_cnt; i++) 
+    st_bare_pad_copy (info->output_buf[i].s, flip->var[i]->name, 8);
+  if (fwrite (info->output_buf, sizeof *info->output_buf,
+              flip->var_cnt, flip->file) != (size_t) flip->var_cnt)
+    msg (FE, _("Error writing FLIP file: %s."), strerror (errno));
 
-  info->file = tmpfile ();
-  if (!info->file)
-    msg (FE, _("Could not create temporary file for FLIP."));
+  flip->case_cnt = 1;
+
+  return create_case_sink (&flip_sink_class, info);
 }
 
 /* Writes case C to the FLIP sink. */
 static void
-flip_sink_write (struct case_sink *sink, struct ccase *c)
+flip_sink_write (struct case_sink *sink, const struct ccase *c)
 {
   struct flip_sink_info *info = sink->aux;
   struct flip_pgm *flip = info->flip;
+  int i;
   
-  info->case_cnt++;
+  flip->case_cnt++;
 
-  if (flip->newnames)
+  if (flip->new_names != NULL)
     {
       struct varname *v = xmalloc (sizeof (struct varname));
       v->next = NULL;
-      if (flip->newnames->type == NUMERIC) 
+      if (flip->new_names->type == NUMERIC) 
         {
-          double f = c->data[flip->newnames->fv].f;
+          double f = c->data[flip->new_names->fv].f;
 
           if (f == SYSMIS)
             strcpy (v->name, "VSYSMIS");
@@ -321,8 +315,8 @@ flip_sink_write (struct case_sink *sink, struct ccase *c)
         }
       else
        {
-         int width = min (flip->newnames->width, 8);
-         memcpy (v->name, c->data[flip->newnames->fv].s, width);
+         int width = min (flip->new_names->width, 8);
+         memcpy (v->name, c->data[flip->new_names->fv].s, width);
          v->name[width] = 0;
        }
       
@@ -332,65 +326,23 @@ flip_sink_write (struct case_sink *sink, struct ccase *c)
        flip->new_names_tail->next = v;
       flip->new_names_tail = v;
     }
-  else
-    flip->case_count++;
-
 
   /* Write to external file. */
-  {
-    double *d = local_alloc (sizeof *d * flip->var_cnt);
-    int i;
-
-    for (i = 0; i < flip->var_cnt; i++)
-      if (flip->var[i]->type == NUMERIC)
-       d[i] = c->data[flip->var[i]->fv].f;
-      else
-       d[i] = SYSMIS;
+  for (i = 0; i < flip->var_cnt; i++)
+    if (flip->var[i]->type == NUMERIC)
+      info->output_buf[i].f = c->data[flip->var[i]->fv].f;
+    else
+      info->output_buf[i].f = SYSMIS;
          
-    if (fwrite (d, sizeof *d, flip->var_cnt, info->file) != (size_t) flip->var_cnt)
-      msg (FE, _("Error writing FLIP file: %s."),
-          strerror (errno));
-
-    local_free (d);
-  }
+  if (fwrite (info->output_buf, sizeof *info->output_buf,
+              flip->var_cnt, flip->file) != (size_t) flip->var_cnt)
+    msg (FE, _("Error writing FLIP file: %s."), strerror (errno));
 }
 
-/* Destroy sink's internal data. */
+/* Transposes the external file into a new file. */
 static void
-flip_sink_destroy (struct case_sink *sink)
+flip_file (struct flip_pgm *flip)
 {
-  struct flip_sink_info *info = sink->aux;
-  
-  free (info->old_names);
-  destroy_flip_pgm (info->flip);
-  free (info);
-}
-
-/* Convert the FLIP sink into a source. */
-static struct case_source *
-flip_sink_make_source (struct case_sink *sink)
-{
-  struct flip_sink_info *sink_info = sink->aux;
-  struct flip_source_info *source_info;
-
-  source_info = xmalloc (sizeof *source_info);
-  source_info->flip = sink_info->flip;
-  source_info->old_names = sink_info->old_names;
-  source_info->case_cnt = sink_info->case_cnt;
-  source_info->file = flip_file (sink_info);
-  fclose (sink_info->file);
-
-  free (sink_info);
-
-  return create_case_source (&flip_source_class, source_info);
-}
-
-/* Transposes the external file into a new file and returns a
-   pointer to the transposed file. */
-static FILE *
-flip_file (struct flip_sink_info *info)
-{
-  struct flip_pgm *flip = info->flip;
   size_t case_bytes;
   size_t case_capacity;
   size_t case_idx;
@@ -400,8 +352,8 @@ flip_file (struct flip_sink_info *info)
   /* Allocate memory for many cases. */
   case_bytes = flip->var_cnt * sizeof *input_buf;
   case_capacity = set_max_workspace / case_bytes;
-  if (case_capacity > info->case_cnt)
-    case_capacity = info->case_cnt;
+  if (case_capacity > flip->case_cnt * 2)
+    case_capacity = flip->case_cnt * 2;
   if (case_capacity < 2)
     case_capacity = 2;
   for (;;)
@@ -424,7 +376,7 @@ flip_file (struct flip_sink_info *info)
   case_capacity /= 2;
   output_buf = input_buf + flip->var_cnt * case_capacity;
 
-  input_file = info->file;
+  input_file = flip->file;
   if (fseek (input_file, 0, SEEK_SET) != 0)
     msg (FE, _("Error rewinding FLIP file: %s."), strerror (errno));
 
@@ -432,9 +384,9 @@ flip_file (struct flip_sink_info *info)
   if (output_file == NULL)
     msg (FE, _("Error creating FLIP source file."));
   
-  for (case_idx = 0; case_idx < info->case_cnt; )
+  for (case_idx = 0; case_idx < flip->case_cnt; )
     {
-      unsigned long read_cases = min (info->case_cnt - case_idx,
+      unsigned long read_cases = min (flip->case_cnt - case_idx,
                                       case_capacity);
       int i;
 
@@ -449,7 +401,7 @@ flip_file (struct flip_sink_info *info)
            output_buf[j] = input_buf[i + j * flip->var_cnt];
 
          if (fseek (output_file,
-                     sizeof *input_buf * (case_idx + i * info->case_cnt),
+                     sizeof *input_buf * (case_idx + i * flip->case_cnt),
                      SEEK_SET) != 0)
            msg (FE, _("Error seeking FLIP source file: %s."),
                       strerror (errno));
@@ -463,58 +415,79 @@ flip_file (struct flip_sink_info *info)
       case_idx += read_cases;
     }
 
+  fclose (input_file);
+  free (input_buf);
+  
   if (fseek (output_file, 0, SEEK_SET) != 0)
     msg (FE, _("Error rewind FLIP source file: %s."), strerror (errno));
+  flip->file = output_file;
+}
 
-  free (input_buf);
-  return output_file;
+/* Destroy sink's internal data. */
+static void
+flip_sink_destroy (struct case_sink *sink)
+{
+  struct flip_sink_info *info = sink->aux;
+
+  free (info->output_buf);
+  free (info);
 }
 
 /* FLIP sink class. */
 static const struct case_sink_class flip_sink_class = 
   {
     "FLIP",
-    flip_sink_open,
+    NULL,
     flip_sink_write,
     flip_sink_destroy,
-    flip_sink_make_source,
+    NULL,
   };
 
-/* Reads the FLIP stream and passes it to WRITE_CASE(). */
+/* Creates and returns a FLIP source based on PGM,
+   which should have already been used as a sink. */
+static struct case_source *
+flip_source_create (struct flip_pgm *pgm)
+{
+  return create_case_source (&flip_source_class, default_dict, pgm);
+}
+
+/* Reads the FLIP stream.  Copies each case into C and calls
+   WRITE_CASE passing WC_DATA. */
 static void
 flip_source_read (struct case_source *source,
+                  struct ccase *c,
                   write_case_func *write_case, write_case_data wc_data)
 {
-  struct flip_source_info *info = source->aux;
-  struct flip_pgm *flip = info->flip;
+  struct flip_pgm *flip = source->aux;
   int i;
-  char *p = info->old_names;
-      
+
   for (i = 0; i < flip->var_cnt; i++)
     {
-      st_bare_pad_copy (temp_case->data[0].s, p, 8);
-      p = strchr (p, 0) + 1;
-
-      if (fread (&temp_case->data[1], sizeof (double), info->case_cnt,
-                 info->file) != info->case_cnt)
-        msg (FE, _("Error reading FLIP source file: %s."),
-             strerror (errno));
+      if (fread (c->data, sizeof *c->data, flip->case_cnt,
+                 flip->file) != flip->case_cnt) 
+        {
+          if (ferror (flip->file))
+            msg (SE, _("Error reading FLIP temporary file: %s."),
+                 strerror (errno));
+          else if (feof (flip->file))
+            msg (SE, _("Unexpected end of file reading FLIP temporary file."));
+          else
+            assert (0);
+          break;
+        }
 
       if (!write_case (wc_data))
-        return;
+        break;
     }
 }
 
-/* Destroy source's internal data. */
+/* Destroy internal data in SOURCE. */
 static void
 flip_source_destroy (struct case_source *source)
 {
-  struct flip_source_info *info = source->aux;
+  struct flip_pgm *flip = source->aux;
 
-  destroy_flip_pgm (info->flip);
-  free (info->old_names);
-  fclose (info->file);
-  free (info);
+  destroy_flip_pgm (flip);
 }
 
 static const struct case_source_class flip_source_class = 
index 33a81ff30142366fc5c044ee1deadd86b8e10e1c..37e691a4a7ae20f0483de8a262f1851012ed1a0b 100644 (file)
@@ -36,50 +36,58 @@ struct fmt_desc formats[FMT_NUMBER_OF_FORMATS + 1] =
   {"",         -1, -1,  -1, -1,   -1, 0000, -1, -1},
 };
 
-const int translate_fmt[40] =
-  {
-    -1, FMT_A, FMT_AHEX, FMT_COMMA, FMT_DOLLAR, FMT_F, FMT_IB,
-    FMT_PIBHEX, FMT_P, FMT_PIB, FMT_PK, FMT_RB, FMT_RBHEX, -1,
-    -1, FMT_Z, FMT_N, FMT_E, -1, -1, FMT_DATE, FMT_TIME,
-    FMT_DATETIME, FMT_ADATE, FMT_JDATE, FMT_DTIME, FMT_WKDAY,
-    FMT_MONTH, FMT_MOYR, FMT_QYR, FMT_WKYR, FMT_PCT, FMT_DOT,
-    FMT_CCA, FMT_CCB, FMT_CCC, FMT_CCD, FMT_CCE, FMT_EDATE,
-    FMT_SDATE,
-  };
-
+/* Parses the alphabetic prefix of the current token as a format
+   specifier name.  Returns the corresponding format specifier
+   type if successful, or -1 on failure.  If ALLOW_XT is zero,
+   then X and T format specifiers are not allowed.  If CP is
+   nonzero, then *CP is set to the first non-alphabetic character
+   in the current token on success or to a null pointer on
+   failure. */
 int
 parse_format_specifier_name (const char **cp, int allow_xt)
 {
-  struct fmt_desc *f;
-  char *ep;
-  int x;
+  char *sp, *ep;
+  int idx;
 
-  ep = ds_value (&tokstr);
+  sp = ep = ds_value (&tokstr);
   while (isalpha ((unsigned char) *ep))
     ep++;
-  x = *ep;
-  *ep = 0;
-
-  for (f = formats; f->name[0]; f++)
-    if (!strcmp (f->name, ds_value (&tokstr)))
-      {
-       int indx = f - formats;
 
-       *ep = x;
-       if (cp)
-         *cp = ep;
+  if (sp != ep) 
+    {
+      /* Find format. */
+      for (idx = 0; idx < FMT_NUMBER_OF_FORMATS; idx++)
+        if (strlen (formats[idx].name) == ep - sp
+            && memcmp (formats[idx].name, sp, ep - sp))
+          break;
 
-       if (!allow_xt && (indx == FMT_T || indx == FMT_X))
-         {
-           msg (SE, _("X and T format specifiers not allowed here."));
-           return -1;
-         }
-       return indx;
-      }
+      /* Check format. */
+      if (idx < FMT_NUMBER_OF_FORMATS)
+        {
+          if (!allow_xt && (idx == FMT_T || idx == FMT_X)) 
+            {
+              msg (SE, _("X and T format specifiers not allowed here."));
+              idx = -1; 
+            }
+        }
+      else 
+        {
+          /* No match. */
+          msg (SE, _("%.*s is not a valid data format."),
+               (int) (ep - sp), ds_value (&tokstr));
+          idx = -1; 
+        }
+    }
+  else 
+    {
+      lex_error ("expecting data format");
+      idx = -1;
+    }
+      
+  if (cp != NULL)
+    *cp = ep;
 
-  msg (SE, _("%s is not a valid data format."), ds_value (&tokstr));
-  *ep = x;
-  return -1;
+  return idx;
 }
 
 /* Converts F to its string representation (for instance, "F8.2") and
@@ -96,6 +104,9 @@ fmt_to_string (const struct fmt_spec *f)
   return buf;
 }
 
+/* Checks whether SPEC is valid as an input format and returns
+   nonzero if so.  Otherwise, emits an error message and returns
+   zero. */
 int
 check_input_specifier (const struct fmt_spec *spec)
 {
@@ -135,6 +146,9 @@ check_input_specifier (const struct fmt_spec *spec)
   return 1;
 }
 
+/* Checks whether SPEC is valid as an output format and returns
+   nonzero if so.  Otherwise, emits an error message and returns
+   zero. */
 int
 check_output_specifier (const struct fmt_spec *spec)
 {
@@ -196,6 +210,8 @@ check_string_specifier (const struct fmt_spec *f, int min_len)
   return 1;
 }
 
+/* Converts input format specifier INPUT into output format
+   specifier OUTPUT. */
 void
 convert_fmt_ItoO (const struct fmt_spec *input, struct fmt_spec *output)
 {
@@ -288,6 +304,12 @@ convert_fmt_ItoO (const struct fmt_spec *input, struct fmt_spec *output)
     }
 }
 
+/* Parses a format specifier from the token stream and returns
+   nonzero only if successful.  Emits an error message on
+   failure.  Allows X and T format specifiers only if ALLOW_XT is
+   nonzero.  The caller should call check_input_specifier() or
+   check_output_specifier() on the parsed format as
+   necessary.  */
 int
 parse_format_specifier (struct fmt_spec *input, int allow_xt)
 {
@@ -340,6 +362,9 @@ parse_format_specifier (struct fmt_spec *input, int allow_xt)
   return 1;
 }
 
+/* Returns the width corresponding to the format specifier.  The
+   return value is the value of the `width' member of a `struct
+   variable' for such an input format. */
 int
 get_format_var_width (const struct fmt_spec *spec) 
 {
@@ -350,3 +375,16 @@ get_format_var_width (const struct fmt_spec *spec)
   else
     return 0;
 }
+
+/* Returns the PSPP format corresponding to the given SPSS
+   format. */
+int
+translate_fmt (int spss) 
+{
+  int type;
+  
+  for (type = 0; type < FMT_NUMBER_OF_FORMATS; type++)
+    if (formats[type].spss == spss)
+      return type;
+  return -1;
+}
index 7f4b5442799f1aaa731f3a3906bf63414c0d70f4..375b639f762c891184833556a78ef3ca3be12202 100644 (file)
@@ -71,9 +71,6 @@ struct fmt_spec
 /* Descriptions of all the display formats above. */
 extern struct fmt_desc formats[];
 
-/* Translates SPSS formats to PSPP formats. */
-extern const int translate_fmt[40];
-
 union value;
 
 /* Maximum length of formatted value, in character. */
@@ -88,6 +85,7 @@ void convert_fmt_ItoO (const struct fmt_spec *input, struct fmt_spec *output);
 int get_format_var_width (const struct fmt_spec *);
 int parse_string_as_format (const char *s, int len, const struct fmt_spec *fp,
                            int fc, union value *v);
+int translate_fmt (int spss);
 void data_out (char *s, const struct fmt_spec *fp, const union value *v);
 char *fmt_to_string (const struct fmt_spec *);
 void num_to_string (double v, char *s, int w, int d);
index d9f8660f94c7e49898c1e8c6db20cf05fbef94bc..66faf5ef027e2608914a0a9b2927bedbe5831ee7 100644 (file)
@@ -518,6 +518,8 @@ get_freq_comparator (int frq_sort, int var_type)
   return 0;
 }
 
+/* Returns nonzero iff the value in struct freq F is non-missing
+   for variable V. */
 static int
 not_missing (const void *f_, void *v_) 
 {
@@ -527,8 +529,9 @@ not_missing (const void *f_, void *v_)
   return !is_missing (&f->v, v);
 }
 
+/* Summarizes the frequency table data for variable V. */
 static void
-postprocess_freq_tab (struct variable * v)
+postprocess_freq_tab (struct variable *v)
 {
   hsh_compare_func *compare;
   struct freq_tab *ft;
@@ -575,6 +578,7 @@ postprocess_freq_tab (struct variable * v)
     }
 }
 
+/* Frees the frequency table for variable V. */
 static void
 cleanup_freq_tab (struct variable *v)
 {
index be1c09a2988443b90327f938853e69b4d9e5b5a3..e0ecc55d93c3c88c6e64080db8086c3639de76c4 100644 (file)
--- a/src/get.c
+++ b/src/get.c
 
 #include "debug-print.h"
 
+/* GET or IMPORT input program. */
+struct get_pgm 
+  {
+    struct file_handle *handle; /* File to GET or IMPORT from. */
+    size_t case_size;           /* Case size in bytes. */
+  };
+
 /* XSAVE transformation (and related SAVE, EXPORT procedures). */
 struct save_trns
   {
@@ -69,6 +76,7 @@ cmd_get (void)
 {
   struct file_handle *handle;
   struct dictionary *dict;
+  struct get_pgm *pgm;
   int options = GTSV_OPT_NONE;
 
   lex_match_id ("GET");
@@ -114,7 +122,10 @@ cmd_get (void)
   dict_destroy (default_dict);
   default_dict = dict;
 
-  vfm_source = create_case_source (&get_source_class, handle);
+  pgm = xmalloc (sizeof *pgm);
+  pgm->handle = handle;
+  pgm->case_size = dict_get_case_size (default_dict);
+  vfm_source = create_case_source (&get_source_class, default_dict, pgm);
 
   return CMD_SUCCESS;
 }
@@ -246,21 +257,24 @@ do_write_case (struct save_trns *t, struct ccase *c)
   sfm_write_case (t->f, t->case_buf, p - t->case_buf);
 }
 
+/* Writes case C to the system file specified on SAVE. */
 static int
-save_write_case_func (struct ccase * c, void *aux UNUSED)
+save_write_case_func (struct ccase *c, void *aux UNUSED)
 {
   do_write_case (aux, c);
   return 1;
 }
 
+/* Writes case C to the system file specified on XSAVE. */
 static int
-save_trns_proc (struct trns_header *h, struct ccase * c, int case_num UNUSED)
+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);
   return -1;
 }
 
+/* Frees a SAVE transformation. */
 static void
 save_trns_free (struct trns_header *pt)
 {
@@ -477,22 +491,24 @@ dump_dict_variables (struct dictionary * dict)
 static void
 get_source_destroy (struct case_source *source)
 {
-  struct file_handle *handle = source->aux;
+  struct get_pgm *pgm = source->aux;
 
   /* It is not necessary to destroy the dictionary because if we get
      to this point then the dictionary is default_dict. */
-  fh_close_handle (handle);
+  fh_close_handle (pgm->handle);
+  free (pgm);
 }
 
-/* Reads all the cases from the data file and passes them to
-   write_case(). */
+/* Reads all the cases from the data file into C and passes them
+   to WRITE_CASE one by one, passing WC_DATA. */
 static void
 get_source_read (struct case_source *source,
+                 struct ccase *c,
                  write_case_func *write_case, write_case_data wc_data)
 {
-  struct file_handle *handle = source->aux;
+  struct get_pgm *pgm = source->aux;
 
-  while (sfm_read_case (handle, temp_case->data, default_dict)
+  while (sfm_read_case (pgm->handle, c->data, default_dict)
         && write_case (wc_data))
     ;
 }
@@ -848,10 +864,7 @@ cmd_match_files (void)
 
      FIXME: For merging large numbers of files (more than 10?) a
      better algorithm would use a heap for finding minimum
-     values, or replacement selection, as described by Knuth in
-     _Art of Computer Programming, Vol. 3_.  The SORT CASES
-     procedure does this, and perhaps some of its code could be
-     adapted. */
+     values. */
 
   if (!(seen & 2))
     discard_variables ();
@@ -894,7 +907,7 @@ mtf_processing_finish (void *aux UNUSED)
   }
   
   while (mtf_head && mtf_head->type == MTF_FILE)
-    if (!mtf_processing (temp_case, NULL))
+    if (!mtf_processing (NULL, NULL))
       break;
 }
 
@@ -1006,20 +1019,22 @@ mtf_read_nonactive_records (void *aux UNUSED)
            iter = iter->next;
        }
       else
-       {
-         iter->input = temp_case->data;
-         iter = iter->next;
-       }
+        iter = iter->next;
     }
 }
 
 /* Compare the BY variables for files A and B; return -1 if A < B, 0
    if A == B, 1 if A > B. */
 static inline int
-mtf_compare_BY_values (struct mtf_file *a, struct mtf_file *b)
+mtf_compare_BY_values (struct mtf_file *a, struct mtf_file *b,
+                       struct ccase *c)
 {
+  union value *a_input, *b_input;
   int i;
-  
+
+  assert ((a == NULL) + (b == NULL) + (c == NULL) <= 1);
+  a_input = a->input != NULL ? a->input : c->data;
+  b_input = b->input != NULL ? b->input : c->data;
   for (i = 0; i < mtf_n_by; i++)
     {
       assert (a->by[i]->type == b->by[i]->type);
@@ -1027,8 +1042,8 @@ mtf_compare_BY_values (struct mtf_file *a, struct mtf_file *b)
       
       if (a->by[i]->type == NUMERIC)
        {
-         double af = a->input[a->by[i]->fv].f;
-         double bf = b->input[b->by[i]->fv].f;
+         double af = a_input[a->by[i]->fv].f;
+         double bf = b_input[b->by[i]->fv].f;
 
          if (af < bf)
            return -1;
@@ -1040,8 +1055,8 @@ mtf_compare_BY_values (struct mtf_file *a, struct mtf_file *b)
          int result;
          
          assert (a->by[i]->type == ALPHA);
-         result = memcmp (a->input[a->by[i]->fv].s,
-                          b->input[b->by[i]->fv].s,
+         result = memcmp (a_input[a->by[i]->fv].s,
+                          b_input[b->by[i]->fv].s,
                           a->by[i]->width);
          if (result < 0)
            return -1;
@@ -1054,7 +1069,7 @@ mtf_compare_BY_values (struct mtf_file *a, struct mtf_file *b)
 
 /* Perform one iteration of steps 3...7 above. */
 static int
-mtf_processing (struct ccase *c UNUSED, void *aux UNUSED)
+mtf_processing (struct ccase *c, void *aux UNUSED)
 {
   /* List of files with minimum BY values. */
   struct mtf_file *min_head, *min_tail;
@@ -1084,7 +1099,7 @@ mtf_processing (struct ccase *c UNUSED, void *aux UNUSED)
       max_head = max_tail = NULL;
       for (iter = mtf_head->next; iter && iter->type == MTF_FILE;
           iter = iter->next)
-       switch (mtf_compare_BY_values (min_head, iter))
+       switch (mtf_compare_BY_values (min_head, iter, c))
          {
          case -1:
            if (max_head)
@@ -1129,7 +1144,7 @@ mtf_processing (struct ccase *c UNUSED, void *aux UNUSED)
            advance = 0;
 
        again:
-         switch (mtf_compare_BY_values (min_head, iter))
+         switch (mtf_compare_BY_values (min_head, iter, c))
            {
            case -1:
              if (max_head)
@@ -1170,26 +1185,20 @@ mtf_processing (struct ccase *c UNUSED, void *aux UNUSED)
          for (i = 0; i < dict_get_var_cnt (iter->dict); i++)
            {
              struct variable *v = dict_get_var (iter->dict, i);
+              union value *record;
          
              if (mtf_seq_nums[v->p.mtf.master->index] == mtf_seq_num)
                continue;
               mtf_seq_nums[v->p.mtf.master->index] = mtf_seq_num;
 
-#if 0
-             printf ("%s/%s: dest-fv=%d, src-fv=%d\n",
-                     fh_handle_name (iter->handle),
-                     v->name,
-                     v->p.mtf.master->fv, v->fv);
-#endif
+              record = iter->input != NULL ? iter->input : c->data;
+
+              assert (v->type == NUMERIC || v->type == ALPHA);
              if (v->type == NUMERIC)
-               compaction_case->data[v->p.mtf.master->fv].f
-                 = iter->input[v->fv].f;
+               compaction_case->data[v->p.mtf.master->fv].f = record[v->fv].f;
              else
-               {
-                 assert (v->type == ALPHA);
-                 memcpy (compaction_case->data[v->p.mtf.master->fv].s,
-                         iter->input[v->fv].s, v->width);
-               }
+                memcpy (compaction_case->data[v->p.mtf.master->fv].s,
+                        record[v->fv].s, v->width);
            }
        }
 
@@ -1226,7 +1235,7 @@ mtf_processing (struct ccase *c UNUSED, void *aux UNUSED)
        }
 
       /* 6. Write the output record. */
-      process_active_file_output_case ();
+      process_active_file_output_case (compaction_case);
 
       /* 7. Read another record from each input file FILE and TABLE
         that we stored values from above.  If we come to the end of
@@ -1338,6 +1347,7 @@ cmd_import (void)
 {
   struct file_handle *handle = NULL;
   struct dictionary *dict;
+  struct get_pgm *pgm;
   int options = GTSV_OPT_NONE;
   int type;
 
@@ -1411,7 +1421,10 @@ cmd_import (void)
   dict_destroy (default_dict);
   default_dict = dict;
 
-  vfm_source = create_case_source (&import_source_class, handle);
+  pgm = xmalloc (sizeof *pgm);
+  pgm->handle = handle;
+  pgm->case_size = dict_get_case_size (default_dict);
+  vfm_source = create_case_source (&import_source_class, default_dict, pgm);
 
   return CMD_SUCCESS;
 }
@@ -1420,10 +1433,12 @@ cmd_import (void)
    write_case(). */
 static void
 import_source_read (struct case_source *source,
+                    struct ccase *c,
                     write_case_func *write_case, write_case_data wc_data)
 {
-  struct file_handle *handle = source->aux;
-  while (pfm_read_case (handle, temp_case->data, default_dict))
+  struct get_pgm *pgm = source->aux;
+  
+  while (pfm_read_case (pgm->handle, c->data, default_dict))
     if (!write_case (wc_data))
       break;
 }
@@ -1503,6 +1518,7 @@ cmd_export (void)
   return CMD_SUCCESS;
 }
 
+/* Writes case C to the EXPORT file. */
 static int
 export_write_case_func (struct ccase *c, void *aux)
 {
index 5bf5600f25189eb2be5d7c5b9c5e62e4ad06d02b..60da1fffd3b2e54e2a6995de86fafcc833b14c01 100644 (file)
@@ -100,8 +100,6 @@ extern void stifle_history ();
 struct dictionary *default_dict;
 struct expression *process_if_expr;
 
-struct ccase *temp_case;
-
 struct trns_header **t_trns;
 int n_trns;
 int m_trns;
index 697d7f5ba59726120f77492504eeeb603dc35c83..dc08f346a9704b7d4dc60f593aa40f1195f5a417 100644 (file)
@@ -50,6 +50,7 @@ struct input_program_pgm
   {
     enum value_init_type *init; /* How to initialize each `union value'. */
     size_t init_cnt;            /* Number of elements in inp_init. */
+    size_t case_size;           /* Size of case in bytes. */
   };
 
 static trns_proc_func end_case_trns_proc, reread_trns_proc, end_file_trns_proc;
@@ -62,7 +63,10 @@ cmd_input_program (void)
   lex_match_id ("PROGRAM");
   discard_variables ();
 
-  vfm_source = create_case_source (&input_program_source_class, NULL);
+  /* FIXME: we shouldn't do this here, but I'm afraid that other
+     code will check the class of vfm_source. */
+  vfm_source = create_case_source (&input_program_source_class,
+                                   default_dict, NULL);
 
   return lex_end_of_command ();
 }
@@ -91,7 +95,7 @@ cmd_end_input_program (void)
      ordinary transformations. */
   f_trns = n_trns;
 
-  /* Figure out how to initialize temp_case. */
+  /* Figure out how to initialize each input case. */
   inp = xmalloc (sizeof *inp);
   inp->init_cnt = dict_get_next_value_idx (default_dict);
   inp->init = xmalloc (inp->init_cnt * sizeof *inp->init);
@@ -111,16 +115,20 @@ cmd_end_input_program (void)
     }
   for (i = 0; i < inp->init_cnt; i++)
     assert (inp->init[i] != -1);
+  inp->case_size = dict_get_case_size (default_dict);
 
   /* Put inp into vfm_source for later use. */
   vfm_source->aux = inp;
 
+  /* FIXME: we should use create_case_source() here. */
+  vfm_source->value_cnt = dict_get_next_value_idx (default_dict);
+
   return lex_end_of_command ();
 }
 
-/* Initializes temp_case.  Called before the first case is read. */
+/* Initializes case C.  Called before the first case is read. */
 static void
-init_case (struct input_program_pgm *inp)
+init_case (const struct input_program_pgm *inp, struct ccase *c)
 {
   size_t i;
 
@@ -128,23 +136,23 @@ init_case (struct input_program_pgm *inp)
     switch (inp->init[i]) 
       {
       case INP_NUMERIC | INP_INIT_ONCE:
-        temp_case->data[i].f = 0.0;
+        c->data[i].f = 0.0;
         break;
       case INP_NUMERIC | INP_REINIT:
-        temp_case->data[i].f = SYSMIS;
+        c->data[i].f = SYSMIS;
         break;
       case INP_STRING | INP_INIT_ONCE:
       case INP_STRING | INP_REINIT:
-        memset (temp_case->data[i].s, ' ', sizeof temp_case->data[i].s);
+        memset (c->data[i].s, ' ', sizeof c->data[i].s);
         break;
       default:
         assert (0);
       }
 }
 
-/* Clears temp_case.  Called between reading successive records. */
+/* Clears case C.  Called between reading successive records. */
 static void
-clear_case (struct input_program_pgm *inp)
+clear_case (const struct input_program_pgm *inp, struct ccase *c)
 {
   size_t i;
 
@@ -154,12 +162,12 @@ clear_case (struct input_program_pgm *inp)
       case INP_NUMERIC | INP_INIT_ONCE:
         break;
       case INP_NUMERIC | INP_REINIT:
-        temp_case->data[i].f = SYSMIS;
+        c->data[i].f = SYSMIS;
         break;
       case INP_STRING | INP_INIT_ONCE:
         break;
       case INP_STRING | INP_REINIT:
-        memset (temp_case->data[i].s, ' ', sizeof temp_case->data[i].s);
+        memset (c->data[i].s, ' ', sizeof c->data[i].s);
         break;
       default:
         assert (0);
@@ -172,6 +180,7 @@ clear_case (struct input_program_pgm *inp)
    return value is the index of the transformation to go to next. */
 static void
 input_program_source_read (struct case_source *source,
+                           struct ccase *c,
                            write_case_func *write_case,
                            write_case_data wc_data)
 {
@@ -190,56 +199,43 @@ input_program_source_read (struct case_source *source,
   int cases_written = 0;
 
   assert (inp != NULL);
-  
+
   /* Figure end_case. */
   for (i = 0; i < f_trns; i++)
     if (t_trns[i]->proc == end_case_trns_proc)
       end_case = 1;
 
-  /* FIXME: This code should not be necessary.  It is an ugly
-     kluge. */
+  /* FIXME: This is an ugly kluge. */
   for (i = 0; i < f_trns; i++)
     if (t_trns[i]->proc == repeating_data_trns_proc)
       repeating_data_set_write_case (t_trns[i], write_case, wc_data);
 
-  init_case (inp);
+  init_case (inp, c);
   for (;;)
     {
-      /* Index of current transformation. */
-      int i;
-
-      /* Return value of last-called transformation. */
-      int code;
-
-      debug_printf (("input-program: "));
-
       /* Perform transformations on `blank' case. */
-      for (i = 0; i < f_trns;)
+      for (i = 0; i < f_trns; )
        {
-#if DEBUGGING
-         printf ("/%d", i);
-         if (t_trns[i]->proc == end_case_trns_proc)
-           printf ("\n");
-#endif
+          int code;     /* Return value of last-called transformation. */
 
           if (t_trns[i]->proc == end_case_trns_proc) 
             {
               cases_written++;
               if (!write_case (wc_data))
-                return;
-              clear_case (inp);
+                goto done;
+              clear_case (inp, c);
               i++;
               continue;
             }
 
-         code = t_trns[i]->proc (t_trns[i], temp_case, cases_written + 1);
+         code = t_trns[i]->proc (t_trns[i], c, cases_written + 1);
          switch (code)
            {
            case -1:
              i++;
              break;
            case -2:
-             return;
+             goto done;
            case -3:
              goto next_case;
            default:
@@ -248,22 +244,22 @@ input_program_source_read (struct case_source *source,
            }
        }
 
-#if DEBUGGING
-      if (!end_case)
-       printf ("\n");
-#endif
-
       /* Write the case if appropriate. */
-      if (!end_case)
-       if (!write_case (wc_data))
-         return;
+      if (!end_case) 
+        {
+          cases_written++;
+          if (!write_case (wc_data))
+            break;
+        }
 
       /* Blank out the case for the next iteration. */
     next_case:
-      clear_case (inp);
+      clear_case (inp, c);
     }
+ done: ;
 }
 
+/* Destroys an INPUT PROGRAM source. */
 static void
 input_program_source_destroy (struct case_source *source)
 {
@@ -309,6 +305,8 @@ cmd_end_case (void)
   return lex_end_of_command ();
 }
 
+/* Should never be called, because this is handled in
+   input_program_source_read(). */
 int
 end_case_trns_proc (struct trns_header *t UNUSED, struct ccase * c UNUSED,
                     int case_num UNUSED)
@@ -393,6 +391,7 @@ cmd_reread (void)
   return CMD_SUCCESS;
 }
 
+/* Executes a REREAD transformation. */
 static int
 reread_trns_proc (struct trns_header * pt, struct ccase * c,
                   int case_num)
@@ -418,6 +417,7 @@ reread_trns_proc (struct trns_header * pt, struct ccase * c,
   return -1;
 }
 
+/* Frees a REREAD transformation. */
 static void
 reread_trns_free (struct trns_header * t)
 {
@@ -448,12 +448,10 @@ cmd_end_file (void)
   return lex_end_of_command ();
 }
 
+/* Executes an END FILE transformation. */
 static int
 end_file_trns_proc (struct trns_header * t UNUSED, struct ccase * c UNUSED,
                     int case_num UNUSED)
 {
-#if DEBUGGING
-  printf ("END FILE\n");
-#endif
   return -2;
 }
index 1989a0748a6964a10593e0639eda0b79993a6c74..b0c836bcc784fe832c19bc35306d3158fec258d2 100644 (file)
@@ -32,7 +32,6 @@
 
 #include "debug-print.h"
 
-/* *INDENT-OFF* */
 /* LOOP strategy:
 
    Each loop causes 3 different transformations to be output.  The
    transformation to -1.  This ensures that the pass number is set to
    -1 every time the loop is encountered, before the first iteration.
 
-   The second transformation increments the pass number.  If there is
-   no indexing or test clause on either LOOP or END LOOP, then the
-   pass number is checked against MXLOOPS and control may pass out of
-   the loop; otherwise the indexing or test clause(s) on LOOP are
-   checked, and again control may pass out of the loop.
+   The second transformation increments the pass number.  If
+   there is no indexing or test clause on either LOOP or END
+   LOOP, then the pass number is checked against MXLOOPS and
+   control may pass out of the loop.  Otherwise the indexing or
+   test clause(s) on LOOP are checked, and again control may pass
+   out of the loop.
 
-   After the second transformation the body of the loop is executed.
+   After the second transformation the body of the loop is
+   executed.
 
    The last transformation checks the test clause if present and
-   either jumps back up to the second transformation or terminates the
-   loop.
-
-   Flow of control: (The characters ^V<> represents arrows.)
-
-     1. LOOP (sets pass # to -1)
-        V
-        V
-   >>2. LOOP (increment pass number)
-   ^         (test optional indexing clause)
-   ^         (test optional IF clause)
-   ^    if we need another trip     if we're done with the loop>>V
-   ^     V                                                       V
-   ^     V                                                         V
-   ^ *. execute loop body                                          V
-   ^    .                                                          V
-   ^    .   (any number of transformations)                        V
-   ^    .                                                          V
-   ^                                                             V
-   ^ 3. END LOOP (test optional IF clause)                         V
-   ^<<<<if we need another trip     if we're done with the loop>>V
-                                                                V
-                                                                V
-     *. transformations after loop body<<<<<<<<<<<<<<<<<<<<<<<<<<<
+   either jumps back up to the second transformation or
+   terminates the loop.
 
+   Flow of control:
+
+   1. LOOP.  Sets pass number to -1 and continues to next
+      transformation.
+
+   2. LOOP.  Increments pass number.  Tests optional indexing
+      clause and optional IF clause.  If we're done with the
+      loop, we jump to the transformation just after LOOP
+      transformation 3.
+
+      Otherwise, we continue through the transformations in the
+      loop body.
+
+   3. END LOOP.  We test the optional IF clause.  If we need to
+      make another pass through the loop, we jump to LOOP
+      transformation 2.
+
+      Otherwise, we continue with the transformation jump after
+      the loop.
  */
-/* *INDENT-ON* */
 
 /* Types of limits on loop execution. */
 enum
index b47112a1c451eef4d55b0a55c00f1a951c17854e..98fcd4ff2c584e4b2841470a0521af622a0cea7a 100644 (file)
@@ -126,7 +126,7 @@ struct matrix_data_pgm
     int contents[EOC * 3 + 1];  /* Contents. */
     int n_contents;             /* Number of entries. */
 
-    
+    /* Continuous variables. */
     int n_continuous;           /* Number of continuous variables. */
     int first_continuous;       /* Index into default_dict.var of
                                    first continuous variable. */
@@ -786,6 +786,7 @@ enum matrix_token_type
     MSTR               /* String. */
   };
 
+/* A MATRIX DATA parsing token. */
 struct matrix_token
   {
     enum matrix_token_type type; 
@@ -1009,9 +1010,10 @@ static double *split_values;
 
 static int nr_read_splits (struct matrix_data_pgm *, int compare);
 static int nr_read_factors (struct matrix_data_pgm *, int cell);
-static void nr_output_data (struct matrix_data_pgm *,
+static void nr_output_data (struct matrix_data_pgm *, struct ccase *,
                             write_case_func *, write_case_data);
 static void matrix_data_read_without_rowtype (struct case_source *source,
+                                              struct ccase *,
                                               write_case_func *,
                                               write_case_data);
 
@@ -1028,7 +1030,7 @@ read_matrices_without_rowtype (struct matrix_data_pgm *mx)
   max_cell_index = 0;
 
   vfm_source = create_case_source (&matrix_data_without_rowtype_source_class,
-                                   mx);
+                                   default_dict, mx);
   
   procedure (NULL, NULL, NULL, NULL);
 
@@ -1201,6 +1203,7 @@ nr_read_data_lines (struct matrix_data_pgm *mx,
    writes them to the output file.  Returns success. */
 static void
 matrix_data_read_without_rowtype (struct case_source *source,
+                                  struct ccase *c,
                                   write_case_func *write_case,
                                   write_case_data wc_data)
 {
@@ -1287,7 +1290,7 @@ matrix_data_read_without_rowtype (struct case_source *source,
          }
        }
 
-      nr_output_data (mx, write_case, wc_data);
+      nr_output_data (mx, c, write_case, wc_data);
 
       if (dict_get_split_cnt (default_dict) == 0
           || !another_token (mx->data_file))
@@ -1405,16 +1408,17 @@ nr_read_factors (struct matrix_data_pgm *mx, int cell)
    CP to the active file. */
 static void
 dump_cell_content (struct matrix_data_pgm *mx, int content, double *cp,
+                   struct ccase *c,
                    write_case_func *write_case, write_case_data wc_data)
 {
   int type = content_type[content];
 
   {
-    st_bare_pad_copy (temp_case->data[mx->rowtype_->fv].s,
+    st_bare_pad_copy (c->data[mx->rowtype_->fv].s,
                      content_names[content], 8);
     
     if (type != 1)
-      memset (&temp_case->data[mx->varname_->fv].s, ' ', 8);
+      memset (&c->data[mx->varname_->fv].s, ' ', 8);
   }
 
   {
@@ -1428,11 +1432,11 @@ dump_cell_content (struct matrix_data_pgm *mx, int content, double *cp,
        for (j = 0; j < mx->n_continuous; j++)
          {
             int fv = dict_get_var (default_dict, mx->first_continuous + j)->fv;
-           temp_case->data[fv].f = *cp;
+           c->data[fv].f = *cp;
            cp++;
          }
        if (type == 1)
-         st_bare_pad_copy (temp_case->data[mx->varname_->fv].s,
+         st_bare_pad_copy (c->data[mx->varname_->fv].s,
                             dict_get_var (default_dict,
                                           mx->first_continuous + i)->name,
                            8);
@@ -1443,7 +1447,7 @@ dump_cell_content (struct matrix_data_pgm *mx, int content, double *cp,
 
 /* Finally dump out everything from nr_data[] to the output file. */
 static void
-nr_output_data (struct matrix_data_pgm *mx,
+nr_output_data (struct matrix_data_pgm *mx, struct ccase *c,
                 write_case_func *write_case, write_case_data wc_data)
 {
   {
@@ -1454,7 +1458,7 @@ nr_output_data (struct matrix_data_pgm *mx,
     split_cnt = dict_get_split_cnt (default_dict);
     split = dict_get_split_vars (default_dict);
     for (i = 0; i < split_cnt; i++)
-      temp_case->data[split[i]->fv].f = split_values[i];
+      c->data[split[i]->fv].f = split_values[i];
   }
 
   if (mx->n_factors)
@@ -1468,7 +1472,7 @@ nr_output_data (struct matrix_data_pgm *mx,
 
            for (factor = 0; factor < mx->n_factors; factor++)
              {
-               temp_case->data[mx->factors[factor]->fv].f
+               c->data[mx->factors[factor]->fv].f
                  = nr_factor_values[factor + cell * mx->n_factors];
                debug_printf (("f:%s ", mx->factors[factor]->name));
              }
@@ -1484,7 +1488,7 @@ nr_output_data (struct matrix_data_pgm *mx,
                          && nr_data[content][cell] != NULL);
 
                  dump_cell_content (mx, content, nr_data[content][cell],
-                                     write_case, wc_data);
+                                     c, write_case, wc_data);
                }
          }
        }
@@ -1497,13 +1501,13 @@ nr_output_data (struct matrix_data_pgm *mx,
       int factor;
 
       for (factor = 0; factor < mx->n_factors; factor++)
-       temp_case->data[mx->factors[factor]->fv].f = SYSMIS;
+       c->data[mx->factors[factor]->fv].f = SYSMIS;
     }
     
     for (content = 0; content <= PROX; content++)
       if (!mx->is_per_factor[content] && nr_data[content] != NULL)
        dump_cell_content (mx, content, nr_data[content][0],
-                           write_case, wc_data);
+                           c, write_case, wc_data);
   }
 }
 \f
@@ -1528,12 +1532,15 @@ struct factor_data *wr_data;
 struct factor_data *wr_current;
 
 static int wr_read_splits (struct matrix_data_pgm *,
+                           struct ccase *,
                            write_case_func *, write_case_data);
-static int wr_output_data (struct matrix_data_pgm *, write_case_func *, write_case_data);
+static int wr_output_data (struct matrix_data_pgm *,
+                           struct ccase *, write_case_func *, write_case_data);
 static int wr_read_rowtype (const struct matrix_token *, struct file_handle *);
 static int wr_read_factors (struct matrix_data_pgm *);
 static int wr_read_indeps (struct matrix_data_pgm *);
 static void matrix_data_read_with_rowtype (struct case_source *,
+                                           struct ccase *,
                                            write_case_func *,
                                            write_case_data);
 
@@ -1546,7 +1553,8 @@ read_matrices_with_rowtype (struct matrix_data_pgm *mx)
   split_values = NULL;
   mx->cells = 0;
 
-  vfm_source = create_case_source (&matrix_data_with_rowtype_source_class, mx);
+  vfm_source = create_case_source (&matrix_data_with_rowtype_source_class,
+                                   default_dict, mx);
   
   procedure (NULL, NULL, NULL, NULL);
 
@@ -1557,6 +1565,7 @@ read_matrices_with_rowtype (struct matrix_data_pgm *mx)
 /* Read from the data file and write it to the active file. */
 static void
 matrix_data_read_with_rowtype (struct case_source *source,
+                               struct ccase *c,
                                write_case_func *write_case,
                                write_case_data wc_data)
 {
@@ -1564,7 +1573,7 @@ matrix_data_read_with_rowtype (struct case_source *source,
 
   do
     {
-      if (!wr_read_splits (mx, write_case, wc_data))
+      if (!wr_read_splits (mx, c, write_case, wc_data))
        return;
 
       if (!wr_read_factors (mx))
@@ -1575,13 +1584,14 @@ matrix_data_read_with_rowtype (struct case_source *source,
     }
   while (another_token (mx->data_file));
 
-  wr_output_data (mx, write_case, wc_data);
+  wr_output_data (mx, c, write_case, wc_data);
 }
 
 /* Read the split file variables.  If they differ from the previous
    set of split variables then output the data.  Returns success. */
 static int 
 wr_read_splits (struct matrix_data_pgm *mx,
+                struct ccase *c,
                 write_case_func *write_case, write_case_data wc_data)
 {
   int compare;
@@ -1617,7 +1627,7 @@ wr_read_splits (struct matrix_data_pgm *mx,
 
        if (compare && split_values[i] != token.number && !different)
          {
-           if (!wr_output_data (mx, write_case, wc_data))
+           if (!wr_output_data (mx, c, write_case, wc_data))
              return 0;
            different = 1;
            mx->cells = 0;
@@ -1669,6 +1679,7 @@ compare_factors (const void *a_, const void *b_, void *mx_)
    file. */
 static int 
 wr_output_data (struct matrix_data_pgm *mx,
+                struct ccase *c,
                 write_case_func *write_case, write_case_data wc_data)
 {
   {
@@ -1679,7 +1690,7 @@ wr_output_data (struct matrix_data_pgm *mx,
     split_cnt = dict_get_split_cnt (default_dict);
     split = dict_get_split_vars (default_dict);
     for (i = 0; i < split_cnt; i++)
-      temp_case->data[split[i]->fv].f = split_values[i];
+      c->data[split[i]->fv].f = split_values[i];
   }
 
   /* Sort the wr_data list. */
@@ -1714,7 +1725,7 @@ wr_output_data (struct matrix_data_pgm *mx,
 
          for (factor = 0; factor < mx->n_factors; factor++)
            {
-             temp_case->data[mx->factors[factor]->fv].f
+             c->data[mx->factors[factor]->fv].f
                = iter->factors[factor];
              debug_printf (("f:%s ", factors[factor]->name));
            }
@@ -1749,7 +1760,7 @@ wr_output_data (struct matrix_data_pgm *mx,
              fill_matrix (mx, content, iter->data[content]);
 
              dump_cell_content (mx, content, iter->data[content],
-                                 write_case, wc_data);
+                                 c, write_case, wc_data);
            }
        }
       }
index b587fbcafa937f3ad183df9f65d7f4b27c8a5b02..8f19f1ba8779df7343b32b491f0861ea7c128313 100644 (file)
@@ -617,11 +617,9 @@ static int
 convert_format (struct file_handle *h, int fmt[3], struct fmt_spec *v,
                struct variable *vv)
 {
-  if (fmt[0] < 0
-      || (size_t) fmt[0] >= sizeof translate_fmt / sizeof *translate_fmt)
+  v->type = translate_fmt (fmt[0]);
+  if (v->type == -1)
     lose ((h, _("%s: Bad format specifier byte (%d)."), vv->name, fmt[0]));
-
-  v->type = translate_fmt[fmt[0]];
   v->w = fmt[1];
   v->d = fmt[2];
 
index b911f8ccdd6ec08588b6a6996aac77cd8dbea060..196e7120cec4f0118cda4331f8bc74b90f11bdb7 100644 (file)
@@ -2575,7 +2575,7 @@ text (struct outp_driver *this, struct outp_text *t, int draw)
       char_name = local_char_name;
       if (ext->current->font->ligatures && *cp == 'f')
        {
-         int lig;
+         int lig = 0;
           char_name = NULL;
 
          if (cp < end - 1)
@@ -2604,7 +2604,7 @@ text (struct outp_driver *this, struct outp_text *t, int draw)
              }
          if ((lig & ext->current->font->ligatures) == 0)
            {
-             local_char_name[0] = *cp++;       /* 'f' */
+             local_char_name[0] = *cp; /* 'f' */
              char_name = local_char_name;
            }
        }
index 95dae157993696e53cb1a166833a762c224da94f..17c0eab2376c9ba146af38c28c3448f796e06e21 100644 (file)
@@ -17,6 +17,8 @@
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
    02111-1307, USA. */
 
+/* FIXME: seems like a lot of code duplication with data-list.c. */
+
 #include <config.h>
 #include <assert.h>
 #include <stdlib.h>
index 53a8e23ad5a943516529c290ab31a3a0d45181c8..ee164b9c7c7889ea04bd6ecf12f941bfc9b5daaf 100644 (file)
@@ -34,6 +34,7 @@
 \f
 /* Definitions. */
 
+/* Type of source value for RECODE. */
 enum
   {
     RCD_END,                   /* sentinel value */
index ce5d18d8131de8a12e0fc5de27f5508356ec0e59..3f887935598ef8d7cbd7d723208563c7702ae45b 100644 (file)
@@ -118,6 +118,7 @@ cmd_sample (void)
   return lex_end_of_command ();
 }
 
+/* Executes a SAMPLE transformation. */
 static int
 sample_trns_proc (struct trns_header * trns, struct ccase *c UNUSED,
                   int case_num UNUSED)
index c14e11acb7da3e770a5bb9f39beb8f5c9a51d931..03b6d5ab55c04805cb7b825c350ae4ce1d79072b 100644 (file)
@@ -895,12 +895,10 @@ lossage:
 static int
 parse_format_spec (struct file_handle *h, int32 s, struct fmt_spec *v, struct variable *vv)
 {
-  if ((size_t) ((s >> 16) & 0xff)
-      >= sizeof translate_fmt / sizeof *translate_fmt)
+  v->type = translate_fmt ((s >> 16) & 0xff);
+  if (v->type == -1)
     lose ((ME, _("%s: Bad format specifier byte (%d)."),
           h->fn, (s >> 16) & 0xff));
-  
-  v->type = translate_fmt[(s >> 16) & 0xff];
   v->w = (s >> 8) & 0xff;
   v->d = s & 0xff;
 
index 99d850ad9345c354de71b39b3f33d75b857e3a9a..b00c492fe6c88f59b55d2d98435bdd071213b9c0 100644 (file)
@@ -141,6 +141,7 @@ parse_sort (void)
   return NULL;
 }
 
+/* Destroys a SORT CASES program. */
 void
 destroy_sort_cases_pgm (struct sort_cases_pgm *scp) 
 {
@@ -169,6 +170,8 @@ destroy_sort_cases_pgm (struct sort_cases_pgm *scp)
 int
 sort_cases (struct sort_cases_pgm *scp, int separate)
 {
+  scp->case_size = sizeof (union value) * compaction_nval;
+
   /* Not sure this is necessary but it's good to be safe. */
   if (separate && case_source_is_class (vfm_source, &sort_source_class))
     procedure (NULL, NULL, NULL, NULL);
@@ -192,6 +195,7 @@ sort_cases (struct sort_cases_pgm *scp, int separate)
   return 0;
 }
 \f
+/* Results of an internal sort. */
 struct internal_sort 
   {
     struct case_list **results;
@@ -261,6 +265,7 @@ do_internal_sort (struct sort_cases_pgm *scp, int separate)
   return NULL;
 }
 
+/* Destroys an internal sort result. */
 static void
 destroy_internal_sort (struct internal_sort *isrt) 
 {
@@ -320,18 +325,19 @@ compare_initial_runs (const void *a_, const void *b_, void *aux UNUSED)
   return a->case_cnt > b->case_cnt ? -1 : a->case_cnt <b->case_cnt;
 }
 
+/* Results of an external sort. */
 struct external_sort 
   {
     struct sort_cases_pgm *scp;       /* SORT CASES info. */
     struct initial_run *initial_runs; /* Array of initial runs. */
     size_t run_cnt, run_cap;          /* Number of runs, allocated capacity. */
     char *temp_dir;                   /* Temporary file directory name. */
+    char *temp_name;                  /* Name of a temporary file. */
     int next_file_idx;                /* Lowest unused file index. */
-    size_t case_size;                 /* Number of bytes in case. */
   };
 
 /* Prototypes for helper functions. */
-static void sort_sink_write (struct case_sink *, struct ccase *);
+static void sort_sink_write (struct case_sink *, const struct ccase *);
 static int write_initial_runs (struct external_sort *, int separate);
 static int init_external_sort (struct external_sort *);
 static int merge (struct external_sort *);
@@ -351,7 +357,6 @@ 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))
@@ -386,6 +391,8 @@ destroy_external_sort (struct external_sort *xsrt)
       for (i = 0; i < xsrt->run_cnt; i++)
         remove_temp_file (xsrt, xsrt->initial_runs[i].file_idx);
       rmdir_temp_dir (xsrt);
+      free (xsrt->temp_dir);
+      free (xsrt->temp_name);
       free (xsrt->initial_runs);
       free (xsrt);
     }
@@ -467,13 +474,16 @@ init_external_sort (struct external_sort *xsrt)
 
   /* Temporary directory. */
   xsrt->temp_dir = make_temp_dir ();
+  xsrt->temp_name = NULL;
   if (xsrt->temp_dir == NULL)
     return 0;
+  xsrt->temp_name = xmalloc (strlen (xsrt->temp_dir) + 64);
 
   return 1;
 }
 
-
+/* Returns nonzero if we should return an error even though the
+   operation succeeded.  Useful for testing. */
 static int
 simulate_error (void) 
 {
@@ -502,22 +512,26 @@ rmdir_temp_dir (struct external_sort *xsrt)
     }
 }
 
-#define TEMP_FILE_NAME_SIZE (L_tmpnam + 32)
-static void
-get_temp_file_name (struct external_sort *xsrt, int file_idx,
-                    char filename[TEMP_FILE_NAME_SIZE]) 
+/* Returns the name of temporary file number FILE_IDX for XSRT.
+   The name is written into a static buffer, so be careful.  */
+static char *
+get_temp_file_name (struct external_sort *xsrt, int file_idx)
 {
   assert (xsrt->temp_dir != NULL);
-  sprintf (filename, "%s%c%04d", xsrt->temp_dir, DIR_SEPARATOR, file_idx);
+  sprintf (xsrt->temp_name, "%s%c%04d",
+           xsrt->temp_dir, DIR_SEPARATOR, file_idx);
+  return xsrt->temp_name;
 }
 
+/* Opens temporary file numbered FILE_IDX for XSRT with mode MODE
+   and returns the FILE *. */
 static FILE *
 open_temp_file (struct external_sort *xsrt, int file_idx, const char *mode)
 {
-  char temp_file[TEMP_FILE_NAME_SIZE];
+  char *temp_file;
   FILE *file;
 
-  get_temp_file_name (xsrt, file_idx, temp_file);
+  temp_file = get_temp_file_name (xsrt, file_idx);
 
   file = fopen (temp_file, mode);
   if (simulate_error () || file == NULL) 
@@ -528,13 +542,14 @@ open_temp_file (struct external_sort *xsrt, int file_idx, const char *mode)
   return file;
 }
 
+/* Closes FILE, which is the temporary file numbered FILE_IDX
+   under XSRT.  Returns nonzero only if successful.  */
 static int
 close_temp_file (struct external_sort *xsrt, int file_idx, FILE *file)
 {
   if (file != NULL) 
     {
-      char temp_file[TEMP_FILE_NAME_SIZE];
-      get_temp_file_name (xsrt, file_idx, temp_file);
+      char *temp_file = get_temp_file_name (xsrt, file_idx);
       if (simulate_error () || fclose (file) == EOF) 
         {
           msg (SE, _("%s: Error closing temporary file: %s."),
@@ -545,19 +560,21 @@ close_temp_file (struct external_sort *xsrt, int file_idx, FILE *file)
   return 1;
 }
 
+/* Delete temporary file numbered FILE_IDX for XSRT. */
 static void
 remove_temp_file (struct external_sort *xsrt, int file_idx) 
 {
   if (file_idx != -1)
     {
-      char temp_file[TEMP_FILE_NAME_SIZE];
-      get_temp_file_name (xsrt, file_idx, temp_file);
+      char *temp_file = get_temp_file_name (xsrt, file_idx);
       if (simulate_error () || remove (temp_file) != 0)
         msg (SE, _("%s: Error removing temporary file: %s."),
              temp_file, strerror (errno));
     }
 }
 
+/* Writes SIZE bytes from buffer DATA into FILE, which is
+   temporary file numbered FILE_IDX from XSRT. */
 static int
 write_temp_file (struct external_sort *xsrt, int file_idx,
                  FILE *file, const void *data, size_t size) 
@@ -566,14 +583,15 @@ write_temp_file (struct external_sort *xsrt, int file_idx,
     return 1;
   else
     {
-      char temp_file[TEMP_FILE_NAME_SIZE];
-      get_temp_file_name (xsrt, file_idx, temp_file);
+      char *temp_file = get_temp_file_name (xsrt, file_idx);
       msg (SE, _("%s: Error writing temporary file: %s."),
            temp_file, strerror (errno));
       return 0;
     }
 }
 
+/* Reads SIZE bytes into buffer DATA into FILE, which is
+   temporary file numbered FILE_IDX from XSRT. */
 static int
 read_temp_file (struct external_sort *xsrt, int file_idx,
                 FILE *file, void *data, size_t size) 
@@ -582,8 +600,7 @@ read_temp_file (struct external_sort *xsrt, int file_idx,
     return 1;
   else 
     {
-      char temp_file[TEMP_FILE_NAME_SIZE];
-      get_temp_file_name (xsrt, file_idx, temp_file);
+      char *temp_file = get_temp_file_name (xsrt, file_idx);
       if (ferror (file))
         msg (SE, _("%s: Error reading temporary file: %s."),
              temp_file, strerror (errno));
@@ -603,6 +620,7 @@ struct record_run
     struct case_list *record;   /* Case data. */
   };
 
+/* Represents a set of initial runs during an external sort. */
 struct initial_run_state 
   {
     struct external_sort *xsrt;
@@ -635,6 +653,8 @@ static int compare_record_run (const struct record_run *,
                                struct sort_cases_pgm *);
 static int compare_record_run_minheap (const void *, const void *, void *);
 
+/* Writes initial runs for XSRT, sending them to a separate file
+   if SEPARATE is nonzero. */
 static int
 write_initial_runs (struct external_sort *xsrt, int separate)
 {
@@ -659,7 +679,7 @@ write_initial_runs (struct external_sort *xsrt, int separate)
   /* Create case sink. */
   if (!separate)
     {
-      if (vfm_sink)
+      if (vfm_sink != NULL && vfm_sink->class->destroy != NULL)
        vfm_sink->class->destroy (vfm_sink);
       vfm_sink = create_case_sink (&sort_sink_class, irs);
       xsrt->scp->ref_cnt++;
@@ -682,7 +702,7 @@ write_initial_runs (struct external_sort *xsrt, int separate)
 
 /* Add a single case to an initial run. */
 static void
-sort_sink_write (struct case_sink *sink, struct ccase *c)
+sort_sink_write (struct case_sink *sink, const struct ccase *c)
 {
   struct initial_run_state *irs = sink->aux;
   struct record_run *new_record_run;
@@ -708,6 +728,7 @@ sort_sink_write (struct case_sink *sink, struct ccase *c)
     output_record (irs);
 }
 
+/* Destroys the initial run state represented by IRS. */
 static void
 destroy_initial_run_state (struct initial_run_state *irs) 
 {
@@ -821,6 +842,8 @@ compare_record (const union value *a, const union value *b,
   return 0;
 }
 
+/* Compares record-run tuples A and B on run number first, then
+   on the current record according to SCP. */
 static int
 compare_record_run (const struct record_run *a,
                     const struct record_run *b,
@@ -832,6 +855,9 @@ compare_record_run (const struct record_run *a,
     return compare_record (a->record->c.data, b->record->c.data, scp);
 }
 
+/* Compares record-run tuples A and B on run number first, then
+   on the current record according to SCP, but in descending
+   order. */
 static int
 compare_record_run_minheap (const void *a, const void *b, void *scp) 
 {
@@ -879,6 +905,7 @@ end_run (struct initial_run_state *irs)
   irs->output_file = NULL;
 }
 
+/* Writes a record to the current initial run. */
 static void
 output_record (struct initial_run_state *irs)
 {
@@ -927,6 +954,8 @@ output_record (struct initial_run_state *irs)
   irs->last_output = record_run->record;
 }
 
+/* Gets a case from the free list in IRS.  It is an error to call
+   this function if the free list is empty. */
 static struct case_list *
 grab_case (struct initial_run_state *irs)
 {
@@ -940,6 +969,7 @@ grab_case (struct initial_run_state *irs)
   return c;
 }
 
+/* Returns C to the free list in IRS. */
 static void 
 release_case (struct initial_run_state *irs, struct case_list *c) 
 {
@@ -952,6 +982,7 @@ release_case (struct initial_run_state *irs, struct case_list *c)
 \f
 /* Merging. */
 
+/* State of merging initial runs. */
 struct merge_state 
   {
     struct external_sort *xsrt; /* External sort state. */
@@ -1228,18 +1259,13 @@ fill_run_buffer (struct merge_state *mrg, struct run *run)
   return 1;
 }
 \f
-static void
-sort_sink_destroy (struct case_sink *sink UNUSED) 
-{
-  assert (0);
-}
-
 static struct case_source *
 sort_sink_make_source (struct case_sink *sink) 
 {
   struct initial_run_state *irs = sink->aux;
 
-  return create_case_source (&sort_source_class, irs->xsrt->scp);
+  return create_case_source (&sort_source_class, default_dict,
+                             irs->xsrt->scp);
 }
 
 const struct case_sink_class sort_sink_class = 
@@ -1247,72 +1273,90 @@ const struct case_sink_class sort_sink_class =
     "SORT CASES",
     NULL,
     sort_sink_write,
-    sort_sink_destroy,
+    NULL,
     sort_sink_make_source,
   };
 \f
+struct sort_source_aux 
+  {
+    struct sort_cases_pgm *scp;
+    struct ccase *dst;
+    write_case_func *write_case;
+    write_case_data wc_data;
+  };
+
+/* Passes C to the write_case function. */
+static int
+sort_source_read_helper (const struct ccase *src, void *aux_) 
+{
+  struct sort_source_aux *aux = aux_;
+
+  memcpy (aux->dst, src, aux->scp->case_size);
+  return aux->write_case (aux->wc_data);
+}
+
 /* Reads all the records from the source stream and passes them
    to write_case(). */
 static void
 sort_source_read (struct case_source *source,
+                  struct ccase *c,
                   write_case_func *write_case, write_case_data wc_data)
 {
   struct sort_cases_pgm *scp = source->aux;
+  struct sort_source_aux aux;
+
+  aux.scp = scp;
+  aux.dst = c;
+  aux.write_case = write_case;
+  aux.wc_data = wc_data;
   
-  read_sort_output (scp, write_case, wc_data);
+  read_sort_output (scp, sort_source_read_helper, &aux);
 }
 
-void read_internal_sort_output (struct internal_sort *isrt,
-                                write_case_func *write_case,
-                                write_case_data wc_data);
-void read_external_sort_output (struct external_sort *xsrt,
-                                write_case_func *write_case,
-                                write_case_data wc_data);
+static void read_internal_sort_output (struct internal_sort *isrt,
+                                       read_sort_output_func *, void *aux);
+static void read_external_sort_output (struct external_sort *xsrt,
+                                       read_sort_output_func *, void *aux);
 
 /* Reads all the records from the output stream and passes them to the
    function provided, which must have an interface identical to
    write_case(). */
 void
 read_sort_output (struct sort_cases_pgm *scp,
-                  write_case_func *write_case, write_case_data wc_data)
+                  read_sort_output_func *output_func, void *aux)
 {
   assert ((scp->isrt != NULL) + (scp->xsrt != NULL) <= 1);
   if (scp->isrt != NULL)
-    read_internal_sort_output (scp->isrt, write_case, wc_data);
+    read_internal_sort_output (scp->isrt, output_func, aux);
   else if (scp->xsrt != NULL)
-    read_external_sort_output (scp->xsrt, write_case, wc_data);
+    read_external_sort_output (scp->xsrt, output_func, aux);
   else 
     {
       /* No results.  Probably an external sort that failed. */
     }
 }
 
-void
+static void
 read_internal_sort_output (struct internal_sort *isrt,
-                           write_case_func *write_case,
-                           write_case_data wc_data)
+                           read_sort_output_func *output_func,
+                           void *aux)
 {
-  struct ccase *save_temp_case = temp_case;
   struct case_list **p;
 
-  for (p = isrt->results; *p; p++) 
-    {
-      temp_case = &(*p)->c;
-      write_case (wc_data);
-    }
+  for (p = isrt->results; *p; p++)
+    if (!output_func (&(*p)->c, aux))
+      break;
   free (isrt->results);
-           
-  temp_case = save_temp_case;
 }
 
-void
+static void
 read_external_sort_output (struct external_sort *xsrt,
-                           write_case_func *write_case,
-                           write_case_data wc_data)
+                           read_sort_output_func *output_func, void *aux)
 {
   FILE *file;
   int file_idx;
   size_t i;
+  struct ccase *c;
 
   assert (xsrt->run_cnt == 1);
   file_idx = xsrt->initial_runs[0].file_idx;
@@ -1324,18 +1368,19 @@ read_external_sort_output (struct external_sort *xsrt,
       return;
     }
 
+  c = xmalloc (xsrt->scp->case_size);
   for (i = 0; i < xsrt->initial_runs[0].case_cnt; i++)
     {
-      if (!read_temp_file (xsrt, file_idx, file,
-                          temp_case, xsrt->case_size))
+      if (!read_temp_file (xsrt, file_idx, file, c, xsrt->scp->case_size))
        {
           err_failure ();
           break;
         }
 
-      if (!write_case (wc_data))
+      if (!output_func (c, aux))
         break;
     }
+  free (c);
 }
 
 static void
index 928a5170b1340caeeb105687020e2ad11db61136..4f8659e68d5de7100a431ee940c2e595a24506d7 100644 (file)
@@ -40,13 +40,17 @@ struct sort_cases_pgm
 
     struct internal_sort *isrt;         /* Internal sort output. */
     struct external_sort *xsrt;         /* External sort output. */
+    size_t case_size;                   /* Number of bytes in case. */
   };
 
 /* SORT CASES programmatic interface. */
+
+typedef int read_sort_output_func (const struct ccase *, void *aux);
+
 struct sort_cases_pgm *parse_sort (void);
 int sort_cases (struct sort_cases_pgm *, int separate);
 void read_sort_output (struct sort_cases_pgm *,
-                       write_case_func *, write_case_data);
+                       read_sort_output_func, void *aux);
 void destroy_sort_cases_pgm (struct sort_cases_pgm *);
 
 #endif /* !sort_h */
index 66fec9ae9ea1de88ec920c3c1adc88eb38dcba57..8b15fd7bc91a8a1f44156788554028452ee58320 100644 (file)
@@ -30,6 +30,9 @@
 #include "misc.h"
 #include "str.h"
 
+/* Parses a name as a variable within VS and returns the variable
+   if successful.  On failure emits an error message and returns
+   a null pointer. */
 static struct variable *
 parse_vs_variable (struct var_set *vs)
 {
@@ -49,6 +52,9 @@ parse_vs_variable (struct var_set *vs)
   return vp;
 }
 
+/* Parses a variable name in dictionary D and returns the
+   variable if successful.  On failure emits an error message and
+   returns a null pointer. */
 struct variable *
 parse_dict_variable (struct dictionary *d) 
 {
@@ -58,13 +64,17 @@ parse_dict_variable (struct dictionary *d)
   return var;
 }
 
+/* Parses a variable name in default_dict and returns the
+   variable if successful.  On failure emits an error message and
+   returns a null pointer. */
 struct variable *
 parse_variable (void)
 {
   return parse_dict_variable (default_dict);
 }
 
-
+/* Returns the dictionary class corresponding to a variable named
+   NAME. */
 enum dict_class
 dict_class_from_id (const char *name) 
 {
@@ -81,22 +91,26 @@ dict_class_from_id (const char *name)
     }
 }
 
+/* Returns the name of dictionary class DICT_CLASS. */
 const char *
 dict_class_to_name (enum dict_class dict_class) 
 {
   switch (dict_class) 
     {
     case DC_ORDINARY:
-      return "ordinary";
+      return _("ordinary");
     case DC_SYSTEM:
-      return "system";
+      return _("system");
     case DC_SCRATCH:
-      return "scratch";
+      return _("scratch");
     default:
       assert (0);
     }
 }
 
+/* Parses a set of variables from dictionary D given options
+   OPTS.  Resulting list of variables stored in *VAR and the
+   number of variables into *CNT. */
 int
 parse_variables (struct dictionary *d, struct variable ***var, int *cnt,
                  int opts) 
@@ -297,6 +311,9 @@ fail:
   return 0;
 }
 
+/* Extracts a numeric suffix from variable name S, copying it
+   into string R.  Sets *D to the length of R and *N to its
+   value. */
 static int
 extract_num (char *s, char *r, int *n, int *d)
 {
@@ -502,6 +519,7 @@ fail:
   return 0;
 }
 \f
+/* A set of variables. */
 struct var_set 
   {
     size_t (*get_cnt) (struct var_set *);
@@ -511,6 +529,7 @@ struct var_set
     void *aux;
   };
 
+/* Returns the number of variables in VS. */
 size_t
 var_set_get_cnt (struct var_set *vs) 
 {
@@ -519,6 +538,8 @@ var_set_get_cnt (struct var_set *vs)
   return vs->get_cnt (vs);
 }
 
+/* Return variable with index IDX in VS.
+   IDX must be less than the number of variables in VS. */
 struct variable *
 var_set_get_var (struct var_set *vs, size_t idx) 
 {
@@ -528,6 +549,8 @@ var_set_get_var (struct var_set *vs, size_t idx)
   return vs->get_var (vs, idx);
 }
 
+/* Returns the variable in VS named NAME, or a null pointer if VS
+   contains no variable with that name. */
 struct variable *
 var_set_lookup_var (struct var_set *vs, const char *name) 
 {
@@ -538,6 +561,7 @@ var_set_lookup_var (struct var_set *vs, const char *name)
   return vs->lookup_var (vs, name);
 }
 
+/* Destroys VS. */
 void
 var_set_destroy (struct var_set *vs) 
 {
@@ -545,6 +569,7 @@ var_set_destroy (struct var_set *vs)
     vs->destroy (vs);
 }
 \f
+/* Returns the number of variables in VS. */
 static size_t
 dict_var_set_get_cnt (struct var_set *vs) 
 {
@@ -553,6 +578,8 @@ dict_var_set_get_cnt (struct var_set *vs)
   return dict_get_var_cnt (d);
 }
 
+/* Return variable with index IDX in VS.
+   IDX must be less than the number of variables in VS. */
 static struct variable *
 dict_var_set_get_var (struct var_set *vs, size_t idx) 
 {
@@ -561,6 +588,8 @@ dict_var_set_get_var (struct var_set *vs, size_t idx)
   return dict_get_var (d, idx);
 }
 
+/* Returns the variable in VS named NAME, or a null pointer if VS
+   contains no variable with that name. */
 static struct variable *
 dict_var_set_lookup_var (struct var_set *vs, const char *name) 
 {
@@ -569,12 +598,14 @@ dict_var_set_lookup_var (struct var_set *vs, const char *name)
   return dict_lookup_var (d, name);
 }
 
+/* Destroys VS. */
 static void
 dict_var_set_destroy (struct var_set *vs) 
 {
   free (vs);
 }
 
+/* Returns a variable set based on D. */
 struct var_set *
 var_set_create_from_dict (struct dictionary *d) 
 {
@@ -587,13 +618,15 @@ var_set_create_from_dict (struct dictionary *d)
   return vs;
 }
 \f
+/* A variable set based on an array. */
 struct array_var_set 
   {
-    struct variable **var;
-    size_t var_cnt;
-    struct hsh_table *name_tab;
+    struct variable **var;      /* Array of variables. */
+    size_t var_cnt;             /* Number of elements in var. */
+    struct hsh_table *name_tab; /* Hash from variable names to variables. */
   };
 
+/* Returns the number of variables in VS. */
 static size_t
 array_var_set_get_cnt (struct var_set *vs) 
 {
@@ -602,6 +635,8 @@ array_var_set_get_cnt (struct var_set *vs)
   return avs->var_cnt;
 }
 
+/* Return variable with index IDX in VS.
+   IDX must be less than the number of variables in VS. */
 static struct variable *
 array_var_set_get_var (struct var_set *vs, size_t idx) 
 {
@@ -610,6 +645,8 @@ array_var_set_get_var (struct var_set *vs, size_t idx)
   return avs->var[idx];
 }
 
+/* Returns the variable in VS named NAME, or a null pointer if VS
+   contains no variable with that name. */
 static struct variable *
 array_var_set_lookup_var (struct var_set *vs, const char *name) 
 {
@@ -621,6 +658,7 @@ array_var_set_lookup_var (struct var_set *vs, const char *name)
   return hsh_find (avs->name_tab, &v);
 }
 
+/* Destroys VS. */
 static void
 array_var_set_destroy (struct var_set *vs) 
 {
@@ -631,6 +669,8 @@ array_var_set_destroy (struct var_set *vs)
   free (vs);
 }
 
+/* Returns a variable set based on the VAR_CNT variables in
+   VAR. */
 struct var_set *
 var_set_create_from_array (struct variable **var, size_t var_cnt) 
 {
index a847ea65f25d5285e714eb881eab9f82faa2711c..07bfaad30a33d9d58d842fbbfb2e33d6d404a53a 100644 (file)
--- a/src/vfm.c
+++ b/src/vfm.c
@@ -97,30 +97,34 @@ 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. */
 
+static struct ccase *create_trns_case (struct dictionary *dict);
 static void open_active_file (void);
 static void close_active_file (struct write_case_data *);
 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 (int case_num);
+static void lag_case (const struct ccase *);
+static write_case_func procedure_write_case;
+static void clear_case (struct ccase *);
+static int exclude_this_case (const struct ccase *, int case_num);
 \f
 /* Public functions. */
 
+/* Auxiliary data for executing a procedure. */
 struct procedure_aux_data 
   {
+    struct ccase *trns_case;    /* Case used for transformations. */
     size_t cases_written;       /* Number of cases written so far. */
   };
 
+/* Auxiliary data for SPLIT FILE. */
 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 PROC_FUNC with CURCASE
-   set to the case, and writes them to a new active file.
+   the active set of transformations, passes each of them to
+   PROC_FUNC, and writes them to a new active file.
 
    Divides the active file into zero or more series of one or more
    cases each.  BEGIN_FUNC is called before each series.  END_FUNC is
@@ -130,7 +134,7 @@ struct split_aux_data
    PROC_FUNC, and END_FUNC as auxiliary data. */
 void
 procedure (void (*begin_func) (void *),
-          int (*proc_func) (struct ccase *curcase, void *),
+          int (*proc_func) (struct ccase *, void *),
           void (*end_func) (void *),
            void *func_aux)
 {
@@ -146,6 +150,7 @@ procedure (void (*begin_func) (void *),
   assert (++recursive_call == 1);
 
   proc_aux.cases_written = 0;
+  proc_aux.trns_case = create_trns_case (default_dict);
 
   /* Normally we just use the data passed by the user. */
   procedure_write_data.begin_func = begin_func;
@@ -174,66 +179,75 @@ procedure (void (*begin_func) (void *),
   open_active_file ();
   if (vfm_source != NULL) 
     vfm_source->class->read (vfm_source,
+                             proc_aux.trns_case,
                              procedure_write_case, &procedure_write_data);
   close_active_file (&procedure_write_data);
 
   if (split)
     free (split_aux.prev_case);
 
+  free (proc_aux.trns_case);
+
   assert (--recursive_call == 0);
 }
 \f
 /* Active file processing support.  Subtly different semantics from
    procedure(). */
 
-static int process_active_file_write_case (struct write_case_data *data);
+static write_case_func process_active_file_write_case;
 
-/* The casefunc might want us to stop calling it. */
+/* The case_func might want us to stop calling it. */
 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
-   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().
+/* Reads all the cases from the active file and passes them
+   one-by-one to CASE_FUNC.  Before any cases are passed, calls
+   BEGIN_FUNC.  After all the cases have been passed, calls
+   END_FUNC.  BEGIN_FUNC, CASE_FUNC, and END_FUNC can write 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 (*begin_func) (void *),
-                    int (*casefunc) (struct ccase *curcase, void *),
+                    int (*case_func) (struct ccase *, void *),
                     void (*end_func) (void *),
                      void *func_aux)
 {
+  struct procedure_aux_data proc_aux;
   struct write_case_data process_active_write_data;
 
+  proc_aux.cases_written = 0;
+  proc_aux.trns_case = create_trns_case (default_dict);
+
   process_active_write_data.begin_func = begin_func;
-  process_active_write_data.proc_func = casefunc;
+  process_active_write_data.proc_func = case_func;
   process_active_write_data.end_func = end_func;
   process_active_write_data.func_aux = func_aux;
+  process_active_write_data.aux = &proc_aux;
 
   not_canceled = 1;
 
   open_active_file ();
   begin_func (func_aux);
   if (vfm_source != NULL)
-    vfm_source->class->read (vfm_source, process_active_file_write_case,
+    vfm_source->class->read (vfm_source, proc_aux.trns_case,
+                             process_active_file_write_case,
                              &process_active_write_data);
   end_func (func_aux);
   close_active_file (&process_active_write_data);
 }
 
-/* Pass the current case to casefunc. */
+/* Pass the current case to case_func. */
 static int
-process_active_file_write_case (struct write_case_data *data)
+process_active_file_write_case (struct write_case_data *wc_data)
 {
-  /* Index of current transformation. */
-  int cur_trns;
+  struct procedure_aux_data *proc_aux = wc_data->aux;
+  int cur_trns;         /* Index of current transformation. */
 
-  for (cur_trns = f_trns ; cur_trns != temp_trns; )
+  for (cur_trns = f_trns; cur_trns != temp_trns; )
     {
       int code;
        
-      code = t_trns[cur_trns]->proc (t_trns[cur_trns], temp_case,
+      code = t_trns[cur_trns]->proc (t_trns[cur_trns], proc_aux->trns_case,
                                      case_count + 1);
       switch (code)
        {
@@ -252,25 +266,52 @@ process_active_file_write_case (struct write_case_data *data)
     }
 
   if (n_lag)
-    lag_case ();
+    lag_case (proc_aux->trns_case);
          
   /* Call the procedure if FILTER and PROCESS IF don't prohibit it. */
-  if (not_canceled && !exclude_this_case (case_count + 1))
-    not_canceled = data->proc_func (temp_case, data->func_aux);
+  if (not_canceled && !exclude_this_case (proc_aux->trns_case, case_count + 1))
+    not_canceled = wc_data->proc_func (proc_aux->trns_case, wc_data->func_aux);
   
   case_count++;
   
  done:
-  clear_temp_case ();
+  clear_case (proc_aux->trns_case);
 
   return 1;
 }
 
-/* Write temp_case to the active file. */
+/* Write the given case to the active file. */
 void
-process_active_file_output_case (void)
+process_active_file_output_case (const struct ccase *c)
 {
-  vfm_sink->class->write (vfm_sink, temp_case);
+  vfm_sink->class->write (vfm_sink, c);
+}
+\f
+/* Creates and returns a case, initializing it from the vectors
+   that say which `value's need to be initialized just once, and
+   which ones need to be re-initialized before every case. */
+static struct ccase *
+create_trns_case (struct dictionary *dict)
+{
+  struct ccase *c = xmalloc (dict_get_case_size (dict));
+  size_t var_cnt = dict_get_var_cnt (dict);
+  size_t i;
+
+  for (i = 0; i < var_cnt; i++) 
+    {
+      struct variable *v = dict_get_var (dict, i);
+
+      if (v->type == NUMERIC) 
+        {
+          if (v->reinit)
+            c->data[v->fv].f = 0.0;
+          else
+            c->data[v->fv].f = SYSMIS;
+        }
+      else
+        memset (c->data[v->fv].s, ' ', v->width);
+    }
+  return c;
 }
 \f
 /* Opening the active file. */
@@ -282,20 +323,6 @@ process_active_file_output_case (void)
 static void
 prepare_for_writing (void)
 {
-  /* FIXME: If ALL the conditions listed below hold true, then the
-     replacement active file is guaranteed to be identical to the
-     original active file:
-
-     1. TEMPORARY was the first transformation, OR, there were no
-     transformations at all.
-
-     2. Input is not coming from an input program.
-
-     3. Compaction is not necessary.
-
-     So, in this case, we shouldn't have to replace the active
-     file--it's just a waste of time and space. */
-
   if (vfm_sink == NULL)
     {
       if (workspace_overflow)
@@ -339,17 +366,11 @@ arrange_compaction (void)
   
   if (vfm_sink->class->open != NULL)
     vfm_sink->class->open (vfm_sink);
-}
-
-/* Prepares the temporary case and compaction case. */
-static void
-make_temp_case (void)
-{
-  temp_case = xmalloc (dict_get_case_size (default_dict));
 
   if (compaction_necessary)
     compaction_case = xmalloc (sizeof (struct ccase)
                               + sizeof (union value) * (compaction_nval - 1));
+
 }
 
 #if DEBUGGING
@@ -371,31 +392,6 @@ index_to_varname (int ccase_index)
 }
 #endif
 
-/* Initializes temp_case from the vectors that say which `value's
-   need to be initialized just once, and which ones need to be
-   re-initialized before every case. */
-static void
-vector_initialization (void)
-{
-  size_t var_cnt = dict_get_var_cnt (default_dict);
-  size_t i;
-  
-  for (i = 0; i < var_cnt; i++) 
-    {
-      struct variable *v = dict_get_var (default_dict, i);
-
-      if (v->type == NUMERIC) 
-        {
-          if (v->reinit)
-            temp_case->data[v->fv].f = 0.0;
-          else
-            temp_case->data[v->fv].f = SYSMIS;
-        }
-      else
-        memset (temp_case->data[v->fv].s, ' ', v->width);
-    }
-}
-
 /* Sets all the lag-related variables based on value of n_lag. */
 static void
 setup_lag (void)
@@ -456,8 +452,6 @@ open_active_file (void)
   /* The rest. */
   prepare_for_writing ();
   arrange_compaction ();
-  make_temp_case ();
-  vector_initialization ();
   discard_ctl_stack ();
   setup_lag ();
 }
@@ -502,7 +496,10 @@ close_active_file (struct write_case_data *data)
       free (vfm_source);
     }
 
-  vfm_source = vfm_sink->class->make_source (vfm_sink);
+  if (vfm_sink->class->make_source != NULL)
+    vfm_source = vfm_sink->class->make_source (vfm_sink);
+  else
+    vfm_source = NULL;
 
   /* Old data sink is gone now. */
   free (vfm_sink);
@@ -512,9 +509,6 @@ close_active_file (struct write_case_data *data)
   cancel_temporary ();
 
   /* Free temporary cases. */
-  free (temp_case);
-  temp_case = NULL;
-
   free (compaction_case);
   compaction_case = NULL;
 
@@ -564,12 +558,12 @@ disk_sink_create (struct case_sink *sink)
     }
 }
 
-/* Writes temp_case to the disk sink. */
+/* Writes case C to the disk sink. */
 static void
-disk_sink_write (struct case_sink *sink, struct ccase *c)
+disk_sink_write (struct case_sink *sink, const struct ccase *c)
 {
   struct disk_stream_info *info = sink->aux;
-  union value *src_case;
+  const union value *src_case;
 
   if (compaction_necessary)
     {
@@ -615,7 +609,7 @@ disk_sink_make_source (struct case_sink *sink)
       err_failure ();
     }
   
-  return create_case_source (&disk_source_class, info);
+  return create_case_source (&disk_source_class, default_dict, info);
 }
 
 /* Disk sink. */
@@ -644,6 +638,7 @@ disk_source_count (const struct case_source *source)
    write_case(). */
 static void
 disk_source_read (struct case_source *source,
+                  struct ccase *c,
                   write_case_func *write_case, write_case_data wc_data)
 {
   struct disk_stream_info *info = source->aux;
@@ -651,17 +646,17 @@ disk_source_read (struct case_source *source,
 
   for (i = 0; i < info->case_cnt; i++)
     {
-      if (!fread (temp_case, info->case_size, 1, info->file))
+      if (!fread (c, 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."),
               strerror (errno));
          err_failure ();
-         return;
+         break;
        }
 
       if (!write_case (wc_data))
-       return;
+       break;
     }
 }
 
@@ -704,6 +699,7 @@ struct memory_source_info
     struct case_list *cases;    /* List of cases. */
   };
 
+/* Creates the SINK memory sink. */
 static void
 memory_sink_create (struct case_sink *sink) 
 {
@@ -718,8 +714,9 @@ memory_sink_create (struct case_sink *sink)
   info->head = info->tail = NULL;
 }
 
+/* Writes case C to memory sink SINK. */
 static void
-memory_sink_write (struct case_sink *sink, struct ccase *c) 
+memory_sink_write (struct case_sink *sink, const struct ccase *c) 
 {
   struct memory_sink_info *info = sink->aux;
   size_t case_size;
@@ -861,7 +858,8 @@ memory_sink_make_source (struct case_sink *sink)
 
   free (sink_info);
 
-  return create_case_source (&memory_source_class, source_info);
+  return create_case_source (&memory_source_class,
+                             default_dict, source_info);
 }
 
 const struct case_sink_class memory_sink_class = 
@@ -885,6 +883,7 @@ memory_source_count (const struct case_source *source)
 /* Reads the case stream from memory and passes it to write_case(). */
 static void
 memory_source_read (struct case_source *source,
+                    struct ccase *c,
                     write_case_func *write_case, write_case_data wc_data)
 {
   struct memory_source_info *info = source->aux;
@@ -892,12 +891,12 @@ memory_source_read (struct case_source *source,
   while (info->cases != NULL) 
     {
       struct case_list *iter = info->cases;
+      memcpy (c, &iter->c, info->case_size);
+      if (!write_case (wc_data)) 
+        break;
+            
       info->cases = iter->next;
-      memcpy (temp_case, &iter->c, info->case_size);
       free (iter);
-      
-      if (!write_case (wc_data))
-       return;
     }
 }
 
@@ -916,6 +915,7 @@ memory_source_destroy (struct case_source *source)
   free (info);
 }
 
+/* Returns the list of cases in memory source SOURCE. */
 struct case_list *
 memory_source_get_cases (const struct case_source *source) 
 {
@@ -924,6 +924,7 @@ memory_source_get_cases (const struct case_source *source)
   return info->cases;
 }
 
+/* Sets the list of cases in memory source SOURCE to CASES. */
 void
 memory_source_set_cases (const struct case_source *source,
                          struct case_list *cases) 
@@ -942,14 +943,13 @@ const struct case_source_class memory_source_class =
     memory_source_destroy,
   };
 \f
-/* Add temp_case to the lag queue. */
+/* Add C to the lag queue. */
 static void
-lag_case (void)
+lag_case (const struct ccase *c)
 {
   if (lag_count < n_lag)
     lag_count++;
-  memcpy (lag_queue[lag_head], temp_case,
-          dict_get_case_size (temp_dict));
+  memcpy (lag_queue[lag_head], c, dict_get_case_size (temp_dict));
   if (++lag_head >= n_lag)
     lag_head = 0;
 }
@@ -971,10 +971,10 @@ lagged_case (int n_before)
   }
 }
    
-/* Transforms temp_case and writes it to the replacement active file
-   if advisable.  Returns nonzero if more cases can be accepted, zero
-   otherwise.  Do not call this function again after it has returned
-   zero once.  */
+/* Transforms trns_case and writes it to the replacement active
+   file if advisable.  Returns nonzero if more cases can be
+   accepted, zero otherwise.  Do not call this function again
+   after it has returned zero once.  */
 int
 procedure_write_case (write_case_data wc_data)
 {
@@ -995,9 +995,9 @@ procedure_write_case (write_case_data wc_data)
           int case_limit;
 
          if (n_lag)
-           lag_case ();
+           lag_case (proc_aux->trns_case);
          
-         vfm_sink->class->write (vfm_sink, temp_case);
+         vfm_sink->class->write (vfm_sink, proc_aux->trns_case);
 
           proc_aux->cases_written++;
           case_limit = dict_get_case_limit (default_dict);
@@ -1013,7 +1013,7 @@ procedure_write_case (write_case_data wc_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], proc_aux->trns_case,
                                        proc_aux->cases_written + 1);
        switch (code)
          {
@@ -1039,22 +1039,22 @@ procedure_write_case (write_case_data wc_data)
   /* Call the procedure if there is one and FILTER and PROCESS IF
      don't prohibit it. */
   if (wc_data->proc_func != NULL
-      && !exclude_this_case (proc_aux->cases_written + 1))
-    wc_data->proc_func (temp_case, wc_data->func_aux);
+      && !exclude_this_case (proc_aux->trns_case, proc_aux->cases_written + 1))
+    wc_data->proc_func (proc_aux->trns_case, wc_data->func_aux);
 
   case_count++;
   
 done:
-  clear_temp_case ();
+  clear_case (proc_aux->trns_case);
   
   /* Return previously determined value. */
   return more_cases;
 }
 
-/* Clears the variables in the temporary case that need to be
-   cleared between processing cases.  */
+/* Clears the variables in C that need to be cleared between
+   processing cases.  */
 static void
-clear_temp_case (void)
+clear_case (struct ccase *c)
 {
   /* FIXME?  This is linear in the number of variables, but
      doesn't need to be, so it's an easy optimization target. */
@@ -1067,31 +1067,31 @@ clear_temp_case (void)
       if (v->init && v->reinit) 
         {
           if (v->type == NUMERIC) 
-            temp_case->data[v->fv].f = SYSMIS;
+            c->data[v->fv].f = SYSMIS;
           else
-            memset (temp_case->data[v->fv].s, ' ', v->width);
+            memset (c->data[v->fv].s, ' ', v->width);
         } 
     }
 }
 
-/* Returns nonzero if this case (numbered CASE_NUM) should be
+/* Returns nonzero if case C with case number CASE_NUM should be
    exclude as specified on FILTER or PROCESS IF, otherwise
    zero. */
 static int
-exclude_this_case (int case_num)
+exclude_this_case (const struct ccase *c, int case_num)
 {
   /* FILTER. */
   struct variable *filter_var = dict_get_filter (default_dict);
   if (filter_var != NULL) 
     {
-      double f = temp_case->data[filter_var->fv].f;
+      double f = c->data[filter_var->fv].f;
       if (f == 0.0 || f == SYSMIS || is_num_user_missing (f, filter_var))
         return 1;
     }
 
   /* PROCESS IF. */
   if (process_if_expr != NULL
-      && expr_evaluate (process_if_expr, temp_case, case_num, NULL) != 1.0)
+      && expr_evaluate (process_if_expr, c, case_num, NULL) != 1.0)
     return 1;
 
   return 0;
@@ -1293,15 +1293,21 @@ finish_compaction (void)
   dict_compact_values (default_dict);
 }
 
+/* Creates a case source with class CLASS and auxiliary data AUX
+   and based on dictionary DICT. */
 struct case_source *
-create_case_source (const struct case_source_class *class, void *aux) 
+create_case_source (const struct case_source_class *class,
+                    const struct dictionary *dict,
+                    void *aux) 
 {
   struct case_source *source = xmalloc (sizeof *source);
   source->class = class;
+  source->value_cnt = dict_get_next_value_idx (dict);
   source->aux = aux;
   return source;
 }
 
+/* Returns nonzero if a case source is "complex". */
 int
 case_source_is_complex (const struct case_source *source) 
 {
@@ -1309,6 +1315,7 @@ case_source_is_complex (const struct case_source *source)
                             || source->class == &file_type_source_class);
 }
 
+/* Returns nonzero if CLASS is the class of SOURCE. */
 int
 case_source_is_class (const struct case_source *source,
                       const struct case_source_class *class) 
@@ -1316,6 +1323,8 @@ case_source_is_class (const struct case_source *source,
   return source != NULL && source->class == class;
 }
 
+/* Creates a case sink with class CLASS and auxiliary data
+   AUX. */
 struct case_sink *
 create_case_sink (const struct case_sink_class *class, void *aux) 
 {
@@ -1324,4 +1333,3 @@ create_case_sink (const struct case_sink_class *class, void *aux)
   sink->aux = aux;
   return sink;
 }
-
index 186dd6f1d09ca17721f0524630346c28d92881d3..06425b2c854d43196d9a3aae98ee1cc450b082db 100644 (file)
--- a/src/vfm.h
+++ b/src/vfm.h
@@ -25,9 +25,7 @@
 /* This is the time at which vfm was last invoked. */
 extern time_t last_vfm_invocation;
 
-/* This is the case that is to be filled in by input programs. */
-extern struct ccase *temp_case;
-
+struct ccase;
 typedef struct write_case_data *write_case_data;
 typedef int write_case_func (write_case_data);
 \f
@@ -38,7 +36,8 @@ extern struct case_source *vfm_source;
 struct case_source 
   {
     const struct case_source_class *class;      /* Class. */
-    void *aux;                                  /* Auxiliary data. */
+    size_t value_cnt;   /* Number of `union value's in case. */
+    void *aux;          /* Auxiliary data. */
   };
 
 /* A case source class. */
@@ -50,9 +49,11 @@ struct case_source_class
        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);
+    /* Reads the cases one by one into C and for each one calls
+       WRITE_CASE passing the given AUX data. */
+    void (*read) (struct case_source *,
+                  struct ccase *c,
+                  write_case_func *write_case, write_case_data aux);
 
     /* Destroys the source. */
     void (*destroy) (struct case_source *);
@@ -67,7 +68,9 @@ extern const struct case_source_class get_source_class;
 extern const struct case_source_class import_source_class;
 extern const struct case_source_class sort_source_class;
 
+struct dictionary;
 struct case_source *create_case_source (const struct case_source_class *,
+                                        const struct dictionary *,
                                         void *);
 int case_source_is_complex (const struct case_source *);
 int case_source_is_class (const struct case_source *,
@@ -95,7 +98,7 @@ struct case_sink_class
     void (*open) (struct case_sink *);
                   
     /* Writes a case to the sink. */
-    void (*write) (struct case_sink *, struct ccase *);
+    void (*write) (struct case_sink *, const struct ccase *);
     
     /* Closes and destroys the sink. */
     void (*destroy) (struct case_sink *);
@@ -115,18 +118,18 @@ struct case_sink *create_case_sink (const struct case_sink_class *, void *);
 /* Number of cases to lag. */
 extern int n_lag;
 
-void procedure (void (*beginfunc) (void *aux),
-               int (*procfunc) (struct ccase *curcase, void *aux),
-               void (*endfunc) (void *aux),
+void procedure (void (*begin_func) (void *aux),
+               int (*proc_func) (struct ccase *, void *aux),
+               void (*end_func) (void *aux),
                 void *aux);
 struct ccase *lagged_case (int n_before);
 void compact_case (struct ccase *dest, const struct ccase *src);
 void write_active_file_to_disk (void);
 
-void process_active_file (void (*beginfunc) (void *),
-                         int (*casefunc) (struct ccase *curcase, void *),
-                         void (*endfunc) (void *),
+void process_active_file (void (*begin_func) (void *),
+                         int (*casefunc) (struct ccase *, void *),
+                         void (*end_func) (void *),
                           void *aux);
-void process_active_file_output_case (void);
+void process_active_file_output_case (const struct ccase *);
 
 #endif /* !vfm_h */
index 642a2b736fdd69b304d56c4ac163400b39b8bdcd..fd19f8c8978a371ea6f3003dc4a92a6f2eca32f1 100644 (file)
 #include "str.h"
 #include "var.h"
 
-/* Notes:
-
-   If the weighting variable is deleted somehow (for instance by
-   end-of-scope of TEMPORARY), weighting must be canceled.
-
-   Scratch vars may not be used for weighting. */
-
 /* WEIGHT transformation. */
 struct weight_trns
   {