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);
642 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
643 table->title = title;
645 /* Set default area styles. */
646 #define STYLE(BOLD, H, V, L, R, T, B) { \
648 .halign = TABLE_HALIGN_##H, \
649 .valign = TABLE_VALIGN_##V, \
650 .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
651 [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
655 .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
656 .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
659 static const struct area_style default_area_styles[PIVOT_N_AREAS] = {
660 [PIVOT_AREA_TITLE] = STYLE( true, CENTER, CENTER, 8,11,1,8),
661 [PIVOT_AREA_CAPTION] = STYLE(false, LEFT, TOP, 8,11,1,1),
662 [PIVOT_AREA_FOOTER] = STYLE(false, LEFT, TOP, 11, 8,2,3),
663 [PIVOT_AREA_CORNER] = STYLE(false, LEFT, BOTTOM, 8,11,1,1),
664 [PIVOT_AREA_COLUMN_LABELS] = STYLE(false, CENTER, BOTTOM, 8,11,1,3),
665 [PIVOT_AREA_ROW_LABELS] = STYLE(false, LEFT, TOP, 8,11,1,3),
666 [PIVOT_AREA_DATA] = STYLE(false, MIXED, TOP, 8,11,1,1),
667 [PIVOT_AREA_LAYERS] = STYLE(false, LEFT, BOTTOM, 8,11,1,3),
670 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
671 table->areas[i] = default_area_styles[i];
673 /* Set default border styles. */
674 static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
675 [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE,
676 [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE,
677 [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE,
678 [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE,
679 [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
680 [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK,
681 [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK,
682 [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK,
683 [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
684 [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK,
685 [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK,
686 [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
687 [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
688 [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
689 [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
690 [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
691 [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
692 [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
693 [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
695 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
696 table->borders[i] = (struct table_border_style) {
697 .stroke = default_strokes[i],
698 .color = CELL_COLOR_BLACK,
701 table->row_labels_in_corner = true;
702 hmap_init (&table->cells);
707 /* Creates and returns a new pivot table with the given TITLE and a single cell
708 with the given CONTENT.
710 This is really just for error handling. */
712 pivot_table_create_for_text (struct pivot_value *title,
713 struct pivot_value *content)
715 struct pivot_table *table = pivot_table_create__ (title);
717 struct pivot_dimension *d = pivot_dimension_create (
718 table, PIVOT_AXIS_ROW, N_("Error"));
719 d->hide_all_labels = true;
720 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
722 pivot_table_put1 (table, 0, content);
727 /* Increases TABLE's reference count, indicating that it has an additional
728 owner. A pivot table that is shared among multiple owners must not be
731 pivot_table_ref (const struct pivot_table *table_)
733 struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
738 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
739 If TABLE no longer has any owners, it is freed. */
741 pivot_table_unref (struct pivot_table *table)
745 assert (table->ref_cnt > 0);
746 if (--table->ref_cnt)
749 free (table->current_layer);
750 free (table->table_look);
752 for (int i = 0; i < TABLE_N_AXES; i++)
753 pivot_table_sizing_uninit (&table->sizing[i]);
755 free (table->continuation);
757 for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
758 free (table->ccs[i]);
760 free (table->command_local);
761 free (table->command_c);
762 free (table->language);
763 free (table->locale);
765 free (table->dataset);
766 free (table->datafile);
768 for (size_t i = 0; i < table->n_footnotes; i++)
769 pivot_footnote_destroy (table->footnotes[i]);
770 free (table->footnotes);
772 pivot_value_destroy (table->title);
773 pivot_value_destroy (table->subtype);
774 pivot_value_destroy (table->corner_text);
775 pivot_value_destroy (table->caption);
777 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
778 area_style_uninit (&table->areas[i]);
780 for (size_t i = 0; i < table->n_dimensions; i++)
781 pivot_dimension_destroy (table->dimensions[i]);
782 free (table->dimensions);
784 for (size_t i = 0; i < PIVOT_N_AXES; i++)
785 free (table->axes[i].dimensions);
787 struct pivot_cell *cell, *next_cell;
788 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
791 hmap_delete (&table->cells, &cell->hmap_node);
792 pivot_value_destroy (cell->value);
795 hmap_destroy (&table->cells);
800 /* Returns true if TABLE has more than one owner. A pivot table that is shared
801 among multiple owners must not be modified. */
803 pivot_table_is_shared (const struct pivot_table *table)
805 return table->ref_cnt > 1;
808 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
809 WV, which should be the weight variable for the dictionary whose data or
810 statistics are being put into TABLE.
812 This has no effect if WV is NULL. */
814 pivot_table_set_weight_var (struct pivot_table *table,
815 const struct variable *wv)
818 pivot_table_set_weight_format (table, var_get_print_format (wv));
821 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
822 format for the dictionary whose data or statistics are being put into TABLE.
824 This has no effect if WFMT is NULL. */
826 pivot_table_set_weight_format (struct pivot_table *table,
827 const struct fmt_spec *wfmt)
830 table->weight_format = *wfmt;
833 /* Returns true if TABLE has no cells, false otherwise. */
835 pivot_table_is_empty (const struct pivot_table *table)
837 return hmap_is_empty (&table->cells);
841 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
843 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
847 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
849 for (size_t i = 0; i < n; i++)
856 static struct pivot_cell *
857 pivot_table_lookup_cell__ (const struct pivot_table *table,
858 const size_t *dindexes, unsigned int hash)
860 struct pivot_cell *cell;
861 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
863 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
868 static struct pivot_cell *
869 pivot_cell_allocate (size_t n_idx)
871 struct pivot_cell *cell UNUSED;
872 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
875 static struct pivot_cell *
876 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
878 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
879 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
882 cell = pivot_cell_allocate (table->n_dimensions);
883 for (size_t i = 0; i < table->n_dimensions; i++)
884 cell->idx[i] = dindexes[i];
886 hmap_insert (&table->cells, &cell->hmap_node, hash);
891 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
892 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
895 If VALUE is a numeric value without a specified format, this function checks
896 each of the categories designated by DINDEXES[] and takes the format from
897 the first category with a result class. If none has a result class, uses
898 the overall default numeric format. */
900 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
901 struct pivot_value *value)
903 assert (n == table->n_dimensions);
905 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
907 for (size_t i = 0; i < table->n_dimensions; i++)
909 const struct pivot_dimension *d = table->dimensions[i];
910 if (dindexes[i] < d->n_leaves)
912 const struct pivot_category *c = d->data_leaves[dindexes[i]];
915 value->numeric.format = c->format;
920 value->numeric.format = *settings_get_format ();
925 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
926 pivot_value_destroy (cell->value);
930 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
931 dimension. Takes ownership of VALUE. */
933 pivot_table_put1 (struct pivot_table *table, size_t idx1,
934 struct pivot_value *value)
936 size_t dindexes[] = { idx1 };
937 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
940 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
941 dimensions. Takes ownership of VALUE. */
943 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
944 struct pivot_value *value)
946 size_t dindexes[] = { idx1, idx2 };
947 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
950 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
951 have 3 dimensions. Takes ownership of VALUE. */
953 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
954 size_t idx3, struct pivot_value *value)
956 size_t dindexes[] = { idx1, idx2, idx3 };
957 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
960 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
961 must have 4 dimensions. Takes ownership of VALUE. */
963 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
964 size_t idx3, size_t idx4, struct pivot_value *value)
966 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
967 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
970 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
971 automatically assigned marker.
973 The footnote will only appear in output if it is referenced. Use
974 pivot_value_add_footnote() to add a reference to the footnote. */
975 struct pivot_footnote *
976 pivot_table_create_footnote (struct pivot_table *table,
977 struct pivot_value *content)
979 return pivot_table_create_footnote__ (table, table->n_footnotes,
983 static struct pivot_value *
984 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
986 char text[INT_BUFSIZE_BOUND (size_t)];
987 if (show_numeric_markers)
988 snprintf (text, sizeof text, "%d", idx + 1);
990 str_format_26adic (idx + 1, false, text, sizeof text);
991 return pivot_value_new_user_text (text, -1);
994 /* Creates or modifies a footnote in TABLE with 0-based number IDX. If MARKER
995 is nonnull, sets the footnote's marker; if CONTENT is nonnull, sets the
996 footnote's content. */
997 struct pivot_footnote *
998 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
999 struct pivot_value *marker,
1000 struct pivot_value *content)
1002 if (idx >= table->n_footnotes)
1004 while (idx >= table->allocated_footnotes)
1005 table->footnotes = x2nrealloc (table->footnotes,
1006 &table->allocated_footnotes,
1007 sizeof *table->footnotes);
1008 while (idx >= table->n_footnotes)
1010 struct pivot_footnote *f = xmalloc (sizeof *f);
1011 f->idx = table->n_footnotes;
1012 f->marker = pivot_make_default_footnote_marker (
1013 f->idx, table->show_numeric_markers);
1016 table->footnotes[table->n_footnotes++] = f;
1020 struct pivot_footnote *f = table->footnotes[idx];
1023 pivot_value_destroy (f->marker);
1028 pivot_value_destroy (f->content);
1029 f->content = content;
1034 /* Frees the data owned by F. */
1036 pivot_footnote_destroy (struct pivot_footnote *f)
1040 pivot_value_destroy (f->content);
1041 pivot_value_destroy (f->marker);
1046 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1047 indexes for each dimension in TABLE in DINDEXES[]. */
1049 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1050 const size_t *pindexes[PIVOT_N_AXES],
1051 size_t dindexes[/* table->n_dimensions */])
1053 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1055 const struct pivot_axis *axis = &table->axes[i];
1057 for (size_t j = 0; j < axis->n_dimensions; j++)
1059 const struct pivot_dimension *d = axis->dimensions[j];
1060 dindexes[d->top_index]
1061 = d->presentation_leaves[pindexes[i][j]]->data_index;
1067 pivot_table_enumerate_axis (const struct pivot_table *table,
1068 enum pivot_axis_type axis_type,
1069 const size_t *layer_indexes, bool omit_empty,
1072 const struct pivot_axis *axis = &table->axes[axis_type];
1073 if (!axis->n_dimensions)
1075 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1077 enumeration[1] = SIZE_MAX;
1082 else if (!axis->extent)
1084 size_t *enumeration = xmalloc (sizeof *enumeration);
1085 *enumeration = SIZE_MAX;
1091 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1092 axis->n_dimensions), 1),
1093 sizeof *enumeration);
1094 size_t *p = enumeration;
1095 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1097 size_t *axis_indexes;
1098 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1102 enum pivot_axis_type axis2_type
1103 = pivot_axis_type_transpose (axis_type);
1105 size_t *axis2_indexes;
1106 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1108 const size_t *pindexes[PIVOT_N_AXES];
1109 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1110 pindexes[axis_type] = axis_indexes;
1111 pindexes[axis2_type] = axis2_indexes;
1112 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1113 if (pivot_table_get (table, dindexes))
1119 free (axis2_indexes);
1122 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1123 p += axis->n_dimensions;
1127 *n = (p - enumeration) / axis->n_dimensions;
1133 static const struct pivot_cell *
1134 pivot_table_lookup_cell (const struct pivot_table *table,
1135 const size_t *dindexes)
1137 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1138 return pivot_table_lookup_cell__ (table, dindexes, hash);
1141 const struct pivot_value *
1142 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1144 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1145 return cell ? cell->value : NULL;
1148 struct pivot_value *
1149 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1151 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1153 cell->value = pivot_value_new_user_text ("", -1);
1158 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1160 if (pivot_category_is_group (category) && category->n_subs)
1161 for (size_t i = 0; i < category->n_subs; i++)
1162 distribute_extra_depth (category->subs[i], extra_depth);
1164 category->extra_depth += extra_depth;
1168 pivot_category_assign_label_depth (struct pivot_category *category,
1169 bool dimension_labels_in_corner)
1171 category->extra_depth = 0;
1173 if (pivot_category_is_group (category))
1176 for (size_t i = 0; i < category->n_subs; i++)
1178 pivot_category_assign_label_depth (category->subs[i], false);
1179 depth = MAX (depth, category->subs[i]->label_depth);
1182 for (size_t i = 0; i < category->n_subs; i++)
1184 struct pivot_category *sub = category->subs[i];
1186 size_t extra_depth = depth - sub->label_depth;
1188 distribute_extra_depth (sub, extra_depth);
1190 sub->label_depth = depth;
1193 category->show_label_in_corner = (category->show_label
1194 && dimension_labels_in_corner);
1195 category->label_depth
1196 = (category->show_label && !category->show_label_in_corner
1197 ? depth + 1 : depth);
1200 category->label_depth = 1;
1204 pivot_axis_assign_label_depth (struct pivot_table *table,
1205 enum pivot_axis_type axis_type,
1206 bool dimension_labels_in_corner)
1208 struct pivot_axis *axis = &table->axes[axis_type];
1209 bool any_label_shown_in_corner = false;
1210 axis->label_depth = 0;
1212 for (size_t i = 0; i < axis->n_dimensions; i++)
1214 struct pivot_dimension *d = axis->dimensions[i];
1215 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1216 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1217 axis->label_depth += d->label_depth;
1218 axis->extent *= d->n_leaves;
1220 if (d->root->show_label_in_corner)
1221 any_label_shown_in_corner = true;
1223 return any_label_shown_in_corner;
1227 pivot_table_assign_label_depth (struct pivot_table *table)
1229 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1230 if (pivot_axis_assign_label_depth (
1231 table, PIVOT_AXIS_ROW, (table->row_labels_in_corner
1232 && !table->corner_text))
1233 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1234 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1235 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1243 indent (int indentation)
1245 for (int i = 0; i < indentation * 2; i++)
1250 pivot_value_dump (const struct pivot_value *value)
1252 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1253 SETTINGS_VALUE_SHOW_DEFAULT);
1259 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1264 indent (indentation);
1265 printf ("%s: ", name);
1266 pivot_value_dump (value);
1272 pivot_table_dump_string (const char *string, const char *name, int indentation)
1276 indent (indentation);
1277 printf ("%s: %s\n", name, string);
1282 pivot_category_dump (const struct pivot_category *c, int indentation)
1284 indent (indentation);
1285 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1286 pivot_value_dump (c->name);
1289 if (pivot_category_is_leaf (c))
1290 printf ("data_index=%zu\n", c->data_index);
1293 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1296 for (size_t i = 0; i < c->n_subs; i++)
1297 pivot_category_dump (c->subs[i], indentation + 1);
1302 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1304 indent (indentation);
1305 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1306 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1308 pivot_category_dump (d->root, indentation + 1);
1312 area_style_dump (enum pivot_area area, const struct area_style *a,
1315 indent (indentation);
1316 printf ("%s: ", pivot_area_to_string (area));
1317 font_style_dump (&a->font_style);
1319 cell_style_dump (&a->cell_style);
1324 table_border_style_dump (enum pivot_border border,
1325 const struct table_border_style *b, int indentation)
1327 indent (indentation);
1328 printf ("%s: %s ", pivot_border_to_string (border),
1329 table_stroke_to_string (b->stroke));
1330 cell_color_dump (&b->color);
1335 compose_headings (const struct pivot_axis *axis,
1336 const size_t *column_enumeration,
1337 enum settings_value_show show_values,
1338 enum settings_value_show show_variables)
1340 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1343 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1344 for (size_t i = 0; i < axis->label_depth; i++)
1345 headings[i] = xcalloc (axis->extent, sizeof **headings);
1347 const size_t *indexes;
1349 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1351 int row = axis->label_depth - 1;
1352 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1354 const struct pivot_dimension *d = axis->dimensions[dim_index];
1355 if (d->hide_all_labels)
1357 for (const struct pivot_category *c
1358 = d->presentation_leaves[indexes[dim_index]];
1362 if (pivot_category_is_leaf (c) || (c->show_label
1363 && !c->show_label_in_corner))
1365 headings[row][column] = pivot_value_to_string (
1366 c->name, show_values, show_variables);
1367 if (!*headings[row][column])
1368 headings[row][column] = xstrdup ("<blank>");
1380 free_headings (const struct pivot_axis *axis, char ***headings)
1382 for (size_t i = 0; i < axis->label_depth; i++)
1384 for (size_t j = 0; j < axis->extent; j++)
1385 free (headings[i][j]);
1392 pivot_table_dump (const struct pivot_table *table, int indentation)
1397 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1398 if (table->decimal == '.' || table->decimal == ',')
1399 settings_set_decimal_char (table->decimal);
1401 pivot_table_dump_value (table->title, "title", indentation);
1402 pivot_table_dump_string (table->command_c, "command", indentation);
1403 pivot_table_dump_string (table->dataset, "dataset", indentation);
1404 pivot_table_dump_string (table->datafile, "datafile", indentation);
1405 pivot_table_dump_string (table->notes, "notes", indentation);
1406 pivot_table_dump_string (table->table_look, "table-look", indentation);
1409 indent (indentation);
1411 printf ("date: %s", ctime_r (&table->date, buf));
1414 indent (indentation);
1415 printf ("areas:\n");
1416 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1417 area_style_dump (area, &table->areas[area], indentation + 1);
1419 indent (indentation);
1420 printf ("borders:\n");
1421 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1422 table_border_style_dump (border, &table->borders[border], indentation + 1);
1424 for (size_t i = 0; i < table->n_dimensions; i++)
1425 pivot_dimension_dump (table->dimensions[i], indentation);
1427 /* Presentation and data indexes. */
1428 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1430 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1431 if (layer_axis->n_dimensions)
1433 indent (indentation);
1434 printf ("current layer:");
1436 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1438 const struct pivot_dimension *d = layer_axis->dimensions[i];
1439 char *name = pivot_value_to_string (d->root->name,
1441 table->show_variables);
1442 char *value = pivot_value_to_string (
1443 d->data_leaves[table->current_layer[i]]->name,
1444 table->show_values, table->show_variables);
1445 printf (" %s=%s", name, value);
1453 size_t *layer_indexes;
1454 size_t layer_iteration = 0;
1455 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1457 indent (indentation);
1458 printf ("layer %zu:", layer_iteration++);
1460 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1461 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1463 const struct pivot_dimension *d = layer_axis->dimensions[i];
1465 fputs (i == 0 ? " " : ", ", stdout);
1466 pivot_value_dump (d->root->name);
1467 fputs (" =", stdout);
1469 struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1472 for (const struct pivot_category *c
1473 = d->presentation_leaves[layer_indexes[i]];
1477 if (pivot_category_is_leaf (c) || c->show_label)
1478 names[n_names++] = c->name;
1481 for (size_t i = n_names; i-- > 0; )
1484 pivot_value_dump (names[i]);
1490 size_t *column_enumeration = pivot_table_enumerate_axis (
1491 table, PIVOT_AXIS_COLUMN, layer_indexes, table->omit_empty, NULL);
1492 size_t *row_enumeration = pivot_table_enumerate_axis (
1493 table, PIVOT_AXIS_ROW, layer_indexes, table->omit_empty, NULL);
1495 char ***column_headings = compose_headings (
1496 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1497 table->show_values, table->show_variables);
1498 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1500 indent (indentation + 1);
1501 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1504 fputs ("; ", stdout);
1505 if (column_headings[y][x])
1506 fputs (column_headings[y][x], stdout);
1510 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1512 indent (indentation + 1);
1513 printf ("-----------------------------------------------\n");
1515 char ***row_headings = compose_headings (
1516 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1517 table->show_values, table->show_variables);
1520 const size_t *pindexes[PIVOT_N_AXES]
1521 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1522 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1523 &table->axes[PIVOT_AXIS_ROW])
1525 indent (indentation + 1);
1528 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1531 fputs ("; ", stdout);
1532 if (row_headings[y][x])
1533 fputs (row_headings[y][x], stdout);
1539 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1541 &table->axes[PIVOT_AXIS_COLUMN])
1546 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1547 const struct pivot_value *value = pivot_table_get (
1550 pivot_value_dump (value);
1557 free (column_enumeration);
1558 free (row_enumeration);
1559 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1562 pivot_table_dump_value (table->caption, "caption", indentation);
1564 for (size_t i = 0; i < table->n_footnotes; i++)
1566 const struct pivot_footnote *f = table->footnotes[i];
1567 indent (indentation);
1570 pivot_value_dump (f->marker);
1572 printf ("%zu", f->idx);
1574 pivot_value_dump (f->content);
1579 settings_set_decimal_char (old_decimal);
1583 consume_int (const char *p, size_t *n)
1586 while (c_isdigit (*p))
1587 *n = *n * 10 + (*p++ - '0');
1592 pivot_format_inner_template (struct string *out, const char *template,
1594 struct pivot_value **values, size_t n_values,
1595 enum settings_value_show show_values,
1596 enum settings_value_show show_variables)
1598 size_t args_consumed = 0;
1599 while (*template && *template != ':')
1601 if (*template == '\\' && template[1])
1603 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1606 else if (*template == escape)
1609 template = consume_int (template + 1, &index);
1610 if (index >= 1 && index <= n_values)
1612 pivot_value_format (values[index - 1], show_values,
1613 show_variables, out);
1614 args_consumed = MAX (args_consumed, index);
1618 ds_put_byte (out, *template++);
1620 return args_consumed;
1624 pivot_extract_inner_template (const char *template, const char **p)
1630 if (*template == '\\' && template[1] != '\0')
1632 else if (*template == ':')
1633 return template + 1;
1634 else if (*template == '\0')
1642 pivot_format_template (struct string *out, const char *template,
1643 const struct pivot_argument *args, size_t n_args,
1644 enum settings_value_show show_values,
1645 enum settings_value_show show_variables)
1649 if (*template == '\\' && template[1] != '\0')
1651 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1654 else if (*template == '^')
1657 template = consume_int (template + 1, &index);
1658 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1659 pivot_value_format (args[index - 1].values[0],
1660 show_values, show_variables, out);
1662 else if (*template == '[')
1664 const char *tmpl[2];
1665 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1666 template = pivot_extract_inner_template (template, &tmpl[1]);
1667 template += *template == ']';
1670 template = consume_int (template, &index);
1671 if (index < 1 || index > n_args)
1674 const struct pivot_argument *arg = &args[index - 1];
1675 size_t left = arg->n;
1678 struct pivot_value **values = arg->values + (arg->n - left);
1679 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1680 char escape = "%^"[tmpl_idx];
1681 size_t used = pivot_format_inner_template (
1682 out, tmpl[tmpl_idx], escape, values, left,
1683 show_values, show_variables);
1684 if (!used || used > left)
1690 ds_put_byte (out, *template++);
1694 static enum settings_value_show
1695 interpret_show (enum settings_value_show global_show,
1696 enum settings_value_show table_show,
1697 enum settings_value_show value_show,
1700 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1701 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1702 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1706 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1707 SHOW_VARIABLES control whether variable and value labels are included.
1709 The "body" omits subscripts and superscripts and footnotes. */
1711 pivot_value_format_body (const struct pivot_value *value,
1712 enum settings_value_show show_values,
1713 enum settings_value_show show_variables,
1716 enum settings_value_show show;
1717 bool numeric = false;
1719 switch (value->type)
1721 case PIVOT_VALUE_NUMERIC:
1722 show = interpret_show (settings_get_show_values (),
1724 value->numeric.show,
1725 value->numeric.value_label != NULL);
1726 if (show & SETTINGS_VALUE_SHOW_VALUE)
1728 char *s = data_out (&(union value) { .f = value->numeric.x },
1729 "UTF-8", &value->numeric.format);
1730 ds_put_cstr (out, s + strspn (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->numeric.value_label);
1739 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1742 case PIVOT_VALUE_STRING:
1743 show = interpret_show (settings_get_show_values (),
1746 value->string.value_label != NULL);
1747 if (show & SETTINGS_VALUE_SHOW_VALUE)
1749 if (value->string.hex)
1751 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1753 ds_put_format (out, "%02X", *p);
1756 ds_put_cstr (out, value->string.s);
1758 if (show & SETTINGS_VALUE_SHOW_LABEL)
1760 if (show & SETTINGS_VALUE_SHOW_VALUE)
1761 ds_put_byte (out, ' ');
1762 ds_put_cstr (out, value->string.value_label);
1766 case PIVOT_VALUE_VARIABLE:
1767 show = interpret_show (settings_get_show_variables (),
1769 value->variable.show,
1770 value->variable.var_label != NULL);
1771 if (show & SETTINGS_VALUE_SHOW_VALUE)
1772 ds_put_cstr (out, value->variable.var_name);
1773 if (show & SETTINGS_VALUE_SHOW_LABEL)
1775 if (show & SETTINGS_VALUE_SHOW_VALUE)
1776 ds_put_byte (out, ' ');
1777 ds_put_cstr (out, value->variable.var_label);
1781 case PIVOT_VALUE_TEXT:
1782 ds_put_cstr (out, value->text.local);
1785 case PIVOT_VALUE_TEMPLATE:
1786 pivot_format_template (out, value->template.s, value->template.args,
1787 value->template.n_args, show_values,
1795 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
1796 SHOW_VARIABLES control whether variable and value labels are included.
1798 Subscripts and superscripts and footnotes are included. */
1800 pivot_value_format (const struct pivot_value *value,
1801 enum settings_value_show show_values,
1802 enum settings_value_show show_variables,
1805 pivot_value_format_body ( value, show_values, show_variables, out);
1807 if (value->subscript)
1808 ds_put_format (out, "_%s", value->subscript);
1810 if (value->superscript)
1811 ds_put_format (out, "^%s", value->superscript);
1813 for (size_t i = 0; i < value->n_footnotes; i++)
1815 ds_put_byte (out, '^');
1816 pivot_value_format (value->footnotes[i]->marker,
1817 show_values, show_variables, out);
1821 /* Returns a text representation of VALUE. The caller must free the string,
1824 pivot_value_to_string (const struct pivot_value *value,
1825 enum settings_value_show show_values,
1826 enum settings_value_show show_variables)
1828 struct string s = DS_EMPTY_INITIALIZER;
1829 pivot_value_format (value, show_values, show_variables, &s);
1830 return ds_steal_cstr (&s);
1833 /* Frees the data owned by V. */
1835 pivot_value_destroy (struct pivot_value *value)
1839 font_style_uninit (value->font_style);
1840 free (value->font_style);
1841 free (value->cell_style);
1842 /* Do not free the elements of footnotes because VALUE does not own
1844 free (value->footnotes);
1845 free (value->subscript);
1847 switch (value->type)
1849 case PIVOT_VALUE_NUMERIC:
1850 free (value->numeric.var_name);
1851 free (value->numeric.value_label);
1854 case PIVOT_VALUE_STRING:
1855 free (value->string.s);
1856 free (value->string.var_name);
1857 free (value->string.value_label);
1860 case PIVOT_VALUE_VARIABLE:
1861 free (value->variable.var_name);
1862 free (value->variable.var_label);
1865 case PIVOT_VALUE_TEXT:
1866 free (value->text.local);
1867 if (value->text.c != value->text.local)
1868 free (value->text.c);
1869 if (value->text.id != value->text.local
1870 && value->text.id != value->text.c)
1871 free (value->text.id);
1874 case PIVOT_VALUE_TEMPLATE:
1875 free (value->template.s);
1876 for (size_t i = 0; i < value->template.n_args; i++)
1877 pivot_argument_uninit (&value->template.args[i]);
1878 free (value->template.args);
1885 /* Sets AREA to the style to use for VALUE, with defaults coming from
1886 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
1888 pivot_value_get_style (struct pivot_value *value,
1889 const struct area_style *default_style,
1890 struct area_style *area)
1892 font_style_copy (&area->font_style, (value->font_style
1894 : &default_style->font_style));
1895 area->cell_style = (value->cell_style
1896 ? *value->cell_style
1897 : default_style->cell_style);
1900 /* Copies AREA into VALUE's style. */
1902 pivot_value_set_style (struct pivot_value *value,
1903 const struct area_style *area)
1905 if (value->font_style)
1906 font_style_uninit (value->font_style);
1908 value->font_style = xmalloc (sizeof *value->font_style);
1909 font_style_copy (value->font_style, &area->font_style);
1911 if (!value->cell_style)
1912 value->cell_style = xmalloc (sizeof *value->cell_style);
1913 *value->cell_style = area->cell_style;
1916 /* Frees the data owned by ARG (but not ARG itself). */
1918 pivot_argument_uninit (struct pivot_argument *arg)
1922 for (size_t i = 0; i < arg->n; i++)
1923 pivot_value_destroy (arg->values[i]);
1928 /* Creates and returns a new pivot_value whose contents is the null-terminated
1929 string TEXT. Takes ownership of TEXT.
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(). */
1936 struct pivot_value *
1937 pivot_value_new_user_text_nocopy (char *text)
1939 struct pivot_value *value = xmalloc (sizeof *value);
1940 *value = (struct pivot_value) {
1941 .type = PIVOT_VALUE_TEXT,
1946 .user_provided = true,
1952 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
1953 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
1956 This function is for text strings provided by the user (with the exception
1957 that pivot_value_new_variable() should be used for variable names). For
1958 strings that are part of the PSPP user interface, such as names of
1959 procedures, statistics, annotations, error messages, etc., use
1960 pivot_value_new_text().j
1962 The caller retains ownership of TEXT.*/
1963 struct pivot_value *
1964 pivot_value_new_user_text (const char *text, size_t length)
1966 return pivot_value_new_user_text_nocopy (
1967 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
1970 /* Creates and returns new pivot_value whose contents is TEXT, which should be
1971 a translatable string, but not actually translated yet, e.g. enclosed in
1972 N_(). This function is for text strings that are part of the PSPP user
1973 interface, such as names of procedures, statistics, annotations, error
1974 messages, etc. For strings that come from the user, use
1975 pivot_value_new_user_text(). */
1976 struct pivot_value *
1977 pivot_value_new_text (const char *text)
1979 char *c = xstrdup (text);
1980 char *local = xstrdup (gettext (c));
1982 struct pivot_value *value = xmalloc (sizeof *value);
1983 *value = (struct pivot_value) {
1984 .type = PIVOT_VALUE_TEXT,
1989 .user_provided = false,
1995 /* Same as pivot_value_new_text() but its argument is a printf()-like format
1997 struct pivot_value * PRINTF_FORMAT (1, 2)
1998 pivot_value_new_text_format (const char *format, ...)
2001 va_start (args, format);
2002 char *c = xvasprintf (format, args);
2005 va_start (args, format);
2006 char *local = xvasprintf (gettext (format), args);
2009 struct pivot_value *value = xmalloc (sizeof *value);
2010 *value = (struct pivot_value) {
2011 .type = PIVOT_VALUE_TEXT,
2016 .user_provided = false,
2023 xstrdup_if_nonempty (const char *s)
2025 return s && s[0] ? xstrdup (s) : NULL;
2028 /* Returns a new pivot_value that represents X.
2030 The format to use for X is unspecified. Usually the easiest way to specify
2031 a format is through assigning a result class to one of the categories that
2032 the pivot_value will end up in. If that is not suitable, then the caller
2033 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2034 struct pivot_value *
2035 pivot_value_new_number (double x)
2037 struct pivot_value *value = xmalloc (sizeof *value);
2038 *value = (struct pivot_value) {
2039 .type = PIVOT_VALUE_NUMERIC,
2040 .numeric = { .x = x, },
2045 /* Returns a new pivot_value that represents X, formatted as an integer. */
2046 struct pivot_value *
2047 pivot_value_new_integer (double x)
2049 struct pivot_value *value = pivot_value_new_number (x);
2050 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2054 /* Returns a new pivot_value that represents VALUE, formatted as for
2056 struct pivot_value *
2057 pivot_value_new_var_value (const struct variable *variable,
2058 const union value *value)
2060 struct pivot_value *pv = pivot_value_new_value (
2061 value, var_get_width (variable), var_get_print_format (variable),
2062 var_get_encoding (variable));
2064 char *var_name = xstrdup (var_get_name (variable));
2065 if (var_is_alpha (variable))
2066 pv->string.var_name = var_name;
2068 pv->numeric.var_name = var_name;
2070 const char *label = var_lookup_value_label (variable, value);
2073 if (var_is_alpha (variable))
2074 pv->string.value_label = xstrdup (label);
2076 pv->numeric.value_label = xstrdup (label);
2082 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2083 formatted with FORMAT. For a string value, ENCODING must be its character
2085 struct pivot_value *
2086 pivot_value_new_value (const union value *value, int width,
2087 const struct fmt_spec *format, const char *encoding)
2089 struct pivot_value *pv = xzalloc (sizeof *pv);
2092 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2094 size_t n = strlen (s);
2095 while (n > 0 && s[n - 1] == ' ')
2098 pv->type = PIVOT_VALUE_STRING;
2100 pv->string.hex = format->type == FMT_AHEX;
2104 pv->type = PIVOT_VALUE_NUMERIC;
2105 pv->numeric.x = value->f;
2106 pv->numeric.format = *format;
2112 /* Returns a new pivot_value for VARIABLE. */
2113 struct pivot_value *
2114 pivot_value_new_variable (const struct variable *variable)
2116 struct pivot_value *value = xmalloc (sizeof *value);
2117 *value = (struct pivot_value) {
2118 .type = PIVOT_VALUE_VARIABLE,
2120 .var_name = xstrdup (var_get_name (variable)),
2121 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2127 /* Attaches a reference to FOOTNOTE to V. */
2129 pivot_value_add_footnote (struct pivot_value *v,
2130 const struct pivot_footnote *footnote)
2132 v->footnotes = xrealloc (v->footnotes,
2133 (v->n_footnotes + 1) * sizeof *v->footnotes);
2134 v->footnotes[v->n_footnotes++] = footnote;
2137 /* If VALUE is a numeric value, and RC is a result class such as
2138 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2140 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2143 if (value->type == PIVOT_VALUE_NUMERIC)
2145 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2147 value->numeric.format = *f;