Use data_out_pool in crosstabs.q
[pspp-builds.git] / src / language / stats / crosstabs.q
index 46b5e41323955d6e06128fbd64f401e66f9b4773..e3f54c817630178cdca465f50d40f8baf9693b64 100644 (file)
@@ -161,41 +161,6 @@ struct pivot_table
     double total;              /* Grand total. */
   };
 
-/* A crosstabulation of exactly 2 variables, conditional on zero
-   or more other variables having given values. */
-struct crosstab
-  {
-    /* Case counts. */
-    double missing;
-
-    /* Variables. */
-    int n_vars;                        /* Number of variables (at least 2). */
-    const struct variable **vars;
-    union value *values;       /* Values of variables beyond 2. */
-
-    /* Data. */
-    struct table_entry **entries;
-    size_t n_entries;
-
-    /* Column values, number of columns. */
-    union value *cols;
-    int n_cols;
-
-    /* Row values, number of rows. */
-    union value *rows;
-    int n_rows;
-
-    /* Number of statistically interesting columns/rows
-       (columns/rows with data in them). */
-    int ns_cols, ns_rows;
-
-    /* Matrix contents. */
-    double *mat;               /* Matrix proper. */
-    double *row_tot;           /* Row totals. */
-    double *col_tot;           /* Column totals. */
-    double total;              /* Grand total. */
-  };
-
 /* Integer mode variable info. */
 struct var_range
   {
@@ -212,6 +177,7 @@ get_var_range (const struct variable *v)
 
 struct crosstabs_proc
   {
+    const struct dictionary *dict;
     enum { INTEGER, GENERAL } mode;
     enum mv_class exclude;
     bool pivot;
@@ -239,6 +205,7 @@ static void
 init_proc (struct crosstabs_proc *proc, struct dataset *ds)
 {
   const struct variable *wv = dict_get_weight (dataset_dict (ds));
+  proc->dict = dataset_dict (ds);
   proc->bad_warn = true;
   proc->variables = NULL;
   proc->n_variables = 0;
@@ -248,9 +215,23 @@ init_proc (struct crosstabs_proc *proc, struct dataset *ds)
 }
 
 static void
-free_proc (struct crosstabs_proc *proc UNUSED)
+free_proc (struct crosstabs_proc *proc)
 {
-  /* XXX */
+  struct pivot_table *pt;
+
+  free (proc->variables);
+  for (pt = &proc->pivots[0]; pt < &proc->pivots[proc->n_pivots]; pt++)
+    {
+      free (pt->vars);
+      free (pt->const_vars);
+      /* We must not call value_destroy on const_values because
+         it is a wild pointer; it never pointed to anything owned
+         by the pivot_table.
+
+         The rest of the data was allocated and destroyed at a
+         lower level already. */
+      free (pt);
+    }
 }
 
 static int internal_cmd_crosstabs (struct lexer *lexer, struct dataset *ds,
@@ -740,7 +721,23 @@ postcalc (struct crosstabs_proc *proc)
         }
     }
 
-  /* XXX clear output and prepare for next split file. */
+  /* Free output and prepare for next split file. */
+  for (pt = &proc->pivots[0]; pt < &proc->pivots[proc->n_pivots]; pt++)
+    {
+      size_t i;
+
+      pt->missing = 0.0;
+
+      /* Free only the members that were allocated in this
+         function.  The other pointer members are either both
+         allocated and destroyed at a lower level (in
+         output_pivot_table), or both allocated and destroyed at
+         a higher level (in crs_custom_tables and free_proc,
+         respectively). */
+      for (i = 0; i < pt->n_entries; i++)
+        free (pt->entries[i]);
+      free (pt->entries);
+    }
 }
 
 static void
@@ -998,26 +995,32 @@ output_pivot_table (struct crosstabs_proc *proc, struct pivot_table *pt)
       if (chisq)
         {
           display_dimensions (proc, &x, chisq, first_difference);
-          display_chisq (pt, chisq, &showed_fisher);
+          display_chisq (&x, chisq, &showed_fisher);
         }
       if (sym)
         {
           display_dimensions (proc, &x, sym, first_difference);
-          display_symmetric (proc, pt, sym);
+          display_symmetric (proc, &x, sym);
         }
       if (risk)
         {
           display_dimensions (proc, &x, risk, first_difference);
-          display_risk (pt, risk);
+          display_risk (&x, risk);
         }
       if (direct)
         {
           display_dimensions (proc, &x, direct, first_difference);
-          display_directional (proc, pt, direct);
+          display_directional (proc, &x, direct);
         }
 
-      /* XXX Free data in x. */
+      /* Free the parts of x that are not owned by pt.  In
+         particular we must not free x.cols, which is the same as
+         pt->cols, which is freed at the end of this function. */
       free (x.rows);
+
+      free (x.mat);
+      free (x.row_tot);
+      free (x.col_tot);
     }
 
   submit (proc, NULL, table);
@@ -1182,10 +1185,19 @@ create_crosstab_table (struct crosstabs_proc *proc, struct pivot_table *pt)
   for (i = 0; i < pt->n_consts; i++)
     {
       const struct variable *var = pt->const_vars[i];
+      size_t ofs;
+      char *s = NULL;
+
       ds_put_format (&title, ", %s=", var_get_name (var));
-      data_out (&pt->const_values[i], var_get_print_format (var),
-                ds_put_uninit (&title, var_get_width (var)));
-      /* XXX remove any leading space in what was just inserted.  */
+
+      /* Insert the formatted value of the variable, then trim
+         leading spaces in what was just inserted. */
+      ofs = ds_length (&title);
+      s = data_out (&pt->const_values[i], dict_get_encoding (proc->dict), var_get_print_format (var));
+      ds_put_cstr (&title, s);
+      free (s);
+      ds_remove (&title, ofs, ss_cspan (ds_substr (&title, ofs, SIZE_MAX),
+                                        ss_cstr (" ")));
     }
 
   ds_put_cstr (&title, " [");
@@ -1228,7 +1240,6 @@ create_chisq_table (struct pivot_table *pt)
             _("Exact. Sig. (2-sided)"));
   tab_text (chisq, 5, 0, TAB_RIGHT | TAT_TITLE,
             _("Exact. Sig. (1-sided)"));
-  chisq = 0;
   tab_offset (chisq, 0, 1);
 
   return chisq;
@@ -1512,9 +1523,8 @@ table_value_missing (struct crosstabs_proc *proc,
       return;
     }
 
-  s.string = tab_alloc (table, print->w);
-  data_out (v, print, s.string);
-  s.length = print->w;
+  s = ss_cstr (data_out_pool (v, dict_get_encoding (proc->dict), print,
+                            table->container));
   if (proc->exclude == MV_NEVER && var_is_num_missing (var, v->f, MV_USER))
     s.string[s.length++] = 'M';
   while (s.length && *s.string == ' ')
@@ -1547,16 +1557,15 @@ display_dimensions (struct crosstabs_proc *proc, struct pivot_table *pt,
    additionally suffixed with a letter `M'. */
 static void
 format_cell_entry (struct tab_table *table, int c, int r, double value,
-                   char suffix, bool mark_missing)
+                   char suffix, bool mark_missing, const struct dictionary *dict)
 {
   const struct fmt_spec f = {FMT_F, 10, 1};
   union value v;
   struct substring s;
 
-  s.length = 10;
-  s.string = tab_alloc (table, 16);
   v.f = value;
-  data_out (&v, &f, s.string);
+  s = ss_cstr (data_out_pool (&v, dict_get_encoding (dict), &f, table->container));
+
   while (*s.string == ' ')
     {
       s.length--;
@@ -1642,7 +1651,7 @@ display_crosstabulation (struct crosstabs_proc *proc, struct pivot_table *pt,
                 default:
                   NOT_REACHED ();
                 }
-              format_cell_entry (table, c, i, v, suffix, mark_missing);
+              format_cell_entry (table, c, i, v, suffix, mark_missing, proc->dict);
             }
 
           mp++;
@@ -1693,7 +1702,7 @@ display_crosstabulation (struct crosstabs_proc *proc, struct pivot_table *pt,
               NOT_REACHED ();
             }
 
-          format_cell_entry (table, pt->n_cols, 0, v, suffix, mark_missing);
+          format_cell_entry (table, pt->n_cols, 0, v, suffix, mark_missing, proc->dict);
           tab_next_row (table);
         }
     }
@@ -1743,7 +1752,7 @@ display_crosstabulation (struct crosstabs_proc *proc, struct pivot_table *pt,
               NOT_REACHED ();
             }
 
-          format_cell_entry (table, c, i, v, suffix, mark_missing);
+          format_cell_entry (table, c, i, v, suffix, mark_missing, proc->dict);
         }
       last_row = i;
     }
@@ -1773,7 +1782,6 @@ display_chisq (struct pivot_table *pt, struct tab_table *chisq,
   double chisq_v[N_CHISQ];
   double fisher1, fisher2;
   int df[N_CHISQ];
-  int s = 0;
 
   int i;
 
@@ -1786,7 +1794,6 @@ display_chisq (struct pivot_table *pt, struct tab_table *chisq,
       if ((i != 2 && chisq_v[i] == SYSMIS)
          || (i == 2 && fisher1 == SYSMIS))
        continue;
-      s = 1;
 
       tab_text (chisq, 0, 0, TAB_LEFT, gettext (chisq_stats[i]));
       if (i != 2)