1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2017, 2018 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "output/pivot-table.h"
23 #include "data/data-out.h"
24 #include "data/settings.h"
25 #include "data/value.h"
26 #include "data/variable.h"
27 #include "libpspp/hash-functions.h"
28 #include "libpspp/i18n.h"
30 #include "gl/c-ctype.h"
31 #include "gl/intprops.h"
32 #include "gl/minmax.h"
33 #include "gl/xalloc.h"
34 #include "gl/xmemdup0.h"
38 #define _(msgid) gettext (msgid)
39 #define N_(msgid) msgid
41 static const struct fmt_spec *pivot_table_get_format (
42 const struct pivot_table *, const char *s);
44 /* Pivot table display styling. */
46 /* Returns the name of AREA. */
48 pivot_area_to_string (enum pivot_area area)
52 case PIVOT_AREA_TITLE: return "title";
53 case PIVOT_AREA_CAPTION: return "caption";
54 case PIVOT_AREA_FOOTER: return "footer";
55 case PIVOT_AREA_CORNER: return "corner";
56 case PIVOT_AREA_COLUMN_LABELS: return "column labels";
57 case PIVOT_AREA_ROW_LABELS: return "row labels";
58 case PIVOT_AREA_DATA: return "data";
59 case PIVOT_AREA_LAYERS: return "layers";
60 case PIVOT_N_AREAS: default: return "**error**";
64 /* Returns the name of BORDER. */
66 pivot_border_to_string (enum pivot_border border)
70 case PIVOT_BORDER_TITLE:
73 case PIVOT_BORDER_OUTER_LEFT:
74 return "left outer frame";
75 case PIVOT_BORDER_OUTER_TOP:
76 return "top outer frame";
77 case PIVOT_BORDER_OUTER_RIGHT:
78 return "right outer frame";
79 case PIVOT_BORDER_OUTER_BOTTOM:
80 return "bottom outer frame";
82 case PIVOT_BORDER_INNER_LEFT:
83 return "left inner frame";
84 case PIVOT_BORDER_INNER_TOP:
85 return "top inner frame";
86 case PIVOT_BORDER_INNER_RIGHT:
87 return "right inner frame";
88 case PIVOT_BORDER_INNER_BOTTOM:
89 return "bottom inner frame";
91 case PIVOT_BORDER_DATA_LEFT:
92 return "data area left";
93 case PIVOT_BORDER_DATA_TOP:
94 return "data area top";
96 case PIVOT_BORDER_DIM_ROW_HORZ:
97 return "row label horizontal dimension border";
98 case PIVOT_BORDER_DIM_ROW_VERT:
99 return "row label vertical dimension border";
100 case PIVOT_BORDER_DIM_COL_HORZ:
101 return "column label horizontal dimension border";
102 case PIVOT_BORDER_DIM_COL_VERT:
103 return "column label vertical dimension border";
105 case PIVOT_BORDER_CAT_ROW_HORZ:
106 return "row label horizontal category border";
107 case PIVOT_BORDER_CAT_ROW_VERT:
108 return "row label vertical category border";
109 case PIVOT_BORDER_CAT_COL_HORZ:
110 return "column label horizontal category border";
111 case PIVOT_BORDER_CAT_COL_VERT:
112 return "column label vertical category border";
114 case PIVOT_N_BORDERS:
121 pivot_table_sizing_uninit (struct pivot_table_sizing *sizing)
125 free (sizing->widths);
126 free (sizing->breaks);
127 free (sizing->keeps);
133 /* Returns the name of AXIS_TYPE. */
135 pivot_axis_type_to_string (enum pivot_axis_type axis_type)
139 case PIVOT_AXIS_LAYER:
145 case PIVOT_AXIS_COLUMN:
153 static enum pivot_axis_type
154 pivot_axis_type_transpose (enum pivot_axis_type axis_type)
156 assert (axis_type == PIVOT_AXIS_ROW || axis_type == PIVOT_AXIS_COLUMN);
157 return (axis_type == PIVOT_AXIS_ROW ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW);
160 /* Implementation of PIVOT_AXIS_FOR_EACH. */
162 pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis)
166 if (axis->n_dimensions)
167 for (size_t i = 0; i < axis->n_dimensions; i++)
168 if (axis->dimensions[i]->n_leaves == 0)
171 return xcalloc (axis->n_dimensions, sizeof *indexes);
174 for (size_t i = 0; i < axis->n_dimensions; i++)
176 const struct pivot_dimension *d = axis->dimensions[i];
177 if (++indexes[i] < d->n_leaves)
190 pivot_category_set_rc (struct pivot_category *category, const char *s)
192 const struct fmt_spec *format = pivot_table_get_format (
193 category->dimension->table, s);
195 category->format = *format;
199 pivot_category_create_leaves_valist (struct pivot_category *parent,
203 while ((s = va_arg (args, const char *)))
205 if (!strncmp (s, "RC_", 3))
207 assert (parent->n_subs);
208 pivot_category_set_rc (parent->subs[parent->n_subs - 1], s);
211 pivot_category_create_leaf (parent, pivot_value_new_text (s));
215 /* Creates a new dimension with the given NAME in TABLE and returns it. The
216 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
219 NAME should be a translatable name, but not actually translated yet,
220 e.g. enclosed in N_(). To use a different kind of value for a name, use
221 pivot_dimension_create__() instead.
223 The optional varargs parameters may be used to add an initial set of
224 categories to the dimension. Each string should be a translatable category
225 name, but not actually translated yet, e.g. enclosed in N_(). Each string
226 may optionally be followod by a PIVOT_RC_* string that specifies the default
227 numeric format for cells in this category. */
228 struct pivot_dimension * SENTINEL (0)
229 (pivot_dimension_create) (struct pivot_table *table,
230 enum pivot_axis_type axis_type,
231 const char *name, ...)
233 struct pivot_dimension *d = pivot_dimension_create__ (
234 table, axis_type, pivot_value_new_text (name));
237 va_start (args, name);
238 pivot_category_create_leaves_valist (d->root, args);
244 /* Creates a new dimension with the given NAME in TABLE and returns it. The
245 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
247 struct pivot_dimension *
248 pivot_dimension_create__ (struct pivot_table *table,
249 enum pivot_axis_type axis_type,
250 struct pivot_value *name)
252 assert (pivot_table_is_empty (table));
254 struct pivot_dimension *d = xmalloc (sizeof *d);
255 *d = (struct pivot_dimension) {
257 .axis_type = axis_type,
258 .level = table->axes[axis_type].n_dimensions,
259 .top_index = table->n_dimensions,
260 .root = xmalloc (sizeof *d->root),
263 struct pivot_category *root = d->root;
264 *root = (struct pivot_category) {
269 .data_index = SIZE_MAX,
270 .presentation_index = SIZE_MAX,
273 table->dimensions = xrealloc (
274 table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions);
275 table->dimensions[table->n_dimensions++] = d;
277 struct pivot_axis *axis = &table->axes[axis_type];
278 axis->dimensions = xrealloc (
279 axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
280 axis->dimensions[axis->n_dimensions++] = d;
282 if (axis_type == PIVOT_AXIS_LAYER)
284 free (table->current_layer);
285 table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
286 sizeof *table->current_layer);
289 /* XXX extent and label_depth need to be calculated later. */
295 pivot_dimension_destroy (struct pivot_dimension *d)
300 pivot_category_destroy (d->root);
301 free (d->data_leaves);
302 free (d->presentation_leaves);
306 /* Returns the first leaf node in an in-order traversal that is a child of
308 static const struct pivot_category * UNUSED
309 pivot_category_first_leaf (const struct pivot_category *cat)
311 if (pivot_category_is_leaf (cat))
314 for (size_t i = 0; i < cat->n_subs; i++)
316 const struct pivot_category *first
317 = pivot_category_first_leaf (cat->subs[i]);
325 /* Returns the next leaf node in an in-order traversal starting at CAT, which
327 static const struct pivot_category * UNUSED
328 pivot_category_next_leaf (const struct pivot_category *cat)
330 assert (pivot_category_is_leaf (cat));
334 const struct pivot_category *parent = cat->parent;
337 for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
339 const struct pivot_category *next
340 = pivot_category_first_leaf (parent->subs[i]);
350 pivot_category_add_child (struct pivot_category *child)
352 struct pivot_category *parent = child->parent;
354 assert (pivot_category_is_group (parent));
355 if (parent->n_subs >= parent->allocated_subs)
356 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
357 sizeof *parent->subs);
358 parent->subs[parent->n_subs++] = child;
361 /* Adds leaf categories as a child of PARENT. To create top-level categories
362 within dimension 'd', pass 'd->root' for PARENT.
364 Each of the varargs parameters should be a string, each of which should be a
365 translatable category name, but not actually translated yet, e.g. enclosed
366 in N_(). Each string may optionally be followod by a PIVOT_RC_* string that
367 specifies the default numeric format for cells in this category.
369 Returns the category index, which is just a 0-based array index, for the
372 Leaves have to be created in in-order, that is, don't create a group and add
373 some leaves, then add leaves outside the group and try to add more leaves
376 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
378 int retval = parent->dimension->n_leaves;
381 va_start (args, parent);
382 pivot_category_create_leaves_valist (parent, args);
388 /* Creates a new leaf category with the given NAME as a child of PARENT. To
389 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
390 Returns the category index, which is just a 0-based array index, for the new
393 Leaves have to be created in in-order, that is, don't create a group and add
394 some leaves, then add leaves outside the group and try to add more leaves
397 pivot_category_create_leaf (struct pivot_category *parent,
398 struct pivot_value *name)
400 return pivot_category_create_leaf_rc (parent, name, NULL);
403 /* Creates a new leaf category with the given NAME as a child of PARENT. To
404 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
405 Returns the category index, which is just a 0-based array index, for the new
408 If RC is nonnull and the name of a result category, the category is assigned
409 that result category.
411 Leaves have to be created in in-order, that is, don't create a group and add
412 some leaves, then add leaves outside the group and try to add more leaves
415 pivot_category_create_leaf_rc (struct pivot_category *parent,
416 struct pivot_value *name, const char *rc)
418 struct pivot_dimension *d = parent->dimension;
420 struct pivot_category *leaf = xmalloc (sizeof *leaf);
421 *leaf = (struct pivot_category) {
425 .group_index = parent->n_subs,
426 .data_index = d->n_leaves,
427 .presentation_index = d->n_leaves,
430 if (d->n_leaves >= d->allocated_leaves)
432 d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
433 sizeof *d->data_leaves);
434 d->presentation_leaves = xrealloc (
435 d->presentation_leaves,
436 d->allocated_leaves * sizeof *d->presentation_leaves);
439 d->data_leaves[d->n_leaves] = leaf;
440 d->presentation_leaves[d->n_leaves] = leaf;
443 pivot_category_add_child (leaf);
445 /* Make sure that the new child is the last in in-order. */
446 assert (!pivot_category_next_leaf (leaf));
448 pivot_category_set_rc (leaf, rc);
450 return leaf->data_index;
453 /* Adds a new category group named NAME as a child of PARENT. To create a
454 top-level group within dimension 'd', pass 'd->root' for PARENT.
456 NAME should be a translatable name, but not actually translated yet,
457 e.g. enclosed in N_(). To use a different kind of value for a name, use
458 pivot_category_create_group__() instead.
460 The optional varargs parameters may be used to add an initial set of
461 categories to the group. Each string should be a translatable category
462 name, but not actually translated yet, e.g. enclosed in N_(). Each string
463 may optionally be followod by a PIVOT_RC_* string that specifies the default
464 numeric format for cells in this category.
466 Returns the new group. */
467 struct pivot_category * SENTINEL (0)
468 (pivot_category_create_group) (struct pivot_category *parent,
469 const char *name, ...)
471 struct pivot_category *group = pivot_category_create_group__ (
472 parent, pivot_value_new_text (name));
475 va_start (args, name);
476 pivot_category_create_leaves_valist (group, args);
482 /* Adds a new category group named NAME as a child of PARENT. To create a
483 top-level group within dimension 'd', pass 'd->root' for PARENT. Returns
485 struct pivot_category *
486 pivot_category_create_group__ (struct pivot_category *parent,
487 struct pivot_value *name)
489 struct pivot_dimension *d = parent->dimension;
491 struct pivot_category *group = xmalloc (sizeof *group);
492 *group = (struct pivot_category) {
497 .group_index = parent->n_subs,
498 .data_index = SIZE_MAX,
499 .presentation_index = SIZE_MAX,
502 pivot_category_add_child (group);
508 pivot_category_destroy (struct pivot_category *c)
513 pivot_value_destroy (c->name);
514 for (size_t i = 0; i < c->n_subs; i++)
515 pivot_category_destroy (c->subs[i]);
522 These are usually the easiest way to control the formatting of numeric data
523 in a pivot table. See pivot_dimension_create() for an explanation of their
527 const char *name; /* "RC_*". */
528 struct fmt_spec format;
531 /* Formats for most of the result classes. */
532 static struct result_class result_classes[] =
534 { PIVOT_RC_INTEGER, { FMT_F, 40, 0 } },
535 { PIVOT_RC_PERCENT, { FMT_PCT, 40, 1 } },
536 { PIVOT_RC_CORRELATION, { FMT_F, 40, 3 } },
537 { PIVOT_RC_SIGNIFICANCE, { FMT_F, 40, 3 } },
538 { PIVOT_RC_RESIDUAL, { FMT_F, 40, 2 } },
539 { PIVOT_RC_COUNT, { 0, 0, 0 } },
540 { PIVOT_RC_OTHER, { 0, 0, 0 } },
543 /* Has PIVOT_RC_COUNT been overridden by the user? */
544 static bool overridden_count_format;
546 static struct result_class *
547 pivot_result_class_find (const char *s)
549 for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
550 if (!strcmp (s, result_classes[i].name))
551 return &result_classes[i];
555 static const struct fmt_spec *
556 pivot_table_get_format (const struct pivot_table *table, const char *s)
560 else if (!strcmp (s, PIVOT_RC_OTHER))
561 return settings_get_format ();
562 else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
563 return &table->weight_format;
566 const struct result_class *rc = pivot_result_class_find (s);
567 return rc ? &rc->format : NULL;
571 /* Sets the format specification for the result class named S (which should not
572 include the RC_ prefix) to *FORMAT. Returns true if successful, false if S
573 does not name a known result class. */
575 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
577 char *s = xasprintf ("RC_%s", s_);
578 struct result_class *rc = pivot_result_class_find (s);
581 rc->format = *format;
582 if (!strcmp (s, PIVOT_RC_COUNT))
583 overridden_count_format = true;
590 /* One piece of data within a pivot table. */
593 struct hmap_node hmap_node; /* In struct pivot_table's 'cells' hmap. */
594 struct pivot_value *value;
595 unsigned int idx[]; /* One index per table dimension. */
600 /* Creates and returns a new pivot table with the given TITLE. TITLE should be
601 a text string marked for translation but not actually translated yet,
602 e.g. N_("Descriptive Statistics").
604 Operations commonly performed on the new pivot_table:
606 - If empty rows or columns should not be displayed, set ->omit_empty to
609 - Set the format to use for "count" values with pivot_table_set_weight_var()
610 or pivot_table_set_weight_format().
612 This function is a shortcut for pivot_table_create__() for the most common
613 case. Use pivot_table_create__() directly if the title should be some kind
614 of value other than an ordinary text string.
616 See the large comment at the top of pivot-table.h for general advice on
617 creating pivot tables. */
619 pivot_table_create (const char *title)
621 return pivot_table_create__ (pivot_value_new_text (title));
624 /* Creates and returns a new pivot table with the given TITLE, and takes
627 Operations commonly performed on the new pivot_table:
629 - If empty rows or columns should not be displayed, set ->omit_empty to
632 - Set the format to use for "count" values with pivot_table_set_weight_var()
633 or pivot_table_set_weight_format().
635 See the large comment at the top of pivot-table.h for general advice on
636 creating pivot tables. */
638 pivot_table_create__ (struct pivot_value *title)
640 struct pivot_table *table = xzalloc (sizeof *table);
641 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
642 table->title = title;
644 /* Set default area styles. */
645 #define STYLE(BOLD, H, V, L, R, T, B) { \
647 .halign = TABLE_HALIGN_##H, \
648 .valign = TABLE_VALIGN_##V, \
649 .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
650 [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
654 .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
655 .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
658 static const struct area_style default_area_styles[PIVOT_N_AREAS] = {
659 [PIVOT_AREA_TITLE] = STYLE( true, CENTER, CENTER, 8,11,1,8),
660 [PIVOT_AREA_CAPTION] = STYLE(false, LEFT, TOP, 8,11,1,1),
661 [PIVOT_AREA_FOOTER] = STYLE(false, LEFT, TOP, 11, 8,2,3),
662 [PIVOT_AREA_CORNER] = STYLE(false, LEFT, BOTTOM, 8,11,1,1),
663 [PIVOT_AREA_COLUMN_LABELS] = STYLE(false, CENTER, BOTTOM, 8,11,1,3),
664 [PIVOT_AREA_ROW_LABELS] = STYLE(false, LEFT, TOP, 8,11,1,3),
665 [PIVOT_AREA_DATA] = STYLE(false, MIXED, TOP, 8,11,1,1),
666 [PIVOT_AREA_LAYERS] = STYLE(false, LEFT, BOTTOM, 8,11,1,3),
669 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
670 table->areas[i] = default_area_styles[i];
672 /* Set default border styles. */
673 static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
674 [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE,
675 [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE,
676 [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE,
677 [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE,
678 [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
679 [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK,
680 [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK,
681 [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK,
682 [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
683 [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK,
684 [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK,
685 [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
686 [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
687 [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
688 [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
689 [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
690 [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
691 [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
692 [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
694 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
695 table->borders[i] = (struct table_border_style) {
696 .stroke = default_strokes[i],
697 .color = CELL_COLOR_BLACK,
700 table->row_labels_in_corner = true;
701 hmap_init (&table->cells);
706 /* Creates and returns a new pivot table with the given TITLE and a single cell
707 with the given CONTENT.
709 This is really just for error handling. */
711 pivot_table_create_for_text (struct pivot_value *title,
712 struct pivot_value *content)
714 struct pivot_table *table = pivot_table_create__ (title);
716 struct pivot_dimension *d = pivot_dimension_create (
717 table, PIVOT_AXIS_ROW, N_("Error"));
718 d->hide_all_labels = true;
719 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
721 pivot_table_put1 (table, 0, content);
726 /* Destroys TABLE and frees everything it points to. */
728 pivot_table_destroy (struct pivot_table *table)
733 free (table->current_layer);
734 free (table->table_look);
736 for (int i = 0; i < TABLE_N_AXES; i++)
737 pivot_table_sizing_uninit (&table->sizing[i]);
739 free (table->continuation);
741 for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
742 free (table->ccs[i]);
744 free (table->command_local);
745 free (table->command_c);
746 free (table->language);
747 free (table->locale);
749 free (table->dataset);
750 free (table->datafile);
752 for (size_t i = 0; i < table->n_footnotes; i++)
753 pivot_footnote_destroy (table->footnotes[i]);
754 free (table->footnotes);
756 pivot_value_destroy (table->title);
757 pivot_value_destroy (table->subtype);
758 pivot_value_destroy (table->corner_text);
759 pivot_value_destroy (table->caption);
761 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
762 area_style_uninit (&table->areas[i]);
764 for (size_t i = 0; i < table->n_dimensions; i++)
765 pivot_dimension_destroy (table->dimensions[i]);
766 free (table->dimensions);
768 for (size_t i = 0; i < PIVOT_N_AXES; i++)
769 free (table->axes[i].dimensions);
771 struct pivot_cell *cell, *next_cell;
772 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
775 hmap_delete (&table->cells, &cell->hmap_node);
776 pivot_value_destroy (cell->value);
779 hmap_destroy (&table->cells);
784 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
785 WV, which should be the weight variable for the dictionary whose data or
786 statistics are being put into TABLE.
788 This has no effect if WV is NULL. */
790 pivot_table_set_weight_var (struct pivot_table *table,
791 const struct variable *wv)
794 pivot_table_set_weight_format (table, var_get_print_format (wv));
797 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
798 format for the dictionary whose data or statistics are being put into TABLE.
800 This has no effect if WFMT is NULL. */
802 pivot_table_set_weight_format (struct pivot_table *table,
803 const struct fmt_spec *wfmt)
806 table->weight_format = *wfmt;
809 /* Returns true if TABLE has no cells, false otherwise. */
811 pivot_table_is_empty (const struct pivot_table *table)
813 return hmap_is_empty (&table->cells);
817 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
819 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
823 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
825 for (size_t i = 0; i < n; i++)
832 static struct pivot_cell *
833 pivot_table_lookup_cell__ (const struct pivot_table *table,
834 const size_t *dindexes, unsigned int hash)
836 struct pivot_cell *cell;
837 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
839 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
844 static struct pivot_cell *
845 pivot_cell_allocate (size_t n_idx)
847 struct pivot_cell *cell UNUSED;
848 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
851 static struct pivot_cell *
852 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
854 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
855 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
858 cell = pivot_cell_allocate (table->n_dimensions);
859 for (size_t i = 0; i < table->n_dimensions; i++)
860 cell->idx[i] = dindexes[i];
862 hmap_insert (&table->cells, &cell->hmap_node, hash);
867 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
868 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
871 If VALUE is a numeric value without a specified format, this function checks
872 each of the categories designated by DINDEXES[] and takes the format from
873 the first category with a result class. If none has a result class, uses
874 the overall default numeric format. */
876 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
877 struct pivot_value *value)
879 assert (n == table->n_dimensions);
881 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
883 for (size_t i = 0; i < table->n_dimensions; i++)
885 const struct pivot_dimension *d = table->dimensions[i];
886 if (dindexes[i] < d->n_leaves)
888 const struct pivot_category *c = d->data_leaves[dindexes[i]];
891 value->numeric.format = c->format;
896 value->numeric.format = *settings_get_format ();
901 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
902 pivot_value_destroy (cell->value);
906 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
907 dimension. Takes ownership of VALUE. */
909 pivot_table_put1 (struct pivot_table *table, size_t idx1,
910 struct pivot_value *value)
912 size_t dindexes[] = { idx1 };
913 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
916 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
917 dimensions. Takes ownership of VALUE. */
919 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
920 struct pivot_value *value)
922 size_t dindexes[] = { idx1, idx2 };
923 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
926 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
927 have 3 dimensions. Takes ownership of VALUE. */
929 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
930 size_t idx3, struct pivot_value *value)
932 size_t dindexes[] = { idx1, idx2, idx3 };
933 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
936 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
937 must have 4 dimensions. Takes ownership of VALUE. */
939 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
940 size_t idx3, size_t idx4, struct pivot_value *value)
942 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
943 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
946 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
947 automatically assigned marker.
949 The footnote will only appear in output if it is referenced. Use
950 pivot_value_add_footnote() to add a reference to the footnote. */
951 struct pivot_footnote *
952 pivot_table_create_footnote (struct pivot_table *table,
953 struct pivot_value *content)
955 return pivot_table_create_footnote__ (table, table->n_footnotes,
959 static struct pivot_value *
960 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
962 char text[INT_BUFSIZE_BOUND (size_t)];
963 if (show_numeric_markers)
964 snprintf (text, sizeof text, "%d", idx + 1);
966 str_format_26adic (idx + 1, false, text, sizeof text);
967 return pivot_value_new_user_text (text, -1);
970 /* Creates or modifies a footnote in TABLE with 0-based number IDX. If MARKER
971 is nonnull, sets the footnote's marker; if CONTENT is nonnull, sets the
972 footnote's content. */
973 struct pivot_footnote *
974 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
975 struct pivot_value *marker,
976 struct pivot_value *content)
978 if (idx >= table->n_footnotes)
980 while (idx >= table->allocated_footnotes)
981 table->footnotes = x2nrealloc (table->footnotes,
982 &table->allocated_footnotes,
983 sizeof *table->footnotes);
984 while (idx >= table->n_footnotes)
986 struct pivot_footnote *f = xmalloc (sizeof *f);
987 f->idx = table->n_footnotes;
988 f->marker = pivot_make_default_footnote_marker (
989 f->idx, table->show_numeric_markers);
992 table->footnotes[table->n_footnotes++] = f;
996 struct pivot_footnote *f = table->footnotes[idx];
999 pivot_value_destroy (f->marker);
1004 pivot_value_destroy (f->content);
1005 f->content = content;
1010 /* Frees the data owned by F. */
1012 pivot_footnote_destroy (struct pivot_footnote *f)
1016 pivot_value_destroy (f->content);
1017 pivot_value_destroy (f->marker);
1022 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1023 indexes for each dimension in TABLE in DINDEXES[]. */
1025 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1026 const size_t *pindexes[PIVOT_N_AXES],
1027 size_t dindexes[/* table->n_dimensions */])
1029 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1031 const struct pivot_axis *axis = &table->axes[i];
1033 for (size_t j = 0; j < axis->n_dimensions; j++)
1035 const struct pivot_dimension *d = axis->dimensions[j];
1036 dindexes[d->top_index]
1037 = d->presentation_leaves[pindexes[i][j]]->data_index;
1043 pivot_table_enumerate_axis (const struct pivot_table *table,
1044 enum pivot_axis_type axis_type,
1045 const size_t *layer_indexes, bool omit_empty,
1048 const struct pivot_axis *axis = &table->axes[axis_type];
1049 if (!axis->n_dimensions)
1051 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1053 enumeration[1] = SIZE_MAX;
1058 else if (!axis->extent)
1060 size_t *enumeration = xmalloc (sizeof *enumeration);
1061 *enumeration = SIZE_MAX;
1067 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1068 axis->n_dimensions), 1),
1069 sizeof *enumeration);
1070 size_t *p = enumeration;
1071 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1073 size_t *axis_indexes;
1074 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1078 enum pivot_axis_type axis2_type
1079 = pivot_axis_type_transpose (axis_type);
1081 size_t *axis2_indexes;
1082 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1084 const size_t *pindexes[PIVOT_N_AXES];
1085 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1086 pindexes[axis_type] = axis_indexes;
1087 pindexes[axis2_type] = axis2_indexes;
1088 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1089 if (pivot_table_get (table, dindexes))
1095 free (axis2_indexes);
1098 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1099 p += axis->n_dimensions;
1103 *n = (p - enumeration) / axis->n_dimensions;
1109 static const struct pivot_cell *
1110 pivot_table_lookup_cell (const struct pivot_table *table,
1111 const size_t *dindexes)
1113 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1114 return pivot_table_lookup_cell__ (table, dindexes, hash);
1117 const struct pivot_value *
1118 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1120 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1121 return cell ? cell->value : NULL;
1124 struct pivot_value *
1125 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1127 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1129 cell->value = pivot_value_new_user_text ("", -1);
1134 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1136 if (pivot_category_is_group (category) && category->n_subs)
1137 for (size_t i = 0; i < category->n_subs; i++)
1138 distribute_extra_depth (category->subs[i], extra_depth);
1140 category->extra_depth += extra_depth;
1144 pivot_category_assign_label_depth (struct pivot_category *category,
1145 bool dimension_labels_in_corner)
1147 category->extra_depth = 0;
1149 if (pivot_category_is_group (category))
1152 for (size_t i = 0; i < category->n_subs; i++)
1154 pivot_category_assign_label_depth (category->subs[i], false);
1155 depth = MAX (depth, category->subs[i]->label_depth);
1158 for (size_t i = 0; i < category->n_subs; i++)
1160 struct pivot_category *sub = category->subs[i];
1162 size_t extra_depth = depth - sub->label_depth;
1164 distribute_extra_depth (sub, extra_depth);
1166 sub->label_depth = depth;
1169 category->show_label_in_corner = (category->show_label
1170 && dimension_labels_in_corner);
1171 category->label_depth
1172 = (category->show_label && !category->show_label_in_corner
1173 ? depth + 1 : depth);
1176 category->label_depth = 1;
1180 pivot_axis_assign_label_depth (struct pivot_table *table,
1181 enum pivot_axis_type axis_type,
1182 bool dimension_labels_in_corner)
1184 struct pivot_axis *axis = &table->axes[axis_type];
1185 bool any_label_shown_in_corner = false;
1186 axis->label_depth = 0;
1188 for (size_t i = 0; i < axis->n_dimensions; i++)
1190 struct pivot_dimension *d = axis->dimensions[i];
1191 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1192 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1193 axis->label_depth += d->label_depth;
1194 axis->extent *= d->n_leaves;
1196 if (d->root->show_label_in_corner)
1197 any_label_shown_in_corner = true;
1199 return any_label_shown_in_corner;
1203 pivot_table_assign_label_depth (struct pivot_table *table)
1205 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1206 if (pivot_axis_assign_label_depth (
1207 table, PIVOT_AXIS_ROW, (table->row_labels_in_corner
1208 && !table->corner_text))
1209 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1210 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1211 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1219 indent (int indentation)
1221 for (int i = 0; i < indentation * 2; i++)
1226 pivot_value_dump (const struct pivot_value *value)
1228 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1229 SETTINGS_VALUE_SHOW_DEFAULT);
1235 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1240 indent (indentation);
1241 printf ("%s: ", name);
1242 pivot_value_dump (value);
1248 pivot_table_dump_string (const char *string, const char *name, int indentation)
1252 indent (indentation);
1253 printf ("%s: %s\n", name, string);
1258 pivot_category_dump (const struct pivot_category *c, int indentation)
1260 indent (indentation);
1261 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1262 pivot_value_dump (c->name);
1265 if (pivot_category_is_leaf (c))
1266 printf ("data_index=%zu\n", c->data_index);
1269 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1272 for (size_t i = 0; i < c->n_subs; i++)
1273 pivot_category_dump (c->subs[i], indentation + 1);
1278 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1280 indent (indentation);
1281 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1282 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1284 pivot_category_dump (d->root, indentation + 1);
1288 area_style_dump (enum pivot_area area, const struct area_style *a,
1291 indent (indentation);
1292 printf ("%s: ", pivot_area_to_string (area));
1293 font_style_dump (&a->font_style);
1295 cell_style_dump (&a->cell_style);
1300 table_border_style_dump (enum pivot_border border,
1301 const struct table_border_style *b, int indentation)
1303 indent (indentation);
1304 printf ("%s: %s ", pivot_border_to_string (border),
1305 table_stroke_to_string (b->stroke));
1306 cell_color_dump (&b->color);
1311 compose_headings (const struct pivot_axis *axis,
1312 const size_t *column_enumeration,
1313 enum settings_value_show show_values,
1314 enum settings_value_show show_variables)
1316 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1319 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1320 for (size_t i = 0; i < axis->label_depth; i++)
1321 headings[i] = xcalloc (axis->extent, sizeof **headings);
1323 const size_t *indexes;
1325 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1327 int row = axis->label_depth - 1;
1328 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1330 const struct pivot_dimension *d = axis->dimensions[dim_index];
1331 if (d->hide_all_labels)
1333 for (const struct pivot_category *c
1334 = d->presentation_leaves[indexes[dim_index]];
1338 if (pivot_category_is_leaf (c) || (c->show_label
1339 && !c->show_label_in_corner))
1341 headings[row][column] = pivot_value_to_string (
1342 c->name, show_values, show_variables);
1343 if (!*headings[row][column])
1344 headings[row][column] = xstrdup ("<blank>");
1356 pivot_table_dump (const struct pivot_table *table, int indentation)
1361 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1362 if (table->decimal == '.' || table->decimal == ',')
1363 settings_set_decimal_char (table->decimal);
1365 pivot_table_dump_value (table->title, "title", indentation);
1366 pivot_table_dump_string (table->command_c, "command", indentation);
1367 pivot_table_dump_string (table->dataset, "dataset", indentation);
1368 pivot_table_dump_string (table->datafile, "datafile", indentation);
1369 pivot_table_dump_string (table->notes, "notes", indentation);
1370 pivot_table_dump_string (table->table_look, "table-look", indentation);
1373 indent (indentation);
1374 printf ("date: %s", ctime (&table->date)); /* XXX thread unsafe */
1377 indent (indentation);
1378 printf ("areas:\n");
1379 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1380 area_style_dump (area, &table->areas[area], indentation + 1);
1382 indent (indentation);
1383 printf ("borders:\n");
1384 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1385 table_border_style_dump (border, &table->borders[border], indentation + 1);
1387 for (size_t i = 0; i < table->n_dimensions; i++)
1388 pivot_dimension_dump (table->dimensions[i], indentation);
1390 /* Presentation and data indexes. */
1391 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1393 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1394 if (layer_axis->n_dimensions)
1396 indent (indentation);
1397 printf ("current layer:");
1399 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1401 const struct pivot_dimension *d = layer_axis->dimensions[i];
1402 char *name = pivot_value_to_string (d->root->name,
1404 table->show_variables);
1405 char *value = pivot_value_to_string (
1406 d->data_leaves[table->current_layer[i]]->name,
1407 table->show_values, table->show_variables);
1408 printf (" %s=%s", name, value);
1416 size_t *layer_indexes;
1417 size_t layer_iteration = 0;
1418 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1420 indent (indentation);
1421 printf ("layer %zu:", layer_iteration++);
1423 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1424 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1426 const struct pivot_dimension *d = layer_axis->dimensions[i];
1428 fputs (i == 0 ? " " : ", ", stdout);
1429 pivot_value_dump (d->root->name);
1430 fputs (" =", stdout);
1432 struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1435 for (const struct pivot_category *c
1436 = d->presentation_leaves[layer_indexes[i]];
1440 if (pivot_category_is_leaf (c) || c->show_label)
1441 names[n_names++] = c->name;
1444 for (size_t i = n_names; i-- > 0; )
1447 pivot_value_dump (names[i]);
1453 size_t *column_enumeration = pivot_table_enumerate_axis (
1454 table, PIVOT_AXIS_COLUMN, layer_indexes, table->omit_empty, NULL);
1455 size_t *row_enumeration = pivot_table_enumerate_axis (
1456 table, PIVOT_AXIS_ROW, layer_indexes, table->omit_empty, NULL);
1458 char ***column_headings = compose_headings (
1459 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1460 table->show_values, table->show_variables);
1461 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1463 indent (indentation + 1);
1464 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1467 fputs ("; ", stdout);
1468 if (column_headings[y][x])
1469 fputs (column_headings[y][x], stdout);
1474 indent (indentation + 1);
1475 printf ("-----------------------------------------------\n");
1477 char ***row_headings = compose_headings (
1478 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1479 table->show_values, table->show_variables);
1482 const size_t *pindexes[PIVOT_N_AXES]
1483 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1484 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1485 &table->axes[PIVOT_AXIS_ROW])
1487 indent (indentation + 1);
1490 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1493 fputs ("; ", stdout);
1494 if (row_headings[y][x])
1495 fputs (row_headings[y][x], stdout);
1501 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1503 &table->axes[PIVOT_AXIS_COLUMN])
1508 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1509 const struct pivot_value *value = pivot_table_get (
1512 pivot_value_dump (value);
1519 free (column_enumeration);
1520 free (row_enumeration);
1523 pivot_table_dump_value (table->caption, "caption", indentation);
1525 for (size_t i = 0; i < table->n_footnotes; i++)
1527 const struct pivot_footnote *f = table->footnotes[i];
1528 indent (indentation);
1531 pivot_value_dump (f->marker);
1533 printf ("%zu", f->idx);
1535 pivot_value_dump (f->content);
1539 settings_set_decimal_char (old_decimal);
1543 consume_int (const char *p, size_t *n)
1546 while (c_isdigit (*p))
1547 *n = *n * 10 + (*p++ - '0');
1552 pivot_format_inner_template (struct string *out, const char *template,
1554 struct pivot_value **values, size_t n_values,
1555 enum settings_value_show show_values,
1556 enum settings_value_show show_variables)
1558 size_t args_consumed = 0;
1559 while (*template && *template != ':')
1561 if (*template == '\\' && template[1])
1563 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1566 else if (*template == escape)
1569 template = consume_int (template + 1, &index);
1570 if (index >= 1 && index <= n_values)
1572 pivot_value_format (values[index - 1], show_values,
1573 show_variables, out);
1574 args_consumed = MAX (args_consumed, index);
1578 ds_put_byte (out, *template++);
1580 return args_consumed;
1584 pivot_extract_inner_template (const char *template, const char **p)
1590 if (*template == '\\' && template[1] != '\0')
1592 else if (*template == ':')
1593 return template + 1;
1594 else if (*template == '\0')
1602 pivot_format_template (struct string *out, const char *template,
1603 const struct pivot_argument *args, size_t n_args,
1604 enum settings_value_show show_values,
1605 enum settings_value_show show_variables)
1609 if (*template == '\\' && template[1] != '\0')
1611 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1614 else if (*template == '^')
1617 template = consume_int (template + 1, &index);
1618 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1619 pivot_value_format (args[index - 1].values[0],
1620 show_values, show_variables, out);
1622 else if (*template == '[')
1624 const char *tmpl[2];
1625 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1626 template = pivot_extract_inner_template (template, &tmpl[1]);
1627 template += *template == ']';
1630 template = consume_int (template, &index);
1631 if (index < 1 || index > n_args)
1634 const struct pivot_argument *arg = &args[index - 1];
1635 size_t left = arg->n;
1638 struct pivot_value **values = arg->values + (arg->n - left);
1639 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1640 char escape = "%^"[tmpl_idx];
1641 size_t used = pivot_format_inner_template (
1642 out, tmpl[tmpl_idx], escape, values, left,
1643 show_values, show_variables);
1644 if (!used || used > left)
1650 ds_put_byte (out, *template++);
1654 static enum settings_value_show
1655 interpret_show (enum settings_value_show global_show,
1656 enum settings_value_show table_show,
1657 enum settings_value_show value_show,
1660 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1661 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1662 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1666 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1667 SHOW_VARIABLES control whether variable and value labels are included.
1669 The "body" omits subscripts and superscripts and footnotes. */
1671 pivot_value_format_body (const struct pivot_value *value,
1672 enum settings_value_show show_values,
1673 enum settings_value_show show_variables,
1676 enum settings_value_show show;
1677 bool numeric = false;
1679 switch (value->type)
1681 case PIVOT_VALUE_NUMERIC:
1682 show = interpret_show (settings_get_show_values (),
1684 value->numeric.show,
1685 value->numeric.value_label != NULL);
1686 if (show & SETTINGS_VALUE_SHOW_VALUE)
1688 char *s = data_out (&(union value) { .f = value->numeric.x },
1689 "UTF-8", &value->numeric.format);
1690 ds_put_cstr (out, s + strspn (s, " "));
1693 if (show & SETTINGS_VALUE_SHOW_LABEL)
1695 if (show & SETTINGS_VALUE_SHOW_VALUE)
1696 ds_put_byte (out, ' ');
1697 ds_put_cstr (out, value->numeric.value_label);
1699 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1702 case PIVOT_VALUE_STRING:
1703 show = interpret_show (settings_get_show_values (),
1706 value->string.value_label != NULL);
1707 if (show & SETTINGS_VALUE_SHOW_VALUE)
1709 if (value->string.hex)
1711 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1713 ds_put_format (out, "%02X", *p);
1716 ds_put_cstr (out, value->string.s);
1718 if (show & SETTINGS_VALUE_SHOW_LABEL)
1720 if (show & SETTINGS_VALUE_SHOW_VALUE)
1721 ds_put_byte (out, ' ');
1722 ds_put_cstr (out, value->string.value_label);
1726 case PIVOT_VALUE_VARIABLE:
1727 show = interpret_show (settings_get_show_variables (),
1729 value->variable.show,
1730 value->variable.var_label != NULL);
1731 if (show & SETTINGS_VALUE_SHOW_VALUE)
1732 ds_put_cstr (out, value->variable.var_name);
1733 if (show & SETTINGS_VALUE_SHOW_LABEL)
1735 if (show & SETTINGS_VALUE_SHOW_VALUE)
1736 ds_put_byte (out, ' ');
1737 ds_put_cstr (out, value->variable.var_label);
1741 case PIVOT_VALUE_TEXT:
1742 ds_put_cstr (out, value->text.local);
1745 case PIVOT_VALUE_TEMPLATE:
1746 pivot_format_template (out, value->template.s, value->template.args,
1747 value->template.n_args, show_values,
1755 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
1756 SHOW_VARIABLES control whether variable and value labels are included.
1758 Subscripts and superscripts and footnotes are included. */
1760 pivot_value_format (const struct pivot_value *value,
1761 enum settings_value_show show_values,
1762 enum settings_value_show show_variables,
1765 pivot_value_format_body ( value, show_values, show_variables, out);
1767 if (value->subscript)
1768 ds_put_format (out, "_%s", value->subscript);
1770 if (value->superscript)
1771 ds_put_format (out, "^%s", value->superscript);
1773 for (size_t i = 0; i < value->n_footnotes; i++)
1775 ds_put_byte (out, '^');
1776 pivot_value_format (value->footnotes[i]->marker,
1777 show_values, show_variables, out);
1781 /* Returns a text representation of VALUE. The caller must free the string,
1784 pivot_value_to_string (const struct pivot_value *value,
1785 enum settings_value_show show_values,
1786 enum settings_value_show show_variables)
1788 struct string s = DS_EMPTY_INITIALIZER;
1789 pivot_value_format (value, show_values, show_variables, &s);
1790 return ds_steal_cstr (&s);
1793 /* Frees the data owned by V. */
1795 pivot_value_destroy (struct pivot_value *value)
1799 font_style_uninit (value->font_style);
1800 free (value->font_style);
1801 free (value->cell_style);
1802 /* Do not free the elements of footnotes because VALUE does not own
1804 free (value->footnotes);
1805 free (value->subscript);
1807 switch (value->type)
1809 case PIVOT_VALUE_NUMERIC:
1810 free (value->numeric.var_name);
1811 free (value->numeric.value_label);
1814 case PIVOT_VALUE_STRING:
1815 free (value->string.s);
1816 free (value->string.var_name);
1817 free (value->string.value_label);
1820 case PIVOT_VALUE_VARIABLE:
1821 free (value->variable.var_name);
1822 free (value->variable.var_label);
1825 case PIVOT_VALUE_TEXT:
1826 free (value->text.local);
1827 if (value->text.c != value->text.local)
1828 free (value->text.c);
1829 if (value->text.id != value->text.local
1830 && value->text.id != value->text.c)
1831 free (value->text.id);
1834 case PIVOT_VALUE_TEMPLATE:
1835 free (value->template.s);
1836 for (size_t i = 0; i < value->template.n_args; i++)
1837 pivot_argument_uninit (&value->template.args[i]);
1838 free (value->template.args);
1845 /* Sets AREA to the style to use for VALUE, with defaults coming from
1846 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
1848 pivot_value_get_style (struct pivot_value *value,
1849 const struct area_style *default_style,
1850 struct area_style *area)
1852 font_style_copy (&area->font_style, (value->font_style
1854 : &default_style->font_style));
1855 area->cell_style = (value->cell_style
1856 ? *value->cell_style
1857 : default_style->cell_style);
1860 /* Copies AREA into VALUE's style. */
1862 pivot_value_set_style (struct pivot_value *value,
1863 const struct area_style *area)
1865 if (value->font_style)
1866 font_style_uninit (value->font_style);
1868 value->font_style = xmalloc (sizeof *value->font_style);
1869 font_style_copy (value->font_style, &area->font_style);
1871 if (!value->cell_style)
1872 value->cell_style = xmalloc (sizeof *value->cell_style);
1873 *value->cell_style = area->cell_style;
1876 /* Frees the data owned by ARG (but not ARG itself). */
1878 pivot_argument_uninit (struct pivot_argument *arg)
1882 for (size_t i = 0; i < arg->n; i++)
1883 pivot_value_destroy (arg->values[i]);
1888 /* Creates and returns a new pivot_value whose contents is the null-terminated
1889 string TEXT. Takes ownership of TEXT.
1891 This function is for text strings provided by the user (with the exception
1892 that pivot_value_new_variable() should be used for variable names). For
1893 strings that are part of the PSPP user interface, such as names of
1894 procedures, statistics, annotations, error messages, etc., use
1895 pivot_value_new_text(). */
1896 struct pivot_value *
1897 pivot_value_new_user_text_nocopy (char *text)
1899 struct pivot_value *value = xmalloc (sizeof *value);
1900 *value = (struct pivot_value) {
1901 .type = PIVOT_VALUE_TEXT,
1906 .user_provided = true,
1912 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
1913 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
1916 This function is for text strings provided by the user (with the exception
1917 that pivot_value_new_variable() should be used for variable names). For
1918 strings that are part of the PSPP user interface, such as names of
1919 procedures, statistics, annotations, error messages, etc., use
1920 pivot_value_new_text().j
1922 The caller retains ownership of TEXT.*/
1923 struct pivot_value *
1924 pivot_value_new_user_text (const char *text, size_t length)
1926 return pivot_value_new_user_text_nocopy (
1927 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
1930 /* Creates and returns new pivot_value whose contents is TEXT, which should be
1931 a translatable string, but not actually translated yet, e.g. enclosed in
1932 N_(). This function is for text strings that are part of the PSPP user
1933 interface, such as names of procedures, statistics, annotations, error
1934 messages, etc. For strings that come from the user, use
1935 pivot_value_new_user_text(). */
1936 struct pivot_value *
1937 pivot_value_new_text (const char *text)
1939 char *c = xstrdup (text);
1940 char *local = xstrdup (gettext (c));
1942 struct pivot_value *value = xmalloc (sizeof *value);
1943 *value = (struct pivot_value) {
1944 .type = PIVOT_VALUE_TEXT,
1949 .user_provided = false,
1955 /* Same as pivot_value_new_text() but its argument is a printf()-like format
1957 struct pivot_value * PRINTF_FORMAT (1, 2)
1958 pivot_value_new_text_format (const char *format, ...)
1961 va_start (args, format);
1962 char *c = xvasprintf (format, args);
1965 va_start (args, format);
1966 char *local = xvasprintf (gettext (format), args);
1969 struct pivot_value *value = xmalloc (sizeof *value);
1970 *value = (struct pivot_value) {
1971 .type = PIVOT_VALUE_TEXT,
1976 .user_provided = false,
1983 xstrdup_if_nonempty (const char *s)
1985 return s && s[0] ? xstrdup (s) : NULL;
1988 /* Returns a new pivot_value that represents X.
1990 The format to use for X is unspecified. Usually the easiest way to specify
1991 a format is through assigning a result class to one of the categories that
1992 the pivot_value will end up in. If that is not suitable, then the caller
1993 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
1994 struct pivot_value *
1995 pivot_value_new_number (double x)
1997 struct pivot_value *value = xmalloc (sizeof *value);
1998 *value = (struct pivot_value) {
1999 .type = PIVOT_VALUE_NUMERIC,
2000 .numeric = { .x = x, },
2005 /* Returns a new pivot_value that represents X, formatted as an integer. */
2006 struct pivot_value *
2007 pivot_value_new_integer (double x)
2009 struct pivot_value *value = pivot_value_new_number (x);
2010 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2014 /* Returns a new pivot_value that represents VALUE, formatted as for
2016 struct pivot_value *
2017 pivot_value_new_var_value (const struct variable *variable,
2018 const union value *value)
2020 struct pivot_value *pv = pivot_value_new_value (
2021 value, var_get_width (variable), var_get_print_format (variable),
2022 var_get_encoding (variable));
2024 char *var_name = xstrdup (var_get_name (variable));
2025 if (var_is_alpha (variable))
2026 pv->string.var_name = var_name;
2028 pv->numeric.var_name = var_name;
2030 const char *label = var_lookup_value_label (variable, value);
2033 if (var_is_alpha (variable))
2034 pv->string.value_label = xstrdup (label);
2036 pv->numeric.value_label = xstrdup (label);
2042 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2043 formatted with FORMAT. For a string value, ENCODING must be its character
2045 struct pivot_value *
2046 pivot_value_new_value (const union value *value, int width,
2047 const struct fmt_spec *format, const char *encoding)
2049 struct pivot_value *pv = xzalloc (sizeof *pv);
2052 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2054 size_t n = strlen (s);
2055 while (n > 0 && s[n - 1] == ' ')
2058 pv->type = PIVOT_VALUE_STRING;
2060 pv->string.hex = format->type == FMT_AHEX;
2064 pv->type = PIVOT_VALUE_NUMERIC;
2065 pv->numeric.x = value->f;
2066 pv->numeric.format = *format;
2072 /* Returns a new pivot_value for VARIABLE. */
2073 struct pivot_value *
2074 pivot_value_new_variable (const struct variable *variable)
2076 struct pivot_value *value = xmalloc (sizeof *value);
2077 *value = (struct pivot_value) {
2078 .type = PIVOT_VALUE_VARIABLE,
2080 .var_name = xstrdup (var_get_name (variable)),
2081 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2087 /* Attaches a reference to FOOTNOTE to V. */
2089 pivot_value_add_footnote (struct pivot_value *v,
2090 const struct pivot_footnote *footnote)
2092 v->footnotes = xrealloc (v->footnotes,
2093 (v->n_footnotes + 1) * sizeof *v->footnotes);
2094 v->footnotes[v->n_footnotes++] = footnote;
2097 /* If VALUE is a numeric value, and RC is a result class such as
2098 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2100 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2103 if (value->type == PIVOT_VALUE_NUMERIC)
2105 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2107 value->numeric.format = *f;