+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->percentile != bs->percentile)
+ return as->percentile < bs->percentile ? 1 : -1;
+ return strcmp (as->label, bs->label);
+}
+
+static void
+ctables_table_output_same_axis (struct ctables *ct, struct ctables_table *t)
+{
+ struct pivot_table *pt = pivot_table_create__ (
+ (t->title
+ ? pivot_value_new_user_text (t->title, SIZE_MAX)
+ : pivot_value_new_text (N_("Custom Tables"))),
+ "Custom Tables");
+ if (t->caption)
+ pivot_table_set_caption (
+ pt, pivot_value_new_user_text (t->caption, SIZE_MAX));
+ if (t->corner)
+ pivot_table_set_caption (
+ pt, pivot_value_new_user_text (t->corner, SIZE_MAX));
+
+ pivot_table_set_look (pt, ct->look);
+ struct pivot_dimension *d[PIVOT_N_AXES];
+ for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
+ {
+ static const char *names[] = {
+ [PIVOT_AXIS_ROW] = N_("Rows"),
+ [PIVOT_AXIS_COLUMN] = N_("Columns"),
+ [PIVOT_AXIS_LAYER] = N_("Layers"),
+ };
+ d[a] = (t->axes[a] || a == t->summary_axis
+ ? pivot_dimension_create (pt, a, names[a])
+ : NULL);
+ if (!d[a])
+ continue;
+
+ assert (t->axes[a]);
+
+ struct ctables_cell **sorted = xnmalloc (t->cells.count, sizeof *sorted);
+
+ struct ctables_cell *cell;
+ size_t n = 0;
+ HMAP_FOR_EACH (cell, struct ctables_cell, node, &t->cells)
+ if (!cell->hide)
+ sorted[n++] = cell;
+ assert (n <= t->cells.count);
+
+ struct ctables_cell_sort_aux aux = { .t = t, .a = a };
+ sort (sorted, n, sizeof *sorted, ctables_cell_compare_3way, &aux);
+
+ size_t max_depth = 0;
+ for (size_t j = 0; j < t->stacks[a].n; j++)
+ if (t->stacks[a].nests[j].n > max_depth)
+ max_depth = t->stacks[a].nests[j].n;
+
+ struct pivot_category **groups = xnmalloc (max_depth, sizeof *groups);
+ struct pivot_category *top = NULL;
+ int prev_leaf = 0;
+ for (size_t j = 0; j < n; j++)
+ {
+ struct ctables_cell *cell = sorted[j];
+ const struct ctables_nest *nest = &t->stacks[a].nests[cell->axes[a].stack_idx];
+
+ size_t n_common = 0;
+ bool new_subtable = false;
+ if (j > 0)
+ {
+ struct ctables_cell *prev = sorted[j - 1];
+ if (prev->axes[a].stack_idx == cell->axes[a].stack_idx)