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);
298 /* Returns the first leaf node in an in-order traversal that is a child of
300 static const struct pivot_category * UNUSED
301 pivot_category_first_leaf (const struct pivot_category *cat)
303 if (pivot_category_is_leaf (cat))
306 for (size_t i = 0; i < cat->n_subs; i++)
308 const struct pivot_category *first
309 = pivot_category_first_leaf (cat->subs[i]);
317 /* Returns the next leaf node in an in-order traversal starting at CAT, which
319 static const struct pivot_category * UNUSED
320 pivot_category_next_leaf (const struct pivot_category *cat)
322 assert (pivot_category_is_leaf (cat));
326 const struct pivot_category *parent = cat->parent;
329 for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
331 const struct pivot_category *next
332 = pivot_category_first_leaf (parent->subs[i]);
342 pivot_category_add_child (struct pivot_category *child)
344 struct pivot_category *parent = child->parent;
346 assert (pivot_category_is_group (parent));
347 if (parent->n_subs >= parent->allocated_subs)
348 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
349 sizeof *parent->subs);
350 parent->subs[parent->n_subs++] = child;
353 /* Adds leaf categories as a child of PARENT. To create top-level categories
354 within dimension 'd', pass 'd->root' for PARENT.
356 Each of the varargs parameters should be a string, each of which should be a
357 translatable category name, but not actually translated yet, e.g. enclosed
358 in N_(). Each string may optionally be followod by a PIVOT_RC_* string that
359 specifies the default numeric format for cells in this category.
361 Returns the category index, which is just a 0-based array index, for the
364 Leaves have to be created in in-order, that is, don't create a group and add
365 some leaves, then add leaves outside the group and try to add more leaves
368 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
370 int retval = parent->dimension->n_leaves;
373 va_start (args, parent);
374 pivot_category_create_leaves_valist (parent, args);
380 /* Creates a new leaf category with the given NAME as a child of PARENT. To
381 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
382 Returns the category index, which is just a 0-based array index, for the new
385 Leaves have to be created in in-order, that is, don't create a group and add
386 some leaves, then add leaves outside the group and try to add more leaves
389 pivot_category_create_leaf (struct pivot_category *parent,
390 struct pivot_value *name)
392 return pivot_category_create_leaf_rc (parent, name, NULL);
395 /* Creates a new leaf category with the given NAME as a child of PARENT. To
396 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
397 Returns the category index, which is just a 0-based array index, for the new
400 If RC is nonnull and the name of a result category, the category is assigned
401 that result category.
403 Leaves have to be created in in-order, that is, don't create a group and add
404 some leaves, then add leaves outside the group and try to add more leaves
407 pivot_category_create_leaf_rc (struct pivot_category *parent,
408 struct pivot_value *name, const char *rc)
410 struct pivot_dimension *d = parent->dimension;
412 struct pivot_category *leaf = xmalloc (sizeof *leaf);
413 *leaf = (struct pivot_category) {
417 .group_index = parent->n_subs,
418 .data_index = d->n_leaves,
419 .presentation_index = d->n_leaves,
422 if (d->n_leaves >= d->allocated_leaves)
424 d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
425 sizeof *d->data_leaves);
426 d->presentation_leaves = xrealloc (
427 d->presentation_leaves,
428 d->allocated_leaves * sizeof *d->presentation_leaves);
431 d->data_leaves[d->n_leaves] = leaf;
432 d->presentation_leaves[d->n_leaves] = leaf;
435 pivot_category_add_child (leaf);
437 /* Make sure that the new child is the last in in-order. */
438 assert (!pivot_category_next_leaf (leaf));
440 pivot_category_set_rc (leaf, rc);
442 return leaf->data_index;
445 /* Adds a new category group named NAME as a child of PARENT. To create a
446 top-level group within dimension 'd', pass 'd->root' for PARENT.
448 NAME should be a translatable name, but not actually translated yet,
449 e.g. enclosed in N_(). To use a different kind of value for a name, use
450 pivot_category_create_group__() instead.
452 The optional varargs parameters may be used to add an initial set of
453 categories to the group. Each string should be a translatable category
454 name, but not actually translated yet, e.g. enclosed in N_(). Each string
455 may optionally be followod by a PIVOT_RC_* string that specifies the default
456 numeric format for cells in this category.
458 Returns the new group. */
459 struct pivot_category * SENTINEL (0)
460 (pivot_category_create_group) (struct pivot_category *parent,
461 const char *name, ...)
463 struct pivot_category *group = pivot_category_create_group__ (
464 parent, pivot_value_new_text (name));
467 va_start (args, name);
468 pivot_category_create_leaves_valist (group, args);
474 /* Adds a new category group named NAME as a child of PARENT. To create a
475 top-level group within dimension 'd', pass 'd->root' for PARENT. Returns
477 struct pivot_category *
478 pivot_category_create_group__ (struct pivot_category *parent,
479 struct pivot_value *name)
481 struct pivot_dimension *d = parent->dimension;
483 struct pivot_category *group = xmalloc (sizeof *group);
484 *group = (struct pivot_category) {
489 .group_index = parent->n_subs,
490 .data_index = SIZE_MAX,
491 .presentation_index = SIZE_MAX,
494 pivot_category_add_child (group);
500 pivot_category_destroy (struct pivot_category *c)
505 pivot_value_destroy (c->name);
506 for (size_t i = 0; i < c->n_subs; i++)
507 pivot_category_destroy (c->subs[i]);
513 These are usually the easiest way to control the formatting of numeric data
514 in a pivot table. See pivot_dimension_create() for an explanation of their
518 const char *name; /* "RC_*". */
519 struct fmt_spec format;
522 /* Formats for most of the result classes. */
523 static struct result_class result_classes[] =
525 { PIVOT_RC_INTEGER, { FMT_F, 40, 0 } },
526 { PIVOT_RC_PERCENT, { FMT_PCT, 40, 1 } },
527 { PIVOT_RC_CORRELATION, { FMT_F, 40, 3 } },
528 { PIVOT_RC_SIGNIFICANCE, { FMT_F, 40, 3 } },
529 { PIVOT_RC_RESIDUAL, { FMT_F, 40, 2 } },
530 { PIVOT_RC_COUNT, { 0, 0, 0 } },
531 { PIVOT_RC_OTHER, { 0, 0, 0 } },
534 /* Has PIVOT_RC_COUNT been overridden by the user? */
535 static bool overridden_count_format;
537 static struct result_class *
538 pivot_result_class_find (const char *s)
540 for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
541 if (!strcmp (s, result_classes[i].name))
542 return &result_classes[i];
546 static const struct fmt_spec *
547 pivot_table_get_format (const struct pivot_table *table, const char *s)
551 else if (!strcmp (s, PIVOT_RC_OTHER))
552 return settings_get_format ();
553 else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
554 return &table->weight_format;
557 const struct result_class *rc = pivot_result_class_find (s);
558 return rc ? &rc->format : NULL;
562 /* Sets the format specification for the result class named S (which should not
563 include the RC_ prefix) to *FORMAT. Returns true if successful, false if S
564 does not name a known result class. */
566 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
568 char *s = xasprintf ("RC_%s", s_);
569 struct result_class *rc = pivot_result_class_find (s);
572 rc->format = *format;
573 if (!strcmp (s, PIVOT_RC_COUNT))
574 overridden_count_format = true;
581 /* One piece of data within a pivot table. */
584 struct hmap_node hmap_node; /* In struct pivot_table's 'cells' hmap. */
585 struct pivot_value *value;
586 unsigned int idx[]; /* One index per table dimension. */
591 /* Creates and returns a new pivot table with the given TITLE. TITLE should be
592 a text string marked for translation but not actually translated yet,
593 e.g. N_("Descriptive Statistics").
595 Operations commonly performed on the new pivot_table:
597 - If empty rows or columns should not be displayed, set ->omit_empty to
600 - Set the format to use for "count" values with pivot_table_set_weight_var()
601 or pivot_table_set_weight_format().
603 This function is a shortcut for pivot_table_create__() for the most common
604 case. Use pivot_table_create__() directly if the title should be some kind
605 of value other than an ordinary text string.
607 See the large comment at the top of pivot-table.h for general advice on
608 creating pivot tables. */
610 pivot_table_create (const char *title)
612 return pivot_table_create__ (pivot_value_new_text (title));
615 /* Creates and returns a new pivot table with the given TITLE.
617 Operations commonly performed on the new pivot_table:
619 - If empty rows or columns should not be displayed, set ->omit_empty to
622 - Set the format to use for "count" values with pivot_table_set_weight_var()
623 or pivot_table_set_weight_format().
625 See the large comment at the top of pivot-table.h for general advice on
626 creating pivot tables. */
628 pivot_table_create__ (struct pivot_value *title)
630 struct pivot_table *table = xzalloc (sizeof *table);
631 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
632 table->title = title;
634 /* Set default area styles. */
635 #define STYLE(BOLD, H, V, L, R, T, B) { \
637 .halign = TABLE_HALIGN_##H, \
638 .valign = TABLE_VALIGN_##V, \
639 .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
640 [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
644 .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
645 .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
648 static const struct area_style default_area_styles[PIVOT_N_AREAS] = {
649 [PIVOT_AREA_TITLE] = STYLE( true, CENTER, CENTER, 8,11,1,8),
650 [PIVOT_AREA_CAPTION] = STYLE(false, LEFT, TOP, 8,11,1,1),
651 [PIVOT_AREA_FOOTER] = STYLE(false, LEFT, TOP, 11, 8,2,3),
652 [PIVOT_AREA_CORNER] = STYLE(false, LEFT, BOTTOM, 8,11,1,1),
653 [PIVOT_AREA_COLUMN_LABELS] = STYLE(false, CENTER, BOTTOM, 8,11,1,3),
654 [PIVOT_AREA_ROW_LABELS] = STYLE(false, LEFT, TOP, 8,11,1,3),
655 [PIVOT_AREA_DATA] = STYLE(false, MIXED, TOP, 8,11,1,1),
656 [PIVOT_AREA_LAYERS] = STYLE(false, LEFT, BOTTOM, 8,11,1,3),
659 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
660 table->areas[i] = default_area_styles[i];
662 /* Set default border styles. */
663 static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
664 [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE,
665 [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE,
666 [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE,
667 [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE,
668 [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
669 [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK,
670 [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK,
671 [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK,
672 [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
673 [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK,
674 [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK,
675 [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
676 [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
677 [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
678 [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
679 [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
680 [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
681 [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
682 [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
684 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
685 table->borders[i] = (struct table_border_style) {
686 .stroke = default_strokes[i],
687 .color = CELL_COLOR_BLACK,
690 table->row_labels_in_corner = true;
691 hmap_init (&table->cells);
696 /* Creates and returns a new pivot table with the given TITLE and a single cell
697 with the given CONTENT.
699 This is really just for error handling. */
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);
1209 indent (int indentation)
1211 for (int i = 0; i < indentation * 2; i++)
1216 pivot_value_dump (const struct pivot_value *value)
1218 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1219 SETTINGS_VALUE_SHOW_DEFAULT);
1225 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1230 indent (indentation);
1231 printf ("%s: ", name);
1232 pivot_value_dump (value);
1238 pivot_table_dump_string (const char *string, const char *name, int indentation)
1242 indent (indentation);
1243 printf ("%s: %s\n", name, string);
1248 pivot_category_dump (const struct pivot_category *c, int indentation)
1250 indent (indentation);
1251 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1252 pivot_value_dump (c->name);
1255 if (pivot_category_is_leaf (c))
1256 printf ("data_index=%zu\n", c->data_index);
1259 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1262 for (size_t i = 0; i < c->n_subs; i++)
1263 pivot_category_dump (c->subs[i], indentation + 1);
1268 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1270 indent (indentation);
1271 printf ("%s dimension %zu (where 0=innermost), label_depth=%zu:\n",
1272 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1274 pivot_category_dump (d->root, indentation + 1);
1278 area_style_dump (enum pivot_area area, const struct area_style *a,
1281 indent (indentation);
1282 printf ("%s: ", pivot_area_to_string (area));
1283 font_style_dump (&a->font_style);
1285 cell_style_dump (&a->cell_style);
1290 table_border_style_dump (enum pivot_border border,
1291 const struct table_border_style *b, int indentation)
1293 indent (indentation);
1294 printf ("%s: %s ", pivot_border_to_string (border),
1295 table_stroke_to_string (b->stroke));
1296 cell_color_dump (&b->color);
1301 compose_headings (const struct pivot_axis *axis,
1302 const size_t *column_enumeration,
1303 enum settings_value_show show_values,
1304 enum settings_value_show show_variables)
1306 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1309 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1310 for (size_t i = 0; i < axis->label_depth; i++)
1311 headings[i] = xcalloc (axis->extent, sizeof **headings);
1313 const size_t *indexes;
1315 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1317 int row = axis->label_depth - 1;
1318 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1320 const struct pivot_dimension *d = axis->dimensions[dim_index];
1321 if (d->hide_all_labels)
1323 for (const struct pivot_category *c
1324 = d->presentation_leaves[indexes[dim_index]];
1328 if (pivot_category_is_leaf (c) || (c->show_label
1329 && !c->show_label_in_corner))
1331 headings[row][column] = pivot_value_to_string (
1332 c->name, show_values, show_variables);
1333 if (!*headings[row][column])
1334 headings[row][column] = xstrdup ("<blank>");
1346 pivot_table_dump (const struct pivot_table *table, int indentation)
1351 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1352 if (table->decimal == '.' || table->decimal == ',')
1353 settings_set_decimal_char (table->decimal);
1355 pivot_table_dump_value (table->title, "title", indentation);
1356 pivot_table_dump_string (table->command_c, "command", indentation);
1357 pivot_table_dump_string (table->dataset, "dataset", indentation);
1358 pivot_table_dump_string (table->datafile, "datafile", indentation);
1359 pivot_table_dump_string (table->notes, "notes", indentation);
1360 pivot_table_dump_string (table->table_look, "table-look", indentation);
1363 indent (indentation);
1364 printf ("date: %s", ctime (&table->date)); /* XXX thread unsafe */
1367 indent (indentation);
1368 printf ("areas:\n");
1369 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1370 area_style_dump (area, &table->areas[area], indentation + 1);
1372 indent (indentation);
1373 printf ("borders:\n");
1374 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1375 table_border_style_dump (border, &table->borders[border], indentation + 1);
1377 for (size_t i = 0; i < table->n_dimensions; i++)
1378 pivot_dimension_dump (table->dimensions[i], indentation);
1380 /* Presentation and data indexes. */
1381 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1383 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1384 if (layer_axis->n_dimensions)
1386 indent (indentation);
1387 printf ("current layer:");
1389 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1391 const struct pivot_dimension *d = layer_axis->dimensions[i];
1392 char *name = pivot_value_to_string (d->root->name,
1394 table->show_variables);
1395 char *value = pivot_value_to_string (
1396 d->data_leaves[table->current_layer[i]]->name,
1397 table->show_values, table->show_variables);
1398 printf (" %s=%s", name, value);
1406 size_t *layer_indexes;
1407 size_t layer_iteration = 0;
1408 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1410 indent (indentation);
1411 printf ("layer %zu:", layer_iteration++);
1413 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1414 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1416 const struct pivot_dimension *d = layer_axis->dimensions[i];
1418 fputs (i == 0 ? " " : ", ", stdout);
1419 pivot_value_dump (d->root->name);
1420 fputs (" =", stdout);
1422 struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1425 for (const struct pivot_category *c
1426 = d->presentation_leaves[layer_indexes[i]];
1430 if (pivot_category_is_leaf (c) || c->show_label)
1431 names[n_names++] = c->name;
1434 for (size_t i = n_names; i-- > 0; )
1437 pivot_value_dump (names[i]);
1443 size_t *column_enumeration = pivot_table_enumerate_axis (
1444 table, PIVOT_AXIS_COLUMN, layer_indexes, table->omit_empty, NULL);
1445 size_t *row_enumeration = pivot_table_enumerate_axis (
1446 table, PIVOT_AXIS_ROW, layer_indexes, table->omit_empty, NULL);
1448 char ***column_headings = compose_headings (
1449 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1450 table->show_values, table->show_variables);
1451 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1453 indent (indentation + 1);
1454 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1457 fputs ("; ", stdout);
1458 if (column_headings[y][x])
1459 fputs (column_headings[y][x], stdout);
1464 indent (indentation + 1);
1465 printf ("-----------------------------------------------\n");
1467 char ***row_headings = compose_headings (
1468 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1469 table->show_values, table->show_variables);
1472 const size_t *pindexes[PIVOT_N_AXES]
1473 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1474 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1475 &table->axes[PIVOT_AXIS_ROW])
1477 indent (indentation + 1);
1480 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1483 fputs ("; ", stdout);
1484 if (row_headings[y][x])
1485 fputs (row_headings[y][x], stdout);
1491 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1493 &table->axes[PIVOT_AXIS_COLUMN])
1498 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1499 const struct pivot_value *value = pivot_table_get (
1502 pivot_value_dump (value);
1509 free (column_enumeration);
1510 free (row_enumeration);
1513 pivot_table_dump_value (table->caption, "caption", indentation);
1515 for (size_t i = 0; i < table->n_footnotes; i++)
1517 const struct pivot_footnote *f = table->footnotes[i];
1518 indent (indentation);
1521 pivot_value_dump (f->marker);
1523 printf ("%d", f->idx);
1525 pivot_value_dump (f->content);
1529 settings_set_decimal_char (old_decimal);
1533 consume_int (const char *p, size_t *n)
1536 while (c_isdigit (*p))
1537 *n = *n * 10 + (*p++ - '0');
1542 pivot_format_inner_template (struct string *out, const char *template,
1544 struct pivot_value **values, size_t n_values,
1545 enum settings_value_show show_values,
1546 enum settings_value_show show_variables)
1548 size_t args_consumed = 0;
1549 while (*template && *template != ':')
1551 if (*template == '\\' && template[1])
1553 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1556 else if (*template == escape)
1559 template = consume_int (template + 1, &index);
1560 if (index >= 1 && index <= n_values)
1562 pivot_value_format (values[index - 1], show_values,
1563 show_variables, out);
1564 args_consumed = MAX (args_consumed, index);
1568 ds_put_byte (out, *template++);
1570 return args_consumed;
1574 pivot_extract_inner_template (const char *template, const char **p)
1580 if (*template == '\\' && template[1] != '\0')
1582 else if (*template == ':')
1583 return template + 1;
1584 else if (*template == '\0')
1592 pivot_format_template (struct string *out, const char *template,
1593 const struct pivot_argument *args, size_t n_args,
1594 enum settings_value_show show_values,
1595 enum settings_value_show show_variables)
1599 if (*template == '\\' && template[1] != '\0')
1601 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1604 else if (*template == '^')
1607 template = consume_int (template + 1, &index);
1608 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1609 pivot_value_format (args[index - 1].values[0],
1610 show_values, show_variables, out);
1612 else if (*template == '[')
1614 const char *tmpl[2];
1615 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1616 template = pivot_extract_inner_template (template, &tmpl[1]);
1617 template += *template == ']';
1620 template = consume_int (template, &index);
1621 if (index < 1 || index > n_args)
1624 const struct pivot_argument *arg = &args[index - 1];
1625 size_t left = arg->n;
1628 struct pivot_value **values = arg->values + (arg->n - left);
1629 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1630 char escape = "%^"[tmpl_idx];
1631 size_t used = pivot_format_inner_template (
1632 out, tmpl[tmpl_idx], escape, values, left,
1633 show_values, show_variables);
1634 if (!used || used > left)
1640 ds_put_byte (out, *template++);
1644 static enum settings_value_show
1645 interpret_show (enum settings_value_show global_show,
1646 enum settings_value_show table_show,
1647 enum settings_value_show value_show,
1650 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1651 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1652 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1656 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1657 SHOW_VARIABLES control whether variable and value labels are included.
1659 The "body" omits subscripts and superscripts and footnotes. */
1661 pivot_value_format_body (const struct pivot_value *value,
1662 enum settings_value_show show_values,
1663 enum settings_value_show show_variables,
1666 enum settings_value_show show;
1667 bool numeric = false;
1669 switch (value->type)
1671 case PIVOT_VALUE_NUMERIC:
1672 show = interpret_show (settings_get_show_values (),
1674 value->numeric.show,
1675 value->numeric.value_label != NULL);
1676 if (show & SETTINGS_VALUE_SHOW_VALUE)
1678 char *s = data_out (&(union value) { .f = value->numeric.x },
1679 "UTF-8", &value->numeric.format);
1680 ds_put_cstr (out, s + strspn (s, " "));
1683 if (show & SETTINGS_VALUE_SHOW_LABEL)
1685 if (show & SETTINGS_VALUE_SHOW_VALUE)
1686 ds_put_byte (out, ' ');
1687 ds_put_cstr (out, value->numeric.value_label);
1689 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1692 case PIVOT_VALUE_STRING:
1693 show = interpret_show (settings_get_show_values (),
1696 value->string.value_label != NULL);
1697 if (show & SETTINGS_VALUE_SHOW_VALUE)
1699 if (value->string.hex)
1701 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1703 ds_put_format (out, "%02X", *p);
1706 ds_put_cstr (out, value->string.s);
1708 if (show & SETTINGS_VALUE_SHOW_LABEL)
1710 if (show & SETTINGS_VALUE_SHOW_VALUE)
1711 ds_put_byte (out, ' ');
1712 ds_put_cstr (out, value->string.value_label);
1716 case PIVOT_VALUE_VARIABLE:
1717 show = interpret_show (settings_get_show_variables (),
1719 value->variable.show,
1720 value->variable.var_label != NULL);
1721 if (show & SETTINGS_VALUE_SHOW_VALUE)
1722 ds_put_cstr (out, value->variable.var_name);
1723 if (show & SETTINGS_VALUE_SHOW_LABEL)
1725 if (show & SETTINGS_VALUE_SHOW_VALUE)
1726 ds_put_byte (out, ' ');
1727 ds_put_cstr (out, value->variable.var_label);
1731 case PIVOT_VALUE_TEXT:
1732 ds_put_cstr (out, value->text.local);
1735 case PIVOT_VALUE_TEMPLATE:
1736 pivot_format_template (out, value->template.s, value->template.args,
1737 value->template.n_args, show_values,
1745 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
1746 SHOW_VARIABLES control whether variable and value labels are included.
1748 Subscripts and superscripts and footnotes are included. */
1750 pivot_value_format (const struct pivot_value *value,
1751 enum settings_value_show show_values,
1752 enum settings_value_show show_variables,
1755 pivot_value_format_body ( value, show_values, show_variables, out);
1757 if (value->subscript)
1758 ds_put_format (out, "_%s", value->subscript);
1760 if (value->superscript)
1761 ds_put_format (out, "^%s", value->superscript);
1763 for (size_t i = 0; i < value->n_footnotes; i++)
1765 ds_put_byte (out, '^');
1766 pivot_value_format (value->footnotes[i]->marker,
1767 show_values, show_variables, out);
1771 /* Returns a text representation of VALUE. The caller must free the string,
1774 pivot_value_to_string (const struct pivot_value *value,
1775 enum settings_value_show show_values,
1776 enum settings_value_show show_variables)
1778 struct string s = DS_EMPTY_INITIALIZER;
1779 pivot_value_format (value, show_values, show_variables, &s);
1780 return ds_steal_cstr (&s);
1783 /* Frees the data owned by V. */
1785 pivot_value_destroy (struct pivot_value *value)
1789 font_style_uninit (value->font_style);
1790 free (value->font_style);
1791 free (value->cell_style);
1792 for (size_t i = 0; i < value->n_footnotes; i++)
1793 pivot_footnote_destroy (value->footnotes[i]);
1794 free (value->footnotes);
1796 switch (value->type)
1798 case PIVOT_VALUE_NUMERIC:
1799 free (value->numeric.var_name);
1800 free (value->numeric.value_label);
1803 case SETTINGS_VALUE_SHOW_VALUE:
1804 free (value->string.var_name);
1805 free (value->string.value_label);
1808 case PIVOT_VALUE_VARIABLE:
1809 free (value->variable.var_name);
1810 free (value->variable.var_label);
1813 case PIVOT_VALUE_TEXT:
1814 free (value->text.local);
1815 if (value->text.c != value->text.local)
1816 free (value->text.c);
1817 if (value->text.id != value->text.local
1818 && value->text.id != value->text.c)
1819 free (value->text.id);
1822 case PIVOT_VALUE_TEMPLATE:
1823 free (value->template.s);
1824 for (size_t i = 0; i < value->template.n_args; i++)
1825 pivot_argument_uninit (&value->template.args[i]);
1826 free (value->template.args);
1833 /* Sets AREA to the style to use for VALUE, with defaults coming from
1834 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
1836 pivot_value_get_style (struct pivot_value *value,
1837 const struct area_style *default_style,
1838 struct area_style *area)
1840 font_style_copy (&area->font_style, (value->font_style
1842 : &default_style->font_style));
1843 area->cell_style = (value->cell_style
1844 ? *value->cell_style
1845 : default_style->cell_style);
1848 /* Copies AREA into VALUE's style. */
1850 pivot_value_set_style (struct pivot_value *value,
1851 const struct area_style *area)
1853 if (value->font_style)
1854 font_style_uninit (value->font_style);
1856 value->font_style = xmalloc (sizeof *value->font_style);
1857 font_style_copy (value->font_style, &area->font_style);
1859 if (!value->cell_style)
1860 value->cell_style = xmalloc (sizeof *value->cell_style);
1861 *value->cell_style = area->cell_style;
1864 /* Frees the data owned by ARG (but not ARG itself). */
1866 pivot_argument_uninit (struct pivot_argument *arg)
1870 for (size_t i = 0; i < arg->n; i++)
1871 pivot_value_destroy (arg->values[i]);
1876 struct pivot_value *
1877 pivot_value_new_user_text_nocopy (char *text)
1879 struct pivot_value *value = xmalloc (sizeof *value);
1880 *value = (struct pivot_value) {
1881 .type = PIVOT_VALUE_TEXT,
1886 .user_provided = true,
1892 struct pivot_value *
1893 pivot_value_new_user_text (const char *text, size_t length)
1895 return pivot_value_new_user_text_nocopy (
1896 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
1899 /* TEXT should be a translatable string, but not actually translated yet,
1900 e.g. enclosed in N_(). */
1901 struct pivot_value *
1902 pivot_value_new_text (const char *text)
1904 char *c = xstrdup (text);
1905 char *local = xstrdup (gettext (c));
1907 struct pivot_value *value = xmalloc (sizeof *value);
1908 *value = (struct pivot_value) {
1909 .type = PIVOT_VALUE_TEXT,
1914 .user_provided = false,
1920 /* FORMAT should be a translatable string, but not actually translated yet,
1921 e.g. enclosed in N_(). */
1922 struct pivot_value * PRINTF_FORMAT (1, 2)
1923 pivot_value_new_text_format (const char *format, ...)
1926 va_start (args, format);
1927 char *c = xvasprintf (format, args);
1930 va_start (args, format);
1931 char *local = xvasprintf (gettext (format), args);
1934 struct pivot_value *value = xmalloc (sizeof *value);
1935 *value = (struct pivot_value) {
1936 .type = PIVOT_VALUE_TEXT,
1941 .user_provided = false,
1948 xstrdup_if_nonempty (const char *s)
1950 return s && s[0] ? xstrdup (s) : NULL;
1953 /* Returns a new pivot_value that represents X.
1955 The format to use for X is unspecified. Usually the easiest way to specify
1956 a format is through assigning a result class to one of the categories that
1957 the pivot_value will end up in. If that is not suitable, then the caller
1958 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
1959 struct pivot_value *
1960 pivot_value_new_number (double x)
1962 struct pivot_value *value = xmalloc (sizeof *value);
1963 *value = (struct pivot_value) {
1964 .type = PIVOT_VALUE_NUMERIC,
1965 .numeric = { .x = x, },
1970 /* Returns a new pivot_value that represents X, formatted as an integer. */
1971 struct pivot_value *
1972 pivot_value_new_integer (double x)
1974 struct pivot_value *value = pivot_value_new_number (x);
1975 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
1979 /* Returns a new pivot_value that represents VALUE, formatted as for
1981 struct pivot_value *
1982 pivot_value_new_var_value (const struct variable *variable,
1983 const union value *value)
1985 struct pivot_value *pv = pivot_value_new_value (
1986 value, var_get_width (variable), var_get_print_format (variable),
1987 var_get_encoding (variable));
1989 char *var_name = xstrdup (var_get_name (variable));
1990 if (var_is_alpha (variable))
1991 pv->string.var_name = var_name;
1993 pv->numeric.var_name = var_name;
1995 const char *label = var_lookup_value_label (variable, value);
1998 if (var_is_alpha (variable))
1999 pv->string.value_label = xstrdup (label);
2001 pv->numeric.value_label = xstrdup (label);
2007 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2008 formatted with FORMAT. For a string value, ENCODING must be its character
2010 struct pivot_value *
2011 pivot_value_new_value (const union value *value, int width,
2012 const struct fmt_spec *format, const char *encoding)
2014 struct pivot_value *pv = xzalloc (sizeof *pv);
2017 char *s = recode_string (UTF8, encoding,
2018 CHAR_CAST (char *, value_str (value, width)),
2020 size_t n = strlen (s);
2021 while (n > 0 && s[n - 1] == ' ')
2024 pv->type = PIVOT_VALUE_STRING;
2026 pv->string.hex = format->type == FMT_AHEX;
2030 pv->type = PIVOT_VALUE_NUMERIC;
2031 pv->numeric.x = value->f;
2032 pv->numeric.format = *format;
2038 /* Returns a new pivot_value for VARIABLE. */
2039 struct pivot_value *
2040 pivot_value_new_variable (const struct variable *variable)
2042 struct pivot_value *value = xmalloc (sizeof *value);
2043 *value = (struct pivot_value) {
2044 .type = PIVOT_VALUE_VARIABLE,
2046 .var_name = xstrdup (var_get_name (variable)),
2047 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2053 /* Attaches a reference to FOOTNOTE to V. */
2055 pivot_value_add_footnote (struct pivot_value *v,
2056 struct pivot_footnote *footnote)
2058 v->footnotes = xrealloc (v->footnotes,
2059 (v->n_footnotes + 1) * sizeof *v->footnotes);
2060 v->footnotes[v->n_footnotes++] = footnote;
2063 /* If VALUE is a numeric value, and RC is a result class such as
2064 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2066 pivot_value_set_rc (struct pivot_table *table, struct pivot_value *value,
2069 if (value->type == PIVOT_VALUE_NUMERIC)
2071 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2073 value->numeric.format = *f;