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 "data/file-name.h"
28 #include "libpspp/assertion.h"
29 #include "libpspp/hash-functions.h"
30 #include "libpspp/i18n.h"
31 #include "output/driver.h"
32 #include "output/spv/spv-table-look.h"
34 #include "gl/c-ctype.h"
35 #include "gl/configmake.h"
36 #include "gl/intprops.h"
37 #include "gl/minmax.h"
38 #include "gl/relocatable.h"
39 #include "gl/xalloc.h"
40 #include "gl/xmemdup0.h"
44 #define _(msgid) gettext (msgid)
45 #define N_(msgid) msgid
47 static const struct fmt_spec *pivot_table_get_format (
48 const struct pivot_table *, const char *s);
50 /* Pivot table display styling. */
52 /* Returns the name of AREA. */
54 pivot_area_to_string (enum pivot_area area)
58 case PIVOT_AREA_TITLE: return "title";
59 case PIVOT_AREA_CAPTION: return "caption";
60 case PIVOT_AREA_FOOTER: return "footer";
61 case PIVOT_AREA_CORNER: return "corner";
62 case PIVOT_AREA_COLUMN_LABELS: return "column labels";
63 case PIVOT_AREA_ROW_LABELS: return "row labels";
64 case PIVOT_AREA_DATA: return "data";
65 case PIVOT_AREA_LAYERS: return "layers";
66 case PIVOT_N_AREAS: default: return "**error**";
70 /* Returns the name of BORDER. */
72 pivot_border_to_string (enum pivot_border border)
76 case PIVOT_BORDER_TITLE:
79 case PIVOT_BORDER_OUTER_LEFT:
80 return "left outer frame";
81 case PIVOT_BORDER_OUTER_TOP:
82 return "top outer frame";
83 case PIVOT_BORDER_OUTER_RIGHT:
84 return "right outer frame";
85 case PIVOT_BORDER_OUTER_BOTTOM:
86 return "bottom outer frame";
88 case PIVOT_BORDER_INNER_LEFT:
89 return "left inner frame";
90 case PIVOT_BORDER_INNER_TOP:
91 return "top inner frame";
92 case PIVOT_BORDER_INNER_RIGHT:
93 return "right inner frame";
94 case PIVOT_BORDER_INNER_BOTTOM:
95 return "bottom inner frame";
97 case PIVOT_BORDER_DATA_LEFT:
98 return "data area left";
99 case PIVOT_BORDER_DATA_TOP:
100 return "data area top";
102 case PIVOT_BORDER_DIM_ROW_HORZ:
103 return "row label horizontal dimension border";
104 case PIVOT_BORDER_DIM_ROW_VERT:
105 return "row label vertical dimension border";
106 case PIVOT_BORDER_DIM_COL_HORZ:
107 return "column label horizontal dimension border";
108 case PIVOT_BORDER_DIM_COL_VERT:
109 return "column label vertical dimension border";
111 case PIVOT_BORDER_CAT_ROW_HORZ:
112 return "row label horizontal category border";
113 case PIVOT_BORDER_CAT_ROW_VERT:
114 return "row label vertical category border";
115 case PIVOT_BORDER_CAT_COL_HORZ:
116 return "column label horizontal category border";
117 case PIVOT_BORDER_CAT_COL_VERT:
118 return "column label vertical category border";
120 case PIVOT_N_BORDERS:
127 pivot_table_sizing_uninit (struct pivot_table_sizing *sizing)
131 free (sizing->widths);
132 free (sizing->breaks);
133 free (sizing->keeps);
137 /* Pivot table looks. */
139 static const struct pivot_table_look *
140 default_look (const struct pivot_table_look *new)
142 static struct pivot_table_look *look;
145 pivot_table_look_unref (look);
146 look = pivot_table_look_ref (new);
150 char *error = pivot_table_look_read ("default.stt", &look);
154 look = pivot_table_look_ref (pivot_table_look_builtin_default ());
160 const struct pivot_table_look *
161 pivot_table_look_get_default (void)
163 return default_look (NULL);
167 pivot_table_look_set_default (const struct pivot_table_look *look)
172 char * WARN_UNUSED_RESULT
173 pivot_table_look_read (const char *name, struct pivot_table_look **lookp)
177 /* Construct search path. */
181 const char *home = getenv ("HOME");
182 char *allocated = NULL;
184 path[n++] = allocated = xasprintf ("%s/.pspp/looks", home);
186 path[n++] = relocate2 (PKGDATADIR "/looks", &allocated2);
190 char *file = fn_search_path (name, (char **) path);
193 char *name2 = xasprintf ("%s.stt", name);
194 file = fn_search_path (name2, (char **) path);
200 return xasprintf ("%s: not found", name);
203 char *error = spv_table_look_read (file, lookp);
208 const struct pivot_table_look *
209 pivot_table_look_builtin_default (void)
211 static struct pivot_table_look look = {
215 .row_labels_in_corner = true,
217 [TABLE_HORZ] = { 36, 72 },
218 [TABLE_VERT] = { 36, 120 },
222 #define AREA(BOLD, H, V, L, R, T, B) { \
224 .halign = TABLE_HALIGN_##H, \
225 .valign = TABLE_VALIGN_##V, \
226 .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
227 [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
231 .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
232 .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
234 .typeface = (char *) "Sans Serif", \
237 [PIVOT_AREA_TITLE] = AREA(true, CENTER, CENTER, 8,11,1,8),
238 [PIVOT_AREA_CAPTION] = AREA(false, LEFT, TOP, 8,11,1,1),
239 [PIVOT_AREA_FOOTER] = AREA(false, LEFT, TOP, 11, 8,2,3),
240 [PIVOT_AREA_CORNER] = AREA(false, LEFT, BOTTOM, 8,11,1,1),
241 [PIVOT_AREA_COLUMN_LABELS] = AREA(false, CENTER, BOTTOM, 8,11,1,3),
242 [PIVOT_AREA_ROW_LABELS] = AREA(false, LEFT, TOP, 8,11,1,3),
243 [PIVOT_AREA_DATA] = AREA(false, MIXED, TOP, 8,11,1,1),
244 [PIVOT_AREA_LAYERS] = AREA(false, LEFT, BOTTOM, 8,11,1,3),
249 #define BORDER(STROKE) { .stroke = STROKE, .color = CELL_COLOR_BLACK }
250 [PIVOT_BORDER_TITLE] = BORDER(TABLE_STROKE_NONE),
251 [PIVOT_BORDER_OUTER_LEFT] = BORDER(TABLE_STROKE_NONE),
252 [PIVOT_BORDER_OUTER_TOP] = BORDER(TABLE_STROKE_NONE),
253 [PIVOT_BORDER_OUTER_RIGHT] = BORDER(TABLE_STROKE_NONE),
254 [PIVOT_BORDER_OUTER_BOTTOM] = BORDER(TABLE_STROKE_NONE),
255 [PIVOT_BORDER_INNER_LEFT] = BORDER(TABLE_STROKE_THICK),
256 [PIVOT_BORDER_INNER_TOP] = BORDER(TABLE_STROKE_THICK),
257 [PIVOT_BORDER_INNER_RIGHT] = BORDER(TABLE_STROKE_THICK),
258 [PIVOT_BORDER_INNER_BOTTOM] = BORDER(TABLE_STROKE_THICK),
259 [PIVOT_BORDER_DATA_LEFT] = BORDER(TABLE_STROKE_THICK),
260 [PIVOT_BORDER_DATA_TOP] = BORDER(TABLE_STROKE_THICK),
261 [PIVOT_BORDER_DIM_ROW_HORZ] = BORDER(TABLE_STROKE_SOLID),
262 [PIVOT_BORDER_DIM_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
263 [PIVOT_BORDER_DIM_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
264 [PIVOT_BORDER_DIM_COL_VERT] = BORDER(TABLE_STROKE_SOLID),
265 [PIVOT_BORDER_CAT_ROW_HORZ] = BORDER(TABLE_STROKE_NONE),
266 [PIVOT_BORDER_CAT_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
267 [PIVOT_BORDER_CAT_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
268 [PIVOT_BORDER_CAT_COL_VERT] = BORDER(TABLE_STROKE_SOLID),
275 struct pivot_table_look *
276 pivot_table_look_new_builtin_default (void)
278 return pivot_table_look_unshare (
279 pivot_table_look_ref (pivot_table_look_builtin_default ()));
282 struct pivot_table_look *
283 pivot_table_look_ref (const struct pivot_table_look *look_)
285 assert (look_->ref_cnt > 0);
287 struct pivot_table_look *look = CONST_CAST (struct pivot_table_look *, look_);
293 xstrdup_if_nonempty (const char *s)
295 return s && s[0] ? xstrdup (s) : NULL;
298 struct pivot_table_look *
299 pivot_table_look_unshare (struct pivot_table_look *old)
301 assert (old->ref_cnt > 0);
302 if (old->ref_cnt == 1)
305 pivot_table_look_unref (old);
307 struct pivot_table_look *new = xmemdup (old, sizeof *old);
309 new->name = xstrdup_if_nonempty (old->name);
310 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
311 table_area_style_copy (NULL, &new->areas[i], &old->areas[i]);
312 new->continuation = xstrdup_if_nonempty (old->continuation);
318 pivot_table_look_unref (struct pivot_table_look *look)
322 assert (look->ref_cnt > 0);
323 if (!--look->ref_cnt)
326 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
327 table_area_style_uninit (&look->areas[i]);
328 free (look->continuation);
336 /* Returns the name of AXIS_TYPE. */
338 pivot_axis_type_to_string (enum pivot_axis_type axis_type)
342 case PIVOT_AXIS_LAYER:
348 case PIVOT_AXIS_COLUMN:
356 static enum pivot_axis_type
357 pivot_axis_type_transpose (enum pivot_axis_type axis_type)
359 assert (axis_type == PIVOT_AXIS_ROW || axis_type == PIVOT_AXIS_COLUMN);
360 return (axis_type == PIVOT_AXIS_ROW ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW);
363 /* Implementation of PIVOT_AXIS_FOR_EACH. */
365 pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis)
369 if (axis->n_dimensions)
370 for (size_t i = 0; i < axis->n_dimensions; i++)
371 if (axis->dimensions[i]->n_leaves == 0)
374 size_t size = axis->n_dimensions * sizeof *indexes;
375 return xzalloc (MAX (size, 1));
378 for (size_t i = 0; i < axis->n_dimensions; i++)
380 const struct pivot_dimension *d = axis->dimensions[i];
381 if (++indexes[i] < d->n_leaves)
394 pivot_category_set_rc (struct pivot_category *category, const char *s)
396 const struct fmt_spec *format = pivot_table_get_format (
397 category->dimension->table, s);
399 category->format = *format;
401 /* Ensure that the category itself, in addition to the cells within it, takes
402 the format. (It's kind of rare for a category to have a numeric format
404 struct pivot_value *name = category->name;
405 if (name->type == PIVOT_VALUE_NUMERIC && !name->numeric.format.w)
406 name->numeric.format = format ? *format : *settings_get_format ();
410 pivot_category_create_leaves_valist (struct pivot_category *parent,
414 while ((s = va_arg (args, const char *)))
416 if (!strncmp (s, "RC_", 3))
418 assert (parent->n_subs);
419 pivot_category_set_rc (parent->subs[parent->n_subs - 1], s);
422 pivot_category_create_leaf (parent, pivot_value_new_text (s));
426 /* Creates a new dimension with the given NAME in TABLE and returns it. The
427 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
430 NAME should be a translatable name, but not actually translated yet,
431 e.g. enclosed in N_(). To use a different kind of value for a name, use
432 pivot_dimension_create__() instead.
434 The optional varargs parameters may be used to add an initial set of
435 categories to the dimension. Each string should be a translatable category
436 name, but not actually translated yet, e.g. enclosed in N_(). Each string
437 may optionally be followod by a PIVOT_RC_* string that specifies the default
438 numeric format for cells in this category. */
439 struct pivot_dimension * SENTINEL (0)
440 (pivot_dimension_create) (struct pivot_table *table,
441 enum pivot_axis_type axis_type,
442 const char *name, ...)
444 struct pivot_dimension *d = pivot_dimension_create__ (
445 table, axis_type, pivot_value_new_text (name));
448 va_start (args, name);
449 pivot_category_create_leaves_valist (d->root, args);
455 /* Creates a new dimension with the given NAME in TABLE and returns it. The
456 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
458 struct pivot_dimension *
459 pivot_dimension_create__ (struct pivot_table *table,
460 enum pivot_axis_type axis_type,
461 struct pivot_value *name)
463 assert (pivot_table_is_empty (table));
465 struct pivot_dimension *d = xmalloc (sizeof *d);
466 *d = (struct pivot_dimension) {
468 .axis_type = axis_type,
469 .level = table->axes[axis_type].n_dimensions,
470 .top_index = table->n_dimensions,
471 .root = xmalloc (sizeof *d->root),
474 struct pivot_category *root = d->root;
475 *root = (struct pivot_category) {
480 .data_index = SIZE_MAX,
481 .presentation_index = SIZE_MAX,
484 table->dimensions = xrealloc (
485 table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions);
486 table->dimensions[table->n_dimensions++] = d;
488 struct pivot_axis *axis = &table->axes[axis_type];
489 axis->dimensions = xrealloc (
490 axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
491 axis->dimensions[axis->n_dimensions++] = d;
493 if (axis_type == PIVOT_AXIS_LAYER)
495 free (table->current_layer);
496 table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
497 sizeof *table->current_layer);
500 /* axis->extent and axis->label_depth will be calculated later. */
506 pivot_dimension_destroy (struct pivot_dimension *d)
511 pivot_category_destroy (d->root);
512 free (d->data_leaves);
513 free (d->presentation_leaves);
517 /* Returns the first leaf node in an in-order traversal that is a child of
519 static const struct pivot_category * UNUSED
520 pivot_category_first_leaf (const struct pivot_category *cat)
522 if (pivot_category_is_leaf (cat))
525 for (size_t i = 0; i < cat->n_subs; i++)
527 const struct pivot_category *first
528 = pivot_category_first_leaf (cat->subs[i]);
536 /* Returns the next leaf node in an in-order traversal starting at CAT, which
538 static const struct pivot_category * UNUSED
539 pivot_category_next_leaf (const struct pivot_category *cat)
541 assert (pivot_category_is_leaf (cat));
545 const struct pivot_category *parent = cat->parent;
548 for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
550 const struct pivot_category *next
551 = pivot_category_first_leaf (parent->subs[i]);
561 pivot_category_add_child (struct pivot_category *child)
563 struct pivot_category *parent = child->parent;
565 assert (pivot_category_is_group (parent));
566 if (parent->n_subs >= parent->allocated_subs)
567 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
568 sizeof *parent->subs);
569 parent->subs[parent->n_subs++] = child;
572 /* Adds leaf categories as a child of PARENT. To create top-level categories
573 within dimension 'd', pass 'd->root' for PARENT.
575 Each of the varargs parameters should be a string, each of which should be a
576 translatable category name, but not actually translated yet, e.g. enclosed
577 in N_(). Each string may optionally be followod by a PIVOT_RC_* string that
578 specifies the default numeric format for cells in this category.
580 Returns the category index, which is just a 0-based array index, for the
583 Leaves have to be created in in-order, that is, don't create a group and add
584 some leaves, then add leaves outside the group and try to add more leaves
587 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
589 int retval = parent->dimension->n_leaves;
592 va_start (args, parent);
593 pivot_category_create_leaves_valist (parent, args);
599 /* Creates a new leaf category with the given NAME as a child of PARENT. To
600 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
601 Returns the category index, which is just a 0-based array index, for the new
604 Leaves have to be created in in-order, that is, don't create a group and add
605 some leaves, then add leaves outside the group and try to add more leaves
608 pivot_category_create_leaf (struct pivot_category *parent,
609 struct pivot_value *name)
611 return pivot_category_create_leaf_rc (parent, name, NULL);
614 /* Creates a new leaf category with the given NAME as a child of PARENT. To
615 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
616 Returns the category index, which is just a 0-based array index, for the new
619 If RC is nonnull and the name of a result category, the category is assigned
620 that result category.
622 Leaves have to be created in in-order, that is, don't create a group and add
623 some leaves, then add leaves outside the group and try to add more leaves
626 pivot_category_create_leaf_rc (struct pivot_category *parent,
627 struct pivot_value *name, const char *rc)
629 struct pivot_dimension *d = parent->dimension;
631 struct pivot_category *leaf = xmalloc (sizeof *leaf);
632 *leaf = (struct pivot_category) {
636 .group_index = parent->n_subs,
637 .data_index = d->n_leaves,
638 .presentation_index = d->n_leaves,
641 if (d->n_leaves >= d->allocated_leaves)
643 d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
644 sizeof *d->data_leaves);
645 d->presentation_leaves = xrealloc (
646 d->presentation_leaves,
647 d->allocated_leaves * sizeof *d->presentation_leaves);
650 d->data_leaves[d->n_leaves] = leaf;
651 d->presentation_leaves[d->n_leaves] = leaf;
654 pivot_category_add_child (leaf);
656 /* Make sure that the new child is the last in in-order. */
657 assert (!pivot_category_next_leaf (leaf));
659 pivot_category_set_rc (leaf, rc);
661 return leaf->data_index;
664 /* Adds a new category group named NAME as a child of PARENT. To create a
665 top-level group within dimension 'd', pass 'd->root' for PARENT.
667 NAME should be a translatable name, but not actually translated yet,
668 e.g. enclosed in N_(). To use a different kind of value for a name, use
669 pivot_category_create_group__() instead.
671 The optional varargs parameters may be used to add an initial set of
672 categories to the group. Each string should be a translatable category
673 name, but not actually translated yet, e.g. enclosed in N_(). Each string
674 may optionally be followod by a PIVOT_RC_* string that specifies the default
675 numeric format for cells in this category.
677 Returns the new group. */
678 struct pivot_category * SENTINEL (0)
679 (pivot_category_create_group) (struct pivot_category *parent,
680 const char *name, ...)
682 struct pivot_category *group = pivot_category_create_group__ (
683 parent, pivot_value_new_text (name));
686 va_start (args, name);
687 pivot_category_create_leaves_valist (group, args);
693 /* Adds a new category group named NAME as a child of PARENT. To create a
694 top-level group within dimension 'd', pass 'd->root' for PARENT. Returns
696 struct pivot_category *
697 pivot_category_create_group__ (struct pivot_category *parent,
698 struct pivot_value *name)
700 struct pivot_dimension *d = parent->dimension;
702 struct pivot_category *group = xmalloc (sizeof *group);
703 *group = (struct pivot_category) {
708 .group_index = parent->n_subs,
709 .data_index = SIZE_MAX,
710 .presentation_index = SIZE_MAX,
713 pivot_category_add_child (group);
719 pivot_category_destroy (struct pivot_category *c)
724 pivot_value_destroy (c->name);
725 for (size_t i = 0; i < c->n_subs; i++)
726 pivot_category_destroy (c->subs[i]);
733 These are usually the easiest way to control the formatting of numeric data
734 in a pivot table. See pivot_dimension_create() for an explanation of their
738 const char *name; /* "RC_*". */
739 struct fmt_spec format;
742 /* Formats for most of the result classes. */
743 static struct result_class result_classes[] =
745 { PIVOT_RC_INTEGER, { FMT_F, 40, 0 } },
746 { PIVOT_RC_PERCENT, { FMT_PCT, 40, 1 } },
747 { PIVOT_RC_CORRELATION, { FMT_F, 40, 3 } },
748 { PIVOT_RC_SIGNIFICANCE, { FMT_F, 40, 3 } },
749 { PIVOT_RC_RESIDUAL, { FMT_F, 40, 2 } },
750 { PIVOT_RC_COUNT, { 0, 0, 0 } },
751 { PIVOT_RC_OTHER, { 0, 0, 0 } },
754 /* Has PIVOT_RC_COUNT been overridden by the user? */
755 static bool overridden_count_format;
757 static struct result_class *
758 pivot_result_class_find (const char *s)
760 for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
761 if (!strcmp (s, result_classes[i].name))
762 return &result_classes[i];
766 static const struct fmt_spec *
767 pivot_table_get_format (const struct pivot_table *table, const char *s)
771 else if (!strcmp (s, PIVOT_RC_OTHER))
772 return settings_get_format ();
773 else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
774 return &table->weight_format;
777 const struct result_class *rc = pivot_result_class_find (s);
778 return rc ? &rc->format : NULL;
782 /* Sets the format specification for the result class named S (which should not
783 include the RC_ prefix) to *FORMAT. Returns true if successful, false if S
784 does not name a known result class. */
786 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
788 char *s = xasprintf ("RC_%s", s_);
789 struct result_class *rc = pivot_result_class_find (s);
792 rc->format = *format;
793 if (!strcmp (s, PIVOT_RC_COUNT))
794 overridden_count_format = true;
802 is_pivot_result_class (const char *s)
804 return pivot_result_class_find (s) != NULL;
809 /* Creates and returns a new pivot table with the given TITLE. TITLE should be
810 a text string marked for translation but not actually translated yet,
811 e.g. N_("Descriptive Statistics"). The un-translated text string is used as
812 the pivot table's subtype.
814 This function is a shortcut for pivot_table_create__() for the most common
815 case. Use pivot_table_create__() directly if the title should be some kind
816 of value other than an ordinary text string, or if the subtype should be
817 different from the title.
819 See the large comment at the top of pivot-table.h for general advice on
820 creating pivot tables. */
822 pivot_table_create (const char *title)
824 return pivot_table_create__ (pivot_value_new_text (title), title);
827 /* Creates and returns a new pivot table with the given TITLE, and takes
828 ownership of TITLE. The new pivot table's subtype is SUBTYPE, which should
829 be an untranslated English string that describes the contents of the table
830 at a high level without being specific about the variables or other context
833 TITLE and SUBTYPE may be NULL, but in that case the client must add them
834 later because they are both mandatory for a pivot table.
836 See the large comment at the top of pivot-table.h for general advice on
837 creating pivot tables. */
839 pivot_table_create__ (struct pivot_value *title, const char *subtype)
841 struct pivot_table *table = xzalloc (sizeof *table);
843 table->show_title = true;
844 table->show_caption = true;
845 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
846 table->title = title;
847 table->subtype = subtype ? pivot_value_new_text (subtype) : NULL;
848 table->command_c = output_get_command_name ();
849 table->look = pivot_table_look_ref (pivot_table_look_get_default ());
851 hmap_init (&table->cells);
856 /* Creates and returns a new pivot table with the given TITLE and a single cell
857 with the given CONTENT.
859 This is really just for error handling. */
861 pivot_table_create_for_text (struct pivot_value *title,
862 struct pivot_value *content)
864 struct pivot_table *table = pivot_table_create__ (title, "Error");
866 struct pivot_dimension *d = pivot_dimension_create (
867 table, PIVOT_AXIS_ROW, N_("Error"));
868 d->hide_all_labels = true;
869 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
871 pivot_table_put1 (table, 0, content);
876 /* Increases TABLE's reference count, indicating that it has an additional
877 owner. A pivot table that is shared among multiple owners must not be
880 pivot_table_ref (const struct pivot_table *table_)
882 struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
887 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
888 If TABLE no longer has any owners, it is freed. */
890 pivot_table_unref (struct pivot_table *table)
894 assert (table->ref_cnt > 0);
895 if (--table->ref_cnt)
898 free (table->current_layer);
899 pivot_table_look_unref (table->look);
901 for (int i = 0; i < TABLE_N_AXES; i++)
902 pivot_table_sizing_uninit (&table->sizing[i]);
904 for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
905 free (table->ccs[i]);
907 free (table->command_local);
908 free (table->command_c);
909 free (table->language);
910 free (table->locale);
912 free (table->dataset);
913 free (table->datafile);
915 for (size_t i = 0; i < table->n_footnotes; i++)
916 pivot_footnote_destroy (table->footnotes[i]);
917 free (table->footnotes);
919 pivot_value_destroy (table->title);
920 pivot_value_destroy (table->subtype);
921 pivot_value_destroy (table->corner_text);
922 pivot_value_destroy (table->caption);
925 for (size_t i = 0; i < table->n_dimensions; i++)
926 pivot_dimension_destroy (table->dimensions[i]);
927 free (table->dimensions);
929 for (size_t i = 0; i < PIVOT_N_AXES; i++)
930 free (table->axes[i].dimensions);
932 struct pivot_cell *cell, *next_cell;
933 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
936 hmap_delete (&table->cells, &cell->hmap_node);
937 pivot_value_destroy (cell->value);
940 hmap_destroy (&table->cells);
945 /* Returns true if TABLE has more than one owner. A pivot table that is shared
946 among multiple owners must not be modified. */
948 pivot_table_is_shared (const struct pivot_table *table)
950 return table->ref_cnt > 1;
953 const struct pivot_table_look *
954 pivot_table_get_look (const struct pivot_table *table)
960 pivot_table_set_look (struct pivot_table *table,
961 const struct pivot_table_look *look)
963 pivot_table_look_unref (table->look);
964 table->look = pivot_table_look_ref (look);
967 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
968 WV, which should be the weight variable for the dictionary whose data or
969 statistics are being put into TABLE.
971 This has no effect if WV is NULL. */
973 pivot_table_set_weight_var (struct pivot_table *table,
974 const struct variable *wv)
977 pivot_table_set_weight_format (table, var_get_print_format (wv));
980 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
981 format for the dictionary whose data or statistics are being put into TABLE.
983 This has no effect if WFMT is NULL. */
985 pivot_table_set_weight_format (struct pivot_table *table,
986 const struct fmt_spec *wfmt)
989 table->weight_format = *wfmt;
992 /* Returns true if TABLE has no cells, false otherwise. */
994 pivot_table_is_empty (const struct pivot_table *table)
996 return hmap_is_empty (&table->cells);
1000 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
1002 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
1006 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
1008 for (size_t i = 0; i < n; i++)
1015 static struct pivot_cell *
1016 pivot_table_lookup_cell__ (const struct pivot_table *table,
1017 const size_t *dindexes, unsigned int hash)
1019 struct pivot_cell *cell;
1020 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
1022 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
1027 static struct pivot_cell *
1028 pivot_cell_allocate (size_t n_idx)
1030 struct pivot_cell *cell UNUSED;
1031 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
1034 static struct pivot_cell *
1035 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
1037 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1038 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
1041 cell = pivot_cell_allocate (table->n_dimensions);
1042 for (size_t i = 0; i < table->n_dimensions; i++)
1043 cell->idx[i] = dindexes[i];
1045 hmap_insert (&table->cells, &cell->hmap_node, hash);
1050 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
1051 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
1054 If VALUE is a numeric value without a specified format, this function checks
1055 each of the categories designated by DINDEXES[] and takes the format from
1056 the first category with a result class. If none has a result class, uses
1057 the overall default numeric format. */
1059 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
1060 struct pivot_value *value)
1062 assert (n == table->n_dimensions);
1063 for (size_t i = 0; i < n; i++)
1064 assert (dindexes[i] < table->dimensions[i]->n_leaves);
1066 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
1068 for (size_t i = 0; i < table->n_dimensions; i++)
1070 const struct pivot_dimension *d = table->dimensions[i];
1071 if (dindexes[i] < d->n_leaves)
1073 const struct pivot_category *c = d->data_leaves[dindexes[i]];
1076 value->numeric.format = c->format;
1081 value->numeric.format = *settings_get_format ();
1086 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1087 pivot_value_destroy (cell->value);
1088 cell->value = value;
1091 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
1092 dimension. Takes ownership of VALUE. */
1094 pivot_table_put1 (struct pivot_table *table, size_t idx1,
1095 struct pivot_value *value)
1097 size_t dindexes[] = { idx1 };
1098 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1101 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
1102 dimensions. Takes ownership of VALUE. */
1104 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
1105 struct pivot_value *value)
1107 size_t dindexes[] = { idx1, idx2 };
1108 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1111 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
1112 have 3 dimensions. Takes ownership of VALUE. */
1114 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
1115 size_t idx3, struct pivot_value *value)
1117 size_t dindexes[] = { idx1, idx2, idx3 };
1118 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1121 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
1122 must have 4 dimensions. Takes ownership of VALUE. */
1124 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1125 size_t idx3, size_t idx4, struct pivot_value *value)
1127 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1128 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1131 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1132 automatically assigned marker.
1134 The footnote will only appear in output if it is referenced. Use
1135 pivot_value_add_footnote() to add a reference to the footnote. */
1136 struct pivot_footnote *
1137 pivot_table_create_footnote (struct pivot_table *table,
1138 struct pivot_value *content)
1140 return pivot_table_create_footnote__ (table, table->n_footnotes,
1144 static struct pivot_value *
1145 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1147 char text[INT_BUFSIZE_BOUND (size_t)];
1148 if (show_numeric_markers)
1149 snprintf (text, sizeof text, "%d", idx + 1);
1151 str_format_26adic (idx + 1, false, text, sizeof text);
1152 return pivot_value_new_user_text (text, -1);
1155 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1156 all lower indexes as a side effect). If MARKER is nonnull, sets the
1157 footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1158 struct pivot_footnote *
1159 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1160 struct pivot_value *marker,
1161 struct pivot_value *content)
1163 if (idx >= table->n_footnotes)
1165 while (idx >= table->allocated_footnotes)
1166 table->footnotes = x2nrealloc (table->footnotes,
1167 &table->allocated_footnotes,
1168 sizeof *table->footnotes);
1169 while (idx >= table->n_footnotes)
1171 struct pivot_footnote *f = xmalloc (sizeof *f);
1172 f->idx = table->n_footnotes;
1173 f->marker = pivot_make_default_footnote_marker (
1174 f->idx, table->look->show_numeric_markers);
1178 table->footnotes[table->n_footnotes++] = f;
1182 struct pivot_footnote *f = table->footnotes[idx];
1185 pivot_value_destroy (f->marker);
1190 pivot_value_destroy (f->content);
1191 f->content = content;
1196 /* Frees the data owned by F. */
1198 pivot_footnote_destroy (struct pivot_footnote *f)
1202 pivot_value_destroy (f->content);
1203 pivot_value_destroy (f->marker);
1208 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1209 indexes for each dimension in TABLE in DINDEXES[]. */
1211 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1212 const size_t *pindexes[PIVOT_N_AXES],
1213 size_t dindexes[/* table->n_dimensions */])
1215 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1217 const struct pivot_axis *axis = &table->axes[i];
1219 for (size_t j = 0; j < axis->n_dimensions; j++)
1221 const struct pivot_dimension *d = axis->dimensions[j];
1222 dindexes[d->top_index]
1223 = d->presentation_leaves[pindexes[i][j]]->data_index;
1229 pivot_table_enumerate_axis (const struct pivot_table *table,
1230 enum pivot_axis_type axis_type,
1231 const size_t *layer_indexes, bool omit_empty,
1234 const struct pivot_axis *axis = &table->axes[axis_type];
1235 if (!axis->n_dimensions)
1237 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1239 enumeration[1] = SIZE_MAX;
1244 else if (!axis->extent)
1246 size_t *enumeration = xmalloc (sizeof *enumeration);
1247 *enumeration = SIZE_MAX;
1253 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1254 axis->n_dimensions), 1),
1255 sizeof *enumeration);
1256 size_t *p = enumeration;
1257 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1259 size_t *axis_indexes;
1260 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1264 enum pivot_axis_type axis2_type
1265 = pivot_axis_type_transpose (axis_type);
1267 size_t *axis2_indexes;
1268 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1270 const size_t *pindexes[PIVOT_N_AXES];
1271 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1272 pindexes[axis_type] = axis_indexes;
1273 pindexes[axis2_type] = axis2_indexes;
1274 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1275 if (pivot_table_get (table, dindexes))
1281 free (axis2_indexes);
1284 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1285 p += axis->n_dimensions;
1287 if (omit_empty && p == enumeration)
1289 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1291 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1292 p += axis->n_dimensions;
1297 *n = (p - enumeration) / axis->n_dimensions;
1303 static const struct pivot_cell *
1304 pivot_table_lookup_cell (const struct pivot_table *table,
1305 const size_t *dindexes)
1307 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1308 return pivot_table_lookup_cell__ (table, dindexes, hash);
1311 const struct pivot_value *
1312 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1314 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1315 return cell ? cell->value : NULL;
1318 struct pivot_value *
1319 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1321 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1323 cell->value = pivot_value_new_user_text ("", -1);
1328 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1330 if (pivot_category_is_group (category) && category->n_subs)
1331 for (size_t i = 0; i < category->n_subs; i++)
1332 distribute_extra_depth (category->subs[i], extra_depth);
1334 category->extra_depth += extra_depth;
1338 pivot_category_assign_label_depth (struct pivot_category *category,
1339 bool dimension_labels_in_corner)
1341 category->extra_depth = 0;
1343 if (pivot_category_is_group (category))
1346 for (size_t i = 0; i < category->n_subs; i++)
1348 pivot_category_assign_label_depth (category->subs[i], false);
1349 depth = MAX (depth, category->subs[i]->label_depth);
1352 for (size_t i = 0; i < category->n_subs; i++)
1354 struct pivot_category *sub = category->subs[i];
1356 size_t extra_depth = depth - sub->label_depth;
1358 distribute_extra_depth (sub, extra_depth);
1360 sub->label_depth = depth;
1363 category->show_label_in_corner = (category->show_label
1364 && dimension_labels_in_corner);
1365 category->label_depth
1366 = (category->show_label && !category->show_label_in_corner
1367 ? depth + 1 : depth);
1370 category->label_depth = 1;
1374 pivot_axis_assign_label_depth (struct pivot_table *table,
1375 enum pivot_axis_type axis_type,
1376 bool dimension_labels_in_corner)
1378 struct pivot_axis *axis = &table->axes[axis_type];
1379 bool any_label_shown_in_corner = false;
1380 axis->label_depth = 0;
1382 for (size_t i = 0; i < axis->n_dimensions; i++)
1384 struct pivot_dimension *d = axis->dimensions[i];
1385 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1386 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1387 axis->label_depth += d->label_depth;
1388 axis->extent *= d->n_leaves;
1390 if (d->root->show_label_in_corner)
1391 any_label_shown_in_corner = true;
1393 return any_label_shown_in_corner;
1397 pivot_table_assign_label_depth (struct pivot_table *table)
1399 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1400 if (pivot_axis_assign_label_depth (
1401 table, PIVOT_AXIS_ROW, (table->look->row_labels_in_corner
1402 && !table->corner_text))
1403 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1404 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1405 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1409 indent (int indentation)
1411 for (int i = 0; i < indentation * 2; i++)
1416 pivot_value_dump (const struct pivot_value *value)
1418 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1419 SETTINGS_VALUE_SHOW_DEFAULT);
1425 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1430 indent (indentation);
1431 printf ("%s: ", name);
1432 pivot_value_dump (value);
1438 pivot_table_dump_string (const char *string, const char *name, int indentation)
1442 indent (indentation);
1443 printf ("%s: %s\n", name, string);
1448 pivot_category_dump (const struct pivot_category *c, int indentation)
1450 indent (indentation);
1451 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1452 pivot_value_dump (c->name);
1455 if (pivot_category_is_leaf (c))
1456 printf ("data_index=%zu\n", c->data_index);
1459 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1462 for (size_t i = 0; i < c->n_subs; i++)
1463 pivot_category_dump (c->subs[i], indentation + 1);
1468 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1470 indent (indentation);
1471 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1472 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1474 pivot_category_dump (d->root, indentation + 1);
1478 table_area_style_dump (enum pivot_area area, const struct table_area_style *a,
1481 indent (indentation);
1482 printf ("%s: ", pivot_area_to_string (area));
1483 font_style_dump (&a->font_style);
1485 cell_style_dump (&a->cell_style);
1490 table_border_style_dump (enum pivot_border border,
1491 const struct table_border_style *b, int indentation)
1493 indent (indentation);
1494 printf ("%s: %s ", pivot_border_to_string (border),
1495 table_stroke_to_string (b->stroke));
1496 cell_color_dump (&b->color);
1501 compose_headings (const struct pivot_axis *axis,
1502 const size_t *column_enumeration,
1503 enum settings_value_show show_values,
1504 enum settings_value_show show_variables)
1506 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1509 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1510 for (size_t i = 0; i < axis->label_depth; i++)
1511 headings[i] = xcalloc (axis->extent, sizeof **headings);
1513 const size_t *indexes;
1515 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1517 int row = axis->label_depth - 1;
1518 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1520 const struct pivot_dimension *d = axis->dimensions[dim_index];
1521 if (d->hide_all_labels)
1523 for (const struct pivot_category *c
1524 = d->presentation_leaves[indexes[dim_index]];
1528 if (pivot_category_is_leaf (c) || (c->show_label
1529 && !c->show_label_in_corner))
1531 headings[row][column] = pivot_value_to_string (
1532 c->name, show_values, show_variables);
1533 if (!*headings[row][column])
1534 headings[row][column] = xstrdup ("<blank>");
1546 free_headings (const struct pivot_axis *axis, char ***headings)
1548 for (size_t i = 0; i < axis->label_depth; i++)
1550 for (size_t j = 0; j < axis->extent; j++)
1551 free (headings[i][j]);
1558 pivot_table_sizing_dump (const char *name,
1559 const int width_ranges[2],
1560 const struct pivot_table_sizing *s,
1563 indent (indentation);
1564 printf ("%ss: min=%d, max=%d\n", name, width_ranges[0], width_ranges[1]);
1567 indent (indentation + 1);
1568 printf ("%s widths:", name);
1569 for (size_t i = 0; i < s->n_widths; i++)
1570 printf (" %d", s->widths[i]);
1575 indent (indentation + 1);
1576 printf ("break after %ss:", name);
1577 for (size_t i = 0; i < s->n_breaks; i++)
1578 printf (" %zu", s->breaks[i]);
1583 indent (indentation + 1);
1584 printf ("keep %ss together:", name);
1585 for (size_t i = 0; i < s->n_keeps; i++)
1586 printf (" [%zu,%zu]",
1588 s->keeps[i].ofs + s->keeps[i].n - 1);
1594 pivot_table_dump (const struct pivot_table *table, int indentation)
1599 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1600 if (table->decimal == '.' || table->decimal == ',')
1601 settings_set_decimal_char (table->decimal);
1603 pivot_table_dump_value (table->title, "title", indentation);
1604 pivot_table_dump_value (table->subtype, "subtype", indentation);
1605 pivot_table_dump_string (table->command_c, "command", indentation);
1606 pivot_table_dump_string (table->dataset, "dataset", indentation);
1607 pivot_table_dump_string (table->datafile, "datafile", indentation);
1608 pivot_table_dump_string (table->notes, "notes", indentation);
1609 pivot_table_dump_string (table->look->name, "table-look", indentation);
1612 indent (indentation);
1614 struct tm *tm = localtime (&table->date);
1615 printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
1616 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
1620 indent (indentation);
1621 printf ("sizing:\n");
1622 pivot_table_sizing_dump ("column", table->look->width_ranges[TABLE_HORZ],
1623 &table->sizing[TABLE_HORZ], indentation + 1);
1624 pivot_table_sizing_dump ("row", table->look->width_ranges[TABLE_VERT],
1625 &table->sizing[TABLE_VERT], indentation + 1);
1627 indent (indentation);
1628 printf ("areas:\n");
1629 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1630 table_area_style_dump (area, &table->look->areas[area], indentation + 1);
1632 indent (indentation);
1633 printf ("borders:\n");
1634 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1635 table_border_style_dump (border, &table->look->borders[border],
1638 for (size_t i = 0; i < table->n_dimensions; i++)
1639 pivot_dimension_dump (table->dimensions[i], indentation);
1641 /* Presentation and data indexes. */
1642 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1644 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1645 if (layer_axis->n_dimensions)
1647 indent (indentation);
1648 printf ("current layer:");
1650 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1652 const struct pivot_dimension *d = layer_axis->dimensions[i];
1653 char *name = pivot_value_to_string (d->root->name,
1655 table->show_variables);
1656 char *value = pivot_value_to_string (
1657 d->data_leaves[table->current_layer[i]]->name,
1658 table->show_values, table->show_variables);
1659 printf (" %s=%s", name, value);
1667 size_t *layer_indexes;
1668 size_t layer_iteration = 0;
1669 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1671 indent (indentation);
1672 printf ("layer %zu:", layer_iteration++);
1674 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1675 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1677 const struct pivot_dimension *d = layer_axis->dimensions[i];
1679 fputs (i == 0 ? " " : ", ", stdout);
1680 pivot_value_dump (d->root->name);
1681 fputs (" =", stdout);
1683 struct pivot_value **names = xnmalloc (d->n_leaves, sizeof *names);
1685 for (const struct pivot_category *c
1686 = d->presentation_leaves[layer_indexes[i]];
1690 if (pivot_category_is_leaf (c) || c->show_label)
1691 names[n_names++] = c->name;
1694 for (size_t i = n_names; i-- > 0;)
1697 pivot_value_dump (names[i]);
1703 size_t *column_enumeration = pivot_table_enumerate_axis (
1704 table, PIVOT_AXIS_COLUMN, layer_indexes, table->look->omit_empty, NULL);
1705 size_t *row_enumeration = pivot_table_enumerate_axis (
1706 table, PIVOT_AXIS_ROW, layer_indexes, table->look->omit_empty, NULL);
1708 char ***column_headings = compose_headings (
1709 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1710 table->show_values, table->show_variables);
1711 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1713 indent (indentation + 1);
1714 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1717 fputs ("; ", stdout);
1718 if (column_headings[y][x])
1719 fputs (column_headings[y][x], stdout);
1723 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1725 indent (indentation + 1);
1726 printf ("-----------------------------------------------\n");
1728 char ***row_headings = compose_headings (
1729 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1730 table->show_values, table->show_variables);
1733 const size_t *pindexes[PIVOT_N_AXES]
1734 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1735 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1736 &table->axes[PIVOT_AXIS_ROW])
1738 indent (indentation + 1);
1741 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1744 fputs ("; ", stdout);
1745 if (row_headings[y][x])
1746 fputs (row_headings[y][x], stdout);
1752 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1754 &table->axes[PIVOT_AXIS_COLUMN])
1759 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1760 const struct pivot_value *value = pivot_table_get (
1763 pivot_value_dump (value);
1770 free (column_enumeration);
1771 free (row_enumeration);
1772 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1775 pivot_table_dump_value (table->caption, "caption", indentation);
1777 for (size_t i = 0; i < table->n_footnotes; i++)
1779 const struct pivot_footnote *f = table->footnotes[i];
1780 indent (indentation);
1783 pivot_value_dump (f->marker);
1785 printf ("%zu", f->idx);
1787 pivot_value_dump (f->content);
1792 settings_set_decimal_char (old_decimal);
1796 consume_int (const char *p, size_t *n)
1799 while (c_isdigit (*p))
1800 *n = *n * 10 + (*p++ - '0');
1805 pivot_format_inner_template (struct string *out, const char *template,
1807 struct pivot_value **values, size_t n_values,
1808 enum settings_value_show show_values,
1809 enum settings_value_show show_variables)
1811 size_t args_consumed = 0;
1812 while (*template && *template != ':')
1814 if (*template == '\\' && template[1])
1816 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1819 else if (*template == escape)
1822 template = consume_int (template + 1, &index);
1823 if (index >= 1 && index <= n_values)
1825 pivot_value_format (values[index - 1], show_values,
1826 show_variables, out);
1827 args_consumed = MAX (args_consumed, index);
1831 ds_put_byte (out, *template++);
1833 return args_consumed;
1837 pivot_extract_inner_template (const char *template, const char **p)
1843 if (*template == '\\' && template[1] != '\0')
1845 else if (*template == ':')
1846 return template + 1;
1847 else if (*template == '\0')
1855 pivot_format_template (struct string *out, const char *template,
1856 const struct pivot_argument *args, size_t n_args,
1857 enum settings_value_show show_values,
1858 enum settings_value_show show_variables)
1862 if (*template == '\\' && template[1] != '\0')
1864 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1867 else if (*template == '^')
1870 template = consume_int (template + 1, &index);
1871 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1872 pivot_value_format (args[index - 1].values[0],
1873 show_values, show_variables, out);
1875 else if (*template == '[')
1877 const char *tmpl[2];
1878 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1879 template = pivot_extract_inner_template (template, &tmpl[1]);
1880 template += *template == ']';
1883 template = consume_int (template, &index);
1884 if (index < 1 || index > n_args)
1887 const struct pivot_argument *arg = &args[index - 1];
1888 size_t left = arg->n;
1891 struct pivot_value **values = arg->values + (arg->n - left);
1892 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1893 char escape = "%^"[tmpl_idx];
1894 size_t used = pivot_format_inner_template (
1895 out, tmpl[tmpl_idx], escape, values, left,
1896 show_values, show_variables);
1897 if (!used || used > left)
1903 ds_put_byte (out, *template++);
1907 static enum settings_value_show
1908 interpret_show (enum settings_value_show global_show,
1909 enum settings_value_show table_show,
1910 enum settings_value_show value_show,
1913 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1914 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1915 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1919 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1920 SHOW_VARIABLES control whether variable and value labels are included.
1922 The "body" omits subscripts and superscripts and footnotes.
1924 Returns true if OUT is a number (or a number plus a value label), false
1927 pivot_value_format_body (const struct pivot_value *value,
1928 enum settings_value_show show_values,
1929 enum settings_value_show show_variables,
1932 enum settings_value_show show;
1933 bool numeric = false;
1935 switch (value->type)
1937 case PIVOT_VALUE_NUMERIC:
1938 show = interpret_show (settings_get_show_values (),
1940 value->numeric.show,
1941 value->numeric.value_label != NULL);
1942 if (show & SETTINGS_VALUE_SHOW_VALUE)
1944 char *s = data_out (&(union value) { .f = value->numeric.x },
1945 "UTF-8", &value->numeric.format);
1946 ds_put_cstr (out, s + strspn (s, " "));
1949 if (show & SETTINGS_VALUE_SHOW_LABEL)
1951 if (show & SETTINGS_VALUE_SHOW_VALUE)
1952 ds_put_byte (out, ' ');
1953 ds_put_cstr (out, value->numeric.value_label);
1955 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1958 case PIVOT_VALUE_STRING:
1959 show = interpret_show (settings_get_show_values (),
1962 value->string.value_label != NULL);
1963 if (show & SETTINGS_VALUE_SHOW_VALUE)
1965 if (value->string.hex)
1967 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1969 ds_put_format (out, "%02X", *p);
1972 ds_put_cstr (out, value->string.s);
1974 if (show & SETTINGS_VALUE_SHOW_LABEL)
1976 if (show & SETTINGS_VALUE_SHOW_VALUE)
1977 ds_put_byte (out, ' ');
1978 ds_put_cstr (out, value->string.value_label);
1982 case PIVOT_VALUE_VARIABLE:
1983 show = interpret_show (settings_get_show_variables (),
1985 value->variable.show,
1986 value->variable.var_label != NULL);
1987 if (show & SETTINGS_VALUE_SHOW_VALUE)
1988 ds_put_cstr (out, value->variable.var_name);
1989 if (show & SETTINGS_VALUE_SHOW_LABEL)
1991 if (show & SETTINGS_VALUE_SHOW_VALUE)
1992 ds_put_byte (out, ' ');
1993 ds_put_cstr (out, value->variable.var_label);
1997 case PIVOT_VALUE_TEXT:
1998 ds_put_cstr (out, value->text.local);
2001 case PIVOT_VALUE_TEMPLATE:
2002 pivot_format_template (out, value->template.local, value->template.args,
2003 value->template.n_args, show_values,
2011 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
2012 SHOW_VARIABLES control whether variable and value labels are included.
2014 Subscripts and footnotes are included. */
2016 pivot_value_format (const struct pivot_value *value,
2017 enum settings_value_show show_values,
2018 enum settings_value_show show_variables,
2021 pivot_value_format_body (value, show_values, show_variables, out);
2023 if (value->n_subscripts)
2025 for (size_t i = 0; i < value->n_subscripts; i++)
2026 ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
2029 for (size_t i = 0; i < value->n_footnotes; i++)
2031 ds_put_byte (out, '^');
2032 pivot_value_format (value->footnotes[i]->marker,
2033 show_values, show_variables, out);
2037 /* Returns a text representation of VALUE. The caller must free the string,
2040 pivot_value_to_string (const struct pivot_value *value,
2041 enum settings_value_show show_values,
2042 enum settings_value_show show_variables)
2044 struct string s = DS_EMPTY_INITIALIZER;
2045 pivot_value_format (value, show_values, show_variables, &s);
2046 return ds_steal_cstr (&s);
2050 xstrdup_if_nonnull (const char *s)
2052 return s ? xstrdup (s) : NULL;
2055 struct pivot_value *
2056 pivot_value_clone (const struct pivot_value *old)
2058 struct pivot_value *new = xmemdup (old, sizeof *new);
2059 if (old->font_style)
2061 new->font_style = xmalloc (sizeof *new->font_style);
2062 font_style_copy (NULL, new->font_style, old->font_style);
2064 if (old->cell_style)
2065 new->font_style = xmemdup (old->font_style, sizeof *new->font_style);
2066 if (old->n_subscripts)
2068 new->subscripts = xnmalloc (old->n_subscripts, sizeof *new->subscripts);
2069 for (size_t i = 0; i < old->n_subscripts; i++)
2070 new->subscripts[i] = xstrdup (old->subscripts[i]);
2072 if (old->n_footnotes)
2073 new->footnotes = xmemdup (old->footnotes,
2074 old->n_footnotes * sizeof *new->footnotes);
2078 case PIVOT_VALUE_NUMERIC:
2079 new->numeric.var_name = xstrdup_if_nonnull (new->numeric.var_name);
2080 new->numeric.value_label = xstrdup_if_nonnull (new->numeric.value_label);
2083 case PIVOT_VALUE_STRING:
2084 new->string.s = xstrdup (new->string.s);
2085 new->string.var_name = xstrdup_if_nonnull (new->string.var_name);
2086 new->string.value_label = xstrdup_if_nonnull (new->string.value_label);
2089 case PIVOT_VALUE_VARIABLE:
2090 new->variable.var_name = xstrdup_if_nonnull (new->variable.var_name);
2091 new->variable.var_label = xstrdup_if_nonnull (new->variable.var_label);
2094 case PIVOT_VALUE_TEXT:
2095 new->text.local = xstrdup (old->text.local);
2096 new->text.c = (old->text.c == old->text.local ? new->text.local
2097 : xstrdup (old->text.c));
2098 new->text.id = (old->text.id == old->text.local ? new->text.local
2099 : old->text.id == old->text.c ? new->text.c
2100 : xstrdup (old->text.id));
2103 case PIVOT_VALUE_TEMPLATE:
2104 new->template.local = xstrdup (old->template.local);
2105 new->template.id = (old->template.id == old->template.local
2106 ? new->template.local
2107 : xstrdup (old->template.id));
2108 new->template.args = xmalloc (new->template.n_args
2109 * sizeof *new->template.args);
2110 for (size_t i = 0; i < old->template.n_args; i++)
2111 pivot_argument_copy (&new->template.args[i],
2112 &old->template.args[i]);
2121 /* Frees the data owned by V. */
2123 pivot_value_destroy (struct pivot_value *value)
2127 font_style_uninit (value->font_style);
2128 free (value->font_style);
2129 free (value->cell_style);
2130 /* Do not free the elements of footnotes because VALUE does not own
2132 free (value->footnotes);
2134 for (size_t i = 0; i < value->n_subscripts; i++)
2135 free (value->subscripts[i]);
2136 free (value->subscripts);
2138 switch (value->type)
2140 case PIVOT_VALUE_NUMERIC:
2141 free (value->numeric.var_name);
2142 free (value->numeric.value_label);
2145 case PIVOT_VALUE_STRING:
2146 free (value->string.s);
2147 free (value->string.var_name);
2148 free (value->string.value_label);
2151 case PIVOT_VALUE_VARIABLE:
2152 free (value->variable.var_name);
2153 free (value->variable.var_label);
2156 case PIVOT_VALUE_TEXT:
2157 free (value->text.local);
2158 if (value->text.c != value->text.local)
2159 free (value->text.c);
2160 if (value->text.id != value->text.local
2161 && value->text.id != value->text.c)
2162 free (value->text.id);
2165 case PIVOT_VALUE_TEMPLATE:
2166 free (value->template.local);
2167 if (value->template.id != value->template.local)
2168 free (value->template.id);
2169 for (size_t i = 0; i < value->template.n_args; i++)
2170 pivot_argument_uninit (&value->template.args[i]);
2171 free (value->template.args);
2181 /* Sets AREA to the style to use for VALUE, with defaults coming from
2182 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
2184 pivot_value_get_style (struct pivot_value *value,
2185 const struct font_style *base_font_style,
2186 const struct cell_style *base_cell_style,
2187 struct table_area_style *area)
2189 font_style_copy (NULL, &area->font_style, (value->font_style
2191 : base_font_style));
2192 area->cell_style = *(value->cell_style
2197 /* Copies AREA into VALUE's style. */
2199 pivot_value_set_style (struct pivot_value *value,
2200 const struct table_area_style *area)
2202 pivot_value_set_font_style (value, &area->font_style);
2203 pivot_value_set_cell_style (value, &area->cell_style);
2207 pivot_value_set_font_style (struct pivot_value *value,
2208 const struct font_style *font_style)
2210 if (value->font_style)
2211 font_style_uninit (value->font_style);
2213 value->font_style = xmalloc (sizeof *value->font_style);
2214 font_style_copy (NULL, value->font_style, font_style);
2218 pivot_value_set_cell_style (struct pivot_value *value,
2219 const struct cell_style *cell_style)
2221 if (!value->cell_style)
2222 value->cell_style = xmalloc (sizeof *value->cell_style);
2223 *value->cell_style = *cell_style;
2227 pivot_argument_copy (struct pivot_argument *dst,
2228 const struct pivot_argument *src)
2230 *dst = (struct pivot_argument) {
2232 .values = xmalloc (src->n * sizeof *dst->values),
2235 for (size_t i = 0; i < src->n; i++)
2236 dst->values[i] = pivot_value_clone (src->values[i]);
2239 /* Frees the data owned by ARG (but not ARG itself). */
2241 pivot_argument_uninit (struct pivot_argument *arg)
2245 for (size_t i = 0; i < arg->n; i++)
2246 pivot_value_destroy (arg->values[i]);
2251 /* Creates and returns a new pivot_value whose contents is the null-terminated
2252 string TEXT. Takes ownership of TEXT.
2254 This function is for text strings provided by the user (with the exception
2255 that pivot_value_new_variable() should be used for variable names). For
2256 strings that are part of the PSPP user interface, such as names of
2257 procedures, statistics, annotations, error messages, etc., use
2258 pivot_value_new_text(). */
2259 struct pivot_value *
2260 pivot_value_new_user_text_nocopy (char *text)
2262 struct pivot_value *value = xmalloc (sizeof *value);
2263 *value = (struct pivot_value) {
2264 .type = PIVOT_VALUE_TEXT,
2269 .user_provided = true,
2275 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2276 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2279 This function is for text strings provided by the user (with the exception
2280 that pivot_value_new_variable() should be used for variable names). For
2281 strings that are part of the PSPP user interface, such as names of
2282 procedures, statistics, annotations, error messages, etc., use
2283 pivot_value_new_text().j
2285 The caller retains ownership of TEXT.*/
2286 struct pivot_value *
2287 pivot_value_new_user_text (const char *text, size_t length)
2289 return pivot_value_new_user_text_nocopy (
2290 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2293 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2294 a translatable string, but not actually translated yet, e.g. enclosed in
2295 N_(). This function is for text strings that are part of the PSPP user
2296 interface, such as names of procedures, statistics, annotations, error
2297 messages, etc. For strings that come from the user, use
2298 pivot_value_new_user_text(). */
2299 struct pivot_value *
2300 pivot_value_new_text (const char *text)
2302 char *c = xstrdup (text);
2303 char *local = xstrdup (gettext (c));
2305 struct pivot_value *value = xmalloc (sizeof *value);
2306 *value = (struct pivot_value) {
2307 .type = PIVOT_VALUE_TEXT,
2312 .user_provided = false,
2318 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2320 struct pivot_value * PRINTF_FORMAT (1, 2)
2321 pivot_value_new_text_format (const char *format, ...)
2324 va_start (args, format);
2325 char *c = xvasprintf (format, args);
2328 va_start (args, format);
2329 char *local = xvasprintf (gettext (format), args);
2332 struct pivot_value *value = xmalloc (sizeof *value);
2333 *value = (struct pivot_value) {
2334 .type = PIVOT_VALUE_TEXT,
2339 .user_provided = false,
2345 /* Returns a new pivot_value that represents X.
2347 The format to use for X is unspecified. Usually the easiest way to specify
2348 a format is through assigning a result class to one of the categories that
2349 the pivot_value will end up in. If that is not suitable, then the caller
2350 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2351 struct pivot_value *
2352 pivot_value_new_number (double x)
2354 struct pivot_value *value = xmalloc (sizeof *value);
2355 *value = (struct pivot_value) {
2356 .type = PIVOT_VALUE_NUMERIC,
2357 .numeric = { .x = x, },
2362 /* Returns a new pivot_value that represents X, formatted as an integer. */
2363 struct pivot_value *
2364 pivot_value_new_integer (double x)
2366 struct pivot_value *value = pivot_value_new_number (x);
2367 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2371 /* Returns a new pivot_value that represents VALUE, formatted as for
2373 struct pivot_value *
2374 pivot_value_new_var_value (const struct variable *variable,
2375 const union value *value)
2377 struct pivot_value *pv = pivot_value_new_value (
2378 value, var_get_width (variable), var_get_print_format (variable),
2379 var_get_encoding (variable));
2381 char *var_name = xstrdup (var_get_name (variable));
2382 if (var_is_alpha (variable))
2383 pv->string.var_name = var_name;
2385 pv->numeric.var_name = var_name;
2387 const char *label = var_lookup_value_label (variable, value);
2390 if (var_is_alpha (variable))
2391 pv->string.value_label = xstrdup (label);
2393 pv->numeric.value_label = xstrdup (label);
2399 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2400 formatted with FORMAT. For a string value, ENCODING must be its character
2402 struct pivot_value *
2403 pivot_value_new_value (const union value *value, int width,
2404 const struct fmt_spec *format, const char *encoding)
2406 struct pivot_value *pv = xzalloc (sizeof *pv);
2409 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2411 size_t n = strlen (s);
2412 while (n > 0 && s[n - 1] == ' ')
2415 pv->type = PIVOT_VALUE_STRING;
2417 pv->string.hex = format->type == FMT_AHEX;
2421 pv->type = PIVOT_VALUE_NUMERIC;
2422 pv->numeric.x = value->f;
2423 pv->numeric.format = *format;
2429 /* Returns a new pivot_value for VARIABLE. */
2430 struct pivot_value *
2431 pivot_value_new_variable (const struct variable *variable)
2433 struct pivot_value *value = xmalloc (sizeof *value);
2434 *value = (struct pivot_value) {
2435 .type = PIVOT_VALUE_VARIABLE,
2437 .var_name = xstrdup (var_get_name (variable)),
2438 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2444 /* Attaches a reference to FOOTNOTE to V. */
2446 pivot_value_add_footnote (struct pivot_value *v,
2447 const struct pivot_footnote *footnote)
2449 /* Some legacy tables include numerous duplicate footnotes. Suppress
2451 for (size_t i = 0; i < v->n_footnotes; i++)
2452 if (v->footnotes[i] == footnote)
2455 v->footnotes = xrealloc (v->footnotes,
2456 (v->n_footnotes + 1) * sizeof *v->footnotes);
2457 v->footnotes[v->n_footnotes++] = footnote;
2460 /* If VALUE is a numeric value, and RC is a result class such as
2461 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2463 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2466 if (value->type == PIVOT_VALUE_NUMERIC)
2468 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2470 value->numeric.format = *f;