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"
24 #include "data/data-out.h"
25 #include "data/settings.h"
26 #include "data/value.h"
27 #include "data/variable.h"
28 #include "data/file-name.h"
29 #include "libpspp/array.h"
30 #include "libpspp/assertion.h"
31 #include "libpspp/hash-functions.h"
32 #include "libpspp/i18n.h"
33 #include "output/driver.h"
34 #include "output/spv/spv-table-look.h"
36 #include "gl/c-ctype.h"
37 #include "gl/configmake.h"
38 #include "gl/intprops.h"
39 #include "gl/minmax.h"
40 #include "gl/relocatable.h"
41 #include "gl/xalloc.h"
42 #include "gl/xmemdup0.h"
46 #define _(msgid) gettext (msgid)
47 #define N_(msgid) msgid
49 static void pivot_table_use_rc (const struct pivot_table *, const char *s,
50 struct fmt_spec *, bool *honor_small);
52 /* Pivot table display styling. */
54 /* Returns the name of AREA. */
56 pivot_area_to_string (enum pivot_area area)
60 case PIVOT_AREA_TITLE: return "title";
61 case PIVOT_AREA_CAPTION: return "caption";
62 case PIVOT_AREA_FOOTER: return "footer";
63 case PIVOT_AREA_CORNER: return "corner";
64 case PIVOT_AREA_COLUMN_LABELS: return "column labels";
65 case PIVOT_AREA_ROW_LABELS: return "row labels";
66 case PIVOT_AREA_DATA: return "data";
67 case PIVOT_AREA_LAYERS: return "layers";
68 case PIVOT_N_AREAS: default: return "**error**";
72 /* Returns the name of BORDER. */
74 pivot_border_to_string (enum pivot_border border)
78 case PIVOT_BORDER_TITLE:
81 case PIVOT_BORDER_OUTER_LEFT:
82 return "left outer frame";
83 case PIVOT_BORDER_OUTER_TOP:
84 return "top outer frame";
85 case PIVOT_BORDER_OUTER_RIGHT:
86 return "right outer frame";
87 case PIVOT_BORDER_OUTER_BOTTOM:
88 return "bottom outer frame";
90 case PIVOT_BORDER_INNER_LEFT:
91 return "left inner frame";
92 case PIVOT_BORDER_INNER_TOP:
93 return "top inner frame";
94 case PIVOT_BORDER_INNER_RIGHT:
95 return "right inner frame";
96 case PIVOT_BORDER_INNER_BOTTOM:
97 return "bottom inner frame";
99 case PIVOT_BORDER_DATA_LEFT:
100 return "data area left";
101 case PIVOT_BORDER_DATA_TOP:
102 return "data area top";
104 case PIVOT_BORDER_DIM_ROW_HORZ:
105 return "row label horizontal dimension border";
106 case PIVOT_BORDER_DIM_ROW_VERT:
107 return "row label vertical dimension border";
108 case PIVOT_BORDER_DIM_COL_HORZ:
109 return "column label horizontal dimension border";
110 case PIVOT_BORDER_DIM_COL_VERT:
111 return "column label vertical dimension border";
113 case PIVOT_BORDER_CAT_ROW_HORZ:
114 return "row label horizontal category border";
115 case PIVOT_BORDER_CAT_ROW_VERT:
116 return "row label vertical category border";
117 case PIVOT_BORDER_CAT_COL_HORZ:
118 return "column label horizontal category border";
119 case PIVOT_BORDER_CAT_COL_VERT:
120 return "column label vertical category border";
122 case PIVOT_N_BORDERS:
129 pivot_table_sizing_uninit (struct pivot_table_sizing *sizing)
133 free (sizing->widths);
134 free (sizing->breaks);
135 free (sizing->keeps);
139 /* Pivot table looks. */
141 static const struct pivot_table_look *
142 default_look (const struct pivot_table_look *new)
144 static struct pivot_table_look *look;
147 pivot_table_look_unref (look);
148 look = pivot_table_look_ref (new);
152 char *error = pivot_table_look_read ("default.stt", &look);
156 look = pivot_table_look_ref (pivot_table_look_builtin_default ());
162 const struct pivot_table_look *
163 pivot_table_look_get_default (void)
165 return default_look (NULL);
169 pivot_table_look_set_default (const struct pivot_table_look *look)
174 char * WARN_UNUSED_RESULT
175 pivot_table_look_read (const char *name, struct pivot_table_look **lookp)
179 /* Construct search path. */
183 const char *home = getenv ("HOME");
184 char *allocated = NULL;
186 path[n++] = allocated = xasprintf ("%s/.pspp/looks", home);
188 path[n++] = relocate2 (PKGDATADIR "/looks", &allocated2);
192 char *file = fn_search_path (name, (char **) path);
195 char *name2 = xasprintf ("%s.stt", name);
196 file = fn_search_path (name2, (char **) path);
202 return xasprintf ("%s: not found", name);
205 char *error = spv_table_look_read (file, lookp);
210 const struct pivot_table_look *
211 pivot_table_look_builtin_default (void)
213 static struct pivot_table_look look = {
217 .row_labels_in_corner = true,
219 [TABLE_HORZ] = { 36, 72 },
220 [TABLE_VERT] = { 36, 120 },
224 #define AREA(BOLD, H, V, L, R, T, B) { \
226 .halign = TABLE_HALIGN_##H, \
227 .valign = TABLE_VALIGN_##V, \
228 .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
229 [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
233 .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
234 .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
236 .typeface = (char *) "Sans Serif", \
239 [PIVOT_AREA_TITLE] = AREA(true, CENTER, CENTER, 8,11,1,8),
240 [PIVOT_AREA_CAPTION] = AREA(false, LEFT, TOP, 8,11,1,1),
241 [PIVOT_AREA_FOOTER] = AREA(false, LEFT, TOP, 11, 8,2,3),
242 [PIVOT_AREA_CORNER] = AREA(false, LEFT, BOTTOM, 8,11,1,1),
243 [PIVOT_AREA_COLUMN_LABELS] = AREA(false, CENTER, BOTTOM, 8,11,1,3),
244 [PIVOT_AREA_ROW_LABELS] = AREA(false, LEFT, TOP, 8,11,1,3),
245 [PIVOT_AREA_DATA] = AREA(false, MIXED, TOP, 8,11,1,1),
246 [PIVOT_AREA_LAYERS] = AREA(false, LEFT, BOTTOM, 8,11,1,3),
251 #define BORDER(STROKE) { .stroke = STROKE, .color = CELL_COLOR_BLACK }
252 [PIVOT_BORDER_TITLE] = BORDER(TABLE_STROKE_NONE),
253 [PIVOT_BORDER_OUTER_LEFT] = BORDER(TABLE_STROKE_NONE),
254 [PIVOT_BORDER_OUTER_TOP] = BORDER(TABLE_STROKE_NONE),
255 [PIVOT_BORDER_OUTER_RIGHT] = BORDER(TABLE_STROKE_NONE),
256 [PIVOT_BORDER_OUTER_BOTTOM] = BORDER(TABLE_STROKE_NONE),
257 [PIVOT_BORDER_INNER_LEFT] = BORDER(TABLE_STROKE_THICK),
258 [PIVOT_BORDER_INNER_TOP] = BORDER(TABLE_STROKE_THICK),
259 [PIVOT_BORDER_INNER_RIGHT] = BORDER(TABLE_STROKE_THICK),
260 [PIVOT_BORDER_INNER_BOTTOM] = BORDER(TABLE_STROKE_THICK),
261 [PIVOT_BORDER_DATA_LEFT] = BORDER(TABLE_STROKE_THICK),
262 [PIVOT_BORDER_DATA_TOP] = BORDER(TABLE_STROKE_THICK),
263 [PIVOT_BORDER_DIM_ROW_HORZ] = BORDER(TABLE_STROKE_SOLID),
264 [PIVOT_BORDER_DIM_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
265 [PIVOT_BORDER_DIM_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
266 [PIVOT_BORDER_DIM_COL_VERT] = BORDER(TABLE_STROKE_SOLID),
267 [PIVOT_BORDER_CAT_ROW_HORZ] = BORDER(TABLE_STROKE_NONE),
268 [PIVOT_BORDER_CAT_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
269 [PIVOT_BORDER_CAT_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
270 [PIVOT_BORDER_CAT_COL_VERT] = BORDER(TABLE_STROKE_SOLID),
277 struct pivot_table_look *
278 pivot_table_look_new_builtin_default (void)
280 return pivot_table_look_unshare (
281 pivot_table_look_ref (pivot_table_look_builtin_default ()));
284 struct pivot_table_look *
285 pivot_table_look_ref (const struct pivot_table_look *look_)
287 assert (look_->ref_cnt > 0);
289 struct pivot_table_look *look = CONST_CAST (struct pivot_table_look *, look_);
295 xstrdup_if_nonempty (const char *s)
297 return s && s[0] ? xstrdup (s) : NULL;
300 struct pivot_table_look *
301 pivot_table_look_unshare (struct pivot_table_look *old)
303 assert (old->ref_cnt > 0);
304 if (old->ref_cnt == 1)
307 pivot_table_look_unref (old);
309 struct pivot_table_look *new = xmemdup (old, sizeof *old);
311 new->name = xstrdup_if_nonempty (old->name);
312 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
313 table_area_style_copy (NULL, &new->areas[i], &old->areas[i]);
314 new->continuation = xstrdup_if_nonempty (old->continuation);
320 pivot_table_look_unref (struct pivot_table_look *look)
324 assert (look->ref_cnt > 0);
325 if (!--look->ref_cnt)
328 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
329 table_area_style_uninit (&look->areas[i]);
330 free (look->continuation);
338 /* Returns the name of AXIS_TYPE. */
340 pivot_axis_type_to_string (enum pivot_axis_type axis_type)
344 case PIVOT_AXIS_LAYER:
350 case PIVOT_AXIS_COLUMN:
358 static enum pivot_axis_type
359 pivot_axis_type_transpose (enum pivot_axis_type axis_type)
361 assert (axis_type == PIVOT_AXIS_ROW || axis_type == PIVOT_AXIS_COLUMN);
362 return (axis_type == PIVOT_AXIS_ROW ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW);
365 /* Implementation of PIVOT_AXIS_FOR_EACH. */
367 pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis)
371 if (axis->n_dimensions)
372 for (size_t i = 0; i < axis->n_dimensions; i++)
373 if (axis->dimensions[i]->n_leaves == 0)
376 size_t size = axis->n_dimensions * sizeof *indexes;
377 return xzalloc (MAX (size, 1));
380 for (size_t i = 0; i < axis->n_dimensions; i++)
382 const struct pivot_dimension *d = axis->dimensions[i];
383 if (++indexes[i] < d->n_leaves)
396 pivot_category_set_rc (struct pivot_category *category, const char *s)
401 pivot_table_use_rc (category->dimension->table, s,
402 &category->format, &category->honor_small);
404 /* Ensure that the category itself, in addition to the cells within it, takes
405 the format. (It's kind of rare for a category to have a numeric format
407 struct pivot_value *name = category->name;
408 if (name->type == PIVOT_VALUE_NUMERIC && !name->numeric.format.w)
409 pivot_table_use_rc (category->dimension->table, s,
410 &name->numeric.format, &name->numeric.honor_small);
414 pivot_category_create_leaves_valist (struct pivot_category *parent,
418 while ((s = va_arg (args, const char *)))
420 if (!strncmp (s, "RC_", 3))
422 assert (parent->n_subs);
423 pivot_category_set_rc (parent->subs[parent->n_subs - 1], s);
426 pivot_category_create_leaf (parent, pivot_value_new_text (s));
430 /* Creates a new dimension with the given NAME in TABLE and returns it. The
431 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
434 NAME should be a translatable name, but not actually translated yet,
435 e.g. enclosed in N_(). To use a different kind of value for a name, use
436 pivot_dimension_create__() instead.
438 The optional varargs parameters may be used to add an initial set of
439 categories to the dimension. Each string should be a translatable category
440 name, but not actually translated yet, e.g. enclosed in N_(). Each string
441 may optionally be followod by a PIVOT_RC_* string that specifies the default
442 numeric format for cells in this category. */
443 struct pivot_dimension * SENTINEL (0)
444 (pivot_dimension_create) (struct pivot_table *table,
445 enum pivot_axis_type axis_type,
446 const char *name, ...)
448 struct pivot_dimension *d = pivot_dimension_create__ (
449 table, axis_type, pivot_value_new_text (name));
452 va_start (args, name);
453 pivot_category_create_leaves_valist (d->root, args);
459 /* Creates a new dimension with the given NAME in TABLE and returns it. The
460 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
462 struct pivot_dimension *
463 pivot_dimension_create__ (struct pivot_table *table,
464 enum pivot_axis_type axis_type,
465 struct pivot_value *name)
467 assert (pivot_table_is_empty (table));
469 struct pivot_dimension *d = xmalloc (sizeof *d);
470 *d = (struct pivot_dimension) {
472 .axis_type = axis_type,
473 .level = table->axes[axis_type].n_dimensions,
474 .top_index = table->n_dimensions,
475 .root = xmalloc (sizeof *d->root),
478 struct pivot_category *root = d->root;
479 *root = (struct pivot_category) {
484 .data_index = SIZE_MAX,
485 .presentation_index = SIZE_MAX,
488 table->dimensions = xrealloc (
489 table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions);
490 table->dimensions[table->n_dimensions++] = d;
492 struct pivot_axis *axis = &table->axes[axis_type];
493 axis->dimensions = xrealloc (
494 axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
495 axis->dimensions[axis->n_dimensions++] = d;
497 if (axis_type == PIVOT_AXIS_LAYER)
499 free (table->current_layer);
500 table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
501 sizeof *table->current_layer);
504 /* axis->extent and axis->label_depth will be calculated later. */
510 pivot_dimension_destroy (struct pivot_dimension *d)
515 pivot_category_destroy (d->root);
516 free (d->data_leaves);
517 free (d->presentation_leaves);
521 /* Returns the first leaf node in an in-order traversal that is a child of
523 static const struct pivot_category * UNUSED
524 pivot_category_first_leaf (const struct pivot_category *cat)
526 if (pivot_category_is_leaf (cat))
529 for (size_t i = 0; i < cat->n_subs; i++)
531 const struct pivot_category *first
532 = pivot_category_first_leaf (cat->subs[i]);
540 /* Returns the next leaf node in an in-order traversal starting at CAT, which
542 static const struct pivot_category * UNUSED
543 pivot_category_next_leaf (const struct pivot_category *cat)
545 assert (pivot_category_is_leaf (cat));
549 const struct pivot_category *parent = cat->parent;
552 for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
554 const struct pivot_category *next
555 = pivot_category_first_leaf (parent->subs[i]);
565 pivot_category_add_child (struct pivot_category *child)
567 struct pivot_category *parent = child->parent;
569 assert (pivot_category_is_group (parent));
570 if (parent->n_subs >= parent->allocated_subs)
571 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
572 sizeof *parent->subs);
573 parent->subs[parent->n_subs++] = child;
576 /* Adds leaf categories as a child of PARENT. To create top-level categories
577 within dimension 'd', pass 'd->root' for PARENT.
579 Each of the varargs parameters should be a string, each of which should be a
580 translatable category name, but not actually translated yet, e.g. enclosed
581 in N_(). Each string may optionally be followod by a PIVOT_RC_* string that
582 specifies the default numeric format for cells in this category.
584 Returns the category index, which is just a 0-based array index, for the
587 Leaves have to be created in in-order, that is, don't create a group and add
588 some leaves, then add leaves outside the group and try to add more leaves
591 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
593 int retval = parent->dimension->n_leaves;
596 va_start (args, parent);
597 pivot_category_create_leaves_valist (parent, args);
603 /* Creates a new leaf category with the given NAME as a child of PARENT. To
604 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
605 Returns the category index, which is just a 0-based array index, for the new
608 Leaves have to be created in in-order, that is, don't create a group and add
609 some leaves, then add leaves outside the group and try to add more leaves
612 pivot_category_create_leaf (struct pivot_category *parent,
613 struct pivot_value *name)
615 return pivot_category_create_leaf_rc (parent, name, NULL);
618 /* Creates a new leaf category with the given NAME as a child of PARENT. To
619 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
620 Returns the category index, which is just a 0-based array index, for the new
623 If RC is nonnull and the name of a result category, the category is assigned
624 that result category.
626 Leaves have to be created in in-order, that is, don't create a group and add
627 some leaves, then add leaves outside the group and try to add more leaves
630 pivot_category_create_leaf_rc (struct pivot_category *parent,
631 struct pivot_value *name, const char *rc)
633 struct pivot_dimension *d = parent->dimension;
635 struct pivot_category *leaf = xmalloc (sizeof *leaf);
636 *leaf = (struct pivot_category) {
640 .group_index = parent->n_subs,
641 .data_index = d->n_leaves,
642 .presentation_index = d->n_leaves,
645 if (d->n_leaves >= d->allocated_leaves)
647 d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
648 sizeof *d->data_leaves);
649 d->presentation_leaves = xrealloc (
650 d->presentation_leaves,
651 d->allocated_leaves * sizeof *d->presentation_leaves);
654 d->data_leaves[d->n_leaves] = leaf;
655 d->presentation_leaves[d->n_leaves] = leaf;
658 pivot_category_add_child (leaf);
660 /* Make sure that the new child is the last in in-order. */
661 assert (!pivot_category_next_leaf (leaf));
663 pivot_category_set_rc (leaf, rc);
665 return leaf->data_index;
668 /* Adds a new category group named NAME as a child of PARENT. To create a
669 top-level group within dimension 'd', pass 'd->root' for PARENT.
671 NAME should be a translatable name, but not actually translated yet,
672 e.g. enclosed in N_(). To use a different kind of value for a name, use
673 pivot_category_create_group__() instead.
675 The optional varargs parameters may be used to add an initial set of
676 categories to the group. Each string should be a translatable category
677 name, but not actually translated yet, e.g. enclosed in N_(). Each string
678 may optionally be followod by a PIVOT_RC_* string that specifies the default
679 numeric format for cells in this category.
681 Returns the new group. */
682 struct pivot_category * SENTINEL (0)
683 (pivot_category_create_group) (struct pivot_category *parent,
684 const char *name, ...)
686 struct pivot_category *group = pivot_category_create_group__ (
687 parent, pivot_value_new_text (name));
690 va_start (args, name);
691 pivot_category_create_leaves_valist (group, args);
697 /* Adds a new category group named NAME as a child of PARENT. To create a
698 top-level group within dimension 'd', pass 'd->root' for PARENT. Returns
700 struct pivot_category *
701 pivot_category_create_group__ (struct pivot_category *parent,
702 struct pivot_value *name)
704 struct pivot_dimension *d = parent->dimension;
706 struct pivot_category *group = xmalloc (sizeof *group);
707 *group = (struct pivot_category) {
712 .group_index = parent->n_subs,
713 .data_index = SIZE_MAX,
714 .presentation_index = SIZE_MAX,
717 pivot_category_add_child (group);
723 pivot_category_destroy (struct pivot_category *c)
728 pivot_value_destroy (c->name);
729 for (size_t i = 0; i < c->n_subs; i++)
730 pivot_category_destroy (c->subs[i]);
737 These are usually the easiest way to control the formatting of numeric data
738 in a pivot table. See pivot_dimension_create() for an explanation of their
742 const char *name; /* "RC_*". */
743 struct fmt_spec format;
746 /* Formats for most of the result classes. */
747 static struct result_class result_classes[] =
749 { PIVOT_RC_INTEGER, { FMT_F, 40, 0 } },
750 { PIVOT_RC_PERCENT, { FMT_PCT, 40, 1 } },
751 { PIVOT_RC_CORRELATION, { FMT_F, 40, 3 } },
752 { PIVOT_RC_SIGNIFICANCE, { FMT_F, 40, 3 } },
753 { PIVOT_RC_RESIDUAL, { FMT_F, 40, 2 } },
754 { PIVOT_RC_COUNT, { 0, 0, 0 } },
755 { PIVOT_RC_OTHER, { 0, 0, 0 } },
758 /* Has PIVOT_RC_COUNT been overridden by the user? */
759 static bool overridden_count_format;
761 static struct result_class *
762 pivot_result_class_find (const char *s)
764 for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
765 if (!strcmp (s, result_classes[i].name))
766 return &result_classes[i];
771 pivot_table_use_rc (const struct pivot_table *table, const char *s,
772 struct fmt_spec *format, bool *honor_small)
776 if (!strcmp (s, PIVOT_RC_OTHER))
778 *format = *settings_get_format ();
781 else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
783 *format = table->weight_format;
784 *honor_small = false;
788 const struct result_class *rc = pivot_result_class_find (s);
791 *format = rc->format;
792 *honor_small = false;
796 printf ("unknown class %s\n", s);
802 /* Sets the format specification for the result class named S (which should not
803 include the RC_ prefix) to *FORMAT. Returns true if successful, false if S
804 does not name a known result class. */
806 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
808 char *s = xasprintf ("RC_%s", s_);
809 struct result_class *rc = pivot_result_class_find (s);
812 rc->format = *format;
813 if (!strcmp (s, PIVOT_RC_COUNT))
814 overridden_count_format = true;
822 is_pivot_result_class (const char *s)
824 return pivot_result_class_find (s) != NULL;
829 static struct pivot_cell *pivot_table_insert_cell (struct pivot_table *,
830 const size_t *dindexes);
831 static void pivot_table_delete_cell (struct pivot_table *,
832 struct pivot_cell *);
834 /* Creates and returns a new pivot table with the given TITLE. TITLE should be
835 a text string marked for translation but not actually translated yet,
836 e.g. N_("Descriptive Statistics"). The un-translated text string is used as
837 the pivot table's subtype.
839 This function is a shortcut for pivot_table_create__() for the most common
840 case. Use pivot_table_create__() directly if the title should be some kind
841 of value other than an ordinary text string, or if the subtype should be
842 different from the title.
844 See the large comment at the top of pivot-table.h for general advice on
845 creating pivot tables. */
847 pivot_table_create (const char *title)
849 return pivot_table_create__ (pivot_value_new_text (title), title);
852 /* Creates and returns a new pivot table with the given TITLE, and takes
853 ownership of TITLE. The new pivot table's subtype is SUBTYPE, which should
854 be an untranslated English string that describes the contents of the table
855 at a high level without being specific about the variables or other context
858 TITLE and SUBTYPE may be NULL, but in that case the client must add them
859 later because they are both mandatory for a pivot table.
861 See the large comment at the top of pivot-table.h for general advice on
862 creating pivot tables. */
864 pivot_table_create__ (struct pivot_value *title, const char *subtype)
866 struct pivot_table *table = xzalloc (sizeof *table);
868 table->show_title = true;
869 table->show_caption = true;
870 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
871 table->title = title;
872 table->subtype = subtype ? pivot_value_new_text (subtype) : NULL;
873 table->command_c = output_get_command_name ();
874 table->look = pivot_table_look_ref (pivot_table_look_get_default ());
875 table->settings = fmt_settings_copy (settings_get_fmt_settings ());
876 table->small = settings_get_small ();
878 hmap_init (&table->cells);
883 /* Creates and returns a new pivot table with the given TITLE and a single cell
884 with the given CONTENT.
886 This is really just for error handling. */
888 pivot_table_create_for_text (struct pivot_value *title,
889 struct pivot_value *content)
891 struct pivot_table *table = pivot_table_create__ (title, "Error");
893 struct pivot_dimension *d = pivot_dimension_create (
894 table, PIVOT_AXIS_ROW, N_("Error"));
895 d->hide_all_labels = true;
896 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
898 pivot_table_put1 (table, 0, content);
903 /* Increases TABLE's reference count, indicating that it has an additional
904 owner. A pivot table that is shared among multiple owners must not be
907 pivot_table_ref (const struct pivot_table *table_)
909 struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
915 xstrdup_if_nonnull (const char *s)
917 return s ? xstrdup (s) : NULL;
920 static struct pivot_table_sizing
921 clone_sizing (const struct pivot_table_sizing *s)
923 return (struct pivot_table_sizing) {
924 .widths = (s->n_widths
925 ? xmemdup (s->widths, s->n_widths * sizeof *s->widths)
927 .n_widths = s->n_widths,
929 .breaks = (s->n_breaks
930 ? xmemdup (s->breaks, s->n_breaks * sizeof *s->breaks)
932 .n_breaks = s->n_breaks,
935 ? xmemdup (s->keeps, s->n_keeps * sizeof *s->keeps)
937 .n_keeps = s->n_keeps,
941 static struct pivot_footnote **
942 clone_footnotes (struct pivot_footnote **old, size_t n)
947 struct pivot_footnote **new = xmalloc (n * sizeof *new);
948 for (size_t i = 0; i < n; i++)
950 new[i] = xmalloc (sizeof *new[i]);
951 *new[i] = (struct pivot_footnote) {
953 .content = pivot_value_clone (old[i]->content),
954 .marker = pivot_value_clone (old[i]->marker),
955 .show = old[i]->show,
961 static struct pivot_category *
962 clone_category (struct pivot_category *old,
963 struct pivot_dimension *new_dimension,
964 struct pivot_category *new_parent)
966 struct pivot_category *new = xmalloc (sizeof *new);
967 *new = (struct pivot_category) {
968 .name = pivot_value_clone (old->name),
969 .parent = new_parent,
970 .dimension = new_dimension,
971 .label_depth = old->label_depth,
972 .extra_depth = old->extra_depth,
975 ? xzalloc (old->n_subs * sizeof *new->subs)
977 .n_subs = old->n_subs,
978 .allocated_subs = old->n_subs,
980 .show_label = old->show_label,
981 .show_label_in_corner = old->show_label_in_corner,
983 .format = old->format,
984 .group_index = old->group_index,
985 .data_index = old->data_index,
986 .presentation_index = old->presentation_index,
989 if (pivot_category_is_leaf (old))
991 new->dimension->data_leaves[new->data_index] = new;
992 new->dimension->presentation_leaves[new->presentation_index] = new;
995 for (size_t i = 0; i < new->n_subs; i++)
996 new->subs[i] = clone_category (old->subs[i], new_dimension, new);
1001 static struct pivot_dimension *
1002 clone_dimension (struct pivot_dimension *old, struct pivot_table *new_pt)
1004 struct pivot_dimension *new = xmalloc (sizeof *new);
1005 *new = (struct pivot_dimension) {
1007 .axis_type = old->axis_type,
1008 .level = old->level,
1009 .top_index = old->top_index,
1010 .data_leaves = xzalloc (old->n_leaves * sizeof *new->data_leaves),
1011 .presentation_leaves = xzalloc (old->n_leaves
1012 * sizeof *new->presentation_leaves),
1013 .n_leaves = old->n_leaves,
1014 .allocated_leaves = old->n_leaves,
1015 .hide_all_labels = old->hide_all_labels,
1016 .label_depth = old->label_depth,
1019 new->root = clone_category (old->root, new, NULL);
1024 static struct pivot_dimension **
1025 clone_dimensions (struct pivot_dimension **old, size_t n,
1026 struct pivot_table *new_pt)
1031 struct pivot_dimension **new = xmalloc (n * sizeof *new);
1032 for (size_t i = 0; i < n; i++)
1033 new[i] = clone_dimension (old[i], new_pt);
1037 struct pivot_table *
1038 pivot_table_unshare (struct pivot_table *old)
1040 assert (old->ref_cnt > 0);
1041 if (old->ref_cnt == 1)
1044 pivot_table_unref (old);
1046 struct pivot_table *new = xmalloc (sizeof *new);
1047 *new = (struct pivot_table) {
1050 .look = pivot_table_look_ref (old->look),
1052 .rotate_inner_column_labels = old->rotate_inner_column_labels,
1053 .rotate_outer_row_labels = old->rotate_outer_row_labels,
1054 .show_grid_lines = old->show_grid_lines,
1055 .show_title = old->show_title,
1056 .show_caption = old->show_caption,
1057 .current_layer = (old->current_layer
1058 ? xmemdup (old->current_layer,
1059 old->axes[PIVOT_AXIS_LAYER].n_dimensions
1060 * sizeof *new->current_layer)
1062 .show_values = old->show_values,
1063 .show_variables = old->show_variables,
1064 .weight_format = old->weight_format,
1067 [TABLE_HORZ] = clone_sizing (&old->sizing[TABLE_HORZ]),
1068 [TABLE_VERT] = clone_sizing (&old->sizing[TABLE_VERT]),
1071 .settings = fmt_settings_copy (&old->settings),
1072 .grouping = old->grouping,
1073 .small = old->small,
1075 .command_local = xstrdup_if_nonnull (old->command_local),
1076 .command_c = xstrdup_if_nonnull (old->command_c),
1077 .language = xstrdup_if_nonnull (old->language),
1078 .locale = xstrdup_if_nonnull (old->locale),
1080 .dataset = xstrdup_if_nonnull (old->dataset),
1081 .datafile = xstrdup_if_nonnull (old->datafile),
1084 .footnotes = clone_footnotes (old->footnotes, old->n_footnotes),
1085 .n_footnotes = old->n_footnotes,
1086 .allocated_footnotes = old->n_footnotes,
1088 .title = pivot_value_clone (old->title),
1089 .subtype = pivot_value_clone (old->subtype),
1090 .corner_text = pivot_value_clone (old->corner_text),
1091 .caption = pivot_value_clone (old->caption),
1092 .notes = xstrdup_if_nonnull (old->notes),
1094 .dimensions = clone_dimensions (old->dimensions, old->n_dimensions, new),
1095 .n_dimensions = old->n_dimensions,
1097 .cells = HMAP_INITIALIZER (new->cells),
1100 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1102 struct pivot_axis *new_axis = &new->axes[i];
1103 const struct pivot_axis *old_axis = &old->axes[i];
1105 *new_axis = (struct pivot_axis) {
1106 .dimensions = xmalloc (old_axis->n_dimensions
1107 * sizeof *new_axis->dimensions),
1108 .n_dimensions = old_axis->n_dimensions,
1109 .extent = old_axis->extent,
1110 .label_depth = old_axis->label_depth,
1113 for (size_t i = 0; i < new_axis->n_dimensions; i++)
1114 new_axis->dimensions[i] = new->dimensions[
1115 old_axis->dimensions[i]->top_index];
1118 const struct pivot_cell *old_cell;
1119 size_t *dindexes = xmalloc (old->n_dimensions * sizeof *dindexes);
1120 HMAP_FOR_EACH (old_cell, struct pivot_cell, hmap_node, &old->cells)
1122 for (size_t i = 0; i < old->n_dimensions; i++)
1123 dindexes[i] = old_cell->idx[i];
1124 struct pivot_cell *new_cell
1125 = pivot_table_insert_cell (new, dindexes);
1126 new_cell->value = pivot_value_clone (old_cell->value);
1133 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
1134 If TABLE no longer has any owners, it is freed. */
1136 pivot_table_unref (struct pivot_table *table)
1140 assert (table->ref_cnt > 0);
1141 if (--table->ref_cnt)
1144 free (table->current_layer);
1145 pivot_table_look_unref (table->look);
1147 for (int i = 0; i < TABLE_N_AXES; i++)
1148 pivot_table_sizing_uninit (&table->sizing[i]);
1150 fmt_settings_uninit (&table->settings);
1152 free (table->command_local);
1153 free (table->command_c);
1154 free (table->language);
1155 free (table->locale);
1157 free (table->dataset);
1158 free (table->datafile);
1160 for (size_t i = 0; i < table->n_footnotes; i++)
1161 pivot_footnote_destroy (table->footnotes[i]);
1162 free (table->footnotes);
1164 pivot_value_destroy (table->title);
1165 pivot_value_destroy (table->subtype);
1166 pivot_value_destroy (table->corner_text);
1167 pivot_value_destroy (table->caption);
1168 free (table->notes);
1170 for (size_t i = 0; i < table->n_dimensions; i++)
1171 pivot_dimension_destroy (table->dimensions[i]);
1172 free (table->dimensions);
1174 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1175 free (table->axes[i].dimensions);
1177 struct pivot_cell *cell, *next_cell;
1178 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
1180 pivot_table_delete_cell (table, cell);
1182 hmap_destroy (&table->cells);
1187 /* Returns true if TABLE has more than one owner. A pivot table that is shared
1188 among multiple owners must not be modified. */
1190 pivot_table_is_shared (const struct pivot_table *table)
1192 return table->ref_cnt > 1;
1195 /* Swaps axes A and B in TABLE. */
1197 pivot_table_swap_axes (struct pivot_table *table,
1198 enum pivot_axis_type a, enum pivot_axis_type b)
1203 struct pivot_axis tmp = table->axes[a];
1204 table->axes[a] = table->axes[b];
1205 table->axes[b] = tmp;
1207 for (int a = 0; a < PIVOT_N_AXES; a++)
1209 struct pivot_axis *axis = &table->axes[a];
1210 for (size_t d = 0; d < axis->n_dimensions; d++)
1211 axis->dimensions[d]->axis_type = a;
1214 if (a == PIVOT_AXIS_LAYER || b == PIVOT_AXIS_LAYER)
1216 free (table->current_layer);
1217 table->current_layer = xzalloc (
1218 table->axes[PIVOT_AXIS_LAYER].n_dimensions
1219 * sizeof *table->current_layer);
1223 /* Swaps the row and column axes in TABLE. */
1225 pivot_table_transpose (struct pivot_table *table)
1227 pivot_table_swap_axes (table, PIVOT_AXIS_ROW, PIVOT_AXIS_COLUMN);
1231 pivot_table_update_axes (struct pivot_table *table)
1233 for (int a = 0; a < PIVOT_N_AXES; a++)
1235 struct pivot_axis *axis = &table->axes[a];
1237 for (size_t d = 0; d < axis->n_dimensions; d++)
1239 struct pivot_dimension *dim = axis->dimensions[d];
1246 /* Moves DIM from its current location in TABLE to POS within AXIS. POS of 0
1247 is the innermost dimension, 1 is the next one out, and so on. */
1249 pivot_table_move_dimension (struct pivot_table *table,
1250 struct pivot_dimension *dim,
1251 enum pivot_axis_type axis, size_t pos)
1253 assert (dim->table == table);
1255 struct pivot_axis *old_axis = &table->axes[dim->axis_type];
1256 struct pivot_axis *new_axis = &table->axes[axis];
1257 pos = MIN (pos, new_axis->n_dimensions);
1259 if (old_axis == new_axis && pos == dim->level)
1266 /* Update the current layer, if necessary. If we're moving within the layer
1267 axis, preserve the current layer. */
1268 if (dim->axis_type == PIVOT_AXIS_LAYER)
1270 if (axis == PIVOT_AXIS_LAYER)
1272 /* Rearranging the layer axis. */
1273 move_element (table->current_layer, old_axis->n_dimensions,
1274 sizeof *table->current_layer,
1279 /* A layer is becoming a row or column. */
1280 remove_element (table->current_layer, old_axis->n_dimensions,
1281 sizeof *table->current_layer, dim->level);
1284 else if (axis == PIVOT_AXIS_LAYER)
1286 /* A row or column is becoming a layer. */
1287 table->current_layer = xrealloc (
1288 table->current_layer,
1289 (new_axis->n_dimensions + 1) * sizeof *table->current_layer);
1290 insert_element (table->current_layer, new_axis->n_dimensions,
1291 sizeof *table->current_layer, pos);
1292 table->current_layer[pos] = 0;
1295 /* Remove DIM from its current axis. */
1296 remove_element (old_axis->dimensions, old_axis->n_dimensions,
1297 sizeof *old_axis->dimensions, dim->level);
1298 old_axis->n_dimensions--;
1300 /* Insert DIM into its new axis. */
1301 new_axis->dimensions = xrealloc (
1302 new_axis->dimensions,
1303 (new_axis->n_dimensions + 1) * sizeof *new_axis->dimensions);
1304 insert_element (new_axis->dimensions, new_axis->n_dimensions,
1305 sizeof *new_axis->dimensions, pos);
1306 new_axis->dimensions[pos] = dim;
1307 new_axis->n_dimensions++;
1309 pivot_table_update_axes (table);
1313 const struct pivot_table_look *
1314 pivot_table_get_look (const struct pivot_table *table)
1320 pivot_table_set_look (struct pivot_table *table,
1321 const struct pivot_table_look *look)
1323 pivot_table_look_unref (table->look);
1324 table->look = pivot_table_look_ref (look);
1327 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
1328 WV, which should be the weight variable for the dictionary whose data or
1329 statistics are being put into TABLE.
1331 This has no effect if WV is NULL. */
1333 pivot_table_set_weight_var (struct pivot_table *table,
1334 const struct variable *wv)
1337 pivot_table_set_weight_format (table, var_get_print_format (wv));
1340 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
1341 format for the dictionary whose data or statistics are being put into TABLE.
1343 This has no effect if WFMT is NULL. */
1345 pivot_table_set_weight_format (struct pivot_table *table,
1346 const struct fmt_spec *wfmt)
1349 table->weight_format = *wfmt;
1352 /* Returns true if TABLE has no cells, false otherwise. */
1354 pivot_table_is_empty (const struct pivot_table *table)
1356 return hmap_is_empty (&table->cells);
1360 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
1362 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
1366 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
1368 for (size_t i = 0; i < n; i++)
1375 static struct pivot_cell *
1376 pivot_table_lookup_cell__ (const struct pivot_table *table,
1377 const size_t *dindexes, unsigned int hash)
1379 struct pivot_cell *cell;
1380 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
1382 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
1387 static struct pivot_cell *
1388 pivot_cell_allocate (size_t n_idx)
1390 struct pivot_cell *cell UNUSED;
1391 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
1394 static struct pivot_cell *
1395 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
1397 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1398 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
1401 cell = pivot_cell_allocate (table->n_dimensions);
1402 for (size_t i = 0; i < table->n_dimensions; i++)
1403 cell->idx[i] = dindexes[i];
1405 hmap_insert (&table->cells, &cell->hmap_node, hash);
1410 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
1411 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
1414 If VALUE is a numeric value without a specified format, this function checks
1415 each of the categories designated by DINDEXES[] and takes the format from
1416 the first category with a result class. If none has a result class, uses
1417 the overall default numeric format. */
1419 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
1420 struct pivot_value *value)
1422 assert (n == table->n_dimensions);
1423 for (size_t i = 0; i < n; i++)
1424 assert (dindexes[i] < table->dimensions[i]->n_leaves);
1426 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
1428 for (size_t i = 0; i < table->n_dimensions; i++)
1430 const struct pivot_dimension *d = table->dimensions[i];
1431 if (dindexes[i] < d->n_leaves)
1433 const struct pivot_category *c = d->data_leaves[dindexes[i]];
1436 value->numeric.format = c->format;
1437 value->numeric.honor_small = c->honor_small;
1442 value->numeric.format = *settings_get_format ();
1443 value->numeric.honor_small = true;
1448 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1449 pivot_value_destroy (cell->value);
1450 cell->value = value;
1453 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
1454 dimension. Takes ownership of VALUE. */
1456 pivot_table_put1 (struct pivot_table *table, size_t idx1,
1457 struct pivot_value *value)
1459 size_t dindexes[] = { idx1 };
1460 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1463 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
1464 dimensions. Takes ownership of VALUE. */
1466 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
1467 struct pivot_value *value)
1469 size_t dindexes[] = { idx1, idx2 };
1470 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1473 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
1474 have 3 dimensions. Takes ownership of VALUE. */
1476 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
1477 size_t idx3, struct pivot_value *value)
1479 size_t dindexes[] = { idx1, idx2, idx3 };
1480 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1483 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
1484 must have 4 dimensions. Takes ownership of VALUE. */
1486 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1487 size_t idx3, size_t idx4, struct pivot_value *value)
1489 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1490 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1493 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1494 automatically assigned marker.
1496 The footnote will only appear in output if it is referenced. Use
1497 pivot_value_add_footnote() to add a reference to the footnote. */
1498 struct pivot_footnote *
1499 pivot_table_create_footnote (struct pivot_table *table,
1500 struct pivot_value *content)
1502 return pivot_table_create_footnote__ (table, table->n_footnotes,
1506 static struct pivot_value *
1507 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1509 char text[INT_BUFSIZE_BOUND (size_t)];
1510 if (show_numeric_markers)
1511 snprintf (text, sizeof text, "%d", idx + 1);
1513 str_format_26adic (idx + 1, false, text, sizeof text);
1514 return pivot_value_new_user_text (text, -1);
1517 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1518 all lower indexes as a side effect). If MARKER is nonnull, sets the
1519 footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1520 struct pivot_footnote *
1521 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1522 struct pivot_value *marker,
1523 struct pivot_value *content)
1525 if (idx >= table->n_footnotes)
1527 while (idx >= table->allocated_footnotes)
1528 table->footnotes = x2nrealloc (table->footnotes,
1529 &table->allocated_footnotes,
1530 sizeof *table->footnotes);
1531 while (idx >= table->n_footnotes)
1533 struct pivot_footnote *f = xmalloc (sizeof *f);
1534 f->idx = table->n_footnotes;
1535 f->marker = pivot_make_default_footnote_marker (
1536 f->idx, table->look->show_numeric_markers);
1540 table->footnotes[table->n_footnotes++] = f;
1544 struct pivot_footnote *f = table->footnotes[idx];
1547 pivot_value_destroy (f->marker);
1552 pivot_value_destroy (f->content);
1553 f->content = content;
1558 /* Frees the data owned by F. */
1560 pivot_footnote_destroy (struct pivot_footnote *f)
1564 pivot_value_destroy (f->content);
1565 pivot_value_destroy (f->marker);
1570 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1571 indexes for each dimension in TABLE in DINDEXES[]. */
1573 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1574 const size_t *pindexes[PIVOT_N_AXES],
1575 size_t dindexes[/* table->n_dimensions */])
1577 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1579 const struct pivot_axis *axis = &table->axes[i];
1581 for (size_t j = 0; j < axis->n_dimensions; j++)
1583 const struct pivot_dimension *d = axis->dimensions[j];
1584 dindexes[d->top_index]
1585 = d->presentation_leaves[pindexes[i][j]]->data_index;
1591 pivot_table_enumerate_axis (const struct pivot_table *table,
1592 enum pivot_axis_type axis_type,
1593 const size_t *layer_indexes, bool omit_empty,
1596 const struct pivot_axis *axis = &table->axes[axis_type];
1597 if (!axis->n_dimensions)
1599 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1601 enumeration[1] = SIZE_MAX;
1606 else if (!axis->extent)
1608 size_t *enumeration = xmalloc (sizeof *enumeration);
1609 *enumeration = SIZE_MAX;
1615 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1616 axis->n_dimensions), 1),
1617 sizeof *enumeration);
1618 size_t *p = enumeration;
1619 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1621 size_t *axis_indexes;
1622 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1626 enum pivot_axis_type axis2_type
1627 = pivot_axis_type_transpose (axis_type);
1629 size_t *axis2_indexes;
1630 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1632 const size_t *pindexes[PIVOT_N_AXES];
1633 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1634 pindexes[axis_type] = axis_indexes;
1635 pindexes[axis2_type] = axis2_indexes;
1636 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1637 if (pivot_table_get (table, dindexes))
1643 free (axis2_indexes);
1646 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1647 p += axis->n_dimensions;
1649 if (omit_empty && p == enumeration)
1651 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1653 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1654 p += axis->n_dimensions;
1659 *n = (p - enumeration) / axis->n_dimensions;
1665 static struct pivot_cell *
1666 pivot_table_lookup_cell (const struct pivot_table *table,
1667 const size_t *dindexes)
1669 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1670 return pivot_table_lookup_cell__ (table, dindexes, hash);
1673 const struct pivot_value *
1674 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1676 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1677 return cell ? cell->value : NULL;
1680 struct pivot_value *
1681 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1683 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1685 cell->value = pivot_value_new_user_text ("", -1);
1690 pivot_table_delete_cell (struct pivot_table *table, struct pivot_cell *cell)
1692 hmap_delete (&table->cells, &cell->hmap_node);
1693 pivot_value_destroy (cell->value);
1698 pivot_table_delete (struct pivot_table *table, const size_t *dindexes)
1700 struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1703 pivot_table_delete_cell (table, cell);
1711 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1713 if (pivot_category_is_group (category) && category->n_subs)
1714 for (size_t i = 0; i < category->n_subs; i++)
1715 distribute_extra_depth (category->subs[i], extra_depth);
1717 category->extra_depth += extra_depth;
1721 pivot_category_assign_label_depth (struct pivot_category *category,
1722 bool dimension_labels_in_corner)
1724 category->extra_depth = 0;
1726 if (pivot_category_is_group (category))
1729 for (size_t i = 0; i < category->n_subs; i++)
1731 pivot_category_assign_label_depth (category->subs[i], false);
1732 depth = MAX (depth, category->subs[i]->label_depth);
1735 for (size_t i = 0; i < category->n_subs; i++)
1737 struct pivot_category *sub = category->subs[i];
1739 size_t extra_depth = depth - sub->label_depth;
1741 distribute_extra_depth (sub, extra_depth);
1743 sub->label_depth = depth;
1746 category->show_label_in_corner = (category->show_label
1747 && dimension_labels_in_corner);
1748 category->label_depth
1749 = (category->show_label && !category->show_label_in_corner
1750 ? depth + 1 : depth);
1753 category->label_depth = 1;
1757 pivot_axis_assign_label_depth (struct pivot_table *table,
1758 enum pivot_axis_type axis_type,
1759 bool dimension_labels_in_corner)
1761 struct pivot_axis *axis = &table->axes[axis_type];
1762 bool any_label_shown_in_corner = false;
1763 axis->label_depth = 0;
1765 for (size_t i = 0; i < axis->n_dimensions; i++)
1767 struct pivot_dimension *d = axis->dimensions[i];
1768 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1769 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1770 axis->label_depth += d->label_depth;
1771 axis->extent *= d->n_leaves;
1773 if (d->root->show_label_in_corner)
1774 any_label_shown_in_corner = true;
1776 return any_label_shown_in_corner;
1780 pivot_table_assign_label_depth (struct pivot_table *table)
1782 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1783 if (pivot_axis_assign_label_depth (
1784 table, PIVOT_AXIS_ROW, (table->look->row_labels_in_corner
1785 && !table->corner_text))
1786 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1787 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1788 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1792 indent (int indentation)
1794 for (int i = 0; i < indentation * 2; i++)
1799 pivot_value_dump (const struct pivot_value *value,
1800 const struct pivot_table *pt)
1802 char *s = pivot_value_to_string (value, pt);
1808 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1809 const struct pivot_table *pt, int indentation)
1813 indent (indentation);
1814 printf ("%s: ", name);
1815 pivot_value_dump (value, pt);
1821 pivot_table_dump_string (const char *string, const char *name, int indentation)
1825 indent (indentation);
1826 printf ("%s: %s\n", name, string);
1831 pivot_category_dump (const struct pivot_category *c,
1832 const struct pivot_table *pt, int indentation)
1834 indent (indentation);
1835 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1836 pivot_value_dump (c->name, pt);
1839 if (pivot_category_is_leaf (c))
1840 printf ("data_index=%zu\n", c->data_index);
1843 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1846 for (size_t i = 0; i < c->n_subs; i++)
1847 pivot_category_dump (c->subs[i], pt, indentation + 1);
1852 pivot_dimension_dump (const struct pivot_dimension *d,
1853 const struct pivot_table *pt, int indentation)
1855 indent (indentation);
1856 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1857 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1859 pivot_category_dump (d->root, pt, indentation + 1);
1863 table_area_style_dump (enum pivot_area area, const struct table_area_style *a,
1866 indent (indentation);
1867 printf ("%s: ", pivot_area_to_string (area));
1868 font_style_dump (&a->font_style);
1870 cell_style_dump (&a->cell_style);
1875 table_border_style_dump (enum pivot_border border,
1876 const struct table_border_style *b, int indentation)
1878 indent (indentation);
1879 printf ("%s: %s ", pivot_border_to_string (border),
1880 table_stroke_to_string (b->stroke));
1881 cell_color_dump (&b->color);
1886 compose_headings (const struct pivot_table *pt,
1887 const struct pivot_axis *axis,
1888 const size_t *column_enumeration)
1890 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1893 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1894 for (size_t i = 0; i < axis->label_depth; i++)
1895 headings[i] = xcalloc (axis->extent, sizeof **headings);
1897 const size_t *indexes;
1899 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1901 int row = axis->label_depth - 1;
1902 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1904 const struct pivot_dimension *d = axis->dimensions[dim_index];
1905 if (d->hide_all_labels)
1907 for (const struct pivot_category *c
1908 = d->presentation_leaves[indexes[dim_index]];
1912 if (pivot_category_is_leaf (c) || (c->show_label
1913 && !c->show_label_in_corner))
1915 headings[row][column] = pivot_value_to_string (c->name, pt);
1916 if (!*headings[row][column])
1917 headings[row][column] = xstrdup ("<blank>");
1929 free_headings (const struct pivot_axis *axis, char ***headings)
1931 for (size_t i = 0; i < axis->label_depth; i++)
1933 for (size_t j = 0; j < axis->extent; j++)
1934 free (headings[i][j]);
1941 pivot_table_sizing_dump (const char *name,
1942 const int width_ranges[2],
1943 const struct pivot_table_sizing *s,
1946 indent (indentation);
1947 printf ("%ss: min=%d, max=%d\n", name, width_ranges[0], width_ranges[1]);
1950 indent (indentation + 1);
1951 printf ("%s widths:", name);
1952 for (size_t i = 0; i < s->n_widths; i++)
1953 printf (" %d", s->widths[i]);
1958 indent (indentation + 1);
1959 printf ("break after %ss:", name);
1960 for (size_t i = 0; i < s->n_breaks; i++)
1961 printf (" %zu", s->breaks[i]);
1966 indent (indentation + 1);
1967 printf ("keep %ss together:", name);
1968 for (size_t i = 0; i < s->n_keeps; i++)
1969 printf (" [%zu,%zu]",
1971 s->keeps[i].ofs + s->keeps[i].n - 1);
1977 pivot_table_dump (const struct pivot_table *table, int indentation)
1982 pivot_table_assign_label_depth (CONST_CAST (struct pivot_table *, table));
1984 pivot_table_dump_value (table->title, "title", table, indentation);
1985 pivot_table_dump_value (table->subtype, "subtype", table, indentation);
1986 pivot_table_dump_string (table->command_c, "command", indentation);
1987 pivot_table_dump_string (table->dataset, "dataset", indentation);
1988 pivot_table_dump_string (table->datafile, "datafile", indentation);
1989 pivot_table_dump_string (table->notes, "notes", indentation);
1990 pivot_table_dump_string (table->look->name, "table-look", indentation);
1993 indent (indentation);
1995 struct tm *tm = localtime (&table->date);
1996 printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
1997 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
2001 indent (indentation);
2002 printf ("sizing:\n");
2003 pivot_table_sizing_dump ("column", table->look->width_ranges[TABLE_HORZ],
2004 &table->sizing[TABLE_HORZ], indentation + 1);
2005 pivot_table_sizing_dump ("row", table->look->width_ranges[TABLE_VERT],
2006 &table->sizing[TABLE_VERT], indentation + 1);
2008 indent (indentation);
2009 printf ("areas:\n");
2010 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
2011 table_area_style_dump (area, &table->look->areas[area], indentation + 1);
2013 indent (indentation);
2014 printf ("borders:\n");
2015 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
2016 table_border_style_dump (border, &table->look->borders[border],
2019 for (size_t i = 0; i < table->n_dimensions; i++)
2020 pivot_dimension_dump (table->dimensions[i], table, indentation);
2022 /* Presentation and data indexes. */
2023 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
2025 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
2026 if (layer_axis->n_dimensions)
2028 indent (indentation);
2029 printf ("current layer:");
2031 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
2033 const struct pivot_dimension *d = layer_axis->dimensions[i];
2034 char *name = pivot_value_to_string (d->root->name, table);
2035 char *value = pivot_value_to_string (
2036 d->data_leaves[table->current_layer[i]]->name, table);
2037 printf (" %s=%s", name, value);
2045 size_t *layer_indexes;
2046 size_t layer_iteration = 0;
2047 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
2049 indent (indentation);
2050 printf ("layer %zu:", layer_iteration++);
2052 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
2053 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
2055 const struct pivot_dimension *d = layer_axis->dimensions[i];
2057 fputs (i == 0 ? " " : ", ", stdout);
2058 pivot_value_dump (d->root->name, table);
2059 fputs (" =", stdout);
2061 struct pivot_value **names = xnmalloc (d->n_leaves, sizeof *names);
2063 for (const struct pivot_category *c
2064 = d->presentation_leaves[layer_indexes[i]];
2068 if (pivot_category_is_leaf (c) || c->show_label)
2069 names[n_names++] = c->name;
2072 for (size_t i = n_names; i-- > 0;)
2075 pivot_value_dump (names[i], table);
2081 size_t *column_enumeration = pivot_table_enumerate_axis (
2082 table, PIVOT_AXIS_COLUMN, layer_indexes, table->look->omit_empty, NULL);
2083 size_t *row_enumeration = pivot_table_enumerate_axis (
2084 table, PIVOT_AXIS_ROW, layer_indexes, table->look->omit_empty, NULL);
2086 char ***column_headings = compose_headings (
2087 table, &table->axes[PIVOT_AXIS_COLUMN], column_enumeration);
2088 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
2090 indent (indentation + 1);
2091 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
2094 fputs ("; ", stdout);
2095 if (column_headings[y][x])
2096 fputs (column_headings[y][x], stdout);
2100 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
2102 indent (indentation + 1);
2103 printf ("-----------------------------------------------\n");
2105 char ***row_headings = compose_headings (
2106 table, &table->axes[PIVOT_AXIS_ROW], row_enumeration);
2109 const size_t *pindexes[PIVOT_N_AXES]
2110 = { [PIVOT_AXIS_LAYER] = layer_indexes };
2111 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
2112 &table->axes[PIVOT_AXIS_ROW])
2114 indent (indentation + 1);
2117 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
2120 fputs ("; ", stdout);
2121 if (row_headings[y][x])
2122 fputs (row_headings[y][x], stdout);
2128 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
2130 &table->axes[PIVOT_AXIS_COLUMN])
2135 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
2136 const struct pivot_value *value = pivot_table_get (
2139 pivot_value_dump (value, table);
2146 free (column_enumeration);
2147 free (row_enumeration);
2148 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
2151 pivot_table_dump_value (table->caption, "caption", table, indentation);
2153 for (size_t i = 0; i < table->n_footnotes; i++)
2155 const struct pivot_footnote *f = table->footnotes[i];
2156 indent (indentation);
2159 pivot_value_dump (f->marker, table);
2161 printf ("%zu", f->idx);
2163 pivot_value_dump (f->content, table);
2171 consume_int (const char *p, size_t *n)
2174 while (c_isdigit (*p))
2175 *n = *n * 10 + (*p++ - '0');
2180 pivot_format_inner_template (struct string *out, const char *template,
2182 struct pivot_value **values, size_t n_values,
2183 const struct pivot_table *pt)
2185 size_t args_consumed = 0;
2186 while (*template && *template != ':')
2188 if (*template == '\\' && template[1])
2190 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
2193 else if (*template == escape)
2196 template = consume_int (template + 1, &index);
2197 if (index >= 1 && index <= n_values)
2199 pivot_value_format (values[index - 1], pt, out);
2200 args_consumed = MAX (args_consumed, index);
2204 ds_put_byte (out, *template++);
2206 return args_consumed;
2210 pivot_extract_inner_template (const char *template, const char **p)
2216 if (*template == '\\' && template[1] != '\0')
2218 else if (*template == ':')
2219 return template + 1;
2220 else if (*template == '\0')
2228 pivot_format_template (struct string *out, const char *template,
2229 const struct pivot_argument *args, size_t n_args,
2230 const struct pivot_table *pt)
2234 if (*template == '\\' && template[1] != '\0')
2236 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
2239 else if (*template == '^')
2242 template = consume_int (template + 1, &index);
2243 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
2244 pivot_value_format (args[index - 1].values[0], pt, out);
2246 else if (*template == '[')
2248 const char *tmpl[2];
2249 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
2250 template = pivot_extract_inner_template (template, &tmpl[1]);
2251 template += *template == ']';
2254 template = consume_int (template, &index);
2255 if (index < 1 || index > n_args)
2258 const struct pivot_argument *arg = &args[index - 1];
2259 size_t left = arg->n;
2262 struct pivot_value **values = arg->values + (arg->n - left);
2263 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
2264 char escape = "%^"[tmpl_idx];
2265 size_t used = pivot_format_inner_template (
2266 out, tmpl[tmpl_idx], escape, values, left, pt);
2267 if (!used || used > left)
2273 ds_put_byte (out, *template++);
2277 static enum settings_value_show
2278 interpret_show (enum settings_value_show global_show,
2279 enum settings_value_show table_show,
2280 enum settings_value_show value_show,
2283 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
2284 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
2285 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
2289 /* Appends a text representation of the body of VALUE to OUT. Settings on
2290 PT control whether variable and value labels are included.
2292 The "body" omits subscripts and superscripts and footnotes.
2294 Returns true if OUT is a number (or a number plus a value label), false
2297 pivot_value_format_body (const struct pivot_value *value,
2298 const struct pivot_table *pt,
2301 enum settings_value_show show;
2302 bool numeric = false;
2304 switch (value->type)
2306 case PIVOT_VALUE_NUMERIC:
2307 show = interpret_show (settings_get_show_values (),
2309 value->numeric.show,
2310 value->numeric.value_label != NULL);
2311 if (show & SETTINGS_VALUE_SHOW_VALUE)
2313 const struct fmt_spec *f = &value->numeric.format;
2314 const struct fmt_spec *format
2316 && value->numeric.honor_small
2317 && value->numeric.x != 0
2318 && fabs (value->numeric.x) < pt->small
2319 ? &(struct fmt_spec) { .type = FMT_E, .w = 40, .d = f->d }
2322 char *s = data_out (&(union value) { .f = value->numeric.x },
2323 "UTF-8", format, &pt->settings);
2324 ds_put_cstr (out, s + strspn (s, " "));
2327 if (show & SETTINGS_VALUE_SHOW_LABEL)
2329 if (show & SETTINGS_VALUE_SHOW_VALUE)
2330 ds_put_byte (out, ' ');
2331 ds_put_cstr (out, value->numeric.value_label);
2333 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
2336 case PIVOT_VALUE_STRING:
2337 show = interpret_show (settings_get_show_values (),
2340 value->string.value_label != NULL);
2341 if (show & SETTINGS_VALUE_SHOW_VALUE)
2343 if (value->string.hex)
2345 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
2347 ds_put_format (out, "%02X", *p);
2350 ds_put_cstr (out, value->string.s);
2352 if (show & SETTINGS_VALUE_SHOW_LABEL)
2354 if (show & SETTINGS_VALUE_SHOW_VALUE)
2355 ds_put_byte (out, ' ');
2356 ds_put_cstr (out, value->string.value_label);
2360 case PIVOT_VALUE_VARIABLE:
2361 show = interpret_show (settings_get_show_variables (),
2363 value->variable.show,
2364 value->variable.var_label != NULL);
2365 if (show & SETTINGS_VALUE_SHOW_VALUE)
2366 ds_put_cstr (out, value->variable.var_name);
2367 if (show & SETTINGS_VALUE_SHOW_LABEL)
2369 if (show & SETTINGS_VALUE_SHOW_VALUE)
2370 ds_put_byte (out, ' ');
2371 ds_put_cstr (out, value->variable.var_label);
2375 case PIVOT_VALUE_TEXT:
2376 ds_put_cstr (out, value->text.local);
2379 case PIVOT_VALUE_TEMPLATE:
2380 pivot_format_template (out, value->template.local, value->template.args,
2381 value->template.n_args, pt);
2388 /* Appends a text representation of VALUE to OUT. Settings on
2389 PT control whether variable and value labels are included.
2391 Subscripts and footnotes are included. */
2393 pivot_value_format (const struct pivot_value *value,
2394 const struct pivot_table *pt,
2397 pivot_value_format_body (value, pt, out);
2399 if (value->n_subscripts)
2401 for (size_t i = 0; i < value->n_subscripts; i++)
2402 ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
2405 for (size_t i = 0; i < value->n_footnotes; i++)
2407 ds_put_byte (out, '[');
2409 size_t idx = value->footnote_indexes[i];
2410 const struct pivot_footnote *f = pt->footnotes[idx];
2411 pivot_value_format (f->marker, pt, out);
2413 ds_put_byte (out, ']');
2417 /* Returns a text representation of VALUE. The caller must free the string,
2420 pivot_value_to_string (const struct pivot_value *value,
2421 const struct pivot_table *pt)
2423 struct string s = DS_EMPTY_INITIALIZER;
2424 pivot_value_format (value, pt, &s);
2425 return ds_steal_cstr (&s);
2429 pivot_value_to_string_defaults (const struct pivot_value *value)
2431 static const struct pivot_table pt = {
2432 .show_values = SETTINGS_VALUE_SHOW_DEFAULT,
2433 .show_variables = SETTINGS_VALUE_SHOW_DEFAULT,
2435 return pivot_value_to_string (value, &pt);
2438 struct pivot_value *
2439 pivot_value_clone (const struct pivot_value *old)
2444 struct pivot_value *new = xmemdup (old, sizeof *new);
2445 if (old->font_style)
2447 new->font_style = xmalloc (sizeof *new->font_style);
2448 font_style_copy (NULL, new->font_style, old->font_style);
2450 if (old->cell_style)
2451 new->font_style = xmemdup (old->font_style, sizeof *new->font_style);
2452 if (old->n_subscripts)
2454 new->subscripts = xnmalloc (old->n_subscripts, sizeof *new->subscripts);
2455 for (size_t i = 0; i < old->n_subscripts; i++)
2456 new->subscripts[i] = xstrdup (old->subscripts[i]);
2458 if (old->n_footnotes)
2459 new->footnote_indexes = xmemdup (
2460 old->footnote_indexes, old->n_footnotes * sizeof *new->footnote_indexes);
2464 case PIVOT_VALUE_NUMERIC:
2465 new->numeric.var_name = xstrdup_if_nonnull (new->numeric.var_name);
2466 new->numeric.value_label = xstrdup_if_nonnull (new->numeric.value_label);
2469 case PIVOT_VALUE_STRING:
2470 new->string.s = xstrdup (new->string.s);
2471 new->string.var_name = xstrdup_if_nonnull (new->string.var_name);
2472 new->string.value_label = xstrdup_if_nonnull (new->string.value_label);
2475 case PIVOT_VALUE_VARIABLE:
2476 new->variable.var_name = xstrdup_if_nonnull (new->variable.var_name);
2477 new->variable.var_label = xstrdup_if_nonnull (new->variable.var_label);
2480 case PIVOT_VALUE_TEXT:
2481 new->text.local = xstrdup (old->text.local);
2482 new->text.c = (old->text.c == old->text.local ? new->text.local
2483 : xstrdup (old->text.c));
2484 new->text.id = (old->text.id == old->text.local ? new->text.local
2485 : old->text.id == old->text.c ? new->text.c
2486 : xstrdup (old->text.id));
2489 case PIVOT_VALUE_TEMPLATE:
2490 new->template.local = xstrdup (old->template.local);
2491 new->template.id = (old->template.id == old->template.local
2492 ? new->template.local
2493 : xstrdup (old->template.id));
2494 new->template.args = xmalloc (new->template.n_args
2495 * sizeof *new->template.args);
2496 for (size_t i = 0; i < old->template.n_args; i++)
2497 pivot_argument_copy (&new->template.args[i],
2498 &old->template.args[i]);
2507 /* Frees the data owned by V. */
2509 pivot_value_destroy (struct pivot_value *value)
2513 font_style_uninit (value->font_style);
2514 free (value->font_style);
2515 free (value->cell_style);
2516 free (value->footnote_indexes);
2518 for (size_t i = 0; i < value->n_subscripts; i++)
2519 free (value->subscripts[i]);
2520 free (value->subscripts);
2522 switch (value->type)
2524 case PIVOT_VALUE_NUMERIC:
2525 free (value->numeric.var_name);
2526 free (value->numeric.value_label);
2529 case PIVOT_VALUE_STRING:
2530 free (value->string.s);
2531 free (value->string.var_name);
2532 free (value->string.value_label);
2535 case PIVOT_VALUE_VARIABLE:
2536 free (value->variable.var_name);
2537 free (value->variable.var_label);
2540 case PIVOT_VALUE_TEXT:
2541 free (value->text.local);
2542 if (value->text.c != value->text.local)
2543 free (value->text.c);
2544 if (value->text.id != value->text.local
2545 && value->text.id != value->text.c)
2546 free (value->text.id);
2549 case PIVOT_VALUE_TEMPLATE:
2550 free (value->template.local);
2551 if (value->template.id != value->template.local)
2552 free (value->template.id);
2553 for (size_t i = 0; i < value->template.n_args; i++)
2554 pivot_argument_uninit (&value->template.args[i]);
2555 free (value->template.args);
2565 /* Sets AREA to the style to use for VALUE, with defaults coming from
2566 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
2568 pivot_value_get_style (struct pivot_value *value,
2569 const struct font_style *base_font_style,
2570 const struct cell_style *base_cell_style,
2571 struct table_area_style *area)
2573 font_style_copy (NULL, &area->font_style, (value->font_style
2575 : base_font_style));
2576 area->cell_style = *(value->cell_style
2581 /* Copies AREA into VALUE's style. */
2583 pivot_value_set_style (struct pivot_value *value,
2584 const struct table_area_style *area)
2586 pivot_value_set_font_style (value, &area->font_style);
2587 pivot_value_set_cell_style (value, &area->cell_style);
2591 pivot_value_set_font_style (struct pivot_value *value,
2592 const struct font_style *font_style)
2594 if (value->font_style)
2595 font_style_uninit (value->font_style);
2597 value->font_style = xmalloc (sizeof *value->font_style);
2598 font_style_copy (NULL, value->font_style, font_style);
2602 pivot_value_set_cell_style (struct pivot_value *value,
2603 const struct cell_style *cell_style)
2605 if (!value->cell_style)
2606 value->cell_style = xmalloc (sizeof *value->cell_style);
2607 *value->cell_style = *cell_style;
2611 pivot_argument_copy (struct pivot_argument *dst,
2612 const struct pivot_argument *src)
2614 *dst = (struct pivot_argument) {
2616 .values = xmalloc (src->n * sizeof *dst->values),
2619 for (size_t i = 0; i < src->n; i++)
2620 dst->values[i] = pivot_value_clone (src->values[i]);
2623 /* Frees the data owned by ARG (but not ARG itself). */
2625 pivot_argument_uninit (struct pivot_argument *arg)
2629 for (size_t i = 0; i < arg->n; i++)
2630 pivot_value_destroy (arg->values[i]);
2635 /* Creates and returns a new pivot_value whose contents is the null-terminated
2636 string TEXT. Takes ownership of TEXT.
2638 This function is for text strings provided by the user (with the exception
2639 that pivot_value_new_variable() should be used for variable names). For
2640 strings that are part of the PSPP user interface, such as names of
2641 procedures, statistics, annotations, error messages, etc., use
2642 pivot_value_new_text(). */
2643 struct pivot_value *
2644 pivot_value_new_user_text_nocopy (char *text)
2646 struct pivot_value *value = xmalloc (sizeof *value);
2647 *value = (struct pivot_value) {
2648 .type = PIVOT_VALUE_TEXT,
2653 .user_provided = true,
2659 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2660 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2663 This function is for text strings provided by the user (with the exception
2664 that pivot_value_new_variable() should be used for variable names). For
2665 strings that are part of the PSPP user interface, such as names of
2666 procedures, statistics, annotations, error messages, etc., use
2667 pivot_value_new_text().j
2669 The caller retains ownership of TEXT.*/
2670 struct pivot_value *
2671 pivot_value_new_user_text (const char *text, size_t length)
2673 return pivot_value_new_user_text_nocopy (
2674 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2677 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2678 a translatable string, but not actually translated yet, e.g. enclosed in
2679 N_(). This function is for text strings that are part of the PSPP user
2680 interface, such as names of procedures, statistics, annotations, error
2681 messages, etc. For strings that come from the user, use
2682 pivot_value_new_user_text(). */
2683 struct pivot_value *
2684 pivot_value_new_text (const char *text)
2686 char *c = xstrdup (text);
2687 char *local = xstrdup (gettext (c));
2689 struct pivot_value *value = xmalloc (sizeof *value);
2690 *value = (struct pivot_value) {
2691 .type = PIVOT_VALUE_TEXT,
2696 .user_provided = false,
2702 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2704 struct pivot_value * PRINTF_FORMAT (1, 2)
2705 pivot_value_new_text_format (const char *format, ...)
2708 va_start (args, format);
2709 char *c = xvasprintf (format, args);
2712 va_start (args, format);
2713 char *local = xvasprintf (gettext (format), args);
2716 struct pivot_value *value = xmalloc (sizeof *value);
2717 *value = (struct pivot_value) {
2718 .type = PIVOT_VALUE_TEXT,
2723 .user_provided = false,
2729 /* Returns a new pivot_value that represents X.
2731 The format to use for X is unspecified. Usually the easiest way to specify
2732 a format is through assigning a result class to one of the categories that
2733 the pivot_value will end up in. If that is not suitable, then the caller
2734 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2735 struct pivot_value *
2736 pivot_value_new_number (double x)
2738 struct pivot_value *value = xmalloc (sizeof *value);
2739 *value = (struct pivot_value) {
2740 .type = PIVOT_VALUE_NUMERIC,
2741 .numeric = { .x = x, },
2746 /* Returns a new pivot_value that represents X, formatted as an integer. */
2747 struct pivot_value *
2748 pivot_value_new_integer (double x)
2750 struct pivot_value *value = pivot_value_new_number (x);
2751 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2755 /* Returns a new pivot_value that represents VALUE, formatted as for
2757 struct pivot_value *
2758 pivot_value_new_var_value (const struct variable *variable,
2759 const union value *value)
2761 struct pivot_value *pv = pivot_value_new_value (
2762 value, var_get_width (variable), var_get_print_format (variable),
2763 var_get_encoding (variable));
2765 char *var_name = xstrdup (var_get_name (variable));
2766 if (var_is_alpha (variable))
2767 pv->string.var_name = var_name;
2769 pv->numeric.var_name = var_name;
2771 const char *label = var_lookup_value_label (variable, value);
2774 if (var_is_alpha (variable))
2775 pv->string.value_label = xstrdup (label);
2777 pv->numeric.value_label = xstrdup (label);
2783 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2784 formatted with FORMAT. For a string value, ENCODING must be its character
2786 struct pivot_value *
2787 pivot_value_new_value (const union value *value, int width,
2788 const struct fmt_spec *format, const char *encoding)
2790 struct pivot_value *pv = xzalloc (sizeof *pv);
2793 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2795 size_t n = strlen (s);
2796 while (n > 0 && s[n - 1] == ' ')
2799 pv->type = PIVOT_VALUE_STRING;
2801 pv->string.hex = format->type == FMT_AHEX;
2805 pv->type = PIVOT_VALUE_NUMERIC;
2806 pv->numeric.x = value->f;
2807 pv->numeric.format = *format;
2813 /* Returns a new pivot_value for VARIABLE. */
2814 struct pivot_value *
2815 pivot_value_new_variable (const struct variable *variable)
2817 struct pivot_value *value = xmalloc (sizeof *value);
2818 *value = (struct pivot_value) {
2819 .type = PIVOT_VALUE_VARIABLE,
2821 .var_name = xstrdup (var_get_name (variable)),
2822 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2828 /* Attaches a reference to FOOTNOTE to V. */
2830 pivot_value_add_footnote (struct pivot_value *v,
2831 const struct pivot_footnote *footnote)
2833 /* Some legacy tables include numerous duplicate footnotes. Suppress
2835 for (size_t i = 0; i < v->n_footnotes; i++)
2836 if (v->footnote_indexes[i] == footnote->idx)
2839 v->footnote_indexes = xrealloc (
2840 v->footnote_indexes, (v->n_footnotes + 1) * sizeof *v->footnote_indexes);
2841 v->footnote_indexes[v->n_footnotes++] = footnote->idx;
2844 /* If VALUE is a numeric value, and RC is a result class such as
2845 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2847 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2850 if (value->type == PIVOT_VALUE_NUMERIC)
2851 pivot_table_use_rc (table, rc,
2852 &value->numeric.format, &value->numeric.honor_small);