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_dump (const struct pivot_table *table, int indentation)
1433 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1434 if (table->decimal == '.' || table->decimal == ',')
1435 settings_set_decimal_char (table->decimal);
1437 pivot_table_dump_value (table->title, "title", indentation);
1438 pivot_table_dump_string (table->command_c, "command", indentation);
1439 pivot_table_dump_string (table->dataset, "dataset", indentation);
1440 pivot_table_dump_string (table->datafile, "datafile", indentation);
1441 pivot_table_dump_string (table->notes, "notes", indentation);
1442 pivot_table_dump_string (table->table_look, "table-look", indentation);
1445 indent (indentation);
1447 printf ("date: %s", ctime_r (&table->date, buf));
1450 indent (indentation);
1451 printf ("areas:\n");
1452 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1453 area_style_dump (area, &table->areas[area], indentation + 1);
1455 indent (indentation);
1456 printf ("borders:\n");
1457 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1458 table_border_style_dump (border, &table->borders[border], indentation + 1);
1460 for (size_t i = 0; i < table->n_dimensions; i++)
1461 pivot_dimension_dump (table->dimensions[i], indentation);
1463 /* Presentation and data indexes. */
1464 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1466 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1467 if (layer_axis->n_dimensions)
1469 indent (indentation);
1470 printf ("current layer:");
1472 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1474 const struct pivot_dimension *d = layer_axis->dimensions[i];
1475 char *name = pivot_value_to_string (d->root->name,
1477 table->show_variables);
1478 char *value = pivot_value_to_string (
1479 d->data_leaves[table->current_layer[i]]->name,
1480 table->show_values, table->show_variables);
1481 printf (" %s=%s", name, value);
1489 size_t *layer_indexes;
1490 size_t layer_iteration = 0;
1491 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1493 indent (indentation);
1494 printf ("layer %zu:", layer_iteration++);
1496 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1497 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1499 const struct pivot_dimension *d = layer_axis->dimensions[i];
1501 fputs (i == 0 ? " " : ", ", stdout);
1502 pivot_value_dump (d->root->name);
1503 fputs (" =", stdout);
1505 struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1508 for (const struct pivot_category *c
1509 = d->presentation_leaves[layer_indexes[i]];
1513 if (pivot_category_is_leaf (c) || c->show_label)
1514 names[n_names++] = c->name;
1517 for (size_t i = n_names; i-- > 0; )
1520 pivot_value_dump (names[i]);
1526 size_t *column_enumeration = pivot_table_enumerate_axis (
1527 table, PIVOT_AXIS_COLUMN, layer_indexes, table->omit_empty, NULL);
1528 size_t *row_enumeration = pivot_table_enumerate_axis (
1529 table, PIVOT_AXIS_ROW, layer_indexes, table->omit_empty, NULL);
1531 char ***column_headings = compose_headings (
1532 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1533 table->show_values, table->show_variables);
1534 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1536 indent (indentation + 1);
1537 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1540 fputs ("; ", stdout);
1541 if (column_headings[y][x])
1542 fputs (column_headings[y][x], stdout);
1546 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1548 indent (indentation + 1);
1549 printf ("-----------------------------------------------\n");
1551 char ***row_headings = compose_headings (
1552 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1553 table->show_values, table->show_variables);
1556 const size_t *pindexes[PIVOT_N_AXES]
1557 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1558 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1559 &table->axes[PIVOT_AXIS_ROW])
1561 indent (indentation + 1);
1564 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1567 fputs ("; ", stdout);
1568 if (row_headings[y][x])
1569 fputs (row_headings[y][x], stdout);
1575 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1577 &table->axes[PIVOT_AXIS_COLUMN])
1582 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1583 const struct pivot_value *value = pivot_table_get (
1586 pivot_value_dump (value);
1593 free (column_enumeration);
1594 free (row_enumeration);
1595 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1598 pivot_table_dump_value (table->caption, "caption", indentation);
1600 for (size_t i = 0; i < table->n_footnotes; i++)
1602 const struct pivot_footnote *f = table->footnotes[i];
1603 indent (indentation);
1606 pivot_value_dump (f->marker);
1608 printf ("%zu", f->idx);
1610 pivot_value_dump (f->content);
1615 settings_set_decimal_char (old_decimal);
1619 consume_int (const char *p, size_t *n)
1622 while (c_isdigit (*p))
1623 *n = *n * 10 + (*p++ - '0');
1628 pivot_format_inner_template (struct string *out, const char *template,
1630 struct pivot_value **values, size_t n_values,
1631 enum settings_value_show show_values,
1632 enum settings_value_show show_variables)
1634 size_t args_consumed = 0;
1635 while (*template && *template != ':')
1637 if (*template == '\\' && template[1])
1639 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1642 else if (*template == escape)
1645 template = consume_int (template + 1, &index);
1646 if (index >= 1 && index <= n_values)
1648 pivot_value_format (values[index - 1], show_values,
1649 show_variables, out);
1650 args_consumed = MAX (args_consumed, index);
1654 ds_put_byte (out, *template++);
1656 return args_consumed;
1660 pivot_extract_inner_template (const char *template, const char **p)
1666 if (*template == '\\' && template[1] != '\0')
1668 else if (*template == ':')
1669 return template + 1;
1670 else if (*template == '\0')
1678 pivot_format_template (struct string *out, const char *template,
1679 const struct pivot_argument *args, size_t n_args,
1680 enum settings_value_show show_values,
1681 enum settings_value_show show_variables)
1685 if (*template == '\\' && template[1] != '\0')
1687 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1690 else if (*template == '^')
1693 template = consume_int (template + 1, &index);
1694 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1695 pivot_value_format (args[index - 1].values[0],
1696 show_values, show_variables, out);
1698 else if (*template == '[')
1700 const char *tmpl[2];
1701 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1702 template = pivot_extract_inner_template (template, &tmpl[1]);
1703 template += *template == ']';
1706 template = consume_int (template, &index);
1707 if (index < 1 || index > n_args)
1710 const struct pivot_argument *arg = &args[index - 1];
1711 size_t left = arg->n;
1714 struct pivot_value **values = arg->values + (arg->n - left);
1715 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1716 char escape = "%^"[tmpl_idx];
1717 size_t used = pivot_format_inner_template (
1718 out, tmpl[tmpl_idx], escape, values, left,
1719 show_values, show_variables);
1720 if (!used || used > left)
1726 ds_put_byte (out, *template++);
1730 static enum settings_value_show
1731 interpret_show (enum settings_value_show global_show,
1732 enum settings_value_show table_show,
1733 enum settings_value_show value_show,
1736 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1737 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1738 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1742 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1743 SHOW_VARIABLES control whether variable and value labels are included.
1745 The "body" omits subscripts and superscripts and footnotes. */
1747 pivot_value_format_body (const struct pivot_value *value,
1748 enum settings_value_show show_values,
1749 enum settings_value_show show_variables,
1752 enum settings_value_show show;
1753 bool numeric = false;
1755 switch (value->type)
1757 case PIVOT_VALUE_NUMERIC:
1758 show = interpret_show (settings_get_show_values (),
1760 value->numeric.show,
1761 value->numeric.value_label != NULL);
1762 if (show & SETTINGS_VALUE_SHOW_VALUE)
1764 char *s = data_out (&(union value) { .f = value->numeric.x },
1765 "UTF-8", &value->numeric.format);
1766 ds_put_cstr (out, s + strspn (s, " "));
1769 if (show & SETTINGS_VALUE_SHOW_LABEL)
1771 if (show & SETTINGS_VALUE_SHOW_VALUE)
1772 ds_put_byte (out, ' ');
1773 ds_put_cstr (out, value->numeric.value_label);
1775 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1778 case PIVOT_VALUE_STRING:
1779 show = interpret_show (settings_get_show_values (),
1782 value->string.value_label != NULL);
1783 if (show & SETTINGS_VALUE_SHOW_VALUE)
1785 if (value->string.hex)
1787 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1789 ds_put_format (out, "%02X", *p);
1792 ds_put_cstr (out, value->string.s);
1794 if (show & SETTINGS_VALUE_SHOW_LABEL)
1796 if (show & SETTINGS_VALUE_SHOW_VALUE)
1797 ds_put_byte (out, ' ');
1798 ds_put_cstr (out, value->string.value_label);
1802 case PIVOT_VALUE_VARIABLE:
1803 show = interpret_show (settings_get_show_variables (),
1805 value->variable.show,
1806 value->variable.var_label != NULL);
1807 if (show & SETTINGS_VALUE_SHOW_VALUE)
1808 ds_put_cstr (out, value->variable.var_name);
1809 if (show & SETTINGS_VALUE_SHOW_LABEL)
1811 if (show & SETTINGS_VALUE_SHOW_VALUE)
1812 ds_put_byte (out, ' ');
1813 ds_put_cstr (out, value->variable.var_label);
1817 case PIVOT_VALUE_TEXT:
1818 ds_put_cstr (out, value->text.local);
1821 case PIVOT_VALUE_TEMPLATE:
1822 pivot_format_template (out, value->template.s, value->template.args,
1823 value->template.n_args, show_values,
1831 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
1832 SHOW_VARIABLES control whether variable and value labels are included.
1834 Subscripts and superscripts and footnotes are included. */
1836 pivot_value_format (const struct pivot_value *value,
1837 enum settings_value_show show_values,
1838 enum settings_value_show show_variables,
1841 pivot_value_format_body ( value, show_values, show_variables, out);
1843 if (value->subscript)
1844 ds_put_format (out, "_%s", value->subscript);
1846 if (value->superscript)
1847 ds_put_format (out, "^%s", value->superscript);
1849 for (size_t i = 0; i < value->n_footnotes; i++)
1851 ds_put_byte (out, '^');
1852 pivot_value_format (value->footnotes[i]->marker,
1853 show_values, show_variables, out);
1857 /* Returns a text representation of VALUE. The caller must free the string,
1860 pivot_value_to_string (const struct pivot_value *value,
1861 enum settings_value_show show_values,
1862 enum settings_value_show show_variables)
1864 struct string s = DS_EMPTY_INITIALIZER;
1865 pivot_value_format (value, show_values, show_variables, &s);
1866 return ds_steal_cstr (&s);
1869 /* Frees the data owned by V. */
1871 pivot_value_destroy (struct pivot_value *value)
1875 font_style_uninit (value->font_style);
1876 free (value->font_style);
1877 free (value->cell_style);
1878 /* Do not free the elements of footnotes because VALUE does not own
1880 free (value->footnotes);
1881 free (value->subscript);
1883 switch (value->type)
1885 case PIVOT_VALUE_NUMERIC:
1886 free (value->numeric.var_name);
1887 free (value->numeric.value_label);
1890 case PIVOT_VALUE_STRING:
1891 free (value->string.s);
1892 free (value->string.var_name);
1893 free (value->string.value_label);
1896 case PIVOT_VALUE_VARIABLE:
1897 free (value->variable.var_name);
1898 free (value->variable.var_label);
1901 case PIVOT_VALUE_TEXT:
1902 free (value->text.local);
1903 if (value->text.c != value->text.local)
1904 free (value->text.c);
1905 if (value->text.id != value->text.local
1906 && value->text.id != value->text.c)
1907 free (value->text.id);
1910 case PIVOT_VALUE_TEMPLATE:
1911 free (value->template.s);
1912 for (size_t i = 0; i < value->template.n_args; i++)
1913 pivot_argument_uninit (&value->template.args[i]);
1914 free (value->template.args);
1921 /* Sets AREA to the style to use for VALUE, with defaults coming from
1922 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
1924 pivot_value_get_style (struct pivot_value *value,
1925 const struct area_style *default_style,
1926 struct area_style *area)
1928 font_style_copy (&area->font_style, (value->font_style
1930 : &default_style->font_style));
1931 area->cell_style = (value->cell_style
1932 ? *value->cell_style
1933 : default_style->cell_style);
1936 /* Copies AREA into VALUE's style. */
1938 pivot_value_set_style (struct pivot_value *value,
1939 const struct area_style *area)
1941 if (value->font_style)
1942 font_style_uninit (value->font_style);
1944 value->font_style = xmalloc (sizeof *value->font_style);
1945 font_style_copy (value->font_style, &area->font_style);
1947 if (!value->cell_style)
1948 value->cell_style = xmalloc (sizeof *value->cell_style);
1949 *value->cell_style = area->cell_style;
1952 /* Frees the data owned by ARG (but not ARG itself). */
1954 pivot_argument_uninit (struct pivot_argument *arg)
1958 for (size_t i = 0; i < arg->n; i++)
1959 pivot_value_destroy (arg->values[i]);
1964 /* Creates and returns a new pivot_value whose contents is the null-terminated
1965 string TEXT. Takes ownership of TEXT.
1967 This function is for text strings provided by the user (with the exception
1968 that pivot_value_new_variable() should be used for variable names). For
1969 strings that are part of the PSPP user interface, such as names of
1970 procedures, statistics, annotations, error messages, etc., use
1971 pivot_value_new_text(). */
1972 struct pivot_value *
1973 pivot_value_new_user_text_nocopy (char *text)
1975 struct pivot_value *value = xmalloc (sizeof *value);
1976 *value = (struct pivot_value) {
1977 .type = PIVOT_VALUE_TEXT,
1982 .user_provided = true,
1988 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
1989 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
1992 This function is for text strings provided by the user (with the exception
1993 that pivot_value_new_variable() should be used for variable names). For
1994 strings that are part of the PSPP user interface, such as names of
1995 procedures, statistics, annotations, error messages, etc., use
1996 pivot_value_new_text().j
1998 The caller retains ownership of TEXT.*/
1999 struct pivot_value *
2000 pivot_value_new_user_text (const char *text, size_t length)
2002 return pivot_value_new_user_text_nocopy (
2003 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2006 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2007 a translatable string, but not actually translated yet, e.g. enclosed in
2008 N_(). This function is for text strings that are part of the PSPP user
2009 interface, such as names of procedures, statistics, annotations, error
2010 messages, etc. For strings that come from the user, use
2011 pivot_value_new_user_text(). */
2012 struct pivot_value *
2013 pivot_value_new_text (const char *text)
2015 char *c = xstrdup (text);
2016 char *local = xstrdup (gettext (c));
2018 struct pivot_value *value = xmalloc (sizeof *value);
2019 *value = (struct pivot_value) {
2020 .type = PIVOT_VALUE_TEXT,
2025 .user_provided = false,
2031 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2033 struct pivot_value * PRINTF_FORMAT (1, 2)
2034 pivot_value_new_text_format (const char *format, ...)
2037 va_start (args, format);
2038 char *c = xvasprintf (format, args);
2041 va_start (args, format);
2042 char *local = xvasprintf (gettext (format), args);
2045 struct pivot_value *value = xmalloc (sizeof *value);
2046 *value = (struct pivot_value) {
2047 .type = PIVOT_VALUE_TEXT,
2052 .user_provided = false,
2059 xstrdup_if_nonempty (const char *s)
2061 return s && s[0] ? xstrdup (s) : NULL;
2064 /* Returns a new pivot_value that represents X.
2066 The format to use for X is unspecified. Usually the easiest way to specify
2067 a format is through assigning a result class to one of the categories that
2068 the pivot_value will end up in. If that is not suitable, then the caller
2069 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2070 struct pivot_value *
2071 pivot_value_new_number (double x)
2073 struct pivot_value *value = xmalloc (sizeof *value);
2074 *value = (struct pivot_value) {
2075 .type = PIVOT_VALUE_NUMERIC,
2076 .numeric = { .x = x, },
2081 /* Returns a new pivot_value that represents X, formatted as an integer. */
2082 struct pivot_value *
2083 pivot_value_new_integer (double x)
2085 struct pivot_value *value = pivot_value_new_number (x);
2086 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2090 /* Returns a new pivot_value that represents VALUE, formatted as for
2092 struct pivot_value *
2093 pivot_value_new_var_value (const struct variable *variable,
2094 const union value *value)
2096 struct pivot_value *pv = pivot_value_new_value (
2097 value, var_get_width (variable), var_get_print_format (variable),
2098 var_get_encoding (variable));
2100 char *var_name = xstrdup (var_get_name (variable));
2101 if (var_is_alpha (variable))
2102 pv->string.var_name = var_name;
2104 pv->numeric.var_name = var_name;
2106 const char *label = var_lookup_value_label (variable, value);
2109 if (var_is_alpha (variable))
2110 pv->string.value_label = xstrdup (label);
2112 pv->numeric.value_label = xstrdup (label);
2118 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2119 formatted with FORMAT. For a string value, ENCODING must be its character
2121 struct pivot_value *
2122 pivot_value_new_value (const union value *value, int width,
2123 const struct fmt_spec *format, const char *encoding)
2125 struct pivot_value *pv = xzalloc (sizeof *pv);
2128 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2130 size_t n = strlen (s);
2131 while (n > 0 && s[n - 1] == ' ')
2134 pv->type = PIVOT_VALUE_STRING;
2136 pv->string.hex = format->type == FMT_AHEX;
2140 pv->type = PIVOT_VALUE_NUMERIC;
2141 pv->numeric.x = value->f;
2142 pv->numeric.format = *format;
2148 /* Returns a new pivot_value for VARIABLE. */
2149 struct pivot_value *
2150 pivot_value_new_variable (const struct variable *variable)
2152 struct pivot_value *value = xmalloc (sizeof *value);
2153 *value = (struct pivot_value) {
2154 .type = PIVOT_VALUE_VARIABLE,
2156 .var_name = xstrdup (var_get_name (variable)),
2157 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2163 /* Attaches a reference to FOOTNOTE to V. */
2165 pivot_value_add_footnote (struct pivot_value *v,
2166 const struct pivot_footnote *footnote)
2168 v->footnotes = xrealloc (v->footnotes,
2169 (v->n_footnotes + 1) * sizeof *v->footnotes);
2170 v->footnotes[v->n_footnotes++] = footnote;
2173 /* If VALUE is a numeric value, and RC is a result class such as
2174 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2176 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2179 if (value->type == PIVOT_VALUE_NUMERIC)
2181 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2183 value->numeric.format = *f;