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 const struct table_area_style *
66 pivot_area_get_default_style (enum pivot_area area)
68 #define STYLE(BOLD, H, V, L, R, T, B) { \
70 .halign = TABLE_HALIGN_##H, \
71 .valign = TABLE_VALIGN_##V, \
72 .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
73 [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
77 .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
78 .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
80 .typeface = (char *) "Sans Serif", \
83 static const struct table_area_style default_area_styles[PIVOT_N_AREAS] = {
84 [PIVOT_AREA_TITLE] = STYLE(true, CENTER, CENTER, 8,11,1,8),
85 [PIVOT_AREA_CAPTION] = STYLE(false, LEFT, TOP, 8,11,1,1),
86 [PIVOT_AREA_FOOTER] = STYLE(false, LEFT, TOP, 11, 8,2,3),
87 [PIVOT_AREA_CORNER] = STYLE(false, LEFT, BOTTOM, 8,11,1,1),
88 [PIVOT_AREA_COLUMN_LABELS] = STYLE(false, CENTER, BOTTOM, 8,11,1,3),
89 [PIVOT_AREA_ROW_LABELS] = STYLE(false, LEFT, TOP, 8,11,1,3),
90 [PIVOT_AREA_DATA] = STYLE(false, MIXED, TOP, 8,11,1,1),
91 [PIVOT_AREA_LAYERS] = STYLE(false, LEFT, BOTTOM, 8,11,1,3),
95 return &default_area_styles[area];
99 pivot_border_get_default_style (enum pivot_border border,
100 struct table_border_style *style)
102 static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
103 [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE,
104 [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE,
105 [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE,
106 [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE,
107 [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
108 [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK,
109 [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK,
110 [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK,
111 [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
112 [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK,
113 [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK,
114 [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
115 [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
116 [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
117 [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
118 [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
119 [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
120 [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
121 [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
123 *style = (struct table_border_style) {
124 .stroke = default_strokes[border],
125 .color = CELL_COLOR_BLACK,
129 /* Returns the name of BORDER. */
131 pivot_border_to_string (enum pivot_border border)
135 case PIVOT_BORDER_TITLE:
138 case PIVOT_BORDER_OUTER_LEFT:
139 return "left outer frame";
140 case PIVOT_BORDER_OUTER_TOP:
141 return "top outer frame";
142 case PIVOT_BORDER_OUTER_RIGHT:
143 return "right outer frame";
144 case PIVOT_BORDER_OUTER_BOTTOM:
145 return "bottom outer frame";
147 case PIVOT_BORDER_INNER_LEFT:
148 return "left inner frame";
149 case PIVOT_BORDER_INNER_TOP:
150 return "top inner frame";
151 case PIVOT_BORDER_INNER_RIGHT:
152 return "right inner frame";
153 case PIVOT_BORDER_INNER_BOTTOM:
154 return "bottom inner frame";
156 case PIVOT_BORDER_DATA_LEFT:
157 return "data area left";
158 case PIVOT_BORDER_DATA_TOP:
159 return "data area top";
161 case PIVOT_BORDER_DIM_ROW_HORZ:
162 return "row label horizontal dimension border";
163 case PIVOT_BORDER_DIM_ROW_VERT:
164 return "row label vertical dimension border";
165 case PIVOT_BORDER_DIM_COL_HORZ:
166 return "column label horizontal dimension border";
167 case PIVOT_BORDER_DIM_COL_VERT:
168 return "column label vertical dimension border";
170 case PIVOT_BORDER_CAT_ROW_HORZ:
171 return "row label horizontal category border";
172 case PIVOT_BORDER_CAT_ROW_VERT:
173 return "row label vertical category border";
174 case PIVOT_BORDER_CAT_COL_HORZ:
175 return "column label horizontal category border";
176 case PIVOT_BORDER_CAT_COL_VERT:
177 return "column label vertical category border";
179 case PIVOT_N_BORDERS:
186 pivot_table_sizing_uninit (struct pivot_table_sizing *sizing)
190 free (sizing->widths);
191 free (sizing->breaks);
192 free (sizing->keeps);
196 /* Pivot table looks. */
199 pivot_table_look_init (struct pivot_table_look *look)
201 memset (look, 0, sizeof *look);
203 look->omit_empty = false;
204 look->row_labels_in_corner = true;
205 look->width_ranges[TABLE_HORZ][0] = 36;
206 look->width_ranges[TABLE_HORZ][1] = 72;
207 look->width_ranges[TABLE_VERT][0] = 36;
208 look->width_ranges[TABLE_VERT][1] = 120;
210 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
211 table_area_style_copy (NULL, &look->areas[i],
212 pivot_area_get_default_style (i));
214 static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
215 [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE,
216 [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE,
217 [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE,
218 [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE,
219 [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
220 [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK,
221 [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK,
222 [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK,
223 [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
224 [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK,
225 [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK,
226 [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
227 [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
228 [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
229 [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
230 [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
231 [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
232 [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
233 [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
235 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
236 look->borders[i] = (struct table_border_style) {
237 .stroke = default_strokes[i],
238 .color = CELL_COLOR_BLACK,
243 pivot_table_look_uninit (struct pivot_table_look *look)
247 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
248 table_area_style_uninit (&look->areas[i]);
250 free (look->continuation);
254 xstrdup_if_nonempty (const char *s)
256 return s && s[0] ? xstrdup (s) : NULL;
260 pivot_table_look_copy (struct pivot_table_look *dst,
261 const struct pivot_table_look *src)
264 dst->name = xstrdup_if_nonempty (src->name);
265 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
266 table_area_style_copy (NULL, &dst->areas[i], &src->areas[i]);
267 dst->continuation = xstrdup_if_nonempty (src->continuation);
272 /* Returns the name of AXIS_TYPE. */
274 pivot_axis_type_to_string (enum pivot_axis_type axis_type)
278 case PIVOT_AXIS_LAYER:
284 case PIVOT_AXIS_COLUMN:
292 static enum pivot_axis_type
293 pivot_axis_type_transpose (enum pivot_axis_type axis_type)
295 assert (axis_type == PIVOT_AXIS_ROW || axis_type == PIVOT_AXIS_COLUMN);
296 return (axis_type == PIVOT_AXIS_ROW ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW);
299 /* Implementation of PIVOT_AXIS_FOR_EACH. */
301 pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis)
305 if (axis->n_dimensions)
306 for (size_t i = 0; i < axis->n_dimensions; i++)
307 if (axis->dimensions[i]->n_leaves == 0)
310 return xcalloc (axis->n_dimensions, sizeof *indexes);
313 for (size_t i = 0; i < axis->n_dimensions; i++)
315 const struct pivot_dimension *d = axis->dimensions[i];
316 if (++indexes[i] < d->n_leaves)
329 pivot_category_set_rc (struct pivot_category *category, const char *s)
331 const struct fmt_spec *format = pivot_table_get_format (
332 category->dimension->table, s);
334 category->format = *format;
338 pivot_category_create_leaves_valist (struct pivot_category *parent,
342 while ((s = va_arg (args, const char *)))
344 if (!strncmp (s, "RC_", 3))
346 assert (parent->n_subs);
347 pivot_category_set_rc (parent->subs[parent->n_subs - 1], s);
350 pivot_category_create_leaf (parent, pivot_value_new_text (s));
354 /* Creates a new dimension with the given NAME in TABLE and returns it. The
355 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
358 NAME should be a translatable name, but not actually translated yet,
359 e.g. enclosed in N_(). To use a different kind of value for a name, use
360 pivot_dimension_create__() instead.
362 The optional varargs parameters may be used to add an initial set of
363 categories to the dimension. Each string should be a translatable category
364 name, but not actually translated yet, e.g. enclosed in N_(). Each string
365 may optionally be followod by a PIVOT_RC_* string that specifies the default
366 numeric format for cells in this category. */
367 struct pivot_dimension * SENTINEL (0)
368 (pivot_dimension_create) (struct pivot_table *table,
369 enum pivot_axis_type axis_type,
370 const char *name, ...)
372 struct pivot_dimension *d = pivot_dimension_create__ (
373 table, axis_type, pivot_value_new_text (name));
376 va_start (args, name);
377 pivot_category_create_leaves_valist (d->root, args);
383 /* Creates a new dimension with the given NAME in TABLE and returns it. The
384 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
386 struct pivot_dimension *
387 pivot_dimension_create__ (struct pivot_table *table,
388 enum pivot_axis_type axis_type,
389 struct pivot_value *name)
391 assert (pivot_table_is_empty (table));
393 struct pivot_dimension *d = xmalloc (sizeof *d);
394 *d = (struct pivot_dimension) {
396 .axis_type = axis_type,
397 .level = table->axes[axis_type].n_dimensions,
398 .top_index = table->n_dimensions,
399 .root = xmalloc (sizeof *d->root),
402 struct pivot_category *root = d->root;
403 *root = (struct pivot_category) {
408 .data_index = SIZE_MAX,
409 .presentation_index = SIZE_MAX,
412 table->dimensions = xrealloc (
413 table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions);
414 table->dimensions[table->n_dimensions++] = d;
416 struct pivot_axis *axis = &table->axes[axis_type];
417 axis->dimensions = xrealloc (
418 axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
419 axis->dimensions[axis->n_dimensions++] = d;
421 if (axis_type == PIVOT_AXIS_LAYER)
423 free (table->current_layer);
424 table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
425 sizeof *table->current_layer);
428 /* axis->extent and axis->label_depth will be calculated later. */
434 pivot_dimension_destroy (struct pivot_dimension *d)
439 pivot_category_destroy (d->root);
440 free (d->data_leaves);
441 free (d->presentation_leaves);
445 /* Returns the first leaf node in an in-order traversal that is a child of
447 static const struct pivot_category * UNUSED
448 pivot_category_first_leaf (const struct pivot_category *cat)
450 if (pivot_category_is_leaf (cat))
453 for (size_t i = 0; i < cat->n_subs; i++)
455 const struct pivot_category *first
456 = pivot_category_first_leaf (cat->subs[i]);
464 /* Returns the next leaf node in an in-order traversal starting at CAT, which
466 static const struct pivot_category * UNUSED
467 pivot_category_next_leaf (const struct pivot_category *cat)
469 assert (pivot_category_is_leaf (cat));
473 const struct pivot_category *parent = cat->parent;
476 for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
478 const struct pivot_category *next
479 = pivot_category_first_leaf (parent->subs[i]);
489 pivot_category_add_child (struct pivot_category *child)
491 struct pivot_category *parent = child->parent;
493 assert (pivot_category_is_group (parent));
494 if (parent->n_subs >= parent->allocated_subs)
495 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
496 sizeof *parent->subs);
497 parent->subs[parent->n_subs++] = child;
500 /* Adds leaf categories as a child of PARENT. To create top-level categories
501 within dimension 'd', pass 'd->root' for PARENT.
503 Each of the varargs parameters should be a string, each of which should be a
504 translatable category name, but not actually translated yet, e.g. enclosed
505 in N_(). Each string may optionally be followod by a PIVOT_RC_* string that
506 specifies the default numeric format for cells in this category.
508 Returns the category index, which is just a 0-based array index, for the
511 Leaves have to be created in in-order, that is, don't create a group and add
512 some leaves, then add leaves outside the group and try to add more leaves
515 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
517 int retval = parent->dimension->n_leaves;
520 va_start (args, parent);
521 pivot_category_create_leaves_valist (parent, args);
527 /* Creates a new leaf category with the given NAME as a child of PARENT. To
528 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
529 Returns the category index, which is just a 0-based array index, for the new
532 Leaves have to be created in in-order, that is, don't create a group and add
533 some leaves, then add leaves outside the group and try to add more leaves
536 pivot_category_create_leaf (struct pivot_category *parent,
537 struct pivot_value *name)
539 return pivot_category_create_leaf_rc (parent, name, NULL);
542 /* Creates a new leaf category with the given NAME as a child of PARENT. To
543 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
544 Returns the category index, which is just a 0-based array index, for the new
547 If RC is nonnull and the name of a result category, the category is assigned
548 that result category.
550 Leaves have to be created in in-order, that is, don't create a group and add
551 some leaves, then add leaves outside the group and try to add more leaves
554 pivot_category_create_leaf_rc (struct pivot_category *parent,
555 struct pivot_value *name, const char *rc)
557 struct pivot_dimension *d = parent->dimension;
559 struct pivot_category *leaf = xmalloc (sizeof *leaf);
560 *leaf = (struct pivot_category) {
564 .group_index = parent->n_subs,
565 .data_index = d->n_leaves,
566 .presentation_index = d->n_leaves,
569 if (d->n_leaves >= d->allocated_leaves)
571 d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
572 sizeof *d->data_leaves);
573 d->presentation_leaves = xrealloc (
574 d->presentation_leaves,
575 d->allocated_leaves * sizeof *d->presentation_leaves);
578 d->data_leaves[d->n_leaves] = leaf;
579 d->presentation_leaves[d->n_leaves] = leaf;
582 pivot_category_add_child (leaf);
584 /* Make sure that the new child is the last in in-order. */
585 assert (!pivot_category_next_leaf (leaf));
587 pivot_category_set_rc (leaf, rc);
589 return leaf->data_index;
592 /* Adds a new category group named NAME as a child of PARENT. To create a
593 top-level group within dimension 'd', pass 'd->root' for PARENT.
595 NAME should be a translatable name, but not actually translated yet,
596 e.g. enclosed in N_(). To use a different kind of value for a name, use
597 pivot_category_create_group__() instead.
599 The optional varargs parameters may be used to add an initial set of
600 categories to the group. Each string should be a translatable category
601 name, but not actually translated yet, e.g. enclosed in N_(). Each string
602 may optionally be followod by a PIVOT_RC_* string that specifies the default
603 numeric format for cells in this category.
605 Returns the new group. */
606 struct pivot_category * SENTINEL (0)
607 (pivot_category_create_group) (struct pivot_category *parent,
608 const char *name, ...)
610 struct pivot_category *group = pivot_category_create_group__ (
611 parent, pivot_value_new_text (name));
614 va_start (args, name);
615 pivot_category_create_leaves_valist (group, args);
621 /* Adds a new category group named NAME as a child of PARENT. To create a
622 top-level group within dimension 'd', pass 'd->root' for PARENT. Returns
624 struct pivot_category *
625 pivot_category_create_group__ (struct pivot_category *parent,
626 struct pivot_value *name)
628 struct pivot_dimension *d = parent->dimension;
630 struct pivot_category *group = xmalloc (sizeof *group);
631 *group = (struct pivot_category) {
636 .group_index = parent->n_subs,
637 .data_index = SIZE_MAX,
638 .presentation_index = SIZE_MAX,
641 pivot_category_add_child (group);
647 pivot_category_destroy (struct pivot_category *c)
652 pivot_value_destroy (c->name);
653 for (size_t i = 0; i < c->n_subs; i++)
654 pivot_category_destroy (c->subs[i]);
661 These are usually the easiest way to control the formatting of numeric data
662 in a pivot table. See pivot_dimension_create() for an explanation of their
666 const char *name; /* "RC_*". */
667 struct fmt_spec format;
670 /* Formats for most of the result classes. */
671 static struct result_class result_classes[] =
673 { PIVOT_RC_INTEGER, { FMT_F, 40, 0 } },
674 { PIVOT_RC_PERCENT, { FMT_PCT, 40, 1 } },
675 { PIVOT_RC_CORRELATION, { FMT_F, 40, 3 } },
676 { PIVOT_RC_SIGNIFICANCE, { FMT_F, 40, 3 } },
677 { PIVOT_RC_RESIDUAL, { FMT_F, 40, 2 } },
678 { PIVOT_RC_COUNT, { 0, 0, 0 } },
679 { PIVOT_RC_OTHER, { 0, 0, 0 } },
682 /* Has PIVOT_RC_COUNT been overridden by the user? */
683 static bool overridden_count_format;
685 static struct result_class *
686 pivot_result_class_find (const char *s)
688 for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
689 if (!strcmp (s, result_classes[i].name))
690 return &result_classes[i];
694 static const struct fmt_spec *
695 pivot_table_get_format (const struct pivot_table *table, const char *s)
699 else if (!strcmp (s, PIVOT_RC_OTHER))
700 return settings_get_format ();
701 else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
702 return &table->weight_format;
705 const struct result_class *rc = pivot_result_class_find (s);
706 return rc ? &rc->format : NULL;
710 /* Sets the format specification for the result class named S (which should not
711 include the RC_ prefix) to *FORMAT. Returns true if successful, false if S
712 does not name a known result class. */
714 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
716 char *s = xasprintf ("RC_%s", s_);
717 struct result_class *rc = pivot_result_class_find (s);
720 rc->format = *format;
721 if (!strcmp (s, PIVOT_RC_COUNT))
722 overridden_count_format = true;
731 /* Creates and returns a new pivot table with the given TITLE. TITLE should be
732 a text string marked for translation but not actually translated yet,
733 e.g. N_("Descriptive Statistics"). The un-translated text string is used as
734 the pivot table's subtype.
736 Operations commonly performed on the new pivot_table:
738 - If empty rows or columns should not be displayed, set ->omit_empty to
741 - Set the format to use for "count" values with pivot_table_set_weight_var()
742 or pivot_table_set_weight_format().
744 This function is a shortcut for pivot_table_create__() for the most common
745 case. Use pivot_table_create__() directly if the title should be some kind
746 of value other than an ordinary text string, or if the subtype should be
747 different from the title.
749 See the large comment at the top of pivot-table.h for general advice on
750 creating pivot tables. */
752 pivot_table_create (const char *title)
754 return pivot_table_create__ (pivot_value_new_text (title), title);
757 /* Creates and returns a new pivot table with the given TITLE, and takes
758 ownership of TITLE. The new pivot table's subtype is SUBTYPE, which
759 should be an untranslated English string that describes the contents of
760 the table at a high level without being specific about the variables or
761 other context involved.
763 Operations commonly performed on the new pivot_table:
765 - If empty rows or columns should not be displayed, set ->omit_empty to
768 - Set the format to use for "count" values with pivot_table_set_weight_var()
769 or pivot_table_set_weight_format().
771 See the large comment at the top of pivot-table.h for general advice on
772 creating pivot tables. */
774 pivot_table_create__ (struct pivot_value *title, const char *subtype)
776 struct pivot_table *table = xzalloc (sizeof *table);
778 table->show_caption = true;
779 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
780 table->title = title;
781 table->subtype = subtype ? pivot_value_new_text (subtype) : NULL;
782 table->command_c = output_get_command_name ();
784 pivot_table_look_init (&table->look);
786 hmap_init (&table->cells);
791 /* Creates and returns a new pivot table with the given TITLE and a single cell
792 with the given CONTENT.
794 This is really just for error handling. */
796 pivot_table_create_for_text (struct pivot_value *title,
797 struct pivot_value *content)
799 struct pivot_table *table = pivot_table_create__ (title, "Error");
801 struct pivot_dimension *d = pivot_dimension_create (
802 table, PIVOT_AXIS_ROW, N_("Error"));
803 d->hide_all_labels = true;
804 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
806 pivot_table_put1 (table, 0, content);
811 /* Increases TABLE's reference count, indicating that it has an additional
812 owner. A pivot table that is shared among multiple owners must not be
815 pivot_table_ref (const struct pivot_table *table_)
817 struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
822 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
823 If TABLE no longer has any owners, it is freed. */
825 pivot_table_unref (struct pivot_table *table)
829 assert (table->ref_cnt > 0);
830 if (--table->ref_cnt)
833 free (table->current_layer);
834 pivot_table_look_uninit (&table->look);
836 for (int i = 0; i < TABLE_N_AXES; i++)
837 pivot_table_sizing_uninit (&table->sizing[i]);
839 for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
840 free (table->ccs[i]);
842 free (table->command_local);
843 free (table->command_c);
844 free (table->language);
845 free (table->locale);
847 free (table->dataset);
848 free (table->datafile);
850 for (size_t i = 0; i < table->n_footnotes; i++)
851 pivot_footnote_destroy (table->footnotes[i]);
852 free (table->footnotes);
854 pivot_value_destroy (table->title);
855 pivot_value_destroy (table->subtype);
856 pivot_value_destroy (table->corner_text);
857 pivot_value_destroy (table->caption);
859 for (size_t i = 0; i < table->n_dimensions; i++)
860 pivot_dimension_destroy (table->dimensions[i]);
861 free (table->dimensions);
863 for (size_t i = 0; i < PIVOT_N_AXES; i++)
864 free (table->axes[i].dimensions);
866 struct pivot_cell *cell, *next_cell;
867 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
870 hmap_delete (&table->cells, &cell->hmap_node);
871 pivot_value_destroy (cell->value);
874 hmap_destroy (&table->cells);
879 /* Returns true if TABLE has more than one owner. A pivot table that is shared
880 among multiple owners must not be modified. */
882 pivot_table_is_shared (const struct pivot_table *table)
884 return table->ref_cnt > 1;
887 const struct pivot_table_look *
888 pivot_table_get_look (const struct pivot_table *table)
894 pivot_table_set_look (struct pivot_table *table,
895 const struct pivot_table_look *look)
897 pivot_table_look_uninit (&table->look);
898 pivot_table_look_copy (&table->look, look);
901 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
902 WV, which should be the weight variable for the dictionary whose data or
903 statistics are being put into TABLE.
905 This has no effect if WV is NULL. */
907 pivot_table_set_weight_var (struct pivot_table *table,
908 const struct variable *wv)
911 pivot_table_set_weight_format (table, var_get_print_format (wv));
914 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
915 format for the dictionary whose data or statistics are being put into TABLE.
917 This has no effect if WFMT is NULL. */
919 pivot_table_set_weight_format (struct pivot_table *table,
920 const struct fmt_spec *wfmt)
923 table->weight_format = *wfmt;
926 /* Returns true if TABLE has no cells, false otherwise. */
928 pivot_table_is_empty (const struct pivot_table *table)
930 return hmap_is_empty (&table->cells);
934 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
936 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
940 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
942 for (size_t i = 0; i < n; i++)
949 static struct pivot_cell *
950 pivot_table_lookup_cell__ (const struct pivot_table *table,
951 const size_t *dindexes, unsigned int hash)
953 struct pivot_cell *cell;
954 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
956 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
961 static struct pivot_cell *
962 pivot_cell_allocate (size_t n_idx)
964 struct pivot_cell *cell UNUSED;
965 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
968 static struct pivot_cell *
969 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
971 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
972 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
975 cell = pivot_cell_allocate (table->n_dimensions);
976 for (size_t i = 0; i < table->n_dimensions; i++)
977 cell->idx[i] = dindexes[i];
979 hmap_insert (&table->cells, &cell->hmap_node, hash);
984 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
985 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
988 If VALUE is a numeric value without a specified format, this function checks
989 each of the categories designated by DINDEXES[] and takes the format from
990 the first category with a result class. If none has a result class, uses
991 the overall default numeric format. */
993 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
994 struct pivot_value *value)
996 assert (n == table->n_dimensions);
998 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
1000 for (size_t i = 0; i < table->n_dimensions; i++)
1002 const struct pivot_dimension *d = table->dimensions[i];
1003 if (dindexes[i] < d->n_leaves)
1005 const struct pivot_category *c = d->data_leaves[dindexes[i]];
1008 value->numeric.format = c->format;
1013 value->numeric.format = *settings_get_format ();
1018 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1019 pivot_value_destroy (cell->value);
1020 cell->value = value;
1023 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
1024 dimension. Takes ownership of VALUE. */
1026 pivot_table_put1 (struct pivot_table *table, size_t idx1,
1027 struct pivot_value *value)
1029 size_t dindexes[] = { idx1 };
1030 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1033 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
1034 dimensions. Takes ownership of VALUE. */
1036 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
1037 struct pivot_value *value)
1039 size_t dindexes[] = { idx1, idx2 };
1040 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1043 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
1044 have 3 dimensions. Takes ownership of VALUE. */
1046 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
1047 size_t idx3, struct pivot_value *value)
1049 size_t dindexes[] = { idx1, idx2, idx3 };
1050 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1053 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
1054 must have 4 dimensions. Takes ownership of VALUE. */
1056 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1057 size_t idx3, size_t idx4, struct pivot_value *value)
1059 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1060 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1063 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1064 automatically assigned marker.
1066 The footnote will only appear in output if it is referenced. Use
1067 pivot_value_add_footnote() to add a reference to the footnote. */
1068 struct pivot_footnote *
1069 pivot_table_create_footnote (struct pivot_table *table,
1070 struct pivot_value *content)
1072 return pivot_table_create_footnote__ (table, table->n_footnotes,
1076 static struct pivot_value *
1077 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1079 char text[INT_BUFSIZE_BOUND (size_t)];
1080 if (show_numeric_markers)
1081 snprintf (text, sizeof text, "%d", idx + 1);
1083 str_format_26adic (idx + 1, false, text, sizeof text);
1084 return pivot_value_new_user_text (text, -1);
1087 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1088 all lower indexes as a side effect). If MARKER is nonnull, sets the
1089 footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1090 struct pivot_footnote *
1091 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1092 struct pivot_value *marker,
1093 struct pivot_value *content)
1095 if (idx >= table->n_footnotes)
1097 while (idx >= table->allocated_footnotes)
1098 table->footnotes = x2nrealloc (table->footnotes,
1099 &table->allocated_footnotes,
1100 sizeof *table->footnotes);
1101 while (idx >= table->n_footnotes)
1103 struct pivot_footnote *f = xmalloc (sizeof *f);
1104 f->idx = table->n_footnotes;
1105 f->marker = pivot_make_default_footnote_marker (
1106 f->idx, table->look.show_numeric_markers);
1110 table->footnotes[table->n_footnotes++] = f;
1114 struct pivot_footnote *f = table->footnotes[idx];
1117 pivot_value_destroy (f->marker);
1122 pivot_value_destroy (f->content);
1123 f->content = content;
1128 /* Frees the data owned by F. */
1130 pivot_footnote_destroy (struct pivot_footnote *f)
1134 pivot_value_destroy (f->content);
1135 pivot_value_destroy (f->marker);
1140 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1141 indexes for each dimension in TABLE in DINDEXES[]. */
1143 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1144 const size_t *pindexes[PIVOT_N_AXES],
1145 size_t dindexes[/* table->n_dimensions */])
1147 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1149 const struct pivot_axis *axis = &table->axes[i];
1151 for (size_t j = 0; j < axis->n_dimensions; j++)
1153 const struct pivot_dimension *d = axis->dimensions[j];
1154 dindexes[d->top_index]
1155 = d->presentation_leaves[pindexes[i][j]]->data_index;
1161 pivot_table_enumerate_axis (const struct pivot_table *table,
1162 enum pivot_axis_type axis_type,
1163 const size_t *layer_indexes, bool omit_empty,
1166 const struct pivot_axis *axis = &table->axes[axis_type];
1167 if (!axis->n_dimensions)
1169 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1171 enumeration[1] = SIZE_MAX;
1176 else if (!axis->extent)
1178 size_t *enumeration = xmalloc (sizeof *enumeration);
1179 *enumeration = SIZE_MAX;
1185 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1186 axis->n_dimensions), 1),
1187 sizeof *enumeration);
1188 size_t *p = enumeration;
1189 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1191 size_t *axis_indexes;
1192 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1196 enum pivot_axis_type axis2_type
1197 = pivot_axis_type_transpose (axis_type);
1199 size_t *axis2_indexes;
1200 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1202 const size_t *pindexes[PIVOT_N_AXES];
1203 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1204 pindexes[axis_type] = axis_indexes;
1205 pindexes[axis2_type] = axis2_indexes;
1206 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1207 if (pivot_table_get (table, dindexes))
1213 free (axis2_indexes);
1216 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1217 p += axis->n_dimensions;
1221 *n = (p - enumeration) / axis->n_dimensions;
1227 static const struct pivot_cell *
1228 pivot_table_lookup_cell (const struct pivot_table *table,
1229 const size_t *dindexes)
1231 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1232 return pivot_table_lookup_cell__ (table, dindexes, hash);
1235 const struct pivot_value *
1236 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1238 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1239 return cell ? cell->value : NULL;
1242 struct pivot_value *
1243 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1245 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1247 cell->value = pivot_value_new_user_text ("", -1);
1252 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1254 if (pivot_category_is_group (category) && category->n_subs)
1255 for (size_t i = 0; i < category->n_subs; i++)
1256 distribute_extra_depth (category->subs[i], extra_depth);
1258 category->extra_depth += extra_depth;
1262 pivot_category_assign_label_depth (struct pivot_category *category,
1263 bool dimension_labels_in_corner)
1265 category->extra_depth = 0;
1267 if (pivot_category_is_group (category))
1270 for (size_t i = 0; i < category->n_subs; i++)
1272 pivot_category_assign_label_depth (category->subs[i], false);
1273 depth = MAX (depth, category->subs[i]->label_depth);
1276 for (size_t i = 0; i < category->n_subs; i++)
1278 struct pivot_category *sub = category->subs[i];
1280 size_t extra_depth = depth - sub->label_depth;
1282 distribute_extra_depth (sub, extra_depth);
1284 sub->label_depth = depth;
1287 category->show_label_in_corner = (category->show_label
1288 && dimension_labels_in_corner);
1289 category->label_depth
1290 = (category->show_label && !category->show_label_in_corner
1291 ? depth + 1 : depth);
1294 category->label_depth = 1;
1298 pivot_axis_assign_label_depth (struct pivot_table *table,
1299 enum pivot_axis_type axis_type,
1300 bool dimension_labels_in_corner)
1302 struct pivot_axis *axis = &table->axes[axis_type];
1303 bool any_label_shown_in_corner = false;
1304 axis->label_depth = 0;
1306 for (size_t i = 0; i < axis->n_dimensions; i++)
1308 struct pivot_dimension *d = axis->dimensions[i];
1309 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1310 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1311 axis->label_depth += d->label_depth;
1312 axis->extent *= d->n_leaves;
1314 if (d->root->show_label_in_corner)
1315 any_label_shown_in_corner = true;
1317 return any_label_shown_in_corner;
1321 pivot_table_assign_label_depth (struct pivot_table *table)
1323 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1324 if (pivot_axis_assign_label_depth (
1325 table, PIVOT_AXIS_ROW, (table->look.row_labels_in_corner
1326 && !table->corner_text))
1327 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1328 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1329 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1337 indent (int indentation)
1339 for (int i = 0; i < indentation * 2; i++)
1344 pivot_value_dump (const struct pivot_value *value)
1346 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1347 SETTINGS_VALUE_SHOW_DEFAULT);
1353 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1358 indent (indentation);
1359 printf ("%s: ", name);
1360 pivot_value_dump (value);
1366 pivot_table_dump_string (const char *string, const char *name, int indentation)
1370 indent (indentation);
1371 printf ("%s: %s\n", name, string);
1376 pivot_category_dump (const struct pivot_category *c, int indentation)
1378 indent (indentation);
1379 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1380 pivot_value_dump (c->name);
1383 if (pivot_category_is_leaf (c))
1384 printf ("data_index=%zu\n", c->data_index);
1387 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1390 for (size_t i = 0; i < c->n_subs; i++)
1391 pivot_category_dump (c->subs[i], indentation + 1);
1396 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1398 indent (indentation);
1399 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1400 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1402 pivot_category_dump (d->root, indentation + 1);
1406 table_area_style_dump (enum pivot_area area, const struct table_area_style *a,
1409 indent (indentation);
1410 printf ("%s: ", pivot_area_to_string (area));
1411 font_style_dump (&a->font_style);
1413 cell_style_dump (&a->cell_style);
1418 table_border_style_dump (enum pivot_border border,
1419 const struct table_border_style *b, int indentation)
1421 indent (indentation);
1422 printf ("%s: %s ", pivot_border_to_string (border),
1423 table_stroke_to_string (b->stroke));
1424 cell_color_dump (&b->color);
1429 compose_headings (const struct pivot_axis *axis,
1430 const size_t *column_enumeration,
1431 enum settings_value_show show_values,
1432 enum settings_value_show show_variables)
1434 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1437 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1438 for (size_t i = 0; i < axis->label_depth; i++)
1439 headings[i] = xcalloc (axis->extent, sizeof **headings);
1441 const size_t *indexes;
1443 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1445 int row = axis->label_depth - 1;
1446 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1448 const struct pivot_dimension *d = axis->dimensions[dim_index];
1449 if (d->hide_all_labels)
1451 for (const struct pivot_category *c
1452 = d->presentation_leaves[indexes[dim_index]];
1456 if (pivot_category_is_leaf (c) || (c->show_label
1457 && !c->show_label_in_corner))
1459 headings[row][column] = pivot_value_to_string (
1460 c->name, show_values, show_variables);
1461 if (!*headings[row][column])
1462 headings[row][column] = xstrdup ("<blank>");
1474 free_headings (const struct pivot_axis *axis, char ***headings)
1476 for (size_t i = 0; i < axis->label_depth; i++)
1478 for (size_t j = 0; j < axis->extent; j++)
1479 free (headings[i][j]);
1486 pivot_table_sizing_dump (const char *name,
1487 const int width_ranges[2],
1488 const struct pivot_table_sizing *s,
1491 indent (indentation);
1492 printf ("%ss: min=%d, max=%d\n", name, width_ranges[0], width_ranges[1]);
1495 indent (indentation + 1);
1496 printf ("%s widths:", name);
1497 for (size_t i = 0; i < s->n_widths; i++)
1498 printf (" %d", s->widths[i]);
1503 indent (indentation + 1);
1504 printf ("break after %ss:", name);
1505 for (size_t i = 0; i < s->n_breaks; i++)
1506 printf (" %zu", s->breaks[i]);
1511 indent (indentation + 1);
1512 printf ("keep %ss together:", name);
1513 for (size_t i = 0; i < s->n_keeps; i++)
1514 printf (" [%zu,%zu]",
1516 s->keeps[i].ofs + s->keeps[i].n - 1);
1522 pivot_table_dump (const struct pivot_table *table, int indentation)
1527 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1528 if (table->decimal == '.' || table->decimal == ',')
1529 settings_set_decimal_char (table->decimal);
1531 pivot_table_dump_value (table->title, "title", indentation);
1532 pivot_table_dump_string (table->command_c, "command", indentation);
1533 pivot_table_dump_string (table->dataset, "dataset", indentation);
1534 pivot_table_dump_string (table->datafile, "datafile", indentation);
1535 pivot_table_dump_string (table->notes, "notes", indentation);
1536 pivot_table_dump_string (table->look.name, "table-look", indentation);
1539 indent (indentation);
1541 struct tm *tm = localtime (&table->date);
1542 printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
1543 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
1547 indent (indentation);
1548 printf ("sizing:\n");
1549 pivot_table_sizing_dump ("column", table->look.width_ranges[TABLE_HORZ],
1550 &table->sizing[TABLE_HORZ], indentation + 1);
1551 pivot_table_sizing_dump ("row", table->look.width_ranges[TABLE_VERT],
1552 &table->sizing[TABLE_VERT], indentation + 1);
1554 indent (indentation);
1555 printf ("areas:\n");
1556 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1557 table_area_style_dump (area, &table->look.areas[area], indentation + 1);
1559 indent (indentation);
1560 printf ("borders:\n");
1561 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1562 table_border_style_dump (border, &table->look.borders[border],
1565 for (size_t i = 0; i < table->n_dimensions; i++)
1566 pivot_dimension_dump (table->dimensions[i], indentation);
1568 /* Presentation and data indexes. */
1569 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1571 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1572 if (layer_axis->n_dimensions)
1574 indent (indentation);
1575 printf ("current layer:");
1577 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1579 const struct pivot_dimension *d = layer_axis->dimensions[i];
1580 char *name = pivot_value_to_string (d->root->name,
1582 table->show_variables);
1583 char *value = pivot_value_to_string (
1584 d->data_leaves[table->current_layer[i]]->name,
1585 table->show_values, table->show_variables);
1586 printf (" %s=%s", name, value);
1594 size_t *layer_indexes;
1595 size_t layer_iteration = 0;
1596 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1598 indent (indentation);
1599 printf ("layer %zu:", layer_iteration++);
1601 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1602 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1604 const struct pivot_dimension *d = layer_axis->dimensions[i];
1606 fputs (i == 0 ? " " : ", ", stdout);
1607 pivot_value_dump (d->root->name);
1608 fputs (" =", stdout);
1610 struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1613 for (const struct pivot_category *c
1614 = d->presentation_leaves[layer_indexes[i]];
1618 if (pivot_category_is_leaf (c) || c->show_label)
1619 names[n_names++] = c->name;
1622 for (size_t i = n_names; i-- > 0;)
1625 pivot_value_dump (names[i]);
1631 size_t *column_enumeration = pivot_table_enumerate_axis (
1632 table, PIVOT_AXIS_COLUMN, layer_indexes, table->look.omit_empty, NULL);
1633 size_t *row_enumeration = pivot_table_enumerate_axis (
1634 table, PIVOT_AXIS_ROW, layer_indexes, table->look.omit_empty, NULL);
1636 char ***column_headings = compose_headings (
1637 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1638 table->show_values, table->show_variables);
1639 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1641 indent (indentation + 1);
1642 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1645 fputs ("; ", stdout);
1646 if (column_headings[y][x])
1647 fputs (column_headings[y][x], stdout);
1651 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1653 indent (indentation + 1);
1654 printf ("-----------------------------------------------\n");
1656 char ***row_headings = compose_headings (
1657 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1658 table->show_values, table->show_variables);
1661 const size_t *pindexes[PIVOT_N_AXES]
1662 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1663 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1664 &table->axes[PIVOT_AXIS_ROW])
1666 indent (indentation + 1);
1669 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1672 fputs ("; ", stdout);
1673 if (row_headings[y][x])
1674 fputs (row_headings[y][x], stdout);
1680 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1682 &table->axes[PIVOT_AXIS_COLUMN])
1687 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1688 const struct pivot_value *value = pivot_table_get (
1691 pivot_value_dump (value);
1698 free (column_enumeration);
1699 free (row_enumeration);
1700 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1703 pivot_table_dump_value (table->caption, "caption", indentation);
1705 for (size_t i = 0; i < table->n_footnotes; i++)
1707 const struct pivot_footnote *f = table->footnotes[i];
1708 indent (indentation);
1711 pivot_value_dump (f->marker);
1713 printf ("%zu", f->idx);
1715 pivot_value_dump (f->content);
1720 settings_set_decimal_char (old_decimal);
1724 consume_int (const char *p, size_t *n)
1727 while (c_isdigit (*p))
1728 *n = *n * 10 + (*p++ - '0');
1733 pivot_format_inner_template (struct string *out, const char *template,
1735 struct pivot_value **values, size_t n_values,
1736 enum settings_value_show show_values,
1737 enum settings_value_show show_variables)
1739 size_t args_consumed = 0;
1740 while (*template && *template != ':')
1742 if (*template == '\\' && template[1])
1744 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1747 else if (*template == escape)
1750 template = consume_int (template + 1, &index);
1751 if (index >= 1 && index <= n_values)
1753 pivot_value_format (values[index - 1], show_values,
1754 show_variables, out);
1755 args_consumed = MAX (args_consumed, index);
1759 ds_put_byte (out, *template++);
1761 return args_consumed;
1765 pivot_extract_inner_template (const char *template, const char **p)
1771 if (*template == '\\' && template[1] != '\0')
1773 else if (*template == ':')
1774 return template + 1;
1775 else if (*template == '\0')
1783 pivot_format_template (struct string *out, const char *template,
1784 const struct pivot_argument *args, size_t n_args,
1785 enum settings_value_show show_values,
1786 enum settings_value_show show_variables)
1790 if (*template == '\\' && template[1] != '\0')
1792 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1795 else if (*template == '^')
1798 template = consume_int (template + 1, &index);
1799 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1800 pivot_value_format (args[index - 1].values[0],
1801 show_values, show_variables, out);
1803 else if (*template == '[')
1805 const char *tmpl[2];
1806 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1807 template = pivot_extract_inner_template (template, &tmpl[1]);
1808 template += *template == ']';
1811 template = consume_int (template, &index);
1812 if (index < 1 || index > n_args)
1815 const struct pivot_argument *arg = &args[index - 1];
1816 size_t left = arg->n;
1819 struct pivot_value **values = arg->values + (arg->n - left);
1820 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1821 char escape = "%^"[tmpl_idx];
1822 size_t used = pivot_format_inner_template (
1823 out, tmpl[tmpl_idx], escape, values, left,
1824 show_values, show_variables);
1825 if (!used || used > left)
1831 ds_put_byte (out, *template++);
1835 static enum settings_value_show
1836 interpret_show (enum settings_value_show global_show,
1837 enum settings_value_show table_show,
1838 enum settings_value_show value_show,
1841 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1842 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1843 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1847 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1848 SHOW_VARIABLES control whether variable and value labels are included.
1850 The "body" omits subscripts and superscripts and footnotes. */
1852 pivot_value_format_body (const struct pivot_value *value,
1853 enum settings_value_show show_values,
1854 enum settings_value_show show_variables,
1857 enum settings_value_show show;
1858 bool numeric = false;
1860 switch (value->type)
1862 case PIVOT_VALUE_NUMERIC:
1863 show = interpret_show (settings_get_show_values (),
1865 value->numeric.show,
1866 value->numeric.value_label != NULL);
1867 if (show & SETTINGS_VALUE_SHOW_VALUE)
1869 char *s = data_out (&(union value) { .f = value->numeric.x },
1870 "UTF-8", &value->numeric.format);
1871 ds_put_cstr (out, s + strspn (s, " "));
1874 if (show & SETTINGS_VALUE_SHOW_LABEL)
1876 if (show & SETTINGS_VALUE_SHOW_VALUE)
1877 ds_put_byte (out, ' ');
1878 ds_put_cstr (out, value->numeric.value_label);
1880 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1883 case PIVOT_VALUE_STRING:
1884 show = interpret_show (settings_get_show_values (),
1887 value->string.value_label != NULL);
1888 if (show & SETTINGS_VALUE_SHOW_VALUE)
1890 if (value->string.hex)
1892 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1894 ds_put_format (out, "%02X", *p);
1897 ds_put_cstr (out, value->string.s);
1899 if (show & SETTINGS_VALUE_SHOW_LABEL)
1901 if (show & SETTINGS_VALUE_SHOW_VALUE)
1902 ds_put_byte (out, ' ');
1903 ds_put_cstr (out, value->string.value_label);
1907 case PIVOT_VALUE_VARIABLE:
1908 show = interpret_show (settings_get_show_variables (),
1910 value->variable.show,
1911 value->variable.var_label != NULL);
1912 if (show & SETTINGS_VALUE_SHOW_VALUE)
1913 ds_put_cstr (out, value->variable.var_name);
1914 if (show & SETTINGS_VALUE_SHOW_LABEL)
1916 if (show & SETTINGS_VALUE_SHOW_VALUE)
1917 ds_put_byte (out, ' ');
1918 ds_put_cstr (out, value->variable.var_label);
1922 case PIVOT_VALUE_TEXT:
1923 ds_put_cstr (out, value->text.local);
1926 case PIVOT_VALUE_TEMPLATE:
1927 pivot_format_template (out, value->template.local, value->template.args,
1928 value->template.n_args, show_values,
1936 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
1937 SHOW_VARIABLES control whether variable and value labels are included.
1939 Subscripts and superscripts and footnotes are included. */
1941 pivot_value_format (const struct pivot_value *value,
1942 enum settings_value_show show_values,
1943 enum settings_value_show show_variables,
1946 pivot_value_format_body (value, show_values, show_variables, out);
1948 if (value->n_subscripts)
1950 for (size_t i = 0; i < value->n_subscripts; i++)
1951 ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
1954 if (value->superscript)
1955 ds_put_format (out, "^%s", value->superscript);
1957 for (size_t i = 0; i < value->n_footnotes; i++)
1959 ds_put_byte (out, '^');
1960 pivot_value_format (value->footnotes[i]->marker,
1961 show_values, show_variables, out);
1965 /* Returns a text representation of VALUE. The caller must free the string,
1968 pivot_value_to_string (const struct pivot_value *value,
1969 enum settings_value_show show_values,
1970 enum settings_value_show show_variables)
1972 struct string s = DS_EMPTY_INITIALIZER;
1973 pivot_value_format (value, show_values, show_variables, &s);
1974 return ds_steal_cstr (&s);
1977 /* Frees the data owned by V. */
1979 pivot_value_destroy (struct pivot_value *value)
1983 font_style_uninit (value->font_style);
1984 free (value->font_style);
1985 free (value->cell_style);
1986 /* Do not free the elements of footnotes because VALUE does not own
1988 free (value->footnotes);
1990 for (size_t i = 0; i < value->n_subscripts; i++)
1991 free (value->subscripts[i]);
1992 free (value->subscripts);
1994 free (value->superscript);
1996 switch (value->type)
1998 case PIVOT_VALUE_NUMERIC:
1999 free (value->numeric.var_name);
2000 free (value->numeric.value_label);
2003 case PIVOT_VALUE_STRING:
2004 free (value->string.s);
2005 free (value->string.var_name);
2006 free (value->string.value_label);
2009 case PIVOT_VALUE_VARIABLE:
2010 free (value->variable.var_name);
2011 free (value->variable.var_label);
2014 case PIVOT_VALUE_TEXT:
2015 free (value->text.local);
2016 if (value->text.c != value->text.local)
2017 free (value->text.c);
2018 if (value->text.id != value->text.local
2019 && value->text.id != value->text.c)
2020 free (value->text.id);
2023 case PIVOT_VALUE_TEMPLATE:
2024 free (value->template.local);
2025 if (value->template.id != value->template.local)
2026 free (value->template.id);
2027 for (size_t i = 0; i < value->template.n_args; i++)
2028 pivot_argument_uninit (&value->template.args[i]);
2029 free (value->template.args);
2036 /* Sets AREA to the style to use for VALUE, with defaults coming from
2037 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
2039 pivot_value_get_style (struct pivot_value *value,
2040 const struct font_style *base_font_style,
2041 const struct cell_style *base_cell_style,
2042 struct table_area_style *area)
2044 font_style_copy (NULL, &area->font_style, (value->font_style
2046 : base_font_style));
2047 area->cell_style = *(value->cell_style
2052 /* Copies AREA into VALUE's style. */
2054 pivot_value_set_style (struct pivot_value *value,
2055 const struct table_area_style *area)
2057 if (value->font_style)
2058 font_style_uninit (value->font_style);
2060 value->font_style = xmalloc (sizeof *value->font_style);
2061 font_style_copy (NULL, value->font_style, &area->font_style);
2063 if (!value->cell_style)
2064 value->cell_style = xmalloc (sizeof *value->cell_style);
2065 *value->cell_style = area->cell_style;
2068 /* Frees the data owned by ARG (but not ARG itself). */
2070 pivot_argument_uninit (struct pivot_argument *arg)
2074 for (size_t i = 0; i < arg->n; i++)
2075 pivot_value_destroy (arg->values[i]);
2080 /* Creates and returns a new pivot_value whose contents is the null-terminated
2081 string TEXT. Takes ownership of TEXT.
2083 This function is for text strings provided by the user (with the exception
2084 that pivot_value_new_variable() should be used for variable names). For
2085 strings that are part of the PSPP user interface, such as names of
2086 procedures, statistics, annotations, error messages, etc., use
2087 pivot_value_new_text(). */
2088 struct pivot_value *
2089 pivot_value_new_user_text_nocopy (char *text)
2091 struct pivot_value *value = xmalloc (sizeof *value);
2092 *value = (struct pivot_value) {
2093 .type = PIVOT_VALUE_TEXT,
2098 .user_provided = true,
2104 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2105 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2108 This function is for text strings provided by the user (with the exception
2109 that pivot_value_new_variable() should be used for variable names). For
2110 strings that are part of the PSPP user interface, such as names of
2111 procedures, statistics, annotations, error messages, etc., use
2112 pivot_value_new_text().j
2114 The caller retains ownership of TEXT.*/
2115 struct pivot_value *
2116 pivot_value_new_user_text (const char *text, size_t length)
2118 return pivot_value_new_user_text_nocopy (
2119 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2122 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2123 a translatable string, but not actually translated yet, e.g. enclosed in
2124 N_(). This function is for text strings that are part of the PSPP user
2125 interface, such as names of procedures, statistics, annotations, error
2126 messages, etc. For strings that come from the user, use
2127 pivot_value_new_user_text(). */
2128 struct pivot_value *
2129 pivot_value_new_text (const char *text)
2131 char *c = xstrdup (text);
2132 char *local = xstrdup (gettext (c));
2134 struct pivot_value *value = xmalloc (sizeof *value);
2135 *value = (struct pivot_value) {
2136 .type = PIVOT_VALUE_TEXT,
2141 .user_provided = false,
2147 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2149 struct pivot_value * PRINTF_FORMAT (1, 2)
2150 pivot_value_new_text_format (const char *format, ...)
2153 va_start (args, format);
2154 char *c = xvasprintf (format, args);
2157 va_start (args, format);
2158 char *local = xvasprintf (gettext (format), args);
2161 struct pivot_value *value = xmalloc (sizeof *value);
2162 *value = (struct pivot_value) {
2163 .type = PIVOT_VALUE_TEXT,
2168 .user_provided = false,
2174 /* Returns a new pivot_value that represents X.
2176 The format to use for X is unspecified. Usually the easiest way to specify
2177 a format is through assigning a result class to one of the categories that
2178 the pivot_value will end up in. If that is not suitable, then the caller
2179 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2180 struct pivot_value *
2181 pivot_value_new_number (double x)
2183 struct pivot_value *value = xmalloc (sizeof *value);
2184 *value = (struct pivot_value) {
2185 .type = PIVOT_VALUE_NUMERIC,
2186 .numeric = { .x = x, },
2191 /* Returns a new pivot_value that represents X, formatted as an integer. */
2192 struct pivot_value *
2193 pivot_value_new_integer (double x)
2195 struct pivot_value *value = pivot_value_new_number (x);
2196 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2200 /* Returns a new pivot_value that represents VALUE, formatted as for
2202 struct pivot_value *
2203 pivot_value_new_var_value (const struct variable *variable,
2204 const union value *value)
2206 struct pivot_value *pv = pivot_value_new_value (
2207 value, var_get_width (variable), var_get_print_format (variable),
2208 var_get_encoding (variable));
2210 char *var_name = xstrdup (var_get_name (variable));
2211 if (var_is_alpha (variable))
2212 pv->string.var_name = var_name;
2214 pv->numeric.var_name = var_name;
2216 const char *label = var_lookup_value_label (variable, value);
2219 if (var_is_alpha (variable))
2220 pv->string.value_label = xstrdup (label);
2222 pv->numeric.value_label = xstrdup (label);
2228 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2229 formatted with FORMAT. For a string value, ENCODING must be its character
2231 struct pivot_value *
2232 pivot_value_new_value (const union value *value, int width,
2233 const struct fmt_spec *format, const char *encoding)
2235 struct pivot_value *pv = xzalloc (sizeof *pv);
2238 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2240 size_t n = strlen (s);
2241 while (n > 0 && s[n - 1] == ' ')
2244 pv->type = PIVOT_VALUE_STRING;
2246 pv->string.hex = format->type == FMT_AHEX;
2250 pv->type = PIVOT_VALUE_NUMERIC;
2251 pv->numeric.x = value->f;
2252 pv->numeric.format = *format;
2258 /* Returns a new pivot_value for VARIABLE. */
2259 struct pivot_value *
2260 pivot_value_new_variable (const struct variable *variable)
2262 struct pivot_value *value = xmalloc (sizeof *value);
2263 *value = (struct pivot_value) {
2264 .type = PIVOT_VALUE_VARIABLE,
2266 .var_name = xstrdup (var_get_name (variable)),
2267 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2273 /* Attaches a reference to FOOTNOTE to V. */
2275 pivot_value_add_footnote (struct pivot_value *v,
2276 const struct pivot_footnote *footnote)
2278 /* Some legacy tables include numerous duplicate footnotes. Suppress
2280 for (size_t i = 0; i < v->n_footnotes; i++)
2281 if (v->footnotes[i] == footnote)
2284 v->footnotes = xrealloc (v->footnotes,
2285 (v->n_footnotes + 1) * sizeof *v->footnotes);
2286 v->footnotes[v->n_footnotes++] = footnote;
2289 /* If VALUE is a numeric value, and RC is a result class such as
2290 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2292 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2295 if (value->type == PIVOT_VALUE_NUMERIC)
2297 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2299 value->numeric.format = *f;