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 /* XXX extent and label_depth need to be calculated later. */
288 pivot_dimension_destroy (struct pivot_dimension *d)
293 pivot_category_destroy (d->root);
294 free (d->data_leaves);
295 free (d->presentation_leaves);
299 /* Returns the first leaf node in an in-order traversal that is a child of
301 static const struct pivot_category * UNUSED
302 pivot_category_first_leaf (const struct pivot_category *cat)
304 if (pivot_category_is_leaf (cat))
307 for (size_t i = 0; i < cat->n_subs; i++)
309 const struct pivot_category *first
310 = pivot_category_first_leaf (cat->subs[i]);
318 /* Returns the next leaf node in an in-order traversal starting at CAT, which
320 static const struct pivot_category * UNUSED
321 pivot_category_next_leaf (const struct pivot_category *cat)
323 assert (pivot_category_is_leaf (cat));
327 const struct pivot_category *parent = cat->parent;
330 for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
332 const struct pivot_category *next
333 = pivot_category_first_leaf (parent->subs[i]);
343 pivot_category_add_child (struct pivot_category *child)
345 struct pivot_category *parent = child->parent;
347 assert (pivot_category_is_group (parent));
348 if (parent->n_subs >= parent->allocated_subs)
349 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
350 sizeof *parent->subs);
351 parent->subs[parent->n_subs++] = child;
354 /* Adds leaf categories as a child of PARENT. To create top-level categories
355 within dimension 'd', pass 'd->root' for PARENT.
357 Each of the varargs parameters should be a string, each of which should be a
358 translatable category name, but not actually translated yet, e.g. enclosed
359 in N_(). Each string may optionally be followod by a PIVOT_RC_* string that
360 specifies the default numeric format for cells in this category.
362 Returns the category index, which is just a 0-based array index, for the
365 Leaves have to be created in in-order, that is, don't create a group and add
366 some leaves, then add leaves outside the group and try to add more leaves
369 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
371 int retval = parent->dimension->n_leaves;
374 va_start (args, parent);
375 pivot_category_create_leaves_valist (parent, args);
381 /* Creates a new leaf category with the given NAME as a child of PARENT. To
382 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
383 Returns the category index, which is just a 0-based array index, for the new
386 Leaves have to be created in in-order, that is, don't create a group and add
387 some leaves, then add leaves outside the group and try to add more leaves
390 pivot_category_create_leaf (struct pivot_category *parent,
391 struct pivot_value *name)
393 return pivot_category_create_leaf_rc (parent, name, NULL);
396 /* Creates a new leaf category with the given NAME as a child of PARENT. To
397 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
398 Returns the category index, which is just a 0-based array index, for the new
401 If RC is nonnull and the name of a result category, the category is assigned
402 that result category.
404 Leaves have to be created in in-order, that is, don't create a group and add
405 some leaves, then add leaves outside the group and try to add more leaves
408 pivot_category_create_leaf_rc (struct pivot_category *parent,
409 struct pivot_value *name, const char *rc)
411 struct pivot_dimension *d = parent->dimension;
413 struct pivot_category *leaf = xmalloc (sizeof *leaf);
414 *leaf = (struct pivot_category) {
418 .group_index = parent->n_subs,
419 .data_index = d->n_leaves,
420 .presentation_index = d->n_leaves,
423 if (d->n_leaves >= d->allocated_leaves)
425 d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
426 sizeof *d->data_leaves);
427 d->presentation_leaves = xrealloc (
428 d->presentation_leaves,
429 d->allocated_leaves * sizeof *d->presentation_leaves);
432 d->data_leaves[d->n_leaves] = leaf;
433 d->presentation_leaves[d->n_leaves] = leaf;
436 pivot_category_add_child (leaf);
438 /* Make sure that the new child is the last in in-order. */
439 assert (!pivot_category_next_leaf (leaf));
441 pivot_category_set_rc (leaf, rc);
443 return leaf->data_index;
446 /* Adds a new category group named NAME as a child of PARENT. To create a
447 top-level group within dimension 'd', pass 'd->root' for PARENT.
449 NAME should be a translatable name, but not actually translated yet,
450 e.g. enclosed in N_(). To use a different kind of value for a name, use
451 pivot_category_create_group__() instead.
453 The optional varargs parameters may be used to add an initial set of
454 categories to the group. Each string should be a translatable category
455 name, but not actually translated yet, e.g. enclosed in N_(). Each string
456 may optionally be followod by a PIVOT_RC_* string that specifies the default
457 numeric format for cells in this category.
459 Returns the new group. */
460 struct pivot_category * SENTINEL (0)
461 (pivot_category_create_group) (struct pivot_category *parent,
462 const char *name, ...)
464 struct pivot_category *group = pivot_category_create_group__ (
465 parent, pivot_value_new_text (name));
468 va_start (args, name);
469 pivot_category_create_leaves_valist (group, args);
475 /* Adds a new category group named NAME as a child of PARENT. To create a
476 top-level group within dimension 'd', pass 'd->root' for PARENT. Returns
478 struct pivot_category *
479 pivot_category_create_group__ (struct pivot_category *parent,
480 struct pivot_value *name)
482 struct pivot_dimension *d = parent->dimension;
484 struct pivot_category *group = xmalloc (sizeof *group);
485 *group = (struct pivot_category) {
490 .group_index = parent->n_subs,
491 .data_index = SIZE_MAX,
492 .presentation_index = SIZE_MAX,
495 pivot_category_add_child (group);
501 pivot_category_destroy (struct pivot_category *c)
506 pivot_value_destroy (c->name);
507 for (size_t i = 0; i < c->n_subs; i++)
508 pivot_category_destroy (c->subs[i]);
515 These are usually the easiest way to control the formatting of numeric data
516 in a pivot table. See pivot_dimension_create() for an explanation of their
520 const char *name; /* "RC_*". */
521 struct fmt_spec format;
524 /* Formats for most of the result classes. */
525 static struct result_class result_classes[] =
527 { PIVOT_RC_INTEGER, { FMT_F, 40, 0 } },
528 { PIVOT_RC_PERCENT, { FMT_PCT, 40, 1 } },
529 { PIVOT_RC_CORRELATION, { FMT_F, 40, 3 } },
530 { PIVOT_RC_SIGNIFICANCE, { FMT_F, 40, 3 } },
531 { PIVOT_RC_RESIDUAL, { FMT_F, 40, 2 } },
532 { PIVOT_RC_COUNT, { 0, 0, 0 } },
533 { PIVOT_RC_OTHER, { 0, 0, 0 } },
536 /* Has PIVOT_RC_COUNT been overridden by the user? */
537 static bool overridden_count_format;
539 static struct result_class *
540 pivot_result_class_find (const char *s)
542 for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
543 if (!strcmp (s, result_classes[i].name))
544 return &result_classes[i];
548 static const struct fmt_spec *
549 pivot_table_get_format (const struct pivot_table *table, const char *s)
553 else if (!strcmp (s, PIVOT_RC_OTHER))
554 return settings_get_format ();
555 else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
556 return &table->weight_format;
559 const struct result_class *rc = pivot_result_class_find (s);
560 return rc ? &rc->format : NULL;
564 /* Sets the format specification for the result class named S (which should not
565 include the RC_ prefix) to *FORMAT. Returns true if successful, false if S
566 does not name a known result class. */
568 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
570 char *s = xasprintf ("RC_%s", s_);
571 struct result_class *rc = pivot_result_class_find (s);
574 rc->format = *format;
575 if (!strcmp (s, PIVOT_RC_COUNT))
576 overridden_count_format = true;
583 /* One piece of data within a pivot table. */
586 struct hmap_node hmap_node; /* In struct pivot_table's 'cells' hmap. */
587 struct pivot_value *value;
588 unsigned int idx[]; /* One index per table dimension. */
593 /* Creates and returns a new pivot table with the given TITLE. TITLE should be
594 a text string marked for translation but not actually translated yet,
595 e.g. N_("Descriptive Statistics").
597 Operations commonly performed on the new pivot_table:
599 - If empty rows or columns should not be displayed, set ->omit_empty to
602 - Set the format to use for "count" values with pivot_table_set_weight_var()
603 or pivot_table_set_weight_format().
605 This function is a shortcut for pivot_table_create__() for the most common
606 case. Use pivot_table_create__() directly if the title should be some kind
607 of value other than an ordinary text string.
609 See the large comment at the top of pivot-table.h for general advice on
610 creating pivot tables. */
612 pivot_table_create (const char *title)
614 return pivot_table_create__ (pivot_value_new_text (title));
617 /* Creates and returns a new pivot table with the given TITLE.
619 Operations commonly performed on the new pivot_table:
621 - If empty rows or columns should not be displayed, set ->omit_empty to
624 - Set the format to use for "count" values with pivot_table_set_weight_var()
625 or pivot_table_set_weight_format().
627 See the large comment at the top of pivot-table.h for general advice on
628 creating pivot tables. */
630 pivot_table_create__ (struct pivot_value *title)
632 struct pivot_table *table = xzalloc (sizeof *table);
633 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
634 table->title = title;
636 /* Set default area styles. */
637 #define STYLE(BOLD, H, V, L, R, T, B) { \
639 .halign = TABLE_HALIGN_##H, \
640 .valign = TABLE_VALIGN_##V, \
641 .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
642 [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
646 .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
647 .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
650 static const struct area_style default_area_styles[PIVOT_N_AREAS] = {
651 [PIVOT_AREA_TITLE] = STYLE( true, CENTER, CENTER, 8,11,1,8),
652 [PIVOT_AREA_CAPTION] = STYLE(false, LEFT, TOP, 8,11,1,1),
653 [PIVOT_AREA_FOOTER] = STYLE(false, LEFT, TOP, 11, 8,2,3),
654 [PIVOT_AREA_CORNER] = STYLE(false, LEFT, BOTTOM, 8,11,1,1),
655 [PIVOT_AREA_COLUMN_LABELS] = STYLE(false, CENTER, BOTTOM, 8,11,1,3),
656 [PIVOT_AREA_ROW_LABELS] = STYLE(false, LEFT, TOP, 8,11,1,3),
657 [PIVOT_AREA_DATA] = STYLE(false, MIXED, TOP, 8,11,1,1),
658 [PIVOT_AREA_LAYERS] = STYLE(false, LEFT, BOTTOM, 8,11,1,3),
661 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
662 table->areas[i] = default_area_styles[i];
664 /* Set default border styles. */
665 static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
666 [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE,
667 [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE,
668 [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE,
669 [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE,
670 [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
671 [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK,
672 [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK,
673 [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK,
674 [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
675 [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK,
676 [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK,
677 [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
678 [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
679 [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
680 [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
681 [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
682 [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
683 [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
684 [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
686 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
687 table->borders[i] = (struct table_border_style) {
688 .stroke = default_strokes[i],
689 .color = CELL_COLOR_BLACK,
692 table->row_labels_in_corner = true;
693 hmap_init (&table->cells);
698 /* Creates and returns a new pivot table with the given TITLE and a single cell
699 with the given CONTENT. */
701 pivot_table_create_for_text (struct pivot_value *title,
702 struct pivot_value *content)
704 struct pivot_table *table = pivot_table_create__ (title);
706 struct pivot_dimension *d = pivot_dimension_create (
707 table, PIVOT_AXIS_ROW, N_("Error"));
708 d->hide_all_labels = true;
709 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
711 pivot_table_put1 (table, 0, content);
716 /* Destroys TABLE and frees everything it points to. */
718 pivot_table_destroy (struct pivot_table *table)
723 free (table->current_layer);
724 free (table->table_look);
726 for (int i = 0; i < TABLE_N_AXES; i++)
727 pivot_table_sizing_uninit (&table->sizing[i]);
729 free (table->continuation);
731 for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
732 free (table->ccs[i]);
734 free (table->command_local);
735 free (table->command_c);
736 free (table->language);
737 free (table->locale);
739 free (table->dataset);
740 free (table->datafile);
742 for (size_t i = 0; i < table->n_footnotes; i++)
743 pivot_footnote_destroy (table->footnotes[i]);
744 free (table->footnotes);
746 pivot_value_destroy (table->title);
747 pivot_value_destroy (table->subtype);
748 pivot_value_destroy (table->corner_text);
749 pivot_value_destroy (table->caption);
751 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
752 area_style_uninit (&table->areas[i]);
754 for (size_t i = 0; i < table->n_dimensions; i++)
755 pivot_dimension_destroy (table->dimensions[i]);
756 free (table->dimensions);
758 for (size_t i = 0; i < PIVOT_N_AXES; i++)
759 free (table->axes[i].dimensions);
761 struct pivot_cell *cell, *next_cell;
762 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
765 hmap_delete (&table->cells, &cell->hmap_node);
766 pivot_value_destroy (cell->value);
769 hmap_destroy (&table->cells);
774 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
775 WV, which should be the weight variable for the dictionary whose data or
776 statistics are being put into TABLE.
778 This has no effect if WV is NULL. */
780 pivot_table_set_weight_var (struct pivot_table *table,
781 const struct variable *wv)
784 pivot_table_set_weight_format (table, var_get_print_format (wv));
787 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
788 format for the dictionary whose data or statistics are being put into TABLE.
790 This has no effect if WFMT is NULL. */
792 pivot_table_set_weight_format (struct pivot_table *table,
793 const struct fmt_spec *wfmt)
796 table->weight_format = *wfmt;
799 /* Returns true if TABLE has no cells, false otherwise. */
801 pivot_table_is_empty (const struct pivot_table *table)
803 return hmap_is_empty (&table->cells);
807 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
809 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
813 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
815 for (size_t i = 0; i < n; i++)
822 static struct pivot_cell *
823 pivot_table_lookup_cell__ (const struct pivot_table *table,
824 const size_t *dindexes, unsigned int hash)
826 struct pivot_cell *cell;
827 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
829 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
834 static struct pivot_cell *
835 pivot_cell_allocate (size_t n_idx)
837 struct pivot_cell *cell UNUSED;
838 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
841 static struct pivot_cell *
842 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
844 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
845 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
848 cell = pivot_cell_allocate (table->n_dimensions);
849 for (size_t i = 0; i < table->n_dimensions; i++)
850 cell->idx[i] = dindexes[i];
852 hmap_insert (&table->cells, &cell->hmap_node, hash);
857 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
858 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
861 If VALUE is a numeric value without a specified format, this function checks
862 each of the categories designated by DINDEXES[] and takes the format from
863 the first category with a result class. If none has a result class, uses
864 the overall default numeric format. */
866 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
867 struct pivot_value *value)
869 assert (n == table->n_dimensions);
871 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
873 for (size_t i = 0; i < table->n_dimensions; i++)
875 const struct pivot_dimension *d = table->dimensions[i];
876 if (dindexes[i] < d->n_leaves)
878 const struct pivot_category *c = d->data_leaves[dindexes[i]];
881 value->numeric.format = c->format;
886 value->numeric.format = *settings_get_format ();
891 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
892 pivot_value_destroy (cell->value);
896 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
897 dimension. Takes ownership of VALUE. */
899 pivot_table_put1 (struct pivot_table *table, size_t idx1,
900 struct pivot_value *value)
902 size_t dindexes[] = { idx1 };
903 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
906 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
907 dimensions. Takes ownership of VALUE. */
909 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
910 struct pivot_value *value)
912 size_t dindexes[] = { idx1, idx2 };
913 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
916 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
917 have 3 dimensions. Takes ownership of VALUE. */
919 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
920 size_t idx3, struct pivot_value *value)
922 size_t dindexes[] = { idx1, idx2, idx3 };
923 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
926 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
927 must have 4 dimensions. Takes ownership of VALUE. */
929 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
930 size_t idx3, size_t idx4, struct pivot_value *value)
932 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
933 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
936 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
937 automatically assigned marker.
939 The footnote will only appear in output if it is referenced. Use
940 pivot_value_add_footnote() to add a reference to the footnote. */
941 struct pivot_footnote *
942 pivot_table_create_footnote (struct pivot_table *table,
943 struct pivot_value *content)
945 return pivot_table_create_footnote__ (table, table->n_footnotes,
949 static struct pivot_value *
950 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
952 char text[INT_BUFSIZE_BOUND (size_t)];
953 if (show_numeric_markers)
954 snprintf (text, sizeof text, "%d", idx + 1);
956 str_format_26adic (idx + 1, false, text, sizeof text);
957 return pivot_value_new_user_text (text, -1);
960 /* Creates or modifies a footnote in TABLE with 0-based number IDX. If MARKER
961 is nonnull, sets the footnote's marker; if CONTENT is nonnull, sets the
962 footnote's content. */
963 struct pivot_footnote *
964 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
965 struct pivot_value *marker,
966 struct pivot_value *content)
968 if (idx >= table->n_footnotes)
970 while (idx >= table->allocated_footnotes)
971 table->footnotes = x2nrealloc (table->footnotes,
972 &table->allocated_footnotes,
973 sizeof *table->footnotes);
974 while (idx >= table->n_footnotes)
976 struct pivot_footnote *f = xmalloc (sizeof *f);
977 f->idx = table->n_footnotes;
978 f->marker = pivot_make_default_footnote_marker (
979 f->idx, table->show_numeric_markers);
982 table->footnotes[table->n_footnotes++] = f;
986 struct pivot_footnote *f = table->footnotes[idx];
989 pivot_value_destroy (f->marker);
994 pivot_value_destroy (f->content);
995 f->content = content;
1000 /* Frees the data owned by F. */
1002 pivot_footnote_destroy (struct pivot_footnote *f)
1006 pivot_value_destroy (f->content);
1007 pivot_value_destroy (f->marker);
1012 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1013 indexes for each dimension in TABLE in DINDEXES[]. */
1015 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1016 const size_t *pindexes[PIVOT_N_AXES],
1017 size_t dindexes[/* table->n_dimensions */])
1019 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1021 const struct pivot_axis *axis = &table->axes[i];
1023 for (size_t j = 0; j < axis->n_dimensions; j++)
1025 const struct pivot_dimension *d = axis->dimensions[j];
1026 dindexes[d->top_index]
1027 = d->presentation_leaves[pindexes[i][j]]->data_index;
1033 pivot_table_enumerate_axis (const struct pivot_table *table,
1034 enum pivot_axis_type axis_type,
1035 const size_t *layer_indexes, bool omit_empty,
1038 const struct pivot_axis *axis = &table->axes[axis_type];
1039 if (!axis->n_dimensions)
1041 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1043 enumeration[1] = SIZE_MAX;
1048 else if (!axis->extent)
1050 size_t *enumeration = xmalloc (sizeof *enumeration);
1051 *enumeration = SIZE_MAX;
1057 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1058 axis->n_dimensions), 1),
1059 sizeof *enumeration);
1060 size_t *p = enumeration;
1061 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1063 size_t *axis_indexes;
1064 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1068 enum pivot_axis_type axis2_type
1069 = pivot_axis_type_transpose (axis_type);
1071 size_t *axis2_indexes;
1072 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1074 const size_t *pindexes[PIVOT_N_AXES];
1075 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1076 pindexes[axis_type] = axis_indexes;
1077 pindexes[axis2_type] = axis2_indexes;
1078 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1079 if (pivot_table_get (table, dindexes))
1085 free (axis2_indexes);
1088 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1089 p += axis->n_dimensions;
1093 *n = (p - enumeration) / axis->n_dimensions;
1099 static const struct pivot_cell *
1100 pivot_table_lookup_cell (const struct pivot_table *table,
1101 const size_t *dindexes)
1103 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1104 return pivot_table_lookup_cell__ (table, dindexes, hash);
1107 const struct pivot_value *
1108 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1110 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1111 return cell ? cell->value : NULL;
1114 struct pivot_value *
1115 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1117 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1119 cell->value = pivot_value_new_user_text ("", -1);
1124 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1126 if (pivot_category_is_group (category) && category->n_subs)
1127 for (size_t i = 0; i < category->n_subs; i++)
1128 distribute_extra_depth (category->subs[i], extra_depth);
1130 category->extra_depth += extra_depth;
1134 pivot_category_assign_label_depth (struct pivot_category *category,
1135 bool dimension_labels_in_corner)
1137 category->extra_depth = 0;
1139 if (pivot_category_is_group (category))
1142 for (size_t i = 0; i < category->n_subs; i++)
1144 pivot_category_assign_label_depth (category->subs[i], false);
1145 depth = MAX (depth, category->subs[i]->label_depth);
1148 for (size_t i = 0; i < category->n_subs; i++)
1150 struct pivot_category *sub = category->subs[i];
1152 size_t extra_depth = depth - sub->label_depth;
1154 distribute_extra_depth (sub, extra_depth);
1156 sub->label_depth = depth;
1159 category->show_label_in_corner = (category->show_label
1160 && dimension_labels_in_corner);
1161 category->label_depth
1162 = (category->show_label && !category->show_label_in_corner
1163 ? depth + 1 : depth);
1166 category->label_depth = 1;
1170 pivot_axis_assign_label_depth (struct pivot_table *table,
1171 enum pivot_axis_type axis_type,
1172 bool dimension_labels_in_corner)
1174 struct pivot_axis *axis = &table->axes[axis_type];
1175 bool any_label_shown_in_corner = false;
1176 axis->label_depth = 0;
1178 for (size_t i = 0; i < axis->n_dimensions; i++)
1180 struct pivot_dimension *d = axis->dimensions[i];
1181 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1182 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1183 axis->label_depth += d->label_depth;
1184 axis->extent *= d->n_leaves;
1186 if (d->root->show_label_in_corner)
1187 any_label_shown_in_corner = true;
1189 return any_label_shown_in_corner;
1193 pivot_table_assign_label_depth (struct pivot_table *table)
1195 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1196 if (pivot_axis_assign_label_depth (
1197 table, PIVOT_AXIS_ROW, (table->row_labels_in_corner
1198 && !table->corner_text))
1199 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1200 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1201 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1205 pivot_table_submit (struct pivot_table *pt)
1207 pivot_table_assign_label_depth (CONST_CAST (struct pivot_table *, pt));
1208 table_item_submit (table_item_create (pt));
1211 indent (int indentation)
1213 for (int i = 0; i < indentation * 2; i++)
1218 pivot_value_dump (const struct pivot_value *value)
1220 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1221 SETTINGS_VALUE_SHOW_DEFAULT);
1227 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1232 indent (indentation);
1233 printf ("%s: ", name);
1234 pivot_value_dump (value);
1240 pivot_table_dump_string (const char *string, const char *name, int indentation)
1244 indent (indentation);
1245 printf ("%s: %s\n", name, string);
1250 pivot_category_dump (const struct pivot_category *c, int indentation)
1252 indent (indentation);
1253 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1254 pivot_value_dump (c->name);
1257 if (pivot_category_is_leaf (c))
1258 printf ("data_index=%zu\n", c->data_index);
1261 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1264 for (size_t i = 0; i < c->n_subs; i++)
1265 pivot_category_dump (c->subs[i], indentation + 1);
1270 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1272 indent (indentation);
1273 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1274 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1276 pivot_category_dump (d->root, indentation + 1);
1280 area_style_dump (enum pivot_area area, const struct area_style *a,
1283 indent (indentation);
1284 printf ("%s: ", pivot_area_to_string (area));
1285 font_style_dump (&a->font_style);
1287 cell_style_dump (&a->cell_style);
1292 table_border_style_dump (enum pivot_border border,
1293 const struct table_border_style *b, int indentation)
1295 indent (indentation);
1296 printf ("%s: %s ", pivot_border_to_string (border),
1297 table_stroke_to_string (b->stroke));
1298 cell_color_dump (&b->color);
1303 compose_headings (const struct pivot_axis *axis,
1304 const size_t *column_enumeration,
1305 enum settings_value_show show_values,
1306 enum settings_value_show show_variables)
1308 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1311 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1312 for (size_t i = 0; i < axis->label_depth; i++)
1313 headings[i] = xcalloc (axis->extent, sizeof **headings);
1315 const size_t *indexes;
1317 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1319 int row = axis->label_depth - 1;
1320 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1322 const struct pivot_dimension *d = axis->dimensions[dim_index];
1323 if (d->hide_all_labels)
1325 for (const struct pivot_category *c
1326 = d->presentation_leaves[indexes[dim_index]];
1330 if (pivot_category_is_leaf (c) || (c->show_label
1331 && !c->show_label_in_corner))
1333 headings[row][column] = pivot_value_to_string (
1334 c->name, show_values, show_variables);
1335 if (!*headings[row][column])
1336 headings[row][column] = xstrdup ("<blank>");
1348 pivot_table_dump (const struct pivot_table *table, int indentation)
1353 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1354 if (table->decimal == '.' || table->decimal == ',')
1355 settings_set_decimal_char (table->decimal);
1357 pivot_table_dump_value (table->title, "title", indentation);
1358 pivot_table_dump_string (table->command_c, "command", indentation);
1359 pivot_table_dump_string (table->dataset, "dataset", indentation);
1360 pivot_table_dump_string (table->datafile, "datafile", indentation);
1361 pivot_table_dump_string (table->notes, "notes", indentation);
1362 pivot_table_dump_string (table->table_look, "table-look", indentation);
1365 indent (indentation);
1366 printf ("date: %s", ctime (&table->date)); /* XXX thread unsafe */
1369 indent (indentation);
1370 printf ("areas:\n");
1371 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1372 area_style_dump (area, &table->areas[area], indentation + 1);
1374 indent (indentation);
1375 printf ("borders:\n");
1376 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1377 table_border_style_dump (border, &table->borders[border], indentation + 1);
1379 for (size_t i = 0; i < table->n_dimensions; i++)
1380 pivot_dimension_dump (table->dimensions[i], indentation);
1382 /* Presentation and data indexes. */
1383 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1385 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1386 if (layer_axis->n_dimensions)
1388 indent (indentation);
1389 printf ("current layer:");
1391 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1393 const struct pivot_dimension *d = layer_axis->dimensions[i];
1394 char *name = pivot_value_to_string (d->root->name,
1396 table->show_variables);
1397 char *value = pivot_value_to_string (
1398 d->data_leaves[table->current_layer[i]]->name,
1399 table->show_values, table->show_variables);
1400 printf (" %s=%s", name, value);
1408 size_t *layer_indexes;
1409 size_t layer_iteration = 0;
1410 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1412 indent (indentation);
1413 printf ("layer %zu:", layer_iteration++);
1415 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1416 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1418 const struct pivot_dimension *d = layer_axis->dimensions[i];
1420 fputs (i == 0 ? " " : ", ", stdout);
1421 pivot_value_dump (d->root->name);
1422 fputs (" =", stdout);
1424 struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1427 for (const struct pivot_category *c
1428 = d->presentation_leaves[layer_indexes[i]];
1432 if (pivot_category_is_leaf (c) || c->show_label)
1433 names[n_names++] = c->name;
1436 for (size_t i = n_names; i-- > 0; )
1439 pivot_value_dump (names[i]);
1445 size_t *column_enumeration = pivot_table_enumerate_axis (
1446 table, PIVOT_AXIS_COLUMN, layer_indexes, table->omit_empty, NULL);
1447 size_t *row_enumeration = pivot_table_enumerate_axis (
1448 table, PIVOT_AXIS_ROW, layer_indexes, table->omit_empty, NULL);
1450 char ***column_headings = compose_headings (
1451 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1452 table->show_values, table->show_variables);
1453 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1455 indent (indentation + 1);
1456 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1459 fputs ("; ", stdout);
1460 if (column_headings[y][x])
1461 fputs (column_headings[y][x], stdout);
1466 indent (indentation + 1);
1467 printf ("-----------------------------------------------\n");
1469 char ***row_headings = compose_headings (
1470 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1471 table->show_values, table->show_variables);
1474 const size_t *pindexes[PIVOT_N_AXES]
1475 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1476 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1477 &table->axes[PIVOT_AXIS_ROW])
1479 indent (indentation + 1);
1482 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1485 fputs ("; ", stdout);
1486 if (row_headings[y][x])
1487 fputs (row_headings[y][x], stdout);
1493 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1495 &table->axes[PIVOT_AXIS_COLUMN])
1500 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1501 const struct pivot_value *value = pivot_table_get (
1504 pivot_value_dump (value);
1511 free (column_enumeration);
1512 free (row_enumeration);
1515 pivot_table_dump_value (table->caption, "caption", indentation);
1517 for (size_t i = 0; i < table->n_footnotes; i++)
1519 const struct pivot_footnote *f = table->footnotes[i];
1520 indent (indentation);
1523 pivot_value_dump (f->marker);
1525 printf ("%zu", f->idx);
1527 pivot_value_dump (f->content);
1531 settings_set_decimal_char (old_decimal);
1535 consume_int (const char *p, size_t *n)
1538 while (c_isdigit (*p))
1539 *n = *n * 10 + (*p++ - '0');
1544 pivot_format_inner_template (struct string *out, const char *template,
1546 struct pivot_value **values, size_t n_values,
1547 enum settings_value_show show_values,
1548 enum settings_value_show show_variables)
1550 size_t args_consumed = 0;
1551 while (*template && *template != ':')
1553 if (*template == '\\' && template[1])
1555 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1558 else if (*template == escape)
1561 template = consume_int (template + 1, &index);
1562 if (index >= 1 && index <= n_values)
1564 pivot_value_format (values[index - 1], show_values,
1565 show_variables, out);
1566 args_consumed = MAX (args_consumed, index);
1570 ds_put_byte (out, *template++);
1572 return args_consumed;
1576 pivot_extract_inner_template (const char *template, const char **p)
1582 if (*template == '\\' && template[1] != '\0')
1584 else if (*template == ':')
1585 return template + 1;
1586 else if (*template == '\0')
1594 pivot_format_template (struct string *out, const char *template,
1595 const struct pivot_argument *args, size_t n_args,
1596 enum settings_value_show show_values,
1597 enum settings_value_show show_variables)
1601 if (*template == '\\' && template[1] != '\0')
1603 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1606 else if (*template == '^')
1609 template = consume_int (template + 1, &index);
1610 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1611 pivot_value_format (args[index - 1].values[0],
1612 show_values, show_variables, out);
1614 else if (*template == '[')
1616 const char *tmpl[2];
1617 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1618 template = pivot_extract_inner_template (template, &tmpl[1]);
1619 template += *template == ']';
1622 template = consume_int (template, &index);
1623 if (index < 1 || index > n_args)
1626 const struct pivot_argument *arg = &args[index - 1];
1627 size_t left = arg->n;
1630 struct pivot_value **values = arg->values + (arg->n - left);
1631 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1632 char escape = "%^"[tmpl_idx];
1633 size_t used = pivot_format_inner_template (
1634 out, tmpl[tmpl_idx], escape, values, left,
1635 show_values, show_variables);
1636 if (!used || used > left)
1642 ds_put_byte (out, *template++);
1646 static enum settings_value_show
1647 interpret_show (enum settings_value_show global_show,
1648 enum settings_value_show table_show,
1649 enum settings_value_show value_show,
1652 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1653 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1654 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1658 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1659 SHOW_VARIABLES control whether variable and value labels are included.
1661 The "body" omits subscripts and superscripts and footnotes. */
1663 pivot_value_format_body (const struct pivot_value *value,
1664 enum settings_value_show show_values,
1665 enum settings_value_show show_variables,
1668 enum settings_value_show show;
1669 bool numeric = false;
1671 switch (value->type)
1673 case PIVOT_VALUE_NUMERIC:
1674 show = interpret_show (settings_get_show_values (),
1676 value->numeric.show,
1677 value->numeric.value_label != NULL);
1678 if (show & SETTINGS_VALUE_SHOW_VALUE)
1680 char *s = data_out (&(union value) { .f = value->numeric.x },
1681 "UTF-8", &value->numeric.format);
1682 ds_put_cstr (out, s + strspn (s, " "));
1685 if (show & SETTINGS_VALUE_SHOW_LABEL)
1687 if (show & SETTINGS_VALUE_SHOW_VALUE)
1688 ds_put_byte (out, ' ');
1689 ds_put_cstr (out, value->numeric.value_label);
1691 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1694 case PIVOT_VALUE_STRING:
1695 show = interpret_show (settings_get_show_values (),
1698 value->string.value_label != NULL);
1699 if (show & SETTINGS_VALUE_SHOW_VALUE)
1701 if (value->string.hex)
1703 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1705 ds_put_format (out, "%02X", *p);
1708 ds_put_cstr (out, value->string.s);
1710 if (show & SETTINGS_VALUE_SHOW_LABEL)
1712 if (show & SETTINGS_VALUE_SHOW_VALUE)
1713 ds_put_byte (out, ' ');
1714 ds_put_cstr (out, value->string.value_label);
1718 case PIVOT_VALUE_VARIABLE:
1719 show = interpret_show (settings_get_show_variables (),
1721 value->variable.show,
1722 value->variable.var_label != NULL);
1723 if (show & SETTINGS_VALUE_SHOW_VALUE)
1724 ds_put_cstr (out, value->variable.var_name);
1725 if (show & SETTINGS_VALUE_SHOW_LABEL)
1727 if (show & SETTINGS_VALUE_SHOW_VALUE)
1728 ds_put_byte (out, ' ');
1729 ds_put_cstr (out, value->variable.var_label);
1733 case PIVOT_VALUE_TEXT:
1734 ds_put_cstr (out, value->text.local);
1737 case PIVOT_VALUE_TEMPLATE:
1738 pivot_format_template (out, value->template.s, value->template.args,
1739 value->template.n_args, show_values,
1747 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
1748 SHOW_VARIABLES control whether variable and value labels are included.
1750 Subscripts and superscripts and footnotes are included. */
1752 pivot_value_format (const struct pivot_value *value,
1753 enum settings_value_show show_values,
1754 enum settings_value_show show_variables,
1757 pivot_value_format_body ( value, show_values, show_variables, out);
1759 if (value->subscript)
1760 ds_put_format (out, "_%s", value->subscript);
1762 if (value->superscript)
1763 ds_put_format (out, "^%s", value->superscript);
1765 for (size_t i = 0; i < value->n_footnotes; i++)
1767 ds_put_byte (out, '^');
1768 pivot_value_format (value->footnotes[i]->marker,
1769 show_values, show_variables, out);
1773 /* Returns a text representation of VALUE. The caller must free the string,
1776 pivot_value_to_string (const struct pivot_value *value,
1777 enum settings_value_show show_values,
1778 enum settings_value_show show_variables)
1780 struct string s = DS_EMPTY_INITIALIZER;
1781 pivot_value_format (value, show_values, show_variables, &s);
1782 return ds_steal_cstr (&s);
1785 /* Frees the data owned by V. */
1787 pivot_value_destroy (struct pivot_value *value)
1791 font_style_uninit (value->font_style);
1792 free (value->font_style);
1793 free (value->cell_style);
1794 /* Do not free the elements of footnotes because VALUE does not own
1796 free (value->footnotes);
1798 switch (value->type)
1800 case PIVOT_VALUE_NUMERIC:
1801 free (value->numeric.var_name);
1802 free (value->numeric.value_label);
1805 case PIVOT_VALUE_STRING:
1806 free (value->string.s);
1807 free (value->string.var_name);
1808 free (value->string.value_label);
1811 case PIVOT_VALUE_VARIABLE:
1812 free (value->variable.var_name);
1813 free (value->variable.var_label);
1816 case PIVOT_VALUE_TEXT:
1817 free (value->text.local);
1818 if (value->text.c != value->text.local)
1819 free (value->text.c);
1820 if (value->text.id != value->text.local
1821 && value->text.id != value->text.c)
1822 free (value->text.id);
1825 case PIVOT_VALUE_TEMPLATE:
1826 free (value->template.s);
1827 for (size_t i = 0; i < value->template.n_args; i++)
1828 pivot_argument_uninit (&value->template.args[i]);
1829 free (value->template.args);
1836 /* Sets AREA to the style to use for VALUE, with defaults coming from
1837 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
1839 pivot_value_get_style (struct pivot_value *value,
1840 const struct area_style *default_style,
1841 struct area_style *area)
1843 font_style_copy (&area->font_style, (value->font_style
1845 : &default_style->font_style));
1846 area->cell_style = (value->cell_style
1847 ? *value->cell_style
1848 : default_style->cell_style);
1851 /* Copies AREA into VALUE's style. */
1853 pivot_value_set_style (struct pivot_value *value,
1854 const struct area_style *area)
1856 if (value->font_style)
1857 font_style_uninit (value->font_style);
1859 value->font_style = xmalloc (sizeof *value->font_style);
1860 font_style_copy (value->font_style, &area->font_style);
1862 if (!value->cell_style)
1863 value->cell_style = xmalloc (sizeof *value->cell_style);
1864 *value->cell_style = area->cell_style;
1867 /* Frees the data owned by ARG (but not ARG itself). */
1869 pivot_argument_uninit (struct pivot_argument *arg)
1873 for (size_t i = 0; i < arg->n; i++)
1874 pivot_value_destroy (arg->values[i]);
1879 struct pivot_value *
1880 pivot_value_new_user_text_nocopy (char *text)
1882 struct pivot_value *value = xmalloc (sizeof *value);
1883 *value = (struct pivot_value) {
1884 .type = PIVOT_VALUE_TEXT,
1889 .user_provided = true,
1895 struct pivot_value *
1896 pivot_value_new_user_text (const char *text, size_t length)
1898 return pivot_value_new_user_text_nocopy (
1899 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
1902 /* TEXT should be a translatable string, but not actually translated yet,
1903 e.g. enclosed in N_(). */
1904 struct pivot_value *
1905 pivot_value_new_text (const char *text)
1907 char *c = xstrdup (text);
1908 char *local = xstrdup (gettext (c));
1910 struct pivot_value *value = xmalloc (sizeof *value);
1911 *value = (struct pivot_value) {
1912 .type = PIVOT_VALUE_TEXT,
1917 .user_provided = false,
1923 /* FORMAT should be a translatable string, but not actually translated yet,
1924 e.g. enclosed in N_(). */
1925 struct pivot_value * PRINTF_FORMAT (1, 2)
1926 pivot_value_new_text_format (const char *format, ...)
1929 va_start (args, format);
1930 char *c = xvasprintf (format, args);
1933 va_start (args, format);
1934 char *local = xvasprintf (gettext (format), args);
1937 struct pivot_value *value = xmalloc (sizeof *value);
1938 *value = (struct pivot_value) {
1939 .type = PIVOT_VALUE_TEXT,
1944 .user_provided = false,
1951 xstrdup_if_nonempty (const char *s)
1953 return s && s[0] ? xstrdup (s) : NULL;
1956 /* Returns a new pivot_value that represents X.
1958 The format to use for X is unspecified. Usually the easiest way to specify
1959 a format is through assigning a result class to one of the categories that
1960 the pivot_value will end up in. If that is not suitable, then the caller
1961 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
1962 struct pivot_value *
1963 pivot_value_new_number (double x)
1965 struct pivot_value *value = xmalloc (sizeof *value);
1966 *value = (struct pivot_value) {
1967 .type = PIVOT_VALUE_NUMERIC,
1968 .numeric = { .x = x, },
1973 /* Returns a new pivot_value that represents X, formatted as an integer. */
1974 struct pivot_value *
1975 pivot_value_new_integer (double x)
1977 struct pivot_value *value = pivot_value_new_number (x);
1978 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
1982 /* Returns a new pivot_value that represents VALUE, formatted as for
1984 struct pivot_value *
1985 pivot_value_new_var_value (const struct variable *variable,
1986 const union value *value)
1988 struct pivot_value *pv = pivot_value_new_value (
1989 value, var_get_width (variable), var_get_print_format (variable),
1990 var_get_encoding (variable));
1992 char *var_name = xstrdup (var_get_name (variable));
1993 if (var_is_alpha (variable))
1994 pv->string.var_name = var_name;
1996 pv->numeric.var_name = var_name;
1998 const char *label = var_lookup_value_label (variable, value);
2001 if (var_is_alpha (variable))
2002 pv->string.value_label = xstrdup (label);
2004 pv->numeric.value_label = xstrdup (label);
2010 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2011 formatted with FORMAT. For a string value, ENCODING must be its character
2013 struct pivot_value *
2014 pivot_value_new_value (const union value *value, int width,
2015 const struct fmt_spec *format, const char *encoding)
2017 struct pivot_value *pv = xzalloc (sizeof *pv);
2020 char *s = recode_string (UTF8, encoding,
2021 CHAR_CAST (char *, value_str (value, width)),
2023 size_t n = strlen (s);
2024 while (n > 0 && s[n - 1] == ' ')
2027 pv->type = PIVOT_VALUE_STRING;
2029 pv->string.hex = format->type == FMT_AHEX;
2033 pv->type = PIVOT_VALUE_NUMERIC;
2034 pv->numeric.x = value->f;
2035 pv->numeric.format = *format;
2041 /* Returns a new pivot_value for VARIABLE. */
2042 struct pivot_value *
2043 pivot_value_new_variable (const struct variable *variable)
2045 struct pivot_value *value = xmalloc (sizeof *value);
2046 *value = (struct pivot_value) {
2047 .type = PIVOT_VALUE_VARIABLE,
2049 .var_name = xstrdup (var_get_name (variable)),
2050 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2056 /* Attaches a reference to FOOTNOTE to V. */
2058 pivot_value_add_footnote (struct pivot_value *v,
2059 struct pivot_footnote *footnote)
2061 v->footnotes = xrealloc (v->footnotes,
2062 (v->n_footnotes + 1) * sizeof *v->footnotes);
2063 v->footnotes[v->n_footnotes++] = footnote;
2066 /* If VALUE is a numeric value, and RC is a result class such as
2067 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2069 pivot_value_set_rc (struct pivot_table *table, struct pivot_value *value,
2072 if (value->type == PIVOT_VALUE_NUMERIC)
2074 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2076 value->numeric.format = *f;