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 free_headings (const struct pivot_axis *axis, char ***headings)
1358 for (size_t i = 0; i < axis->label_depth; i++)
1360 for (size_t j = 0; j < axis->extent; j++)
1361 free (headings[i][j]);
1368 pivot_table_dump (const struct pivot_table *table, int indentation)
1373 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1374 if (table->decimal == '.' || table->decimal == ',')
1375 settings_set_decimal_char (table->decimal);
1377 pivot_table_dump_value (table->title, "title", indentation);
1378 pivot_table_dump_string (table->command_c, "command", indentation);
1379 pivot_table_dump_string (table->dataset, "dataset", indentation);
1380 pivot_table_dump_string (table->datafile, "datafile", indentation);
1381 pivot_table_dump_string (table->notes, "notes", indentation);
1382 pivot_table_dump_string (table->table_look, "table-look", indentation);
1385 indent (indentation);
1387 printf ("date: %s", ctime_r (&table->date, buf));
1390 indent (indentation);
1391 printf ("areas:\n");
1392 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1393 area_style_dump (area, &table->areas[area], indentation + 1);
1395 indent (indentation);
1396 printf ("borders:\n");
1397 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1398 table_border_style_dump (border, &table->borders[border], indentation + 1);
1400 for (size_t i = 0; i < table->n_dimensions; i++)
1401 pivot_dimension_dump (table->dimensions[i], indentation);
1403 /* Presentation and data indexes. */
1404 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1406 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1407 if (layer_axis->n_dimensions)
1409 indent (indentation);
1410 printf ("current layer:");
1412 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1414 const struct pivot_dimension *d = layer_axis->dimensions[i];
1415 char *name = pivot_value_to_string (d->root->name,
1417 table->show_variables);
1418 char *value = pivot_value_to_string (
1419 d->data_leaves[table->current_layer[i]]->name,
1420 table->show_values, table->show_variables);
1421 printf (" %s=%s", name, value);
1429 size_t *layer_indexes;
1430 size_t layer_iteration = 0;
1431 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1433 indent (indentation);
1434 printf ("layer %zu:", layer_iteration++);
1436 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1437 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1439 const struct pivot_dimension *d = layer_axis->dimensions[i];
1441 fputs (i == 0 ? " " : ", ", stdout);
1442 pivot_value_dump (d->root->name);
1443 fputs (" =", stdout);
1445 struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1448 for (const struct pivot_category *c
1449 = d->presentation_leaves[layer_indexes[i]];
1453 if (pivot_category_is_leaf (c) || c->show_label)
1454 names[n_names++] = c->name;
1457 for (size_t i = n_names; i-- > 0; )
1460 pivot_value_dump (names[i]);
1466 size_t *column_enumeration = pivot_table_enumerate_axis (
1467 table, PIVOT_AXIS_COLUMN, layer_indexes, table->omit_empty, NULL);
1468 size_t *row_enumeration = pivot_table_enumerate_axis (
1469 table, PIVOT_AXIS_ROW, layer_indexes, table->omit_empty, NULL);
1471 char ***column_headings = compose_headings (
1472 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1473 table->show_values, table->show_variables);
1474 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1476 indent (indentation + 1);
1477 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1480 fputs ("; ", stdout);
1481 if (column_headings[y][x])
1482 fputs (column_headings[y][x], stdout);
1486 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1488 indent (indentation + 1);
1489 printf ("-----------------------------------------------\n");
1491 char ***row_headings = compose_headings (
1492 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1493 table->show_values, table->show_variables);
1496 const size_t *pindexes[PIVOT_N_AXES]
1497 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1498 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1499 &table->axes[PIVOT_AXIS_ROW])
1501 indent (indentation + 1);
1504 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1507 fputs ("; ", stdout);
1508 if (row_headings[y][x])
1509 fputs (row_headings[y][x], stdout);
1515 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1517 &table->axes[PIVOT_AXIS_COLUMN])
1522 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1523 const struct pivot_value *value = pivot_table_get (
1526 pivot_value_dump (value);
1533 free (column_enumeration);
1534 free (row_enumeration);
1535 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1538 pivot_table_dump_value (table->caption, "caption", indentation);
1540 for (size_t i = 0; i < table->n_footnotes; i++)
1542 const struct pivot_footnote *f = table->footnotes[i];
1543 indent (indentation);
1546 pivot_value_dump (f->marker);
1548 printf ("%zu", f->idx);
1550 pivot_value_dump (f->content);
1555 settings_set_decimal_char (old_decimal);
1559 consume_int (const char *p, size_t *n)
1562 while (c_isdigit (*p))
1563 *n = *n * 10 + (*p++ - '0');
1568 pivot_format_inner_template (struct string *out, const char *template,
1570 struct pivot_value **values, size_t n_values,
1571 enum settings_value_show show_values,
1572 enum settings_value_show show_variables)
1574 size_t args_consumed = 0;
1575 while (*template && *template != ':')
1577 if (*template == '\\' && template[1])
1579 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1582 else if (*template == escape)
1585 template = consume_int (template + 1, &index);
1586 if (index >= 1 && index <= n_values)
1588 pivot_value_format (values[index - 1], show_values,
1589 show_variables, out);
1590 args_consumed = MAX (args_consumed, index);
1594 ds_put_byte (out, *template++);
1596 return args_consumed;
1600 pivot_extract_inner_template (const char *template, const char **p)
1606 if (*template == '\\' && template[1] != '\0')
1608 else if (*template == ':')
1609 return template + 1;
1610 else if (*template == '\0')
1618 pivot_format_template (struct string *out, const char *template,
1619 const struct pivot_argument *args, size_t n_args,
1620 enum settings_value_show show_values,
1621 enum settings_value_show show_variables)
1625 if (*template == '\\' && template[1] != '\0')
1627 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1630 else if (*template == '^')
1633 template = consume_int (template + 1, &index);
1634 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1635 pivot_value_format (args[index - 1].values[0],
1636 show_values, show_variables, out);
1638 else if (*template == '[')
1640 const char *tmpl[2];
1641 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1642 template = pivot_extract_inner_template (template, &tmpl[1]);
1643 template += *template == ']';
1646 template = consume_int (template, &index);
1647 if (index < 1 || index > n_args)
1650 const struct pivot_argument *arg = &args[index - 1];
1651 size_t left = arg->n;
1654 struct pivot_value **values = arg->values + (arg->n - left);
1655 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1656 char escape = "%^"[tmpl_idx];
1657 size_t used = pivot_format_inner_template (
1658 out, tmpl[tmpl_idx], escape, values, left,
1659 show_values, show_variables);
1660 if (!used || used > left)
1666 ds_put_byte (out, *template++);
1670 static enum settings_value_show
1671 interpret_show (enum settings_value_show global_show,
1672 enum settings_value_show table_show,
1673 enum settings_value_show value_show,
1676 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1677 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1678 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1682 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1683 SHOW_VARIABLES control whether variable and value labels are included.
1685 The "body" omits subscripts and superscripts and footnotes. */
1687 pivot_value_format_body (const struct pivot_value *value,
1688 enum settings_value_show show_values,
1689 enum settings_value_show show_variables,
1692 enum settings_value_show show;
1693 bool numeric = false;
1695 switch (value->type)
1697 case PIVOT_VALUE_NUMERIC:
1698 show = interpret_show (settings_get_show_values (),
1700 value->numeric.show,
1701 value->numeric.value_label != NULL);
1702 if (show & SETTINGS_VALUE_SHOW_VALUE)
1704 char *s = data_out (&(union value) { .f = value->numeric.x },
1705 "UTF-8", &value->numeric.format);
1706 ds_put_cstr (out, s + strspn (s, " "));
1709 if (show & SETTINGS_VALUE_SHOW_LABEL)
1711 if (show & SETTINGS_VALUE_SHOW_VALUE)
1712 ds_put_byte (out, ' ');
1713 ds_put_cstr (out, value->numeric.value_label);
1715 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1718 case PIVOT_VALUE_STRING:
1719 show = interpret_show (settings_get_show_values (),
1722 value->string.value_label != NULL);
1723 if (show & SETTINGS_VALUE_SHOW_VALUE)
1725 if (value->string.hex)
1727 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1729 ds_put_format (out, "%02X", *p);
1732 ds_put_cstr (out, value->string.s);
1734 if (show & SETTINGS_VALUE_SHOW_LABEL)
1736 if (show & SETTINGS_VALUE_SHOW_VALUE)
1737 ds_put_byte (out, ' ');
1738 ds_put_cstr (out, value->string.value_label);
1742 case PIVOT_VALUE_VARIABLE:
1743 show = interpret_show (settings_get_show_variables (),
1745 value->variable.show,
1746 value->variable.var_label != NULL);
1747 if (show & SETTINGS_VALUE_SHOW_VALUE)
1748 ds_put_cstr (out, value->variable.var_name);
1749 if (show & SETTINGS_VALUE_SHOW_LABEL)
1751 if (show & SETTINGS_VALUE_SHOW_VALUE)
1752 ds_put_byte (out, ' ');
1753 ds_put_cstr (out, value->variable.var_label);
1757 case PIVOT_VALUE_TEXT:
1758 ds_put_cstr (out, value->text.local);
1761 case PIVOT_VALUE_TEMPLATE:
1762 pivot_format_template (out, value->template.s, value->template.args,
1763 value->template.n_args, show_values,
1771 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
1772 SHOW_VARIABLES control whether variable and value labels are included.
1774 Subscripts and superscripts and footnotes are included. */
1776 pivot_value_format (const struct pivot_value *value,
1777 enum settings_value_show show_values,
1778 enum settings_value_show show_variables,
1781 pivot_value_format_body ( value, show_values, show_variables, out);
1783 if (value->subscript)
1784 ds_put_format (out, "_%s", value->subscript);
1786 if (value->superscript)
1787 ds_put_format (out, "^%s", value->superscript);
1789 for (size_t i = 0; i < value->n_footnotes; i++)
1791 ds_put_byte (out, '^');
1792 pivot_value_format (value->footnotes[i]->marker,
1793 show_values, show_variables, out);
1797 /* Returns a text representation of VALUE. The caller must free the string,
1800 pivot_value_to_string (const struct pivot_value *value,
1801 enum settings_value_show show_values,
1802 enum settings_value_show show_variables)
1804 struct string s = DS_EMPTY_INITIALIZER;
1805 pivot_value_format (value, show_values, show_variables, &s);
1806 return ds_steal_cstr (&s);
1809 /* Frees the data owned by V. */
1811 pivot_value_destroy (struct pivot_value *value)
1815 font_style_uninit (value->font_style);
1816 free (value->font_style);
1817 free (value->cell_style);
1818 /* Do not free the elements of footnotes because VALUE does not own
1820 free (value->footnotes);
1821 free (value->subscript);
1823 switch (value->type)
1825 case PIVOT_VALUE_NUMERIC:
1826 free (value->numeric.var_name);
1827 free (value->numeric.value_label);
1830 case PIVOT_VALUE_STRING:
1831 free (value->string.s);
1832 free (value->string.var_name);
1833 free (value->string.value_label);
1836 case PIVOT_VALUE_VARIABLE:
1837 free (value->variable.var_name);
1838 free (value->variable.var_label);
1841 case PIVOT_VALUE_TEXT:
1842 free (value->text.local);
1843 if (value->text.c != value->text.local)
1844 free (value->text.c);
1845 if (value->text.id != value->text.local
1846 && value->text.id != value->text.c)
1847 free (value->text.id);
1850 case PIVOT_VALUE_TEMPLATE:
1851 free (value->template.s);
1852 for (size_t i = 0; i < value->template.n_args; i++)
1853 pivot_argument_uninit (&value->template.args[i]);
1854 free (value->template.args);
1861 /* Sets AREA to the style to use for VALUE, with defaults coming from
1862 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
1864 pivot_value_get_style (struct pivot_value *value,
1865 const struct area_style *default_style,
1866 struct area_style *area)
1868 font_style_copy (&area->font_style, (value->font_style
1870 : &default_style->font_style));
1871 area->cell_style = (value->cell_style
1872 ? *value->cell_style
1873 : default_style->cell_style);
1876 /* Copies AREA into VALUE's style. */
1878 pivot_value_set_style (struct pivot_value *value,
1879 const struct area_style *area)
1881 if (value->font_style)
1882 font_style_uninit (value->font_style);
1884 value->font_style = xmalloc (sizeof *value->font_style);
1885 font_style_copy (value->font_style, &area->font_style);
1887 if (!value->cell_style)
1888 value->cell_style = xmalloc (sizeof *value->cell_style);
1889 *value->cell_style = area->cell_style;
1892 /* Frees the data owned by ARG (but not ARG itself). */
1894 pivot_argument_uninit (struct pivot_argument *arg)
1898 for (size_t i = 0; i < arg->n; i++)
1899 pivot_value_destroy (arg->values[i]);
1904 /* Creates and returns a new pivot_value whose contents is the null-terminated
1905 string TEXT. Takes ownership of TEXT.
1907 This function is for text strings provided by the user (with the exception
1908 that pivot_value_new_variable() should be used for variable names). For
1909 strings that are part of the PSPP user interface, such as names of
1910 procedures, statistics, annotations, error messages, etc., use
1911 pivot_value_new_text(). */
1912 struct pivot_value *
1913 pivot_value_new_user_text_nocopy (char *text)
1915 struct pivot_value *value = xmalloc (sizeof *value);
1916 *value = (struct pivot_value) {
1917 .type = PIVOT_VALUE_TEXT,
1922 .user_provided = true,
1928 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
1929 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
1932 This function is for text strings provided by the user (with the exception
1933 that pivot_value_new_variable() should be used for variable names). For
1934 strings that are part of the PSPP user interface, such as names of
1935 procedures, statistics, annotations, error messages, etc., use
1936 pivot_value_new_text().j
1938 The caller retains ownership of TEXT.*/
1939 struct pivot_value *
1940 pivot_value_new_user_text (const char *text, size_t length)
1942 return pivot_value_new_user_text_nocopy (
1943 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
1946 /* Creates and returns new pivot_value whose contents is TEXT, which should be
1947 a translatable string, but not actually translated yet, e.g. enclosed in
1948 N_(). This function is for text strings that are part of the PSPP user
1949 interface, such as names of procedures, statistics, annotations, error
1950 messages, etc. For strings that come from the user, use
1951 pivot_value_new_user_text(). */
1952 struct pivot_value *
1953 pivot_value_new_text (const char *text)
1955 char *c = xstrdup (text);
1956 char *local = xstrdup (gettext (c));
1958 struct pivot_value *value = xmalloc (sizeof *value);
1959 *value = (struct pivot_value) {
1960 .type = PIVOT_VALUE_TEXT,
1965 .user_provided = false,
1971 /* Same as pivot_value_new_text() but its argument is a printf()-like format
1973 struct pivot_value * PRINTF_FORMAT (1, 2)
1974 pivot_value_new_text_format (const char *format, ...)
1977 va_start (args, format);
1978 char *c = xvasprintf (format, args);
1981 va_start (args, format);
1982 char *local = xvasprintf (gettext (format), args);
1985 struct pivot_value *value = xmalloc (sizeof *value);
1986 *value = (struct pivot_value) {
1987 .type = PIVOT_VALUE_TEXT,
1992 .user_provided = false,
1999 xstrdup_if_nonempty (const char *s)
2001 return s && s[0] ? xstrdup (s) : NULL;
2004 /* Returns a new pivot_value that represents X.
2006 The format to use for X is unspecified. Usually the easiest way to specify
2007 a format is through assigning a result class to one of the categories that
2008 the pivot_value will end up in. If that is not suitable, then the caller
2009 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2010 struct pivot_value *
2011 pivot_value_new_number (double x)
2013 struct pivot_value *value = xmalloc (sizeof *value);
2014 *value = (struct pivot_value) {
2015 .type = PIVOT_VALUE_NUMERIC,
2016 .numeric = { .x = x, },
2021 /* Returns a new pivot_value that represents X, formatted as an integer. */
2022 struct pivot_value *
2023 pivot_value_new_integer (double x)
2025 struct pivot_value *value = pivot_value_new_number (x);
2026 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2030 /* Returns a new pivot_value that represents VALUE, formatted as for
2032 struct pivot_value *
2033 pivot_value_new_var_value (const struct variable *variable,
2034 const union value *value)
2036 struct pivot_value *pv = pivot_value_new_value (
2037 value, var_get_width (variable), var_get_print_format (variable),
2038 var_get_encoding (variable));
2040 char *var_name = xstrdup (var_get_name (variable));
2041 if (var_is_alpha (variable))
2042 pv->string.var_name = var_name;
2044 pv->numeric.var_name = var_name;
2046 const char *label = var_lookup_value_label (variable, value);
2049 if (var_is_alpha (variable))
2050 pv->string.value_label = xstrdup (label);
2052 pv->numeric.value_label = xstrdup (label);
2058 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2059 formatted with FORMAT. For a string value, ENCODING must be its character
2061 struct pivot_value *
2062 pivot_value_new_value (const union value *value, int width,
2063 const struct fmt_spec *format, const char *encoding)
2065 struct pivot_value *pv = xzalloc (sizeof *pv);
2068 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2070 size_t n = strlen (s);
2071 while (n > 0 && s[n - 1] == ' ')
2074 pv->type = PIVOT_VALUE_STRING;
2076 pv->string.hex = format->type == FMT_AHEX;
2080 pv->type = PIVOT_VALUE_NUMERIC;
2081 pv->numeric.x = value->f;
2082 pv->numeric.format = *format;
2088 /* Returns a new pivot_value for VARIABLE. */
2089 struct pivot_value *
2090 pivot_value_new_variable (const struct variable *variable)
2092 struct pivot_value *value = xmalloc (sizeof *value);
2093 *value = (struct pivot_value) {
2094 .type = PIVOT_VALUE_VARIABLE,
2096 .var_name = xstrdup (var_get_name (variable)),
2097 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2103 /* Attaches a reference to FOOTNOTE to V. */
2105 pivot_value_add_footnote (struct pivot_value *v,
2106 const struct pivot_footnote *footnote)
2108 v->footnotes = xrealloc (v->footnotes,
2109 (v->n_footnotes + 1) * sizeof *v->footnotes);
2110 v->footnotes[v->n_footnotes++] = footnote;
2113 /* If VALUE is a numeric value, and RC is a result class such as
2114 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2116 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2119 if (value->type == PIVOT_VALUE_NUMERIC)
2121 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2123 value->numeric.format = *f;