Eliminate temp_case, and a few other cleanups.
[pspp-builds.git] / src / aggregate.c
index 1c885b1be54bfe6e8e837f8603bed9d3dc78b281..4d00a34ad2cbb7404548762a0096f94b22f9e409 100644 (file)
@@ -26,6 +26,7 @@
 #include "file-handle.h"
 #include "lexer.h"
 #include "misc.h"
+#include "pool.h"
 #include "settings.h"
 #include "sfm.h"
 #include "sort.h"
@@ -76,7 +77,7 @@ struct agr_func
   };
 
 /* Attributes of aggregation functions. */
-static struct agr_func agr_func_tab[] = 
+static const struct agr_func agr_func_tab[] = 
   {
     {"<NONE>",  0, -1,      {0, 0, 0}},
     {"SUM",     0, -1,      {FMT_F, 8, 2}},
@@ -116,6 +117,9 @@ enum
 /* ITEMWISE or COLUMNWISE. */
 static int missing;
 
+/* Sort program. */
+static struct sort_cases_pgm *sort;
+
 /* Aggregate variables. */
 static struct agr_var *agr_first, *agr_next;
 
@@ -137,15 +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 int agr_00x_trns_proc (struct trns_header *, struct ccase *);
-static void agr_00x_end_func (void);
-static int agr_10x_trns_proc (struct trns_header *, struct ccase *);
-static void agr_10x_trns_free (struct trns_header *);
-static void agr_10x_end_func (void);
-static int agr_11x_func (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 read_sort_output_func agr_11x_read;
+static void agr_11x_finish (void);
 
 #if DEBUGGING
 static void debug_print (int flags);
@@ -157,15 +162,12 @@ static void debug_print (int flags);
 int
 cmd_aggregate (void)
 {
-  /* From sort.c. */
-  int parse_sort_variables (void);
-  
   /* Have we seen these subcommands? */
   unsigned seen = 0;
 
   outfile = NULL;
   missing = ITEMWISE;
-  v_sort = NULL;
+  sort = NULL;
   prev_case = NULL;
   
   agr_dict = dict_create ();
@@ -183,7 +185,7 @@ cmd_aggregate (void)
        {
          if (seen & 1)
            {
-             free (v_sort);
+             destroy_sort_cases_pgm (sort);
              dict_destroy (agr_dict);
              msg (SE, _("%s subcommand given multiple times."),"OUTFILE");
              return CMD_FAILURE;
@@ -198,7 +200,7 @@ cmd_aggregate (void)
              outfile = fh_parse_file_handle ();
              if (outfile == NULL)
                {
-                 free (v_sort);
+                 destroy_sort_cases_pgm (sort);
                  dict_destroy (agr_dict);
                  return CMD_FAILURE;
                }
@@ -209,7 +211,7 @@ cmd_aggregate (void)
          lex_match ('=');
          if (!lex_match_id ("COLUMNWISE"))
            {
-             free (v_sort);
+             destroy_sort_cases_pgm (sort);
              dict_destroy (agr_dict);
              lex_error (_("while expecting COLUMNWISE"));
              return CMD_FAILURE;
@@ -224,7 +226,7 @@ cmd_aggregate (void)
        {
          if (seen & 8)
            {
-             free (v_sort);
+             destroy_sort_cases_pgm (sort);
              dict_destroy (agr_dict);
              msg (SE, _("%s subcommand given multiple times."),"BREAK");
              return CMD_FAILURE;
@@ -232,7 +234,8 @@ cmd_aggregate (void)
          seen |= 8;
 
          lex_match ('=');
-         if (!parse_sort_variables ())
+          sort = parse_sort ();
+          if (sort == NULL)
            {
              dict_destroy (agr_dict);
              return CMD_FAILURE;
@@ -241,11 +244,11 @@ cmd_aggregate (void)
          {
            int i;
            
-           for (i = 0; i < nv_sort; i++)
+           for (i = 0; i < sort->var_cnt; i++)
              {
                struct variable *v;
              
-               v = dict_clone_var (agr_dict, v_sort[i], v_sort[i]->name);
+               v = dict_clone_var (agr_dict, sort->vars[i], sort->vars[i]->name);
                assert (v != NULL);
              }
          }
@@ -261,7 +264,7 @@ cmd_aggregate (void)
   if (!parse_aggregate_functions ())
     {
       free_aggregate_functions ();
-      free (v_sort);
+      destroy_sort_cases_pgm (sort);
       return CMD_FAILURE;
     }
 
@@ -312,7 +315,7 @@ cmd_aggregate (void)
 
     if (outfile != NULL)
       type |= 4;
-    if (nv_sort != 0 && (seen & 4) == 0)
+    if (sort != NULL && (seen & 4) == 0)
       type |= 2;
     if (temporary)
       type |= 1;
@@ -323,7 +326,7 @@ cmd_aggregate (void)
        cancel_temporary ();
        /* fall through */
       case 2:
-       sort_cases (0);
+       sort_cases (sort, 0);
        goto case0;
          
       case 1:
@@ -343,7 +346,7 @@ cmd_aggregate (void)
          
          agr_dict = NULL;
 
-         procedure (NULL, NULL, agr_00x_end_func);
+         procedure (NULL, NULL, agr_00x_end_func, NULL);
          break;
        }
 
@@ -359,27 +362,21 @@ cmd_aggregate (void)
            t->free = agr_10x_trns_free;
            add_transformation (t);
 
-           procedure (NULL, NULL, agr_10x_end_func);
+           procedure (NULL, NULL, agr_10x_end_func, NULL);
          }
          
          break;
        }
          
       case 6:
-      case 7:
-       sort_cases (1);
+      case 7: 
+       sort_cases (sort, 1);
        
        if (!create_sysfile ())
          goto lossage;
-       read_sort_output (agr_11x_func);
-       
-       {
-         struct ccase *save_temp_case = temp_case;
-         temp_case = NULL;
-         agr_11x_func ();
-         temp_case = save_temp_case;
-       }
-       
+       read_sort_output (sort, agr_11x_read, NULL);
+        agr_11x_finish ();
+
        break;
 
       default:
@@ -391,7 +388,7 @@ cmd_aggregate (void)
   free (buf_1xx);
   
   /* Clean up. */
-  free (v_sort);
+  destroy_sort_cases_pgm (sort);
   free_aggregate_functions ();
   free (prev_case);
   
@@ -399,7 +396,7 @@ cmd_aggregate (void)
 
 lossage:
   /* Clean up. */
-  free (v_sort);
+  destroy_sort_cases_pgm (sort);
   free_aggregate_functions ();
   free (prev_case);
 
@@ -418,15 +415,13 @@ create_sysfile (void)
   if (!sfm_write_dictionary (&w))
     {
       free_aggregate_functions ();
-      free (v_sort);
+      destroy_sort_cases_pgm (sort);
       dict_destroy (agr_dict);
       return 0;
     }
     
   buf64_1xx = xmalloc (sizeof *buf64_1xx * w.case_size);
-  buf_1xx = xmalloc (sizeof (struct ccase)
-                     + (sizeof (union value)
-                        * (dict_get_value_cnt (agr_dict) - 1)));
+  buf_1xx = xmalloc (dict_get_case_size (agr_dict));
 
   return 1;
 }
@@ -445,7 +440,7 @@ parse_aggregate_functions (void)
       int n_dest;
 
       int include_missing;
-      struct agr_func *function;
+      const struct agr_func *function;
       int func_index;
 
       union value arg[2];
@@ -459,6 +454,7 @@ parse_aggregate_functions (void)
       dest_label = NULL;
       n_dest = 0;
       src = NULL;
+      function = NULL;
       n_src = 0;
       arg[0].c = NULL;
       arg[1].c = NULL;
@@ -664,6 +660,7 @@ parse_aggregate_functions (void)
              }
 
            free (dest[i]);
+            destvar->init = 0;
            if (dest_label[i])
              {
                destvar->label = dest_label[i];
@@ -761,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
@@ -771,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. */
@@ -782,8 +779,8 @@ aggregate_single_case (struct ccase *input, struct ccase *output)
       {
        int i;
 
-       for (i = 0; i < nv_sort; i++)
-         n_elem += v_sort[i]->nv;
+       for (i = 0; i < sort->var_cnt; i++)
+         n_elem += sort->vars[i]->nv;
       }
       
       prev_case = xmalloc (sizeof *prev_case * n_elem);
@@ -793,9 +790,9 @@ aggregate_single_case (struct ccase *input, struct ccase *output)
        union value *iter = prev_case;
        int i;
 
-       for (i = 0; i < nv_sort; i++)
+       for (i = 0; i < sort->var_cnt; i++)
          {
-           struct variable *v = v_sort[i];
+           struct variable *v = sort->vars[i];
            
            if (v->type == NUMERIC)
              (iter++)->f = input->data[v->fv].f;
@@ -818,9 +815,9 @@ aggregate_single_case (struct ccase *input, struct ccase *output)
     union value *iter = prev_case;
     int i;
     
-    for (i = 0; i < nv_sort; i++)
+    for (i = 0; i < sort->var_cnt; i++)
       {
-       struct variable *v = v_sort[i];
+       struct variable *v = sort->vars[i];
       
        switch (v->type)
          {
@@ -857,9 +854,9 @@ not_equal:
     union value *iter = prev_case;
     int i;
 
-    for (i = 0; i < nv_sort; i++)
+    for (i = 0; i < sort->var_cnt; i++)
       {
-       struct variable *v = v_sort[i];
+       struct variable *v = sort->vars[i];
            
        if (v->type == NUMERIC)
          (iter++)->f = input->data[v->fv].f;
@@ -876,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;
@@ -886,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
@@ -1051,8 +1048,8 @@ dump_aggregate_info (struct ccase *output)
     {
       int i;
 
-      for (i = 0; i < nv_sort; i++)
-       n_elem += v_sort[i]->nv;
+      for (i = 0; i < sort->var_cnt; i++)
+       n_elem += sort->vars[i]->nv;
     }
     debug_printf (("n_elem=%d:", n_elem));
     memcpy (output->data, prev_case, sizeof (union value) * n_elem);
@@ -1195,7 +1192,8 @@ initialize_aggregate_info (void)
 /* Aggregate each case as it comes through.  Cases which aren't needed
    are dropped. */
 static int
-agr_00x_trns_proc (struct trns_header *h UNUSED, struct ccase *c)
+agr_00x_trns_proc (struct trns_header *h UNUSED, struct ccase *c,
+                   int case_num UNUSED)
 {
   int code = aggregate_single_case (c, compaction_case);
   debug_printf (("%d ", code));
@@ -1207,13 +1205,12 @@ agr_00x_trns_proc (struct trns_header *h UNUSED, struct ccase *c)
    the cases have been output; very little has been cleaned up at this
    point. */
 static void
-agr_00x_end_func (void)
+agr_00x_end_func (void *aux UNUSED)
 {
   /* Ensure that info for the last break group gets written to the
      active file. */
   dump_aggregate_info (compaction_case);
-  vfm_sink_info.ncases++;
-  vfm_sink->write ();
+  vfm_sink->class->write (vfm_sink, compaction_case);
 }
 
 /* Transform the aggregate case buf_1xx, in internal format, to system
@@ -1252,7 +1249,8 @@ write_case_to_sfm (void)
 /* Aggregate the current case and output it if we passed a
    breakpoint. */
 static int
-agr_10x_trns_proc (struct trns_header *h UNUSED, struct ccase *c)
+agr_10x_trns_proc (struct trns_header *h UNUSED, struct ccase *c,
+                   int case_num UNUSED)
 {
   int code = aggregate_single_case (c, buf_1xx);
 
@@ -1272,37 +1270,36 @@ agr_10x_trns_free (struct trns_header *h UNUSED)
 /* Ensure that info for the last break group gets written to the
    system file. */
 static void
-agr_10x_end_func (void)
+agr_10x_end_func (void *aux UNUSED)
 {
   dump_aggregate_info (buf_1xx);
   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 (void)
+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. */
@@ -1326,9 +1323,9 @@ debug_print (int flags)
     int i;
 
     printf (" /BREAK=");
-    for (i = 0; i < nv_sort; i++)
-      printf ("%s(%c) ", v_sort[i]->name,
-             v_sort[i]->p.srt.order == SRT_ASCEND ? 'A' : 'D');
+    for (i = 0; i < sort->var_cnt; i++)
+      printf ("%s(%c) ", sort->vars[i]->name,
+             sort->vars[i]->p.srt.order == SRT_ASCEND ? 'A' : 'D');
     putc ('\n', stdout);
   }