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 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 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);
198 /* Returns the name of AXIS_TYPE. */
200 pivot_axis_type_to_string (enum pivot_axis_type axis_type)
204 case PIVOT_AXIS_LAYER:
210 case PIVOT_AXIS_COLUMN:
218 static enum pivot_axis_type
219 pivot_axis_type_transpose (enum pivot_axis_type axis_type)
221 assert (axis_type == PIVOT_AXIS_ROW || axis_type == PIVOT_AXIS_COLUMN);
222 return (axis_type == PIVOT_AXIS_ROW ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW);
225 /* Implementation of PIVOT_AXIS_FOR_EACH. */
227 pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis)
231 if (axis->n_dimensions)
232 for (size_t i = 0; i < axis->n_dimensions; i++)
233 if (axis->dimensions[i]->n_leaves == 0)
236 return xcalloc (axis->n_dimensions, sizeof *indexes);
239 for (size_t i = 0; i < axis->n_dimensions; i++)
241 const struct pivot_dimension *d = axis->dimensions[i];
242 if (++indexes[i] < d->n_leaves)
255 pivot_category_set_rc (struct pivot_category *category, const char *s)
257 const struct fmt_spec *format = pivot_table_get_format (
258 category->dimension->table, s);
260 category->format = *format;
264 pivot_category_create_leaves_valist (struct pivot_category *parent,
268 while ((s = va_arg (args, const char *)))
270 if (!strncmp (s, "RC_", 3))
272 assert (parent->n_subs);
273 pivot_category_set_rc (parent->subs[parent->n_subs - 1], s);
276 pivot_category_create_leaf (parent, pivot_value_new_text (s));
280 /* Creates a new dimension with the given NAME in TABLE and returns it. The
281 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
284 NAME should be a translatable name, but not actually translated yet,
285 e.g. enclosed in N_(). To use a different kind of value for a name, use
286 pivot_dimension_create__() instead.
288 The optional varargs parameters may be used to add an initial set of
289 categories to the dimension. Each string should be a translatable category
290 name, but not actually translated yet, e.g. enclosed in N_(). Each string
291 may optionally be followod by a PIVOT_RC_* string that specifies the default
292 numeric format for cells in this category. */
293 struct pivot_dimension * SENTINEL (0)
294 (pivot_dimension_create) (struct pivot_table *table,
295 enum pivot_axis_type axis_type,
296 const char *name, ...)
298 struct pivot_dimension *d = pivot_dimension_create__ (
299 table, axis_type, pivot_value_new_text (name));
302 va_start (args, name);
303 pivot_category_create_leaves_valist (d->root, args);
309 /* Creates a new dimension with the given NAME in TABLE and returns it. The
310 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
312 struct pivot_dimension *
313 pivot_dimension_create__ (struct pivot_table *table,
314 enum pivot_axis_type axis_type,
315 struct pivot_value *name)
317 assert (pivot_table_is_empty (table));
319 struct pivot_dimension *d = xmalloc (sizeof *d);
320 *d = (struct pivot_dimension) {
322 .axis_type = axis_type,
323 .level = table->axes[axis_type].n_dimensions,
324 .top_index = table->n_dimensions,
325 .root = xmalloc (sizeof *d->root),
328 struct pivot_category *root = d->root;
329 *root = (struct pivot_category) {
334 .data_index = SIZE_MAX,
335 .presentation_index = SIZE_MAX,
338 table->dimensions = xrealloc (
339 table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions);
340 table->dimensions[table->n_dimensions++] = d;
342 struct pivot_axis *axis = &table->axes[axis_type];
343 axis->dimensions = xrealloc (
344 axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
345 axis->dimensions[axis->n_dimensions++] = d;
347 if (axis_type == PIVOT_AXIS_LAYER)
349 free (table->current_layer);
350 table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
351 sizeof *table->current_layer);
354 /* axis->extent and axis->label_depth will be calculated later. */
360 pivot_dimension_destroy (struct pivot_dimension *d)
365 pivot_category_destroy (d->root);
366 free (d->data_leaves);
367 free (d->presentation_leaves);
371 /* Returns the first leaf node in an in-order traversal that is a child of
373 static const struct pivot_category * UNUSED
374 pivot_category_first_leaf (const struct pivot_category *cat)
376 if (pivot_category_is_leaf (cat))
379 for (size_t i = 0; i < cat->n_subs; i++)
381 const struct pivot_category *first
382 = pivot_category_first_leaf (cat->subs[i]);
390 /* Returns the next leaf node in an in-order traversal starting at CAT, which
392 static const struct pivot_category * UNUSED
393 pivot_category_next_leaf (const struct pivot_category *cat)
395 assert (pivot_category_is_leaf (cat));
399 const struct pivot_category *parent = cat->parent;
402 for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
404 const struct pivot_category *next
405 = pivot_category_first_leaf (parent->subs[i]);
415 pivot_category_add_child (struct pivot_category *child)
417 struct pivot_category *parent = child->parent;
419 assert (pivot_category_is_group (parent));
420 if (parent->n_subs >= parent->allocated_subs)
421 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
422 sizeof *parent->subs);
423 parent->subs[parent->n_subs++] = child;
426 /* Adds leaf categories as a child of PARENT. To create top-level categories
427 within dimension 'd', pass 'd->root' for PARENT.
429 Each of the varargs parameters should be a string, each of which should be a
430 translatable category name, but not actually translated yet, e.g. enclosed
431 in N_(). Each string may optionally be followod by a PIVOT_RC_* string that
432 specifies the default numeric format for cells in this category.
434 Returns the category index, which is just a 0-based array index, for the
437 Leaves have to be created in in-order, that is, don't create a group and add
438 some leaves, then add leaves outside the group and try to add more leaves
441 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
443 int retval = parent->dimension->n_leaves;
446 va_start (args, parent);
447 pivot_category_create_leaves_valist (parent, args);
453 /* Creates a new leaf category with the given NAME as a child of PARENT. To
454 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
455 Returns the category index, which is just a 0-based array index, for the new
458 Leaves have to be created in in-order, that is, don't create a group and add
459 some leaves, then add leaves outside the group and try to add more leaves
462 pivot_category_create_leaf (struct pivot_category *parent,
463 struct pivot_value *name)
465 return pivot_category_create_leaf_rc (parent, name, NULL);
468 /* Creates a new leaf category with the given NAME as a child of PARENT. To
469 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
470 Returns the category index, which is just a 0-based array index, for the new
473 If RC is nonnull and the name of a result category, the category is assigned
474 that result category.
476 Leaves have to be created in in-order, that is, don't create a group and add
477 some leaves, then add leaves outside the group and try to add more leaves
480 pivot_category_create_leaf_rc (struct pivot_category *parent,
481 struct pivot_value *name, const char *rc)
483 struct pivot_dimension *d = parent->dimension;
485 struct pivot_category *leaf = xmalloc (sizeof *leaf);
486 *leaf = (struct pivot_category) {
490 .group_index = parent->n_subs,
491 .data_index = d->n_leaves,
492 .presentation_index = d->n_leaves,
495 if (d->n_leaves >= d->allocated_leaves)
497 d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
498 sizeof *d->data_leaves);
499 d->presentation_leaves = xrealloc (
500 d->presentation_leaves,
501 d->allocated_leaves * sizeof *d->presentation_leaves);
504 d->data_leaves[d->n_leaves] = leaf;
505 d->presentation_leaves[d->n_leaves] = leaf;
508 pivot_category_add_child (leaf);
510 /* Make sure that the new child is the last in in-order. */
511 assert (!pivot_category_next_leaf (leaf));
513 pivot_category_set_rc (leaf, rc);
515 return leaf->data_index;
518 /* Adds a new category group named NAME as a child of PARENT. To create a
519 top-level group within dimension 'd', pass 'd->root' for PARENT.
521 NAME should be a translatable name, but not actually translated yet,
522 e.g. enclosed in N_(). To use a different kind of value for a name, use
523 pivot_category_create_group__() instead.
525 The optional varargs parameters may be used to add an initial set of
526 categories to the group. Each string should be a translatable category
527 name, but not actually translated yet, e.g. enclosed in N_(). Each string
528 may optionally be followod by a PIVOT_RC_* string that specifies the default
529 numeric format for cells in this category.
531 Returns the new group. */
532 struct pivot_category * SENTINEL (0)
533 (pivot_category_create_group) (struct pivot_category *parent,
534 const char *name, ...)
536 struct pivot_category *group = pivot_category_create_group__ (
537 parent, pivot_value_new_text (name));
540 va_start (args, name);
541 pivot_category_create_leaves_valist (group, args);
547 /* Adds a new category group named NAME as a child of PARENT. To create a
548 top-level group within dimension 'd', pass 'd->root' for PARENT. Returns
550 struct pivot_category *
551 pivot_category_create_group__ (struct pivot_category *parent,
552 struct pivot_value *name)
554 struct pivot_dimension *d = parent->dimension;
556 struct pivot_category *group = xmalloc (sizeof *group);
557 *group = (struct pivot_category) {
562 .group_index = parent->n_subs,
563 .data_index = SIZE_MAX,
564 .presentation_index = SIZE_MAX,
567 pivot_category_add_child (group);
573 pivot_category_destroy (struct pivot_category *c)
578 pivot_value_destroy (c->name);
579 for (size_t i = 0; i < c->n_subs; i++)
580 pivot_category_destroy (c->subs[i]);
587 These are usually the easiest way to control the formatting of numeric data
588 in a pivot table. See pivot_dimension_create() for an explanation of their
592 const char *name; /* "RC_*". */
593 struct fmt_spec format;
596 /* Formats for most of the result classes. */
597 static struct result_class result_classes[] =
599 { PIVOT_RC_INTEGER, { FMT_F, 40, 0 } },
600 { PIVOT_RC_PERCENT, { FMT_PCT, 40, 1 } },
601 { PIVOT_RC_CORRELATION, { FMT_F, 40, 3 } },
602 { PIVOT_RC_SIGNIFICANCE, { FMT_F, 40, 3 } },
603 { PIVOT_RC_RESIDUAL, { FMT_F, 40, 2 } },
604 { PIVOT_RC_COUNT, { 0, 0, 0 } },
605 { PIVOT_RC_OTHER, { 0, 0, 0 } },
608 /* Has PIVOT_RC_COUNT been overridden by the user? */
609 static bool overridden_count_format;
611 static struct result_class *
612 pivot_result_class_find (const char *s)
614 for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
615 if (!strcmp (s, result_classes[i].name))
616 return &result_classes[i];
620 static const struct fmt_spec *
621 pivot_table_get_format (const struct pivot_table *table, const char *s)
625 else if (!strcmp (s, PIVOT_RC_OTHER))
626 return settings_get_format ();
627 else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
628 return &table->weight_format;
631 const struct result_class *rc = pivot_result_class_find (s);
632 return rc ? &rc->format : NULL;
636 /* Sets the format specification for the result class named S (which should not
637 include the RC_ prefix) to *FORMAT. Returns true if successful, false if S
638 does not name a known result class. */
640 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
642 char *s = xasprintf ("RC_%s", s_);
643 struct result_class *rc = pivot_result_class_find (s);
646 rc->format = *format;
647 if (!strcmp (s, PIVOT_RC_COUNT))
648 overridden_count_format = true;
657 /* Creates and returns a new pivot table with the given TITLE. TITLE should be
658 a text string marked for translation but not actually translated yet,
659 e.g. N_("Descriptive Statistics"). The un-translated text string is used as
660 the pivot table's subtype.
662 Operations commonly performed on the new pivot_table:
664 - If empty rows or columns should not be displayed, set ->omit_empty to
667 - Set the format to use for "count" values with pivot_table_set_weight_var()
668 or pivot_table_set_weight_format().
670 This function is a shortcut for pivot_table_create__() for the most common
671 case. Use pivot_table_create__() directly if the title should be some kind
672 of value other than an ordinary text string, or if the subtype should be
673 different from the title.
675 See the large comment at the top of pivot-table.h for general advice on
676 creating pivot tables. */
678 pivot_table_create (const char *title)
680 return pivot_table_create__ (pivot_value_new_text (title), title);
683 /* Creates and returns a new pivot table with the given TITLE, and takes
684 ownership of TITLE. The new pivot table's subtype is SUBTYPE, which
685 should be an untranslated English string that describes the contents of
686 the table at a high level without being specific about the variables or
687 other context involved.
689 Operations commonly performed on the new pivot_table:
691 - If empty rows or columns should not be displayed, set ->omit_empty to
694 - Set the format to use for "count" values with pivot_table_set_weight_var()
695 or pivot_table_set_weight_format().
697 See the large comment at the top of pivot-table.h for general advice on
698 creating pivot tables. */
700 pivot_table_create__ (struct pivot_value *title, const char *subtype)
702 struct pivot_table *table = xzalloc (sizeof *table);
704 table->show_caption = true;
705 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
706 table->title = title;
707 table->subtype = subtype ? pivot_value_new_text (subtype) : NULL;
708 table->command_c = output_get_command_name ();
710 table->sizing[TABLE_HORZ].range[0] = 50;
711 table->sizing[TABLE_HORZ].range[1] = 72;
712 table->sizing[TABLE_VERT].range[0] = 36;
713 table->sizing[TABLE_VERT].range[1] = 120;
715 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
716 area_style_copy (NULL, &table->areas[i], pivot_area_get_default_style (i));
718 /* Set default border styles. */
719 static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
720 [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE,
721 [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE,
722 [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE,
723 [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE,
724 [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
725 [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK,
726 [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK,
727 [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK,
728 [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
729 [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK,
730 [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK,
731 [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
732 [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
733 [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
734 [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
735 [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
736 [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
737 [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
738 [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
740 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
741 table->borders[i] = (struct table_border_style) {
742 .stroke = default_strokes[i],
743 .color = CELL_COLOR_BLACK,
746 table->row_labels_in_corner = true;
747 hmap_init (&table->cells);
752 /* Creates and returns a new pivot table with the given TITLE and a single cell
753 with the given CONTENT.
755 This is really just for error handling. */
757 pivot_table_create_for_text (struct pivot_value *title,
758 struct pivot_value *content)
760 struct pivot_table *table = pivot_table_create__ (title, "Error");
762 struct pivot_dimension *d = pivot_dimension_create (
763 table, PIVOT_AXIS_ROW, N_("Error"));
764 d->hide_all_labels = true;
765 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
767 pivot_table_put1 (table, 0, content);
772 /* Increases TABLE's reference count, indicating that it has an additional
773 owner. A pivot table that is shared among multiple owners must not be
776 pivot_table_ref (const struct pivot_table *table_)
778 struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
783 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
784 If TABLE no longer has any owners, it is freed. */
786 pivot_table_unref (struct pivot_table *table)
790 assert (table->ref_cnt > 0);
791 if (--table->ref_cnt)
794 free (table->current_layer);
795 free (table->table_look);
797 for (int i = 0; i < TABLE_N_AXES; i++)
798 pivot_table_sizing_uninit (&table->sizing[i]);
800 free (table->continuation);
802 for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
803 free (table->ccs[i]);
805 free (table->command_local);
806 free (table->command_c);
807 free (table->language);
808 free (table->locale);
810 free (table->dataset);
811 free (table->datafile);
813 for (size_t i = 0; i < table->n_footnotes; i++)
814 pivot_footnote_destroy (table->footnotes[i]);
815 free (table->footnotes);
817 pivot_value_destroy (table->title);
818 pivot_value_destroy (table->subtype);
819 pivot_value_destroy (table->corner_text);
820 pivot_value_destroy (table->caption);
822 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
823 area_style_uninit (&table->areas[i]);
825 for (size_t i = 0; i < table->n_dimensions; i++)
826 pivot_dimension_destroy (table->dimensions[i]);
827 free (table->dimensions);
829 for (size_t i = 0; i < PIVOT_N_AXES; i++)
830 free (table->axes[i].dimensions);
832 struct pivot_cell *cell, *next_cell;
833 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
836 hmap_delete (&table->cells, &cell->hmap_node);
837 pivot_value_destroy (cell->value);
840 hmap_destroy (&table->cells);
845 /* Returns true if TABLE has more than one owner. A pivot table that is shared
846 among multiple owners must not be modified. */
848 pivot_table_is_shared (const struct pivot_table *table)
850 return table->ref_cnt > 1;
853 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
854 WV, which should be the weight variable for the dictionary whose data or
855 statistics are being put into TABLE.
857 This has no effect if WV is NULL. */
859 pivot_table_set_weight_var (struct pivot_table *table,
860 const struct variable *wv)
863 pivot_table_set_weight_format (table, var_get_print_format (wv));
866 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
867 format for the dictionary whose data or statistics are being put into TABLE.
869 This has no effect if WFMT is NULL. */
871 pivot_table_set_weight_format (struct pivot_table *table,
872 const struct fmt_spec *wfmt)
875 table->weight_format = *wfmt;
878 /* Returns true if TABLE has no cells, false otherwise. */
880 pivot_table_is_empty (const struct pivot_table *table)
882 return hmap_is_empty (&table->cells);
886 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
888 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
892 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
894 for (size_t i = 0; i < n; i++)
901 static struct pivot_cell *
902 pivot_table_lookup_cell__ (const struct pivot_table *table,
903 const size_t *dindexes, unsigned int hash)
905 struct pivot_cell *cell;
906 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
908 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
913 static struct pivot_cell *
914 pivot_cell_allocate (size_t n_idx)
916 struct pivot_cell *cell UNUSED;
917 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
920 static struct pivot_cell *
921 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
923 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
924 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
927 cell = pivot_cell_allocate (table->n_dimensions);
928 for (size_t i = 0; i < table->n_dimensions; i++)
929 cell->idx[i] = dindexes[i];
931 hmap_insert (&table->cells, &cell->hmap_node, hash);
936 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
937 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
940 If VALUE is a numeric value without a specified format, this function checks
941 each of the categories designated by DINDEXES[] and takes the format from
942 the first category with a result class. If none has a result class, uses
943 the overall default numeric format. */
945 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
946 struct pivot_value *value)
948 assert (n == table->n_dimensions);
950 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
952 for (size_t i = 0; i < table->n_dimensions; i++)
954 const struct pivot_dimension *d = table->dimensions[i];
955 if (dindexes[i] < d->n_leaves)
957 const struct pivot_category *c = d->data_leaves[dindexes[i]];
960 value->numeric.format = c->format;
965 value->numeric.format = *settings_get_format ();
970 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
971 pivot_value_destroy (cell->value);
975 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
976 dimension. Takes ownership of VALUE. */
978 pivot_table_put1 (struct pivot_table *table, size_t idx1,
979 struct pivot_value *value)
981 size_t dindexes[] = { idx1 };
982 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
985 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
986 dimensions. Takes ownership of VALUE. */
988 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
989 struct pivot_value *value)
991 size_t dindexes[] = { idx1, idx2 };
992 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
995 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
996 have 3 dimensions. Takes ownership of VALUE. */
998 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
999 size_t idx3, struct pivot_value *value)
1001 size_t dindexes[] = { idx1, idx2, idx3 };
1002 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1005 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
1006 must have 4 dimensions. Takes ownership of VALUE. */
1008 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1009 size_t idx3, size_t idx4, struct pivot_value *value)
1011 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1012 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1015 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1016 automatically assigned marker.
1018 The footnote will only appear in output if it is referenced. Use
1019 pivot_value_add_footnote() to add a reference to the footnote. */
1020 struct pivot_footnote *
1021 pivot_table_create_footnote (struct pivot_table *table,
1022 struct pivot_value *content)
1024 return pivot_table_create_footnote__ (table, table->n_footnotes,
1028 static struct pivot_value *
1029 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1031 char text[INT_BUFSIZE_BOUND (size_t)];
1032 if (show_numeric_markers)
1033 snprintf (text, sizeof text, "%d", idx + 1);
1035 str_format_26adic (idx + 1, false, text, sizeof text);
1036 return pivot_value_new_user_text (text, -1);
1039 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1040 all lower indexes as a side effect). If MARKER is nonnull, sets the
1041 footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1042 struct pivot_footnote *
1043 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1044 struct pivot_value *marker,
1045 struct pivot_value *content)
1047 if (idx >= table->n_footnotes)
1049 while (idx >= table->allocated_footnotes)
1050 table->footnotes = x2nrealloc (table->footnotes,
1051 &table->allocated_footnotes,
1052 sizeof *table->footnotes);
1053 while (idx >= table->n_footnotes)
1055 struct pivot_footnote *f = xmalloc (sizeof *f);
1056 f->idx = table->n_footnotes;
1057 f->marker = pivot_make_default_footnote_marker (
1058 f->idx, table->show_numeric_markers);
1062 table->footnotes[table->n_footnotes++] = f;
1066 struct pivot_footnote *f = table->footnotes[idx];
1069 pivot_value_destroy (f->marker);
1074 pivot_value_destroy (f->content);
1075 f->content = content;
1080 /* Frees the data owned by F. */
1082 pivot_footnote_destroy (struct pivot_footnote *f)
1086 pivot_value_destroy (f->content);
1087 pivot_value_destroy (f->marker);
1092 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1093 indexes for each dimension in TABLE in DINDEXES[]. */
1095 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1096 const size_t *pindexes[PIVOT_N_AXES],
1097 size_t dindexes[/* table->n_dimensions */])
1099 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1101 const struct pivot_axis *axis = &table->axes[i];
1103 for (size_t j = 0; j < axis->n_dimensions; j++)
1105 const struct pivot_dimension *d = axis->dimensions[j];
1106 dindexes[d->top_index]
1107 = d->presentation_leaves[pindexes[i][j]]->data_index;
1113 pivot_table_enumerate_axis (const struct pivot_table *table,
1114 enum pivot_axis_type axis_type,
1115 const size_t *layer_indexes, bool omit_empty,
1118 const struct pivot_axis *axis = &table->axes[axis_type];
1119 if (!axis->n_dimensions)
1121 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1123 enumeration[1] = SIZE_MAX;
1128 else if (!axis->extent)
1130 size_t *enumeration = xmalloc (sizeof *enumeration);
1131 *enumeration = SIZE_MAX;
1137 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1138 axis->n_dimensions), 1),
1139 sizeof *enumeration);
1140 size_t *p = enumeration;
1141 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1143 size_t *axis_indexes;
1144 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1148 enum pivot_axis_type axis2_type
1149 = pivot_axis_type_transpose (axis_type);
1151 size_t *axis2_indexes;
1152 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1154 const size_t *pindexes[PIVOT_N_AXES];
1155 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1156 pindexes[axis_type] = axis_indexes;
1157 pindexes[axis2_type] = axis2_indexes;
1158 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1159 if (pivot_table_get (table, dindexes))
1165 free (axis2_indexes);
1168 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1169 p += axis->n_dimensions;
1173 *n = (p - enumeration) / axis->n_dimensions;
1179 static const struct pivot_cell *
1180 pivot_table_lookup_cell (const struct pivot_table *table,
1181 const size_t *dindexes)
1183 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1184 return pivot_table_lookup_cell__ (table, dindexes, hash);
1187 const struct pivot_value *
1188 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1190 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1191 return cell ? cell->value : NULL;
1194 struct pivot_value *
1195 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1197 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1199 cell->value = pivot_value_new_user_text ("", -1);
1204 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1206 if (pivot_category_is_group (category) && category->n_subs)
1207 for (size_t i = 0; i < category->n_subs; i++)
1208 distribute_extra_depth (category->subs[i], extra_depth);
1210 category->extra_depth += extra_depth;
1214 pivot_category_assign_label_depth (struct pivot_category *category,
1215 bool dimension_labels_in_corner)
1217 category->extra_depth = 0;
1219 if (pivot_category_is_group (category))
1222 for (size_t i = 0; i < category->n_subs; i++)
1224 pivot_category_assign_label_depth (category->subs[i], false);
1225 depth = MAX (depth, category->subs[i]->label_depth);
1228 for (size_t i = 0; i < category->n_subs; i++)
1230 struct pivot_category *sub = category->subs[i];
1232 size_t extra_depth = depth - sub->label_depth;
1234 distribute_extra_depth (sub, extra_depth);
1236 sub->label_depth = depth;
1239 category->show_label_in_corner = (category->show_label
1240 && dimension_labels_in_corner);
1241 category->label_depth
1242 = (category->show_label && !category->show_label_in_corner
1243 ? depth + 1 : depth);
1246 category->label_depth = 1;
1250 pivot_axis_assign_label_depth (struct pivot_table *table,
1251 enum pivot_axis_type axis_type,
1252 bool dimension_labels_in_corner)
1254 struct pivot_axis *axis = &table->axes[axis_type];
1255 bool any_label_shown_in_corner = false;
1256 axis->label_depth = 0;
1258 for (size_t i = 0; i < axis->n_dimensions; i++)
1260 struct pivot_dimension *d = axis->dimensions[i];
1261 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1262 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1263 axis->label_depth += d->label_depth;
1264 axis->extent *= d->n_leaves;
1266 if (d->root->show_label_in_corner)
1267 any_label_shown_in_corner = true;
1269 return any_label_shown_in_corner;
1273 pivot_table_assign_label_depth (struct pivot_table *table)
1275 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1276 if (pivot_axis_assign_label_depth (
1277 table, PIVOT_AXIS_ROW, (table->row_labels_in_corner
1278 && !table->corner_text))
1279 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1280 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1281 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1289 indent (int indentation)
1291 for (int i = 0; i < indentation * 2; i++)
1296 pivot_value_dump (const struct pivot_value *value)
1298 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1299 SETTINGS_VALUE_SHOW_DEFAULT);
1305 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1310 indent (indentation);
1311 printf ("%s: ", name);
1312 pivot_value_dump (value);
1318 pivot_table_dump_string (const char *string, const char *name, int indentation)
1322 indent (indentation);
1323 printf ("%s: %s\n", name, string);
1328 pivot_category_dump (const struct pivot_category *c, int indentation)
1330 indent (indentation);
1331 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1332 pivot_value_dump (c->name);
1335 if (pivot_category_is_leaf (c))
1336 printf ("data_index=%zu\n", c->data_index);
1339 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1342 for (size_t i = 0; i < c->n_subs; i++)
1343 pivot_category_dump (c->subs[i], indentation + 1);
1348 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1350 indent (indentation);
1351 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1352 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1354 pivot_category_dump (d->root, indentation + 1);
1358 area_style_dump (enum pivot_area area, const struct area_style *a,
1361 indent (indentation);
1362 printf ("%s: ", pivot_area_to_string (area));
1363 font_style_dump (&a->font_style);
1365 cell_style_dump (&a->cell_style);
1370 table_border_style_dump (enum pivot_border border,
1371 const struct table_border_style *b, int indentation)
1373 indent (indentation);
1374 printf ("%s: %s ", pivot_border_to_string (border),
1375 table_stroke_to_string (b->stroke));
1376 cell_color_dump (&b->color);
1381 compose_headings (const struct pivot_axis *axis,
1382 const size_t *column_enumeration,
1383 enum settings_value_show show_values,
1384 enum settings_value_show show_variables)
1386 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1389 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1390 for (size_t i = 0; i < axis->label_depth; i++)
1391 headings[i] = xcalloc (axis->extent, sizeof **headings);
1393 const size_t *indexes;
1395 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1397 int row = axis->label_depth - 1;
1398 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1400 const struct pivot_dimension *d = axis->dimensions[dim_index];
1401 if (d->hide_all_labels)
1403 for (const struct pivot_category *c
1404 = d->presentation_leaves[indexes[dim_index]];
1408 if (pivot_category_is_leaf (c) || (c->show_label
1409 && !c->show_label_in_corner))
1411 headings[row][column] = pivot_value_to_string (
1412 c->name, show_values, show_variables);
1413 if (!*headings[row][column])
1414 headings[row][column] = xstrdup ("<blank>");
1426 free_headings (const struct pivot_axis *axis, char ***headings)
1428 for (size_t i = 0; i < axis->label_depth; i++)
1430 for (size_t j = 0; j < axis->extent; j++)
1431 free (headings[i][j]);
1438 pivot_table_sizing_dump (const char *name, const struct pivot_table_sizing *s,
1441 indent (indentation);
1442 printf ("%ss: min=%d, max=%d\n", name, s->range[0], s->range[1]);
1445 indent (indentation + 1);
1446 printf ("%s widths:", name);
1447 for (size_t i = 0; i < s->n_widths; i++)
1448 printf (" %d", s->widths[i]);
1453 indent (indentation + 1);
1454 printf ("break after %ss:", name);
1455 for (size_t i = 0; i < s->n_breaks; i++)
1456 printf (" %zu", s->breaks[i]);
1461 indent (indentation + 1);
1462 printf ("keep %ss together:", name);
1463 for (size_t i = 0; i < s->n_keeps; i++)
1464 printf (" [%zu,%zu]",
1466 s->keeps[i].ofs + s->keeps[i].n - 1);
1472 pivot_table_dump (const struct pivot_table *table, int indentation)
1477 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1478 if (table->decimal == '.' || table->decimal == ',')
1479 settings_set_decimal_char (table->decimal);
1481 pivot_table_dump_value (table->title, "title", indentation);
1482 pivot_table_dump_string (table->command_c, "command", indentation);
1483 pivot_table_dump_string (table->dataset, "dataset", indentation);
1484 pivot_table_dump_string (table->datafile, "datafile", indentation);
1485 pivot_table_dump_string (table->notes, "notes", indentation);
1486 pivot_table_dump_string (table->table_look, "table-look", indentation);
1489 indent (indentation);
1491 struct tm *tm = localtime (&table->date);
1492 printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
1493 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
1497 indent (indentation);
1498 printf ("sizing:\n");
1499 pivot_table_sizing_dump ("column", &table->sizing[TABLE_HORZ],
1501 pivot_table_sizing_dump ("row", &table->sizing[TABLE_VERT],
1504 indent (indentation);
1505 printf ("areas:\n");
1506 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1507 area_style_dump (area, &table->areas[area], indentation + 1);
1509 indent (indentation);
1510 printf ("borders:\n");
1511 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1512 table_border_style_dump (border, &table->borders[border], indentation + 1);
1514 for (size_t i = 0; i < table->n_dimensions; i++)
1515 pivot_dimension_dump (table->dimensions[i], indentation);
1517 /* Presentation and data indexes. */
1518 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1520 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1521 if (layer_axis->n_dimensions)
1523 indent (indentation);
1524 printf ("current layer:");
1526 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1528 const struct pivot_dimension *d = layer_axis->dimensions[i];
1529 char *name = pivot_value_to_string (d->root->name,
1531 table->show_variables);
1532 char *value = pivot_value_to_string (
1533 d->data_leaves[table->current_layer[i]]->name,
1534 table->show_values, table->show_variables);
1535 printf (" %s=%s", name, value);
1543 size_t *layer_indexes;
1544 size_t layer_iteration = 0;
1545 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1547 indent (indentation);
1548 printf ("layer %zu:", layer_iteration++);
1550 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1551 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1553 const struct pivot_dimension *d = layer_axis->dimensions[i];
1555 fputs (i == 0 ? " " : ", ", stdout);
1556 pivot_value_dump (d->root->name);
1557 fputs (" =", stdout);
1559 struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1562 for (const struct pivot_category *c
1563 = d->presentation_leaves[layer_indexes[i]];
1567 if (pivot_category_is_leaf (c) || c->show_label)
1568 names[n_names++] = c->name;
1571 for (size_t i = n_names; i-- > 0;)
1574 pivot_value_dump (names[i]);
1580 size_t *column_enumeration = pivot_table_enumerate_axis (
1581 table, PIVOT_AXIS_COLUMN, layer_indexes, table->omit_empty, NULL);
1582 size_t *row_enumeration = pivot_table_enumerate_axis (
1583 table, PIVOT_AXIS_ROW, layer_indexes, table->omit_empty, NULL);
1585 char ***column_headings = compose_headings (
1586 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1587 table->show_values, table->show_variables);
1588 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1590 indent (indentation + 1);
1591 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1594 fputs ("; ", stdout);
1595 if (column_headings[y][x])
1596 fputs (column_headings[y][x], stdout);
1600 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1602 indent (indentation + 1);
1603 printf ("-----------------------------------------------\n");
1605 char ***row_headings = compose_headings (
1606 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1607 table->show_values, table->show_variables);
1610 const size_t *pindexes[PIVOT_N_AXES]
1611 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1612 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1613 &table->axes[PIVOT_AXIS_ROW])
1615 indent (indentation + 1);
1618 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1621 fputs ("; ", stdout);
1622 if (row_headings[y][x])
1623 fputs (row_headings[y][x], stdout);
1629 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1631 &table->axes[PIVOT_AXIS_COLUMN])
1636 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1637 const struct pivot_value *value = pivot_table_get (
1640 pivot_value_dump (value);
1647 free (column_enumeration);
1648 free (row_enumeration);
1649 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1652 pivot_table_dump_value (table->caption, "caption", indentation);
1654 for (size_t i = 0; i < table->n_footnotes; i++)
1656 const struct pivot_footnote *f = table->footnotes[i];
1657 indent (indentation);
1660 pivot_value_dump (f->marker);
1662 printf ("%zu", f->idx);
1664 pivot_value_dump (f->content);
1669 settings_set_decimal_char (old_decimal);
1673 consume_int (const char *p, size_t *n)
1676 while (c_isdigit (*p))
1677 *n = *n * 10 + (*p++ - '0');
1682 pivot_format_inner_template (struct string *out, const char *template,
1684 struct pivot_value **values, size_t n_values,
1685 enum settings_value_show show_values,
1686 enum settings_value_show show_variables)
1688 size_t args_consumed = 0;
1689 while (*template && *template != ':')
1691 if (*template == '\\' && template[1])
1693 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1696 else if (*template == escape)
1699 template = consume_int (template + 1, &index);
1700 if (index >= 1 && index <= n_values)
1702 pivot_value_format (values[index - 1], show_values,
1703 show_variables, out);
1704 args_consumed = MAX (args_consumed, index);
1708 ds_put_byte (out, *template++);
1710 return args_consumed;
1714 pivot_extract_inner_template (const char *template, const char **p)
1720 if (*template == '\\' && template[1] != '\0')
1722 else if (*template == ':')
1723 return template + 1;
1724 else if (*template == '\0')
1732 pivot_format_template (struct string *out, const char *template,
1733 const struct pivot_argument *args, size_t n_args,
1734 enum settings_value_show show_values,
1735 enum settings_value_show show_variables)
1739 if (*template == '\\' && template[1] != '\0')
1741 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1744 else if (*template == '^')
1747 template = consume_int (template + 1, &index);
1748 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1749 pivot_value_format (args[index - 1].values[0],
1750 show_values, show_variables, out);
1752 else if (*template == '[')
1754 const char *tmpl[2];
1755 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1756 template = pivot_extract_inner_template (template, &tmpl[1]);
1757 template += *template == ']';
1760 template = consume_int (template, &index);
1761 if (index < 1 || index > n_args)
1764 const struct pivot_argument *arg = &args[index - 1];
1765 size_t left = arg->n;
1768 struct pivot_value **values = arg->values + (arg->n - left);
1769 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1770 char escape = "%^"[tmpl_idx];
1771 size_t used = pivot_format_inner_template (
1772 out, tmpl[tmpl_idx], escape, values, left,
1773 show_values, show_variables);
1774 if (!used || used > left)
1780 ds_put_byte (out, *template++);
1784 static enum settings_value_show
1785 interpret_show (enum settings_value_show global_show,
1786 enum settings_value_show table_show,
1787 enum settings_value_show value_show,
1790 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1791 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1792 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1796 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1797 SHOW_VARIABLES control whether variable and value labels are included.
1799 The "body" omits subscripts and superscripts and footnotes. */
1801 pivot_value_format_body (const struct pivot_value *value,
1802 enum settings_value_show show_values,
1803 enum settings_value_show show_variables,
1806 enum settings_value_show show;
1807 bool numeric = false;
1809 switch (value->type)
1811 case PIVOT_VALUE_NUMERIC:
1812 show = interpret_show (settings_get_show_values (),
1814 value->numeric.show,
1815 value->numeric.value_label != NULL);
1816 if (show & SETTINGS_VALUE_SHOW_VALUE)
1818 char *s = data_out (&(union value) { .f = value->numeric.x },
1819 "UTF-8", &value->numeric.format);
1820 ds_put_cstr (out, s + strspn (s, " "));
1823 if (show & SETTINGS_VALUE_SHOW_LABEL)
1825 if (show & SETTINGS_VALUE_SHOW_VALUE)
1826 ds_put_byte (out, ' ');
1827 ds_put_cstr (out, value->numeric.value_label);
1829 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1832 case PIVOT_VALUE_STRING:
1833 show = interpret_show (settings_get_show_values (),
1836 value->string.value_label != NULL);
1837 if (show & SETTINGS_VALUE_SHOW_VALUE)
1839 if (value->string.hex)
1841 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1843 ds_put_format (out, "%02X", *p);
1846 ds_put_cstr (out, value->string.s);
1848 if (show & SETTINGS_VALUE_SHOW_LABEL)
1850 if (show & SETTINGS_VALUE_SHOW_VALUE)
1851 ds_put_byte (out, ' ');
1852 ds_put_cstr (out, value->string.value_label);
1856 case PIVOT_VALUE_VARIABLE:
1857 show = interpret_show (settings_get_show_variables (),
1859 value->variable.show,
1860 value->variable.var_label != NULL);
1861 if (show & SETTINGS_VALUE_SHOW_VALUE)
1862 ds_put_cstr (out, value->variable.var_name);
1863 if (show & SETTINGS_VALUE_SHOW_LABEL)
1865 if (show & SETTINGS_VALUE_SHOW_VALUE)
1866 ds_put_byte (out, ' ');
1867 ds_put_cstr (out, value->variable.var_label);
1871 case PIVOT_VALUE_TEXT:
1872 ds_put_cstr (out, value->text.local);
1875 case PIVOT_VALUE_TEMPLATE:
1876 pivot_format_template (out, value->template.local, value->template.args,
1877 value->template.n_args, show_values,
1885 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
1886 SHOW_VARIABLES control whether variable and value labels are included.
1888 Subscripts and superscripts and footnotes are included. */
1890 pivot_value_format (const struct pivot_value *value,
1891 enum settings_value_show show_values,
1892 enum settings_value_show show_variables,
1895 pivot_value_format_body (value, show_values, show_variables, out);
1897 if (value->n_subscripts)
1899 for (size_t i = 0; i < value->n_subscripts; i++)
1900 ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
1903 if (value->superscript)
1904 ds_put_format (out, "^%s", value->superscript);
1906 for (size_t i = 0; i < value->n_footnotes; i++)
1908 ds_put_byte (out, '^');
1909 pivot_value_format (value->footnotes[i]->marker,
1910 show_values, show_variables, out);
1914 /* Returns a text representation of VALUE. The caller must free the string,
1917 pivot_value_to_string (const struct pivot_value *value,
1918 enum settings_value_show show_values,
1919 enum settings_value_show show_variables)
1921 struct string s = DS_EMPTY_INITIALIZER;
1922 pivot_value_format (value, show_values, show_variables, &s);
1923 return ds_steal_cstr (&s);
1926 /* Frees the data owned by V. */
1928 pivot_value_destroy (struct pivot_value *value)
1932 font_style_uninit (value->font_style);
1933 free (value->font_style);
1934 free (value->cell_style);
1935 /* Do not free the elements of footnotes because VALUE does not own
1937 free (value->footnotes);
1939 for (size_t i = 0; i < value->n_subscripts; i++)
1940 free (value->subscripts[i]);
1941 free (value->subscripts);
1943 free (value->superscript);
1945 switch (value->type)
1947 case PIVOT_VALUE_NUMERIC:
1948 free (value->numeric.var_name);
1949 free (value->numeric.value_label);
1952 case PIVOT_VALUE_STRING:
1953 free (value->string.s);
1954 free (value->string.var_name);
1955 free (value->string.value_label);
1958 case PIVOT_VALUE_VARIABLE:
1959 free (value->variable.var_name);
1960 free (value->variable.var_label);
1963 case PIVOT_VALUE_TEXT:
1964 free (value->text.local);
1965 if (value->text.c != value->text.local)
1966 free (value->text.c);
1967 if (value->text.id != value->text.local
1968 && value->text.id != value->text.c)
1969 free (value->text.id);
1972 case PIVOT_VALUE_TEMPLATE:
1973 free (value->template.local);
1974 if (value->template.id != value->template.local)
1975 free (value->template.id);
1976 for (size_t i = 0; i < value->template.n_args; i++)
1977 pivot_argument_uninit (&value->template.args[i]);
1978 free (value->template.args);
1985 /* Sets AREA to the style to use for VALUE, with defaults coming from
1986 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
1988 pivot_value_get_style (struct pivot_value *value,
1989 const struct font_style *base_font_style,
1990 const struct cell_style *base_cell_style,
1991 struct area_style *area)
1993 font_style_copy (NULL, &area->font_style, (value->font_style
1995 : base_font_style));
1996 area->cell_style = *(value->cell_style
2001 /* Copies AREA into VALUE's style. */
2003 pivot_value_set_style (struct pivot_value *value,
2004 const struct area_style *area)
2006 if (value->font_style)
2007 font_style_uninit (value->font_style);
2009 value->font_style = xmalloc (sizeof *value->font_style);
2010 font_style_copy (NULL, value->font_style, &area->font_style);
2012 if (!value->cell_style)
2013 value->cell_style = xmalloc (sizeof *value->cell_style);
2014 *value->cell_style = area->cell_style;
2017 /* Frees the data owned by ARG (but not ARG itself). */
2019 pivot_argument_uninit (struct pivot_argument *arg)
2023 for (size_t i = 0; i < arg->n; i++)
2024 pivot_value_destroy (arg->values[i]);
2029 /* Creates and returns a new pivot_value whose contents is the null-terminated
2030 string TEXT. Takes ownership of TEXT.
2032 This function is for text strings provided by the user (with the exception
2033 that pivot_value_new_variable() should be used for variable names). For
2034 strings that are part of the PSPP user interface, such as names of
2035 procedures, statistics, annotations, error messages, etc., use
2036 pivot_value_new_text(). */
2037 struct pivot_value *
2038 pivot_value_new_user_text_nocopy (char *text)
2040 struct pivot_value *value = xmalloc (sizeof *value);
2041 *value = (struct pivot_value) {
2042 .type = PIVOT_VALUE_TEXT,
2047 .user_provided = true,
2053 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2054 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2057 This function is for text strings provided by the user (with the exception
2058 that pivot_value_new_variable() should be used for variable names). For
2059 strings that are part of the PSPP user interface, such as names of
2060 procedures, statistics, annotations, error messages, etc., use
2061 pivot_value_new_text().j
2063 The caller retains ownership of TEXT.*/
2064 struct pivot_value *
2065 pivot_value_new_user_text (const char *text, size_t length)
2067 return pivot_value_new_user_text_nocopy (
2068 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2071 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2072 a translatable string, but not actually translated yet, e.g. enclosed in
2073 N_(). This function is for text strings that are part of the PSPP user
2074 interface, such as names of procedures, statistics, annotations, error
2075 messages, etc. For strings that come from the user, use
2076 pivot_value_new_user_text(). */
2077 struct pivot_value *
2078 pivot_value_new_text (const char *text)
2080 char *c = xstrdup (text);
2081 char *local = xstrdup (gettext (c));
2083 struct pivot_value *value = xmalloc (sizeof *value);
2084 *value = (struct pivot_value) {
2085 .type = PIVOT_VALUE_TEXT,
2090 .user_provided = false,
2096 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2098 struct pivot_value * PRINTF_FORMAT (1, 2)
2099 pivot_value_new_text_format (const char *format, ...)
2102 va_start (args, format);
2103 char *c = xvasprintf (format, args);
2106 va_start (args, format);
2107 char *local = xvasprintf (gettext (format), args);
2110 struct pivot_value *value = xmalloc (sizeof *value);
2111 *value = (struct pivot_value) {
2112 .type = PIVOT_VALUE_TEXT,
2117 .user_provided = false,
2124 xstrdup_if_nonempty (const char *s)
2126 return s && s[0] ? xstrdup (s) : NULL;
2129 /* Returns a new pivot_value that represents X.
2131 The format to use for X is unspecified. Usually the easiest way to specify
2132 a format is through assigning a result class to one of the categories that
2133 the pivot_value will end up in. If that is not suitable, then the caller
2134 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2135 struct pivot_value *
2136 pivot_value_new_number (double x)
2138 struct pivot_value *value = xmalloc (sizeof *value);
2139 *value = (struct pivot_value) {
2140 .type = PIVOT_VALUE_NUMERIC,
2141 .numeric = { .x = x, },
2146 /* Returns a new pivot_value that represents X, formatted as an integer. */
2147 struct pivot_value *
2148 pivot_value_new_integer (double x)
2150 struct pivot_value *value = pivot_value_new_number (x);
2151 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2155 /* Returns a new pivot_value that represents VALUE, formatted as for
2157 struct pivot_value *
2158 pivot_value_new_var_value (const struct variable *variable,
2159 const union value *value)
2161 struct pivot_value *pv = pivot_value_new_value (
2162 value, var_get_width (variable), var_get_print_format (variable),
2163 var_get_encoding (variable));
2165 char *var_name = xstrdup (var_get_name (variable));
2166 if (var_is_alpha (variable))
2167 pv->string.var_name = var_name;
2169 pv->numeric.var_name = var_name;
2171 const char *label = var_lookup_value_label (variable, value);
2174 if (var_is_alpha (variable))
2175 pv->string.value_label = xstrdup (label);
2177 pv->numeric.value_label = xstrdup (label);
2183 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2184 formatted with FORMAT. For a string value, ENCODING must be its character
2186 struct pivot_value *
2187 pivot_value_new_value (const union value *value, int width,
2188 const struct fmt_spec *format, const char *encoding)
2190 struct pivot_value *pv = xzalloc (sizeof *pv);
2193 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2195 size_t n = strlen (s);
2196 while (n > 0 && s[n - 1] == ' ')
2199 pv->type = PIVOT_VALUE_STRING;
2201 pv->string.hex = format->type == FMT_AHEX;
2205 pv->type = PIVOT_VALUE_NUMERIC;
2206 pv->numeric.x = value->f;
2207 pv->numeric.format = *format;
2213 /* Returns a new pivot_value for VARIABLE. */
2214 struct pivot_value *
2215 pivot_value_new_variable (const struct variable *variable)
2217 struct pivot_value *value = xmalloc (sizeof *value);
2218 *value = (struct pivot_value) {
2219 .type = PIVOT_VALUE_VARIABLE,
2221 .var_name = xstrdup (var_get_name (variable)),
2222 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2228 /* Attaches a reference to FOOTNOTE to V. */
2230 pivot_value_add_footnote (struct pivot_value *v,
2231 const struct pivot_footnote *footnote)
2233 /* Some legacy tables include numerous duplicate footnotes. Suppress
2235 for (size_t i = 0; i < v->n_footnotes; i++)
2236 if (v->footnotes[i] == footnote)
2239 v->footnotes = xrealloc (v->footnotes,
2240 (v->n_footnotes + 1) * sizeof *v->footnotes);
2241 v->footnotes[v->n_footnotes++] = footnote;
2244 /* If VALUE is a numeric value, and RC is a result class such as
2245 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2247 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2250 if (value->type == PIVOT_VALUE_NUMERIC)
2252 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2254 value->numeric.format = *f;