1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2017, 2018 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "output/pivot-table.h"
23 #include "data/data-out.h"
24 #include "data/settings.h"
25 #include "data/value.h"
26 #include "data/variable.h"
27 #include "libpspp/hash-functions.h"
28 #include "libpspp/i18n.h"
29 #include "output/driver.h"
31 #include "gl/c-ctype.h"
32 #include "gl/intprops.h"
33 #include "gl/minmax.h"
34 #include "gl/xalloc.h"
35 #include "gl/xmemdup0.h"
39 #define _(msgid) gettext (msgid)
40 #define N_(msgid) msgid
42 static const struct fmt_spec *pivot_table_get_format (
43 const struct pivot_table *, const char *s);
45 /* Pivot table display styling. */
47 /* Returns the name of AREA. */
49 pivot_area_to_string (enum pivot_area area)
53 case PIVOT_AREA_TITLE: return "title";
54 case PIVOT_AREA_CAPTION: return "caption";
55 case PIVOT_AREA_FOOTER: return "footer";
56 case PIVOT_AREA_CORNER: return "corner";
57 case PIVOT_AREA_COLUMN_LABELS: return "column labels";
58 case PIVOT_AREA_ROW_LABELS: return "row labels";
59 case PIVOT_AREA_DATA: return "data";
60 case PIVOT_AREA_LAYERS: return "layers";
61 case PIVOT_N_AREAS: default: return "**error**";
65 /* Returns the name of BORDER. */
67 pivot_border_to_string (enum pivot_border border)
71 case PIVOT_BORDER_TITLE:
74 case PIVOT_BORDER_OUTER_LEFT:
75 return "left outer frame";
76 case PIVOT_BORDER_OUTER_TOP:
77 return "top outer frame";
78 case PIVOT_BORDER_OUTER_RIGHT:
79 return "right outer frame";
80 case PIVOT_BORDER_OUTER_BOTTOM:
81 return "bottom outer frame";
83 case PIVOT_BORDER_INNER_LEFT:
84 return "left inner frame";
85 case PIVOT_BORDER_INNER_TOP:
86 return "top inner frame";
87 case PIVOT_BORDER_INNER_RIGHT:
88 return "right inner frame";
89 case PIVOT_BORDER_INNER_BOTTOM:
90 return "bottom inner frame";
92 case PIVOT_BORDER_DATA_LEFT:
93 return "data area left";
94 case PIVOT_BORDER_DATA_TOP:
95 return "data area top";
97 case PIVOT_BORDER_DIM_ROW_HORZ:
98 return "row label horizontal dimension border";
99 case PIVOT_BORDER_DIM_ROW_VERT:
100 return "row label vertical dimension border";
101 case PIVOT_BORDER_DIM_COL_HORZ:
102 return "column label horizontal dimension border";
103 case PIVOT_BORDER_DIM_COL_VERT:
104 return "column label vertical dimension border";
106 case PIVOT_BORDER_CAT_ROW_HORZ:
107 return "row label horizontal category border";
108 case PIVOT_BORDER_CAT_ROW_VERT:
109 return "row label vertical category border";
110 case PIVOT_BORDER_CAT_COL_HORZ:
111 return "column label horizontal category border";
112 case PIVOT_BORDER_CAT_COL_VERT:
113 return "column label vertical category border";
115 case PIVOT_N_BORDERS:
122 pivot_table_sizing_uninit (struct pivot_table_sizing *sizing)
126 free (sizing->widths);
127 free (sizing->breaks);
128 free (sizing->keeps);
132 /* Pivot table looks. */
134 const struct pivot_table_look *
135 pivot_table_look_builtin_default (void)
137 static struct pivot_table_look look = {
141 .row_labels_in_corner = true,
143 [TABLE_HORZ] = { 36, 72 },
144 [TABLE_VERT] = { 36, 120 },
148 #define AREA(BOLD, H, V, L, R, T, B) { \
150 .halign = TABLE_HALIGN_##H, \
151 .valign = TABLE_VALIGN_##V, \
152 .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
153 [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
157 .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
158 .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
160 .typeface = (char *) "Sans Serif", \
163 [PIVOT_AREA_TITLE] = AREA(true, CENTER, CENTER, 8,11,1,8),
164 [PIVOT_AREA_CAPTION] = AREA(false, LEFT, TOP, 8,11,1,1),
165 [PIVOT_AREA_FOOTER] = AREA(false, LEFT, TOP, 11, 8,2,3),
166 [PIVOT_AREA_CORNER] = AREA(false, LEFT, BOTTOM, 8,11,1,1),
167 [PIVOT_AREA_COLUMN_LABELS] = AREA(false, CENTER, BOTTOM, 8,11,1,3),
168 [PIVOT_AREA_ROW_LABELS] = AREA(false, LEFT, TOP, 8,11,1,3),
169 [PIVOT_AREA_DATA] = AREA(false, MIXED, TOP, 8,11,1,1),
170 [PIVOT_AREA_LAYERS] = AREA(false, LEFT, BOTTOM, 8,11,1,3),
175 #define BORDER(STROKE) { .stroke = STROKE, .color = CELL_COLOR_BLACK }
176 [PIVOT_BORDER_TITLE] = BORDER(TABLE_STROKE_NONE),
177 [PIVOT_BORDER_OUTER_LEFT] = BORDER(TABLE_STROKE_NONE),
178 [PIVOT_BORDER_OUTER_TOP] = BORDER(TABLE_STROKE_NONE),
179 [PIVOT_BORDER_OUTER_RIGHT] = BORDER(TABLE_STROKE_NONE),
180 [PIVOT_BORDER_OUTER_BOTTOM] = BORDER(TABLE_STROKE_NONE),
181 [PIVOT_BORDER_INNER_LEFT] = BORDER(TABLE_STROKE_THICK),
182 [PIVOT_BORDER_INNER_TOP] = BORDER(TABLE_STROKE_THICK),
183 [PIVOT_BORDER_INNER_RIGHT] = BORDER(TABLE_STROKE_THICK),
184 [PIVOT_BORDER_INNER_BOTTOM] = BORDER(TABLE_STROKE_THICK),
185 [PIVOT_BORDER_DATA_LEFT] = BORDER(TABLE_STROKE_THICK),
186 [PIVOT_BORDER_DATA_TOP] = BORDER(TABLE_STROKE_THICK),
187 [PIVOT_BORDER_DIM_ROW_HORZ] = BORDER(TABLE_STROKE_SOLID),
188 [PIVOT_BORDER_DIM_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
189 [PIVOT_BORDER_DIM_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
190 [PIVOT_BORDER_DIM_COL_VERT] = BORDER(TABLE_STROKE_SOLID),
191 [PIVOT_BORDER_CAT_ROW_HORZ] = BORDER(TABLE_STROKE_NONE),
192 [PIVOT_BORDER_CAT_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
193 [PIVOT_BORDER_CAT_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
194 [PIVOT_BORDER_CAT_COL_VERT] = BORDER(TABLE_STROKE_SOLID),
201 struct pivot_table_look *
202 pivot_table_look_new_builtin_default (void)
204 return pivot_table_look_unshare (
205 pivot_table_look_ref (pivot_table_look_builtin_default ()));
208 struct pivot_table_look *
209 pivot_table_look_ref (const struct pivot_table_look *look_)
211 assert (look_->ref_cnt > 0);
213 struct pivot_table_look *look = CONST_CAST (struct pivot_table_look *, look_);
219 xstrdup_if_nonempty (const char *s)
221 return s && s[0] ? xstrdup (s) : NULL;
224 struct pivot_table_look *
225 pivot_table_look_unshare (struct pivot_table_look *old)
227 assert (old->ref_cnt > 0);
228 if (old->ref_cnt == 1)
231 pivot_table_look_unref (old);
233 struct pivot_table_look *new = xmemdup (old, sizeof *old);
235 new->name = xstrdup_if_nonempty (old->name);
236 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
237 table_area_style_copy (NULL, &new->areas[i], &old->areas[i]);
238 new->continuation = xstrdup_if_nonempty (old->continuation);
244 pivot_table_look_unref (struct pivot_table_look *look)
248 assert (look->ref_cnt > 0);
249 if (!--look->ref_cnt)
252 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
253 table_area_style_uninit (&look->areas[i]);
254 free (look->continuation);
262 /* Returns the name of AXIS_TYPE. */
264 pivot_axis_type_to_string (enum pivot_axis_type axis_type)
268 case PIVOT_AXIS_LAYER:
274 case PIVOT_AXIS_COLUMN:
282 static enum pivot_axis_type
283 pivot_axis_type_transpose (enum pivot_axis_type axis_type)
285 assert (axis_type == PIVOT_AXIS_ROW || axis_type == PIVOT_AXIS_COLUMN);
286 return (axis_type == PIVOT_AXIS_ROW ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW);
289 /* Implementation of PIVOT_AXIS_FOR_EACH. */
291 pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis)
295 if (axis->n_dimensions)
296 for (size_t i = 0; i < axis->n_dimensions; i++)
297 if (axis->dimensions[i]->n_leaves == 0)
300 return xcalloc (axis->n_dimensions, sizeof *indexes);
303 for (size_t i = 0; i < axis->n_dimensions; i++)
305 const struct pivot_dimension *d = axis->dimensions[i];
306 if (++indexes[i] < d->n_leaves)
319 pivot_category_set_rc (struct pivot_category *category, const char *s)
321 const struct fmt_spec *format = pivot_table_get_format (
322 category->dimension->table, s);
324 category->format = *format;
328 pivot_category_create_leaves_valist (struct pivot_category *parent,
332 while ((s = va_arg (args, const char *)))
334 if (!strncmp (s, "RC_", 3))
336 assert (parent->n_subs);
337 pivot_category_set_rc (parent->subs[parent->n_subs - 1], s);
340 pivot_category_create_leaf (parent, pivot_value_new_text (s));
344 /* Creates a new dimension with the given NAME in TABLE and returns it. The
345 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
348 NAME should be a translatable name, but not actually translated yet,
349 e.g. enclosed in N_(). To use a different kind of value for a name, use
350 pivot_dimension_create__() instead.
352 The optional varargs parameters may be used to add an initial set of
353 categories to the dimension. Each string should be a translatable category
354 name, but not actually translated yet, e.g. enclosed in N_(). Each string
355 may optionally be followod by a PIVOT_RC_* string that specifies the default
356 numeric format for cells in this category. */
357 struct pivot_dimension * SENTINEL (0)
358 (pivot_dimension_create) (struct pivot_table *table,
359 enum pivot_axis_type axis_type,
360 const char *name, ...)
362 struct pivot_dimension *d = pivot_dimension_create__ (
363 table, axis_type, pivot_value_new_text (name));
366 va_start (args, name);
367 pivot_category_create_leaves_valist (d->root, args);
373 /* Creates a new dimension with the given NAME in TABLE and returns it. The
374 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
376 struct pivot_dimension *
377 pivot_dimension_create__ (struct pivot_table *table,
378 enum pivot_axis_type axis_type,
379 struct pivot_value *name)
381 assert (pivot_table_is_empty (table));
383 struct pivot_dimension *d = xmalloc (sizeof *d);
384 *d = (struct pivot_dimension) {
386 .axis_type = axis_type,
387 .level = table->axes[axis_type].n_dimensions,
388 .top_index = table->n_dimensions,
389 .root = xmalloc (sizeof *d->root),
392 struct pivot_category *root = d->root;
393 *root = (struct pivot_category) {
398 .data_index = SIZE_MAX,
399 .presentation_index = SIZE_MAX,
402 table->dimensions = xrealloc (
403 table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions);
404 table->dimensions[table->n_dimensions++] = d;
406 struct pivot_axis *axis = &table->axes[axis_type];
407 axis->dimensions = xrealloc (
408 axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
409 axis->dimensions[axis->n_dimensions++] = d;
411 if (axis_type == PIVOT_AXIS_LAYER)
413 free (table->current_layer);
414 table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
415 sizeof *table->current_layer);
418 /* axis->extent and axis->label_depth will be calculated later. */
424 pivot_dimension_destroy (struct pivot_dimension *d)
429 pivot_category_destroy (d->root);
430 free (d->data_leaves);
431 free (d->presentation_leaves);
435 /* Returns the first leaf node in an in-order traversal that is a child of
437 static const struct pivot_category * UNUSED
438 pivot_category_first_leaf (const struct pivot_category *cat)
440 if (pivot_category_is_leaf (cat))
443 for (size_t i = 0; i < cat->n_subs; i++)
445 const struct pivot_category *first
446 = pivot_category_first_leaf (cat->subs[i]);
454 /* Returns the next leaf node in an in-order traversal starting at CAT, which
456 static const struct pivot_category * UNUSED
457 pivot_category_next_leaf (const struct pivot_category *cat)
459 assert (pivot_category_is_leaf (cat));
463 const struct pivot_category *parent = cat->parent;
466 for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
468 const struct pivot_category *next
469 = pivot_category_first_leaf (parent->subs[i]);
479 pivot_category_add_child (struct pivot_category *child)
481 struct pivot_category *parent = child->parent;
483 assert (pivot_category_is_group (parent));
484 if (parent->n_subs >= parent->allocated_subs)
485 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
486 sizeof *parent->subs);
487 parent->subs[parent->n_subs++] = child;
490 /* Adds leaf categories as a child of PARENT. To create top-level categories
491 within dimension 'd', pass 'd->root' for PARENT.
493 Each of the varargs parameters should be a string, each of which should be a
494 translatable category name, but not actually translated yet, e.g. enclosed
495 in N_(). Each string may optionally be followod by a PIVOT_RC_* string that
496 specifies the default numeric format for cells in this category.
498 Returns the category index, which is just a 0-based array index, for the
501 Leaves have to be created in in-order, that is, don't create a group and add
502 some leaves, then add leaves outside the group and try to add more leaves
505 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
507 int retval = parent->dimension->n_leaves;
510 va_start (args, parent);
511 pivot_category_create_leaves_valist (parent, args);
517 /* Creates a new leaf category with the given NAME as a child of PARENT. To
518 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
519 Returns the category index, which is just a 0-based array index, for the new
522 Leaves have to be created in in-order, that is, don't create a group and add
523 some leaves, then add leaves outside the group and try to add more leaves
526 pivot_category_create_leaf (struct pivot_category *parent,
527 struct pivot_value *name)
529 return pivot_category_create_leaf_rc (parent, name, NULL);
532 /* Creates a new leaf category with the given NAME as a child of PARENT. To
533 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
534 Returns the category index, which is just a 0-based array index, for the new
537 If RC is nonnull and the name of a result category, the category is assigned
538 that result category.
540 Leaves have to be created in in-order, that is, don't create a group and add
541 some leaves, then add leaves outside the group and try to add more leaves
544 pivot_category_create_leaf_rc (struct pivot_category *parent,
545 struct pivot_value *name, const char *rc)
547 struct pivot_dimension *d = parent->dimension;
549 struct pivot_category *leaf = xmalloc (sizeof *leaf);
550 *leaf = (struct pivot_category) {
554 .group_index = parent->n_subs,
555 .data_index = d->n_leaves,
556 .presentation_index = d->n_leaves,
559 if (d->n_leaves >= d->allocated_leaves)
561 d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
562 sizeof *d->data_leaves);
563 d->presentation_leaves = xrealloc (
564 d->presentation_leaves,
565 d->allocated_leaves * sizeof *d->presentation_leaves);
568 d->data_leaves[d->n_leaves] = leaf;
569 d->presentation_leaves[d->n_leaves] = leaf;
572 pivot_category_add_child (leaf);
574 /* Make sure that the new child is the last in in-order. */
575 assert (!pivot_category_next_leaf (leaf));
577 pivot_category_set_rc (leaf, rc);
579 return leaf->data_index;
582 /* Adds a new category group named NAME as a child of PARENT. To create a
583 top-level group within dimension 'd', pass 'd->root' for PARENT.
585 NAME should be a translatable name, but not actually translated yet,
586 e.g. enclosed in N_(). To use a different kind of value for a name, use
587 pivot_category_create_group__() instead.
589 The optional varargs parameters may be used to add an initial set of
590 categories to the group. Each string should be a translatable category
591 name, but not actually translated yet, e.g. enclosed in N_(). Each string
592 may optionally be followod by a PIVOT_RC_* string that specifies the default
593 numeric format for cells in this category.
595 Returns the new group. */
596 struct pivot_category * SENTINEL (0)
597 (pivot_category_create_group) (struct pivot_category *parent,
598 const char *name, ...)
600 struct pivot_category *group = pivot_category_create_group__ (
601 parent, pivot_value_new_text (name));
604 va_start (args, name);
605 pivot_category_create_leaves_valist (group, args);
611 /* Adds a new category group named NAME as a child of PARENT. To create a
612 top-level group within dimension 'd', pass 'd->root' for PARENT. Returns
614 struct pivot_category *
615 pivot_category_create_group__ (struct pivot_category *parent,
616 struct pivot_value *name)
618 struct pivot_dimension *d = parent->dimension;
620 struct pivot_category *group = xmalloc (sizeof *group);
621 *group = (struct pivot_category) {
626 .group_index = parent->n_subs,
627 .data_index = SIZE_MAX,
628 .presentation_index = SIZE_MAX,
631 pivot_category_add_child (group);
637 pivot_category_destroy (struct pivot_category *c)
642 pivot_value_destroy (c->name);
643 for (size_t i = 0; i < c->n_subs; i++)
644 pivot_category_destroy (c->subs[i]);
651 These are usually the easiest way to control the formatting of numeric data
652 in a pivot table. See pivot_dimension_create() for an explanation of their
656 const char *name; /* "RC_*". */
657 struct fmt_spec format;
660 /* Formats for most of the result classes. */
661 static struct result_class result_classes[] =
663 { PIVOT_RC_INTEGER, { FMT_F, 40, 0 } },
664 { PIVOT_RC_PERCENT, { FMT_PCT, 40, 1 } },
665 { PIVOT_RC_CORRELATION, { FMT_F, 40, 3 } },
666 { PIVOT_RC_SIGNIFICANCE, { FMT_F, 40, 3 } },
667 { PIVOT_RC_RESIDUAL, { FMT_F, 40, 2 } },
668 { PIVOT_RC_COUNT, { 0, 0, 0 } },
669 { PIVOT_RC_OTHER, { 0, 0, 0 } },
672 /* Has PIVOT_RC_COUNT been overridden by the user? */
673 static bool overridden_count_format;
675 static struct result_class *
676 pivot_result_class_find (const char *s)
678 for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
679 if (!strcmp (s, result_classes[i].name))
680 return &result_classes[i];
684 static const struct fmt_spec *
685 pivot_table_get_format (const struct pivot_table *table, const char *s)
689 else if (!strcmp (s, PIVOT_RC_OTHER))
690 return settings_get_format ();
691 else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
692 return &table->weight_format;
695 const struct result_class *rc = pivot_result_class_find (s);
696 return rc ? &rc->format : NULL;
700 /* Sets the format specification for the result class named S (which should not
701 include the RC_ prefix) to *FORMAT. Returns true if successful, false if S
702 does not name a known result class. */
704 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
706 char *s = xasprintf ("RC_%s", s_);
707 struct result_class *rc = pivot_result_class_find (s);
710 rc->format = *format;
711 if (!strcmp (s, PIVOT_RC_COUNT))
712 overridden_count_format = true;
721 /* Creates and returns a new pivot table with the given TITLE. TITLE should be
722 a text string marked for translation but not actually translated yet,
723 e.g. N_("Descriptive Statistics"). The un-translated text string is used as
724 the pivot table's subtype.
726 Operations commonly performed on the new pivot_table:
728 - If empty rows or columns should not be displayed, set ->omit_empty to
731 - Set the format to use for "count" values with pivot_table_set_weight_var()
732 or pivot_table_set_weight_format().
734 This function is a shortcut for pivot_table_create__() for the most common
735 case. Use pivot_table_create__() directly if the title should be some kind
736 of value other than an ordinary text string, or if the subtype should be
737 different from the title.
739 See the large comment at the top of pivot-table.h for general advice on
740 creating pivot tables. */
742 pivot_table_create (const char *title)
744 return pivot_table_create__ (pivot_value_new_text (title), title);
747 /* Creates and returns a new pivot table with the given TITLE, and takes
748 ownership of TITLE. The new pivot table's subtype is SUBTYPE, which
749 should be an untranslated English string that describes the contents of
750 the table at a high level without being specific about the variables or
751 other context involved.
753 Operations commonly performed on the new pivot_table:
755 - If empty rows or columns should not be displayed, set ->omit_empty to
758 - Set the format to use for "count" values with pivot_table_set_weight_var()
759 or pivot_table_set_weight_format().
761 See the large comment at the top of pivot-table.h for general advice on
762 creating pivot tables. */
764 pivot_table_create__ (struct pivot_value *title, const char *subtype)
766 struct pivot_table *table = xzalloc (sizeof *table);
768 table->show_caption = true;
769 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
770 table->title = title;
771 table->subtype = subtype ? pivot_value_new_text (subtype) : NULL;
772 table->command_c = output_get_command_name ();
773 table->look = pivot_table_look_ref (pivot_table_look_builtin_default ());
775 hmap_init (&table->cells);
780 /* Creates and returns a new pivot table with the given TITLE and a single cell
781 with the given CONTENT.
783 This is really just for error handling. */
785 pivot_table_create_for_text (struct pivot_value *title,
786 struct pivot_value *content)
788 struct pivot_table *table = pivot_table_create__ (title, "Error");
790 struct pivot_dimension *d = pivot_dimension_create (
791 table, PIVOT_AXIS_ROW, N_("Error"));
792 d->hide_all_labels = true;
793 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
795 pivot_table_put1 (table, 0, content);
800 /* Increases TABLE's reference count, indicating that it has an additional
801 owner. A pivot table that is shared among multiple owners must not be
804 pivot_table_ref (const struct pivot_table *table_)
806 struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
811 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
812 If TABLE no longer has any owners, it is freed. */
814 pivot_table_unref (struct pivot_table *table)
818 assert (table->ref_cnt > 0);
819 if (--table->ref_cnt)
822 free (table->current_layer);
823 pivot_table_look_unref (table->look);
825 for (int i = 0; i < TABLE_N_AXES; i++)
826 pivot_table_sizing_uninit (&table->sizing[i]);
828 for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
829 free (table->ccs[i]);
831 free (table->command_local);
832 free (table->command_c);
833 free (table->language);
834 free (table->locale);
836 free (table->dataset);
837 free (table->datafile);
839 for (size_t i = 0; i < table->n_footnotes; i++)
840 pivot_footnote_destroy (table->footnotes[i]);
841 free (table->footnotes);
843 pivot_value_destroy (table->title);
844 pivot_value_destroy (table->subtype);
845 pivot_value_destroy (table->corner_text);
846 pivot_value_destroy (table->caption);
848 for (size_t i = 0; i < table->n_dimensions; i++)
849 pivot_dimension_destroy (table->dimensions[i]);
850 free (table->dimensions);
852 for (size_t i = 0; i < PIVOT_N_AXES; i++)
853 free (table->axes[i].dimensions);
855 struct pivot_cell *cell, *next_cell;
856 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
859 hmap_delete (&table->cells, &cell->hmap_node);
860 pivot_value_destroy (cell->value);
863 hmap_destroy (&table->cells);
868 /* Returns true if TABLE has more than one owner. A pivot table that is shared
869 among multiple owners must not be modified. */
871 pivot_table_is_shared (const struct pivot_table *table)
873 return table->ref_cnt > 1;
876 const struct pivot_table_look *
877 pivot_table_get_look (const struct pivot_table *table)
883 pivot_table_set_look (struct pivot_table *table,
884 const struct pivot_table_look *look)
886 pivot_table_look_unref (table->look);
887 table->look = pivot_table_look_ref (look);
890 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
891 WV, which should be the weight variable for the dictionary whose data or
892 statistics are being put into TABLE.
894 This has no effect if WV is NULL. */
896 pivot_table_set_weight_var (struct pivot_table *table,
897 const struct variable *wv)
900 pivot_table_set_weight_format (table, var_get_print_format (wv));
903 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
904 format for the dictionary whose data or statistics are being put into TABLE.
906 This has no effect if WFMT is NULL. */
908 pivot_table_set_weight_format (struct pivot_table *table,
909 const struct fmt_spec *wfmt)
912 table->weight_format = *wfmt;
915 /* Returns true if TABLE has no cells, false otherwise. */
917 pivot_table_is_empty (const struct pivot_table *table)
919 return hmap_is_empty (&table->cells);
923 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
925 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
929 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
931 for (size_t i = 0; i < n; i++)
938 static struct pivot_cell *
939 pivot_table_lookup_cell__ (const struct pivot_table *table,
940 const size_t *dindexes, unsigned int hash)
942 struct pivot_cell *cell;
943 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
945 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
950 static struct pivot_cell *
951 pivot_cell_allocate (size_t n_idx)
953 struct pivot_cell *cell UNUSED;
954 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
957 static struct pivot_cell *
958 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
960 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
961 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
964 cell = pivot_cell_allocate (table->n_dimensions);
965 for (size_t i = 0; i < table->n_dimensions; i++)
966 cell->idx[i] = dindexes[i];
968 hmap_insert (&table->cells, &cell->hmap_node, hash);
973 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
974 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
977 If VALUE is a numeric value without a specified format, this function checks
978 each of the categories designated by DINDEXES[] and takes the format from
979 the first category with a result class. If none has a result class, uses
980 the overall default numeric format. */
982 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
983 struct pivot_value *value)
985 assert (n == table->n_dimensions);
987 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
989 for (size_t i = 0; i < table->n_dimensions; i++)
991 const struct pivot_dimension *d = table->dimensions[i];
992 if (dindexes[i] < d->n_leaves)
994 const struct pivot_category *c = d->data_leaves[dindexes[i]];
997 value->numeric.format = c->format;
1002 value->numeric.format = *settings_get_format ();
1007 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1008 pivot_value_destroy (cell->value);
1009 cell->value = value;
1012 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
1013 dimension. Takes ownership of VALUE. */
1015 pivot_table_put1 (struct pivot_table *table, size_t idx1,
1016 struct pivot_value *value)
1018 size_t dindexes[] = { idx1 };
1019 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1022 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
1023 dimensions. Takes ownership of VALUE. */
1025 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
1026 struct pivot_value *value)
1028 size_t dindexes[] = { idx1, idx2 };
1029 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1032 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
1033 have 3 dimensions. Takes ownership of VALUE. */
1035 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
1036 size_t idx3, struct pivot_value *value)
1038 size_t dindexes[] = { idx1, idx2, idx3 };
1039 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1042 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
1043 must have 4 dimensions. Takes ownership of VALUE. */
1045 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1046 size_t idx3, size_t idx4, struct pivot_value *value)
1048 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1049 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1052 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1053 automatically assigned marker.
1055 The footnote will only appear in output if it is referenced. Use
1056 pivot_value_add_footnote() to add a reference to the footnote. */
1057 struct pivot_footnote *
1058 pivot_table_create_footnote (struct pivot_table *table,
1059 struct pivot_value *content)
1061 return pivot_table_create_footnote__ (table, table->n_footnotes,
1065 static struct pivot_value *
1066 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1068 char text[INT_BUFSIZE_BOUND (size_t)];
1069 if (show_numeric_markers)
1070 snprintf (text, sizeof text, "%d", idx + 1);
1072 str_format_26adic (idx + 1, false, text, sizeof text);
1073 return pivot_value_new_user_text (text, -1);
1076 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1077 all lower indexes as a side effect). If MARKER is nonnull, sets the
1078 footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1079 struct pivot_footnote *
1080 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1081 struct pivot_value *marker,
1082 struct pivot_value *content)
1084 if (idx >= table->n_footnotes)
1086 while (idx >= table->allocated_footnotes)
1087 table->footnotes = x2nrealloc (table->footnotes,
1088 &table->allocated_footnotes,
1089 sizeof *table->footnotes);
1090 while (idx >= table->n_footnotes)
1092 struct pivot_footnote *f = xmalloc (sizeof *f);
1093 f->idx = table->n_footnotes;
1094 f->marker = pivot_make_default_footnote_marker (
1095 f->idx, table->look->show_numeric_markers);
1099 table->footnotes[table->n_footnotes++] = f;
1103 struct pivot_footnote *f = table->footnotes[idx];
1106 pivot_value_destroy (f->marker);
1111 pivot_value_destroy (f->content);
1112 f->content = content;
1117 /* Frees the data owned by F. */
1119 pivot_footnote_destroy (struct pivot_footnote *f)
1123 pivot_value_destroy (f->content);
1124 pivot_value_destroy (f->marker);
1129 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1130 indexes for each dimension in TABLE in DINDEXES[]. */
1132 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1133 const size_t *pindexes[PIVOT_N_AXES],
1134 size_t dindexes[/* table->n_dimensions */])
1136 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1138 const struct pivot_axis *axis = &table->axes[i];
1140 for (size_t j = 0; j < axis->n_dimensions; j++)
1142 const struct pivot_dimension *d = axis->dimensions[j];
1143 dindexes[d->top_index]
1144 = d->presentation_leaves[pindexes[i][j]]->data_index;
1150 pivot_table_enumerate_axis (const struct pivot_table *table,
1151 enum pivot_axis_type axis_type,
1152 const size_t *layer_indexes, bool omit_empty,
1155 const struct pivot_axis *axis = &table->axes[axis_type];
1156 if (!axis->n_dimensions)
1158 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1160 enumeration[1] = SIZE_MAX;
1165 else if (!axis->extent)
1167 size_t *enumeration = xmalloc (sizeof *enumeration);
1168 *enumeration = SIZE_MAX;
1174 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1175 axis->n_dimensions), 1),
1176 sizeof *enumeration);
1177 size_t *p = enumeration;
1178 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1180 size_t *axis_indexes;
1181 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1185 enum pivot_axis_type axis2_type
1186 = pivot_axis_type_transpose (axis_type);
1188 size_t *axis2_indexes;
1189 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1191 const size_t *pindexes[PIVOT_N_AXES];
1192 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1193 pindexes[axis_type] = axis_indexes;
1194 pindexes[axis2_type] = axis2_indexes;
1195 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1196 if (pivot_table_get (table, dindexes))
1202 free (axis2_indexes);
1205 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1206 p += axis->n_dimensions;
1208 if (omit_empty && p == enumeration)
1210 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1212 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1213 p += axis->n_dimensions;
1218 *n = (p - enumeration) / axis->n_dimensions;
1224 static const struct pivot_cell *
1225 pivot_table_lookup_cell (const struct pivot_table *table,
1226 const size_t *dindexes)
1228 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1229 return pivot_table_lookup_cell__ (table, dindexes, hash);
1232 const struct pivot_value *
1233 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1235 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1236 return cell ? cell->value : NULL;
1239 struct pivot_value *
1240 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1242 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1244 cell->value = pivot_value_new_user_text ("", -1);
1249 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1251 if (pivot_category_is_group (category) && category->n_subs)
1252 for (size_t i = 0; i < category->n_subs; i++)
1253 distribute_extra_depth (category->subs[i], extra_depth);
1255 category->extra_depth += extra_depth;
1259 pivot_category_assign_label_depth (struct pivot_category *category,
1260 bool dimension_labels_in_corner)
1262 category->extra_depth = 0;
1264 if (pivot_category_is_group (category))
1267 for (size_t i = 0; i < category->n_subs; i++)
1269 pivot_category_assign_label_depth (category->subs[i], false);
1270 depth = MAX (depth, category->subs[i]->label_depth);
1273 for (size_t i = 0; i < category->n_subs; i++)
1275 struct pivot_category *sub = category->subs[i];
1277 size_t extra_depth = depth - sub->label_depth;
1279 distribute_extra_depth (sub, extra_depth);
1281 sub->label_depth = depth;
1284 category->show_label_in_corner = (category->show_label
1285 && dimension_labels_in_corner);
1286 category->label_depth
1287 = (category->show_label && !category->show_label_in_corner
1288 ? depth + 1 : depth);
1291 category->label_depth = 1;
1295 pivot_axis_assign_label_depth (struct pivot_table *table,
1296 enum pivot_axis_type axis_type,
1297 bool dimension_labels_in_corner)
1299 struct pivot_axis *axis = &table->axes[axis_type];
1300 bool any_label_shown_in_corner = false;
1301 axis->label_depth = 0;
1303 for (size_t i = 0; i < axis->n_dimensions; i++)
1305 struct pivot_dimension *d = axis->dimensions[i];
1306 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1307 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1308 axis->label_depth += d->label_depth;
1309 axis->extent *= d->n_leaves;
1311 if (d->root->show_label_in_corner)
1312 any_label_shown_in_corner = true;
1314 return any_label_shown_in_corner;
1318 pivot_table_assign_label_depth (struct pivot_table *table)
1320 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1321 if (pivot_axis_assign_label_depth (
1322 table, PIVOT_AXIS_ROW, (table->look->row_labels_in_corner
1323 && !table->corner_text))
1324 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1325 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1326 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1334 indent (int indentation)
1336 for (int i = 0; i < indentation * 2; i++)
1341 pivot_value_dump (const struct pivot_value *value)
1343 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1344 SETTINGS_VALUE_SHOW_DEFAULT);
1350 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1355 indent (indentation);
1356 printf ("%s: ", name);
1357 pivot_value_dump (value);
1363 pivot_table_dump_string (const char *string, const char *name, int indentation)
1367 indent (indentation);
1368 printf ("%s: %s\n", name, string);
1373 pivot_category_dump (const struct pivot_category *c, int indentation)
1375 indent (indentation);
1376 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1377 pivot_value_dump (c->name);
1380 if (pivot_category_is_leaf (c))
1381 printf ("data_index=%zu\n", c->data_index);
1384 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1387 for (size_t i = 0; i < c->n_subs; i++)
1388 pivot_category_dump (c->subs[i], indentation + 1);
1393 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1395 indent (indentation);
1396 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1397 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1399 pivot_category_dump (d->root, indentation + 1);
1403 table_area_style_dump (enum pivot_area area, const struct table_area_style *a,
1406 indent (indentation);
1407 printf ("%s: ", pivot_area_to_string (area));
1408 font_style_dump (&a->font_style);
1410 cell_style_dump (&a->cell_style);
1415 table_border_style_dump (enum pivot_border border,
1416 const struct table_border_style *b, int indentation)
1418 indent (indentation);
1419 printf ("%s: %s ", pivot_border_to_string (border),
1420 table_stroke_to_string (b->stroke));
1421 cell_color_dump (&b->color);
1426 compose_headings (const struct pivot_axis *axis,
1427 const size_t *column_enumeration,
1428 enum settings_value_show show_values,
1429 enum settings_value_show show_variables)
1431 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1434 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1435 for (size_t i = 0; i < axis->label_depth; i++)
1436 headings[i] = xcalloc (axis->extent, sizeof **headings);
1438 const size_t *indexes;
1440 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1442 int row = axis->label_depth - 1;
1443 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1445 const struct pivot_dimension *d = axis->dimensions[dim_index];
1446 if (d->hide_all_labels)
1448 for (const struct pivot_category *c
1449 = d->presentation_leaves[indexes[dim_index]];
1453 if (pivot_category_is_leaf (c) || (c->show_label
1454 && !c->show_label_in_corner))
1456 headings[row][column] = pivot_value_to_string (
1457 c->name, show_values, show_variables);
1458 if (!*headings[row][column])
1459 headings[row][column] = xstrdup ("<blank>");
1471 free_headings (const struct pivot_axis *axis, char ***headings)
1473 for (size_t i = 0; i < axis->label_depth; i++)
1475 for (size_t j = 0; j < axis->extent; j++)
1476 free (headings[i][j]);
1483 pivot_table_sizing_dump (const char *name,
1484 const int width_ranges[2],
1485 const struct pivot_table_sizing *s,
1488 indent (indentation);
1489 printf ("%ss: min=%d, max=%d\n", name, width_ranges[0], width_ranges[1]);
1492 indent (indentation + 1);
1493 printf ("%s widths:", name);
1494 for (size_t i = 0; i < s->n_widths; i++)
1495 printf (" %d", s->widths[i]);
1500 indent (indentation + 1);
1501 printf ("break after %ss:", name);
1502 for (size_t i = 0; i < s->n_breaks; i++)
1503 printf (" %zu", s->breaks[i]);
1508 indent (indentation + 1);
1509 printf ("keep %ss together:", name);
1510 for (size_t i = 0; i < s->n_keeps; i++)
1511 printf (" [%zu,%zu]",
1513 s->keeps[i].ofs + s->keeps[i].n - 1);
1519 pivot_table_dump (const struct pivot_table *table, int indentation)
1524 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1525 if (table->decimal == '.' || table->decimal == ',')
1526 settings_set_decimal_char (table->decimal);
1528 pivot_table_dump_value (table->title, "title", indentation);
1529 pivot_table_dump_string (table->command_c, "command", indentation);
1530 pivot_table_dump_string (table->dataset, "dataset", indentation);
1531 pivot_table_dump_string (table->datafile, "datafile", indentation);
1532 pivot_table_dump_string (table->notes, "notes", indentation);
1533 pivot_table_dump_string (table->look->name, "table-look", indentation);
1536 indent (indentation);
1538 struct tm *tm = localtime (&table->date);
1539 printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
1540 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
1544 indent (indentation);
1545 printf ("sizing:\n");
1546 pivot_table_sizing_dump ("column", table->look->width_ranges[TABLE_HORZ],
1547 &table->sizing[TABLE_HORZ], indentation + 1);
1548 pivot_table_sizing_dump ("row", table->look->width_ranges[TABLE_VERT],
1549 &table->sizing[TABLE_VERT], indentation + 1);
1551 indent (indentation);
1552 printf ("areas:\n");
1553 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1554 table_area_style_dump (area, &table->look->areas[area], indentation + 1);
1556 indent (indentation);
1557 printf ("borders:\n");
1558 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1559 table_border_style_dump (border, &table->look->borders[border],
1562 for (size_t i = 0; i < table->n_dimensions; i++)
1563 pivot_dimension_dump (table->dimensions[i], indentation);
1565 /* Presentation and data indexes. */
1566 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1568 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1569 if (layer_axis->n_dimensions)
1571 indent (indentation);
1572 printf ("current layer:");
1574 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1576 const struct pivot_dimension *d = layer_axis->dimensions[i];
1577 char *name = pivot_value_to_string (d->root->name,
1579 table->show_variables);
1580 char *value = pivot_value_to_string (
1581 d->data_leaves[table->current_layer[i]]->name,
1582 table->show_values, table->show_variables);
1583 printf (" %s=%s", name, value);
1591 size_t *layer_indexes;
1592 size_t layer_iteration = 0;
1593 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1595 indent (indentation);
1596 printf ("layer %zu:", layer_iteration++);
1598 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1599 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1601 const struct pivot_dimension *d = layer_axis->dimensions[i];
1603 fputs (i == 0 ? " " : ", ", stdout);
1604 pivot_value_dump (d->root->name);
1605 fputs (" =", stdout);
1607 struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1610 for (const struct pivot_category *c
1611 = d->presentation_leaves[layer_indexes[i]];
1615 if (pivot_category_is_leaf (c) || c->show_label)
1616 names[n_names++] = c->name;
1619 for (size_t i = n_names; i-- > 0;)
1622 pivot_value_dump (names[i]);
1628 size_t *column_enumeration = pivot_table_enumerate_axis (
1629 table, PIVOT_AXIS_COLUMN, layer_indexes, table->look->omit_empty, NULL);
1630 size_t *row_enumeration = pivot_table_enumerate_axis (
1631 table, PIVOT_AXIS_ROW, layer_indexes, table->look->omit_empty, NULL);
1633 char ***column_headings = compose_headings (
1634 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1635 table->show_values, table->show_variables);
1636 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1638 indent (indentation + 1);
1639 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1642 fputs ("; ", stdout);
1643 if (column_headings[y][x])
1644 fputs (column_headings[y][x], stdout);
1648 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1650 indent (indentation + 1);
1651 printf ("-----------------------------------------------\n");
1653 char ***row_headings = compose_headings (
1654 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1655 table->show_values, table->show_variables);
1658 const size_t *pindexes[PIVOT_N_AXES]
1659 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1660 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1661 &table->axes[PIVOT_AXIS_ROW])
1663 indent (indentation + 1);
1666 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1669 fputs ("; ", stdout);
1670 if (row_headings[y][x])
1671 fputs (row_headings[y][x], stdout);
1677 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1679 &table->axes[PIVOT_AXIS_COLUMN])
1684 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1685 const struct pivot_value *value = pivot_table_get (
1688 pivot_value_dump (value);
1695 free (column_enumeration);
1696 free (row_enumeration);
1697 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1700 pivot_table_dump_value (table->caption, "caption", indentation);
1702 for (size_t i = 0; i < table->n_footnotes; i++)
1704 const struct pivot_footnote *f = table->footnotes[i];
1705 indent (indentation);
1708 pivot_value_dump (f->marker);
1710 printf ("%zu", f->idx);
1712 pivot_value_dump (f->content);
1717 settings_set_decimal_char (old_decimal);
1721 consume_int (const char *p, size_t *n)
1724 while (c_isdigit (*p))
1725 *n = *n * 10 + (*p++ - '0');
1730 pivot_format_inner_template (struct string *out, const char *template,
1732 struct pivot_value **values, size_t n_values,
1733 enum settings_value_show show_values,
1734 enum settings_value_show show_variables)
1736 size_t args_consumed = 0;
1737 while (*template && *template != ':')
1739 if (*template == '\\' && template[1])
1741 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1744 else if (*template == escape)
1747 template = consume_int (template + 1, &index);
1748 if (index >= 1 && index <= n_values)
1750 pivot_value_format (values[index - 1], show_values,
1751 show_variables, out);
1752 args_consumed = MAX (args_consumed, index);
1756 ds_put_byte (out, *template++);
1758 return args_consumed;
1762 pivot_extract_inner_template (const char *template, const char **p)
1768 if (*template == '\\' && template[1] != '\0')
1770 else if (*template == ':')
1771 return template + 1;
1772 else if (*template == '\0')
1780 pivot_format_template (struct string *out, const char *template,
1781 const struct pivot_argument *args, size_t n_args,
1782 enum settings_value_show show_values,
1783 enum settings_value_show show_variables)
1787 if (*template == '\\' && template[1] != '\0')
1789 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1792 else if (*template == '^')
1795 template = consume_int (template + 1, &index);
1796 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1797 pivot_value_format (args[index - 1].values[0],
1798 show_values, show_variables, out);
1800 else if (*template == '[')
1802 const char *tmpl[2];
1803 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1804 template = pivot_extract_inner_template (template, &tmpl[1]);
1805 template += *template == ']';
1808 template = consume_int (template, &index);
1809 if (index < 1 || index > n_args)
1812 const struct pivot_argument *arg = &args[index - 1];
1813 size_t left = arg->n;
1816 struct pivot_value **values = arg->values + (arg->n - left);
1817 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1818 char escape = "%^"[tmpl_idx];
1819 size_t used = pivot_format_inner_template (
1820 out, tmpl[tmpl_idx], escape, values, left,
1821 show_values, show_variables);
1822 if (!used || used > left)
1828 ds_put_byte (out, *template++);
1832 static enum settings_value_show
1833 interpret_show (enum settings_value_show global_show,
1834 enum settings_value_show table_show,
1835 enum settings_value_show value_show,
1838 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1839 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1840 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1844 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1845 SHOW_VARIABLES control whether variable and value labels are included.
1847 The "body" omits subscripts and superscripts and footnotes. */
1849 pivot_value_format_body (const struct pivot_value *value,
1850 enum settings_value_show show_values,
1851 enum settings_value_show show_variables,
1854 enum settings_value_show show;
1855 bool numeric = false;
1857 switch (value->type)
1859 case PIVOT_VALUE_NUMERIC:
1860 show = interpret_show (settings_get_show_values (),
1862 value->numeric.show,
1863 value->numeric.value_label != NULL);
1864 if (show & SETTINGS_VALUE_SHOW_VALUE)
1866 char *s = data_out (&(union value) { .f = value->numeric.x },
1867 "UTF-8", &value->numeric.format);
1868 ds_put_cstr (out, s + strspn (s, " "));
1871 if (show & SETTINGS_VALUE_SHOW_LABEL)
1873 if (show & SETTINGS_VALUE_SHOW_VALUE)
1874 ds_put_byte (out, ' ');
1875 ds_put_cstr (out, value->numeric.value_label);
1877 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1880 case PIVOT_VALUE_STRING:
1881 show = interpret_show (settings_get_show_values (),
1884 value->string.value_label != NULL);
1885 if (show & SETTINGS_VALUE_SHOW_VALUE)
1887 if (value->string.hex)
1889 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1891 ds_put_format (out, "%02X", *p);
1894 ds_put_cstr (out, value->string.s);
1896 if (show & SETTINGS_VALUE_SHOW_LABEL)
1898 if (show & SETTINGS_VALUE_SHOW_VALUE)
1899 ds_put_byte (out, ' ');
1900 ds_put_cstr (out, value->string.value_label);
1904 case PIVOT_VALUE_VARIABLE:
1905 show = interpret_show (settings_get_show_variables (),
1907 value->variable.show,
1908 value->variable.var_label != NULL);
1909 if (show & SETTINGS_VALUE_SHOW_VALUE)
1910 ds_put_cstr (out, value->variable.var_name);
1911 if (show & SETTINGS_VALUE_SHOW_LABEL)
1913 if (show & SETTINGS_VALUE_SHOW_VALUE)
1914 ds_put_byte (out, ' ');
1915 ds_put_cstr (out, value->variable.var_label);
1919 case PIVOT_VALUE_TEXT:
1920 ds_put_cstr (out, value->text.local);
1923 case PIVOT_VALUE_TEMPLATE:
1924 pivot_format_template (out, value->template.local, value->template.args,
1925 value->template.n_args, show_values,
1933 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
1934 SHOW_VARIABLES control whether variable and value labels are included.
1936 Subscripts and superscripts and footnotes are included. */
1938 pivot_value_format (const struct pivot_value *value,
1939 enum settings_value_show show_values,
1940 enum settings_value_show show_variables,
1943 pivot_value_format_body (value, show_values, show_variables, out);
1945 if (value->n_subscripts)
1947 for (size_t i = 0; i < value->n_subscripts; i++)
1948 ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
1951 if (value->superscript)
1952 ds_put_format (out, "^%s", value->superscript);
1954 for (size_t i = 0; i < value->n_footnotes; i++)
1956 ds_put_byte (out, '^');
1957 pivot_value_format (value->footnotes[i]->marker,
1958 show_values, show_variables, out);
1962 /* Returns a text representation of VALUE. The caller must free the string,
1965 pivot_value_to_string (const struct pivot_value *value,
1966 enum settings_value_show show_values,
1967 enum settings_value_show show_variables)
1969 struct string s = DS_EMPTY_INITIALIZER;
1970 pivot_value_format (value, show_values, show_variables, &s);
1971 return ds_steal_cstr (&s);
1974 /* Frees the data owned by V. */
1976 pivot_value_destroy (struct pivot_value *value)
1980 font_style_uninit (value->font_style);
1981 free (value->font_style);
1982 free (value->cell_style);
1983 /* Do not free the elements of footnotes because VALUE does not own
1985 free (value->footnotes);
1987 for (size_t i = 0; i < value->n_subscripts; i++)
1988 free (value->subscripts[i]);
1989 free (value->subscripts);
1991 free (value->superscript);
1993 switch (value->type)
1995 case PIVOT_VALUE_NUMERIC:
1996 free (value->numeric.var_name);
1997 free (value->numeric.value_label);
2000 case PIVOT_VALUE_STRING:
2001 free (value->string.s);
2002 free (value->string.var_name);
2003 free (value->string.value_label);
2006 case PIVOT_VALUE_VARIABLE:
2007 free (value->variable.var_name);
2008 free (value->variable.var_label);
2011 case PIVOT_VALUE_TEXT:
2012 free (value->text.local);
2013 if (value->text.c != value->text.local)
2014 free (value->text.c);
2015 if (value->text.id != value->text.local
2016 && value->text.id != value->text.c)
2017 free (value->text.id);
2020 case PIVOT_VALUE_TEMPLATE:
2021 free (value->template.local);
2022 if (value->template.id != value->template.local)
2023 free (value->template.id);
2024 for (size_t i = 0; i < value->template.n_args; i++)
2025 pivot_argument_uninit (&value->template.args[i]);
2026 free (value->template.args);
2033 /* Sets AREA to the style to use for VALUE, with defaults coming from
2034 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
2036 pivot_value_get_style (struct pivot_value *value,
2037 const struct font_style *base_font_style,
2038 const struct cell_style *base_cell_style,
2039 struct table_area_style *area)
2041 font_style_copy (NULL, &area->font_style, (value->font_style
2043 : base_font_style));
2044 area->cell_style = *(value->cell_style
2049 /* Copies AREA into VALUE's style. */
2051 pivot_value_set_style (struct pivot_value *value,
2052 const struct table_area_style *area)
2054 if (value->font_style)
2055 font_style_uninit (value->font_style);
2057 value->font_style = xmalloc (sizeof *value->font_style);
2058 font_style_copy (NULL, value->font_style, &area->font_style);
2060 if (!value->cell_style)
2061 value->cell_style = xmalloc (sizeof *value->cell_style);
2062 *value->cell_style = area->cell_style;
2065 /* Frees the data owned by ARG (but not ARG itself). */
2067 pivot_argument_uninit (struct pivot_argument *arg)
2071 for (size_t i = 0; i < arg->n; i++)
2072 pivot_value_destroy (arg->values[i]);
2077 /* Creates and returns a new pivot_value whose contents is the null-terminated
2078 string TEXT. Takes ownership of TEXT.
2080 This function is for text strings provided by the user (with the exception
2081 that pivot_value_new_variable() should be used for variable names). For
2082 strings that are part of the PSPP user interface, such as names of
2083 procedures, statistics, annotations, error messages, etc., use
2084 pivot_value_new_text(). */
2085 struct pivot_value *
2086 pivot_value_new_user_text_nocopy (char *text)
2088 struct pivot_value *value = xmalloc (sizeof *value);
2089 *value = (struct pivot_value) {
2090 .type = PIVOT_VALUE_TEXT,
2095 .user_provided = true,
2101 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2102 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2105 This function is for text strings provided by the user (with the exception
2106 that pivot_value_new_variable() should be used for variable names). For
2107 strings that are part of the PSPP user interface, such as names of
2108 procedures, statistics, annotations, error messages, etc., use
2109 pivot_value_new_text().j
2111 The caller retains ownership of TEXT.*/
2112 struct pivot_value *
2113 pivot_value_new_user_text (const char *text, size_t length)
2115 return pivot_value_new_user_text_nocopy (
2116 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2119 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2120 a translatable string, but not actually translated yet, e.g. enclosed in
2121 N_(). This function is for text strings that are part of the PSPP user
2122 interface, such as names of procedures, statistics, annotations, error
2123 messages, etc. For strings that come from the user, use
2124 pivot_value_new_user_text(). */
2125 struct pivot_value *
2126 pivot_value_new_text (const char *text)
2128 char *c = xstrdup (text);
2129 char *local = xstrdup (gettext (c));
2131 struct pivot_value *value = xmalloc (sizeof *value);
2132 *value = (struct pivot_value) {
2133 .type = PIVOT_VALUE_TEXT,
2138 .user_provided = false,
2144 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2146 struct pivot_value * PRINTF_FORMAT (1, 2)
2147 pivot_value_new_text_format (const char *format, ...)
2150 va_start (args, format);
2151 char *c = xvasprintf (format, args);
2154 va_start (args, format);
2155 char *local = xvasprintf (gettext (format), args);
2158 struct pivot_value *value = xmalloc (sizeof *value);
2159 *value = (struct pivot_value) {
2160 .type = PIVOT_VALUE_TEXT,
2165 .user_provided = false,
2171 /* Returns a new pivot_value that represents X.
2173 The format to use for X is unspecified. Usually the easiest way to specify
2174 a format is through assigning a result class to one of the categories that
2175 the pivot_value will end up in. If that is not suitable, then the caller
2176 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2177 struct pivot_value *
2178 pivot_value_new_number (double x)
2180 struct pivot_value *value = xmalloc (sizeof *value);
2181 *value = (struct pivot_value) {
2182 .type = PIVOT_VALUE_NUMERIC,
2183 .numeric = { .x = x, },
2188 /* Returns a new pivot_value that represents X, formatted as an integer. */
2189 struct pivot_value *
2190 pivot_value_new_integer (double x)
2192 struct pivot_value *value = pivot_value_new_number (x);
2193 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2197 /* Returns a new pivot_value that represents VALUE, formatted as for
2199 struct pivot_value *
2200 pivot_value_new_var_value (const struct variable *variable,
2201 const union value *value)
2203 struct pivot_value *pv = pivot_value_new_value (
2204 value, var_get_width (variable), var_get_print_format (variable),
2205 var_get_encoding (variable));
2207 char *var_name = xstrdup (var_get_name (variable));
2208 if (var_is_alpha (variable))
2209 pv->string.var_name = var_name;
2211 pv->numeric.var_name = var_name;
2213 const char *label = var_lookup_value_label (variable, value);
2216 if (var_is_alpha (variable))
2217 pv->string.value_label = xstrdup (label);
2219 pv->numeric.value_label = xstrdup (label);
2225 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2226 formatted with FORMAT. For a string value, ENCODING must be its character
2228 struct pivot_value *
2229 pivot_value_new_value (const union value *value, int width,
2230 const struct fmt_spec *format, const char *encoding)
2232 struct pivot_value *pv = xzalloc (sizeof *pv);
2235 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2237 size_t n = strlen (s);
2238 while (n > 0 && s[n - 1] == ' ')
2241 pv->type = PIVOT_VALUE_STRING;
2243 pv->string.hex = format->type == FMT_AHEX;
2247 pv->type = PIVOT_VALUE_NUMERIC;
2248 pv->numeric.x = value->f;
2249 pv->numeric.format = *format;
2255 /* Returns a new pivot_value for VARIABLE. */
2256 struct pivot_value *
2257 pivot_value_new_variable (const struct variable *variable)
2259 struct pivot_value *value = xmalloc (sizeof *value);
2260 *value = (struct pivot_value) {
2261 .type = PIVOT_VALUE_VARIABLE,
2263 .var_name = xstrdup (var_get_name (variable)),
2264 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2270 /* Attaches a reference to FOOTNOTE to V. */
2272 pivot_value_add_footnote (struct pivot_value *v,
2273 const struct pivot_footnote *footnote)
2275 /* Some legacy tables include numerous duplicate footnotes. Suppress
2277 for (size_t i = 0; i < v->n_footnotes; i++)
2278 if (v->footnotes[i] == footnote)
2281 v->footnotes = xrealloc (v->footnotes,
2282 (v->n_footnotes + 1) * sizeof *v->footnotes);
2283 v->footnotes[v->n_footnotes++] = footnote;
2286 /* If VALUE is a numeric value, and RC is a result class such as
2287 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2289 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2292 if (value->type == PIVOT_VALUE_NUMERIC)
2294 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2296 value->numeric.format = *f;