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
{
struct crosstabs_proc
{
+ const struct dictionary *dict;
enum { INTEGER, GENERAL } mode;
enum mv_class exclude;
bool pivot;
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;
}
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,
}
}
- /* 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
{
tab_double (summary, i * 2 + 1, 0, TAB_RIGHT, n[i],
&proc->weight_format);
- tab_text (summary, i * 2 + 2, 0, TAB_RIGHT | TAT_PRINTF, "%.1f%%",
- n[i] / n[2] * 100.);
+ tab_text_format (summary, i * 2 + 2, 0, TAB_RIGHT, "%.1f%%",
+ n[i] / n[2] * 100.);
}
tab_next_row (summary);
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);
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, " [");
tab_text (chisq, 3, 0, TAB_RIGHT | TAT_TITLE,
_("Asymp. Sig. (2-sided)"));
tab_text (chisq, 4, 0, TAB_RIGHT | TAT_TITLE,
- _("Exact. Sig. (2-sided)"));
+ _("Exact Sig. (2-sided)"));
tab_text (chisq, 5, 0, TAB_RIGHT | TAT_TITLE,
- _("Exact. Sig. (1-sided)"));
- chisq = 0;
+ _("Exact Sig. (1-sided)"));
tab_offset (chisq, 0, 1);
return chisq;
tab_title (risk, _("Risk estimate."));
tab_offset (risk, pt->n_vars - 2, 0);
- tab_joint_text (risk, 2, 0, 3, 0, TAB_CENTER | TAT_TITLE | TAT_PRINTF,
- _("95%% Confidence Interval"));
+ tab_joint_text_format (risk, 2, 0, 3, 0, TAB_CENTER | TAT_TITLE,
+ _("95%% Confidence Interval"));
tab_text (risk, 0, 1, TAB_LEFT | TAT_TITLE, _("Statistic"));
tab_text (risk, 1, 1, TAB_RIGHT | TAT_TITLE, _("Value"));
tab_text (risk, 2, 1, TAB_RIGHT | TAT_TITLE, _("Lower"));
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 == ' ')
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--;
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++;
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);
}
}
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;
}
double chisq_v[N_CHISQ];
double fisher1, fisher2;
int df[N_CHISQ];
- int s = 0;
int i;
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)
else
string = var_get_name (pt->vars[1]);
- tab_text (direct, j, 0, TAB_LEFT | TAT_PRINTF,
- gettext (stats_names[j][k]), string);
+ tab_text_format (direct, j, 0, TAB_LEFT,
+ gettext (stats_names[j][k]), string);
}
}
}