- const struct ctables_cell_value *cv = &cell->axes[a].cvs[level->var_idx];
- label = ctables_category_create_value_label (
- t->categories[var_get_dict_index (var)],
- cv->category, var, &cv->value);
- }
- else
- NOT_REACHED ();
-
- if (k == n_levels - 1)
- prev_leaf = pivot_category_create_leaf (parent, label);
- else
- groups[k] = pivot_category_create_group__ (parent, label);
- }
- }
-
- cell->axes[a].leaf = prev_leaf;
- }
- free (sorted);
- free (groups);
- free (levels);
- free (sections);
-
- }
-
- d[a]->hide_all_labels = all_hidden_vlabels (t, a);
- }
-
- {
- size_t n_total_cells = 0;
- for (size_t j = 0; j < t->n_sections; j++)
- n_total_cells += hmap_count (&t->sections[j].cells);
-
- struct ctables_cell **sorted = xnmalloc (n_total_cells, sizeof *sorted);
- size_t n_sorted = 0;
- for (size_t j = 0; j < t->n_sections; j++)
- {
- const struct ctables_section *s = &t->sections[j];
- struct ctables_cell *cell;
- HMAP_FOR_EACH (cell, struct ctables_cell, node, &s->cells)
- if (!cell->hide)
- sorted[n_sorted++] = cell;
- }
- assert (n_sorted <= n_total_cells);
- sort (sorted, n_sorted, sizeof *sorted, ctables_cell_compare_leaf_3way,
- NULL);
- size_t ids[N_CTATS];
- memset (ids, 0, sizeof ids);
- for (size_t j = 0; j < n_sorted; j++)
- {
- struct ctables_cell *cell = sorted[j];
- for (enum ctables_area_type at = 0; at < N_CTATS; at++)
- {
- struct ctables_area *area = cell->areas[at];
- if (!area->sequence)
- area->sequence = ++ids[at];
- }
- }
-
- free (sorted);
- }
-
- for (size_t i = 0; i < t->n_sections; i++)
- {
- struct ctables_section *s = &t->sections[i];
-
- struct ctables_cell *cell;
- HMAP_FOR_EACH (cell, struct ctables_cell, node, &s->cells)
- {
- if (cell->hide)
- continue;
-
- const struct ctables_nest *specs_nest = s->nests[t->summary_axis];
- const struct ctables_summary_spec_set *specs = &specs_nest->specs[cell->sv];
- for (size_t j = 0; j < specs->n; j++)
- {
- size_t dindexes[5];
- size_t n_dindexes = 0;
-
- if (summary_dimension)
- dindexes[n_dindexes++] = specs->specs[j].axis_idx;
-
- if (categories_dimension)
- {
- const struct ctables_nest *clabels_nest = s->nests[t->clabels_from_axis];
- const struct variable *var = clabels_nest->vars[clabels_nest->n - 1];
- const union value *value = &cell->axes[t->clabels_from_axis].cvs[clabels_nest->n - 1].value;
- const struct ctables_value *ctv = ctables_value_find (t, value, var_get_width (var));
- if (!ctv)
- continue;
- dindexes[n_dindexes++] = ctv->leaf;
- }
-
- for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
- if (d[a])
- {
- int leaf = cell->axes[a].leaf;
- if (a == t->summary_axis && !summary_dimension)
- leaf += j;
- dindexes[n_dindexes++] = leaf;
- }
-
- const struct ctables_summary_spec *ss = &specs->specs[j];
-
- struct fmt_spec format = specs->specs[j].format;
- bool is_ctables_format = ss->is_ctables_format;
- double d = (cell->postcompute
- ? ctables_cell_calculate_postcompute (
- s, cell, ss, &format, &is_ctables_format, j)
- : ctables_summary_value (cell, &cell->summaries[j],
- ss));
-
- struct pivot_value *value;
- if (ct->hide_threshold != 0
- && d < ct->hide_threshold
- && ctables_summary_function_is_count (ss->function))
- {
- value = pivot_value_new_user_text_nocopy (
- xasprintf ("<%d", ct->hide_threshold));
- }
- else if (d == 0 && ct->zero)
- value = pivot_value_new_user_text (ct->zero, SIZE_MAX);
- else if (d == SYSMIS && ct->missing)
- value = pivot_value_new_user_text (ct->missing, SIZE_MAX);
- else if (is_ctables_format)
- value = pivot_value_new_user_text_nocopy (
- ctables_format (d, &format, &ct->ctables_formats));
- else
- {
- value = pivot_value_new_number (d);
- value->numeric.format = format;
- }
- /* XXX should text values be right-justified? */
- pivot_table_put (pt, dindexes, n_dindexes, value);
- }
- }
- }
-
- pivot_table_submit (pt);
-}
-
-static bool
-ctables_check_label_position (struct ctables_table *t, enum pivot_axis_type a)
-{
- enum pivot_axis_type label_pos = t->label_axis[a];
- if (label_pos == a)
- return true;
-
- t->clabels_from_axis = a;
-
- const char *subcommand_name = a == PIVOT_AXIS_ROW ? "ROWLABELS" : "COLLABELS";
- const char *pos_name = label_pos == PIVOT_AXIS_LAYER ? "LAYER" : "OPPOSITE";
-
- const struct ctables_stack *stack = &t->stacks[a];
- if (!stack->n)
- return true;
-
- const struct ctables_nest *n0 = &stack->nests[0];
- if (n0->n == 0)
- {
- assert (stack->n == 1);
- return true;
- }
-
- const struct variable *v0 = n0->vars[n0->n - 1];
- struct ctables_categories *c0 = t->categories[var_get_dict_index (v0)];
- t->clabels_example = v0;
-
- for (size_t i = 0; i < c0->n_cats; i++)
- if (c0->cats[i].type == CCT_FUNCTION)
- {
- msg (SE, _("%s=%s is not allowed with sorting based "
- "on a summary function."),
- subcommand_name, pos_name);
- return false;
- }
- if (n0->n - 1 == n0->scale_idx)
- {
- msg (SE, _("%s=%s requires the variables to be moved to be categorical, "
- "but %s is a scale variable."),
- subcommand_name, pos_name, var_get_name (v0));
- return false;
- }
-
- for (size_t i = 1; i < stack->n; i++)
- {
- const struct ctables_nest *ni = &stack->nests[i];
- assert (ni->n > 0);
- const struct variable *vi = ni->vars[ni->n - 1];
- struct ctables_categories *ci = t->categories[var_get_dict_index (vi)];
-
- if (ni->n - 1 == ni->scale_idx)
- {
- msg (SE, _("%s=%s requires the variables to be moved to be "
- "categorical, but %s is a scale variable."),
- subcommand_name, pos_name, var_get_name (vi));
- return false;
- }
- if (var_get_width (v0) != var_get_width (vi))
- {
- msg (SE, _("%s=%s requires the variables to be "
- "moved to have the same width, but %s has "
- "width %d and %s has width %d."),
- subcommand_name, pos_name,
- var_get_name (v0), var_get_width (v0),
- var_get_name (vi), var_get_width (vi));
- return false;
- }
- if (!val_labs_equal (var_get_value_labels (v0),
- var_get_value_labels (vi)))
- {
- msg (SE, _("%s=%s requires the variables to be "
- "moved to have the same value labels, but %s "
- "and %s have different value labels."),
- subcommand_name, pos_name,
- var_get_name (v0), var_get_name (vi));
- return false;
- }
- if (!ctables_categories_equal (c0, ci))
- {
- msg (SE, _("%s=%s requires the variables to be "
- "moved to have the same category "
- "specifications, but %s and %s have different "
- "category specifications."),
- subcommand_name, pos_name,
- var_get_name (v0), var_get_name (vi));
- return false;
- }
- }
-
- return true;
-}
-
-static size_t
-add_sum_var (struct variable *var,
- struct variable ***sum_vars, size_t *n, size_t *allocated)
-{
- for (size_t i = 0; i < *n; i++)
- if (var == (*sum_vars)[i])
- return i;
-
- if (*n >= *allocated)
- *sum_vars = x2nrealloc (*sum_vars, allocated, sizeof **sum_vars);
- (*sum_vars)[*n] = var;
- return (*n)++;
-}
-
-static enum ctables_area_type
-rotate_area (enum ctables_area_type area)
-{
- return area;
- switch (area)
- {
- case CTAT_TABLE:
- case CTAT_LAYER:
- case CTAT_SUBTABLE:
- return area;