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"
30 #include "gl/c-ctype.h"
31 #include "gl/intprops.h"
32 #include "gl/minmax.h"
33 #include "gl/xalloc.h"
34 #include "gl/xmemdup0.h"
38 #define _(msgid) gettext (msgid)
39 #define N_(msgid) msgid
41 static const struct fmt_spec *pivot_table_get_format (
42 const struct pivot_table *, const char *s);
44 /* Pivot table display styling. */
46 /* Returns the name of AREA. */
48 pivot_area_to_string (enum pivot_area area)
52 case PIVOT_AREA_TITLE: return "title";
53 case PIVOT_AREA_CAPTION: return "caption";
54 case PIVOT_AREA_FOOTER: return "footer";
55 case PIVOT_AREA_CORNER: return "corner";
56 case PIVOT_AREA_COLUMN_LABELS: return "column labels";
57 case PIVOT_AREA_ROW_LABELS: return "row labels";
58 case PIVOT_AREA_DATA: return "data";
59 case PIVOT_AREA_LAYERS: return "layers";
60 case PIVOT_N_AREAS: default: return "**error**";
65 pivot_area_get_default_style (enum pivot_area area, struct area_style *style)
67 #define STYLE(BOLD, H, V, L, R, T, B) { \
69 .halign = TABLE_HALIGN_##H, \
70 .valign = TABLE_VALIGN_##V, \
71 .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
72 [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
76 .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
77 .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
81 static const struct area_style default_area_styles[PIVOT_N_AREAS] = {
82 [PIVOT_AREA_TITLE] = STYLE( true, CENTER, CENTER, 8,11,1,8),
83 [PIVOT_AREA_CAPTION] = STYLE(false, LEFT, TOP, 8,11,1,1),
84 [PIVOT_AREA_FOOTER] = STYLE(false, LEFT, TOP, 11, 8,2,3),
85 [PIVOT_AREA_CORNER] = STYLE(false, LEFT, BOTTOM, 8,11,1,1),
86 [PIVOT_AREA_COLUMN_LABELS] = STYLE(false, CENTER, BOTTOM, 8,11,1,3),
87 [PIVOT_AREA_ROW_LABELS] = STYLE(false, LEFT, TOP, 8,11,1,3),
88 [PIVOT_AREA_DATA] = STYLE(false, MIXED, TOP, 8,11,1,1),
89 [PIVOT_AREA_LAYERS] = STYLE(false, LEFT, BOTTOM, 8,11,1,3),
93 *style = default_area_styles[area];
94 style->font_style.typeface = xstrdup ("SansSerif");
98 pivot_border_get_default_style (enum pivot_border border,
99 struct table_border_style *style)
101 static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
102 [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE,
103 [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE,
104 [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE,
105 [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE,
106 [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
107 [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK,
108 [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK,
109 [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK,
110 [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
111 [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK,
112 [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK,
113 [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
114 [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
115 [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
116 [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
117 [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
118 [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
119 [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
120 [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
122 *style = (struct table_border_style) {
123 .stroke = default_strokes[border],
124 .color = CELL_COLOR_BLACK,
128 /* Returns the name of BORDER. */
130 pivot_border_to_string (enum pivot_border border)
134 case PIVOT_BORDER_TITLE:
137 case PIVOT_BORDER_OUTER_LEFT:
138 return "left outer frame";
139 case PIVOT_BORDER_OUTER_TOP:
140 return "top outer frame";
141 case PIVOT_BORDER_OUTER_RIGHT:
142 return "right outer frame";
143 case PIVOT_BORDER_OUTER_BOTTOM:
144 return "bottom outer frame";
146 case PIVOT_BORDER_INNER_LEFT:
147 return "left inner frame";
148 case PIVOT_BORDER_INNER_TOP:
149 return "top inner frame";
150 case PIVOT_BORDER_INNER_RIGHT:
151 return "right inner frame";
152 case PIVOT_BORDER_INNER_BOTTOM:
153 return "bottom inner frame";
155 case PIVOT_BORDER_DATA_LEFT:
156 return "data area left";
157 case PIVOT_BORDER_DATA_TOP:
158 return "data area top";
160 case PIVOT_BORDER_DIM_ROW_HORZ:
161 return "row label horizontal dimension border";
162 case PIVOT_BORDER_DIM_ROW_VERT:
163 return "row label vertical dimension border";
164 case PIVOT_BORDER_DIM_COL_HORZ:
165 return "column label horizontal dimension border";
166 case PIVOT_BORDER_DIM_COL_VERT:
167 return "column label vertical dimension border";
169 case PIVOT_BORDER_CAT_ROW_HORZ:
170 return "row label horizontal category border";
171 case PIVOT_BORDER_CAT_ROW_VERT:
172 return "row label vertical category border";
173 case PIVOT_BORDER_CAT_COL_HORZ:
174 return "column label horizontal category border";
175 case PIVOT_BORDER_CAT_COL_VERT:
176 return "column label vertical category border";
178 case PIVOT_N_BORDERS:
185 pivot_table_sizing_uninit (struct pivot_table_sizing *sizing)
189 free (sizing->widths);
190 free (sizing->breaks);
191 free (sizing->keeps);
197 /* Returns the name of AXIS_TYPE. */
199 pivot_axis_type_to_string (enum pivot_axis_type axis_type)
203 case PIVOT_AXIS_LAYER:
209 case PIVOT_AXIS_COLUMN:
217 static enum pivot_axis_type
218 pivot_axis_type_transpose (enum pivot_axis_type axis_type)
220 assert (axis_type == PIVOT_AXIS_ROW || axis_type == PIVOT_AXIS_COLUMN);
221 return (axis_type == PIVOT_AXIS_ROW ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW);
224 /* Implementation of PIVOT_AXIS_FOR_EACH. */
226 pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis)
230 if (axis->n_dimensions)
231 for (size_t i = 0; i < axis->n_dimensions; i++)
232 if (axis->dimensions[i]->n_leaves == 0)
235 return xcalloc (axis->n_dimensions, sizeof *indexes);
238 for (size_t i = 0; i < axis->n_dimensions; i++)
240 const struct pivot_dimension *d = axis->dimensions[i];
241 if (++indexes[i] < d->n_leaves)
254 pivot_category_set_rc (struct pivot_category *category, const char *s)
256 const struct fmt_spec *format = pivot_table_get_format (
257 category->dimension->table, s);
259 category->format = *format;
263 pivot_category_create_leaves_valist (struct pivot_category *parent,
267 while ((s = va_arg (args, const char *)))
269 if (!strncmp (s, "RC_", 3))
271 assert (parent->n_subs);
272 pivot_category_set_rc (parent->subs[parent->n_subs - 1], s);
275 pivot_category_create_leaf (parent, pivot_value_new_text (s));
279 /* Creates a new dimension with the given NAME in TABLE and returns it. The
280 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
283 NAME should be a translatable name, but not actually translated yet,
284 e.g. enclosed in N_(). To use a different kind of value for a name, use
285 pivot_dimension_create__() instead.
287 The optional varargs parameters may be used to add an initial set of
288 categories to the dimension. Each string should be a translatable category
289 name, but not actually translated yet, e.g. enclosed in N_(). Each string
290 may optionally be followod by a PIVOT_RC_* string that specifies the default
291 numeric format for cells in this category. */
292 struct pivot_dimension * SENTINEL (0)
293 (pivot_dimension_create) (struct pivot_table *table,
294 enum pivot_axis_type axis_type,
295 const char *name, ...)
297 struct pivot_dimension *d = pivot_dimension_create__ (
298 table, axis_type, pivot_value_new_text (name));
301 va_start (args, name);
302 pivot_category_create_leaves_valist (d->root, args);
308 /* Creates a new dimension with the given NAME in TABLE and returns it. The
309 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
311 struct pivot_dimension *
312 pivot_dimension_create__ (struct pivot_table *table,
313 enum pivot_axis_type axis_type,
314 struct pivot_value *name)
316 assert (pivot_table_is_empty (table));
318 struct pivot_dimension *d = xmalloc (sizeof *d);
319 *d = (struct pivot_dimension) {
321 .axis_type = axis_type,
322 .level = table->axes[axis_type].n_dimensions,
323 .top_index = table->n_dimensions,
324 .root = xmalloc (sizeof *d->root),
327 struct pivot_category *root = d->root;
328 *root = (struct pivot_category) {
333 .data_index = SIZE_MAX,
334 .presentation_index = SIZE_MAX,
337 table->dimensions = xrealloc (
338 table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions);
339 table->dimensions[table->n_dimensions++] = d;
341 struct pivot_axis *axis = &table->axes[axis_type];
342 axis->dimensions = xrealloc (
343 axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
344 axis->dimensions[axis->n_dimensions++] = d;
346 if (axis_type == PIVOT_AXIS_LAYER)
348 free (table->current_layer);
349 table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
350 sizeof *table->current_layer);
353 /* axis->extent and axis->label_depth will be calculated later. */
359 pivot_dimension_destroy (struct pivot_dimension *d)
364 pivot_category_destroy (d->root);
365 free (d->data_leaves);
366 free (d->presentation_leaves);
370 /* Returns the first leaf node in an in-order traversal that is a child of
372 static const struct pivot_category * UNUSED
373 pivot_category_first_leaf (const struct pivot_category *cat)
375 if (pivot_category_is_leaf (cat))
378 for (size_t i = 0; i < cat->n_subs; i++)
380 const struct pivot_category *first
381 = pivot_category_first_leaf (cat->subs[i]);
389 /* Returns the next leaf node in an in-order traversal starting at CAT, which
391 static const struct pivot_category * UNUSED
392 pivot_category_next_leaf (const struct pivot_category *cat)
394 assert (pivot_category_is_leaf (cat));
398 const struct pivot_category *parent = cat->parent;
401 for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
403 const struct pivot_category *next
404 = pivot_category_first_leaf (parent->subs[i]);
414 pivot_category_add_child (struct pivot_category *child)
416 struct pivot_category *parent = child->parent;
418 assert (pivot_category_is_group (parent));
419 if (parent->n_subs >= parent->allocated_subs)
420 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
421 sizeof *parent->subs);
422 parent->subs[parent->n_subs++] = child;
425 /* Adds leaf categories as a child of PARENT. To create top-level categories
426 within dimension 'd', pass 'd->root' for PARENT.
428 Each of the varargs parameters should be a string, each of which should be a
429 translatable category name, but not actually translated yet, e.g. enclosed
430 in N_(). Each string may optionally be followod by a PIVOT_RC_* string that
431 specifies the default numeric format for cells in this category.
433 Returns the category index, which is just a 0-based array index, for the
436 Leaves have to be created in in-order, that is, don't create a group and add
437 some leaves, then add leaves outside the group and try to add more leaves
440 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
442 int retval = parent->dimension->n_leaves;
445 va_start (args, parent);
446 pivot_category_create_leaves_valist (parent, args);
452 /* Creates a new leaf category with the given NAME as a child of PARENT. To
453 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
454 Returns the category index, which is just a 0-based array index, for the new
457 Leaves have to be created in in-order, that is, don't create a group and add
458 some leaves, then add leaves outside the group and try to add more leaves
461 pivot_category_create_leaf (struct pivot_category *parent,
462 struct pivot_value *name)
464 return pivot_category_create_leaf_rc (parent, name, NULL);
467 /* Creates a new leaf category with the given NAME as a child of PARENT. To
468 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
469 Returns the category index, which is just a 0-based array index, for the new
472 If RC is nonnull and the name of a result category, the category is assigned
473 that result category.
475 Leaves have to be created in in-order, that is, don't create a group and add
476 some leaves, then add leaves outside the group and try to add more leaves
479 pivot_category_create_leaf_rc (struct pivot_category *parent,
480 struct pivot_value *name, const char *rc)
482 struct pivot_dimension *d = parent->dimension;
484 struct pivot_category *leaf = xmalloc (sizeof *leaf);
485 *leaf = (struct pivot_category) {
489 .group_index = parent->n_subs,
490 .data_index = d->n_leaves,
491 .presentation_index = d->n_leaves,
494 if (d->n_leaves >= d->allocated_leaves)
496 d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
497 sizeof *d->data_leaves);
498 d->presentation_leaves = xrealloc (
499 d->presentation_leaves,
500 d->allocated_leaves * sizeof *d->presentation_leaves);
503 d->data_leaves[d->n_leaves] = leaf;
504 d->presentation_leaves[d->n_leaves] = leaf;
507 pivot_category_add_child (leaf);
509 /* Make sure that the new child is the last in in-order. */
510 assert (!pivot_category_next_leaf (leaf));
512 pivot_category_set_rc (leaf, rc);
514 return leaf->data_index;
517 /* Adds a new category group named NAME as a child of PARENT. To create a
518 top-level group within dimension 'd', pass 'd->root' for PARENT.
520 NAME should be a translatable name, but not actually translated yet,
521 e.g. enclosed in N_(). To use a different kind of value for a name, use
522 pivot_category_create_group__() instead.
524 The optional varargs parameters may be used to add an initial set of
525 categories to the group. Each string should be a translatable category
526 name, but not actually translated yet, e.g. enclosed in N_(). Each string
527 may optionally be followod by a PIVOT_RC_* string that specifies the default
528 numeric format for cells in this category.
530 Returns the new group. */
531 struct pivot_category * SENTINEL (0)
532 (pivot_category_create_group) (struct pivot_category *parent,
533 const char *name, ...)
535 struct pivot_category *group = pivot_category_create_group__ (
536 parent, pivot_value_new_text (name));
539 va_start (args, name);
540 pivot_category_create_leaves_valist (group, args);
546 /* Adds a new category group named NAME as a child of PARENT. To create a
547 top-level group within dimension 'd', pass 'd->root' for PARENT. Returns
549 struct pivot_category *
550 pivot_category_create_group__ (struct pivot_category *parent,
551 struct pivot_value *name)
553 struct pivot_dimension *d = parent->dimension;
555 struct pivot_category *group = xmalloc (sizeof *group);
556 *group = (struct pivot_category) {
561 .group_index = parent->n_subs,
562 .data_index = SIZE_MAX,
563 .presentation_index = SIZE_MAX,
566 pivot_category_add_child (group);
572 pivot_category_destroy (struct pivot_category *c)
577 pivot_value_destroy (c->name);
578 for (size_t i = 0; i < c->n_subs; i++)
579 pivot_category_destroy (c->subs[i]);
586 These are usually the easiest way to control the formatting of numeric data
587 in a pivot table. See pivot_dimension_create() for an explanation of their
591 const char *name; /* "RC_*". */
592 struct fmt_spec format;
595 /* Formats for most of the result classes. */
596 static struct result_class result_classes[] =
598 { PIVOT_RC_INTEGER, { FMT_F, 40, 0 } },
599 { PIVOT_RC_PERCENT, { FMT_PCT, 40, 1 } },
600 { PIVOT_RC_CORRELATION, { FMT_F, 40, 3 } },
601 { PIVOT_RC_SIGNIFICANCE, { FMT_F, 40, 3 } },
602 { PIVOT_RC_RESIDUAL, { FMT_F, 40, 2 } },
603 { PIVOT_RC_COUNT, { 0, 0, 0 } },
604 { PIVOT_RC_OTHER, { 0, 0, 0 } },
607 /* Has PIVOT_RC_COUNT been overridden by the user? */
608 static bool overridden_count_format;
610 static struct result_class *
611 pivot_result_class_find (const char *s)
613 for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
614 if (!strcmp (s, result_classes[i].name))
615 return &result_classes[i];
619 static const struct fmt_spec *
620 pivot_table_get_format (const struct pivot_table *table, const char *s)
624 else if (!strcmp (s, PIVOT_RC_OTHER))
625 return settings_get_format ();
626 else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
627 return &table->weight_format;
630 const struct result_class *rc = pivot_result_class_find (s);
631 return rc ? &rc->format : NULL;
635 /* Sets the format specification for the result class named S (which should not
636 include the RC_ prefix) to *FORMAT. Returns true if successful, false if S
637 does not name a known result class. */
639 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
641 char *s = xasprintf ("RC_%s", s_);
642 struct result_class *rc = pivot_result_class_find (s);
645 rc->format = *format;
646 if (!strcmp (s, PIVOT_RC_COUNT))
647 overridden_count_format = true;
656 /* Creates and returns a new pivot table with the given TITLE. TITLE should be
657 a text string marked for translation but not actually translated yet,
658 e.g. N_("Descriptive Statistics").
660 Operations commonly performed on the new pivot_table:
662 - If empty rows or columns should not be displayed, set ->omit_empty to
665 - Set the format to use for "count" values with pivot_table_set_weight_var()
666 or pivot_table_set_weight_format().
668 This function is a shortcut for pivot_table_create__() for the most common
669 case. Use pivot_table_create__() directly if the title should be some kind
670 of value other than an ordinary text string.
672 See the large comment at the top of pivot-table.h for general advice on
673 creating pivot tables. */
675 pivot_table_create (const char *title)
677 return pivot_table_create__ (pivot_value_new_text (title));
680 /* Creates and returns a new pivot table with the given TITLE, and takes
683 Operations commonly performed on the new pivot_table:
685 - If empty rows or columns should not be displayed, set ->omit_empty to
688 - Set the format to use for "count" values with pivot_table_set_weight_var()
689 or pivot_table_set_weight_format().
691 See the large comment at the top of pivot-table.h for general advice on
692 creating pivot tables. */
694 pivot_table_create__ (struct pivot_value *title)
696 struct pivot_table *table = xzalloc (sizeof *table);
698 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
699 table->title = title;
701 table->sizing[TABLE_HORZ].range[0] = 50;
702 table->sizing[TABLE_HORZ].range[1] = 72;
703 table->sizing[TABLE_VERT].range[0] = 36;
704 table->sizing[TABLE_VERT].range[1] = 120;
706 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
707 pivot_area_get_default_style (i, &table->areas[i]);
709 /* Set default border styles. */
710 static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
711 [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE,
712 [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE,
713 [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE,
714 [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE,
715 [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
716 [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK,
717 [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK,
718 [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK,
719 [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
720 [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK,
721 [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK,
722 [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
723 [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
724 [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
725 [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
726 [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
727 [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
728 [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
729 [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
731 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
732 table->borders[i] = (struct table_border_style) {
733 .stroke = default_strokes[i],
734 .color = CELL_COLOR_BLACK,
737 table->row_labels_in_corner = true;
738 hmap_init (&table->cells);
743 /* Creates and returns a new pivot table with the given TITLE and a single cell
744 with the given CONTENT.
746 This is really just for error handling. */
748 pivot_table_create_for_text (struct pivot_value *title,
749 struct pivot_value *content)
751 struct pivot_table *table = pivot_table_create__ (title);
753 struct pivot_dimension *d = pivot_dimension_create (
754 table, PIVOT_AXIS_ROW, N_("Error"));
755 d->hide_all_labels = true;
756 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
758 pivot_table_put1 (table, 0, content);
763 /* Increases TABLE's reference count, indicating that it has an additional
764 owner. A pivot table that is shared among multiple owners must not be
767 pivot_table_ref (const struct pivot_table *table_)
769 struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
774 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
775 If TABLE no longer has any owners, it is freed. */
777 pivot_table_unref (struct pivot_table *table)
781 assert (table->ref_cnt > 0);
782 if (--table->ref_cnt)
785 free (table->current_layer);
786 free (table->table_look);
788 for (int i = 0; i < TABLE_N_AXES; i++)
789 pivot_table_sizing_uninit (&table->sizing[i]);
791 free (table->continuation);
793 for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
794 free (table->ccs[i]);
796 free (table->command_local);
797 free (table->command_c);
798 free (table->language);
799 free (table->locale);
801 free (table->dataset);
802 free (table->datafile);
804 for (size_t i = 0; i < table->n_footnotes; i++)
805 pivot_footnote_destroy (table->footnotes[i]);
806 free (table->footnotes);
808 pivot_value_destroy (table->title);
809 pivot_value_destroy (table->subtype);
810 pivot_value_destroy (table->corner_text);
811 pivot_value_destroy (table->caption);
813 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
814 area_style_uninit (&table->areas[i]);
816 for (size_t i = 0; i < table->n_dimensions; i++)
817 pivot_dimension_destroy (table->dimensions[i]);
818 free (table->dimensions);
820 for (size_t i = 0; i < PIVOT_N_AXES; i++)
821 free (table->axes[i].dimensions);
823 struct pivot_cell *cell, *next_cell;
824 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
827 hmap_delete (&table->cells, &cell->hmap_node);
828 pivot_value_destroy (cell->value);
831 hmap_destroy (&table->cells);
836 /* Returns true if TABLE has more than one owner. A pivot table that is shared
837 among multiple owners must not be modified. */
839 pivot_table_is_shared (const struct pivot_table *table)
841 return table->ref_cnt > 1;
844 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
845 WV, which should be the weight variable for the dictionary whose data or
846 statistics are being put into TABLE.
848 This has no effect if WV is NULL. */
850 pivot_table_set_weight_var (struct pivot_table *table,
851 const struct variable *wv)
854 pivot_table_set_weight_format (table, var_get_print_format (wv));
857 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
858 format for the dictionary whose data or statistics are being put into TABLE.
860 This has no effect if WFMT is NULL. */
862 pivot_table_set_weight_format (struct pivot_table *table,
863 const struct fmt_spec *wfmt)
866 table->weight_format = *wfmt;
869 /* Returns true if TABLE has no cells, false otherwise. */
871 pivot_table_is_empty (const struct pivot_table *table)
873 return hmap_is_empty (&table->cells);
877 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
879 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
883 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
885 for (size_t i = 0; i < n; i++)
892 static struct pivot_cell *
893 pivot_table_lookup_cell__ (const struct pivot_table *table,
894 const size_t *dindexes, unsigned int hash)
896 struct pivot_cell *cell;
897 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
899 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
904 static struct pivot_cell *
905 pivot_cell_allocate (size_t n_idx)
907 struct pivot_cell *cell UNUSED;
908 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
911 static struct pivot_cell *
912 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
914 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
915 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
918 cell = pivot_cell_allocate (table->n_dimensions);
919 for (size_t i = 0; i < table->n_dimensions; i++)
920 cell->idx[i] = dindexes[i];
922 hmap_insert (&table->cells, &cell->hmap_node, hash);
927 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
928 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
931 If VALUE is a numeric value without a specified format, this function checks
932 each of the categories designated by DINDEXES[] and takes the format from
933 the first category with a result class. If none has a result class, uses
934 the overall default numeric format. */
936 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
937 struct pivot_value *value)
939 assert (n == table->n_dimensions);
941 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
943 for (size_t i = 0; i < table->n_dimensions; i++)
945 const struct pivot_dimension *d = table->dimensions[i];
946 if (dindexes[i] < d->n_leaves)
948 const struct pivot_category *c = d->data_leaves[dindexes[i]];
951 value->numeric.format = c->format;
956 value->numeric.format = *settings_get_format ();
961 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
962 pivot_value_destroy (cell->value);
966 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
967 dimension. Takes ownership of VALUE. */
969 pivot_table_put1 (struct pivot_table *table, size_t idx1,
970 struct pivot_value *value)
972 size_t dindexes[] = { idx1 };
973 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
976 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
977 dimensions. Takes ownership of VALUE. */
979 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
980 struct pivot_value *value)
982 size_t dindexes[] = { idx1, idx2 };
983 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
986 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
987 have 3 dimensions. Takes ownership of VALUE. */
989 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
990 size_t idx3, struct pivot_value *value)
992 size_t dindexes[] = { idx1, idx2, idx3 };
993 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
996 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
997 must have 4 dimensions. Takes ownership of VALUE. */
999 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1000 size_t idx3, size_t idx4, struct pivot_value *value)
1002 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1003 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1006 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1007 automatically assigned marker.
1009 The footnote will only appear in output if it is referenced. Use
1010 pivot_value_add_footnote() to add a reference to the footnote. */
1011 struct pivot_footnote *
1012 pivot_table_create_footnote (struct pivot_table *table,
1013 struct pivot_value *content)
1015 return pivot_table_create_footnote__ (table, table->n_footnotes,
1019 static struct pivot_value *
1020 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1022 char text[INT_BUFSIZE_BOUND (size_t)];
1023 if (show_numeric_markers)
1024 snprintf (text, sizeof text, "%d", idx + 1);
1026 str_format_26adic (idx + 1, false, text, sizeof text);
1027 return pivot_value_new_user_text (text, -1);
1030 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1031 all lower indexes as a side effect). If MARKER is nonnull, sets the
1032 footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1033 struct pivot_footnote *
1034 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1035 struct pivot_value *marker,
1036 struct pivot_value *content)
1038 if (idx >= table->n_footnotes)
1040 while (idx >= table->allocated_footnotes)
1041 table->footnotes = x2nrealloc (table->footnotes,
1042 &table->allocated_footnotes,
1043 sizeof *table->footnotes);
1044 while (idx >= table->n_footnotes)
1046 struct pivot_footnote *f = xmalloc (sizeof *f);
1047 f->idx = table->n_footnotes;
1048 f->marker = pivot_make_default_footnote_marker (
1049 f->idx, table->show_numeric_markers);
1052 table->footnotes[table->n_footnotes++] = f;
1056 struct pivot_footnote *f = table->footnotes[idx];
1059 pivot_value_destroy (f->marker);
1064 pivot_value_destroy (f->content);
1065 f->content = content;
1070 /* Frees the data owned by F. */
1072 pivot_footnote_destroy (struct pivot_footnote *f)
1076 pivot_value_destroy (f->content);
1077 pivot_value_destroy (f->marker);
1082 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1083 indexes for each dimension in TABLE in DINDEXES[]. */
1085 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1086 const size_t *pindexes[PIVOT_N_AXES],
1087 size_t dindexes[/* table->n_dimensions */])
1089 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1091 const struct pivot_axis *axis = &table->axes[i];
1093 for (size_t j = 0; j < axis->n_dimensions; j++)
1095 const struct pivot_dimension *d = axis->dimensions[j];
1096 dindexes[d->top_index]
1097 = d->presentation_leaves[pindexes[i][j]]->data_index;
1103 pivot_table_enumerate_axis (const struct pivot_table *table,
1104 enum pivot_axis_type axis_type,
1105 const size_t *layer_indexes, bool omit_empty,
1108 const struct pivot_axis *axis = &table->axes[axis_type];
1109 if (!axis->n_dimensions)
1111 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1113 enumeration[1] = SIZE_MAX;
1118 else if (!axis->extent)
1120 size_t *enumeration = xmalloc (sizeof *enumeration);
1121 *enumeration = SIZE_MAX;
1127 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1128 axis->n_dimensions), 1),
1129 sizeof *enumeration);
1130 size_t *p = enumeration;
1131 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1133 size_t *axis_indexes;
1134 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1138 enum pivot_axis_type axis2_type
1139 = pivot_axis_type_transpose (axis_type);
1141 size_t *axis2_indexes;
1142 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1144 const size_t *pindexes[PIVOT_N_AXES];
1145 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1146 pindexes[axis_type] = axis_indexes;
1147 pindexes[axis2_type] = axis2_indexes;
1148 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1149 if (pivot_table_get (table, dindexes))
1155 free (axis2_indexes);
1158 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1159 p += axis->n_dimensions;
1163 *n = (p - enumeration) / axis->n_dimensions;
1169 static const struct pivot_cell *
1170 pivot_table_lookup_cell (const struct pivot_table *table,
1171 const size_t *dindexes)
1173 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1174 return pivot_table_lookup_cell__ (table, dindexes, hash);
1177 const struct pivot_value *
1178 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1180 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1181 return cell ? cell->value : NULL;
1184 struct pivot_value *
1185 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1187 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1189 cell->value = pivot_value_new_user_text ("", -1);
1194 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1196 if (pivot_category_is_group (category) && category->n_subs)
1197 for (size_t i = 0; i < category->n_subs; i++)
1198 distribute_extra_depth (category->subs[i], extra_depth);
1200 category->extra_depth += extra_depth;
1204 pivot_category_assign_label_depth (struct pivot_category *category,
1205 bool dimension_labels_in_corner)
1207 category->extra_depth = 0;
1209 if (pivot_category_is_group (category))
1212 for (size_t i = 0; i < category->n_subs; i++)
1214 pivot_category_assign_label_depth (category->subs[i], false);
1215 depth = MAX (depth, category->subs[i]->label_depth);
1218 for (size_t i = 0; i < category->n_subs; i++)
1220 struct pivot_category *sub = category->subs[i];
1222 size_t extra_depth = depth - sub->label_depth;
1224 distribute_extra_depth (sub, extra_depth);
1226 sub->label_depth = depth;
1229 category->show_label_in_corner = (category->show_label
1230 && dimension_labels_in_corner);
1231 category->label_depth
1232 = (category->show_label && !category->show_label_in_corner
1233 ? depth + 1 : depth);
1236 category->label_depth = 1;
1240 pivot_axis_assign_label_depth (struct pivot_table *table,
1241 enum pivot_axis_type axis_type,
1242 bool dimension_labels_in_corner)
1244 struct pivot_axis *axis = &table->axes[axis_type];
1245 bool any_label_shown_in_corner = false;
1246 axis->label_depth = 0;
1248 for (size_t i = 0; i < axis->n_dimensions; i++)
1250 struct pivot_dimension *d = axis->dimensions[i];
1251 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1252 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1253 axis->label_depth += d->label_depth;
1254 axis->extent *= d->n_leaves;
1256 if (d->root->show_label_in_corner)
1257 any_label_shown_in_corner = true;
1259 return any_label_shown_in_corner;
1263 pivot_table_assign_label_depth (struct pivot_table *table)
1265 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1266 if (pivot_axis_assign_label_depth (
1267 table, PIVOT_AXIS_ROW, (table->row_labels_in_corner
1268 && !table->corner_text))
1269 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1270 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1271 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1279 indent (int indentation)
1281 for (int i = 0; i < indentation * 2; i++)
1286 pivot_value_dump (const struct pivot_value *value)
1288 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1289 SETTINGS_VALUE_SHOW_DEFAULT);
1295 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1300 indent (indentation);
1301 printf ("%s: ", name);
1302 pivot_value_dump (value);
1308 pivot_table_dump_string (const char *string, const char *name, int indentation)
1312 indent (indentation);
1313 printf ("%s: %s\n", name, string);
1318 pivot_category_dump (const struct pivot_category *c, int indentation)
1320 indent (indentation);
1321 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1322 pivot_value_dump (c->name);
1325 if (pivot_category_is_leaf (c))
1326 printf ("data_index=%zu\n", c->data_index);
1329 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1332 for (size_t i = 0; i < c->n_subs; i++)
1333 pivot_category_dump (c->subs[i], indentation + 1);
1338 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1340 indent (indentation);
1341 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1342 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1344 pivot_category_dump (d->root, indentation + 1);
1348 area_style_dump (enum pivot_area area, const struct area_style *a,
1351 indent (indentation);
1352 printf ("%s: ", pivot_area_to_string (area));
1353 font_style_dump (&a->font_style);
1355 cell_style_dump (&a->cell_style);
1360 table_border_style_dump (enum pivot_border border,
1361 const struct table_border_style *b, int indentation)
1363 indent (indentation);
1364 printf ("%s: %s ", pivot_border_to_string (border),
1365 table_stroke_to_string (b->stroke));
1366 cell_color_dump (&b->color);
1371 compose_headings (const struct pivot_axis *axis,
1372 const size_t *column_enumeration,
1373 enum settings_value_show show_values,
1374 enum settings_value_show show_variables)
1376 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1379 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1380 for (size_t i = 0; i < axis->label_depth; i++)
1381 headings[i] = xcalloc (axis->extent, sizeof **headings);
1383 const size_t *indexes;
1385 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1387 int row = axis->label_depth - 1;
1388 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1390 const struct pivot_dimension *d = axis->dimensions[dim_index];
1391 if (d->hide_all_labels)
1393 for (const struct pivot_category *c
1394 = d->presentation_leaves[indexes[dim_index]];
1398 if (pivot_category_is_leaf (c) || (c->show_label
1399 && !c->show_label_in_corner))
1401 headings[row][column] = pivot_value_to_string (
1402 c->name, show_values, show_variables);
1403 if (!*headings[row][column])
1404 headings[row][column] = xstrdup ("<blank>");
1416 free_headings (const struct pivot_axis *axis, char ***headings)
1418 for (size_t i = 0; i < axis->label_depth; i++)
1420 for (size_t j = 0; j < axis->extent; j++)
1421 free (headings[i][j]);
1428 pivot_table_sizing_dump (const char *name, const struct pivot_table_sizing *s,
1431 indent (indentation);
1432 printf ("%ss: min=%d, max=%d\n", name, s->range[0], s->range[1]);
1435 indent (indentation + 1);
1436 printf ("%s widths:", name);
1437 for (size_t i = 0; i < s->n_widths; i++)
1438 printf (" %d", s->widths[i]);
1443 indent (indentation + 1);
1444 printf ("break after %ss:", name);
1445 for (size_t i = 0; i < s->n_breaks; i++)
1446 printf (" %zu", s->breaks[i]);
1451 indent (indentation + 1);
1452 printf ("keep %ss together:", name);
1453 for (size_t i = 0; i < s->n_keeps; i++)
1454 printf (" [%zu,%zu]",
1456 s->keeps[i].ofs + s->keeps[i].n - 1);
1462 pivot_table_dump (const struct pivot_table *table, int indentation)
1467 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1468 if (table->decimal == '.' || table->decimal == ',')
1469 settings_set_decimal_char (table->decimal);
1471 pivot_table_dump_value (table->title, "title", indentation);
1472 pivot_table_dump_string (table->command_c, "command", indentation);
1473 pivot_table_dump_string (table->dataset, "dataset", indentation);
1474 pivot_table_dump_string (table->datafile, "datafile", indentation);
1475 pivot_table_dump_string (table->notes, "notes", indentation);
1476 pivot_table_dump_string (table->table_look, "table-look", indentation);
1479 indent (indentation);
1481 printf ("date: %s", ctime_r (&table->date, buf));
1484 indent (indentation);
1485 printf ("sizing:\n");
1486 pivot_table_sizing_dump ("column", &table->sizing[TABLE_HORZ],
1488 pivot_table_sizing_dump ("row", &table->sizing[TABLE_VERT],
1491 indent (indentation);
1492 printf ("areas:\n");
1493 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1494 area_style_dump (area, &table->areas[area], indentation + 1);
1496 indent (indentation);
1497 printf ("borders:\n");
1498 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1499 table_border_style_dump (border, &table->borders[border], indentation + 1);
1501 for (size_t i = 0; i < table->n_dimensions; i++)
1502 pivot_dimension_dump (table->dimensions[i], indentation);
1504 /* Presentation and data indexes. */
1505 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1507 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1508 if (layer_axis->n_dimensions)
1510 indent (indentation);
1511 printf ("current layer:");
1513 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1515 const struct pivot_dimension *d = layer_axis->dimensions[i];
1516 char *name = pivot_value_to_string (d->root->name,
1518 table->show_variables);
1519 char *value = pivot_value_to_string (
1520 d->data_leaves[table->current_layer[i]]->name,
1521 table->show_values, table->show_variables);
1522 printf (" %s=%s", name, value);
1530 size_t *layer_indexes;
1531 size_t layer_iteration = 0;
1532 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1534 indent (indentation);
1535 printf ("layer %zu:", layer_iteration++);
1537 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1538 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1540 const struct pivot_dimension *d = layer_axis->dimensions[i];
1542 fputs (i == 0 ? " " : ", ", stdout);
1543 pivot_value_dump (d->root->name);
1544 fputs (" =", stdout);
1546 struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1549 for (const struct pivot_category *c
1550 = d->presentation_leaves[layer_indexes[i]];
1554 if (pivot_category_is_leaf (c) || c->show_label)
1555 names[n_names++] = c->name;
1558 for (size_t i = n_names; i-- > 0; )
1561 pivot_value_dump (names[i]);
1567 size_t *column_enumeration = pivot_table_enumerate_axis (
1568 table, PIVOT_AXIS_COLUMN, layer_indexes, table->omit_empty, NULL);
1569 size_t *row_enumeration = pivot_table_enumerate_axis (
1570 table, PIVOT_AXIS_ROW, layer_indexes, table->omit_empty, NULL);
1572 char ***column_headings = compose_headings (
1573 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1574 table->show_values, table->show_variables);
1575 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1577 indent (indentation + 1);
1578 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1581 fputs ("; ", stdout);
1582 if (column_headings[y][x])
1583 fputs (column_headings[y][x], stdout);
1587 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1589 indent (indentation + 1);
1590 printf ("-----------------------------------------------\n");
1592 char ***row_headings = compose_headings (
1593 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1594 table->show_values, table->show_variables);
1597 const size_t *pindexes[PIVOT_N_AXES]
1598 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1599 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1600 &table->axes[PIVOT_AXIS_ROW])
1602 indent (indentation + 1);
1605 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1608 fputs ("; ", stdout);
1609 if (row_headings[y][x])
1610 fputs (row_headings[y][x], stdout);
1616 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1618 &table->axes[PIVOT_AXIS_COLUMN])
1623 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1624 const struct pivot_value *value = pivot_table_get (
1627 pivot_value_dump (value);
1634 free (column_enumeration);
1635 free (row_enumeration);
1636 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1639 pivot_table_dump_value (table->caption, "caption", indentation);
1641 for (size_t i = 0; i < table->n_footnotes; i++)
1643 const struct pivot_footnote *f = table->footnotes[i];
1644 indent (indentation);
1647 pivot_value_dump (f->marker);
1649 printf ("%zu", f->idx);
1651 pivot_value_dump (f->content);
1656 settings_set_decimal_char (old_decimal);
1660 consume_int (const char *p, size_t *n)
1663 while (c_isdigit (*p))
1664 *n = *n * 10 + (*p++ - '0');
1669 pivot_format_inner_template (struct string *out, const char *template,
1671 struct pivot_value **values, size_t n_values,
1672 enum settings_value_show show_values,
1673 enum settings_value_show show_variables)
1675 size_t args_consumed = 0;
1676 while (*template && *template != ':')
1678 if (*template == '\\' && template[1])
1680 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1683 else if (*template == escape)
1686 template = consume_int (template + 1, &index);
1687 if (index >= 1 && index <= n_values)
1689 pivot_value_format (values[index - 1], show_values,
1690 show_variables, out);
1691 args_consumed = MAX (args_consumed, index);
1695 ds_put_byte (out, *template++);
1697 return args_consumed;
1701 pivot_extract_inner_template (const char *template, const char **p)
1707 if (*template == '\\' && template[1] != '\0')
1709 else if (*template == ':')
1710 return template + 1;
1711 else if (*template == '\0')
1719 pivot_format_template (struct string *out, const char *template,
1720 const struct pivot_argument *args, size_t n_args,
1721 enum settings_value_show show_values,
1722 enum settings_value_show show_variables)
1726 if (*template == '\\' && template[1] != '\0')
1728 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1731 else if (*template == '^')
1734 template = consume_int (template + 1, &index);
1735 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1736 pivot_value_format (args[index - 1].values[0],
1737 show_values, show_variables, out);
1739 else if (*template == '[')
1741 const char *tmpl[2];
1742 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1743 template = pivot_extract_inner_template (template, &tmpl[1]);
1744 template += *template == ']';
1747 template = consume_int (template, &index);
1748 if (index < 1 || index > n_args)
1751 const struct pivot_argument *arg = &args[index - 1];
1752 size_t left = arg->n;
1755 struct pivot_value **values = arg->values + (arg->n - left);
1756 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1757 char escape = "%^"[tmpl_idx];
1758 size_t used = pivot_format_inner_template (
1759 out, tmpl[tmpl_idx], escape, values, left,
1760 show_values, show_variables);
1761 if (!used || used > left)
1767 ds_put_byte (out, *template++);
1771 static enum settings_value_show
1772 interpret_show (enum settings_value_show global_show,
1773 enum settings_value_show table_show,
1774 enum settings_value_show value_show,
1777 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1778 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1779 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1783 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1784 SHOW_VARIABLES control whether variable and value labels are included.
1786 The "body" omits subscripts and superscripts and footnotes. */
1788 pivot_value_format_body (const struct pivot_value *value,
1789 enum settings_value_show show_values,
1790 enum settings_value_show show_variables,
1793 enum settings_value_show show;
1794 bool numeric = false;
1796 switch (value->type)
1798 case PIVOT_VALUE_NUMERIC:
1799 show = interpret_show (settings_get_show_values (),
1801 value->numeric.show,
1802 value->numeric.value_label != NULL);
1803 if (show & SETTINGS_VALUE_SHOW_VALUE)
1805 char *s = data_out (&(union value) { .f = value->numeric.x },
1806 "UTF-8", &value->numeric.format);
1807 ds_put_cstr (out, s + strspn (s, " "));
1810 if (show & SETTINGS_VALUE_SHOW_LABEL)
1812 if (show & SETTINGS_VALUE_SHOW_VALUE)
1813 ds_put_byte (out, ' ');
1814 ds_put_cstr (out, value->numeric.value_label);
1816 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1819 case PIVOT_VALUE_STRING:
1820 show = interpret_show (settings_get_show_values (),
1823 value->string.value_label != NULL);
1824 if (show & SETTINGS_VALUE_SHOW_VALUE)
1826 if (value->string.hex)
1828 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1830 ds_put_format (out, "%02X", *p);
1833 ds_put_cstr (out, value->string.s);
1835 if (show & SETTINGS_VALUE_SHOW_LABEL)
1837 if (show & SETTINGS_VALUE_SHOW_VALUE)
1838 ds_put_byte (out, ' ');
1839 ds_put_cstr (out, value->string.value_label);
1843 case PIVOT_VALUE_VARIABLE:
1844 show = interpret_show (settings_get_show_variables (),
1846 value->variable.show,
1847 value->variable.var_label != NULL);
1848 if (show & SETTINGS_VALUE_SHOW_VALUE)
1849 ds_put_cstr (out, value->variable.var_name);
1850 if (show & SETTINGS_VALUE_SHOW_LABEL)
1852 if (show & SETTINGS_VALUE_SHOW_VALUE)
1853 ds_put_byte (out, ' ');
1854 ds_put_cstr (out, value->variable.var_label);
1858 case PIVOT_VALUE_TEXT:
1859 ds_put_cstr (out, value->text.local);
1862 case PIVOT_VALUE_TEMPLATE:
1863 pivot_format_template (out, value->template.s, value->template.args,
1864 value->template.n_args, show_values,
1872 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
1873 SHOW_VARIABLES control whether variable and value labels are included.
1875 Subscripts and superscripts and footnotes are included. */
1877 pivot_value_format (const struct pivot_value *value,
1878 enum settings_value_show show_values,
1879 enum settings_value_show show_variables,
1882 pivot_value_format_body ( value, show_values, show_variables, out);
1884 if (value->subscript)
1885 ds_put_format (out, "_%s", value->subscript);
1887 if (value->superscript)
1888 ds_put_format (out, "^%s", value->superscript);
1890 for (size_t i = 0; i < value->n_footnotes; i++)
1892 ds_put_byte (out, '^');
1893 pivot_value_format (value->footnotes[i]->marker,
1894 show_values, show_variables, out);
1898 /* Returns a text representation of VALUE. The caller must free the string,
1901 pivot_value_to_string (const struct pivot_value *value,
1902 enum settings_value_show show_values,
1903 enum settings_value_show show_variables)
1905 struct string s = DS_EMPTY_INITIALIZER;
1906 pivot_value_format (value, show_values, show_variables, &s);
1907 return ds_steal_cstr (&s);
1910 /* Frees the data owned by V. */
1912 pivot_value_destroy (struct pivot_value *value)
1916 font_style_uninit (value->font_style);
1917 free (value->font_style);
1918 free (value->cell_style);
1919 /* Do not free the elements of footnotes because VALUE does not own
1921 free (value->footnotes);
1922 free (value->subscript);
1924 switch (value->type)
1926 case PIVOT_VALUE_NUMERIC:
1927 free (value->numeric.var_name);
1928 free (value->numeric.value_label);
1931 case PIVOT_VALUE_STRING:
1932 free (value->string.s);
1933 free (value->string.var_name);
1934 free (value->string.value_label);
1937 case PIVOT_VALUE_VARIABLE:
1938 free (value->variable.var_name);
1939 free (value->variable.var_label);
1942 case PIVOT_VALUE_TEXT:
1943 free (value->text.local);
1944 if (value->text.c != value->text.local)
1945 free (value->text.c);
1946 if (value->text.id != value->text.local
1947 && value->text.id != value->text.c)
1948 free (value->text.id);
1951 case PIVOT_VALUE_TEMPLATE:
1952 free (value->template.s);
1953 for (size_t i = 0; i < value->template.n_args; i++)
1954 pivot_argument_uninit (&value->template.args[i]);
1955 free (value->template.args);
1962 /* Sets AREA to the style to use for VALUE, with defaults coming from
1963 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
1965 pivot_value_get_style (struct pivot_value *value,
1966 const struct area_style *default_style,
1967 struct area_style *area)
1969 font_style_copy (&area->font_style, (value->font_style
1971 : &default_style->font_style));
1972 area->cell_style = (value->cell_style
1973 ? *value->cell_style
1974 : default_style->cell_style);
1977 /* Copies AREA into VALUE's style. */
1979 pivot_value_set_style (struct pivot_value *value,
1980 const struct area_style *area)
1982 if (value->font_style)
1983 font_style_uninit (value->font_style);
1985 value->font_style = xmalloc (sizeof *value->font_style);
1986 font_style_copy (value->font_style, &area->font_style);
1988 if (!value->cell_style)
1989 value->cell_style = xmalloc (sizeof *value->cell_style);
1990 *value->cell_style = area->cell_style;
1993 /* Frees the data owned by ARG (but not ARG itself). */
1995 pivot_argument_uninit (struct pivot_argument *arg)
1999 for (size_t i = 0; i < arg->n; i++)
2000 pivot_value_destroy (arg->values[i]);
2005 /* Creates and returns a new pivot_value whose contents is the null-terminated
2006 string TEXT. Takes ownership of TEXT.
2008 This function is for text strings provided by the user (with the exception
2009 that pivot_value_new_variable() should be used for variable names). For
2010 strings that are part of the PSPP user interface, such as names of
2011 procedures, statistics, annotations, error messages, etc., use
2012 pivot_value_new_text(). */
2013 struct pivot_value *
2014 pivot_value_new_user_text_nocopy (char *text)
2016 struct pivot_value *value = xmalloc (sizeof *value);
2017 *value = (struct pivot_value) {
2018 .type = PIVOT_VALUE_TEXT,
2023 .user_provided = true,
2029 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2030 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2033 This function is for text strings provided by the user (with the exception
2034 that pivot_value_new_variable() should be used for variable names). For
2035 strings that are part of the PSPP user interface, such as names of
2036 procedures, statistics, annotations, error messages, etc., use
2037 pivot_value_new_text().j
2039 The caller retains ownership of TEXT.*/
2040 struct pivot_value *
2041 pivot_value_new_user_text (const char *text, size_t length)
2043 return pivot_value_new_user_text_nocopy (
2044 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2047 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2048 a translatable string, but not actually translated yet, e.g. enclosed in
2049 N_(). This function is for text strings that are part of the PSPP user
2050 interface, such as names of procedures, statistics, annotations, error
2051 messages, etc. For strings that come from the user, use
2052 pivot_value_new_user_text(). */
2053 struct pivot_value *
2054 pivot_value_new_text (const char *text)
2056 char *c = xstrdup (text);
2057 char *local = xstrdup (gettext (c));
2059 struct pivot_value *value = xmalloc (sizeof *value);
2060 *value = (struct pivot_value) {
2061 .type = PIVOT_VALUE_TEXT,
2066 .user_provided = false,
2072 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2074 struct pivot_value * PRINTF_FORMAT (1, 2)
2075 pivot_value_new_text_format (const char *format, ...)
2078 va_start (args, format);
2079 char *c = xvasprintf (format, args);
2082 va_start (args, format);
2083 char *local = xvasprintf (gettext (format), args);
2086 struct pivot_value *value = xmalloc (sizeof *value);
2087 *value = (struct pivot_value) {
2088 .type = PIVOT_VALUE_TEXT,
2093 .user_provided = false,
2100 xstrdup_if_nonempty (const char *s)
2102 return s && s[0] ? xstrdup (s) : NULL;
2105 /* Returns a new pivot_value that represents X.
2107 The format to use for X is unspecified. Usually the easiest way to specify
2108 a format is through assigning a result class to one of the categories that
2109 the pivot_value will end up in. If that is not suitable, then the caller
2110 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2111 struct pivot_value *
2112 pivot_value_new_number (double x)
2114 struct pivot_value *value = xmalloc (sizeof *value);
2115 *value = (struct pivot_value) {
2116 .type = PIVOT_VALUE_NUMERIC,
2117 .numeric = { .x = x, },
2122 /* Returns a new pivot_value that represents X, formatted as an integer. */
2123 struct pivot_value *
2124 pivot_value_new_integer (double x)
2126 struct pivot_value *value = pivot_value_new_number (x);
2127 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2131 /* Returns a new pivot_value that represents VALUE, formatted as for
2133 struct pivot_value *
2134 pivot_value_new_var_value (const struct variable *variable,
2135 const union value *value)
2137 struct pivot_value *pv = pivot_value_new_value (
2138 value, var_get_width (variable), var_get_print_format (variable),
2139 var_get_encoding (variable));
2141 char *var_name = xstrdup (var_get_name (variable));
2142 if (var_is_alpha (variable))
2143 pv->string.var_name = var_name;
2145 pv->numeric.var_name = var_name;
2147 const char *label = var_lookup_value_label (variable, value);
2150 if (var_is_alpha (variable))
2151 pv->string.value_label = xstrdup (label);
2153 pv->numeric.value_label = xstrdup (label);
2159 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2160 formatted with FORMAT. For a string value, ENCODING must be its character
2162 struct pivot_value *
2163 pivot_value_new_value (const union value *value, int width,
2164 const struct fmt_spec *format, const char *encoding)
2166 struct pivot_value *pv = xzalloc (sizeof *pv);
2169 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2171 size_t n = strlen (s);
2172 while (n > 0 && s[n - 1] == ' ')
2175 pv->type = PIVOT_VALUE_STRING;
2177 pv->string.hex = format->type == FMT_AHEX;
2181 pv->type = PIVOT_VALUE_NUMERIC;
2182 pv->numeric.x = value->f;
2183 pv->numeric.format = *format;
2189 /* Returns a new pivot_value for VARIABLE. */
2190 struct pivot_value *
2191 pivot_value_new_variable (const struct variable *variable)
2193 struct pivot_value *value = xmalloc (sizeof *value);
2194 *value = (struct pivot_value) {
2195 .type = PIVOT_VALUE_VARIABLE,
2197 .var_name = xstrdup (var_get_name (variable)),
2198 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2204 /* Attaches a reference to FOOTNOTE to V. */
2206 pivot_value_add_footnote (struct pivot_value *v,
2207 const struct pivot_footnote *footnote)
2209 v->footnotes = xrealloc (v->footnotes,
2210 (v->n_footnotes + 1) * sizeof *v->footnotes);
2211 v->footnotes[v->n_footnotes++] = footnote;
2214 /* If VALUE is a numeric value, and RC is a result class such as
2215 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2217 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2220 if (value->type == PIVOT_VALUE_NUMERIC)
2222 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2224 value->numeric.format = *f;