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 /* XXX extent and label_depth need to 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;
654 /* One piece of data within a pivot table. */
657 struct hmap_node hmap_node; /* In struct pivot_table's 'cells' hmap. */
658 struct pivot_value *value;
659 unsigned int idx[]; /* One index per table dimension. */
664 /* Creates and returns a new pivot table with the given TITLE. TITLE should be
665 a text string marked for translation but not actually translated yet,
666 e.g. N_("Descriptive Statistics").
668 Operations commonly performed on the new pivot_table:
670 - If empty rows or columns should not be displayed, set ->omit_empty to
673 - Set the format to use for "count" values with pivot_table_set_weight_var()
674 or pivot_table_set_weight_format().
676 This function is a shortcut for pivot_table_create__() for the most common
677 case. Use pivot_table_create__() directly if the title should be some kind
678 of value other than an ordinary text string.
680 See the large comment at the top of pivot-table.h for general advice on
681 creating pivot tables. */
683 pivot_table_create (const char *title)
685 return pivot_table_create__ (pivot_value_new_text (title));
688 /* Creates and returns a new pivot table with the given TITLE, and takes
691 Operations commonly performed on the new pivot_table:
693 - If empty rows or columns should not be displayed, set ->omit_empty to
696 - Set the format to use for "count" values with pivot_table_set_weight_var()
697 or pivot_table_set_weight_format().
699 See the large comment at the top of pivot-table.h for general advice on
700 creating pivot tables. */
702 pivot_table_create__ (struct pivot_value *title)
704 struct pivot_table *table = xzalloc (sizeof *table);
706 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
707 table->title = title;
709 table->sizing[TABLE_HORZ].range[0] = 50;
710 table->sizing[TABLE_HORZ].range[1] = 72;
711 table->sizing[TABLE_VERT].range[0] = 36;
712 table->sizing[TABLE_VERT].range[1] = 120;
714 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
715 pivot_area_get_default_style (i, &table->areas[i]);
717 /* Set default border styles. */
718 static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
719 [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE,
720 [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE,
721 [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE,
722 [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE,
723 [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
724 [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK,
725 [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK,
726 [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK,
727 [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
728 [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK,
729 [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK,
730 [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
731 [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
732 [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
733 [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
734 [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
735 [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
736 [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
737 [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
739 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
740 table->borders[i] = (struct table_border_style) {
741 .stroke = default_strokes[i],
742 .color = CELL_COLOR_BLACK,
745 table->row_labels_in_corner = true;
746 hmap_init (&table->cells);
751 /* Creates and returns a new pivot table with the given TITLE and a single cell
752 with the given CONTENT.
754 This is really just for error handling. */
756 pivot_table_create_for_text (struct pivot_value *title,
757 struct pivot_value *content)
759 struct pivot_table *table = pivot_table_create__ (title);
761 struct pivot_dimension *d = pivot_dimension_create (
762 table, PIVOT_AXIS_ROW, N_("Error"));
763 d->hide_all_labels = true;
764 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
766 pivot_table_put1 (table, 0, content);
771 /* Increases TABLE's reference count, indicating that it has an additional
772 owner. A pivot table that is shared among multiple owners must not be
775 pivot_table_ref (const struct pivot_table *table_)
777 struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
782 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
783 If TABLE no longer has any owners, it is freed. */
785 pivot_table_unref (struct pivot_table *table)
789 assert (table->ref_cnt > 0);
790 if (--table->ref_cnt)
793 free (table->current_layer);
794 free (table->table_look);
796 for (int i = 0; i < TABLE_N_AXES; i++)
797 pivot_table_sizing_uninit (&table->sizing[i]);
799 free (table->continuation);
801 for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
802 free (table->ccs[i]);
804 free (table->command_local);
805 free (table->command_c);
806 free (table->language);
807 free (table->locale);
809 free (table->dataset);
810 free (table->datafile);
812 for (size_t i = 0; i < table->n_footnotes; i++)
813 pivot_footnote_destroy (table->footnotes[i]);
814 free (table->footnotes);
816 pivot_value_destroy (table->title);
817 pivot_value_destroy (table->subtype);
818 pivot_value_destroy (table->corner_text);
819 pivot_value_destroy (table->caption);
821 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
822 area_style_uninit (&table->areas[i]);
824 for (size_t i = 0; i < table->n_dimensions; i++)
825 pivot_dimension_destroy (table->dimensions[i]);
826 free (table->dimensions);
828 for (size_t i = 0; i < PIVOT_N_AXES; i++)
829 free (table->axes[i].dimensions);
831 struct pivot_cell *cell, *next_cell;
832 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
835 hmap_delete (&table->cells, &cell->hmap_node);
836 pivot_value_destroy (cell->value);
839 hmap_destroy (&table->cells);
844 /* Returns true if TABLE has more than one owner. A pivot table that is shared
845 among multiple owners must not be modified. */
847 pivot_table_is_shared (const struct pivot_table *table)
849 return table->ref_cnt > 1;
852 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
853 WV, which should be the weight variable for the dictionary whose data or
854 statistics are being put into TABLE.
856 This has no effect if WV is NULL. */
858 pivot_table_set_weight_var (struct pivot_table *table,
859 const struct variable *wv)
862 pivot_table_set_weight_format (table, var_get_print_format (wv));
865 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
866 format for the dictionary whose data or statistics are being put into TABLE.
868 This has no effect if WFMT is NULL. */
870 pivot_table_set_weight_format (struct pivot_table *table,
871 const struct fmt_spec *wfmt)
874 table->weight_format = *wfmt;
877 /* Returns true if TABLE has no cells, false otherwise. */
879 pivot_table_is_empty (const struct pivot_table *table)
881 return hmap_is_empty (&table->cells);
885 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
887 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
891 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
893 for (size_t i = 0; i < n; i++)
900 static struct pivot_cell *
901 pivot_table_lookup_cell__ (const struct pivot_table *table,
902 const size_t *dindexes, unsigned int hash)
904 struct pivot_cell *cell;
905 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
907 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
912 static struct pivot_cell *
913 pivot_cell_allocate (size_t n_idx)
915 struct pivot_cell *cell UNUSED;
916 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
919 static struct pivot_cell *
920 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
922 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
923 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
926 cell = pivot_cell_allocate (table->n_dimensions);
927 for (size_t i = 0; i < table->n_dimensions; i++)
928 cell->idx[i] = dindexes[i];
930 hmap_insert (&table->cells, &cell->hmap_node, hash);
935 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
936 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
939 If VALUE is a numeric value without a specified format, this function checks
940 each of the categories designated by DINDEXES[] and takes the format from
941 the first category with a result class. If none has a result class, uses
942 the overall default numeric format. */
944 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
945 struct pivot_value *value)
947 assert (n == table->n_dimensions);
949 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
951 for (size_t i = 0; i < table->n_dimensions; i++)
953 const struct pivot_dimension *d = table->dimensions[i];
954 if (dindexes[i] < d->n_leaves)
956 const struct pivot_category *c = d->data_leaves[dindexes[i]];
959 value->numeric.format = c->format;
964 value->numeric.format = *settings_get_format ();
969 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
970 pivot_value_destroy (cell->value);
974 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
975 dimension. Takes ownership of VALUE. */
977 pivot_table_put1 (struct pivot_table *table, size_t idx1,
978 struct pivot_value *value)
980 size_t dindexes[] = { idx1 };
981 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
984 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
985 dimensions. Takes ownership of VALUE. */
987 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
988 struct pivot_value *value)
990 size_t dindexes[] = { idx1, idx2 };
991 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
994 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
995 have 3 dimensions. Takes ownership of VALUE. */
997 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
998 size_t idx3, struct pivot_value *value)
1000 size_t dindexes[] = { idx1, idx2, idx3 };
1001 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1004 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
1005 must have 4 dimensions. Takes ownership of VALUE. */
1007 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1008 size_t idx3, size_t idx4, struct pivot_value *value)
1010 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1011 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1014 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1015 automatically assigned marker.
1017 The footnote will only appear in output if it is referenced. Use
1018 pivot_value_add_footnote() to add a reference to the footnote. */
1019 struct pivot_footnote *
1020 pivot_table_create_footnote (struct pivot_table *table,
1021 struct pivot_value *content)
1023 return pivot_table_create_footnote__ (table, table->n_footnotes,
1027 static struct pivot_value *
1028 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1030 char text[INT_BUFSIZE_BOUND (size_t)];
1031 if (show_numeric_markers)
1032 snprintf (text, sizeof text, "%d", idx + 1);
1034 str_format_26adic (idx + 1, false, text, sizeof text);
1035 return pivot_value_new_user_text (text, -1);
1038 /* Creates or modifies a footnote in TABLE with 0-based number IDX. If MARKER
1039 is nonnull, sets the footnote's marker; if CONTENT is nonnull, sets the
1040 footnote's content. */
1041 struct pivot_footnote *
1042 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1043 struct pivot_value *marker,
1044 struct pivot_value *content)
1046 if (idx >= table->n_footnotes)
1048 while (idx >= table->allocated_footnotes)
1049 table->footnotes = x2nrealloc (table->footnotes,
1050 &table->allocated_footnotes,
1051 sizeof *table->footnotes);
1052 while (idx >= table->n_footnotes)
1054 struct pivot_footnote *f = xmalloc (sizeof *f);
1055 f->idx = table->n_footnotes;
1056 f->marker = pivot_make_default_footnote_marker (
1057 f->idx, table->show_numeric_markers);
1060 table->footnotes[table->n_footnotes++] = f;
1064 struct pivot_footnote *f = table->footnotes[idx];
1067 pivot_value_destroy (f->marker);
1072 pivot_value_destroy (f->content);
1073 f->content = content;
1078 /* Frees the data owned by F. */
1080 pivot_footnote_destroy (struct pivot_footnote *f)
1084 pivot_value_destroy (f->content);
1085 pivot_value_destroy (f->marker);
1090 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1091 indexes for each dimension in TABLE in DINDEXES[]. */
1093 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1094 const size_t *pindexes[PIVOT_N_AXES],
1095 size_t dindexes[/* table->n_dimensions */])
1097 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1099 const struct pivot_axis *axis = &table->axes[i];
1101 for (size_t j = 0; j < axis->n_dimensions; j++)
1103 const struct pivot_dimension *d = axis->dimensions[j];
1104 dindexes[d->top_index]
1105 = d->presentation_leaves[pindexes[i][j]]->data_index;
1111 pivot_table_enumerate_axis (const struct pivot_table *table,
1112 enum pivot_axis_type axis_type,
1113 const size_t *layer_indexes, bool omit_empty,
1116 const struct pivot_axis *axis = &table->axes[axis_type];
1117 if (!axis->n_dimensions)
1119 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1121 enumeration[1] = SIZE_MAX;
1126 else if (!axis->extent)
1128 size_t *enumeration = xmalloc (sizeof *enumeration);
1129 *enumeration = SIZE_MAX;
1135 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1136 axis->n_dimensions), 1),
1137 sizeof *enumeration);
1138 size_t *p = enumeration;
1139 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1141 size_t *axis_indexes;
1142 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1146 enum pivot_axis_type axis2_type
1147 = pivot_axis_type_transpose (axis_type);
1149 size_t *axis2_indexes;
1150 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1152 const size_t *pindexes[PIVOT_N_AXES];
1153 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1154 pindexes[axis_type] = axis_indexes;
1155 pindexes[axis2_type] = axis2_indexes;
1156 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1157 if (pivot_table_get (table, dindexes))
1163 free (axis2_indexes);
1166 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1167 p += axis->n_dimensions;
1171 *n = (p - enumeration) / axis->n_dimensions;
1177 static const struct pivot_cell *
1178 pivot_table_lookup_cell (const struct pivot_table *table,
1179 const size_t *dindexes)
1181 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1182 return pivot_table_lookup_cell__ (table, dindexes, hash);
1185 const struct pivot_value *
1186 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1188 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1189 return cell ? cell->value : NULL;
1192 struct pivot_value *
1193 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1195 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1197 cell->value = pivot_value_new_user_text ("", -1);
1202 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1204 if (pivot_category_is_group (category) && category->n_subs)
1205 for (size_t i = 0; i < category->n_subs; i++)
1206 distribute_extra_depth (category->subs[i], extra_depth);
1208 category->extra_depth += extra_depth;
1212 pivot_category_assign_label_depth (struct pivot_category *category,
1213 bool dimension_labels_in_corner)
1215 category->extra_depth = 0;
1217 if (pivot_category_is_group (category))
1220 for (size_t i = 0; i < category->n_subs; i++)
1222 pivot_category_assign_label_depth (category->subs[i], false);
1223 depth = MAX (depth, category->subs[i]->label_depth);
1226 for (size_t i = 0; i < category->n_subs; i++)
1228 struct pivot_category *sub = category->subs[i];
1230 size_t extra_depth = depth - sub->label_depth;
1232 distribute_extra_depth (sub, extra_depth);
1234 sub->label_depth = depth;
1237 category->show_label_in_corner = (category->show_label
1238 && dimension_labels_in_corner);
1239 category->label_depth
1240 = (category->show_label && !category->show_label_in_corner
1241 ? depth + 1 : depth);
1244 category->label_depth = 1;
1248 pivot_axis_assign_label_depth (struct pivot_table *table,
1249 enum pivot_axis_type axis_type,
1250 bool dimension_labels_in_corner)
1252 struct pivot_axis *axis = &table->axes[axis_type];
1253 bool any_label_shown_in_corner = false;
1254 axis->label_depth = 0;
1256 for (size_t i = 0; i < axis->n_dimensions; i++)
1258 struct pivot_dimension *d = axis->dimensions[i];
1259 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1260 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1261 axis->label_depth += d->label_depth;
1262 axis->extent *= d->n_leaves;
1264 if (d->root->show_label_in_corner)
1265 any_label_shown_in_corner = true;
1267 return any_label_shown_in_corner;
1271 pivot_table_assign_label_depth (struct pivot_table *table)
1273 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1274 if (pivot_axis_assign_label_depth (
1275 table, PIVOT_AXIS_ROW, (table->row_labels_in_corner
1276 && !table->corner_text))
1277 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1278 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1279 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1287 indent (int indentation)
1289 for (int i = 0; i < indentation * 2; i++)
1294 pivot_value_dump (const struct pivot_value *value)
1296 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1297 SETTINGS_VALUE_SHOW_DEFAULT);
1303 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1308 indent (indentation);
1309 printf ("%s: ", name);
1310 pivot_value_dump (value);
1316 pivot_table_dump_string (const char *string, const char *name, int indentation)
1320 indent (indentation);
1321 printf ("%s: %s\n", name, string);
1326 pivot_category_dump (const struct pivot_category *c, int indentation)
1328 indent (indentation);
1329 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1330 pivot_value_dump (c->name);
1333 if (pivot_category_is_leaf (c))
1334 printf ("data_index=%zu\n", c->data_index);
1337 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1340 for (size_t i = 0; i < c->n_subs; i++)
1341 pivot_category_dump (c->subs[i], indentation + 1);
1346 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1348 indent (indentation);
1349 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1350 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1352 pivot_category_dump (d->root, indentation + 1);
1356 area_style_dump (enum pivot_area area, const struct area_style *a,
1359 indent (indentation);
1360 printf ("%s: ", pivot_area_to_string (area));
1361 font_style_dump (&a->font_style);
1363 cell_style_dump (&a->cell_style);
1368 table_border_style_dump (enum pivot_border border,
1369 const struct table_border_style *b, int indentation)
1371 indent (indentation);
1372 printf ("%s: %s ", pivot_border_to_string (border),
1373 table_stroke_to_string (b->stroke));
1374 cell_color_dump (&b->color);
1379 compose_headings (const struct pivot_axis *axis,
1380 const size_t *column_enumeration,
1381 enum settings_value_show show_values,
1382 enum settings_value_show show_variables)
1384 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1387 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1388 for (size_t i = 0; i < axis->label_depth; i++)
1389 headings[i] = xcalloc (axis->extent, sizeof **headings);
1391 const size_t *indexes;
1393 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1395 int row = axis->label_depth - 1;
1396 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1398 const struct pivot_dimension *d = axis->dimensions[dim_index];
1399 if (d->hide_all_labels)
1401 for (const struct pivot_category *c
1402 = d->presentation_leaves[indexes[dim_index]];
1406 if (pivot_category_is_leaf (c) || (c->show_label
1407 && !c->show_label_in_corner))
1409 headings[row][column] = pivot_value_to_string (
1410 c->name, show_values, show_variables);
1411 if (!*headings[row][column])
1412 headings[row][column] = xstrdup ("<blank>");
1424 free_headings (const struct pivot_axis *axis, char ***headings)
1426 for (size_t i = 0; i < axis->label_depth; i++)
1428 for (size_t j = 0; j < axis->extent; j++)
1429 free (headings[i][j]);
1436 pivot_table_dump (const struct pivot_table *table, int indentation)
1441 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1442 if (table->decimal == '.' || table->decimal == ',')
1443 settings_set_decimal_char (table->decimal);
1445 pivot_table_dump_value (table->title, "title", indentation);
1446 pivot_table_dump_string (table->command_c, "command", indentation);
1447 pivot_table_dump_string (table->dataset, "dataset", indentation);
1448 pivot_table_dump_string (table->datafile, "datafile", indentation);
1449 pivot_table_dump_string (table->notes, "notes", indentation);
1450 pivot_table_dump_string (table->table_look, "table-look", indentation);
1453 indent (indentation);
1455 printf ("date: %s", ctime_r (&table->date, buf));
1458 indent (indentation);
1459 printf ("areas:\n");
1460 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1461 area_style_dump (area, &table->areas[area], indentation + 1);
1463 indent (indentation);
1464 printf ("borders:\n");
1465 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1466 table_border_style_dump (border, &table->borders[border], indentation + 1);
1468 for (size_t i = 0; i < table->n_dimensions; i++)
1469 pivot_dimension_dump (table->dimensions[i], indentation);
1471 /* Presentation and data indexes. */
1472 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1474 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1475 if (layer_axis->n_dimensions)
1477 indent (indentation);
1478 printf ("current layer:");
1480 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1482 const struct pivot_dimension *d = layer_axis->dimensions[i];
1483 char *name = pivot_value_to_string (d->root->name,
1485 table->show_variables);
1486 char *value = pivot_value_to_string (
1487 d->data_leaves[table->current_layer[i]]->name,
1488 table->show_values, table->show_variables);
1489 printf (" %s=%s", name, value);
1497 size_t *layer_indexes;
1498 size_t layer_iteration = 0;
1499 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1501 indent (indentation);
1502 printf ("layer %zu:", layer_iteration++);
1504 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1505 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1507 const struct pivot_dimension *d = layer_axis->dimensions[i];
1509 fputs (i == 0 ? " " : ", ", stdout);
1510 pivot_value_dump (d->root->name);
1511 fputs (" =", stdout);
1513 struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1516 for (const struct pivot_category *c
1517 = d->presentation_leaves[layer_indexes[i]];
1521 if (pivot_category_is_leaf (c) || c->show_label)
1522 names[n_names++] = c->name;
1525 for (size_t i = n_names; i-- > 0; )
1528 pivot_value_dump (names[i]);
1534 size_t *column_enumeration = pivot_table_enumerate_axis (
1535 table, PIVOT_AXIS_COLUMN, layer_indexes, table->omit_empty, NULL);
1536 size_t *row_enumeration = pivot_table_enumerate_axis (
1537 table, PIVOT_AXIS_ROW, layer_indexes, table->omit_empty, NULL);
1539 char ***column_headings = compose_headings (
1540 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1541 table->show_values, table->show_variables);
1542 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1544 indent (indentation + 1);
1545 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1548 fputs ("; ", stdout);
1549 if (column_headings[y][x])
1550 fputs (column_headings[y][x], stdout);
1554 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1556 indent (indentation + 1);
1557 printf ("-----------------------------------------------\n");
1559 char ***row_headings = compose_headings (
1560 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1561 table->show_values, table->show_variables);
1564 const size_t *pindexes[PIVOT_N_AXES]
1565 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1566 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1567 &table->axes[PIVOT_AXIS_ROW])
1569 indent (indentation + 1);
1572 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1575 fputs ("; ", stdout);
1576 if (row_headings[y][x])
1577 fputs (row_headings[y][x], stdout);
1583 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1585 &table->axes[PIVOT_AXIS_COLUMN])
1590 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1591 const struct pivot_value *value = pivot_table_get (
1594 pivot_value_dump (value);
1601 free (column_enumeration);
1602 free (row_enumeration);
1603 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1606 pivot_table_dump_value (table->caption, "caption", indentation);
1608 for (size_t i = 0; i < table->n_footnotes; i++)
1610 const struct pivot_footnote *f = table->footnotes[i];
1611 indent (indentation);
1614 pivot_value_dump (f->marker);
1616 printf ("%zu", f->idx);
1618 pivot_value_dump (f->content);
1623 settings_set_decimal_char (old_decimal);
1627 consume_int (const char *p, size_t *n)
1630 while (c_isdigit (*p))
1631 *n = *n * 10 + (*p++ - '0');
1636 pivot_format_inner_template (struct string *out, const char *template,
1638 struct pivot_value **values, size_t n_values,
1639 enum settings_value_show show_values,
1640 enum settings_value_show show_variables)
1642 size_t args_consumed = 0;
1643 while (*template && *template != ':')
1645 if (*template == '\\' && template[1])
1647 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1650 else if (*template == escape)
1653 template = consume_int (template + 1, &index);
1654 if (index >= 1 && index <= n_values)
1656 pivot_value_format (values[index - 1], show_values,
1657 show_variables, out);
1658 args_consumed = MAX (args_consumed, index);
1662 ds_put_byte (out, *template++);
1664 return args_consumed;
1668 pivot_extract_inner_template (const char *template, const char **p)
1674 if (*template == '\\' && template[1] != '\0')
1676 else if (*template == ':')
1677 return template + 1;
1678 else if (*template == '\0')
1686 pivot_format_template (struct string *out, const char *template,
1687 const struct pivot_argument *args, size_t n_args,
1688 enum settings_value_show show_values,
1689 enum settings_value_show show_variables)
1693 if (*template == '\\' && template[1] != '\0')
1695 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1698 else if (*template == '^')
1701 template = consume_int (template + 1, &index);
1702 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1703 pivot_value_format (args[index - 1].values[0],
1704 show_values, show_variables, out);
1706 else if (*template == '[')
1708 const char *tmpl[2];
1709 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1710 template = pivot_extract_inner_template (template, &tmpl[1]);
1711 template += *template == ']';
1714 template = consume_int (template, &index);
1715 if (index < 1 || index > n_args)
1718 const struct pivot_argument *arg = &args[index - 1];
1719 size_t left = arg->n;
1722 struct pivot_value **values = arg->values + (arg->n - left);
1723 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1724 char escape = "%^"[tmpl_idx];
1725 size_t used = pivot_format_inner_template (
1726 out, tmpl[tmpl_idx], escape, values, left,
1727 show_values, show_variables);
1728 if (!used || used > left)
1734 ds_put_byte (out, *template++);
1738 static enum settings_value_show
1739 interpret_show (enum settings_value_show global_show,
1740 enum settings_value_show table_show,
1741 enum settings_value_show value_show,
1744 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1745 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1746 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1750 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1751 SHOW_VARIABLES control whether variable and value labels are included.
1753 The "body" omits subscripts and superscripts and footnotes. */
1755 pivot_value_format_body (const struct pivot_value *value,
1756 enum settings_value_show show_values,
1757 enum settings_value_show show_variables,
1760 enum settings_value_show show;
1761 bool numeric = false;
1763 switch (value->type)
1765 case PIVOT_VALUE_NUMERIC:
1766 show = interpret_show (settings_get_show_values (),
1768 value->numeric.show,
1769 value->numeric.value_label != NULL);
1770 if (show & SETTINGS_VALUE_SHOW_VALUE)
1772 char *s = data_out (&(union value) { .f = value->numeric.x },
1773 "UTF-8", &value->numeric.format);
1774 ds_put_cstr (out, s + strspn (s, " "));
1777 if (show & SETTINGS_VALUE_SHOW_LABEL)
1779 if (show & SETTINGS_VALUE_SHOW_VALUE)
1780 ds_put_byte (out, ' ');
1781 ds_put_cstr (out, value->numeric.value_label);
1783 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1786 case PIVOT_VALUE_STRING:
1787 show = interpret_show (settings_get_show_values (),
1790 value->string.value_label != NULL);
1791 if (show & SETTINGS_VALUE_SHOW_VALUE)
1793 if (value->string.hex)
1795 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1797 ds_put_format (out, "%02X", *p);
1800 ds_put_cstr (out, value->string.s);
1802 if (show & SETTINGS_VALUE_SHOW_LABEL)
1804 if (show & SETTINGS_VALUE_SHOW_VALUE)
1805 ds_put_byte (out, ' ');
1806 ds_put_cstr (out, value->string.value_label);
1810 case PIVOT_VALUE_VARIABLE:
1811 show = interpret_show (settings_get_show_variables (),
1813 value->variable.show,
1814 value->variable.var_label != NULL);
1815 if (show & SETTINGS_VALUE_SHOW_VALUE)
1816 ds_put_cstr (out, value->variable.var_name);
1817 if (show & SETTINGS_VALUE_SHOW_LABEL)
1819 if (show & SETTINGS_VALUE_SHOW_VALUE)
1820 ds_put_byte (out, ' ');
1821 ds_put_cstr (out, value->variable.var_label);
1825 case PIVOT_VALUE_TEXT:
1826 ds_put_cstr (out, value->text.local);
1829 case PIVOT_VALUE_TEMPLATE:
1830 pivot_format_template (out, value->template.s, value->template.args,
1831 value->template.n_args, show_values,
1839 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
1840 SHOW_VARIABLES control whether variable and value labels are included.
1842 Subscripts and superscripts and footnotes are included. */
1844 pivot_value_format (const struct pivot_value *value,
1845 enum settings_value_show show_values,
1846 enum settings_value_show show_variables,
1849 pivot_value_format_body ( value, show_values, show_variables, out);
1851 if (value->subscript)
1852 ds_put_format (out, "_%s", value->subscript);
1854 if (value->superscript)
1855 ds_put_format (out, "^%s", value->superscript);
1857 for (size_t i = 0; i < value->n_footnotes; i++)
1859 ds_put_byte (out, '^');
1860 pivot_value_format (value->footnotes[i]->marker,
1861 show_values, show_variables, out);
1865 /* Returns a text representation of VALUE. The caller must free the string,
1868 pivot_value_to_string (const struct pivot_value *value,
1869 enum settings_value_show show_values,
1870 enum settings_value_show show_variables)
1872 struct string s = DS_EMPTY_INITIALIZER;
1873 pivot_value_format (value, show_values, show_variables, &s);
1874 return ds_steal_cstr (&s);
1877 /* Frees the data owned by V. */
1879 pivot_value_destroy (struct pivot_value *value)
1883 font_style_uninit (value->font_style);
1884 free (value->font_style);
1885 free (value->cell_style);
1886 /* Do not free the elements of footnotes because VALUE does not own
1888 free (value->footnotes);
1889 free (value->subscript);
1891 switch (value->type)
1893 case PIVOT_VALUE_NUMERIC:
1894 free (value->numeric.var_name);
1895 free (value->numeric.value_label);
1898 case PIVOT_VALUE_STRING:
1899 free (value->string.s);
1900 free (value->string.var_name);
1901 free (value->string.value_label);
1904 case PIVOT_VALUE_VARIABLE:
1905 free (value->variable.var_name);
1906 free (value->variable.var_label);
1909 case PIVOT_VALUE_TEXT:
1910 free (value->text.local);
1911 if (value->text.c != value->text.local)
1912 free (value->text.c);
1913 if (value->text.id != value->text.local
1914 && value->text.id != value->text.c)
1915 free (value->text.id);
1918 case PIVOT_VALUE_TEMPLATE:
1919 free (value->template.s);
1920 for (size_t i = 0; i < value->template.n_args; i++)
1921 pivot_argument_uninit (&value->template.args[i]);
1922 free (value->template.args);
1929 /* Sets AREA to the style to use for VALUE, with defaults coming from
1930 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
1932 pivot_value_get_style (struct pivot_value *value,
1933 const struct area_style *default_style,
1934 struct area_style *area)
1936 font_style_copy (&area->font_style, (value->font_style
1938 : &default_style->font_style));
1939 area->cell_style = (value->cell_style
1940 ? *value->cell_style
1941 : default_style->cell_style);
1944 /* Copies AREA into VALUE's style. */
1946 pivot_value_set_style (struct pivot_value *value,
1947 const struct area_style *area)
1949 if (value->font_style)
1950 font_style_uninit (value->font_style);
1952 value->font_style = xmalloc (sizeof *value->font_style);
1953 font_style_copy (value->font_style, &area->font_style);
1955 if (!value->cell_style)
1956 value->cell_style = xmalloc (sizeof *value->cell_style);
1957 *value->cell_style = area->cell_style;
1960 /* Frees the data owned by ARG (but not ARG itself). */
1962 pivot_argument_uninit (struct pivot_argument *arg)
1966 for (size_t i = 0; i < arg->n; i++)
1967 pivot_value_destroy (arg->values[i]);
1972 /* Creates and returns a new pivot_value whose contents is the null-terminated
1973 string TEXT. Takes ownership of TEXT.
1975 This function is for text strings provided by the user (with the exception
1976 that pivot_value_new_variable() should be used for variable names). For
1977 strings that are part of the PSPP user interface, such as names of
1978 procedures, statistics, annotations, error messages, etc., use
1979 pivot_value_new_text(). */
1980 struct pivot_value *
1981 pivot_value_new_user_text_nocopy (char *text)
1983 struct pivot_value *value = xmalloc (sizeof *value);
1984 *value = (struct pivot_value) {
1985 .type = PIVOT_VALUE_TEXT,
1990 .user_provided = true,
1996 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
1997 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2000 This function is for text strings provided by the user (with the exception
2001 that pivot_value_new_variable() should be used for variable names). For
2002 strings that are part of the PSPP user interface, such as names of
2003 procedures, statistics, annotations, error messages, etc., use
2004 pivot_value_new_text().j
2006 The caller retains ownership of TEXT.*/
2007 struct pivot_value *
2008 pivot_value_new_user_text (const char *text, size_t length)
2010 return pivot_value_new_user_text_nocopy (
2011 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2014 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2015 a translatable string, but not actually translated yet, e.g. enclosed in
2016 N_(). This function is for text strings that are part of the PSPP user
2017 interface, such as names of procedures, statistics, annotations, error
2018 messages, etc. For strings that come from the user, use
2019 pivot_value_new_user_text(). */
2020 struct pivot_value *
2021 pivot_value_new_text (const char *text)
2023 char *c = xstrdup (text);
2024 char *local = xstrdup (gettext (c));
2026 struct pivot_value *value = xmalloc (sizeof *value);
2027 *value = (struct pivot_value) {
2028 .type = PIVOT_VALUE_TEXT,
2033 .user_provided = false,
2039 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2041 struct pivot_value * PRINTF_FORMAT (1, 2)
2042 pivot_value_new_text_format (const char *format, ...)
2045 va_start (args, format);
2046 char *c = xvasprintf (format, args);
2049 va_start (args, format);
2050 char *local = xvasprintf (gettext (format), args);
2053 struct pivot_value *value = xmalloc (sizeof *value);
2054 *value = (struct pivot_value) {
2055 .type = PIVOT_VALUE_TEXT,
2060 .user_provided = false,
2067 xstrdup_if_nonempty (const char *s)
2069 return s && s[0] ? xstrdup (s) : NULL;
2072 /* Returns a new pivot_value that represents X.
2074 The format to use for X is unspecified. Usually the easiest way to specify
2075 a format is through assigning a result class to one of the categories that
2076 the pivot_value will end up in. If that is not suitable, then the caller
2077 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2078 struct pivot_value *
2079 pivot_value_new_number (double x)
2081 struct pivot_value *value = xmalloc (sizeof *value);
2082 *value = (struct pivot_value) {
2083 .type = PIVOT_VALUE_NUMERIC,
2084 .numeric = { .x = x, },
2089 /* Returns a new pivot_value that represents X, formatted as an integer. */
2090 struct pivot_value *
2091 pivot_value_new_integer (double x)
2093 struct pivot_value *value = pivot_value_new_number (x);
2094 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2098 /* Returns a new pivot_value that represents VALUE, formatted as for
2100 struct pivot_value *
2101 pivot_value_new_var_value (const struct variable *variable,
2102 const union value *value)
2104 struct pivot_value *pv = pivot_value_new_value (
2105 value, var_get_width (variable), var_get_print_format (variable),
2106 var_get_encoding (variable));
2108 char *var_name = xstrdup (var_get_name (variable));
2109 if (var_is_alpha (variable))
2110 pv->string.var_name = var_name;
2112 pv->numeric.var_name = var_name;
2114 const char *label = var_lookup_value_label (variable, value);
2117 if (var_is_alpha (variable))
2118 pv->string.value_label = xstrdup (label);
2120 pv->numeric.value_label = xstrdup (label);
2126 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2127 formatted with FORMAT. For a string value, ENCODING must be its character
2129 struct pivot_value *
2130 pivot_value_new_value (const union value *value, int width,
2131 const struct fmt_spec *format, const char *encoding)
2133 struct pivot_value *pv = xzalloc (sizeof *pv);
2136 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2138 size_t n = strlen (s);
2139 while (n > 0 && s[n - 1] == ' ')
2142 pv->type = PIVOT_VALUE_STRING;
2144 pv->string.hex = format->type == FMT_AHEX;
2148 pv->type = PIVOT_VALUE_NUMERIC;
2149 pv->numeric.x = value->f;
2150 pv->numeric.format = *format;
2156 /* Returns a new pivot_value for VARIABLE. */
2157 struct pivot_value *
2158 pivot_value_new_variable (const struct variable *variable)
2160 struct pivot_value *value = xmalloc (sizeof *value);
2161 *value = (struct pivot_value) {
2162 .type = PIVOT_VALUE_VARIABLE,
2164 .var_name = xstrdup (var_get_name (variable)),
2165 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2171 /* Attaches a reference to FOOTNOTE to V. */
2173 pivot_value_add_footnote (struct pivot_value *v,
2174 const struct pivot_footnote *footnote)
2176 v->footnotes = xrealloc (v->footnotes,
2177 (v->n_footnotes + 1) * sizeof *v->footnotes);
2178 v->footnotes[v->n_footnotes++] = footnote;
2181 /* If VALUE is a numeric value, and RC is a result class such as
2182 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2184 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2187 if (value->type == PIVOT_VALUE_NUMERIC)
2189 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2191 value->numeric.format = *f;