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);
1386 printf ("date: %s", ctime (&table->date)); /* XXX thread unsafe */
1389 indent (indentation);
1390 printf ("areas:\n");
1391 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1392 area_style_dump (area, &table->areas[area], indentation + 1);
1394 indent (indentation);
1395 printf ("borders:\n");
1396 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1397 table_border_style_dump (border, &table->borders[border], indentation + 1);
1399 for (size_t i = 0; i < table->n_dimensions; i++)
1400 pivot_dimension_dump (table->dimensions[i], indentation);
1402 /* Presentation and data indexes. */
1403 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1405 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1406 if (layer_axis->n_dimensions)
1408 indent (indentation);
1409 printf ("current layer:");
1411 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1413 const struct pivot_dimension *d = layer_axis->dimensions[i];
1414 char *name = pivot_value_to_string (d->root->name,
1416 table->show_variables);
1417 char *value = pivot_value_to_string (
1418 d->data_leaves[table->current_layer[i]]->name,
1419 table->show_values, table->show_variables);
1420 printf (" %s=%s", name, value);
1428 size_t *layer_indexes;
1429 size_t layer_iteration = 0;
1430 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1432 indent (indentation);
1433 printf ("layer %zu:", layer_iteration++);
1435 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1436 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1438 const struct pivot_dimension *d = layer_axis->dimensions[i];
1440 fputs (i == 0 ? " " : ", ", stdout);
1441 pivot_value_dump (d->root->name);
1442 fputs (" =", stdout);
1444 struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1447 for (const struct pivot_category *c
1448 = d->presentation_leaves[layer_indexes[i]];
1452 if (pivot_category_is_leaf (c) || c->show_label)
1453 names[n_names++] = c->name;
1456 for (size_t i = n_names; i-- > 0; )
1459 pivot_value_dump (names[i]);
1465 size_t *column_enumeration = pivot_table_enumerate_axis (
1466 table, PIVOT_AXIS_COLUMN, layer_indexes, table->omit_empty, NULL);
1467 size_t *row_enumeration = pivot_table_enumerate_axis (
1468 table, PIVOT_AXIS_ROW, layer_indexes, table->omit_empty, NULL);
1470 char ***column_headings = compose_headings (
1471 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1472 table->show_values, table->show_variables);
1473 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1475 indent (indentation + 1);
1476 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1479 fputs ("; ", stdout);
1480 if (column_headings[y][x])
1481 fputs (column_headings[y][x], stdout);
1485 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1487 indent (indentation + 1);
1488 printf ("-----------------------------------------------\n");
1490 char ***row_headings = compose_headings (
1491 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1492 table->show_values, table->show_variables);
1495 const size_t *pindexes[PIVOT_N_AXES]
1496 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1497 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1498 &table->axes[PIVOT_AXIS_ROW])
1500 indent (indentation + 1);
1503 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1506 fputs ("; ", stdout);
1507 if (row_headings[y][x])
1508 fputs (row_headings[y][x], stdout);
1514 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1516 &table->axes[PIVOT_AXIS_COLUMN])
1521 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1522 const struct pivot_value *value = pivot_table_get (
1525 pivot_value_dump (value);
1532 free (column_enumeration);
1533 free (row_enumeration);
1534 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1537 pivot_table_dump_value (table->caption, "caption", indentation);
1539 for (size_t i = 0; i < table->n_footnotes; i++)
1541 const struct pivot_footnote *f = table->footnotes[i];
1542 indent (indentation);
1545 pivot_value_dump (f->marker);
1547 printf ("%zu", f->idx);
1549 pivot_value_dump (f->content);
1554 settings_set_decimal_char (old_decimal);
1558 consume_int (const char *p, size_t *n)
1561 while (c_isdigit (*p))
1562 *n = *n * 10 + (*p++ - '0');
1567 pivot_format_inner_template (struct string *out, const char *template,
1569 struct pivot_value **values, size_t n_values,
1570 enum settings_value_show show_values,
1571 enum settings_value_show show_variables)
1573 size_t args_consumed = 0;
1574 while (*template && *template != ':')
1576 if (*template == '\\' && template[1])
1578 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1581 else if (*template == escape)
1584 template = consume_int (template + 1, &index);
1585 if (index >= 1 && index <= n_values)
1587 pivot_value_format (values[index - 1], show_values,
1588 show_variables, out);
1589 args_consumed = MAX (args_consumed, index);
1593 ds_put_byte (out, *template++);
1595 return args_consumed;
1599 pivot_extract_inner_template (const char *template, const char **p)
1605 if (*template == '\\' && template[1] != '\0')
1607 else if (*template == ':')
1608 return template + 1;
1609 else if (*template == '\0')
1617 pivot_format_template (struct string *out, const char *template,
1618 const struct pivot_argument *args, size_t n_args,
1619 enum settings_value_show show_values,
1620 enum settings_value_show show_variables)
1624 if (*template == '\\' && template[1] != '\0')
1626 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1629 else if (*template == '^')
1632 template = consume_int (template + 1, &index);
1633 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1634 pivot_value_format (args[index - 1].values[0],
1635 show_values, show_variables, out);
1637 else if (*template == '[')
1639 const char *tmpl[2];
1640 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1641 template = pivot_extract_inner_template (template, &tmpl[1]);
1642 template += *template == ']';
1645 template = consume_int (template, &index);
1646 if (index < 1 || index > n_args)
1649 const struct pivot_argument *arg = &args[index - 1];
1650 size_t left = arg->n;
1653 struct pivot_value **values = arg->values + (arg->n - left);
1654 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1655 char escape = "%^"[tmpl_idx];
1656 size_t used = pivot_format_inner_template (
1657 out, tmpl[tmpl_idx], escape, values, left,
1658 show_values, show_variables);
1659 if (!used || used > left)
1665 ds_put_byte (out, *template++);
1669 static enum settings_value_show
1670 interpret_show (enum settings_value_show global_show,
1671 enum settings_value_show table_show,
1672 enum settings_value_show value_show,
1675 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1676 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1677 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1681 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1682 SHOW_VARIABLES control whether variable and value labels are included.
1684 The "body" omits subscripts and superscripts and footnotes. */
1686 pivot_value_format_body (const struct pivot_value *value,
1687 enum settings_value_show show_values,
1688 enum settings_value_show show_variables,
1691 enum settings_value_show show;
1692 bool numeric = false;
1694 switch (value->type)
1696 case PIVOT_VALUE_NUMERIC:
1697 show = interpret_show (settings_get_show_values (),
1699 value->numeric.show,
1700 value->numeric.value_label != NULL);
1701 if (show & SETTINGS_VALUE_SHOW_VALUE)
1703 char *s = data_out (&(union value) { .f = value->numeric.x },
1704 "UTF-8", &value->numeric.format);
1705 ds_put_cstr (out, s + strspn (s, " "));
1708 if (show & SETTINGS_VALUE_SHOW_LABEL)
1710 if (show & SETTINGS_VALUE_SHOW_VALUE)
1711 ds_put_byte (out, ' ');
1712 ds_put_cstr (out, value->numeric.value_label);
1714 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1717 case PIVOT_VALUE_STRING:
1718 show = interpret_show (settings_get_show_values (),
1721 value->string.value_label != NULL);
1722 if (show & SETTINGS_VALUE_SHOW_VALUE)
1724 if (value->string.hex)
1726 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1728 ds_put_format (out, "%02X", *p);
1731 ds_put_cstr (out, value->string.s);
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->string.value_label);
1741 case PIVOT_VALUE_VARIABLE:
1742 show = interpret_show (settings_get_show_variables (),
1744 value->variable.show,
1745 value->variable.var_label != NULL);
1746 if (show & SETTINGS_VALUE_SHOW_VALUE)
1747 ds_put_cstr (out, value->variable.var_name);
1748 if (show & SETTINGS_VALUE_SHOW_LABEL)
1750 if (show & SETTINGS_VALUE_SHOW_VALUE)
1751 ds_put_byte (out, ' ');
1752 ds_put_cstr (out, value->variable.var_label);
1756 case PIVOT_VALUE_TEXT:
1757 ds_put_cstr (out, value->text.local);
1760 case PIVOT_VALUE_TEMPLATE:
1761 pivot_format_template (out, value->template.s, value->template.args,
1762 value->template.n_args, show_values,
1770 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
1771 SHOW_VARIABLES control whether variable and value labels are included.
1773 Subscripts and superscripts and footnotes are included. */
1775 pivot_value_format (const struct pivot_value *value,
1776 enum settings_value_show show_values,
1777 enum settings_value_show show_variables,
1780 pivot_value_format_body ( value, show_values, show_variables, out);
1782 if (value->subscript)
1783 ds_put_format (out, "_%s", value->subscript);
1785 if (value->superscript)
1786 ds_put_format (out, "^%s", value->superscript);
1788 for (size_t i = 0; i < value->n_footnotes; i++)
1790 ds_put_byte (out, '^');
1791 pivot_value_format (value->footnotes[i]->marker,
1792 show_values, show_variables, out);
1796 /* Returns a text representation of VALUE. The caller must free the string,
1799 pivot_value_to_string (const struct pivot_value *value,
1800 enum settings_value_show show_values,
1801 enum settings_value_show show_variables)
1803 struct string s = DS_EMPTY_INITIALIZER;
1804 pivot_value_format (value, show_values, show_variables, &s);
1805 return ds_steal_cstr (&s);
1808 /* Frees the data owned by V. */
1810 pivot_value_destroy (struct pivot_value *value)
1814 font_style_uninit (value->font_style);
1815 free (value->font_style);
1816 free (value->cell_style);
1817 /* Do not free the elements of footnotes because VALUE does not own
1819 free (value->footnotes);
1820 free (value->subscript);
1822 switch (value->type)
1824 case PIVOT_VALUE_NUMERIC:
1825 free (value->numeric.var_name);
1826 free (value->numeric.value_label);
1829 case PIVOT_VALUE_STRING:
1830 free (value->string.s);
1831 free (value->string.var_name);
1832 free (value->string.value_label);
1835 case PIVOT_VALUE_VARIABLE:
1836 free (value->variable.var_name);
1837 free (value->variable.var_label);
1840 case PIVOT_VALUE_TEXT:
1841 free (value->text.local);
1842 if (value->text.c != value->text.local)
1843 free (value->text.c);
1844 if (value->text.id != value->text.local
1845 && value->text.id != value->text.c)
1846 free (value->text.id);
1849 case PIVOT_VALUE_TEMPLATE:
1850 free (value->template.s);
1851 for (size_t i = 0; i < value->template.n_args; i++)
1852 pivot_argument_uninit (&value->template.args[i]);
1853 free (value->template.args);
1860 /* Sets AREA to the style to use for VALUE, with defaults coming from
1861 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
1863 pivot_value_get_style (struct pivot_value *value,
1864 const struct area_style *default_style,
1865 struct area_style *area)
1867 font_style_copy (&area->font_style, (value->font_style
1869 : &default_style->font_style));
1870 area->cell_style = (value->cell_style
1871 ? *value->cell_style
1872 : default_style->cell_style);
1875 /* Copies AREA into VALUE's style. */
1877 pivot_value_set_style (struct pivot_value *value,
1878 const struct area_style *area)
1880 if (value->font_style)
1881 font_style_uninit (value->font_style);
1883 value->font_style = xmalloc (sizeof *value->font_style);
1884 font_style_copy (value->font_style, &area->font_style);
1886 if (!value->cell_style)
1887 value->cell_style = xmalloc (sizeof *value->cell_style);
1888 *value->cell_style = area->cell_style;
1891 /* Frees the data owned by ARG (but not ARG itself). */
1893 pivot_argument_uninit (struct pivot_argument *arg)
1897 for (size_t i = 0; i < arg->n; i++)
1898 pivot_value_destroy (arg->values[i]);
1903 /* Creates and returns a new pivot_value whose contents is the null-terminated
1904 string TEXT. Takes ownership of TEXT.
1906 This function is for text strings provided by the user (with the exception
1907 that pivot_value_new_variable() should be used for variable names). For
1908 strings that are part of the PSPP user interface, such as names of
1909 procedures, statistics, annotations, error messages, etc., use
1910 pivot_value_new_text(). */
1911 struct pivot_value *
1912 pivot_value_new_user_text_nocopy (char *text)
1914 struct pivot_value *value = xmalloc (sizeof *value);
1915 *value = (struct pivot_value) {
1916 .type = PIVOT_VALUE_TEXT,
1921 .user_provided = true,
1927 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
1928 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
1931 This function is for text strings provided by the user (with the exception
1932 that pivot_value_new_variable() should be used for variable names). For
1933 strings that are part of the PSPP user interface, such as names of
1934 procedures, statistics, annotations, error messages, etc., use
1935 pivot_value_new_text().j
1937 The caller retains ownership of TEXT.*/
1938 struct pivot_value *
1939 pivot_value_new_user_text (const char *text, size_t length)
1941 return pivot_value_new_user_text_nocopy (
1942 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
1945 /* Creates and returns new pivot_value whose contents is TEXT, which should be
1946 a translatable string, but not actually translated yet, e.g. enclosed in
1947 N_(). This function is for text strings that are part of the PSPP user
1948 interface, such as names of procedures, statistics, annotations, error
1949 messages, etc. For strings that come from the user, use
1950 pivot_value_new_user_text(). */
1951 struct pivot_value *
1952 pivot_value_new_text (const char *text)
1954 char *c = xstrdup (text);
1955 char *local = xstrdup (gettext (c));
1957 struct pivot_value *value = xmalloc (sizeof *value);
1958 *value = (struct pivot_value) {
1959 .type = PIVOT_VALUE_TEXT,
1964 .user_provided = false,
1970 /* Same as pivot_value_new_text() but its argument is a printf()-like format
1972 struct pivot_value * PRINTF_FORMAT (1, 2)
1973 pivot_value_new_text_format (const char *format, ...)
1976 va_start (args, format);
1977 char *c = xvasprintf (format, args);
1980 va_start (args, format);
1981 char *local = xvasprintf (gettext (format), args);
1984 struct pivot_value *value = xmalloc (sizeof *value);
1985 *value = (struct pivot_value) {
1986 .type = PIVOT_VALUE_TEXT,
1991 .user_provided = false,
1998 xstrdup_if_nonempty (const char *s)
2000 return s && s[0] ? xstrdup (s) : NULL;
2003 /* Returns a new pivot_value that represents X.
2005 The format to use for X is unspecified. Usually the easiest way to specify
2006 a format is through assigning a result class to one of the categories that
2007 the pivot_value will end up in. If that is not suitable, then the caller
2008 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2009 struct pivot_value *
2010 pivot_value_new_number (double x)
2012 struct pivot_value *value = xmalloc (sizeof *value);
2013 *value = (struct pivot_value) {
2014 .type = PIVOT_VALUE_NUMERIC,
2015 .numeric = { .x = x, },
2020 /* Returns a new pivot_value that represents X, formatted as an integer. */
2021 struct pivot_value *
2022 pivot_value_new_integer (double x)
2024 struct pivot_value *value = pivot_value_new_number (x);
2025 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2029 /* Returns a new pivot_value that represents VALUE, formatted as for
2031 struct pivot_value *
2032 pivot_value_new_var_value (const struct variable *variable,
2033 const union value *value)
2035 struct pivot_value *pv = pivot_value_new_value (
2036 value, var_get_width (variable), var_get_print_format (variable),
2037 var_get_encoding (variable));
2039 char *var_name = xstrdup (var_get_name (variable));
2040 if (var_is_alpha (variable))
2041 pv->string.var_name = var_name;
2043 pv->numeric.var_name = var_name;
2045 const char *label = var_lookup_value_label (variable, value);
2048 if (var_is_alpha (variable))
2049 pv->string.value_label = xstrdup (label);
2051 pv->numeric.value_label = xstrdup (label);
2057 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2058 formatted with FORMAT. For a string value, ENCODING must be its character
2060 struct pivot_value *
2061 pivot_value_new_value (const union value *value, int width,
2062 const struct fmt_spec *format, const char *encoding)
2064 struct pivot_value *pv = xzalloc (sizeof *pv);
2067 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2069 size_t n = strlen (s);
2070 while (n > 0 && s[n - 1] == ' ')
2073 pv->type = PIVOT_VALUE_STRING;
2075 pv->string.hex = format->type == FMT_AHEX;
2079 pv->type = PIVOT_VALUE_NUMERIC;
2080 pv->numeric.x = value->f;
2081 pv->numeric.format = *format;
2087 /* Returns a new pivot_value for VARIABLE. */
2088 struct pivot_value *
2089 pivot_value_new_variable (const struct variable *variable)
2091 struct pivot_value *value = xmalloc (sizeof *value);
2092 *value = (struct pivot_value) {
2093 .type = PIVOT_VALUE_VARIABLE,
2095 .var_name = xstrdup (var_get_name (variable)),
2096 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2102 /* Attaches a reference to FOOTNOTE to V. */
2104 pivot_value_add_footnote (struct pivot_value *v,
2105 const struct pivot_footnote *footnote)
2107 v->footnotes = xrealloc (v->footnotes,
2108 (v->n_footnotes + 1) * sizeof *v->footnotes);
2109 v->footnotes[v->n_footnotes++] = footnote;
2112 /* If VALUE is a numeric value, and RC is a result class such as
2113 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2115 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2118 if (value->type == PIVOT_VALUE_NUMERIC)
2120 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2122 value->numeric.format = *f;