- ctables_cell_add__ (s, c, cats, is_included, weight);
- recurse_totals (s, c, cats, is_included, weight, a, i + 1);
- cats[a][i] = save;
- }
- }
- start_nest = 0;
- }
-}
-
-static void
-recurse_subtotals (struct ctables_section *s, const struct ccase *c,
- const struct ctables_category **cats[PIVOT_N_AXES],
- bool is_included, double weight[N_CTWS],
- enum pivot_axis_type start_axis, size_t start_nest)
-{
- for (enum pivot_axis_type a = start_axis; a < PIVOT_N_AXES; a++)
- {
- const struct ctables_nest *nest = s->nests[a];
- for (size_t i = start_nest; i < nest->n; i++)
- {
- if (i == nest->scale_idx)
- continue;
-
- const struct ctables_category *save = cats[a][i];
- if (save->subtotal)
- {
- cats[a][i] = save->subtotal;
- ctables_cell_add__ (s, c, cats, is_included, weight);
- recurse_subtotals (s, c, cats, is_included, weight, a, i + 1);
- cats[a][i] = save;
- }
- }
- start_nest = 0;
- }
-}
-
-static void
-ctables_add_occurrence (const struct variable *var,
- const union value *value,
- struct hmap *occurrences)
-{
- int width = var_get_width (var);
- unsigned int hash = value_hash (value, width, 0);
-
- struct ctables_occurrence *o;
- HMAP_FOR_EACH_WITH_HASH (o, struct ctables_occurrence, node, hash,
- occurrences)
- if (value_equal (value, &o->value, width))
- return;
-
- o = xmalloc (sizeof *o);
- value_clone (&o->value, value, width);
- hmap_insert (occurrences, &o->node, hash);
-}
-
-static void
-ctables_cell_insert (struct ctables_section *s, const struct ccase *c,
- double weight[N_CTWS])
-{
- const struct ctables_category *layer_cats[s->nests[PIVOT_AXIS_LAYER]->n];
- const struct ctables_category *row_cats[s->nests[PIVOT_AXIS_ROW]->n];
- const struct ctables_category *column_cats[s->nests[PIVOT_AXIS_COLUMN]->n];
- const struct ctables_category **cats[PIVOT_N_AXES] =
- {
- [PIVOT_AXIS_LAYER] = layer_cats,
- [PIVOT_AXIS_ROW] = row_cats,
- [PIVOT_AXIS_COLUMN] = column_cats,
- };
-
- bool is_included = true;
-
- for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
- {
- const struct ctables_nest *nest = s->nests[a];
- for (size_t i = 0; i < nest->n; i++)
- if (i != nest->scale_idx)
- {
- const struct variable *var = nest->vars[i];
- const union value *value = case_data (c, var);
-
- cats[a][i] = ctables_categories_match (
- s->table->categories[var_get_dict_index (var)], value, var);
- if (!cats[a][i])
- {
- if (i != nest->summary_idx)
- return;
-
- if (!var_is_value_missing (var, value))
- return;
-
- static const struct ctables_category cct_excluded_missing = {
- .type = CCT_EXCLUDED_MISSING,
- .hide = true,
- };
- cats[a][i] = &cct_excluded_missing;
- is_included = false;
- }
- }
- }
-
- if (is_included)
- for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
- {
- const struct ctables_nest *nest = s->nests[a];
- for (size_t i = 0; i < nest->n; i++)
- if (i != nest->scale_idx)
- {
- const struct variable *var = nest->vars[i];
- const union value *value = case_data (c, var);
- ctables_add_occurrence (var, value, &s->occurrences[a][i]);
- }
- }
-
- ctables_cell_add__ (s, c, cats, is_included, weight);
- recurse_totals (s, c, cats, is_included, weight, 0, 0);
- recurse_subtotals (s, c, cats, is_included, weight, 0, 0);
-}
-
-struct merge_item
- {
- const struct ctables_summary_spec_set *set;
- size_t ofs;
- };
-
-static int
-merge_item_compare_3way (const struct merge_item *a, const struct merge_item *b)
-{
- const struct ctables_summary_spec *as = &a->set->specs[a->ofs];
- const struct ctables_summary_spec *bs = &b->set->specs[b->ofs];
- if (as->function != bs->function)
- return as->function > bs->function ? 1 : -1;
- else if (as->weighting != bs->weighting)
- return as->weighting > bs->weighting ? 1 : -1;
- else if (as->calc_area != bs->calc_area)
- return as->calc_area > bs->calc_area ? 1 : -1;
- else if (as->percentile != bs->percentile)
- return as->percentile < bs->percentile ? 1 : -1;
-
- const char *as_label = as->label ? as->label : "";
- const char *bs_label = bs->label ? bs->label : "";
- return strcmp (as_label, bs_label);
-}
-
-static void
-ctables_category_format_number (double number, const struct variable *var,
- struct string *s)
-{
- struct pivot_value *pv = pivot_value_new_var_value (
- var, &(union value) { .f = number });
- pivot_value_format (pv, NULL, s);
- pivot_value_destroy (pv);
-}
-
-static void
-ctables_category_format_string (struct substring string,
- const struct variable *var, struct string *out)
-{
- int width = var_get_width (var);
- char *s = xmalloc (width);
- buf_copy_rpad (s, width, string.string, string.length, ' ');
- struct pivot_value *pv = pivot_value_new_var_value (
- var, &(union value) { .s = CHAR_CAST (uint8_t *, s) });
- pivot_value_format (pv, NULL, out);
- pivot_value_destroy (pv);
- free (s);
-}
-
-static bool
-ctables_category_format_label (const struct ctables_category *cat,
- const struct variable *var,
- struct string *s)
-{
- switch (cat->type)
- {
- case CCT_NUMBER:
- ctables_category_format_number (cat->number, var, s);
- return true;
-
- case CCT_STRING:
- ctables_category_format_string (cat->string, var, s);
- return true;
-
- case CCT_NRANGE:
- ctables_category_format_number (cat->nrange[0], var, s);
- ds_put_format (s, " THRU ");
- ctables_category_format_number (cat->nrange[1], var, s);
- return true;
-
- case CCT_SRANGE:
- ctables_category_format_string (cat->srange[0], var, s);
- ds_put_format (s, " THRU ");
- ctables_category_format_string (cat->srange[1], var, s);
- return true;
-
- case CCT_MISSING:
- ds_put_cstr (s, "MISSING");
- return true;
-
- case CCT_OTHERNM:
- ds_put_cstr (s, "OTHERNM");
- return true;
-
- case CCT_POSTCOMPUTE:
- ds_put_format (s, "&%s", cat->pc->name);
- return true;
-
- case CCT_TOTAL:
- case CCT_SUBTOTAL:
- ds_put_cstr (s, cat->total_label);
- return true;
-
- case CCT_VALUE:
- case CCT_LABEL:
- case CCT_FUNCTION:
- case CCT_EXCLUDED_MISSING:
- return false;