-struct ctables_value
- {
- struct hmap_node node;
- union value value;
- int leaf;
- };
-
-struct ctables_occurrence
- {
- struct hmap_node node;
- union value value;
- };
-
-struct ctables_section
- {
- /* Settings. */
- struct ctables_table *table;
- struct ctables_nest *nests[PIVOT_N_AXES];
-
- /* Data. */
- struct hmap *occurrences[PIVOT_N_AXES]; /* "struct ctables_occurrence"s. */
- struct hmap cells; /* Contains "struct ctables_cell"s. */
- struct hmap areas[N_CTATS]; /* Contains "struct ctables_area"s. */
- };
-
-static void ctables_section_uninit (struct ctables_section *);
-
-struct ctables_table
- {
- struct ctables *ctables;
- struct ctables_axis *axes[PIVOT_N_AXES];
- struct ctables_stack stacks[PIVOT_N_AXES];
- struct ctables_section *sections;
- size_t n_sections;
- enum pivot_axis_type summary_axis;
- struct ctables_summary_spec_set summary_specs;
- struct variable **sum_vars;
- size_t n_sum_vars;
-
- enum pivot_axis_type slabels_axis;
- bool slabels_visible;
-
- /* The innermost category labels for axis 'a' appear on axis label_axis[a].
-
- Most commonly, label_axis[a] == a, and in particular we always have
- label_axis{PIVOT_AXIS_LAYER] == PIVOT_AXIS_LAYER.
-
- If ROWLABELS or COLLABELS is specified, then one of
- label_axis[PIVOT_AXIS_ROW] or label_axis[PIVOT_AXIS_COLUMN] can be the
- opposite axis or PIVOT_AXIS_LAYER. Only one of them will differ.
-
- If any category labels are moved, then 'clabels_example' is one of the
- variables being moved (and it is otherwise NULL). All of the variables
- being moved have the same width, value labels, and categories, so this
- example variable can be used to find those out.
-
- The remaining members in this group are relevant only if category labels
- are moved.
-
- 'clabels_values_map' holds a "struct ctables_value" for all the values
- that appear in all of the variables in the moved categories. It is
- accumulated as the data is read. Once the data is fully read, its
- sorted values are put into 'clabels_values' and 'n_clabels_values'.
- */
- enum pivot_axis_type label_axis[PIVOT_N_AXES];
- enum pivot_axis_type clabels_from_axis;
- enum pivot_axis_type clabels_to_axis;
- const struct variable *clabels_example;
- struct hmap clabels_values_map;
- struct ctables_value **clabels_values;
- size_t n_clabels_values;
-
- /* Indexed by variable dictionary index. */
- struct ctables_categories **categories;
- size_t n_categories;
-
- double cilevel;
-
- char *caption;
- char *corner;
- char *title;
-
- struct ctables_chisq *chisq;
- struct ctables_pairwise *pairwise;
- };
-
-struct ctables_categories
- {
- size_t n_refs;
- struct ctables_category *cats;
- size_t n_cats;
- bool show_empty;
- };
-
-struct ctables_category
- {
- enum ctables_category_type
- {
- /* Explicit category lists. */
- CCT_NUMBER,
- CCT_STRING,
- CCT_NRANGE, /* Numerical range. */
- CCT_SRANGE, /* String range. */
- CCT_MISSING,
- CCT_OTHERNM,
- CCT_POSTCOMPUTE,
-
- /* Totals and subtotals. */
- CCT_SUBTOTAL,
- CCT_TOTAL,
-
- /* Implicit category lists. */
- CCT_VALUE,
- CCT_LABEL,
- CCT_FUNCTION,
-
- /* For contributing to TOTALN. */
- CCT_EXCLUDED_MISSING,
- }
- type;
-
- struct ctables_category *subtotal;
-
- bool hide;
-
- union
- {
- double number; /* CCT_NUMBER. */
- struct substring string; /* CCT_STRING, in dictionary encoding. */
- double nrange[2]; /* CCT_NRANGE. */
- struct substring srange[2]; /* CCT_SRANGE. */
-
- struct
- {
- char *total_label; /* CCT_SUBTOTAL, CCT_TOTAL. */
- bool hide_subcategories; /* CCT_SUBTOTAL. */
- };
-
- /* CCT_POSTCOMPUTE. */
- struct
- {
- const struct ctables_postcompute *pc;
- enum fmt_type parse_format;
- };
-
- /* CCT_VALUE, CCT_LABEL, CCT_FUNCTION. */
- struct
- {
- bool include_missing;
- bool sort_ascending;
-
- /* CCT_FUNCTION. */
- enum ctables_summary_function sort_function;
- bool weighted;
- enum ctables_area_type area;
- struct variable *sort_var;
- double percentile;
- };
- };
-
- /* Source location. This is null for CCT_TOTAL, CCT_VALUE, CCT_LABEL,
- CCT_FUNCTION, CCT_EXCLUDED_MISSING. */
- struct msg_location *location;
- };
-
-static void
-ctables_category_uninit (struct ctables_category *cat)
-{
- if (!cat)
- return;
-
- msg_location_destroy (cat->location);
- switch (cat->type)
- {
- case CCT_NUMBER:
- case CCT_NRANGE:
- case CCT_MISSING:
- case CCT_OTHERNM:
- case CCT_POSTCOMPUTE:
- break;
-
- case CCT_STRING:
- ss_dealloc (&cat->string);
- break;
-
- case CCT_SRANGE:
- ss_dealloc (&cat->srange[0]);
- ss_dealloc (&cat->srange[1]);
- break;
-
- case CCT_SUBTOTAL:
- case CCT_TOTAL:
- free (cat->total_label);
- break;
-
- case CCT_VALUE:
- case CCT_LABEL:
- case CCT_FUNCTION:
- break;
-
- case CCT_EXCLUDED_MISSING:
- break;
- }
-}
-
-static bool
-nullable_substring_equal (const struct substring *a,
- const struct substring *b)
-{
- return !a->string ? !b->string : b->string && ss_equals (*a, *b);
-}
-
-static bool
-ctables_category_equal (const struct ctables_category *a,
- const struct ctables_category *b)
-{
- if (a->type != b->type)
- return false;
-
- switch (a->type)
- {
- case CCT_NUMBER:
- return a->number == b->number;
-
- case CCT_STRING:
- return ss_equals (a->string, b->string);
-
- case CCT_NRANGE:
- return a->nrange[0] == b->nrange[0] && a->nrange[1] == b->nrange[1];
-
- case CCT_SRANGE:
- return (nullable_substring_equal (&a->srange[0], &b->srange[0])
- && nullable_substring_equal (&a->srange[1], &b->srange[1]));
-
- case CCT_MISSING:
- case CCT_OTHERNM:
- return true;
-
- case CCT_POSTCOMPUTE:
- return a->pc == b->pc;
-
- case CCT_SUBTOTAL:
- case CCT_TOTAL:
- return !strcmp (a->total_label, b->total_label);
-
- case CCT_VALUE:
- case CCT_LABEL:
- case CCT_FUNCTION:
- return (a->include_missing == b->include_missing
- && a->sort_ascending == b->sort_ascending
- && a->sort_function == b->sort_function
- && a->sort_var == b->sort_var
- && a->percentile == b->percentile);
-
- case CCT_EXCLUDED_MISSING:
- return true;
- }
-
- NOT_REACHED ();
-}
-
-static void
-ctables_categories_unref (struct ctables_categories *c)
-{
- if (!c)
- return;
-
- assert (c->n_refs > 0);
- if (--c->n_refs)
- return;
-
- for (size_t i = 0; i < c->n_cats; i++)
- ctables_category_uninit (&c->cats[i]);
- free (c->cats);
- free (c);
-}
-
-static bool
-ctables_categories_equal (const struct ctables_categories *a,
- const struct ctables_categories *b)
-{
- if (a->n_cats != b->n_cats || a->show_empty != b->show_empty)
- return false;
-
- for (size_t i = 0; i < a->n_cats; i++)
- if (!ctables_category_equal (&a->cats[i], &b->cats[i]))
- return false;
-
- return true;
-}
-
-/* Chi-square test (SIGTEST). */
-struct ctables_chisq
- {
- double alpha;
- bool include_mrsets;
- bool all_visible;
- };
-
-/* Pairwise comparison test (COMPARETEST). */
-struct ctables_pairwise
- {
- enum { PROP, MEAN } type;
- double alpha[2];
- bool include_mrsets;
- bool meansvariance_allcats;
- bool all_visible;
- enum { BONFERRONI = 1, BH } adjust;
- bool merge;
- bool apa_style;
- bool show_sig;
- };
-
-struct ctables_axis
- {
- enum ctables_axis_op
- {
- /* Terminals. */
- CTAO_VAR,
-
- /* Nonterminals. */
- CTAO_STACK, /* + */
- CTAO_NEST, /* > */
- }
- op;
-
- union
- {
- /* Terminals. */
- struct
- {
- struct variable *var;
- bool scale;
- struct ctables_summary_spec_set specs[N_CSVS];
- };
-
- /* Nonterminals. */
- struct ctables_axis *subs[2];
- };
-
- struct msg_location *loc;
- };
-
-static void ctables_axis_destroy (struct ctables_axis *);
-
-struct ctables_summary_spec
- {
- /* The calculation to be performed.
-
- 'function' is the function to calculate. 'weighted' specifies whether
- to use weighted or unweighted data (for functions that do not support a
- choice, it must be true). 'calc_area' is the area over which the
- calculation takes place (for functions that target only an individual
- cell, it must be 0). For CTSF_PTILE only, 'percentile' is the
- percentile between 0 and 100 (for other functions it must be 0). */
- enum ctables_summary_function function;
- bool weighted;
- enum ctables_area_type calc_area;
- double percentile; /* CTSF_PTILE only. */
-
- /* How to display the result of the calculation.
-
- 'label' is a user-specified label, NULL if the user didn't specify
- one.
-
- 'user_area' is usually the same as 'calc_area', but when category labels
- are rotated from one axis to another it swaps rows and columns.
-
- 'format' is the format for displaying the output. If
- 'is_ctables_format' is true, then 'format.type' is one of the special
- CTEF_* formats instead of the standard ones. */
- char *label;
- enum ctables_area_type user_area;
- struct fmt_spec format;
- bool is_ctables_format; /* Is 'format' one of CTEF_*? */
-
- size_t axis_idx;
- size_t sum_var_idx;
- };
-
-static void
-ctables_summary_spec_clone (struct ctables_summary_spec *dst,
- const struct ctables_summary_spec *src)
-{
- *dst = *src;
- dst->label = xstrdup_if_nonnull (src->label);
-}
-
-static void
-ctables_summary_spec_uninit (struct ctables_summary_spec *s)
-{
- if (s)
- free (s->label);
-}
-
-static void
-ctables_summary_spec_set_clone (struct ctables_summary_spec_set *dst,
- const struct ctables_summary_spec_set *src)
-{
- struct ctables_summary_spec *specs
- = (src->n ? xnmalloc (src->n, sizeof *specs) : NULL);
- for (size_t i = 0; i < src->n; i++)
- ctables_summary_spec_clone (&specs[i], &src->specs[i]);
-
- *dst = (struct ctables_summary_spec_set) {
- .specs = specs,
- .n = src->n,
- .allocated = src->n,
- .var = src->var,
- .is_scale = src->is_scale,
- };
-}
-
-static void
-ctables_summary_spec_set_uninit (struct ctables_summary_spec_set *set)
-{
- for (size_t i = 0; i < set->n; i++)
- ctables_summary_spec_uninit (&set->specs[i]);
- free (set->listwise_vars);
- free (set->specs);
-}
-
-static bool
-parse_col_width (struct lexer *lexer, const char *name, double *width)
-{
- lex_match (lexer, T_EQUALS);
- if (lex_match_id (lexer, "DEFAULT"))
- *width = SYSMIS;
- else if (lex_force_num_range_closed (lexer, name, 0, DBL_MAX))
- {
- *width = lex_number (lexer);
- lex_get (lexer);
- }
- else
- return false;
-
- return true;
-}
-
-static bool
-parse_bool (struct lexer *lexer, bool *b)
-{
- if (lex_match_id (lexer, "NO"))
- *b = false;
- else if (lex_match_id (lexer, "YES"))
- *b = true;
- else
- {
- lex_error_expecting (lexer, "YES", "NO");
- return false;
- }
- return true;
-}
-
-static enum ctables_function_availability
-ctables_function_availability (enum ctables_summary_function f)
-{
- static enum ctables_function_availability availability[] = {
-#define S(ENUM, NAME, TYPE, FORMAT, AVAILABILITY) [ENUM] = AVAILABILITY,
-#include "ctables.inc"
-#undef S
- };
-
- return availability[f];
-}