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**";
64 /* Returns the name of BORDER. */
66 pivot_border_to_string (enum pivot_border border)
70 case PIVOT_BORDER_TITLE:
73 case PIVOT_BORDER_OUTER_LEFT:
74 return "left outer frame";
75 case PIVOT_BORDER_OUTER_TOP:
76 return "top outer frame";
77 case PIVOT_BORDER_OUTER_RIGHT:
78 return "right outer frame";
79 case PIVOT_BORDER_OUTER_BOTTOM:
80 return "bottom outer frame";
82 case PIVOT_BORDER_INNER_LEFT:
83 return "left inner frame";
84 case PIVOT_BORDER_INNER_TOP:
85 return "top inner frame";
86 case PIVOT_BORDER_INNER_RIGHT:
87 return "right inner frame";
88 case PIVOT_BORDER_INNER_BOTTOM:
89 return "bottom inner frame";
91 case PIVOT_BORDER_DATA_LEFT:
92 return "data area left";
93 case PIVOT_BORDER_DATA_TOP:
94 return "data area top";
96 case PIVOT_BORDER_DIM_ROW_HORZ:
97 return "row label horizontal dimension border";
98 case PIVOT_BORDER_DIM_ROW_VERT:
99 return "row label vertical dimension border";
100 case PIVOT_BORDER_DIM_COL_HORZ:
101 return "column label horizontal dimension border";
102 case PIVOT_BORDER_DIM_COL_VERT:
103 return "column label vertical dimension border";
105 case PIVOT_BORDER_CAT_ROW_HORZ:
106 return "row label horizontal category border";
107 case PIVOT_BORDER_CAT_ROW_VERT:
108 return "row label vertical category border";
109 case PIVOT_BORDER_CAT_COL_HORZ:
110 return "column label horizontal category border";
111 case PIVOT_BORDER_CAT_COL_VERT:
112 return "column label vertical category border";
114 case PIVOT_N_BORDERS:
121 pivot_table_sizing_uninit (struct pivot_table_sizing *sizing)
125 free (sizing->widths);
126 free (sizing->breaks);
127 free (sizing->keeps);
133 /* Returns the name of AXIS_TYPE. */
135 pivot_axis_type_to_string (enum pivot_axis_type axis_type)
139 case PIVOT_AXIS_LAYER:
145 case PIVOT_AXIS_COLUMN:
153 static enum pivot_axis_type
154 pivot_axis_type_transpose (enum pivot_axis_type axis_type)
156 assert (axis_type == PIVOT_AXIS_ROW || axis_type == PIVOT_AXIS_COLUMN);
157 return (axis_type == PIVOT_AXIS_ROW ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW);
160 /* Implementation of PIVOT_AXIS_FOR_EACH. */
162 pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis)
166 if (axis->n_dimensions)
167 for (size_t i = 0; i < axis->n_dimensions; i++)
168 if (axis->dimensions[i]->n_leaves == 0)
171 return xcalloc (axis->n_dimensions, sizeof *indexes);
174 for (size_t i = 0; i < axis->n_dimensions; i++)
176 const struct pivot_dimension *d = axis->dimensions[i];
177 if (++indexes[i] < d->n_leaves)
190 pivot_category_set_rc (struct pivot_category *category, const char *s)
192 const struct fmt_spec *format = pivot_table_get_format (
193 category->dimension->table, s);
195 category->format = *format;
199 pivot_category_create_leaves_valist (struct pivot_category *parent,
203 while ((s = va_arg (args, const char *)))
205 if (!strncmp (s, "RC_", 3))
207 assert (parent->n_subs);
208 pivot_category_set_rc (parent->subs[parent->n_subs - 1], s);
211 pivot_category_create_leaf (parent, pivot_value_new_text (s));
215 /* Creates a new dimension with the given NAME in TABLE and returns it. The
216 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
219 NAME should be a translatable name, but not actually translated yet,
220 e.g. enclosed in N_(). To use a different kind of value for a name, use
221 pivot_dimension_create__() instead.
223 The optional varargs parameters may be used to add an initial set of
224 categories to the dimension. Each string should be a translatable category
225 name, but not actually translated yet, e.g. enclosed in N_(). Each string
226 may optionally be followod by a PIVOT_RC_* string that specifies the default
227 numeric format for cells in this category. */
228 struct pivot_dimension * SENTINEL (0)
229 (pivot_dimension_create) (struct pivot_table *table,
230 enum pivot_axis_type axis_type,
231 const char *name, ...)
233 struct pivot_dimension *d = pivot_dimension_create__ (
234 table, axis_type, pivot_value_new_text (name));
237 va_start (args, name);
238 pivot_category_create_leaves_valist (d->root, args);
244 /* Creates a new dimension with the given NAME in TABLE and returns it. The
245 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
247 struct pivot_dimension *
248 pivot_dimension_create__ (struct pivot_table *table,
249 enum pivot_axis_type axis_type,
250 struct pivot_value *name)
252 assert (pivot_table_is_empty (table));
254 struct pivot_dimension *d = xmalloc (sizeof *d);
255 *d = (struct pivot_dimension) {
257 .axis_type = axis_type,
258 .level = table->axes[axis_type].n_dimensions,
259 .top_index = table->n_dimensions,
260 .root = xmalloc (sizeof *d->root),
263 struct pivot_category *root = d->root;
264 *root = (struct pivot_category) {
269 .data_index = SIZE_MAX,
270 .presentation_index = SIZE_MAX,
273 table->dimensions = xrealloc (
274 table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions);
275 table->dimensions[table->n_dimensions++] = d;
277 struct pivot_axis *axis = &table->axes[axis_type];
278 axis->dimensions = xrealloc (
279 axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
280 axis->dimensions[axis->n_dimensions++] = d;
282 if (axis_type == PIVOT_AXIS_LAYER)
284 free (table->current_layer);
285 table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
286 sizeof *table->current_layer);
289 /* XXX extent and label_depth need to be calculated later. */
295 pivot_dimension_destroy (struct pivot_dimension *d)
300 pivot_category_destroy (d->root);
301 free (d->data_leaves);
302 free (d->presentation_leaves);
306 /* Returns the first leaf node in an in-order traversal that is a child of
308 static const struct pivot_category * UNUSED
309 pivot_category_first_leaf (const struct pivot_category *cat)
311 if (pivot_category_is_leaf (cat))
314 for (size_t i = 0; i < cat->n_subs; i++)
316 const struct pivot_category *first
317 = pivot_category_first_leaf (cat->subs[i]);
325 /* Returns the next leaf node in an in-order traversal starting at CAT, which
327 static const struct pivot_category * UNUSED
328 pivot_category_next_leaf (const struct pivot_category *cat)
330 assert (pivot_category_is_leaf (cat));
334 const struct pivot_category *parent = cat->parent;
337 for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
339 const struct pivot_category *next
340 = pivot_category_first_leaf (parent->subs[i]);
350 pivot_category_add_child (struct pivot_category *child)
352 struct pivot_category *parent = child->parent;
354 assert (pivot_category_is_group (parent));
355 if (parent->n_subs >= parent->allocated_subs)
356 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
357 sizeof *parent->subs);
358 parent->subs[parent->n_subs++] = child;
361 /* Adds leaf categories as a child of PARENT. To create top-level categories
362 within dimension 'd', pass 'd->root' for PARENT.
364 Each of the varargs parameters should be a string, each of which should be a
365 translatable category name, but not actually translated yet, e.g. enclosed
366 in N_(). Each string may optionally be followod by a PIVOT_RC_* string that
367 specifies the default numeric format for cells in this category.
369 Returns the category index, which is just a 0-based array index, for the
372 Leaves have to be created in in-order, that is, don't create a group and add
373 some leaves, then add leaves outside the group and try to add more leaves
376 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
378 int retval = parent->dimension->n_leaves;
381 va_start (args, parent);
382 pivot_category_create_leaves_valist (parent, args);
388 /* Creates a new leaf category with the given NAME as a child of PARENT. To
389 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
390 Returns the category index, which is just a 0-based array index, for the new
393 Leaves have to be created in in-order, that is, don't create a group and add
394 some leaves, then add leaves outside the group and try to add more leaves
397 pivot_category_create_leaf (struct pivot_category *parent,
398 struct pivot_value *name)
400 return pivot_category_create_leaf_rc (parent, name, NULL);
403 /* Creates a new leaf category with the given NAME as a child of PARENT. To
404 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
405 Returns the category index, which is just a 0-based array index, for the new
408 If RC is nonnull and the name of a result category, the category is assigned
409 that result category.
411 Leaves have to be created in in-order, that is, don't create a group and add
412 some leaves, then add leaves outside the group and try to add more leaves
415 pivot_category_create_leaf_rc (struct pivot_category *parent,
416 struct pivot_value *name, const char *rc)
418 struct pivot_dimension *d = parent->dimension;
420 struct pivot_category *leaf = xmalloc (sizeof *leaf);
421 *leaf = (struct pivot_category) {
425 .group_index = parent->n_subs,
426 .data_index = d->n_leaves,
427 .presentation_index = d->n_leaves,
430 if (d->n_leaves >= d->allocated_leaves)
432 d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
433 sizeof *d->data_leaves);
434 d->presentation_leaves = xrealloc (
435 d->presentation_leaves,
436 d->allocated_leaves * sizeof *d->presentation_leaves);
439 d->data_leaves[d->n_leaves] = leaf;
440 d->presentation_leaves[d->n_leaves] = leaf;
443 pivot_category_add_child (leaf);
445 /* Make sure that the new child is the last in in-order. */
446 assert (!pivot_category_next_leaf (leaf));
448 pivot_category_set_rc (leaf, rc);
450 return leaf->data_index;
453 /* Adds a new category group named NAME as a child of PARENT. To create a
454 top-level group within dimension 'd', pass 'd->root' for PARENT.
456 NAME should be a translatable name, but not actually translated yet,
457 e.g. enclosed in N_(). To use a different kind of value for a name, use
458 pivot_category_create_group__() instead.
460 The optional varargs parameters may be used to add an initial set of
461 categories to the group. Each string should be a translatable category
462 name, but not actually translated yet, e.g. enclosed in N_(). Each string
463 may optionally be followod by a PIVOT_RC_* string that specifies the default
464 numeric format for cells in this category.
466 Returns the new group. */
467 struct pivot_category * SENTINEL (0)
468 (pivot_category_create_group) (struct pivot_category *parent,
469 const char *name, ...)
471 struct pivot_category *group = pivot_category_create_group__ (
472 parent, pivot_value_new_text (name));
475 va_start (args, name);
476 pivot_category_create_leaves_valist (group, args);
482 /* Adds a new category group named NAME as a child of PARENT. To create a
483 top-level group within dimension 'd', pass 'd->root' for PARENT. Returns
485 struct pivot_category *
486 pivot_category_create_group__ (struct pivot_category *parent,
487 struct pivot_value *name)
489 struct pivot_dimension *d = parent->dimension;
491 struct pivot_category *group = xmalloc (sizeof *group);
492 *group = (struct pivot_category) {
497 .group_index = parent->n_subs,
498 .data_index = SIZE_MAX,
499 .presentation_index = SIZE_MAX,
502 pivot_category_add_child (group);
508 pivot_category_destroy (struct pivot_category *c)
513 pivot_value_destroy (c->name);
514 for (size_t i = 0; i < c->n_subs; i++)
515 pivot_category_destroy (c->subs[i]);
522 These are usually the easiest way to control the formatting of numeric data
523 in a pivot table. See pivot_dimension_create() for an explanation of their
527 const char *name; /* "RC_*". */
528 struct fmt_spec format;
531 /* Formats for most of the result classes. */
532 static struct result_class result_classes[] =
534 { PIVOT_RC_INTEGER, { FMT_F, 40, 0 } },
535 { PIVOT_RC_PERCENT, { FMT_PCT, 40, 1 } },
536 { PIVOT_RC_CORRELATION, { FMT_F, 40, 3 } },
537 { PIVOT_RC_SIGNIFICANCE, { FMT_F, 40, 3 } },
538 { PIVOT_RC_RESIDUAL, { FMT_F, 40, 2 } },
539 { PIVOT_RC_COUNT, { 0, 0, 0 } },
540 { PIVOT_RC_OTHER, { 0, 0, 0 } },
543 /* Has PIVOT_RC_COUNT been overridden by the user? */
544 static bool overridden_count_format;
546 static struct result_class *
547 pivot_result_class_find (const char *s)
549 for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
550 if (!strcmp (s, result_classes[i].name))
551 return &result_classes[i];
555 static const struct fmt_spec *
556 pivot_table_get_format (const struct pivot_table *table, const char *s)
560 else if (!strcmp (s, PIVOT_RC_OTHER))
561 return settings_get_format ();
562 else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
563 return &table->weight_format;
566 const struct result_class *rc = pivot_result_class_find (s);
567 return rc ? &rc->format : NULL;
571 /* Sets the format specification for the result class named S (which should not
572 include the RC_ prefix) to *FORMAT. Returns true if successful, false if S
573 does not name a known result class. */
575 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
577 char *s = xasprintf ("RC_%s", s_);
578 struct result_class *rc = pivot_result_class_find (s);
581 rc->format = *format;
582 if (!strcmp (s, PIVOT_RC_COUNT))
583 overridden_count_format = true;
590 /* One piece of data within a pivot table. */
593 struct hmap_node hmap_node; /* In struct pivot_table's 'cells' hmap. */
594 struct pivot_value *value;
595 unsigned int idx[]; /* One index per table dimension. */
600 /* Creates and returns a new pivot table with the given TITLE. TITLE should be
601 a text string marked for translation but not actually translated yet,
602 e.g. N_("Descriptive Statistics").
604 Operations commonly performed on the new pivot_table:
606 - If empty rows or columns should not be displayed, set ->omit_empty to
609 - Set the format to use for "count" values with pivot_table_set_weight_var()
610 or pivot_table_set_weight_format().
612 This function is a shortcut for pivot_table_create__() for the most common
613 case. Use pivot_table_create__() directly if the title should be some kind
614 of value other than an ordinary text string.
616 See the large comment at the top of pivot-table.h for general advice on
617 creating pivot tables. */
619 pivot_table_create (const char *title)
621 return pivot_table_create__ (pivot_value_new_text (title));
624 /* Creates and returns a new pivot table with the given TITLE.
626 Operations commonly performed on the new pivot_table:
628 - If empty rows or columns should not be displayed, set ->omit_empty to
631 - Set the format to use for "count" values with pivot_table_set_weight_var()
632 or pivot_table_set_weight_format().
634 See the large comment at the top of pivot-table.h for general advice on
635 creating pivot tables. */
637 pivot_table_create__ (struct pivot_value *title)
639 struct pivot_table *table = xzalloc (sizeof *table);
640 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
641 table->title = title;
643 /* Set default area styles. */
644 #define STYLE(BOLD, H, V, L, R, T, B) { \
646 .halign = TABLE_HALIGN_##H, \
647 .valign = TABLE_VALIGN_##V, \
648 .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
649 [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
653 .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
654 .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
657 static const struct area_style default_area_styles[PIVOT_N_AREAS] = {
658 [PIVOT_AREA_TITLE] = STYLE( true, CENTER, CENTER, 8,11,1,8),
659 [PIVOT_AREA_CAPTION] = STYLE(false, LEFT, TOP, 8,11,1,1),
660 [PIVOT_AREA_FOOTER] = STYLE(false, LEFT, TOP, 11, 8,2,3),
661 [PIVOT_AREA_CORNER] = STYLE(false, LEFT, BOTTOM, 8,11,1,1),
662 [PIVOT_AREA_COLUMN_LABELS] = STYLE(false, CENTER, BOTTOM, 8,11,1,3),
663 [PIVOT_AREA_ROW_LABELS] = STYLE(false, LEFT, TOP, 8,11,1,3),
664 [PIVOT_AREA_DATA] = STYLE(false, MIXED, TOP, 8,11,1,1),
665 [PIVOT_AREA_LAYERS] = STYLE(false, LEFT, BOTTOM, 8,11,1,3),
668 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
669 table->areas[i] = default_area_styles[i];
671 /* Set default border styles. */
672 static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
673 [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE,
674 [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE,
675 [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE,
676 [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE,
677 [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
678 [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK,
679 [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK,
680 [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK,
681 [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
682 [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK,
683 [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK,
684 [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
685 [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
686 [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
687 [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
688 [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
689 [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
690 [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
691 [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
693 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
694 table->borders[i] = (struct table_border_style) {
695 .stroke = default_strokes[i],
696 .color = CELL_COLOR_BLACK,
699 table->row_labels_in_corner = true;
700 hmap_init (&table->cells);
705 /* Creates and returns a new pivot table with the given TITLE and a single cell
706 with the given CONTENT.
708 This is really just for error handling. */
710 pivot_table_create_for_text (struct pivot_value *title,
711 struct pivot_value *content)
713 struct pivot_table *table = pivot_table_create__ (title);
715 struct pivot_dimension *d = pivot_dimension_create (
716 table, PIVOT_AXIS_ROW, N_("Error"));
717 d->hide_all_labels = true;
718 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
720 pivot_table_put1 (table, 0, content);
725 /* Destroys TABLE and frees everything it points to. */
727 pivot_table_destroy (struct pivot_table *table)
732 free (table->current_layer);
733 free (table->table_look);
735 for (int i = 0; i < TABLE_N_AXES; i++)
736 pivot_table_sizing_uninit (&table->sizing[i]);
738 free (table->continuation);
740 for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
741 free (table->ccs[i]);
743 free (table->command_local);
744 free (table->command_c);
745 free (table->language);
746 free (table->locale);
748 free (table->dataset);
749 free (table->datafile);
751 for (size_t i = 0; i < table->n_footnotes; i++)
752 pivot_footnote_destroy (table->footnotes[i]);
753 free (table->footnotes);
755 pivot_value_destroy (table->title);
756 pivot_value_destroy (table->subtype);
757 pivot_value_destroy (table->corner_text);
758 pivot_value_destroy (table->caption);
760 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
761 area_style_uninit (&table->areas[i]);
763 for (size_t i = 0; i < table->n_dimensions; i++)
764 pivot_dimension_destroy (table->dimensions[i]);
765 free (table->dimensions);
767 for (size_t i = 0; i < PIVOT_N_AXES; i++)
768 free (table->axes[i].dimensions);
770 struct pivot_cell *cell, *next_cell;
771 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
774 hmap_delete (&table->cells, &cell->hmap_node);
775 pivot_value_destroy (cell->value);
778 hmap_destroy (&table->cells);
783 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
784 WV, which should be the weight variable for the dictionary whose data or
785 statistics are being put into TABLE.
787 This has no effect if WV is NULL. */
789 pivot_table_set_weight_var (struct pivot_table *table,
790 const struct variable *wv)
793 pivot_table_set_weight_format (table, var_get_print_format (wv));
796 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
797 format for the dictionary whose data or statistics are being put into TABLE.
799 This has no effect if WFMT is NULL. */
801 pivot_table_set_weight_format (struct pivot_table *table,
802 const struct fmt_spec *wfmt)
805 table->weight_format = *wfmt;
808 /* Returns true if TABLE has no cells, false otherwise. */
810 pivot_table_is_empty (const struct pivot_table *table)
812 return hmap_is_empty (&table->cells);
816 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
818 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
822 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
824 for (size_t i = 0; i < n; i++)
831 static struct pivot_cell *
832 pivot_table_lookup_cell__ (const struct pivot_table *table,
833 const size_t *dindexes, unsigned int hash)
835 struct pivot_cell *cell;
836 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
838 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
843 static struct pivot_cell *
844 pivot_cell_allocate (size_t n_idx)
846 struct pivot_cell *cell UNUSED;
847 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
850 static struct pivot_cell *
851 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
853 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
854 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
857 cell = pivot_cell_allocate (table->n_dimensions);
858 for (size_t i = 0; i < table->n_dimensions; i++)
859 cell->idx[i] = dindexes[i];
861 hmap_insert (&table->cells, &cell->hmap_node, hash);
866 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
867 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
870 If VALUE is a numeric value without a specified format, this function checks
871 each of the categories designated by DINDEXES[] and takes the format from
872 the first category with a result class. If none has a result class, uses
873 the overall default numeric format. */
875 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
876 struct pivot_value *value)
878 assert (n == table->n_dimensions);
880 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
882 for (size_t i = 0; i < table->n_dimensions; i++)
884 const struct pivot_dimension *d = table->dimensions[i];
885 if (dindexes[i] < d->n_leaves)
887 const struct pivot_category *c = d->data_leaves[dindexes[i]];
890 value->numeric.format = c->format;
895 value->numeric.format = *settings_get_format ();
900 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
901 pivot_value_destroy (cell->value);
905 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
906 dimension. Takes ownership of VALUE. */
908 pivot_table_put1 (struct pivot_table *table, size_t idx1,
909 struct pivot_value *value)
911 size_t dindexes[] = { idx1 };
912 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
915 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
916 dimensions. Takes ownership of VALUE. */
918 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
919 struct pivot_value *value)
921 size_t dindexes[] = { idx1, idx2 };
922 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
925 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
926 have 3 dimensions. Takes ownership of VALUE. */
928 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
929 size_t idx3, struct pivot_value *value)
931 size_t dindexes[] = { idx1, idx2, idx3 };
932 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
935 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
936 must have 4 dimensions. Takes ownership of VALUE. */
938 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
939 size_t idx3, size_t idx4, struct pivot_value *value)
941 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
942 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
945 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
946 automatically assigned marker.
948 The footnote will only appear in output if it is referenced. Use
949 pivot_value_add_footnote() to add a reference to the footnote. */
950 struct pivot_footnote *
951 pivot_table_create_footnote (struct pivot_table *table,
952 struct pivot_value *content)
954 return pivot_table_create_footnote__ (table, table->n_footnotes,
958 static struct pivot_value *
959 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
961 char text[INT_BUFSIZE_BOUND (size_t)];
962 if (show_numeric_markers)
963 snprintf (text, sizeof text, "%d", idx + 1);
965 str_format_26adic (idx + 1, false, text, sizeof text);
966 return pivot_value_new_user_text (text, -1);
969 /* Creates or modifies a footnote in TABLE with 0-based number IDX. If MARKER
970 is nonnull, sets the footnote's marker; if CONTENT is nonnull, sets the
971 footnote's content. */
972 struct pivot_footnote *
973 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
974 struct pivot_value *marker,
975 struct pivot_value *content)
977 if (idx >= table->n_footnotes)
979 while (idx >= table->allocated_footnotes)
980 table->footnotes = x2nrealloc (table->footnotes,
981 &table->allocated_footnotes,
982 sizeof *table->footnotes);
983 while (idx >= table->n_footnotes)
985 struct pivot_footnote *f = xmalloc (sizeof *f);
986 f->idx = table->n_footnotes;
987 f->marker = pivot_make_default_footnote_marker (
988 f->idx, table->show_numeric_markers);
991 table->footnotes[table->n_footnotes++] = f;
995 struct pivot_footnote *f = table->footnotes[idx];
998 pivot_value_destroy (f->marker);
1003 pivot_value_destroy (f->content);
1004 f->content = content;
1009 /* Frees the data owned by F. */
1011 pivot_footnote_destroy (struct pivot_footnote *f)
1015 pivot_value_destroy (f->content);
1016 pivot_value_destroy (f->marker);
1021 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1022 indexes for each dimension in TABLE in DINDEXES[]. */
1024 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1025 const size_t *pindexes[PIVOT_N_AXES],
1026 size_t dindexes[/* table->n_dimensions */])
1028 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1030 const struct pivot_axis *axis = &table->axes[i];
1032 for (size_t j = 0; j < axis->n_dimensions; j++)
1034 const struct pivot_dimension *d = axis->dimensions[j];
1035 dindexes[d->top_index]
1036 = d->presentation_leaves[pindexes[i][j]]->data_index;
1042 pivot_table_enumerate_axis (const struct pivot_table *table,
1043 enum pivot_axis_type axis_type,
1044 const size_t *layer_indexes, bool omit_empty,
1047 const struct pivot_axis *axis = &table->axes[axis_type];
1048 if (!axis->n_dimensions)
1050 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1052 enumeration[1] = SIZE_MAX;
1057 else if (!axis->extent)
1059 size_t *enumeration = xmalloc (sizeof *enumeration);
1060 *enumeration = SIZE_MAX;
1066 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1067 axis->n_dimensions), 1),
1068 sizeof *enumeration);
1069 size_t *p = enumeration;
1070 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1072 size_t *axis_indexes;
1073 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1077 enum pivot_axis_type axis2_type
1078 = pivot_axis_type_transpose (axis_type);
1080 size_t *axis2_indexes;
1081 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1083 const size_t *pindexes[PIVOT_N_AXES];
1084 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1085 pindexes[axis_type] = axis_indexes;
1086 pindexes[axis2_type] = axis2_indexes;
1087 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1088 if (pivot_table_get (table, dindexes))
1094 free (axis2_indexes);
1097 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1098 p += axis->n_dimensions;
1102 *n = (p - enumeration) / axis->n_dimensions;
1108 static const struct pivot_cell *
1109 pivot_table_lookup_cell (const struct pivot_table *table,
1110 const size_t *dindexes)
1112 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1113 return pivot_table_lookup_cell__ (table, dindexes, hash);
1116 const struct pivot_value *
1117 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1119 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1120 return cell ? cell->value : NULL;
1123 struct pivot_value *
1124 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1126 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1128 cell->value = pivot_value_new_user_text ("", -1);
1133 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1135 if (pivot_category_is_group (category) && category->n_subs)
1136 for (size_t i = 0; i < category->n_subs; i++)
1137 distribute_extra_depth (category->subs[i], extra_depth);
1139 category->extra_depth += extra_depth;
1143 pivot_category_assign_label_depth (struct pivot_category *category,
1144 bool dimension_labels_in_corner)
1146 category->extra_depth = 0;
1148 if (pivot_category_is_group (category))
1151 for (size_t i = 0; i < category->n_subs; i++)
1153 pivot_category_assign_label_depth (category->subs[i], false);
1154 depth = MAX (depth, category->subs[i]->label_depth);
1157 for (size_t i = 0; i < category->n_subs; i++)
1159 struct pivot_category *sub = category->subs[i];
1161 size_t extra_depth = depth - sub->label_depth;
1163 distribute_extra_depth (sub, extra_depth);
1165 sub->label_depth = depth;
1168 category->show_label_in_corner = (category->show_label
1169 && dimension_labels_in_corner);
1170 category->label_depth
1171 = (category->show_label && !category->show_label_in_corner
1172 ? depth + 1 : depth);
1175 category->label_depth = 1;
1179 pivot_axis_assign_label_depth (struct pivot_table *table,
1180 enum pivot_axis_type axis_type,
1181 bool dimension_labels_in_corner)
1183 struct pivot_axis *axis = &table->axes[axis_type];
1184 bool any_label_shown_in_corner = false;
1185 axis->label_depth = 0;
1187 for (size_t i = 0; i < axis->n_dimensions; i++)
1189 struct pivot_dimension *d = axis->dimensions[i];
1190 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1191 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1192 axis->label_depth += d->label_depth;
1193 axis->extent *= d->n_leaves;
1195 if (d->root->show_label_in_corner)
1196 any_label_shown_in_corner = true;
1198 return any_label_shown_in_corner;
1202 pivot_table_assign_label_depth (struct pivot_table *table)
1204 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1205 if (pivot_axis_assign_label_depth (
1206 table, PIVOT_AXIS_ROW, (table->row_labels_in_corner
1207 && !table->corner_text))
1208 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1209 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1210 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1218 indent (int indentation)
1220 for (int i = 0; i < indentation * 2; i++)
1225 pivot_value_dump (const struct pivot_value *value)
1227 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1228 SETTINGS_VALUE_SHOW_DEFAULT);
1234 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1239 indent (indentation);
1240 printf ("%s: ", name);
1241 pivot_value_dump (value);
1247 pivot_table_dump_string (const char *string, const char *name, int indentation)
1251 indent (indentation);
1252 printf ("%s: %s\n", name, string);
1257 pivot_category_dump (const struct pivot_category *c, int indentation)
1259 indent (indentation);
1260 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1261 pivot_value_dump (c->name);
1264 if (pivot_category_is_leaf (c))
1265 printf ("data_index=%zu\n", c->data_index);
1268 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1271 for (size_t i = 0; i < c->n_subs; i++)
1272 pivot_category_dump (c->subs[i], indentation + 1);
1277 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1279 indent (indentation);
1280 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1281 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1283 pivot_category_dump (d->root, indentation + 1);
1287 area_style_dump (enum pivot_area area, const struct area_style *a,
1290 indent (indentation);
1291 printf ("%s: ", pivot_area_to_string (area));
1292 font_style_dump (&a->font_style);
1294 cell_style_dump (&a->cell_style);
1299 table_border_style_dump (enum pivot_border border,
1300 const struct table_border_style *b, int indentation)
1302 indent (indentation);
1303 printf ("%s: %s ", pivot_border_to_string (border),
1304 table_stroke_to_string (b->stroke));
1305 cell_color_dump (&b->color);
1310 compose_headings (const struct pivot_axis *axis,
1311 const size_t *column_enumeration,
1312 enum settings_value_show show_values,
1313 enum settings_value_show show_variables)
1315 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1318 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1319 for (size_t i = 0; i < axis->label_depth; i++)
1320 headings[i] = xcalloc (axis->extent, sizeof **headings);
1322 const size_t *indexes;
1324 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1326 int row = axis->label_depth - 1;
1327 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1329 const struct pivot_dimension *d = axis->dimensions[dim_index];
1330 if (d->hide_all_labels)
1332 for (const struct pivot_category *c
1333 = d->presentation_leaves[indexes[dim_index]];
1337 if (pivot_category_is_leaf (c) || (c->show_label
1338 && !c->show_label_in_corner))
1340 headings[row][column] = pivot_value_to_string (
1341 c->name, show_values, show_variables);
1342 if (!*headings[row][column])
1343 headings[row][column] = xstrdup ("<blank>");
1355 pivot_table_dump (const struct pivot_table *table, int indentation)
1360 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1361 if (table->decimal == '.' || table->decimal == ',')
1362 settings_set_decimal_char (table->decimal);
1364 pivot_table_dump_value (table->title, "title", indentation);
1365 pivot_table_dump_string (table->command_c, "command", indentation);
1366 pivot_table_dump_string (table->dataset, "dataset", indentation);
1367 pivot_table_dump_string (table->datafile, "datafile", indentation);
1368 pivot_table_dump_string (table->notes, "notes", indentation);
1369 pivot_table_dump_string (table->table_look, "table-look", indentation);
1372 indent (indentation);
1373 printf ("date: %s", ctime (&table->date)); /* XXX thread unsafe */
1376 indent (indentation);
1377 printf ("areas:\n");
1378 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1379 area_style_dump (area, &table->areas[area], indentation + 1);
1381 indent (indentation);
1382 printf ("borders:\n");
1383 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1384 table_border_style_dump (border, &table->borders[border], indentation + 1);
1386 for (size_t i = 0; i < table->n_dimensions; i++)
1387 pivot_dimension_dump (table->dimensions[i], indentation);
1389 /* Presentation and data indexes. */
1390 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1392 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1393 if (layer_axis->n_dimensions)
1395 indent (indentation);
1396 printf ("current layer:");
1398 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1400 const struct pivot_dimension *d = layer_axis->dimensions[i];
1401 char *name = pivot_value_to_string (d->root->name,
1403 table->show_variables);
1404 char *value = pivot_value_to_string (
1405 d->data_leaves[table->current_layer[i]]->name,
1406 table->show_values, table->show_variables);
1407 printf (" %s=%s", name, value);
1415 size_t *layer_indexes;
1416 size_t layer_iteration = 0;
1417 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1419 indent (indentation);
1420 printf ("layer %zu:", layer_iteration++);
1422 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1423 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1425 const struct pivot_dimension *d = layer_axis->dimensions[i];
1427 fputs (i == 0 ? " " : ", ", stdout);
1428 pivot_value_dump (d->root->name);
1429 fputs (" =", stdout);
1431 struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1434 for (const struct pivot_category *c
1435 = d->presentation_leaves[layer_indexes[i]];
1439 if (pivot_category_is_leaf (c) || c->show_label)
1440 names[n_names++] = c->name;
1443 for (size_t i = n_names; i-- > 0; )
1446 pivot_value_dump (names[i]);
1452 size_t *column_enumeration = pivot_table_enumerate_axis (
1453 table, PIVOT_AXIS_COLUMN, layer_indexes, table->omit_empty, NULL);
1454 size_t *row_enumeration = pivot_table_enumerate_axis (
1455 table, PIVOT_AXIS_ROW, layer_indexes, table->omit_empty, NULL);
1457 char ***column_headings = compose_headings (
1458 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1459 table->show_values, table->show_variables);
1460 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1462 indent (indentation + 1);
1463 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1466 fputs ("; ", stdout);
1467 if (column_headings[y][x])
1468 fputs (column_headings[y][x], stdout);
1473 indent (indentation + 1);
1474 printf ("-----------------------------------------------\n");
1476 char ***row_headings = compose_headings (
1477 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1478 table->show_values, table->show_variables);
1481 const size_t *pindexes[PIVOT_N_AXES]
1482 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1483 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1484 &table->axes[PIVOT_AXIS_ROW])
1486 indent (indentation + 1);
1489 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1492 fputs ("; ", stdout);
1493 if (row_headings[y][x])
1494 fputs (row_headings[y][x], stdout);
1500 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1502 &table->axes[PIVOT_AXIS_COLUMN])
1507 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1508 const struct pivot_value *value = pivot_table_get (
1511 pivot_value_dump (value);
1518 free (column_enumeration);
1519 free (row_enumeration);
1522 pivot_table_dump_value (table->caption, "caption", indentation);
1524 for (size_t i = 0; i < table->n_footnotes; i++)
1526 const struct pivot_footnote *f = table->footnotes[i];
1527 indent (indentation);
1530 pivot_value_dump (f->marker);
1532 printf ("%zu", f->idx);
1534 pivot_value_dump (f->content);
1538 settings_set_decimal_char (old_decimal);
1542 consume_int (const char *p, size_t *n)
1545 while (c_isdigit (*p))
1546 *n = *n * 10 + (*p++ - '0');
1551 pivot_format_inner_template (struct string *out, const char *template,
1553 struct pivot_value **values, size_t n_values,
1554 enum settings_value_show show_values,
1555 enum settings_value_show show_variables)
1557 size_t args_consumed = 0;
1558 while (*template && *template != ':')
1560 if (*template == '\\' && template[1])
1562 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1565 else if (*template == escape)
1568 template = consume_int (template + 1, &index);
1569 if (index >= 1 && index <= n_values)
1571 pivot_value_format (values[index - 1], show_values,
1572 show_variables, out);
1573 args_consumed = MAX (args_consumed, index);
1577 ds_put_byte (out, *template++);
1579 return args_consumed;
1583 pivot_extract_inner_template (const char *template, const char **p)
1589 if (*template == '\\' && template[1] != '\0')
1591 else if (*template == ':')
1592 return template + 1;
1593 else if (*template == '\0')
1601 pivot_format_template (struct string *out, const char *template,
1602 const struct pivot_argument *args, size_t n_args,
1603 enum settings_value_show show_values,
1604 enum settings_value_show show_variables)
1608 if (*template == '\\' && template[1] != '\0')
1610 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1613 else if (*template == '^')
1616 template = consume_int (template + 1, &index);
1617 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1618 pivot_value_format (args[index - 1].values[0],
1619 show_values, show_variables, out);
1621 else if (*template == '[')
1623 const char *tmpl[2];
1624 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1625 template = pivot_extract_inner_template (template, &tmpl[1]);
1626 template += *template == ']';
1629 template = consume_int (template, &index);
1630 if (index < 1 || index > n_args)
1633 const struct pivot_argument *arg = &args[index - 1];
1634 size_t left = arg->n;
1637 struct pivot_value **values = arg->values + (arg->n - left);
1638 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1639 char escape = "%^"[tmpl_idx];
1640 size_t used = pivot_format_inner_template (
1641 out, tmpl[tmpl_idx], escape, values, left,
1642 show_values, show_variables);
1643 if (!used || used > left)
1649 ds_put_byte (out, *template++);
1653 static enum settings_value_show
1654 interpret_show (enum settings_value_show global_show,
1655 enum settings_value_show table_show,
1656 enum settings_value_show value_show,
1659 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1660 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1661 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1665 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1666 SHOW_VARIABLES control whether variable and value labels are included.
1668 The "body" omits subscripts and superscripts and footnotes. */
1670 pivot_value_format_body (const struct pivot_value *value,
1671 enum settings_value_show show_values,
1672 enum settings_value_show show_variables,
1675 enum settings_value_show show;
1676 bool numeric = false;
1678 switch (value->type)
1680 case PIVOT_VALUE_NUMERIC:
1681 show = interpret_show (settings_get_show_values (),
1683 value->numeric.show,
1684 value->numeric.value_label != NULL);
1685 if (show & SETTINGS_VALUE_SHOW_VALUE)
1687 char *s = data_out (&(union value) { .f = value->numeric.x },
1688 "UTF-8", &value->numeric.format);
1689 ds_put_cstr (out, s + strspn (s, " "));
1692 if (show & SETTINGS_VALUE_SHOW_LABEL)
1694 if (show & SETTINGS_VALUE_SHOW_VALUE)
1695 ds_put_byte (out, ' ');
1696 ds_put_cstr (out, value->numeric.value_label);
1698 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1701 case PIVOT_VALUE_STRING:
1702 show = interpret_show (settings_get_show_values (),
1705 value->string.value_label != NULL);
1706 if (show & SETTINGS_VALUE_SHOW_VALUE)
1708 if (value->string.hex)
1710 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1712 ds_put_format (out, "%02X", *p);
1715 ds_put_cstr (out, value->string.s);
1717 if (show & SETTINGS_VALUE_SHOW_LABEL)
1719 if (show & SETTINGS_VALUE_SHOW_VALUE)
1720 ds_put_byte (out, ' ');
1721 ds_put_cstr (out, value->string.value_label);
1725 case PIVOT_VALUE_VARIABLE:
1726 show = interpret_show (settings_get_show_variables (),
1728 value->variable.show,
1729 value->variable.var_label != NULL);
1730 if (show & SETTINGS_VALUE_SHOW_VALUE)
1731 ds_put_cstr (out, value->variable.var_name);
1732 if (show & SETTINGS_VALUE_SHOW_LABEL)
1734 if (show & SETTINGS_VALUE_SHOW_VALUE)
1735 ds_put_byte (out, ' ');
1736 ds_put_cstr (out, value->variable.var_label);
1740 case PIVOT_VALUE_TEXT:
1741 ds_put_cstr (out, value->text.local);
1744 case PIVOT_VALUE_TEMPLATE:
1745 pivot_format_template (out, value->template.s, value->template.args,
1746 value->template.n_args, show_values,
1754 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
1755 SHOW_VARIABLES control whether variable and value labels are included.
1757 Subscripts and superscripts and footnotes are included. */
1759 pivot_value_format (const struct pivot_value *value,
1760 enum settings_value_show show_values,
1761 enum settings_value_show show_variables,
1764 pivot_value_format_body ( value, show_values, show_variables, out);
1766 if (value->subscript)
1767 ds_put_format (out, "_%s", value->subscript);
1769 if (value->superscript)
1770 ds_put_format (out, "^%s", value->superscript);
1772 for (size_t i = 0; i < value->n_footnotes; i++)
1774 ds_put_byte (out, '^');
1775 pivot_value_format (value->footnotes[i]->marker,
1776 show_values, show_variables, out);
1780 /* Returns a text representation of VALUE. The caller must free the string,
1783 pivot_value_to_string (const struct pivot_value *value,
1784 enum settings_value_show show_values,
1785 enum settings_value_show show_variables)
1787 struct string s = DS_EMPTY_INITIALIZER;
1788 pivot_value_format (value, show_values, show_variables, &s);
1789 return ds_steal_cstr (&s);
1792 /* Frees the data owned by V. */
1794 pivot_value_destroy (struct pivot_value *value)
1798 font_style_uninit (value->font_style);
1799 free (value->font_style);
1800 free (value->cell_style);
1801 /* Do not free the elements of footnotes because VALUE does not own
1803 free (value->footnotes);
1805 switch (value->type)
1807 case PIVOT_VALUE_NUMERIC:
1808 free (value->numeric.var_name);
1809 free (value->numeric.value_label);
1812 case PIVOT_VALUE_STRING:
1813 free (value->string.s);
1814 free (value->string.var_name);
1815 free (value->string.value_label);
1818 case PIVOT_VALUE_VARIABLE:
1819 free (value->variable.var_name);
1820 free (value->variable.var_label);
1823 case PIVOT_VALUE_TEXT:
1824 free (value->text.local);
1825 if (value->text.c != value->text.local)
1826 free (value->text.c);
1827 if (value->text.id != value->text.local
1828 && value->text.id != value->text.c)
1829 free (value->text.id);
1832 case PIVOT_VALUE_TEMPLATE:
1833 free (value->template.s);
1834 for (size_t i = 0; i < value->template.n_args; i++)
1835 pivot_argument_uninit (&value->template.args[i]);
1836 free (value->template.args);
1843 /* Sets AREA to the style to use for VALUE, with defaults coming from
1844 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
1846 pivot_value_get_style (struct pivot_value *value,
1847 const struct area_style *default_style,
1848 struct area_style *area)
1850 font_style_copy (&area->font_style, (value->font_style
1852 : &default_style->font_style));
1853 area->cell_style = (value->cell_style
1854 ? *value->cell_style
1855 : default_style->cell_style);
1858 /* Copies AREA into VALUE's style. */
1860 pivot_value_set_style (struct pivot_value *value,
1861 const struct area_style *area)
1863 if (value->font_style)
1864 font_style_uninit (value->font_style);
1866 value->font_style = xmalloc (sizeof *value->font_style);
1867 font_style_copy (value->font_style, &area->font_style);
1869 if (!value->cell_style)
1870 value->cell_style = xmalloc (sizeof *value->cell_style);
1871 *value->cell_style = area->cell_style;
1874 /* Frees the data owned by ARG (but not ARG itself). */
1876 pivot_argument_uninit (struct pivot_argument *arg)
1880 for (size_t i = 0; i < arg->n; i++)
1881 pivot_value_destroy (arg->values[i]);
1886 struct pivot_value *
1887 pivot_value_new_user_text_nocopy (char *text)
1889 struct pivot_value *value = xmalloc (sizeof *value);
1890 *value = (struct pivot_value) {
1891 .type = PIVOT_VALUE_TEXT,
1896 .user_provided = true,
1902 struct pivot_value *
1903 pivot_value_new_user_text (const char *text, size_t length)
1905 return pivot_value_new_user_text_nocopy (
1906 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
1909 /* TEXT should be a translatable string, but not actually translated yet,
1910 e.g. enclosed in N_(). */
1911 struct pivot_value *
1912 pivot_value_new_text (const char *text)
1914 char *c = xstrdup (text);
1915 char *local = xstrdup (gettext (c));
1917 struct pivot_value *value = xmalloc (sizeof *value);
1918 *value = (struct pivot_value) {
1919 .type = PIVOT_VALUE_TEXT,
1924 .user_provided = false,
1930 /* FORMAT should be a translatable string, but not actually translated yet,
1931 e.g. enclosed in N_(). */
1932 struct pivot_value * PRINTF_FORMAT (1, 2)
1933 pivot_value_new_text_format (const char *format, ...)
1936 va_start (args, format);
1937 char *c = xvasprintf (format, args);
1940 va_start (args, format);
1941 char *local = xvasprintf (gettext (format), args);
1944 struct pivot_value *value = xmalloc (sizeof *value);
1945 *value = (struct pivot_value) {
1946 .type = PIVOT_VALUE_TEXT,
1951 .user_provided = false,
1958 xstrdup_if_nonempty (const char *s)
1960 return s && s[0] ? xstrdup (s) : NULL;
1963 /* Returns a new pivot_value that represents X.
1965 The format to use for X is unspecified. Usually the easiest way to specify
1966 a format is through assigning a result class to one of the categories that
1967 the pivot_value will end up in. If that is not suitable, then the caller
1968 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
1969 struct pivot_value *
1970 pivot_value_new_number (double x)
1972 struct pivot_value *value = xmalloc (sizeof *value);
1973 *value = (struct pivot_value) {
1974 .type = PIVOT_VALUE_NUMERIC,
1975 .numeric = { .x = x, },
1980 /* Returns a new pivot_value that represents X, formatted as an integer. */
1981 struct pivot_value *
1982 pivot_value_new_integer (double x)
1984 struct pivot_value *value = pivot_value_new_number (x);
1985 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
1989 /* Returns a new pivot_value that represents VALUE, formatted as for
1991 struct pivot_value *
1992 pivot_value_new_var_value (const struct variable *variable,
1993 const union value *value)
1995 struct pivot_value *pv = pivot_value_new_value (
1996 value, var_get_width (variable), var_get_print_format (variable),
1997 var_get_encoding (variable));
1999 char *var_name = xstrdup (var_get_name (variable));
2000 if (var_is_alpha (variable))
2001 pv->string.var_name = var_name;
2003 pv->numeric.var_name = var_name;
2005 const char *label = var_lookup_value_label (variable, value);
2008 if (var_is_alpha (variable))
2009 pv->string.value_label = xstrdup (label);
2011 pv->numeric.value_label = xstrdup (label);
2017 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2018 formatted with FORMAT. For a string value, ENCODING must be its character
2020 struct pivot_value *
2021 pivot_value_new_value (const union value *value, int width,
2022 const struct fmt_spec *format, const char *encoding)
2024 struct pivot_value *pv = xzalloc (sizeof *pv);
2027 char *s = recode_string (UTF8, encoding,
2028 CHAR_CAST (char *, value_str (value, width)),
2030 size_t n = strlen (s);
2031 while (n > 0 && s[n - 1] == ' ')
2034 pv->type = PIVOT_VALUE_STRING;
2036 pv->string.hex = format->type == FMT_AHEX;
2040 pv->type = PIVOT_VALUE_NUMERIC;
2041 pv->numeric.x = value->f;
2042 pv->numeric.format = *format;
2048 /* Returns a new pivot_value for VARIABLE. */
2049 struct pivot_value *
2050 pivot_value_new_variable (const struct variable *variable)
2052 struct pivot_value *value = xmalloc (sizeof *value);
2053 *value = (struct pivot_value) {
2054 .type = PIVOT_VALUE_VARIABLE,
2056 .var_name = xstrdup (var_get_name (variable)),
2057 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2063 /* Attaches a reference to FOOTNOTE to V. */
2065 pivot_value_add_footnote (struct pivot_value *v,
2066 struct pivot_footnote *footnote)
2068 v->footnotes = xrealloc (v->footnotes,
2069 (v->n_footnotes + 1) * sizeof *v->footnotes);
2070 v->footnotes[v->n_footnotes++] = footnote;
2073 /* If VALUE is a numeric value, and RC is a result class such as
2074 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2076 pivot_value_set_rc (struct pivot_table *table, struct pivot_value *value,
2079 if (value->type == PIVOT_VALUE_NUMERIC)
2081 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2083 value->numeric.format = *f;