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 = true;
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;
1219 if (omit_empty && p == enumeration)
1221 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1223 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1224 p += axis->n_dimensions;
1229 *n = (p - enumeration) / axis->n_dimensions;
1235 static const struct pivot_cell *
1236 pivot_table_lookup_cell (const struct pivot_table *table,
1237 const size_t *dindexes)
1239 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1240 return pivot_table_lookup_cell__ (table, dindexes, hash);
1243 const struct pivot_value *
1244 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1246 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1247 return cell ? cell->value : NULL;
1250 struct pivot_value *
1251 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1253 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1255 cell->value = pivot_value_new_user_text ("", -1);
1260 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1262 if (pivot_category_is_group (category) && category->n_subs)
1263 for (size_t i = 0; i < category->n_subs; i++)
1264 distribute_extra_depth (category->subs[i], extra_depth);
1266 category->extra_depth += extra_depth;
1270 pivot_category_assign_label_depth (struct pivot_category *category,
1271 bool dimension_labels_in_corner)
1273 category->extra_depth = 0;
1275 if (pivot_category_is_group (category))
1278 for (size_t i = 0; i < category->n_subs; i++)
1280 pivot_category_assign_label_depth (category->subs[i], false);
1281 depth = MAX (depth, category->subs[i]->label_depth);
1284 for (size_t i = 0; i < category->n_subs; i++)
1286 struct pivot_category *sub = category->subs[i];
1288 size_t extra_depth = depth - sub->label_depth;
1290 distribute_extra_depth (sub, extra_depth);
1292 sub->label_depth = depth;
1295 category->show_label_in_corner = (category->show_label
1296 && dimension_labels_in_corner);
1297 category->label_depth
1298 = (category->show_label && !category->show_label_in_corner
1299 ? depth + 1 : depth);
1302 category->label_depth = 1;
1306 pivot_axis_assign_label_depth (struct pivot_table *table,
1307 enum pivot_axis_type axis_type,
1308 bool dimension_labels_in_corner)
1310 struct pivot_axis *axis = &table->axes[axis_type];
1311 bool any_label_shown_in_corner = false;
1312 axis->label_depth = 0;
1314 for (size_t i = 0; i < axis->n_dimensions; i++)
1316 struct pivot_dimension *d = axis->dimensions[i];
1317 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1318 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1319 axis->label_depth += d->label_depth;
1320 axis->extent *= d->n_leaves;
1322 if (d->root->show_label_in_corner)
1323 any_label_shown_in_corner = true;
1325 return any_label_shown_in_corner;
1329 pivot_table_assign_label_depth (struct pivot_table *table)
1331 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1332 if (pivot_axis_assign_label_depth (
1333 table, PIVOT_AXIS_ROW, (table->look.row_labels_in_corner
1334 && !table->corner_text))
1335 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1336 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1337 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1345 indent (int indentation)
1347 for (int i = 0; i < indentation * 2; i++)
1352 pivot_value_dump (const struct pivot_value *value)
1354 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1355 SETTINGS_VALUE_SHOW_DEFAULT);
1361 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1366 indent (indentation);
1367 printf ("%s: ", name);
1368 pivot_value_dump (value);
1374 pivot_table_dump_string (const char *string, const char *name, int indentation)
1378 indent (indentation);
1379 printf ("%s: %s\n", name, string);
1384 pivot_category_dump (const struct pivot_category *c, int indentation)
1386 indent (indentation);
1387 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1388 pivot_value_dump (c->name);
1391 if (pivot_category_is_leaf (c))
1392 printf ("data_index=%zu\n", c->data_index);
1395 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1398 for (size_t i = 0; i < c->n_subs; i++)
1399 pivot_category_dump (c->subs[i], indentation + 1);
1404 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1406 indent (indentation);
1407 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1408 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1410 pivot_category_dump (d->root, indentation + 1);
1414 table_area_style_dump (enum pivot_area area, const struct table_area_style *a,
1417 indent (indentation);
1418 printf ("%s: ", pivot_area_to_string (area));
1419 font_style_dump (&a->font_style);
1421 cell_style_dump (&a->cell_style);
1426 table_border_style_dump (enum pivot_border border,
1427 const struct table_border_style *b, int indentation)
1429 indent (indentation);
1430 printf ("%s: %s ", pivot_border_to_string (border),
1431 table_stroke_to_string (b->stroke));
1432 cell_color_dump (&b->color);
1437 compose_headings (const struct pivot_axis *axis,
1438 const size_t *column_enumeration,
1439 enum settings_value_show show_values,
1440 enum settings_value_show show_variables)
1442 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1445 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1446 for (size_t i = 0; i < axis->label_depth; i++)
1447 headings[i] = xcalloc (axis->extent, sizeof **headings);
1449 const size_t *indexes;
1451 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1453 int row = axis->label_depth - 1;
1454 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1456 const struct pivot_dimension *d = axis->dimensions[dim_index];
1457 if (d->hide_all_labels)
1459 for (const struct pivot_category *c
1460 = d->presentation_leaves[indexes[dim_index]];
1464 if (pivot_category_is_leaf (c) || (c->show_label
1465 && !c->show_label_in_corner))
1467 headings[row][column] = pivot_value_to_string (
1468 c->name, show_values, show_variables);
1469 if (!*headings[row][column])
1470 headings[row][column] = xstrdup ("<blank>");
1482 free_headings (const struct pivot_axis *axis, char ***headings)
1484 for (size_t i = 0; i < axis->label_depth; i++)
1486 for (size_t j = 0; j < axis->extent; j++)
1487 free (headings[i][j]);
1494 pivot_table_sizing_dump (const char *name,
1495 const int width_ranges[2],
1496 const struct pivot_table_sizing *s,
1499 indent (indentation);
1500 printf ("%ss: min=%d, max=%d\n", name, width_ranges[0], width_ranges[1]);
1503 indent (indentation + 1);
1504 printf ("%s widths:", name);
1505 for (size_t i = 0; i < s->n_widths; i++)
1506 printf (" %d", s->widths[i]);
1511 indent (indentation + 1);
1512 printf ("break after %ss:", name);
1513 for (size_t i = 0; i < s->n_breaks; i++)
1514 printf (" %zu", s->breaks[i]);
1519 indent (indentation + 1);
1520 printf ("keep %ss together:", name);
1521 for (size_t i = 0; i < s->n_keeps; i++)
1522 printf (" [%zu,%zu]",
1524 s->keeps[i].ofs + s->keeps[i].n - 1);
1530 pivot_table_dump (const struct pivot_table *table, int indentation)
1535 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1536 if (table->decimal == '.' || table->decimal == ',')
1537 settings_set_decimal_char (table->decimal);
1539 pivot_table_dump_value (table->title, "title", indentation);
1540 pivot_table_dump_string (table->command_c, "command", indentation);
1541 pivot_table_dump_string (table->dataset, "dataset", indentation);
1542 pivot_table_dump_string (table->datafile, "datafile", indentation);
1543 pivot_table_dump_string (table->notes, "notes", indentation);
1544 pivot_table_dump_string (table->look.name, "table-look", indentation);
1547 indent (indentation);
1549 struct tm *tm = localtime (&table->date);
1550 printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
1551 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
1555 indent (indentation);
1556 printf ("sizing:\n");
1557 pivot_table_sizing_dump ("column", table->look.width_ranges[TABLE_HORZ],
1558 &table->sizing[TABLE_HORZ], indentation + 1);
1559 pivot_table_sizing_dump ("row", table->look.width_ranges[TABLE_VERT],
1560 &table->sizing[TABLE_VERT], indentation + 1);
1562 indent (indentation);
1563 printf ("areas:\n");
1564 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1565 table_area_style_dump (area, &table->look.areas[area], indentation + 1);
1567 indent (indentation);
1568 printf ("borders:\n");
1569 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1570 table_border_style_dump (border, &table->look.borders[border],
1573 for (size_t i = 0; i < table->n_dimensions; i++)
1574 pivot_dimension_dump (table->dimensions[i], indentation);
1576 /* Presentation and data indexes. */
1577 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1579 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1580 if (layer_axis->n_dimensions)
1582 indent (indentation);
1583 printf ("current layer:");
1585 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1587 const struct pivot_dimension *d = layer_axis->dimensions[i];
1588 char *name = pivot_value_to_string (d->root->name,
1590 table->show_variables);
1591 char *value = pivot_value_to_string (
1592 d->data_leaves[table->current_layer[i]]->name,
1593 table->show_values, table->show_variables);
1594 printf (" %s=%s", name, value);
1602 size_t *layer_indexes;
1603 size_t layer_iteration = 0;
1604 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1606 indent (indentation);
1607 printf ("layer %zu:", layer_iteration++);
1609 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1610 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1612 const struct pivot_dimension *d = layer_axis->dimensions[i];
1614 fputs (i == 0 ? " " : ", ", stdout);
1615 pivot_value_dump (d->root->name);
1616 fputs (" =", stdout);
1618 struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1621 for (const struct pivot_category *c
1622 = d->presentation_leaves[layer_indexes[i]];
1626 if (pivot_category_is_leaf (c) || c->show_label)
1627 names[n_names++] = c->name;
1630 for (size_t i = n_names; i-- > 0;)
1633 pivot_value_dump (names[i]);
1639 size_t *column_enumeration = pivot_table_enumerate_axis (
1640 table, PIVOT_AXIS_COLUMN, layer_indexes, table->look.omit_empty, NULL);
1641 size_t *row_enumeration = pivot_table_enumerate_axis (
1642 table, PIVOT_AXIS_ROW, layer_indexes, table->look.omit_empty, NULL);
1644 char ***column_headings = compose_headings (
1645 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1646 table->show_values, table->show_variables);
1647 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1649 indent (indentation + 1);
1650 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1653 fputs ("; ", stdout);
1654 if (column_headings[y][x])
1655 fputs (column_headings[y][x], stdout);
1659 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1661 indent (indentation + 1);
1662 printf ("-----------------------------------------------\n");
1664 char ***row_headings = compose_headings (
1665 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1666 table->show_values, table->show_variables);
1669 const size_t *pindexes[PIVOT_N_AXES]
1670 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1671 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1672 &table->axes[PIVOT_AXIS_ROW])
1674 indent (indentation + 1);
1677 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1680 fputs ("; ", stdout);
1681 if (row_headings[y][x])
1682 fputs (row_headings[y][x], stdout);
1688 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1690 &table->axes[PIVOT_AXIS_COLUMN])
1695 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1696 const struct pivot_value *value = pivot_table_get (
1699 pivot_value_dump (value);
1706 free (column_enumeration);
1707 free (row_enumeration);
1708 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1711 pivot_table_dump_value (table->caption, "caption", indentation);
1713 for (size_t i = 0; i < table->n_footnotes; i++)
1715 const struct pivot_footnote *f = table->footnotes[i];
1716 indent (indentation);
1719 pivot_value_dump (f->marker);
1721 printf ("%zu", f->idx);
1723 pivot_value_dump (f->content);
1728 settings_set_decimal_char (old_decimal);
1732 consume_int (const char *p, size_t *n)
1735 while (c_isdigit (*p))
1736 *n = *n * 10 + (*p++ - '0');
1741 pivot_format_inner_template (struct string *out, const char *template,
1743 struct pivot_value **values, size_t n_values,
1744 enum settings_value_show show_values,
1745 enum settings_value_show show_variables)
1747 size_t args_consumed = 0;
1748 while (*template && *template != ':')
1750 if (*template == '\\' && template[1])
1752 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1755 else if (*template == escape)
1758 template = consume_int (template + 1, &index);
1759 if (index >= 1 && index <= n_values)
1761 pivot_value_format (values[index - 1], show_values,
1762 show_variables, out);
1763 args_consumed = MAX (args_consumed, index);
1767 ds_put_byte (out, *template++);
1769 return args_consumed;
1773 pivot_extract_inner_template (const char *template, const char **p)
1779 if (*template == '\\' && template[1] != '\0')
1781 else if (*template == ':')
1782 return template + 1;
1783 else if (*template == '\0')
1791 pivot_format_template (struct string *out, const char *template,
1792 const struct pivot_argument *args, size_t n_args,
1793 enum settings_value_show show_values,
1794 enum settings_value_show show_variables)
1798 if (*template == '\\' && template[1] != '\0')
1800 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1803 else if (*template == '^')
1806 template = consume_int (template + 1, &index);
1807 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1808 pivot_value_format (args[index - 1].values[0],
1809 show_values, show_variables, out);
1811 else if (*template == '[')
1813 const char *tmpl[2];
1814 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1815 template = pivot_extract_inner_template (template, &tmpl[1]);
1816 template += *template == ']';
1819 template = consume_int (template, &index);
1820 if (index < 1 || index > n_args)
1823 const struct pivot_argument *arg = &args[index - 1];
1824 size_t left = arg->n;
1827 struct pivot_value **values = arg->values + (arg->n - left);
1828 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1829 char escape = "%^"[tmpl_idx];
1830 size_t used = pivot_format_inner_template (
1831 out, tmpl[tmpl_idx], escape, values, left,
1832 show_values, show_variables);
1833 if (!used || used > left)
1839 ds_put_byte (out, *template++);
1843 static enum settings_value_show
1844 interpret_show (enum settings_value_show global_show,
1845 enum settings_value_show table_show,
1846 enum settings_value_show value_show,
1849 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1850 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1851 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1855 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1856 SHOW_VARIABLES control whether variable and value labels are included.
1858 The "body" omits subscripts and superscripts and footnotes. */
1860 pivot_value_format_body (const struct pivot_value *value,
1861 enum settings_value_show show_values,
1862 enum settings_value_show show_variables,
1865 enum settings_value_show show;
1866 bool numeric = false;
1868 switch (value->type)
1870 case PIVOT_VALUE_NUMERIC:
1871 show = interpret_show (settings_get_show_values (),
1873 value->numeric.show,
1874 value->numeric.value_label != NULL);
1875 if (show & SETTINGS_VALUE_SHOW_VALUE)
1877 char *s = data_out (&(union value) { .f = value->numeric.x },
1878 "UTF-8", &value->numeric.format);
1879 ds_put_cstr (out, s + strspn (s, " "));
1882 if (show & SETTINGS_VALUE_SHOW_LABEL)
1884 if (show & SETTINGS_VALUE_SHOW_VALUE)
1885 ds_put_byte (out, ' ');
1886 ds_put_cstr (out, value->numeric.value_label);
1888 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1891 case PIVOT_VALUE_STRING:
1892 show = interpret_show (settings_get_show_values (),
1895 value->string.value_label != NULL);
1896 if (show & SETTINGS_VALUE_SHOW_VALUE)
1898 if (value->string.hex)
1900 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1902 ds_put_format (out, "%02X", *p);
1905 ds_put_cstr (out, value->string.s);
1907 if (show & SETTINGS_VALUE_SHOW_LABEL)
1909 if (show & SETTINGS_VALUE_SHOW_VALUE)
1910 ds_put_byte (out, ' ');
1911 ds_put_cstr (out, value->string.value_label);
1915 case PIVOT_VALUE_VARIABLE:
1916 show = interpret_show (settings_get_show_variables (),
1918 value->variable.show,
1919 value->variable.var_label != NULL);
1920 if (show & SETTINGS_VALUE_SHOW_VALUE)
1921 ds_put_cstr (out, value->variable.var_name);
1922 if (show & SETTINGS_VALUE_SHOW_LABEL)
1924 if (show & SETTINGS_VALUE_SHOW_VALUE)
1925 ds_put_byte (out, ' ');
1926 ds_put_cstr (out, value->variable.var_label);
1930 case PIVOT_VALUE_TEXT:
1931 ds_put_cstr (out, value->text.local);
1934 case PIVOT_VALUE_TEMPLATE:
1935 pivot_format_template (out, value->template.local, value->template.args,
1936 value->template.n_args, show_values,
1944 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
1945 SHOW_VARIABLES control whether variable and value labels are included.
1947 Subscripts and superscripts and footnotes are included. */
1949 pivot_value_format (const struct pivot_value *value,
1950 enum settings_value_show show_values,
1951 enum settings_value_show show_variables,
1954 pivot_value_format_body (value, show_values, show_variables, out);
1956 if (value->n_subscripts)
1958 for (size_t i = 0; i < value->n_subscripts; i++)
1959 ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
1962 if (value->superscript)
1963 ds_put_format (out, "^%s", value->superscript);
1965 for (size_t i = 0; i < value->n_footnotes; i++)
1967 ds_put_byte (out, '^');
1968 pivot_value_format (value->footnotes[i]->marker,
1969 show_values, show_variables, out);
1973 /* Returns a text representation of VALUE. The caller must free the string,
1976 pivot_value_to_string (const struct pivot_value *value,
1977 enum settings_value_show show_values,
1978 enum settings_value_show show_variables)
1980 struct string s = DS_EMPTY_INITIALIZER;
1981 pivot_value_format (value, show_values, show_variables, &s);
1982 return ds_steal_cstr (&s);
1985 /* Frees the data owned by V. */
1987 pivot_value_destroy (struct pivot_value *value)
1991 font_style_uninit (value->font_style);
1992 free (value->font_style);
1993 free (value->cell_style);
1994 /* Do not free the elements of footnotes because VALUE does not own
1996 free (value->footnotes);
1998 for (size_t i = 0; i < value->n_subscripts; i++)
1999 free (value->subscripts[i]);
2000 free (value->subscripts);
2002 free (value->superscript);
2004 switch (value->type)
2006 case PIVOT_VALUE_NUMERIC:
2007 free (value->numeric.var_name);
2008 free (value->numeric.value_label);
2011 case PIVOT_VALUE_STRING:
2012 free (value->string.s);
2013 free (value->string.var_name);
2014 free (value->string.value_label);
2017 case PIVOT_VALUE_VARIABLE:
2018 free (value->variable.var_name);
2019 free (value->variable.var_label);
2022 case PIVOT_VALUE_TEXT:
2023 free (value->text.local);
2024 if (value->text.c != value->text.local)
2025 free (value->text.c);
2026 if (value->text.id != value->text.local
2027 && value->text.id != value->text.c)
2028 free (value->text.id);
2031 case PIVOT_VALUE_TEMPLATE:
2032 free (value->template.local);
2033 if (value->template.id != value->template.local)
2034 free (value->template.id);
2035 for (size_t i = 0; i < value->template.n_args; i++)
2036 pivot_argument_uninit (&value->template.args[i]);
2037 free (value->template.args);
2044 /* Sets AREA to the style to use for VALUE, with defaults coming from
2045 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
2047 pivot_value_get_style (struct pivot_value *value,
2048 const struct font_style *base_font_style,
2049 const struct cell_style *base_cell_style,
2050 struct table_area_style *area)
2052 font_style_copy (NULL, &area->font_style, (value->font_style
2054 : base_font_style));
2055 area->cell_style = *(value->cell_style
2060 /* Copies AREA into VALUE's style. */
2062 pivot_value_set_style (struct pivot_value *value,
2063 const struct table_area_style *area)
2065 if (value->font_style)
2066 font_style_uninit (value->font_style);
2068 value->font_style = xmalloc (sizeof *value->font_style);
2069 font_style_copy (NULL, value->font_style, &area->font_style);
2071 if (!value->cell_style)
2072 value->cell_style = xmalloc (sizeof *value->cell_style);
2073 *value->cell_style = area->cell_style;
2076 /* Frees the data owned by ARG (but not ARG itself). */
2078 pivot_argument_uninit (struct pivot_argument *arg)
2082 for (size_t i = 0; i < arg->n; i++)
2083 pivot_value_destroy (arg->values[i]);
2088 /* Creates and returns a new pivot_value whose contents is the null-terminated
2089 string TEXT. Takes ownership of TEXT.
2091 This function is for text strings provided by the user (with the exception
2092 that pivot_value_new_variable() should be used for variable names). For
2093 strings that are part of the PSPP user interface, such as names of
2094 procedures, statistics, annotations, error messages, etc., use
2095 pivot_value_new_text(). */
2096 struct pivot_value *
2097 pivot_value_new_user_text_nocopy (char *text)
2099 struct pivot_value *value = xmalloc (sizeof *value);
2100 *value = (struct pivot_value) {
2101 .type = PIVOT_VALUE_TEXT,
2106 .user_provided = true,
2112 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2113 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2116 This function is for text strings provided by the user (with the exception
2117 that pivot_value_new_variable() should be used for variable names). For
2118 strings that are part of the PSPP user interface, such as names of
2119 procedures, statistics, annotations, error messages, etc., use
2120 pivot_value_new_text().j
2122 The caller retains ownership of TEXT.*/
2123 struct pivot_value *
2124 pivot_value_new_user_text (const char *text, size_t length)
2126 return pivot_value_new_user_text_nocopy (
2127 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2130 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2131 a translatable string, but not actually translated yet, e.g. enclosed in
2132 N_(). This function is for text strings that are part of the PSPP user
2133 interface, such as names of procedures, statistics, annotations, error
2134 messages, etc. For strings that come from the user, use
2135 pivot_value_new_user_text(). */
2136 struct pivot_value *
2137 pivot_value_new_text (const char *text)
2139 char *c = xstrdup (text);
2140 char *local = xstrdup (gettext (c));
2142 struct pivot_value *value = xmalloc (sizeof *value);
2143 *value = (struct pivot_value) {
2144 .type = PIVOT_VALUE_TEXT,
2149 .user_provided = false,
2155 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2157 struct pivot_value * PRINTF_FORMAT (1, 2)
2158 pivot_value_new_text_format (const char *format, ...)
2161 va_start (args, format);
2162 char *c = xvasprintf (format, args);
2165 va_start (args, format);
2166 char *local = xvasprintf (gettext (format), args);
2169 struct pivot_value *value = xmalloc (sizeof *value);
2170 *value = (struct pivot_value) {
2171 .type = PIVOT_VALUE_TEXT,
2176 .user_provided = false,
2182 /* Returns a new pivot_value that represents X.
2184 The format to use for X is unspecified. Usually the easiest way to specify
2185 a format is through assigning a result class to one of the categories that
2186 the pivot_value will end up in. If that is not suitable, then the caller
2187 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2188 struct pivot_value *
2189 pivot_value_new_number (double x)
2191 struct pivot_value *value = xmalloc (sizeof *value);
2192 *value = (struct pivot_value) {
2193 .type = PIVOT_VALUE_NUMERIC,
2194 .numeric = { .x = x, },
2199 /* Returns a new pivot_value that represents X, formatted as an integer. */
2200 struct pivot_value *
2201 pivot_value_new_integer (double x)
2203 struct pivot_value *value = pivot_value_new_number (x);
2204 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2208 /* Returns a new pivot_value that represents VALUE, formatted as for
2210 struct pivot_value *
2211 pivot_value_new_var_value (const struct variable *variable,
2212 const union value *value)
2214 struct pivot_value *pv = pivot_value_new_value (
2215 value, var_get_width (variable), var_get_print_format (variable),
2216 var_get_encoding (variable));
2218 char *var_name = xstrdup (var_get_name (variable));
2219 if (var_is_alpha (variable))
2220 pv->string.var_name = var_name;
2222 pv->numeric.var_name = var_name;
2224 const char *label = var_lookup_value_label (variable, value);
2227 if (var_is_alpha (variable))
2228 pv->string.value_label = xstrdup (label);
2230 pv->numeric.value_label = xstrdup (label);
2236 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2237 formatted with FORMAT. For a string value, ENCODING must be its character
2239 struct pivot_value *
2240 pivot_value_new_value (const union value *value, int width,
2241 const struct fmt_spec *format, const char *encoding)
2243 struct pivot_value *pv = xzalloc (sizeof *pv);
2246 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2248 size_t n = strlen (s);
2249 while (n > 0 && s[n - 1] == ' ')
2252 pv->type = PIVOT_VALUE_STRING;
2254 pv->string.hex = format->type == FMT_AHEX;
2258 pv->type = PIVOT_VALUE_NUMERIC;
2259 pv->numeric.x = value->f;
2260 pv->numeric.format = *format;
2266 /* Returns a new pivot_value for VARIABLE. */
2267 struct pivot_value *
2268 pivot_value_new_variable (const struct variable *variable)
2270 struct pivot_value *value = xmalloc (sizeof *value);
2271 *value = (struct pivot_value) {
2272 .type = PIVOT_VALUE_VARIABLE,
2274 .var_name = xstrdup (var_get_name (variable)),
2275 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2281 /* Attaches a reference to FOOTNOTE to V. */
2283 pivot_value_add_footnote (struct pivot_value *v,
2284 const struct pivot_footnote *footnote)
2286 /* Some legacy tables include numerous duplicate footnotes. Suppress
2288 for (size_t i = 0; i < v->n_footnotes; i++)
2289 if (v->footnotes[i] == footnote)
2292 v->footnotes = xrealloc (v->footnotes,
2293 (v->n_footnotes + 1) * sizeof *v->footnotes);
2294 v->footnotes[v->n_footnotes++] = footnote;
2297 /* If VALUE is a numeric value, and RC is a result class such as
2298 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2300 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2303 if (value->type == PIVOT_VALUE_NUMERIC)
2305 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2307 value->numeric.format = *f;