-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 d_weight, double e_weight)
-{
- const struct ctables_category *cats[PIVOT_N_AXES][10]; /* XXX */
-
- /* Does at least one categorical variable have a missing value in an included
- or excluded category? */
- bool is_missing = false;
-
- /* Does at least one categorical variable have a missing value in an excluded
- category? */
- bool excluded_missing = false;
-
- 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)
- continue;
-
- const struct variable *var = nest->vars[i];
- const union value *value = case_data (c, var);
-
- bool var_missing = var_is_value_missing (var, value) != 0;
- if (var_missing)
- is_missing = true;
-
- cats[a][i] = ctables_categories_match (
- s->table->categories[var_get_dict_index (var)], value, var);
- if (!cats[a][i])
- {
- if (!var_missing)
- return;
-
- static const struct ctables_category cct_excluded_missing = {
- .type = CCT_EXCLUDED_MISSING,
- .hide = true,
- };
- cats[a][i] = &cct_excluded_missing;
- excluded_missing = true;
- }
- }
- }
-
- if (!excluded_missing)
- 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_missing, excluded_missing,
- d_weight, e_weight);
-
- //if (!excluded_missing)
- {
- recurse_totals (s, c, cats, is_missing, excluded_missing,
- d_weight, e_weight, 0, 0);
- recurse_subtotals (s, c, cats, is_missing, excluded_missing,
- d_weight, e_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->weighted != bs->weighted)
- return as->weighted > bs->weighted ? 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;
- }
-
- return false;
-}
-
-static struct pivot_value *
-ctables_postcompute_label (const struct ctables_categories *cats,
- const struct ctables_category *cat,
- const struct variable *var)