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"
21 #include <libxml/parser.h>
22 #include <libxml/tree.h>
26 #include "data/data-out.h"
27 #include "data/settings.h"
28 #include "data/value.h"
29 #include "data/variable.h"
30 #include "data/file-name.h"
31 #include "libpspp/array.h"
32 #include "libpspp/assertion.h"
33 #include "libpspp/hash-functions.h"
34 #include "libpspp/i18n.h"
35 #include "output/driver.h"
36 #include "output/spv/spv-table-look.h"
38 #include "gl/c-ctype.h"
39 #include "gl/configmake.h"
40 #include "gl/intprops.h"
41 #include "gl/minmax.h"
42 #include "gl/relocatable.h"
43 #include "gl/xalloc.h"
44 #include "gl/xmemdup0.h"
48 #define _(msgid) gettext (msgid)
49 #define N_(msgid) msgid
51 static void pivot_table_use_rc (const struct pivot_table *, const char *s,
52 struct fmt_spec *, bool *honor_small);
54 /* Pivot table display styling. */
56 /* Returns the name of AREA. */
58 pivot_area_to_string (enum pivot_area area)
62 case PIVOT_AREA_TITLE: return "title";
63 case PIVOT_AREA_CAPTION: return "caption";
64 case PIVOT_AREA_FOOTER: return "footer";
65 case PIVOT_AREA_CORNER: return "corner";
66 case PIVOT_AREA_COLUMN_LABELS: return "column labels";
67 case PIVOT_AREA_ROW_LABELS: return "row labels";
68 case PIVOT_AREA_DATA: return "data";
69 case PIVOT_AREA_LAYERS: return "layers";
70 case PIVOT_N_AREAS: default: return "**error**";
74 /* Returns the name of BORDER. */
76 pivot_border_to_string (enum pivot_border border)
80 case PIVOT_BORDER_TITLE:
83 case PIVOT_BORDER_OUTER_LEFT:
84 return "left outer frame";
85 case PIVOT_BORDER_OUTER_TOP:
86 return "top outer frame";
87 case PIVOT_BORDER_OUTER_RIGHT:
88 return "right outer frame";
89 case PIVOT_BORDER_OUTER_BOTTOM:
90 return "bottom outer frame";
92 case PIVOT_BORDER_INNER_LEFT:
93 return "left inner frame";
94 case PIVOT_BORDER_INNER_TOP:
95 return "top inner frame";
96 case PIVOT_BORDER_INNER_RIGHT:
97 return "right inner frame";
98 case PIVOT_BORDER_INNER_BOTTOM:
99 return "bottom inner frame";
101 case PIVOT_BORDER_DATA_LEFT:
102 return "data area left";
103 case PIVOT_BORDER_DATA_TOP:
104 return "data area top";
106 case PIVOT_BORDER_DIM_ROW_HORZ:
107 return "row label horizontal dimension border";
108 case PIVOT_BORDER_DIM_ROW_VERT:
109 return "row label vertical dimension border";
110 case PIVOT_BORDER_DIM_COL_HORZ:
111 return "column label horizontal dimension border";
112 case PIVOT_BORDER_DIM_COL_VERT:
113 return "column label vertical dimension border";
115 case PIVOT_BORDER_CAT_ROW_HORZ:
116 return "row label horizontal category border";
117 case PIVOT_BORDER_CAT_ROW_VERT:
118 return "row label vertical category border";
119 case PIVOT_BORDER_CAT_COL_HORZ:
120 return "column label horizontal category border";
121 case PIVOT_BORDER_CAT_COL_VERT:
122 return "column label vertical category border";
124 case PIVOT_N_BORDERS:
131 pivot_table_sizing_uninit (struct pivot_table_sizing *sizing)
135 free (sizing->widths);
136 free (sizing->breaks);
137 free (sizing->keeps);
141 /* Pivot table looks. */
143 static const struct pivot_table_look *
144 default_look (const struct pivot_table_look *new)
146 static struct pivot_table_look *look;
149 pivot_table_look_unref (look);
150 look = pivot_table_look_ref (new);
154 char *error = pivot_table_look_read ("default.stt", &look);
158 look = pivot_table_look_ref (pivot_table_look_builtin_default ());
164 const struct pivot_table_look *
165 pivot_table_look_get_default (void)
167 return default_look (NULL);
171 pivot_table_look_set_default (const struct pivot_table_look *look)
176 char * WARN_UNUSED_RESULT
177 pivot_table_look_read (const char *name, struct pivot_table_look **lookp)
181 /* Construct search path. */
185 const char *home = getenv ("HOME");
186 char *allocated = NULL;
188 path[n++] = allocated = xasprintf ("%s/.pspp/looks", home);
190 path[n++] = relocate2 (PKGDATADIR "/looks", &allocated2);
194 char *file = fn_search_path (name, (char **) path);
197 char *name2 = xasprintf ("%s.stt", name);
198 file = fn_search_path (name2, (char **) path);
204 return xasprintf ("%s: not found", name);
207 char *error = spv_table_look_read (file, lookp);
212 const struct pivot_table_look *
213 pivot_table_look_builtin_default (void)
215 static struct pivot_table_look look = {
219 .row_labels_in_corner = true,
221 [TABLE_HORZ] = { 36, 72 },
222 [TABLE_VERT] = { 36, 120 },
226 #define AREA(BOLD, H, V, L, R, T, B) { \
228 .halign = TABLE_HALIGN_##H, \
229 .valign = TABLE_VALIGN_##V, \
230 .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
231 [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
235 .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
236 .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
238 .typeface = (char *) "Sans Serif", \
241 [PIVOT_AREA_TITLE] = AREA(true, CENTER, CENTER, 8,11,1,8),
242 [PIVOT_AREA_CAPTION] = AREA(false, LEFT, TOP, 8,11,1,1),
243 [PIVOT_AREA_FOOTER] = AREA(false, LEFT, TOP, 11, 8,2,3),
244 [PIVOT_AREA_CORNER] = AREA(false, LEFT, BOTTOM, 8,11,1,1),
245 [PIVOT_AREA_COLUMN_LABELS] = AREA(false, CENTER, BOTTOM, 8,11,1,3),
246 [PIVOT_AREA_ROW_LABELS] = AREA(false, LEFT, TOP, 8,11,1,3),
247 [PIVOT_AREA_DATA] = AREA(false, MIXED, TOP, 8,11,1,1),
248 [PIVOT_AREA_LAYERS] = AREA(false, LEFT, BOTTOM, 8,11,1,3),
253 #define BORDER(STROKE) { .stroke = STROKE, .color = CELL_COLOR_BLACK }
254 [PIVOT_BORDER_TITLE] = BORDER(TABLE_STROKE_NONE),
255 [PIVOT_BORDER_OUTER_LEFT] = BORDER(TABLE_STROKE_NONE),
256 [PIVOT_BORDER_OUTER_TOP] = BORDER(TABLE_STROKE_NONE),
257 [PIVOT_BORDER_OUTER_RIGHT] = BORDER(TABLE_STROKE_NONE),
258 [PIVOT_BORDER_OUTER_BOTTOM] = BORDER(TABLE_STROKE_NONE),
259 [PIVOT_BORDER_INNER_LEFT] = BORDER(TABLE_STROKE_THICK),
260 [PIVOT_BORDER_INNER_TOP] = BORDER(TABLE_STROKE_THICK),
261 [PIVOT_BORDER_INNER_RIGHT] = BORDER(TABLE_STROKE_THICK),
262 [PIVOT_BORDER_INNER_BOTTOM] = BORDER(TABLE_STROKE_THICK),
263 [PIVOT_BORDER_DATA_LEFT] = BORDER(TABLE_STROKE_THICK),
264 [PIVOT_BORDER_DATA_TOP] = BORDER(TABLE_STROKE_THICK),
265 [PIVOT_BORDER_DIM_ROW_HORZ] = BORDER(TABLE_STROKE_SOLID),
266 [PIVOT_BORDER_DIM_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
267 [PIVOT_BORDER_DIM_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
268 [PIVOT_BORDER_DIM_COL_VERT] = BORDER(TABLE_STROKE_SOLID),
269 [PIVOT_BORDER_CAT_ROW_HORZ] = BORDER(TABLE_STROKE_NONE),
270 [PIVOT_BORDER_CAT_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
271 [PIVOT_BORDER_CAT_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
272 [PIVOT_BORDER_CAT_COL_VERT] = BORDER(TABLE_STROKE_SOLID),
279 struct pivot_table_look *
280 pivot_table_look_new_builtin_default (void)
282 return pivot_table_look_unshare (
283 pivot_table_look_ref (pivot_table_look_builtin_default ()));
286 struct pivot_table_look *
287 pivot_table_look_ref (const struct pivot_table_look *look_)
289 assert (look_->ref_cnt > 0);
291 struct pivot_table_look *look = CONST_CAST (struct pivot_table_look *, look_);
297 xstrdup_if_nonempty (const char *s)
299 return s && s[0] ? xstrdup (s) : NULL;
302 struct pivot_table_look *
303 pivot_table_look_unshare (struct pivot_table_look *old)
305 assert (old->ref_cnt > 0);
306 if (old->ref_cnt == 1)
309 pivot_table_look_unref (old);
311 struct pivot_table_look *new = xmemdup (old, sizeof *old);
313 new->name = xstrdup_if_nonempty (old->name);
314 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
315 table_area_style_copy (NULL, &new->areas[i], &old->areas[i]);
316 new->continuation = xstrdup_if_nonempty (old->continuation);
322 pivot_table_look_unref (struct pivot_table_look *look)
326 assert (look->ref_cnt > 0);
327 if (!--look->ref_cnt)
330 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
331 table_area_style_uninit (&look->areas[i]);
332 free (look->continuation);
340 /* Returns the name of AXIS_TYPE. */
342 pivot_axis_type_to_string (enum pivot_axis_type axis_type)
346 case PIVOT_AXIS_LAYER:
352 case PIVOT_AXIS_COLUMN:
360 static enum pivot_axis_type
361 pivot_axis_type_transpose (enum pivot_axis_type axis_type)
363 assert (axis_type == PIVOT_AXIS_ROW || axis_type == PIVOT_AXIS_COLUMN);
364 return (axis_type == PIVOT_AXIS_ROW ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW);
367 /* Implementation of PIVOT_AXIS_FOR_EACH. */
369 pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis)
373 if (axis->n_dimensions)
374 for (size_t i = 0; i < axis->n_dimensions; i++)
375 if (axis->dimensions[i]->n_leaves == 0)
378 size_t size = axis->n_dimensions * sizeof *indexes;
379 return xzalloc (MAX (size, 1));
382 for (size_t i = 0; i < axis->n_dimensions; i++)
384 const struct pivot_dimension *d = axis->dimensions[i];
385 if (++indexes[i] < d->n_leaves)
398 pivot_category_set_rc (struct pivot_category *category, const char *s)
403 pivot_table_use_rc (category->dimension->table, s,
404 &category->format, &category->honor_small);
406 /* Ensure that the category itself, in addition to the cells within it, takes
407 the format. (It's kind of rare for a category to have a numeric format
409 struct pivot_value *name = category->name;
410 if (name->type == PIVOT_VALUE_NUMERIC && !name->numeric.format.w)
411 pivot_table_use_rc (category->dimension->table, s,
412 &name->numeric.format, &name->numeric.honor_small);
416 pivot_category_create_leaves_valist (struct pivot_category *parent,
420 while ((s = va_arg (args, const char *)))
422 if (!strncmp (s, "RC_", 3))
424 assert (parent->n_subs);
425 pivot_category_set_rc (parent->subs[parent->n_subs - 1], s);
428 pivot_category_create_leaf (parent, pivot_value_new_text (s));
432 /* Creates a new dimension with the given NAME in TABLE and returns it. The
433 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
436 NAME should be a translatable name, but not actually translated yet,
437 e.g. enclosed in N_(). To use a different kind of value for a name, use
438 pivot_dimension_create__() instead.
440 The optional varargs parameters may be used to add an initial set of
441 categories to the dimension. Each string should be a translatable category
442 name, but not actually translated yet, e.g. enclosed in N_(). Each string
443 may optionally be followod by a PIVOT_RC_* string that specifies the default
444 numeric format for cells in this category. */
445 struct pivot_dimension * SENTINEL (0)
446 (pivot_dimension_create) (struct pivot_table *table,
447 enum pivot_axis_type axis_type,
448 const char *name, ...)
450 struct pivot_dimension *d = pivot_dimension_create__ (
451 table, axis_type, pivot_value_new_text (name));
454 va_start (args, name);
455 pivot_category_create_leaves_valist (d->root, args);
461 /* Creates a new dimension with the given NAME in TABLE and returns it. The
462 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
464 struct pivot_dimension *
465 pivot_dimension_create__ (struct pivot_table *table,
466 enum pivot_axis_type axis_type,
467 struct pivot_value *name)
469 assert (pivot_table_is_empty (table));
471 struct pivot_dimension *d = xmalloc (sizeof *d);
472 *d = (struct pivot_dimension) {
474 .axis_type = axis_type,
475 .level = table->axes[axis_type].n_dimensions,
476 .top_index = table->n_dimensions,
477 .root = xmalloc (sizeof *d->root),
480 struct pivot_category *root = d->root;
481 *root = (struct pivot_category) {
486 .data_index = SIZE_MAX,
487 .presentation_index = SIZE_MAX,
490 table->dimensions = xrealloc (
491 table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions);
492 table->dimensions[table->n_dimensions++] = d;
494 struct pivot_axis *axis = &table->axes[axis_type];
495 axis->dimensions = xrealloc (
496 axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
497 axis->dimensions[axis->n_dimensions++] = d;
499 if (axis_type == PIVOT_AXIS_LAYER)
501 free (table->current_layer);
502 table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
503 sizeof *table->current_layer);
506 /* axis->extent and axis->label_depth will be calculated later. */
512 pivot_dimension_destroy (struct pivot_dimension *d)
517 pivot_category_destroy (d->root);
518 free (d->data_leaves);
519 free (d->presentation_leaves);
523 /* Returns the first leaf node in an in-order traversal that is a child of
525 static const struct pivot_category * UNUSED
526 pivot_category_first_leaf (const struct pivot_category *cat)
528 if (pivot_category_is_leaf (cat))
531 for (size_t i = 0; i < cat->n_subs; i++)
533 const struct pivot_category *first
534 = pivot_category_first_leaf (cat->subs[i]);
542 /* Returns the next leaf node in an in-order traversal starting at CAT, which
544 static const struct pivot_category * UNUSED
545 pivot_category_next_leaf (const struct pivot_category *cat)
547 assert (pivot_category_is_leaf (cat));
551 const struct pivot_category *parent = cat->parent;
554 for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
556 const struct pivot_category *next
557 = pivot_category_first_leaf (parent->subs[i]);
567 pivot_category_add_child (struct pivot_category *child)
569 struct pivot_category *parent = child->parent;
571 assert (pivot_category_is_group (parent));
572 if (parent->n_subs >= parent->allocated_subs)
573 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
574 sizeof *parent->subs);
575 parent->subs[parent->n_subs++] = child;
578 /* Adds leaf categories as a child of PARENT. To create top-level categories
579 within dimension 'd', pass 'd->root' for PARENT.
581 Each of the varargs parameters should be a string, each of which should be a
582 translatable category name, but not actually translated yet, e.g. enclosed
583 in N_(). Each string may optionally be followod by a PIVOT_RC_* string that
584 specifies the default numeric format for cells in this category.
586 Returns the category index, which is just a 0-based array index, for the
589 Leaves have to be created in in-order, that is, don't create a group and add
590 some leaves, then add leaves outside the group and try to add more leaves
593 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
595 int retval = parent->dimension->n_leaves;
598 va_start (args, parent);
599 pivot_category_create_leaves_valist (parent, args);
605 /* Creates a new leaf category with the given NAME as a child of PARENT. To
606 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
607 Returns the category index, which is just a 0-based array index, for the new
610 Leaves have to be created in in-order, that is, don't create a group and add
611 some leaves, then add leaves outside the group and try to add more leaves
614 pivot_category_create_leaf (struct pivot_category *parent,
615 struct pivot_value *name)
617 return pivot_category_create_leaf_rc (parent, name, NULL);
620 /* Creates a new leaf category with the given NAME as a child of PARENT. To
621 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
622 Returns the category index, which is just a 0-based array index, for the new
625 If RC is nonnull and the name of a result category, the category is assigned
626 that result category.
628 Leaves have to be created in in-order, that is, don't create a group and add
629 some leaves, then add leaves outside the group and try to add more leaves
632 pivot_category_create_leaf_rc (struct pivot_category *parent,
633 struct pivot_value *name, const char *rc)
635 struct pivot_dimension *d = parent->dimension;
637 struct pivot_category *leaf = xmalloc (sizeof *leaf);
638 *leaf = (struct pivot_category) {
642 .group_index = parent->n_subs,
643 .data_index = d->n_leaves,
644 .presentation_index = d->n_leaves,
647 if (d->n_leaves >= d->allocated_leaves)
649 d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
650 sizeof *d->data_leaves);
651 d->presentation_leaves = xrealloc (
652 d->presentation_leaves,
653 d->allocated_leaves * sizeof *d->presentation_leaves);
656 d->data_leaves[d->n_leaves] = leaf;
657 d->presentation_leaves[d->n_leaves] = leaf;
660 pivot_category_add_child (leaf);
662 /* Make sure that the new child is the last in in-order. */
663 assert (!pivot_category_next_leaf (leaf));
665 pivot_category_set_rc (leaf, rc);
667 return leaf->data_index;
670 /* Adds a new category group named NAME as a child of PARENT. To create a
671 top-level group within dimension 'd', pass 'd->root' for PARENT.
673 NAME should be a translatable name, but not actually translated yet,
674 e.g. enclosed in N_(). To use a different kind of value for a name, use
675 pivot_category_create_group__() instead.
677 The optional varargs parameters may be used to add an initial set of
678 categories to the group. Each string should be a translatable category
679 name, but not actually translated yet, e.g. enclosed in N_(). Each string
680 may optionally be followod by a PIVOT_RC_* string that specifies the default
681 numeric format for cells in this category.
683 Returns the new group. */
684 struct pivot_category * SENTINEL (0)
685 (pivot_category_create_group) (struct pivot_category *parent,
686 const char *name, ...)
688 struct pivot_category *group = pivot_category_create_group__ (
689 parent, pivot_value_new_text (name));
692 va_start (args, name);
693 pivot_category_create_leaves_valist (group, args);
699 /* Adds a new category group named NAME as a child of PARENT. To create a
700 top-level group within dimension 'd', pass 'd->root' for PARENT. Returns
702 struct pivot_category *
703 pivot_category_create_group__ (struct pivot_category *parent,
704 struct pivot_value *name)
706 struct pivot_dimension *d = parent->dimension;
708 struct pivot_category *group = xmalloc (sizeof *group);
709 *group = (struct pivot_category) {
714 .group_index = parent->n_subs,
715 .data_index = SIZE_MAX,
716 .presentation_index = SIZE_MAX,
719 pivot_category_add_child (group);
725 pivot_category_destroy (struct pivot_category *c)
730 pivot_value_destroy (c->name);
731 for (size_t i = 0; i < c->n_subs; i++)
732 pivot_category_destroy (c->subs[i]);
739 These are usually the easiest way to control the formatting of numeric data
740 in a pivot table. See pivot_dimension_create() for an explanation of their
744 const char *name; /* "RC_*". */
745 struct fmt_spec format;
748 /* Formats for most of the result classes. */
749 static struct result_class result_classes[] =
751 { PIVOT_RC_INTEGER, { .type = FMT_F, .w = 40, .d = 0 } },
752 { PIVOT_RC_PERCENT, { .type = FMT_PCT, .w = 40, .d = 1 } },
753 { PIVOT_RC_CORRELATION, { .type = FMT_F, .w = 40, .d = 3 } },
754 { PIVOT_RC_SIGNIFICANCE, { .type = FMT_F, .w = 40, .d = 3 } },
755 { PIVOT_RC_RESIDUAL, { .type = FMT_F, .w = 40, .d = 2 } },
756 { PIVOT_RC_COUNT, { 0, 0, 0 } },
757 { PIVOT_RC_OTHER, { 0, 0, 0 } },
760 /* Has PIVOT_RC_COUNT been overridden by the user? */
761 static bool overridden_count_format;
763 static struct result_class *
764 pivot_result_class_find (const char *s)
766 for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
767 if (!strcmp (s, result_classes[i].name))
768 return &result_classes[i];
773 pivot_table_use_rc (const struct pivot_table *table, const char *s,
774 struct fmt_spec *format, bool *honor_small)
778 if (!strcmp (s, PIVOT_RC_OTHER))
780 *format = *settings_get_format ();
783 else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
785 *format = table->weight_format;
786 *honor_small = false;
790 const struct result_class *rc = pivot_result_class_find (s);
793 *format = rc->format;
794 *honor_small = false;
798 printf ("unknown class %s\n", s);
804 /* Sets the format specification for the result class named S (which should not
805 include the RC_ prefix) to *FORMAT. Returns true if successful, false if S
806 does not name a known result class. */
808 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
810 char *s = xasprintf ("RC_%s", s_);
811 struct result_class *rc = pivot_result_class_find (s);
814 rc->format = *format;
815 if (!strcmp (s, PIVOT_RC_COUNT))
816 overridden_count_format = true;
824 is_pivot_result_class (const char *s)
826 return pivot_result_class_find (s) != NULL;
831 static struct pivot_cell *pivot_table_insert_cell (struct pivot_table *,
832 const size_t *dindexes);
833 static void pivot_table_delete_cell (struct pivot_table *,
834 struct pivot_cell *);
836 /* Creates and returns a new pivot table with the given TITLE. TITLE should be
837 a text string marked for translation but not actually translated yet,
838 e.g. N_("Descriptive Statistics"). The un-translated text string is used as
839 the pivot table's subtype.
841 This function is a shortcut for pivot_table_create__() for the most common
842 case. Use pivot_table_create__() directly if the title should be some kind
843 of value other than an ordinary text string, or if the subtype should be
844 different from the title.
846 See the large comment at the top of pivot-table.h for general advice on
847 creating pivot tables. */
849 pivot_table_create (const char *title)
851 return pivot_table_create__ (pivot_value_new_text (title), title);
854 /* Creates and returns a new pivot table with the given TITLE, and takes
855 ownership of TITLE. The new pivot table's subtype is SUBTYPE, which should
856 be an untranslated English string that describes the contents of the table
857 at a high level without being specific about the variables or other context
860 TITLE and SUBTYPE may be NULL, but in that case the client must add them
861 later because they are both mandatory for a pivot table.
863 See the large comment at the top of pivot-table.h for general advice on
864 creating pivot tables. */
866 pivot_table_create__ (struct pivot_value *title, const char *subtype)
868 struct pivot_table *table = XZALLOC (struct pivot_table);
870 table->show_title = true;
871 table->show_caption = true;
872 table->weight_format = (struct fmt_spec) { .type = FMT_F, .w = 40 };
873 table->title = title;
874 table->subtype = subtype ? pivot_value_new_text (subtype) : NULL;
875 table->command_c = xstrdup_if_nonempty (output_get_command_name ());
876 table->look = pivot_table_look_ref (pivot_table_look_get_default ());
877 table->settings = fmt_settings_copy (settings_get_fmt_settings ());
878 table->small = settings_get_small ();
880 hmap_init (&table->cells);
885 /* Creates and returns a new pivot table with the given TITLE and a single cell
886 with the given CONTENT.
888 This is really just for error handling. */
890 pivot_table_create_for_text (struct pivot_value *title,
891 struct pivot_value *content)
893 struct pivot_table *table = pivot_table_create__ (title, "Error");
895 struct pivot_dimension *d = pivot_dimension_create (
896 table, PIVOT_AXIS_ROW, N_("Error"));
897 d->hide_all_labels = true;
898 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
900 pivot_table_put1 (table, 0, content);
905 /* Increases TABLE's reference count, indicating that it has an additional
906 owner. A pivot table that is shared among multiple owners must not be
909 pivot_table_ref (const struct pivot_table *table_)
911 struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
916 static struct pivot_table_sizing
917 clone_sizing (const struct pivot_table_sizing *s)
919 return (struct pivot_table_sizing) {
920 .widths = (s->n_widths
921 ? xmemdup (s->widths, s->n_widths * sizeof *s->widths)
923 .n_widths = s->n_widths,
925 .breaks = (s->n_breaks
926 ? xmemdup (s->breaks, s->n_breaks * sizeof *s->breaks)
928 .n_breaks = s->n_breaks,
931 ? xmemdup (s->keeps, s->n_keeps * sizeof *s->keeps)
933 .n_keeps = s->n_keeps,
937 static struct pivot_footnote **
938 clone_footnotes (struct pivot_footnote **old, size_t n)
943 struct pivot_footnote **new = xmalloc (n * sizeof *new);
944 for (size_t i = 0; i < n; i++)
946 new[i] = xmalloc (sizeof *new[i]);
947 *new[i] = (struct pivot_footnote) {
949 .content = pivot_value_clone (old[i]->content),
950 .marker = pivot_value_clone (old[i]->marker),
951 .show = old[i]->show,
957 static struct pivot_category *
958 clone_category (struct pivot_category *old,
959 struct pivot_dimension *new_dimension,
960 struct pivot_category *new_parent)
962 struct pivot_category *new = xmalloc (sizeof *new);
963 *new = (struct pivot_category) {
964 .name = pivot_value_clone (old->name),
965 .parent = new_parent,
966 .dimension = new_dimension,
967 .label_depth = old->label_depth,
968 .extra_depth = old->extra_depth,
971 ? xcalloc (old->n_subs, sizeof *new->subs)
973 .n_subs = old->n_subs,
974 .allocated_subs = old->n_subs,
976 .show_label = old->show_label,
977 .show_label_in_corner = old->show_label_in_corner,
979 .format = old->format,
980 .group_index = old->group_index,
981 .data_index = old->data_index,
982 .presentation_index = old->presentation_index,
985 if (pivot_category_is_leaf (old))
987 assert (new->data_index < new_dimension->n_leaves);
988 new->dimension->data_leaves[new->data_index] = new;
990 assert (new->presentation_index < new_dimension->n_leaves);
991 new->dimension->presentation_leaves[new->presentation_index] = new;
994 for (size_t i = 0; i < new->n_subs; i++)
995 new->subs[i] = clone_category (old->subs[i], new_dimension, new);
1000 static struct pivot_dimension *
1001 clone_dimension (struct pivot_dimension *old, struct pivot_table *new_pt)
1003 struct pivot_dimension *new = xmalloc (sizeof *new);
1004 *new = (struct pivot_dimension) {
1006 .axis_type = old->axis_type,
1007 .level = old->level,
1008 .top_index = old->top_index,
1009 .data_leaves = xcalloc (old->n_leaves , sizeof *new->data_leaves),
1010 .presentation_leaves = xcalloc (old->n_leaves
1011 , sizeof *new->presentation_leaves),
1012 .n_leaves = old->n_leaves,
1013 .allocated_leaves = old->n_leaves,
1014 .hide_all_labels = old->hide_all_labels,
1015 .label_depth = old->label_depth,
1018 new->root = clone_category (old->root, new, NULL);
1023 static struct pivot_dimension **
1024 clone_dimensions (struct pivot_dimension **old, size_t n,
1025 struct pivot_table *new_pt)
1030 struct pivot_dimension **new = xmalloc (n * sizeof *new);
1031 for (size_t i = 0; i < n; i++)
1032 new[i] = clone_dimension (old[i], new_pt);
1036 struct pivot_table *
1037 pivot_table_unshare (struct pivot_table *old)
1039 assert (old->ref_cnt > 0);
1040 if (old->ref_cnt == 1)
1043 pivot_table_unref (old);
1045 struct pivot_table *new = xmalloc (sizeof *new);
1046 *new = (struct pivot_table) {
1049 .look = pivot_table_look_ref (old->look),
1051 .rotate_inner_column_labels = old->rotate_inner_column_labels,
1052 .rotate_outer_row_labels = old->rotate_outer_row_labels,
1053 .show_grid_lines = old->show_grid_lines,
1054 .show_title = old->show_title,
1055 .show_caption = old->show_caption,
1056 .current_layer = (old->current_layer
1057 ? xmemdup (old->current_layer,
1058 old->axes[PIVOT_AXIS_LAYER].n_dimensions
1059 * sizeof *new->current_layer)
1061 .show_values = old->show_values,
1062 .show_variables = old->show_variables,
1063 .weight_format = old->weight_format,
1066 [TABLE_HORZ] = clone_sizing (&old->sizing[TABLE_HORZ]),
1067 [TABLE_VERT] = clone_sizing (&old->sizing[TABLE_VERT]),
1070 .settings = fmt_settings_copy (&old->settings),
1071 .grouping = old->grouping,
1072 .small = old->small,
1074 .command_local = xstrdup_if_nonnull (old->command_local),
1075 .command_c = xstrdup_if_nonnull (old->command_c),
1076 .language = xstrdup_if_nonnull (old->language),
1077 .locale = xstrdup_if_nonnull (old->locale),
1079 .dataset = xstrdup_if_nonnull (old->dataset),
1080 .datafile = xstrdup_if_nonnull (old->datafile),
1083 .footnotes = clone_footnotes (old->footnotes, old->n_footnotes),
1084 .n_footnotes = old->n_footnotes,
1085 .allocated_footnotes = old->n_footnotes,
1087 .title = pivot_value_clone (old->title),
1088 .subtype = pivot_value_clone (old->subtype),
1089 .corner_text = pivot_value_clone (old->corner_text),
1090 .caption = pivot_value_clone (old->caption),
1091 .notes = xstrdup_if_nonnull (old->notes),
1093 .dimensions = clone_dimensions (old->dimensions, old->n_dimensions, new),
1094 .n_dimensions = old->n_dimensions,
1096 .cells = HMAP_INITIALIZER (new->cells),
1099 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1101 struct pivot_axis *new_axis = &new->axes[i];
1102 const struct pivot_axis *old_axis = &old->axes[i];
1104 *new_axis = (struct pivot_axis) {
1105 .dimensions = xmalloc (old_axis->n_dimensions
1106 * sizeof *new_axis->dimensions),
1107 .n_dimensions = old_axis->n_dimensions,
1108 .extent = old_axis->extent,
1109 .label_depth = old_axis->label_depth,
1112 for (size_t i = 0; i < new_axis->n_dimensions; i++)
1113 new_axis->dimensions[i] = new->dimensions[
1114 old_axis->dimensions[i]->top_index];
1117 const struct pivot_cell *old_cell;
1118 size_t *dindexes = xmalloc (old->n_dimensions * sizeof *dindexes);
1119 HMAP_FOR_EACH (old_cell, struct pivot_cell, hmap_node, &old->cells)
1121 for (size_t i = 0; i < old->n_dimensions; i++)
1122 dindexes[i] = old_cell->idx[i];
1123 struct pivot_cell *new_cell
1124 = pivot_table_insert_cell (new, dindexes);
1125 new_cell->value = pivot_value_clone (old_cell->value);
1132 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
1133 If TABLE no longer has any owners, it is freed. */
1135 pivot_table_unref (struct pivot_table *table)
1139 assert (table->ref_cnt > 0);
1140 if (--table->ref_cnt)
1143 free (table->current_layer);
1144 pivot_table_look_unref (table->look);
1146 for (int i = 0; i < TABLE_N_AXES; i++)
1147 pivot_table_sizing_uninit (&table->sizing[i]);
1149 fmt_settings_uninit (&table->settings);
1151 free (table->command_local);
1152 free (table->command_c);
1153 free (table->language);
1154 free (table->locale);
1156 free (table->dataset);
1157 free (table->datafile);
1159 for (size_t i = 0; i < table->n_footnotes; i++)
1160 pivot_footnote_destroy (table->footnotes[i]);
1161 free (table->footnotes);
1163 pivot_value_destroy (table->title);
1164 pivot_value_destroy (table->subtype);
1165 pivot_value_destroy (table->corner_text);
1166 pivot_value_destroy (table->caption);
1167 free (table->notes);
1169 for (size_t i = 0; i < table->n_dimensions; i++)
1170 pivot_dimension_destroy (table->dimensions[i]);
1171 free (table->dimensions);
1173 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1174 free (table->axes[i].dimensions);
1176 struct pivot_cell *cell, *next_cell;
1177 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
1179 pivot_table_delete_cell (table, cell);
1181 hmap_destroy (&table->cells);
1186 /* Returns true if TABLE has more than one owner. A pivot table that is shared
1187 among multiple owners must not be modified. */
1189 pivot_table_is_shared (const struct pivot_table *table)
1191 return table->ref_cnt > 1;
1194 /* Swaps axes A and B in TABLE. */
1196 pivot_table_swap_axes (struct pivot_table *table,
1197 enum pivot_axis_type a, enum pivot_axis_type b)
1202 struct pivot_axis tmp = table->axes[a];
1203 table->axes[a] = table->axes[b];
1204 table->axes[b] = tmp;
1206 for (int a = 0; a < PIVOT_N_AXES; a++)
1208 struct pivot_axis *axis = &table->axes[a];
1209 for (size_t d = 0; d < axis->n_dimensions; d++)
1210 axis->dimensions[d]->axis_type = a;
1213 if (a == PIVOT_AXIS_LAYER || b == PIVOT_AXIS_LAYER)
1215 free (table->current_layer);
1216 table->current_layer = xzalloc (
1217 table->axes[PIVOT_AXIS_LAYER].n_dimensions
1218 * sizeof *table->current_layer);
1222 /* Swaps the row and column axes in TABLE. */
1224 pivot_table_transpose (struct pivot_table *table)
1226 pivot_table_swap_axes (table, PIVOT_AXIS_ROW, PIVOT_AXIS_COLUMN);
1230 pivot_table_update_axes (struct pivot_table *table)
1232 for (int a = 0; a < PIVOT_N_AXES; a++)
1234 struct pivot_axis *axis = &table->axes[a];
1236 for (size_t d = 0; d < axis->n_dimensions; d++)
1238 struct pivot_dimension *dim = axis->dimensions[d];
1245 /* Moves DIM from its current location in TABLE to POS within AXIS. POS of 0
1246 is the innermost dimension, 1 is the next one out, and so on. */
1248 pivot_table_move_dimension (struct pivot_table *table,
1249 struct pivot_dimension *dim,
1250 enum pivot_axis_type axis, size_t pos)
1252 assert (dim->table == table);
1254 struct pivot_axis *old_axis = &table->axes[dim->axis_type];
1255 struct pivot_axis *new_axis = &table->axes[axis];
1256 pos = MIN (pos, new_axis->n_dimensions);
1258 if (old_axis == new_axis && pos == dim->level)
1264 /* Update the current layer, if necessary. If we're moving within the layer
1265 axis, preserve the current layer. */
1266 if (dim->axis_type == PIVOT_AXIS_LAYER)
1268 if (axis == PIVOT_AXIS_LAYER)
1270 /* Rearranging the layer axis. */
1271 move_element (table->current_layer, old_axis->n_dimensions,
1272 sizeof *table->current_layer,
1277 /* A layer is becoming a row or column. */
1278 remove_element (table->current_layer, old_axis->n_dimensions,
1279 sizeof *table->current_layer, dim->level);
1282 else if (axis == PIVOT_AXIS_LAYER)
1284 /* A row or column is becoming a layer. */
1285 table->current_layer = xrealloc (
1286 table->current_layer,
1287 (new_axis->n_dimensions + 1) * sizeof *table->current_layer);
1288 insert_element (table->current_layer, new_axis->n_dimensions,
1289 sizeof *table->current_layer, pos);
1290 table->current_layer[pos] = 0;
1293 /* Remove DIM from its current axis. */
1294 remove_element (old_axis->dimensions, old_axis->n_dimensions,
1295 sizeof *old_axis->dimensions, dim->level);
1296 old_axis->n_dimensions--;
1298 /* Insert DIM into its new axis. */
1299 new_axis->dimensions = xrealloc (
1300 new_axis->dimensions,
1301 (new_axis->n_dimensions + 1) * sizeof *new_axis->dimensions);
1302 insert_element (new_axis->dimensions, new_axis->n_dimensions,
1303 sizeof *new_axis->dimensions, pos);
1304 new_axis->dimensions[pos] = dim;
1305 new_axis->n_dimensions++;
1307 pivot_table_update_axes (table);
1311 const struct pivot_table_look *
1312 pivot_table_get_look (const struct pivot_table *table)
1318 pivot_table_set_look (struct pivot_table *table,
1319 const struct pivot_table_look *look)
1321 pivot_table_look_unref (table->look);
1322 table->look = pivot_table_look_ref (look);
1325 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
1326 WV, which should be the weight variable for the dictionary whose data or
1327 statistics are being put into TABLE.
1329 This has no effect if WV is NULL. */
1331 pivot_table_set_weight_var (struct pivot_table *table,
1332 const struct variable *wv)
1335 pivot_table_set_weight_format (table, var_get_print_format (wv));
1338 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
1339 format for the dictionary whose data or statistics are being put into TABLE.
1341 This has no effect if WFMT is NULL. */
1343 pivot_table_set_weight_format (struct pivot_table *table,
1344 const struct fmt_spec *wfmt)
1347 table->weight_format = *wfmt;
1350 /* Returns true if TABLE has no cells, false otherwise. */
1352 pivot_table_is_empty (const struct pivot_table *table)
1354 return hmap_is_empty (&table->cells);
1358 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
1360 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
1364 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
1366 for (size_t i = 0; i < n; i++)
1373 static struct pivot_cell *
1374 pivot_table_lookup_cell__ (const struct pivot_table *table,
1375 const size_t *dindexes, unsigned int hash)
1377 struct pivot_cell *cell;
1378 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
1380 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
1385 static struct pivot_cell *
1386 pivot_cell_allocate (size_t n_idx)
1388 struct pivot_cell *cell UNUSED;
1389 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
1392 static struct pivot_cell *
1393 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
1395 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1396 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
1399 cell = pivot_cell_allocate (table->n_dimensions);
1400 for (size_t i = 0; i < table->n_dimensions; i++)
1401 cell->idx[i] = dindexes[i];
1403 hmap_insert (&table->cells, &cell->hmap_node, hash);
1408 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
1409 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
1412 If VALUE is a numeric value without a specified format, this function checks
1413 each of the categories designated by DINDEXES[] and takes the format from
1414 the first category with a result class. If none has a result class, uses
1415 the overall default numeric format. */
1417 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
1418 struct pivot_value *value)
1420 assert (n == table->n_dimensions);
1421 for (size_t i = 0; i < n; i++)
1422 assert (dindexes[i] < table->dimensions[i]->n_leaves);
1424 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
1426 for (size_t i = 0; i < table->n_dimensions; i++)
1428 const struct pivot_dimension *d = table->dimensions[i];
1429 if (dindexes[i] < d->n_leaves)
1431 const struct pivot_category *c = d->data_leaves[dindexes[i]];
1434 value->numeric.format = c->format;
1435 value->numeric.honor_small = c->honor_small;
1440 value->numeric.format = *settings_get_format ();
1441 value->numeric.honor_small = true;
1446 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1447 pivot_value_destroy (cell->value);
1448 cell->value = value;
1451 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
1452 dimension. Takes ownership of VALUE. */
1454 pivot_table_put1 (struct pivot_table *table, size_t idx1,
1455 struct pivot_value *value)
1457 size_t dindexes[] = { idx1 };
1458 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1461 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
1462 dimensions. Takes ownership of VALUE. */
1464 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
1465 struct pivot_value *value)
1467 size_t dindexes[] = { idx1, idx2 };
1468 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1471 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
1472 have 3 dimensions. Takes ownership of VALUE. */
1474 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
1475 size_t idx3, struct pivot_value *value)
1477 size_t dindexes[] = { idx1, idx2, idx3 };
1478 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1481 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
1482 must have 4 dimensions. Takes ownership of VALUE. */
1484 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1485 size_t idx3, size_t idx4, struct pivot_value *value)
1487 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1488 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1491 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1492 automatically assigned marker.
1494 The footnote will only appear in output if it is referenced. Use
1495 pivot_value_add_footnote() to add a reference to the footnote. */
1496 struct pivot_footnote *
1497 pivot_table_create_footnote (struct pivot_table *table,
1498 struct pivot_value *content)
1500 return pivot_table_create_footnote__ (table, table->n_footnotes,
1505 pivot_footnote_format_marker (const struct pivot_footnote *f,
1506 const struct pivot_table *pt,
1510 pivot_value_format_body (f->marker, pt, s);
1511 else if (pt->look->show_numeric_markers)
1512 ds_put_format (s, "%zu", f->idx + 1);
1515 char text[INT_BUFSIZE_BOUND (size_t)];
1516 str_format_26adic (f->idx + 1, false, text, sizeof text);
1517 ds_put_cstr (s, text);
1522 pivot_footnote_marker_string (const struct pivot_footnote *f,
1523 const struct pivot_table *pt)
1525 struct string s = DS_EMPTY_INITIALIZER;
1526 pivot_footnote_format_marker (f, pt, &s);
1527 return ds_steal_cstr (&s);
1530 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1531 all lower indexes as a side effect). If MARKER is nonnull, sets the
1532 footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1533 struct pivot_footnote *
1534 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1535 struct pivot_value *marker,
1536 struct pivot_value *content)
1538 if (idx >= table->n_footnotes)
1540 while (idx >= table->allocated_footnotes)
1541 table->footnotes = x2nrealloc (table->footnotes,
1542 &table->allocated_footnotes,
1543 sizeof *table->footnotes);
1544 while (idx >= table->n_footnotes)
1546 struct pivot_footnote *f = xmalloc (sizeof *f);
1547 *f = (struct pivot_footnote) {
1548 .idx = table->n_footnotes,
1551 table->footnotes[table->n_footnotes++] = f;
1555 struct pivot_footnote *f = table->footnotes[idx];
1558 pivot_value_destroy (f->marker);
1563 pivot_value_destroy (f->content);
1564 f->content = content;
1569 /* Frees the data owned by F. */
1571 pivot_footnote_destroy (struct pivot_footnote *f)
1575 pivot_value_destroy (f->content);
1576 pivot_value_destroy (f->marker);
1581 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1582 indexes for each dimension in TABLE in DINDEXES[]. */
1584 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1585 const size_t *pindexes[PIVOT_N_AXES],
1586 size_t dindexes[/* table->n_dimensions */])
1588 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1590 const struct pivot_axis *axis = &table->axes[i];
1592 for (size_t j = 0; j < axis->n_dimensions; j++)
1594 const struct pivot_dimension *d = axis->dimensions[j];
1595 size_t pindex = pindexes[i][j];
1596 dindexes[d->top_index] = d->presentation_leaves[pindex]->data_index;
1602 pivot_table_enumerate_axis (const struct pivot_table *table,
1603 enum pivot_axis_type axis_type,
1604 const size_t *layer_indexes, bool omit_empty,
1607 const struct pivot_axis *axis = &table->axes[axis_type];
1608 if (!axis->n_dimensions)
1610 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1612 enumeration[1] = SIZE_MAX;
1617 else if (!axis->extent)
1619 size_t *enumeration = xmalloc (sizeof *enumeration);
1620 *enumeration = SIZE_MAX;
1626 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1627 axis->n_dimensions), 1),
1628 sizeof *enumeration);
1629 size_t *p = enumeration;
1630 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1632 size_t *axis_indexes;
1633 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1637 enum pivot_axis_type axis2_type
1638 = pivot_axis_type_transpose (axis_type);
1640 size_t *axis2_indexes;
1641 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1643 const size_t *pindexes[PIVOT_N_AXES];
1644 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1645 pindexes[axis_type] = axis_indexes;
1646 pindexes[axis2_type] = axis2_indexes;
1647 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1648 if (pivot_table_get (table, dindexes))
1654 free (axis2_indexes);
1657 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1658 p += axis->n_dimensions;
1660 if (omit_empty && p == enumeration)
1662 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1664 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1665 p += axis->n_dimensions;
1670 *n = (p - enumeration) / axis->n_dimensions;
1676 static struct pivot_cell *
1677 pivot_table_lookup_cell (const struct pivot_table *table,
1678 const size_t *dindexes)
1680 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1681 return pivot_table_lookup_cell__ (table, dindexes, hash);
1684 const struct pivot_value *
1685 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1687 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1688 return cell ? cell->value : NULL;
1691 struct pivot_value *
1692 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1694 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1696 cell->value = pivot_value_new_user_text ("", -1);
1701 pivot_table_delete_cell (struct pivot_table *table, struct pivot_cell *cell)
1703 hmap_delete (&table->cells, &cell->hmap_node);
1704 pivot_value_destroy (cell->value);
1709 pivot_table_delete (struct pivot_table *table, const size_t *dindexes)
1711 struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1714 pivot_table_delete_cell (table, cell);
1722 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1724 if (pivot_category_is_group (category) && category->n_subs)
1725 for (size_t i = 0; i < category->n_subs; i++)
1726 distribute_extra_depth (category->subs[i], extra_depth);
1728 category->extra_depth += extra_depth;
1732 pivot_category_assign_label_depth (struct pivot_category *category,
1733 bool dimension_labels_in_corner)
1735 category->extra_depth = 0;
1737 if (pivot_category_is_group (category))
1740 for (size_t i = 0; i < category->n_subs; i++)
1742 pivot_category_assign_label_depth (category->subs[i], false);
1743 depth = MAX (depth, category->subs[i]->label_depth);
1746 for (size_t i = 0; i < category->n_subs; i++)
1748 struct pivot_category *sub = category->subs[i];
1750 size_t extra_depth = depth - sub->label_depth;
1752 distribute_extra_depth (sub, extra_depth);
1754 sub->label_depth = depth;
1757 category->show_label_in_corner = (category->show_label
1758 && dimension_labels_in_corner);
1759 category->label_depth
1760 = (category->show_label && !category->show_label_in_corner
1761 ? depth + 1 : depth);
1764 category->label_depth = 1;
1768 pivot_axis_assign_label_depth (struct pivot_table *table,
1769 enum pivot_axis_type axis_type,
1770 bool dimension_labels_in_corner)
1772 struct pivot_axis *axis = &table->axes[axis_type];
1773 bool any_label_shown_in_corner = false;
1774 axis->label_depth = 0;
1776 for (size_t i = 0; i < axis->n_dimensions; i++)
1778 struct pivot_dimension *d = axis->dimensions[i];
1779 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1780 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1781 axis->label_depth += d->label_depth;
1782 axis->extent *= d->n_leaves;
1784 if (d->root->show_label_in_corner)
1785 any_label_shown_in_corner = true;
1787 return any_label_shown_in_corner;
1791 pivot_table_assign_label_depth (struct pivot_table *table)
1793 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1794 if (pivot_axis_assign_label_depth (
1795 table, PIVOT_AXIS_ROW, (table->look->row_labels_in_corner
1796 && !table->corner_text))
1797 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1798 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1799 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1803 indent (int indentation)
1805 for (int i = 0; i < indentation * 2; i++)
1810 pivot_value_dump (const struct pivot_value *value,
1811 const struct pivot_table *pt)
1813 char *s = pivot_value_to_string (value, pt);
1819 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1820 const struct pivot_table *pt, int indentation)
1824 indent (indentation);
1825 printf ("%s: ", name);
1826 pivot_value_dump (value, pt);
1832 pivot_table_dump_string (const char *string, const char *name, int indentation)
1836 indent (indentation);
1837 printf ("%s: %s\n", name, string);
1842 pivot_category_dump (const struct pivot_category *c,
1843 const struct pivot_table *pt, int indentation)
1845 indent (indentation);
1846 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1847 pivot_value_dump (c->name, pt);
1850 if (pivot_category_is_leaf (c))
1851 printf ("data_index=%zu\n", c->data_index);
1854 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1857 for (size_t i = 0; i < c->n_subs; i++)
1858 pivot_category_dump (c->subs[i], pt, indentation + 1);
1863 pivot_dimension_dump (const struct pivot_dimension *d,
1864 const struct pivot_table *pt, int indentation)
1866 indent (indentation);
1867 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1868 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1870 pivot_category_dump (d->root, pt, indentation + 1);
1874 table_area_style_dump (enum pivot_area area, const struct table_area_style *a,
1877 indent (indentation);
1878 printf ("%s: ", pivot_area_to_string (area));
1879 font_style_dump (&a->font_style);
1881 cell_style_dump (&a->cell_style);
1886 table_border_style_dump (enum pivot_border border,
1887 const struct table_border_style *b, int indentation)
1889 indent (indentation);
1890 printf ("%s: %s ", pivot_border_to_string (border),
1891 table_stroke_to_string (b->stroke));
1892 cell_color_dump (&b->color);
1897 compose_headings (const struct pivot_table *pt,
1898 const struct pivot_axis *axis,
1899 const size_t *column_enumeration)
1901 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1904 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1905 for (size_t i = 0; i < axis->label_depth; i++)
1906 headings[i] = xcalloc (axis->extent, sizeof **headings);
1908 const size_t *indexes;
1910 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1912 int row = axis->label_depth - 1;
1913 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1915 const struct pivot_dimension *d = axis->dimensions[dim_index];
1916 if (d->hide_all_labels)
1918 for (const struct pivot_category *c
1919 = d->presentation_leaves[indexes[dim_index]];
1923 if (pivot_category_is_leaf (c) || (c->show_label
1924 && !c->show_label_in_corner))
1926 headings[row][column] = pivot_value_to_string (c->name, pt);
1927 if (!*headings[row][column])
1928 headings[row][column] = xstrdup ("<blank>");
1940 free_headings (const struct pivot_axis *axis, char ***headings)
1944 for (size_t i = 0; i < axis->label_depth; i++)
1946 for (size_t j = 0; j < axis->extent; j++)
1947 free (headings[i][j]);
1954 pivot_table_sizing_dump (const char *name,
1955 const int width_ranges[2],
1956 const struct pivot_table_sizing *s,
1959 indent (indentation);
1960 printf ("%ss: min=%d, max=%d\n", name, width_ranges[0], width_ranges[1]);
1963 indent (indentation + 1);
1964 printf ("%s widths:", name);
1965 for (size_t i = 0; i < s->n_widths; i++)
1966 printf (" %d", s->widths[i]);
1971 indent (indentation + 1);
1972 printf ("break after %ss:", name);
1973 for (size_t i = 0; i < s->n_breaks; i++)
1974 printf (" %zu", s->breaks[i]);
1979 indent (indentation + 1);
1980 printf ("keep %ss together:", name);
1981 for (size_t i = 0; i < s->n_keeps; i++)
1982 printf (" [%zu,%zu]",
1984 s->keeps[i].ofs + s->keeps[i].n - 1);
1990 pivot_table_dump (const struct pivot_table *table, int indentation)
1995 pivot_table_assign_label_depth (CONST_CAST (struct pivot_table *, table));
1997 pivot_table_dump_value (table->title, "title", table, indentation);
1998 pivot_table_dump_value (table->subtype, "subtype", table, indentation);
1999 pivot_table_dump_string (table->command_c, "command", indentation);
2000 pivot_table_dump_string (table->dataset, "dataset", indentation);
2001 pivot_table_dump_string (table->datafile, "datafile", indentation);
2002 pivot_table_dump_string (table->notes, "notes", indentation);
2003 pivot_table_dump_string (table->look->name, "table-look", indentation);
2006 indent (indentation);
2008 struct tm *tm = localtime (&table->date);
2009 printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
2010 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
2014 indent (indentation);
2015 printf ("sizing:\n");
2016 pivot_table_sizing_dump ("column", table->look->width_ranges[TABLE_HORZ],
2017 &table->sizing[TABLE_HORZ], indentation + 1);
2018 pivot_table_sizing_dump ("row", table->look->width_ranges[TABLE_VERT],
2019 &table->sizing[TABLE_VERT], indentation + 1);
2021 indent (indentation);
2022 printf ("areas:\n");
2023 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
2024 table_area_style_dump (area, &table->look->areas[area], indentation + 1);
2026 indent (indentation);
2027 printf ("borders:\n");
2028 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
2029 table_border_style_dump (border, &table->look->borders[border],
2032 for (size_t i = 0; i < table->n_dimensions; i++)
2033 pivot_dimension_dump (table->dimensions[i], table, indentation);
2035 /* Presentation and data indexes. */
2036 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
2038 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
2039 if (layer_axis->n_dimensions)
2041 indent (indentation);
2042 printf ("current layer:");
2044 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
2046 const struct pivot_dimension *d = layer_axis->dimensions[i];
2047 char *name = pivot_value_to_string (d->root->name, table);
2048 char *value = pivot_value_to_string (
2049 d->data_leaves[table->current_layer[i]]->name, table);
2050 printf (" %s=%s", name, value);
2058 size_t *layer_indexes;
2059 size_t layer_iteration = 0;
2060 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
2062 indent (indentation);
2063 printf ("layer %zu:", layer_iteration++);
2065 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
2066 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
2068 const struct pivot_dimension *d = layer_axis->dimensions[i];
2070 fputs (i == 0 ? " " : ", ", stdout);
2071 pivot_value_dump (d->root->name, table);
2072 fputs (" =", stdout);
2074 struct pivot_value **names = xnmalloc (d->n_leaves, sizeof *names);
2076 for (const struct pivot_category *c
2077 = d->presentation_leaves[layer_indexes[i]];
2081 if (pivot_category_is_leaf (c) || c->show_label)
2082 names[n_names++] = c->name;
2085 for (size_t i = n_names; i-- > 0;)
2088 pivot_value_dump (names[i], table);
2094 size_t *column_enumeration = pivot_table_enumerate_axis (
2095 table, PIVOT_AXIS_COLUMN, layer_indexes, table->look->omit_empty, NULL);
2096 size_t *row_enumeration = pivot_table_enumerate_axis (
2097 table, PIVOT_AXIS_ROW, layer_indexes, table->look->omit_empty, NULL);
2099 /* Print column headings.
2101 Ordinarily the test for nonnull 'column_headings' would be
2102 unnecessary, because 'column_headings' is null only if the axis's
2103 label_depth is 0, but there is a special case for the column axis only
2104 in pivot_table_assign_label_depth(). */
2105 char ***column_headings = compose_headings (
2106 table, &table->axes[PIVOT_AXIS_COLUMN], column_enumeration);
2107 if (column_headings)
2109 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
2111 indent (indentation + 1);
2112 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
2115 fputs ("; ", stdout);
2116 if (column_headings && column_headings[y] && column_headings[y][x])
2117 fputs (column_headings[y][x], stdout);
2121 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
2124 indent (indentation + 1);
2125 printf ("-----------------------------------------------\n");
2127 char ***row_headings = compose_headings (
2128 table, &table->axes[PIVOT_AXIS_ROW], row_enumeration);
2131 const size_t *pindexes[PIVOT_N_AXES]
2132 = { [PIVOT_AXIS_LAYER] = layer_indexes };
2133 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
2134 &table->axes[PIVOT_AXIS_ROW])
2136 indent (indentation + 1);
2139 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
2142 fputs ("; ", stdout);
2143 if (row_headings[y][x])
2144 fputs (row_headings[y][x], stdout);
2150 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
2152 &table->axes[PIVOT_AXIS_COLUMN])
2157 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
2158 const struct pivot_value *value = pivot_table_get (
2161 pivot_value_dump (value, table);
2168 free (column_enumeration);
2169 free (row_enumeration);
2170 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
2173 pivot_table_dump_value (table->caption, "caption", table, indentation);
2175 for (size_t i = 0; i < table->n_footnotes; i++)
2177 const struct pivot_footnote *f = table->footnotes[i];
2178 indent (indentation);
2181 pivot_value_dump (f->marker, table);
2183 printf ("%zu", f->idx);
2185 pivot_value_dump (f->content, table);
2193 consume_int (const char *p, size_t *n)
2196 while (c_isdigit (*p))
2197 *n = *n * 10 + (*p++ - '0');
2202 pivot_format_inner_template (struct string *out, const char *template,
2204 struct pivot_value **values, size_t n_values,
2205 const struct pivot_table *pt)
2207 size_t args_consumed = 0;
2208 while (*template && *template != ':')
2210 if (*template == '\\' && template[1])
2212 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
2215 else if (*template == escape)
2218 template = consume_int (template + 1, &index);
2219 if (index >= 1 && index <= n_values)
2221 pivot_value_format (values[index - 1], pt, out);
2222 args_consumed = MAX (args_consumed, index);
2226 ds_put_byte (out, *template++);
2228 return args_consumed;
2232 pivot_extract_inner_template (const char *template, const char **p)
2238 if (*template == '\\' && template[1] != '\0')
2240 else if (*template == ':')
2241 return template + 1;
2242 else if (*template == '\0')
2250 pivot_format_template (struct string *out, const char *template,
2251 const struct pivot_argument *args, size_t n_args,
2252 const struct pivot_table *pt)
2256 if (*template == '\\' && template[1] != '\0')
2258 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
2261 else if (*template == '^')
2264 template = consume_int (template + 1, &index);
2265 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
2266 pivot_value_format (args[index - 1].values[0], pt, out);
2268 else if (*template == '[')
2270 const char *tmpl[2];
2271 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
2272 template = pivot_extract_inner_template (template, &tmpl[1]);
2273 template += *template == ']';
2276 template = consume_int (template, &index);
2277 if (index < 1 || index > n_args)
2280 const struct pivot_argument *arg = &args[index - 1];
2281 size_t left = arg->n;
2284 struct pivot_value **values = arg->values + (arg->n - left);
2285 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
2286 char escape = "%^"[tmpl_idx];
2287 size_t used = pivot_format_inner_template (
2288 out, tmpl[tmpl_idx], escape, values, left, pt);
2289 if (!used || used > left)
2295 ds_put_byte (out, *template++);
2299 static enum settings_value_show
2300 interpret_show (enum settings_value_show global_show,
2301 enum settings_value_show table_show,
2302 enum settings_value_show value_show,
2305 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
2306 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
2307 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
2311 /* Appends to OUT the actual text content from the given Pango MARKUP. */
2313 get_text_from_markup (const char *markup, struct string *out)
2315 xmlParserCtxt *parser = xmlCreatePushParserCtxt (NULL, NULL, NULL, 0, NULL);
2318 ds_put_cstr (out, markup);
2322 xmlParseChunk (parser, "<xml>", strlen ("<xml>"), false);
2323 xmlParseChunk (parser, markup, strlen (markup), false);
2324 xmlParseChunk (parser, "</xml>", strlen ("</xml>"), true);
2326 if (parser->wellFormed)
2328 xmlChar *s = xmlNodeGetContent (xmlDocGetRootElement (parser->myDoc));
2329 ds_put_cstr (out, CHAR_CAST (char *, s));
2333 ds_put_cstr (out, markup);
2334 xmlFreeDoc (parser->myDoc);
2335 xmlFreeParserCtxt (parser);
2338 /* Appends a text representation of the body of VALUE to OUT. Settings on
2339 PT control whether variable and value labels are included.
2341 The "body" omits subscripts and superscripts and footnotes.
2343 Returns true if OUT is a number (or a number plus a value label), false
2346 pivot_value_format_body (const struct pivot_value *value,
2347 const struct pivot_table *pt,
2350 enum settings_value_show show;
2351 bool numeric = false;
2353 switch (value->type)
2355 case PIVOT_VALUE_NUMERIC:
2356 show = interpret_show (settings_get_show_values (),
2358 value->numeric.show,
2359 value->numeric.value_label != NULL);
2360 if (show & SETTINGS_VALUE_SHOW_VALUE)
2362 const struct fmt_spec *f = &value->numeric.format;
2363 const struct fmt_spec *format
2365 && value->numeric.honor_small
2366 && value->numeric.x != 0
2367 && fabs (value->numeric.x) < pt->small
2368 ? &(struct fmt_spec) { .type = FMT_E, .w = 40, .d = f->d }
2371 char *s = data_out (&(union value) { .f = value->numeric.x },
2372 "UTF-8", format, &pt->settings);
2373 ds_put_cstr (out, s + strspn (s, " "));
2376 if (show & SETTINGS_VALUE_SHOW_LABEL)
2378 if (show & SETTINGS_VALUE_SHOW_VALUE)
2379 ds_put_byte (out, ' ');
2380 ds_put_cstr (out, value->numeric.value_label);
2382 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
2385 case PIVOT_VALUE_STRING:
2386 show = interpret_show (settings_get_show_values (),
2389 value->string.value_label != NULL);
2390 if (show & SETTINGS_VALUE_SHOW_VALUE)
2392 if (value->string.hex)
2394 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
2396 ds_put_format (out, "%02X", *p);
2399 ds_put_cstr (out, value->string.s);
2401 if (show & SETTINGS_VALUE_SHOW_LABEL)
2403 if (show & SETTINGS_VALUE_SHOW_VALUE)
2404 ds_put_byte (out, ' ');
2405 ds_put_cstr (out, value->string.value_label);
2409 case PIVOT_VALUE_VARIABLE:
2410 show = interpret_show (settings_get_show_variables (),
2412 value->variable.show,
2413 value->variable.var_label != NULL);
2414 if (show & SETTINGS_VALUE_SHOW_VALUE)
2415 ds_put_cstr (out, value->variable.var_name);
2416 if (show & SETTINGS_VALUE_SHOW_LABEL)
2418 if (show & SETTINGS_VALUE_SHOW_VALUE)
2419 ds_put_byte (out, ' ');
2420 ds_put_cstr (out, value->variable.var_label);
2424 case PIVOT_VALUE_TEXT:
2425 if (value->ex && value->ex->font_style && value->ex->font_style->markup)
2426 get_text_from_markup (value->text.local, out);
2428 ds_put_cstr (out, value->text.local);
2431 case PIVOT_VALUE_TEMPLATE:
2432 pivot_format_template (out, value->template.local, value->template.args,
2433 value->template.n_args, pt);
2440 /* Appends a text representation of VALUE to OUT. Settings on
2441 PT control whether variable and value labels are included.
2443 Subscripts and footnotes are included.
2445 Returns true if OUT is a number (or a number plus a value label), false
2448 pivot_value_format (const struct pivot_value *value,
2449 const struct pivot_table *pt,
2452 bool numeric = pivot_value_format_body (value, pt, out);
2454 const struct pivot_value_ex *ex = value->ex;
2457 if (ex->n_subscripts)
2459 for (size_t i = 0; i < ex->n_subscripts; i++)
2460 ds_put_format (out, "%c%s", i ? ',' : '_', ex->subscripts[i]);
2463 for (size_t i = 0; i < ex->n_footnotes; i++)
2465 ds_put_byte (out, '[');
2467 size_t idx = ex->footnote_indexes[i];
2468 const struct pivot_footnote *f = pt->footnotes[idx];
2469 pivot_footnote_format_marker (f, pt, out);
2471 ds_put_byte (out, ']');
2478 /* Returns a text representation of VALUE. The caller must free the string,
2481 pivot_value_to_string (const struct pivot_value *value,
2482 const struct pivot_table *pt)
2484 struct string s = DS_EMPTY_INITIALIZER;
2485 pivot_value_format (value, pt, &s);
2486 return ds_steal_cstr (&s);
2490 pivot_value_to_string_defaults (const struct pivot_value *value)
2492 static const struct pivot_table pt = {
2493 .show_values = SETTINGS_VALUE_SHOW_DEFAULT,
2494 .show_variables = SETTINGS_VALUE_SHOW_DEFAULT,
2495 .settings = FMT_SETTINGS_INIT,
2497 return pivot_value_to_string (value, &pt);
2500 struct pivot_value *
2501 pivot_value_clone (const struct pivot_value *old)
2506 struct pivot_value *new = xmemdup (old, sizeof *new);
2508 new->ex = pivot_value_ex_clone (old->ex);
2512 case PIVOT_VALUE_NUMERIC:
2513 new->numeric.var_name = xstrdup_if_nonnull (new->numeric.var_name);
2514 new->numeric.value_label = xstrdup_if_nonnull (new->numeric.value_label);
2517 case PIVOT_VALUE_STRING:
2518 new->string.s = xstrdup (new->string.s);
2519 new->string.var_name = xstrdup_if_nonnull (new->string.var_name);
2520 new->string.value_label = xstrdup_if_nonnull (new->string.value_label);
2523 case PIVOT_VALUE_VARIABLE:
2524 new->variable.var_name = xstrdup_if_nonnull (new->variable.var_name);
2525 new->variable.var_label = xstrdup_if_nonnull (new->variable.var_label);
2528 case PIVOT_VALUE_TEXT:
2529 new->text.local = xstrdup (old->text.local);
2530 new->text.c = (old->text.c == old->text.local ? new->text.local
2531 : xstrdup_if_nonnull (old->text.c));
2532 new->text.id = (old->text.id == old->text.local ? new->text.local
2533 : old->text.id == old->text.c ? new->text.c
2534 : xstrdup_if_nonnull (old->text.id));
2537 case PIVOT_VALUE_TEMPLATE:
2538 new->template.local = xstrdup (old->template.local);
2539 new->template.id = (old->template.id == old->template.local
2540 ? new->template.local
2541 : xstrdup (old->template.id));
2542 new->template.args = xmalloc (new->template.n_args
2543 * sizeof *new->template.args);
2544 for (size_t i = 0; i < old->template.n_args; i++)
2545 pivot_argument_copy (&new->template.args[i],
2546 &old->template.args[i]);
2555 /* Frees the data owned by V. */
2557 pivot_value_destroy (struct pivot_value *value)
2561 pivot_value_ex_destroy (value->ex);
2562 switch (value->type)
2564 case PIVOT_VALUE_NUMERIC:
2565 free (value->numeric.var_name);
2566 free (value->numeric.value_label);
2569 case PIVOT_VALUE_STRING:
2570 free (value->string.s);
2571 free (value->string.var_name);
2572 free (value->string.value_label);
2575 case PIVOT_VALUE_VARIABLE:
2576 free (value->variable.var_name);
2577 free (value->variable.var_label);
2580 case PIVOT_VALUE_TEXT:
2581 free (value->text.local);
2582 if (value->text.c != value->text.local)
2583 free (value->text.c);
2584 if (value->text.id != value->text.local
2585 && value->text.id != value->text.c)
2586 free (value->text.id);
2589 case PIVOT_VALUE_TEMPLATE:
2590 free (value->template.local);
2591 if (value->template.id != value->template.local)
2592 free (value->template.id);
2593 for (size_t i = 0; i < value->template.n_args; i++)
2594 pivot_argument_uninit (&value->template.args[i]);
2595 free (value->template.args);
2605 /* Sets AREA to the style to use for VALUE, with defaults coming from
2606 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
2608 pivot_value_get_style (struct pivot_value *value,
2609 const struct font_style *base_font_style,
2610 const struct cell_style *base_cell_style,
2611 struct table_area_style *area)
2613 const struct pivot_value_ex *ex = pivot_value_ex (value);
2614 font_style_copy (NULL, &area->font_style,
2615 ex->font_style ? ex->font_style : base_font_style);
2616 area->cell_style = *(ex->cell_style ? ex->cell_style : base_cell_style);
2619 /* Copies AREA into VALUE's style. */
2621 pivot_value_set_style (struct pivot_value *value,
2622 const struct table_area_style *area)
2624 pivot_value_set_font_style (value, &area->font_style);
2625 pivot_value_set_cell_style (value, &area->cell_style);
2629 pivot_value_set_font_style (struct pivot_value *value,
2630 const struct font_style *font_style)
2632 struct pivot_value_ex *ex = pivot_value_ex_rw (value);
2634 font_style_uninit (ex->font_style);
2636 ex->font_style = xmalloc (sizeof *ex->font_style);
2637 font_style_copy (NULL, ex->font_style, font_style);
2641 pivot_value_set_cell_style (struct pivot_value *value,
2642 const struct cell_style *cell_style)
2644 struct pivot_value_ex *ex = pivot_value_ex_rw (value);
2645 if (!ex->cell_style)
2646 ex->cell_style = xmalloc (sizeof *ex->cell_style);
2647 *ex->cell_style = *cell_style;
2651 pivot_argument_copy (struct pivot_argument *dst,
2652 const struct pivot_argument *src)
2654 *dst = (struct pivot_argument) {
2656 .values = xmalloc (src->n * sizeof *dst->values),
2659 for (size_t i = 0; i < src->n; i++)
2660 dst->values[i] = pivot_value_clone (src->values[i]);
2663 /* Frees the data owned by ARG (but not ARG itself). */
2665 pivot_argument_uninit (struct pivot_argument *arg)
2669 for (size_t i = 0; i < arg->n; i++)
2670 pivot_value_destroy (arg->values[i]);
2675 /* Creates and returns a new pivot_value whose contents is the null-terminated
2676 string TEXT. Takes ownership of TEXT.
2678 This function is for text strings provided by the user (with the exception
2679 that pivot_value_new_variable() should be used for variable names). For
2680 strings that are part of the PSPP user interface, such as names of
2681 procedures, statistics, annotations, error messages, etc., use
2682 pivot_value_new_text(). */
2683 struct pivot_value *
2684 pivot_value_new_user_text_nocopy (char *text)
2686 struct pivot_value *value = xmalloc (sizeof *value);
2687 *value = (struct pivot_value) {
2689 .type = PIVOT_VALUE_TEXT,
2693 .user_provided = true,
2699 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2700 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2703 This function is for text strings provided by the user (with the exception
2704 that pivot_value_new_variable() should be used for variable names). For
2705 strings that are part of the PSPP user interface, such as names of
2706 procedures, statistics, annotations, error messages, etc., use
2707 pivot_value_new_text().j
2709 The caller retains ownership of TEXT.*/
2710 struct pivot_value *
2711 pivot_value_new_user_text (const char *text, size_t length)
2713 return pivot_value_new_user_text_nocopy (
2714 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2717 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2718 a translatable string, but not actually translated yet, e.g. enclosed in
2719 N_(). This function is for text strings that are part of the PSPP user
2720 interface, such as names of procedures, statistics, annotations, error
2721 messages, etc. For strings that come from the user, use
2722 pivot_value_new_user_text(). */
2723 struct pivot_value *
2724 pivot_value_new_text (const char *text)
2726 char *c = xstrdup (text);
2727 char *local = xstrdup (gettext (c));
2729 struct pivot_value *value = xmalloc (sizeof *value);
2730 *value = (struct pivot_value) {
2732 .type = PIVOT_VALUE_TEXT,
2736 .user_provided = false,
2742 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2744 struct pivot_value * PRINTF_FORMAT (1, 2)
2745 pivot_value_new_text_format (const char *format, ...)
2748 va_start (args, format);
2749 char *c = xvasprintf (format, args);
2752 va_start (args, format);
2753 char *local = xvasprintf (gettext (format), args);
2756 struct pivot_value *value = xmalloc (sizeof *value);
2757 *value = (struct pivot_value) {
2759 .type = PIVOT_VALUE_TEXT,
2763 .user_provided = false,
2769 /* Returns a new pivot_value that represents X.
2771 The format to use for X is unspecified. Usually the easiest way to specify
2772 a format is through assigning a result class to one of the categories that
2773 the pivot_value will end up in. If that is not suitable, then the caller
2774 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2775 struct pivot_value *
2776 pivot_value_new_number (double x)
2778 struct pivot_value *value = xmalloc (sizeof *value);
2779 *value = (struct pivot_value) {
2781 .type = PIVOT_VALUE_NUMERIC,
2788 /* Returns a new pivot_value that represents X, formatted as an integer. */
2789 struct pivot_value *
2790 pivot_value_new_integer (double x)
2792 struct pivot_value *value = pivot_value_new_number (x);
2793 value->numeric.format = (struct fmt_spec) { .type = FMT_F, .w = 40 };
2797 /* Returns a new pivot_value that represents VALUE, formatted as for
2799 struct pivot_value *
2800 pivot_value_new_var_value (const struct variable *variable,
2801 const union value *value)
2803 struct pivot_value *pv = pivot_value_new_value (
2804 value, var_get_width (variable), var_get_print_format (variable),
2805 var_get_encoding (variable));
2807 char *var_name = xstrdup (var_get_name (variable));
2808 if (var_is_alpha (variable))
2809 pv->string.var_name = var_name;
2811 pv->numeric.var_name = var_name;
2813 const char *label = var_lookup_value_label (variable, value);
2816 if (var_is_alpha (variable))
2817 pv->string.value_label = xstrdup (label);
2819 pv->numeric.value_label = xstrdup (label);
2825 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2826 formatted with FORMAT. For a string value, ENCODING must be its character
2828 struct pivot_value *
2829 pivot_value_new_value (const union value *value, int width,
2830 const struct fmt_spec *format, const char *encoding)
2832 struct pivot_value *pv = XZALLOC (struct pivot_value);
2835 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2837 size_t n = strlen (s);
2838 while (n > 0 && s[n - 1] == ' ')
2841 pv->type = PIVOT_VALUE_STRING;
2843 pv->string.hex = format->type == FMT_AHEX;
2847 pv->type = PIVOT_VALUE_NUMERIC;
2848 pv->numeric.x = value->f;
2849 pv->numeric.format = *format;
2855 /* Returns a new pivot_value for VARIABLE. */
2856 struct pivot_value *
2857 pivot_value_new_variable (const struct variable *variable)
2859 return pivot_value_new_variable__ (var_get_name (variable),
2860 var_get_label (variable));
2863 /* Returns a new pivot_value for a variable with the given NAME and optional
2865 struct pivot_value *
2866 pivot_value_new_variable__ (const char *name, const char *label)
2868 struct pivot_value *value = xmalloc (sizeof *value);
2869 *value = (struct pivot_value) {
2871 .type = PIVOT_VALUE_VARIABLE,
2872 .var_name = xstrdup (name),
2873 .var_label = xstrdup_if_nonempty (label),
2879 /* Attaches a reference to FOOTNOTE to V. */
2881 pivot_value_add_footnote (struct pivot_value *v,
2882 const struct pivot_footnote *footnote)
2884 struct pivot_value_ex *ex = pivot_value_ex_rw (v);
2886 /* Some legacy tables include numerous duplicate footnotes. Suppress
2888 for (size_t i = 0; i < ex->n_footnotes; i++)
2889 if (ex->footnote_indexes[i] == footnote->idx)
2892 ex->footnote_indexes = xrealloc (
2893 ex->footnote_indexes,
2894 (ex->n_footnotes + 1) * sizeof *ex->footnote_indexes);
2895 ex->footnote_indexes[ex->n_footnotes++] = footnote->idx;
2896 pivot_value_sort_footnotes (v);
2900 compare_footnote_indexes (const void *a_, const void *b_)
2902 const size_t *ap = a_;
2903 const size_t *bp = b_;
2906 return a < b ? -1 : a > b;
2909 /* Sorts the footnote references in V in the standard ascending order.
2911 This is only necessary if code adds (plural) footnotes to a pivot_value by
2912 itself, because pivot_value_add_footnote() does it automatically. */
2914 pivot_value_sort_footnotes (struct pivot_value *v)
2916 if (v->ex && v->ex->n_footnotes > 1)
2917 qsort (v->ex->footnote_indexes, v->ex->n_footnotes,
2918 sizeof *v->ex->footnote_indexes, compare_footnote_indexes);
2921 /* If VALUE is a numeric value, and RC is a result class such as
2922 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2924 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2927 if (value->type == PIVOT_VALUE_NUMERIC)
2928 pivot_table_use_rc (table, rc,
2929 &value->numeric.format, &value->numeric.honor_small);
2932 /* pivot_value_ex. */
2934 struct pivot_value_ex *
2935 pivot_value_ex_rw (struct pivot_value *value)
2938 value->ex = xzalloc (sizeof *value->ex);
2942 struct pivot_value_ex *
2943 pivot_value_ex_clone (const struct pivot_value_ex *old)
2945 struct font_style *font_style = NULL;
2946 if (old->font_style)
2948 font_style = xmalloc (sizeof *font_style);
2949 font_style_copy (NULL, font_style, old->font_style);
2952 char **subscripts = NULL;
2953 if (old->n_subscripts)
2955 subscripts = xnmalloc (old->n_subscripts, sizeof *subscripts);
2956 for (size_t i = 0; i < old->n_subscripts; i++)
2957 subscripts[i] = xstrdup (old->subscripts[i]);
2960 struct pivot_value_ex *new = xmalloc (sizeof *new);
2961 *new = (struct pivot_value_ex) {
2962 .font_style = font_style,
2963 .cell_style = (old->cell_style
2964 ? xmemdup (old->cell_style, sizeof *new->cell_style)
2966 .subscripts = subscripts,
2967 .n_subscripts = old->n_subscripts,
2968 .footnote_indexes = (
2970 ? xmemdup (old->footnote_indexes,
2971 old->n_footnotes * sizeof *new->footnote_indexes)
2973 .n_footnotes = old->n_footnotes
2979 pivot_value_ex_destroy (struct pivot_value_ex *ex)
2983 font_style_uninit (ex->font_style);
2984 free (ex->font_style);
2985 free (ex->cell_style);
2986 free (ex->footnote_indexes);
2988 for (size_t i = 0; i < ex->n_subscripts; i++)
2989 free (ex->subscripts[i]);
2990 free (ex->subscripts);