Eliminate temp_case, and a few other cleanups.
[pspp-builds.git] / src / aggregate.c
index dbfad40f6d4b2b79b938b6a83ed3c771bfa49b8d..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 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);
@@ -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:
@@ -366,20 +369,14 @@ cmd_aggregate (void)
        }
          
       case 6:
-      case 7:
-       sort_cases (1);
+      case 7: 
+       sort_cases (sort, 1);
        
        if (!create_sysfile ())
          goto lossage;
-       read_sort_output (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:
@@ -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,7 +415,7 @@ 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;
     }
@@ -443,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];
@@ -457,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;
@@ -760,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
@@ -770,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. */
@@ -781,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);
@@ -792,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;
@@ -817,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)
          {
@@ -856,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;
@@ -875,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;
@@ -885,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
@@ -1050,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);
@@ -1194,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));
@@ -1211,8 +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_info.ncases++;
-  vfm_sink->write ();
+  vfm_sink->class->write (vfm_sink, compaction_case);
 }
 
 /* Transform the aggregate case buf_1xx, in internal format, to system
@@ -1251,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);
 
@@ -1277,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. */
@@ -1325,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);
   }