1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2017, 2018 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "output/pivot-table.h"
23 #include "data/data-out.h"
24 #include "data/settings.h"
25 #include "data/value.h"
26 #include "data/variable.h"
27 #include "data/file-name.h"
28 #include "libpspp/array.h"
29 #include "libpspp/assertion.h"
30 #include "libpspp/hash-functions.h"
31 #include "libpspp/i18n.h"
32 #include "output/driver.h"
33 #include "output/spv/spv-table-look.h"
35 #include "gl/c-ctype.h"
36 #include "gl/configmake.h"
37 #include "gl/intprops.h"
38 #include "gl/minmax.h"
39 #include "gl/relocatable.h"
40 #include "gl/xalloc.h"
41 #include "gl/xmemdup0.h"
45 #define _(msgid) gettext (msgid)
46 #define N_(msgid) msgid
48 static const struct fmt_spec *pivot_table_get_format (
49 const struct pivot_table *, const char *s);
51 /* Pivot table display styling. */
53 /* Returns the name of AREA. */
55 pivot_area_to_string (enum pivot_area area)
59 case PIVOT_AREA_TITLE: return "title";
60 case PIVOT_AREA_CAPTION: return "caption";
61 case PIVOT_AREA_FOOTER: return "footer";
62 case PIVOT_AREA_CORNER: return "corner";
63 case PIVOT_AREA_COLUMN_LABELS: return "column labels";
64 case PIVOT_AREA_ROW_LABELS: return "row labels";
65 case PIVOT_AREA_DATA: return "data";
66 case PIVOT_AREA_LAYERS: return "layers";
67 case PIVOT_N_AREAS: default: return "**error**";
71 /* Returns the name of BORDER. */
73 pivot_border_to_string (enum pivot_border border)
77 case PIVOT_BORDER_TITLE:
80 case PIVOT_BORDER_OUTER_LEFT:
81 return "left outer frame";
82 case PIVOT_BORDER_OUTER_TOP:
83 return "top outer frame";
84 case PIVOT_BORDER_OUTER_RIGHT:
85 return "right outer frame";
86 case PIVOT_BORDER_OUTER_BOTTOM:
87 return "bottom outer frame";
89 case PIVOT_BORDER_INNER_LEFT:
90 return "left inner frame";
91 case PIVOT_BORDER_INNER_TOP:
92 return "top inner frame";
93 case PIVOT_BORDER_INNER_RIGHT:
94 return "right inner frame";
95 case PIVOT_BORDER_INNER_BOTTOM:
96 return "bottom inner frame";
98 case PIVOT_BORDER_DATA_LEFT:
99 return "data area left";
100 case PIVOT_BORDER_DATA_TOP:
101 return "data area top";
103 case PIVOT_BORDER_DIM_ROW_HORZ:
104 return "row label horizontal dimension border";
105 case PIVOT_BORDER_DIM_ROW_VERT:
106 return "row label vertical dimension border";
107 case PIVOT_BORDER_DIM_COL_HORZ:
108 return "column label horizontal dimension border";
109 case PIVOT_BORDER_DIM_COL_VERT:
110 return "column label vertical dimension border";
112 case PIVOT_BORDER_CAT_ROW_HORZ:
113 return "row label horizontal category border";
114 case PIVOT_BORDER_CAT_ROW_VERT:
115 return "row label vertical category border";
116 case PIVOT_BORDER_CAT_COL_HORZ:
117 return "column label horizontal category border";
118 case PIVOT_BORDER_CAT_COL_VERT:
119 return "column label vertical category border";
121 case PIVOT_N_BORDERS:
128 pivot_table_sizing_uninit (struct pivot_table_sizing *sizing)
132 free (sizing->widths);
133 free (sizing->breaks);
134 free (sizing->keeps);
138 /* Pivot table looks. */
140 static const struct pivot_table_look *
141 default_look (const struct pivot_table_look *new)
143 static struct pivot_table_look *look;
146 pivot_table_look_unref (look);
147 look = pivot_table_look_ref (new);
151 char *error = pivot_table_look_read ("default.stt", &look);
155 look = pivot_table_look_ref (pivot_table_look_builtin_default ());
161 const struct pivot_table_look *
162 pivot_table_look_get_default (void)
164 return default_look (NULL);
168 pivot_table_look_set_default (const struct pivot_table_look *look)
173 char * WARN_UNUSED_RESULT
174 pivot_table_look_read (const char *name, struct pivot_table_look **lookp)
178 /* Construct search path. */
182 const char *home = getenv ("HOME");
183 char *allocated = NULL;
185 path[n++] = allocated = xasprintf ("%s/.pspp/looks", home);
187 path[n++] = relocate2 (PKGDATADIR "/looks", &allocated2);
191 char *file = fn_search_path (name, (char **) path);
194 char *name2 = xasprintf ("%s.stt", name);
195 file = fn_search_path (name2, (char **) path);
201 return xasprintf ("%s: not found", name);
204 char *error = spv_table_look_read (file, lookp);
209 const struct pivot_table_look *
210 pivot_table_look_builtin_default (void)
212 static struct pivot_table_look look = {
216 .row_labels_in_corner = true,
218 [TABLE_HORZ] = { 36, 72 },
219 [TABLE_VERT] = { 36, 120 },
223 #define AREA(BOLD, H, V, L, R, T, B) { \
225 .halign = TABLE_HALIGN_##H, \
226 .valign = TABLE_VALIGN_##V, \
227 .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
228 [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
232 .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
233 .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
235 .typeface = (char *) "Sans Serif", \
238 [PIVOT_AREA_TITLE] = AREA(true, CENTER, CENTER, 8,11,1,8),
239 [PIVOT_AREA_CAPTION] = AREA(false, LEFT, TOP, 8,11,1,1),
240 [PIVOT_AREA_FOOTER] = AREA(false, LEFT, TOP, 11, 8,2,3),
241 [PIVOT_AREA_CORNER] = AREA(false, LEFT, BOTTOM, 8,11,1,1),
242 [PIVOT_AREA_COLUMN_LABELS] = AREA(false, CENTER, BOTTOM, 8,11,1,3),
243 [PIVOT_AREA_ROW_LABELS] = AREA(false, LEFT, TOP, 8,11,1,3),
244 [PIVOT_AREA_DATA] = AREA(false, MIXED, TOP, 8,11,1,1),
245 [PIVOT_AREA_LAYERS] = AREA(false, LEFT, BOTTOM, 8,11,1,3),
250 #define BORDER(STROKE) { .stroke = STROKE, .color = CELL_COLOR_BLACK }
251 [PIVOT_BORDER_TITLE] = BORDER(TABLE_STROKE_NONE),
252 [PIVOT_BORDER_OUTER_LEFT] = BORDER(TABLE_STROKE_NONE),
253 [PIVOT_BORDER_OUTER_TOP] = BORDER(TABLE_STROKE_NONE),
254 [PIVOT_BORDER_OUTER_RIGHT] = BORDER(TABLE_STROKE_NONE),
255 [PIVOT_BORDER_OUTER_BOTTOM] = BORDER(TABLE_STROKE_NONE),
256 [PIVOT_BORDER_INNER_LEFT] = BORDER(TABLE_STROKE_THICK),
257 [PIVOT_BORDER_INNER_TOP] = BORDER(TABLE_STROKE_THICK),
258 [PIVOT_BORDER_INNER_RIGHT] = BORDER(TABLE_STROKE_THICK),
259 [PIVOT_BORDER_INNER_BOTTOM] = BORDER(TABLE_STROKE_THICK),
260 [PIVOT_BORDER_DATA_LEFT] = BORDER(TABLE_STROKE_THICK),
261 [PIVOT_BORDER_DATA_TOP] = BORDER(TABLE_STROKE_THICK),
262 [PIVOT_BORDER_DIM_ROW_HORZ] = BORDER(TABLE_STROKE_SOLID),
263 [PIVOT_BORDER_DIM_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
264 [PIVOT_BORDER_DIM_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
265 [PIVOT_BORDER_DIM_COL_VERT] = BORDER(TABLE_STROKE_SOLID),
266 [PIVOT_BORDER_CAT_ROW_HORZ] = BORDER(TABLE_STROKE_NONE),
267 [PIVOT_BORDER_CAT_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
268 [PIVOT_BORDER_CAT_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
269 [PIVOT_BORDER_CAT_COL_VERT] = BORDER(TABLE_STROKE_SOLID),
276 struct pivot_table_look *
277 pivot_table_look_new_builtin_default (void)
279 return pivot_table_look_unshare (
280 pivot_table_look_ref (pivot_table_look_builtin_default ()));
283 struct pivot_table_look *
284 pivot_table_look_ref (const struct pivot_table_look *look_)
286 assert (look_->ref_cnt > 0);
288 struct pivot_table_look *look = CONST_CAST (struct pivot_table_look *, look_);
294 xstrdup_if_nonempty (const char *s)
296 return s && s[0] ? xstrdup (s) : NULL;
299 struct pivot_table_look *
300 pivot_table_look_unshare (struct pivot_table_look *old)
302 assert (old->ref_cnt > 0);
303 if (old->ref_cnt == 1)
306 pivot_table_look_unref (old);
308 struct pivot_table_look *new = xmemdup (old, sizeof *old);
310 new->name = xstrdup_if_nonempty (old->name);
311 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
312 table_area_style_copy (NULL, &new->areas[i], &old->areas[i]);
313 new->continuation = xstrdup_if_nonempty (old->continuation);
319 pivot_table_look_unref (struct pivot_table_look *look)
323 assert (look->ref_cnt > 0);
324 if (!--look->ref_cnt)
327 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
328 table_area_style_uninit (&look->areas[i]);
329 free (look->continuation);
337 /* Returns the name of AXIS_TYPE. */
339 pivot_axis_type_to_string (enum pivot_axis_type axis_type)
343 case PIVOT_AXIS_LAYER:
349 case PIVOT_AXIS_COLUMN:
357 static enum pivot_axis_type
358 pivot_axis_type_transpose (enum pivot_axis_type axis_type)
360 assert (axis_type == PIVOT_AXIS_ROW || axis_type == PIVOT_AXIS_COLUMN);
361 return (axis_type == PIVOT_AXIS_ROW ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW);
364 /* Implementation of PIVOT_AXIS_FOR_EACH. */
366 pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis)
370 if (axis->n_dimensions)
371 for (size_t i = 0; i < axis->n_dimensions; i++)
372 if (axis->dimensions[i]->n_leaves == 0)
375 size_t size = axis->n_dimensions * sizeof *indexes;
376 return xzalloc (MAX (size, 1));
379 for (size_t i = 0; i < axis->n_dimensions; i++)
381 const struct pivot_dimension *d = axis->dimensions[i];
382 if (++indexes[i] < d->n_leaves)
395 pivot_category_set_rc (struct pivot_category *category, const char *s)
397 const struct fmt_spec *format = pivot_table_get_format (
398 category->dimension->table, s);
400 category->format = *format;
402 /* Ensure that the category itself, in addition to the cells within it, takes
403 the format. (It's kind of rare for a category to have a numeric format
405 struct pivot_value *name = category->name;
406 if (name->type == PIVOT_VALUE_NUMERIC && !name->numeric.format.w)
407 name->numeric.format = format ? *format : *settings_get_format ();
411 pivot_category_create_leaves_valist (struct pivot_category *parent,
415 while ((s = va_arg (args, const char *)))
417 if (!strncmp (s, "RC_", 3))
419 assert (parent->n_subs);
420 pivot_category_set_rc (parent->subs[parent->n_subs - 1], s);
423 pivot_category_create_leaf (parent, pivot_value_new_text (s));
427 /* Creates a new dimension with the given NAME in TABLE and returns it. The
428 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
431 NAME should be a translatable name, but not actually translated yet,
432 e.g. enclosed in N_(). To use a different kind of value for a name, use
433 pivot_dimension_create__() instead.
435 The optional varargs parameters may be used to add an initial set of
436 categories to the dimension. Each string should be a translatable category
437 name, but not actually translated yet, e.g. enclosed in N_(). Each string
438 may optionally be followod by a PIVOT_RC_* string that specifies the default
439 numeric format for cells in this category. */
440 struct pivot_dimension * SENTINEL (0)
441 (pivot_dimension_create) (struct pivot_table *table,
442 enum pivot_axis_type axis_type,
443 const char *name, ...)
445 struct pivot_dimension *d = pivot_dimension_create__ (
446 table, axis_type, pivot_value_new_text (name));
449 va_start (args, name);
450 pivot_category_create_leaves_valist (d->root, args);
456 /* Creates a new dimension with the given NAME in TABLE and returns it. The
457 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
459 struct pivot_dimension *
460 pivot_dimension_create__ (struct pivot_table *table,
461 enum pivot_axis_type axis_type,
462 struct pivot_value *name)
464 assert (pivot_table_is_empty (table));
466 struct pivot_dimension *d = xmalloc (sizeof *d);
467 *d = (struct pivot_dimension) {
469 .axis_type = axis_type,
470 .level = table->axes[axis_type].n_dimensions,
471 .top_index = table->n_dimensions,
472 .root = xmalloc (sizeof *d->root),
475 struct pivot_category *root = d->root;
476 *root = (struct pivot_category) {
481 .data_index = SIZE_MAX,
482 .presentation_index = SIZE_MAX,
485 table->dimensions = xrealloc (
486 table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions);
487 table->dimensions[table->n_dimensions++] = d;
489 struct pivot_axis *axis = &table->axes[axis_type];
490 axis->dimensions = xrealloc (
491 axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
492 axis->dimensions[axis->n_dimensions++] = d;
494 if (axis_type == PIVOT_AXIS_LAYER)
496 free (table->current_layer);
497 table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
498 sizeof *table->current_layer);
501 /* axis->extent and axis->label_depth will be calculated later. */
507 pivot_dimension_destroy (struct pivot_dimension *d)
512 pivot_category_destroy (d->root);
513 free (d->data_leaves);
514 free (d->presentation_leaves);
518 /* Returns the first leaf node in an in-order traversal that is a child of
520 static const struct pivot_category * UNUSED
521 pivot_category_first_leaf (const struct pivot_category *cat)
523 if (pivot_category_is_leaf (cat))
526 for (size_t i = 0; i < cat->n_subs; i++)
528 const struct pivot_category *first
529 = pivot_category_first_leaf (cat->subs[i]);
537 /* Returns the next leaf node in an in-order traversal starting at CAT, which
539 static const struct pivot_category * UNUSED
540 pivot_category_next_leaf (const struct pivot_category *cat)
542 assert (pivot_category_is_leaf (cat));
546 const struct pivot_category *parent = cat->parent;
549 for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
551 const struct pivot_category *next
552 = pivot_category_first_leaf (parent->subs[i]);
562 pivot_category_add_child (struct pivot_category *child)
564 struct pivot_category *parent = child->parent;
566 assert (pivot_category_is_group (parent));
567 if (parent->n_subs >= parent->allocated_subs)
568 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
569 sizeof *parent->subs);
570 parent->subs[parent->n_subs++] = child;
573 /* Adds leaf categories as a child of PARENT. To create top-level categories
574 within dimension 'd', pass 'd->root' for PARENT.
576 Each of the varargs parameters should be a string, each of which should be a
577 translatable category name, but not actually translated yet, e.g. enclosed
578 in N_(). Each string may optionally be followod by a PIVOT_RC_* string that
579 specifies the default numeric format for cells in this category.
581 Returns the category index, which is just a 0-based array index, for the
584 Leaves have to be created in in-order, that is, don't create a group and add
585 some leaves, then add leaves outside the group and try to add more leaves
588 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
590 int retval = parent->dimension->n_leaves;
593 va_start (args, parent);
594 pivot_category_create_leaves_valist (parent, args);
600 /* Creates a new leaf category with the given NAME as a child of PARENT. To
601 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
602 Returns the category index, which is just a 0-based array index, for the new
605 Leaves have to be created in in-order, that is, don't create a group and add
606 some leaves, then add leaves outside the group and try to add more leaves
609 pivot_category_create_leaf (struct pivot_category *parent,
610 struct pivot_value *name)
612 return pivot_category_create_leaf_rc (parent, name, NULL);
615 /* Creates a new leaf category with the given NAME as a child of PARENT. To
616 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
617 Returns the category index, which is just a 0-based array index, for the new
620 If RC is nonnull and the name of a result category, the category is assigned
621 that result category.
623 Leaves have to be created in in-order, that is, don't create a group and add
624 some leaves, then add leaves outside the group and try to add more leaves
627 pivot_category_create_leaf_rc (struct pivot_category *parent,
628 struct pivot_value *name, const char *rc)
630 struct pivot_dimension *d = parent->dimension;
632 struct pivot_category *leaf = xmalloc (sizeof *leaf);
633 *leaf = (struct pivot_category) {
637 .group_index = parent->n_subs,
638 .data_index = d->n_leaves,
639 .presentation_index = d->n_leaves,
642 if (d->n_leaves >= d->allocated_leaves)
644 d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
645 sizeof *d->data_leaves);
646 d->presentation_leaves = xrealloc (
647 d->presentation_leaves,
648 d->allocated_leaves * sizeof *d->presentation_leaves);
651 d->data_leaves[d->n_leaves] = leaf;
652 d->presentation_leaves[d->n_leaves] = leaf;
655 pivot_category_add_child (leaf);
657 /* Make sure that the new child is the last in in-order. */
658 assert (!pivot_category_next_leaf (leaf));
660 pivot_category_set_rc (leaf, rc);
662 return leaf->data_index;
665 /* Adds a new category group named NAME as a child of PARENT. To create a
666 top-level group within dimension 'd', pass 'd->root' for PARENT.
668 NAME should be a translatable name, but not actually translated yet,
669 e.g. enclosed in N_(). To use a different kind of value for a name, use
670 pivot_category_create_group__() instead.
672 The optional varargs parameters may be used to add an initial set of
673 categories to the group. Each string should be a translatable category
674 name, but not actually translated yet, e.g. enclosed in N_(). Each string
675 may optionally be followod by a PIVOT_RC_* string that specifies the default
676 numeric format for cells in this category.
678 Returns the new group. */
679 struct pivot_category * SENTINEL (0)
680 (pivot_category_create_group) (struct pivot_category *parent,
681 const char *name, ...)
683 struct pivot_category *group = pivot_category_create_group__ (
684 parent, pivot_value_new_text (name));
687 va_start (args, name);
688 pivot_category_create_leaves_valist (group, args);
694 /* Adds a new category group named NAME as a child of PARENT. To create a
695 top-level group within dimension 'd', pass 'd->root' for PARENT. Returns
697 struct pivot_category *
698 pivot_category_create_group__ (struct pivot_category *parent,
699 struct pivot_value *name)
701 struct pivot_dimension *d = parent->dimension;
703 struct pivot_category *group = xmalloc (sizeof *group);
704 *group = (struct pivot_category) {
709 .group_index = parent->n_subs,
710 .data_index = SIZE_MAX,
711 .presentation_index = SIZE_MAX,
714 pivot_category_add_child (group);
720 pivot_category_destroy (struct pivot_category *c)
725 pivot_value_destroy (c->name);
726 for (size_t i = 0; i < c->n_subs; i++)
727 pivot_category_destroy (c->subs[i]);
734 These are usually the easiest way to control the formatting of numeric data
735 in a pivot table. See pivot_dimension_create() for an explanation of their
739 const char *name; /* "RC_*". */
740 struct fmt_spec format;
743 /* Formats for most of the result classes. */
744 static struct result_class result_classes[] =
746 { PIVOT_RC_INTEGER, { FMT_F, 40, 0 } },
747 { PIVOT_RC_PERCENT, { FMT_PCT, 40, 1 } },
748 { PIVOT_RC_CORRELATION, { FMT_F, 40, 3 } },
749 { PIVOT_RC_SIGNIFICANCE, { FMT_F, 40, 3 } },
750 { PIVOT_RC_RESIDUAL, { FMT_F, 40, 2 } },
751 { PIVOT_RC_COUNT, { 0, 0, 0 } },
752 { PIVOT_RC_OTHER, { 0, 0, 0 } },
755 /* Has PIVOT_RC_COUNT been overridden by the user? */
756 static bool overridden_count_format;
758 static struct result_class *
759 pivot_result_class_find (const char *s)
761 for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
762 if (!strcmp (s, result_classes[i].name))
763 return &result_classes[i];
767 static const struct fmt_spec *
768 pivot_table_get_format (const struct pivot_table *table, const char *s)
772 else if (!strcmp (s, PIVOT_RC_OTHER))
773 return settings_get_format ();
774 else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
775 return &table->weight_format;
778 const struct result_class *rc = pivot_result_class_find (s);
779 return rc ? &rc->format : NULL;
783 /* Sets the format specification for the result class named S (which should not
784 include the RC_ prefix) to *FORMAT. Returns true if successful, false if S
785 does not name a known result class. */
787 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
789 char *s = xasprintf ("RC_%s", s_);
790 struct result_class *rc = pivot_result_class_find (s);
793 rc->format = *format;
794 if (!strcmp (s, PIVOT_RC_COUNT))
795 overridden_count_format = true;
803 is_pivot_result_class (const char *s)
805 return pivot_result_class_find (s) != NULL;
810 static struct pivot_cell *pivot_table_insert_cell (struct pivot_table *,
811 const size_t *dindexes);
812 static void pivot_table_delete_cell (struct pivot_table *,
813 struct pivot_cell *);
815 /* Creates and returns a new pivot table with the given TITLE. TITLE should be
816 a text string marked for translation but not actually translated yet,
817 e.g. N_("Descriptive Statistics"). The un-translated text string is used as
818 the pivot table's subtype.
820 This function is a shortcut for pivot_table_create__() for the most common
821 case. Use pivot_table_create__() directly if the title should be some kind
822 of value other than an ordinary text string, or if the subtype should be
823 different from the title.
825 See the large comment at the top of pivot-table.h for general advice on
826 creating pivot tables. */
828 pivot_table_create (const char *title)
830 return pivot_table_create__ (pivot_value_new_text (title), title);
833 /* Creates and returns a new pivot table with the given TITLE, and takes
834 ownership of TITLE. The new pivot table's subtype is SUBTYPE, which should
835 be an untranslated English string that describes the contents of the table
836 at a high level without being specific about the variables or other context
839 TITLE and SUBTYPE may be NULL, but in that case the client must add them
840 later because they are both mandatory for a pivot table.
842 See the large comment at the top of pivot-table.h for general advice on
843 creating pivot tables. */
845 pivot_table_create__ (struct pivot_value *title, const char *subtype)
847 struct pivot_table *table = xzalloc (sizeof *table);
849 table->show_title = true;
850 table->show_caption = true;
851 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
852 table->title = title;
853 table->subtype = subtype ? pivot_value_new_text (subtype) : NULL;
854 table->command_c = output_get_command_name ();
855 table->look = pivot_table_look_ref (pivot_table_look_get_default ());
856 table->settings = fmt_settings_copy (settings_get_fmt_settings ());
858 hmap_init (&table->cells);
863 /* Creates and returns a new pivot table with the given TITLE and a single cell
864 with the given CONTENT.
866 This is really just for error handling. */
868 pivot_table_create_for_text (struct pivot_value *title,
869 struct pivot_value *content)
871 struct pivot_table *table = pivot_table_create__ (title, "Error");
873 struct pivot_dimension *d = pivot_dimension_create (
874 table, PIVOT_AXIS_ROW, N_("Error"));
875 d->hide_all_labels = true;
876 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
878 pivot_table_put1 (table, 0, content);
883 /* Increases TABLE's reference count, indicating that it has an additional
884 owner. A pivot table that is shared among multiple owners must not be
887 pivot_table_ref (const struct pivot_table *table_)
889 struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
895 xstrdup_if_nonnull (const char *s)
897 return s ? xstrdup (s) : NULL;
900 static struct pivot_table_sizing
901 clone_sizing (const struct pivot_table_sizing *s)
903 return (struct pivot_table_sizing) {
904 .widths = (s->n_widths
905 ? xmemdup (s->widths, s->n_widths * sizeof *s->widths)
907 .n_widths = s->n_widths,
909 .breaks = (s->n_breaks
910 ? xmemdup (s->breaks, s->n_breaks * sizeof *s->breaks)
912 .n_breaks = s->n_breaks,
915 ? xmemdup (s->keeps, s->n_keeps * sizeof *s->keeps)
917 .n_keeps = s->n_keeps,
921 static struct pivot_footnote **
922 clone_footnotes (struct pivot_footnote **old, size_t n)
927 struct pivot_footnote **new = xmalloc (n * sizeof *new);
928 for (size_t i = 0; i < n; i++)
930 new[i] = xmalloc (sizeof *new[i]);
931 *new[i] = (struct pivot_footnote) {
933 .content = pivot_value_clone (old[i]->content),
934 .marker = pivot_value_clone (old[i]->marker),
935 .show = old[i]->show,
941 static struct pivot_category *
942 clone_category (struct pivot_category *old,
943 struct pivot_dimension *new_dimension,
944 struct pivot_category *new_parent)
946 struct pivot_category *new = xmalloc (sizeof *new);
947 *new = (struct pivot_category) {
948 .name = pivot_value_clone (old->name),
949 .parent = new_parent,
950 .dimension = new_dimension,
951 .label_depth = old->label_depth,
952 .extra_depth = old->extra_depth,
955 ? xzalloc (old->n_subs * sizeof *new->subs)
957 .n_subs = old->n_subs,
958 .allocated_subs = old->n_subs,
960 .show_label = old->show_label,
961 .show_label_in_corner = old->show_label_in_corner,
963 .format = old->format,
964 .group_index = old->group_index,
965 .data_index = old->data_index,
966 .presentation_index = old->presentation_index,
969 if (pivot_category_is_leaf (old))
971 new->dimension->data_leaves[new->data_index] = new;
972 new->dimension->presentation_leaves[new->presentation_index] = new;
975 for (size_t i = 0; i < new->n_subs; i++)
976 new->subs[i] = clone_category (old->subs[i], new_dimension, new);
981 static struct pivot_dimension *
982 clone_dimension (struct pivot_dimension *old, struct pivot_table *new_pt)
984 struct pivot_dimension *new = xmalloc (sizeof *new);
985 *new = (struct pivot_dimension) {
987 .axis_type = old->axis_type,
989 .top_index = old->top_index,
990 .data_leaves = xzalloc (old->n_leaves * sizeof *new->data_leaves),
991 .presentation_leaves = xzalloc (old->n_leaves
992 * sizeof *new->presentation_leaves),
993 .n_leaves = old->n_leaves,
994 .allocated_leaves = old->n_leaves,
995 .hide_all_labels = old->hide_all_labels,
996 .label_depth = old->label_depth,
999 new->root = clone_category (old->root, new, NULL);
1004 static struct pivot_dimension **
1005 clone_dimensions (struct pivot_dimension **old, size_t n,
1006 struct pivot_table *new_pt)
1011 struct pivot_dimension **new = xmalloc (n * sizeof *new);
1012 for (size_t i = 0; i < n; i++)
1013 new[i] = clone_dimension (old[i], new_pt);
1017 struct pivot_table *
1018 pivot_table_unshare (struct pivot_table *old)
1020 assert (old->ref_cnt > 0);
1021 if (old->ref_cnt == 1)
1024 pivot_table_unref (old);
1026 struct pivot_table *new = xmalloc (sizeof *new);
1027 *new = (struct pivot_table) {
1030 .look = pivot_table_look_ref (old->look),
1032 .rotate_inner_column_labels = old->rotate_inner_column_labels,
1033 .rotate_outer_row_labels = old->rotate_outer_row_labels,
1034 .show_grid_lines = old->show_grid_lines,
1035 .show_title = old->show_title,
1036 .show_caption = old->show_caption,
1037 .current_layer = (old->current_layer
1038 ? xmemdup (old->current_layer,
1039 old->axes[PIVOT_AXIS_LAYER].n_dimensions
1040 * sizeof *new->current_layer)
1042 .show_values = old->show_values,
1043 .show_variables = old->show_variables,
1044 .weight_format = old->weight_format,
1047 [TABLE_HORZ] = clone_sizing (&old->sizing[TABLE_HORZ]),
1048 [TABLE_VERT] = clone_sizing (&old->sizing[TABLE_VERT]),
1051 .settings = fmt_settings_copy (&old->settings),
1052 .grouping = old->grouping,
1053 .small = old->small,
1055 .command_local = xstrdup_if_nonnull (old->command_local),
1056 .command_c = xstrdup_if_nonnull (old->command_c),
1057 .language = xstrdup_if_nonnull (old->language),
1058 .locale = xstrdup_if_nonnull (old->locale),
1060 .dataset = xstrdup_if_nonnull (old->dataset),
1061 .datafile = xstrdup_if_nonnull (old->datafile),
1064 .footnotes = clone_footnotes (old->footnotes, old->n_footnotes),
1065 .n_footnotes = old->n_footnotes,
1066 .allocated_footnotes = old->n_footnotes,
1068 .title = pivot_value_clone (old->title),
1069 .subtype = pivot_value_clone (old->subtype),
1070 .corner_text = pivot_value_clone (old->corner_text),
1071 .caption = pivot_value_clone (old->caption),
1072 .notes = xstrdup_if_nonnull (old->notes),
1074 .dimensions = clone_dimensions (old->dimensions, old->n_dimensions, new),
1075 .n_dimensions = old->n_dimensions,
1077 .cells = HMAP_INITIALIZER (new->cells),
1080 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1082 struct pivot_axis *new_axis = &new->axes[i];
1083 const struct pivot_axis *old_axis = &old->axes[i];
1085 *new_axis = (struct pivot_axis) {
1086 .dimensions = xmalloc (old_axis->n_dimensions
1087 * sizeof *new_axis->dimensions),
1088 .n_dimensions = old_axis->n_dimensions,
1089 .extent = old_axis->extent,
1090 .label_depth = old_axis->label_depth,
1093 for (size_t i = 0; i < new_axis->n_dimensions; i++)
1094 new_axis->dimensions[i] = new->dimensions[
1095 old_axis->dimensions[i]->top_index];
1098 const struct pivot_cell *old_cell;
1099 size_t *dindexes = xmalloc (old->n_dimensions * sizeof *dindexes);
1100 HMAP_FOR_EACH (old_cell, struct pivot_cell, hmap_node, &old->cells)
1102 for (size_t i = 0; i < old->n_dimensions; i++)
1103 dindexes[i] = old_cell->idx[i];
1104 struct pivot_cell *new_cell
1105 = pivot_table_insert_cell (new, dindexes);
1106 new_cell->value = pivot_value_clone (old_cell->value);
1113 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
1114 If TABLE no longer has any owners, it is freed. */
1116 pivot_table_unref (struct pivot_table *table)
1120 assert (table->ref_cnt > 0);
1121 if (--table->ref_cnt)
1124 free (table->current_layer);
1125 pivot_table_look_unref (table->look);
1127 for (int i = 0; i < TABLE_N_AXES; i++)
1128 pivot_table_sizing_uninit (&table->sizing[i]);
1130 fmt_settings_uninit (&table->settings);
1132 free (table->command_local);
1133 free (table->command_c);
1134 free (table->language);
1135 free (table->locale);
1137 free (table->dataset);
1138 free (table->datafile);
1140 for (size_t i = 0; i < table->n_footnotes; i++)
1141 pivot_footnote_destroy (table->footnotes[i]);
1142 free (table->footnotes);
1144 pivot_value_destroy (table->title);
1145 pivot_value_destroy (table->subtype);
1146 pivot_value_destroy (table->corner_text);
1147 pivot_value_destroy (table->caption);
1148 free (table->notes);
1150 for (size_t i = 0; i < table->n_dimensions; i++)
1151 pivot_dimension_destroy (table->dimensions[i]);
1152 free (table->dimensions);
1154 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1155 free (table->axes[i].dimensions);
1157 struct pivot_cell *cell, *next_cell;
1158 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
1160 pivot_table_delete_cell (table, cell);
1162 hmap_destroy (&table->cells);
1167 /* Returns true if TABLE has more than one owner. A pivot table that is shared
1168 among multiple owners must not be modified. */
1170 pivot_table_is_shared (const struct pivot_table *table)
1172 return table->ref_cnt > 1;
1175 /* Swaps axes A and B in TABLE. */
1177 pivot_table_swap_axes (struct pivot_table *table,
1178 enum pivot_axis_type a, enum pivot_axis_type b)
1183 struct pivot_axis tmp = table->axes[a];
1184 table->axes[a] = table->axes[b];
1185 table->axes[b] = tmp;
1187 for (int a = 0; a < PIVOT_N_AXES; a++)
1189 struct pivot_axis *axis = &table->axes[a];
1190 for (size_t d = 0; d < axis->n_dimensions; d++)
1191 axis->dimensions[d]->axis_type = a;
1194 if (a == PIVOT_AXIS_LAYER || b == PIVOT_AXIS_LAYER)
1196 free (table->current_layer);
1197 table->current_layer = xzalloc (
1198 table->axes[PIVOT_AXIS_LAYER].n_dimensions
1199 * sizeof *table->current_layer);
1203 /* Swaps the row and column axes in TABLE. */
1205 pivot_table_transpose (struct pivot_table *table)
1207 pivot_table_swap_axes (table, PIVOT_AXIS_ROW, PIVOT_AXIS_COLUMN);
1211 pivot_table_update_axes (struct pivot_table *table)
1213 for (int a = 0; a < PIVOT_N_AXES; a++)
1215 struct pivot_axis *axis = &table->axes[a];
1217 for (size_t d = 0; d < axis->n_dimensions; d++)
1219 struct pivot_dimension *dim = axis->dimensions[d];
1226 /* Moves DIM from its current location in TABLE to POS within AXIS. POS of 0
1227 is the innermost dimension, 1 is the next one out, and so on. */
1229 pivot_table_move_dimension (struct pivot_table *table,
1230 struct pivot_dimension *dim,
1231 enum pivot_axis_type axis, size_t pos)
1233 assert (dim->table == table);
1235 struct pivot_axis *old_axis = &table->axes[dim->axis_type];
1236 struct pivot_axis *new_axis = &table->axes[axis];
1237 pos = MIN (pos, new_axis->n_dimensions);
1239 if (old_axis == new_axis && pos == dim->level)
1246 /* Update the current layer, if necessary. If we're moving within the layer
1247 axis, preserve the current layer. */
1248 if (dim->axis_type == PIVOT_AXIS_LAYER)
1250 if (axis == PIVOT_AXIS_LAYER)
1252 /* Rearranging the layer axis. */
1253 move_element (table->current_layer, old_axis->n_dimensions,
1254 sizeof *table->current_layer,
1259 /* A layer is becoming a row or column. */
1260 remove_element (table->current_layer, old_axis->n_dimensions,
1261 sizeof *table->current_layer, dim->level);
1264 else if (axis == PIVOT_AXIS_LAYER)
1266 /* A row or column is becoming a layer. */
1267 table->current_layer = xrealloc (
1268 table->current_layer,
1269 (new_axis->n_dimensions + 1) * sizeof *table->current_layer);
1270 insert_element (table->current_layer, new_axis->n_dimensions,
1271 sizeof *table->current_layer, pos);
1272 table->current_layer[pos] = 0;
1275 /* Remove DIM from its current axis. */
1276 remove_element (old_axis->dimensions, old_axis->n_dimensions,
1277 sizeof *old_axis->dimensions, dim->level);
1278 old_axis->n_dimensions--;
1280 /* Insert DIM into its new axis. */
1281 new_axis->dimensions = xrealloc (
1282 new_axis->dimensions,
1283 (new_axis->n_dimensions + 1) * sizeof *new_axis->dimensions);
1284 insert_element (new_axis->dimensions, new_axis->n_dimensions,
1285 sizeof *new_axis->dimensions, pos);
1286 new_axis->dimensions[pos] = dim;
1287 new_axis->n_dimensions++;
1289 pivot_table_update_axes (table);
1293 const struct pivot_table_look *
1294 pivot_table_get_look (const struct pivot_table *table)
1300 pivot_table_set_look (struct pivot_table *table,
1301 const struct pivot_table_look *look)
1303 pivot_table_look_unref (table->look);
1304 table->look = pivot_table_look_ref (look);
1307 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
1308 WV, which should be the weight variable for the dictionary whose data or
1309 statistics are being put into TABLE.
1311 This has no effect if WV is NULL. */
1313 pivot_table_set_weight_var (struct pivot_table *table,
1314 const struct variable *wv)
1317 pivot_table_set_weight_format (table, var_get_print_format (wv));
1320 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
1321 format for the dictionary whose data or statistics are being put into TABLE.
1323 This has no effect if WFMT is NULL. */
1325 pivot_table_set_weight_format (struct pivot_table *table,
1326 const struct fmt_spec *wfmt)
1329 table->weight_format = *wfmt;
1332 /* Returns true if TABLE has no cells, false otherwise. */
1334 pivot_table_is_empty (const struct pivot_table *table)
1336 return hmap_is_empty (&table->cells);
1340 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
1342 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
1346 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
1348 for (size_t i = 0; i < n; i++)
1355 static struct pivot_cell *
1356 pivot_table_lookup_cell__ (const struct pivot_table *table,
1357 const size_t *dindexes, unsigned int hash)
1359 struct pivot_cell *cell;
1360 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
1362 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
1367 static struct pivot_cell *
1368 pivot_cell_allocate (size_t n_idx)
1370 struct pivot_cell *cell UNUSED;
1371 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
1374 static struct pivot_cell *
1375 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
1377 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1378 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
1381 cell = pivot_cell_allocate (table->n_dimensions);
1382 for (size_t i = 0; i < table->n_dimensions; i++)
1383 cell->idx[i] = dindexes[i];
1385 hmap_insert (&table->cells, &cell->hmap_node, hash);
1390 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
1391 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
1394 If VALUE is a numeric value without a specified format, this function checks
1395 each of the categories designated by DINDEXES[] and takes the format from
1396 the first category with a result class. If none has a result class, uses
1397 the overall default numeric format. */
1399 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
1400 struct pivot_value *value)
1402 assert (n == table->n_dimensions);
1403 for (size_t i = 0; i < n; i++)
1404 assert (dindexes[i] < table->dimensions[i]->n_leaves);
1406 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
1408 for (size_t i = 0; i < table->n_dimensions; i++)
1410 const struct pivot_dimension *d = table->dimensions[i];
1411 if (dindexes[i] < d->n_leaves)
1413 const struct pivot_category *c = d->data_leaves[dindexes[i]];
1416 value->numeric.format = c->format;
1421 value->numeric.format = *settings_get_format ();
1426 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1427 pivot_value_destroy (cell->value);
1428 cell->value = value;
1431 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
1432 dimension. Takes ownership of VALUE. */
1434 pivot_table_put1 (struct pivot_table *table, size_t idx1,
1435 struct pivot_value *value)
1437 size_t dindexes[] = { idx1 };
1438 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1441 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
1442 dimensions. Takes ownership of VALUE. */
1444 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
1445 struct pivot_value *value)
1447 size_t dindexes[] = { idx1, idx2 };
1448 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1451 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
1452 have 3 dimensions. Takes ownership of VALUE. */
1454 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
1455 size_t idx3, struct pivot_value *value)
1457 size_t dindexes[] = { idx1, idx2, idx3 };
1458 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1461 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
1462 must have 4 dimensions. Takes ownership of VALUE. */
1464 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1465 size_t idx3, size_t idx4, struct pivot_value *value)
1467 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1468 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1471 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1472 automatically assigned marker.
1474 The footnote will only appear in output if it is referenced. Use
1475 pivot_value_add_footnote() to add a reference to the footnote. */
1476 struct pivot_footnote *
1477 pivot_table_create_footnote (struct pivot_table *table,
1478 struct pivot_value *content)
1480 return pivot_table_create_footnote__ (table, table->n_footnotes,
1484 static struct pivot_value *
1485 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1487 char text[INT_BUFSIZE_BOUND (size_t)];
1488 if (show_numeric_markers)
1489 snprintf (text, sizeof text, "%d", idx + 1);
1491 str_format_26adic (idx + 1, false, text, sizeof text);
1492 return pivot_value_new_user_text (text, -1);
1495 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1496 all lower indexes as a side effect). If MARKER is nonnull, sets the
1497 footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1498 struct pivot_footnote *
1499 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1500 struct pivot_value *marker,
1501 struct pivot_value *content)
1503 if (idx >= table->n_footnotes)
1505 while (idx >= table->allocated_footnotes)
1506 table->footnotes = x2nrealloc (table->footnotes,
1507 &table->allocated_footnotes,
1508 sizeof *table->footnotes);
1509 while (idx >= table->n_footnotes)
1511 struct pivot_footnote *f = xmalloc (sizeof *f);
1512 f->idx = table->n_footnotes;
1513 f->marker = pivot_make_default_footnote_marker (
1514 f->idx, table->look->show_numeric_markers);
1518 table->footnotes[table->n_footnotes++] = f;
1522 struct pivot_footnote *f = table->footnotes[idx];
1525 pivot_value_destroy (f->marker);
1530 pivot_value_destroy (f->content);
1531 f->content = content;
1536 /* Frees the data owned by F. */
1538 pivot_footnote_destroy (struct pivot_footnote *f)
1542 pivot_value_destroy (f->content);
1543 pivot_value_destroy (f->marker);
1548 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1549 indexes for each dimension in TABLE in DINDEXES[]. */
1551 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1552 const size_t *pindexes[PIVOT_N_AXES],
1553 size_t dindexes[/* table->n_dimensions */])
1555 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1557 const struct pivot_axis *axis = &table->axes[i];
1559 for (size_t j = 0; j < axis->n_dimensions; j++)
1561 const struct pivot_dimension *d = axis->dimensions[j];
1562 dindexes[d->top_index]
1563 = d->presentation_leaves[pindexes[i][j]]->data_index;
1569 pivot_table_enumerate_axis (const struct pivot_table *table,
1570 enum pivot_axis_type axis_type,
1571 const size_t *layer_indexes, bool omit_empty,
1574 const struct pivot_axis *axis = &table->axes[axis_type];
1575 if (!axis->n_dimensions)
1577 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1579 enumeration[1] = SIZE_MAX;
1584 else if (!axis->extent)
1586 size_t *enumeration = xmalloc (sizeof *enumeration);
1587 *enumeration = SIZE_MAX;
1593 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1594 axis->n_dimensions), 1),
1595 sizeof *enumeration);
1596 size_t *p = enumeration;
1597 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1599 size_t *axis_indexes;
1600 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1604 enum pivot_axis_type axis2_type
1605 = pivot_axis_type_transpose (axis_type);
1607 size_t *axis2_indexes;
1608 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1610 const size_t *pindexes[PIVOT_N_AXES];
1611 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1612 pindexes[axis_type] = axis_indexes;
1613 pindexes[axis2_type] = axis2_indexes;
1614 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1615 if (pivot_table_get (table, dindexes))
1621 free (axis2_indexes);
1624 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1625 p += axis->n_dimensions;
1627 if (omit_empty && p == enumeration)
1629 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1631 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1632 p += axis->n_dimensions;
1637 *n = (p - enumeration) / axis->n_dimensions;
1643 static struct pivot_cell *
1644 pivot_table_lookup_cell (const struct pivot_table *table,
1645 const size_t *dindexes)
1647 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1648 return pivot_table_lookup_cell__ (table, dindexes, hash);
1651 const struct pivot_value *
1652 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1654 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1655 return cell ? cell->value : NULL;
1658 struct pivot_value *
1659 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1661 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1663 cell->value = pivot_value_new_user_text ("", -1);
1668 pivot_table_delete_cell (struct pivot_table *table, struct pivot_cell *cell)
1670 hmap_delete (&table->cells, &cell->hmap_node);
1671 pivot_value_destroy (cell->value);
1676 pivot_table_delete (struct pivot_table *table, const size_t *dindexes)
1678 struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1681 pivot_table_delete_cell (table, cell);
1689 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1691 if (pivot_category_is_group (category) && category->n_subs)
1692 for (size_t i = 0; i < category->n_subs; i++)
1693 distribute_extra_depth (category->subs[i], extra_depth);
1695 category->extra_depth += extra_depth;
1699 pivot_category_assign_label_depth (struct pivot_category *category,
1700 bool dimension_labels_in_corner)
1702 category->extra_depth = 0;
1704 if (pivot_category_is_group (category))
1707 for (size_t i = 0; i < category->n_subs; i++)
1709 pivot_category_assign_label_depth (category->subs[i], false);
1710 depth = MAX (depth, category->subs[i]->label_depth);
1713 for (size_t i = 0; i < category->n_subs; i++)
1715 struct pivot_category *sub = category->subs[i];
1717 size_t extra_depth = depth - sub->label_depth;
1719 distribute_extra_depth (sub, extra_depth);
1721 sub->label_depth = depth;
1724 category->show_label_in_corner = (category->show_label
1725 && dimension_labels_in_corner);
1726 category->label_depth
1727 = (category->show_label && !category->show_label_in_corner
1728 ? depth + 1 : depth);
1731 category->label_depth = 1;
1735 pivot_axis_assign_label_depth (struct pivot_table *table,
1736 enum pivot_axis_type axis_type,
1737 bool dimension_labels_in_corner)
1739 struct pivot_axis *axis = &table->axes[axis_type];
1740 bool any_label_shown_in_corner = false;
1741 axis->label_depth = 0;
1743 for (size_t i = 0; i < axis->n_dimensions; i++)
1745 struct pivot_dimension *d = axis->dimensions[i];
1746 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1747 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1748 axis->label_depth += d->label_depth;
1749 axis->extent *= d->n_leaves;
1751 if (d->root->show_label_in_corner)
1752 any_label_shown_in_corner = true;
1754 return any_label_shown_in_corner;
1758 pivot_table_assign_label_depth (struct pivot_table *table)
1760 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1761 if (pivot_axis_assign_label_depth (
1762 table, PIVOT_AXIS_ROW, (table->look->row_labels_in_corner
1763 && !table->corner_text))
1764 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1765 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1766 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1770 indent (int indentation)
1772 for (int i = 0; i < indentation * 2; i++)
1777 pivot_value_dump (const struct pivot_value *value,
1778 const struct pivot_table *pt)
1780 char *s = pivot_value_to_string (value, pt);
1786 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1787 const struct pivot_table *pt, int indentation)
1791 indent (indentation);
1792 printf ("%s: ", name);
1793 pivot_value_dump (value, pt);
1799 pivot_table_dump_string (const char *string, const char *name, int indentation)
1803 indent (indentation);
1804 printf ("%s: %s\n", name, string);
1809 pivot_category_dump (const struct pivot_category *c,
1810 const struct pivot_table *pt, int indentation)
1812 indent (indentation);
1813 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1814 pivot_value_dump (c->name, pt);
1817 if (pivot_category_is_leaf (c))
1818 printf ("data_index=%zu\n", c->data_index);
1821 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1824 for (size_t i = 0; i < c->n_subs; i++)
1825 pivot_category_dump (c->subs[i], pt, indentation + 1);
1830 pivot_dimension_dump (const struct pivot_dimension *d,
1831 const struct pivot_table *pt, int indentation)
1833 indent (indentation);
1834 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1835 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1837 pivot_category_dump (d->root, pt, indentation + 1);
1841 table_area_style_dump (enum pivot_area area, const struct table_area_style *a,
1844 indent (indentation);
1845 printf ("%s: ", pivot_area_to_string (area));
1846 font_style_dump (&a->font_style);
1848 cell_style_dump (&a->cell_style);
1853 table_border_style_dump (enum pivot_border border,
1854 const struct table_border_style *b, int indentation)
1856 indent (indentation);
1857 printf ("%s: %s ", pivot_border_to_string (border),
1858 table_stroke_to_string (b->stroke));
1859 cell_color_dump (&b->color);
1864 compose_headings (const struct pivot_table *pt,
1865 const struct pivot_axis *axis,
1866 const size_t *column_enumeration)
1868 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1871 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1872 for (size_t i = 0; i < axis->label_depth; i++)
1873 headings[i] = xcalloc (axis->extent, sizeof **headings);
1875 const size_t *indexes;
1877 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1879 int row = axis->label_depth - 1;
1880 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1882 const struct pivot_dimension *d = axis->dimensions[dim_index];
1883 if (d->hide_all_labels)
1885 for (const struct pivot_category *c
1886 = d->presentation_leaves[indexes[dim_index]];
1890 if (pivot_category_is_leaf (c) || (c->show_label
1891 && !c->show_label_in_corner))
1893 headings[row][column] = pivot_value_to_string (c->name, pt);
1894 if (!*headings[row][column])
1895 headings[row][column] = xstrdup ("<blank>");
1907 free_headings (const struct pivot_axis *axis, char ***headings)
1909 for (size_t i = 0; i < axis->label_depth; i++)
1911 for (size_t j = 0; j < axis->extent; j++)
1912 free (headings[i][j]);
1919 pivot_table_sizing_dump (const char *name,
1920 const int width_ranges[2],
1921 const struct pivot_table_sizing *s,
1924 indent (indentation);
1925 printf ("%ss: min=%d, max=%d\n", name, width_ranges[0], width_ranges[1]);
1928 indent (indentation + 1);
1929 printf ("%s widths:", name);
1930 for (size_t i = 0; i < s->n_widths; i++)
1931 printf (" %d", s->widths[i]);
1936 indent (indentation + 1);
1937 printf ("break after %ss:", name);
1938 for (size_t i = 0; i < s->n_breaks; i++)
1939 printf (" %zu", s->breaks[i]);
1944 indent (indentation + 1);
1945 printf ("keep %ss together:", name);
1946 for (size_t i = 0; i < s->n_keeps; i++)
1947 printf (" [%zu,%zu]",
1949 s->keeps[i].ofs + s->keeps[i].n - 1);
1955 pivot_table_dump (const struct pivot_table *table, int indentation)
1960 pivot_table_assign_label_depth (CONST_CAST (struct pivot_table *, table));
1962 pivot_table_dump_value (table->title, "title", table, indentation);
1963 pivot_table_dump_value (table->subtype, "subtype", table, indentation);
1964 pivot_table_dump_string (table->command_c, "command", indentation);
1965 pivot_table_dump_string (table->dataset, "dataset", indentation);
1966 pivot_table_dump_string (table->datafile, "datafile", indentation);
1967 pivot_table_dump_string (table->notes, "notes", indentation);
1968 pivot_table_dump_string (table->look->name, "table-look", indentation);
1971 indent (indentation);
1973 struct tm *tm = localtime (&table->date);
1974 printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
1975 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
1979 indent (indentation);
1980 printf ("sizing:\n");
1981 pivot_table_sizing_dump ("column", table->look->width_ranges[TABLE_HORZ],
1982 &table->sizing[TABLE_HORZ], indentation + 1);
1983 pivot_table_sizing_dump ("row", table->look->width_ranges[TABLE_VERT],
1984 &table->sizing[TABLE_VERT], indentation + 1);
1986 indent (indentation);
1987 printf ("areas:\n");
1988 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1989 table_area_style_dump (area, &table->look->areas[area], indentation + 1);
1991 indent (indentation);
1992 printf ("borders:\n");
1993 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1994 table_border_style_dump (border, &table->look->borders[border],
1997 for (size_t i = 0; i < table->n_dimensions; i++)
1998 pivot_dimension_dump (table->dimensions[i], table, indentation);
2000 /* Presentation and data indexes. */
2001 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
2003 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
2004 if (layer_axis->n_dimensions)
2006 indent (indentation);
2007 printf ("current layer:");
2009 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
2011 const struct pivot_dimension *d = layer_axis->dimensions[i];
2012 char *name = pivot_value_to_string (d->root->name, table);
2013 char *value = pivot_value_to_string (
2014 d->data_leaves[table->current_layer[i]]->name, table);
2015 printf (" %s=%s", name, value);
2023 size_t *layer_indexes;
2024 size_t layer_iteration = 0;
2025 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
2027 indent (indentation);
2028 printf ("layer %zu:", layer_iteration++);
2030 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
2031 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
2033 const struct pivot_dimension *d = layer_axis->dimensions[i];
2035 fputs (i == 0 ? " " : ", ", stdout);
2036 pivot_value_dump (d->root->name, table);
2037 fputs (" =", stdout);
2039 struct pivot_value **names = xnmalloc (d->n_leaves, sizeof *names);
2041 for (const struct pivot_category *c
2042 = d->presentation_leaves[layer_indexes[i]];
2046 if (pivot_category_is_leaf (c) || c->show_label)
2047 names[n_names++] = c->name;
2050 for (size_t i = n_names; i-- > 0;)
2053 pivot_value_dump (names[i], table);
2059 size_t *column_enumeration = pivot_table_enumerate_axis (
2060 table, PIVOT_AXIS_COLUMN, layer_indexes, table->look->omit_empty, NULL);
2061 size_t *row_enumeration = pivot_table_enumerate_axis (
2062 table, PIVOT_AXIS_ROW, layer_indexes, table->look->omit_empty, NULL);
2064 char ***column_headings = compose_headings (
2065 table, &table->axes[PIVOT_AXIS_COLUMN], column_enumeration);
2066 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
2068 indent (indentation + 1);
2069 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
2072 fputs ("; ", stdout);
2073 if (column_headings[y][x])
2074 fputs (column_headings[y][x], stdout);
2078 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
2080 indent (indentation + 1);
2081 printf ("-----------------------------------------------\n");
2083 char ***row_headings = compose_headings (
2084 table, &table->axes[PIVOT_AXIS_ROW], row_enumeration);
2087 const size_t *pindexes[PIVOT_N_AXES]
2088 = { [PIVOT_AXIS_LAYER] = layer_indexes };
2089 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
2090 &table->axes[PIVOT_AXIS_ROW])
2092 indent (indentation + 1);
2095 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
2098 fputs ("; ", stdout);
2099 if (row_headings[y][x])
2100 fputs (row_headings[y][x], stdout);
2106 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
2108 &table->axes[PIVOT_AXIS_COLUMN])
2113 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
2114 const struct pivot_value *value = pivot_table_get (
2117 pivot_value_dump (value, table);
2124 free (column_enumeration);
2125 free (row_enumeration);
2126 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
2129 pivot_table_dump_value (table->caption, "caption", table, indentation);
2131 for (size_t i = 0; i < table->n_footnotes; i++)
2133 const struct pivot_footnote *f = table->footnotes[i];
2134 indent (indentation);
2137 pivot_value_dump (f->marker, table);
2139 printf ("%zu", f->idx);
2141 pivot_value_dump (f->content, table);
2149 consume_int (const char *p, size_t *n)
2152 while (c_isdigit (*p))
2153 *n = *n * 10 + (*p++ - '0');
2158 pivot_format_inner_template (struct string *out, const char *template,
2160 struct pivot_value **values, size_t n_values,
2161 const struct pivot_table *pt)
2163 size_t args_consumed = 0;
2164 while (*template && *template != ':')
2166 if (*template == '\\' && template[1])
2168 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
2171 else if (*template == escape)
2174 template = consume_int (template + 1, &index);
2175 if (index >= 1 && index <= n_values)
2177 pivot_value_format (values[index - 1], pt, out);
2178 args_consumed = MAX (args_consumed, index);
2182 ds_put_byte (out, *template++);
2184 return args_consumed;
2188 pivot_extract_inner_template (const char *template, const char **p)
2194 if (*template == '\\' && template[1] != '\0')
2196 else if (*template == ':')
2197 return template + 1;
2198 else if (*template == '\0')
2206 pivot_format_template (struct string *out, const char *template,
2207 const struct pivot_argument *args, size_t n_args,
2208 const struct pivot_table *pt)
2212 if (*template == '\\' && template[1] != '\0')
2214 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
2217 else if (*template == '^')
2220 template = consume_int (template + 1, &index);
2221 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
2222 pivot_value_format (args[index - 1].values[0], pt, out);
2224 else if (*template == '[')
2226 const char *tmpl[2];
2227 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
2228 template = pivot_extract_inner_template (template, &tmpl[1]);
2229 template += *template == ']';
2232 template = consume_int (template, &index);
2233 if (index < 1 || index > n_args)
2236 const struct pivot_argument *arg = &args[index - 1];
2237 size_t left = arg->n;
2240 struct pivot_value **values = arg->values + (arg->n - left);
2241 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
2242 char escape = "%^"[tmpl_idx];
2243 size_t used = pivot_format_inner_template (
2244 out, tmpl[tmpl_idx], escape, values, left, pt);
2245 if (!used || used > left)
2251 ds_put_byte (out, *template++);
2255 static enum settings_value_show
2256 interpret_show (enum settings_value_show global_show,
2257 enum settings_value_show table_show,
2258 enum settings_value_show value_show,
2261 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
2262 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
2263 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
2267 /* Appends a text representation of the body of VALUE to OUT. Settings on
2268 PT control whether variable and value labels are included.
2270 The "body" omits subscripts and superscripts and footnotes.
2272 Returns true if OUT is a number (or a number plus a value label), false
2275 pivot_value_format_body (const struct pivot_value *value,
2276 const struct pivot_table *pt,
2279 enum settings_value_show show;
2280 bool numeric = false;
2282 switch (value->type)
2284 case PIVOT_VALUE_NUMERIC:
2285 show = interpret_show (settings_get_show_values (),
2287 value->numeric.show,
2288 value->numeric.value_label != NULL);
2289 if (show & SETTINGS_VALUE_SHOW_VALUE)
2291 char *s = data_out (&(union value) { .f = value->numeric.x },
2292 "UTF-8", &value->numeric.format, &pt->settings);
2293 ds_put_cstr (out, s + strspn (s, " "));
2296 if (show & SETTINGS_VALUE_SHOW_LABEL)
2298 if (show & SETTINGS_VALUE_SHOW_VALUE)
2299 ds_put_byte (out, ' ');
2300 ds_put_cstr (out, value->numeric.value_label);
2302 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
2305 case PIVOT_VALUE_STRING:
2306 show = interpret_show (settings_get_show_values (),
2309 value->string.value_label != NULL);
2310 if (show & SETTINGS_VALUE_SHOW_VALUE)
2312 if (value->string.hex)
2314 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
2316 ds_put_format (out, "%02X", *p);
2319 ds_put_cstr (out, value->string.s);
2321 if (show & SETTINGS_VALUE_SHOW_LABEL)
2323 if (show & SETTINGS_VALUE_SHOW_VALUE)
2324 ds_put_byte (out, ' ');
2325 ds_put_cstr (out, value->string.value_label);
2329 case PIVOT_VALUE_VARIABLE:
2330 show = interpret_show (settings_get_show_variables (),
2332 value->variable.show,
2333 value->variable.var_label != NULL);
2334 if (show & SETTINGS_VALUE_SHOW_VALUE)
2335 ds_put_cstr (out, value->variable.var_name);
2336 if (show & SETTINGS_VALUE_SHOW_LABEL)
2338 if (show & SETTINGS_VALUE_SHOW_VALUE)
2339 ds_put_byte (out, ' ');
2340 ds_put_cstr (out, value->variable.var_label);
2344 case PIVOT_VALUE_TEXT:
2345 ds_put_cstr (out, value->text.local);
2348 case PIVOT_VALUE_TEMPLATE:
2349 pivot_format_template (out, value->template.local, value->template.args,
2350 value->template.n_args, pt);
2357 /* Appends a text representation of VALUE to OUT. Settings on
2358 PT control whether variable and value labels are included.
2360 Subscripts and footnotes are included. */
2362 pivot_value_format (const struct pivot_value *value,
2363 const struct pivot_table *pt,
2366 pivot_value_format_body (value, pt, out);
2368 if (value->n_subscripts)
2370 for (size_t i = 0; i < value->n_subscripts; i++)
2371 ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
2374 for (size_t i = 0; i < value->n_footnotes; i++)
2376 ds_put_byte (out, '[');
2378 size_t idx = value->footnote_indexes[i];
2379 const struct pivot_footnote *f = pt->footnotes[idx];
2380 pivot_value_format (f->marker, pt, out);
2382 ds_put_byte (out, ']');
2386 /* Returns a text representation of VALUE. The caller must free the string,
2389 pivot_value_to_string (const struct pivot_value *value,
2390 const struct pivot_table *pt)
2392 struct string s = DS_EMPTY_INITIALIZER;
2393 pivot_value_format (value, pt, &s);
2394 return ds_steal_cstr (&s);
2398 pivot_value_to_string_defaults (const struct pivot_value *value)
2400 static const struct pivot_table pt = {
2401 .show_values = SETTINGS_VALUE_SHOW_DEFAULT,
2402 .show_variables = SETTINGS_VALUE_SHOW_DEFAULT,
2404 return pivot_value_to_string (value, &pt);
2407 struct pivot_value *
2408 pivot_value_clone (const struct pivot_value *old)
2413 struct pivot_value *new = xmemdup (old, sizeof *new);
2414 if (old->font_style)
2416 new->font_style = xmalloc (sizeof *new->font_style);
2417 font_style_copy (NULL, new->font_style, old->font_style);
2419 if (old->cell_style)
2420 new->font_style = xmemdup (old->font_style, sizeof *new->font_style);
2421 if (old->n_subscripts)
2423 new->subscripts = xnmalloc (old->n_subscripts, sizeof *new->subscripts);
2424 for (size_t i = 0; i < old->n_subscripts; i++)
2425 new->subscripts[i] = xstrdup (old->subscripts[i]);
2427 if (old->n_footnotes)
2428 new->footnote_indexes = xmemdup (
2429 old->footnote_indexes, old->n_footnotes * sizeof *new->footnote_indexes);
2433 case PIVOT_VALUE_NUMERIC:
2434 new->numeric.var_name = xstrdup_if_nonnull (new->numeric.var_name);
2435 new->numeric.value_label = xstrdup_if_nonnull (new->numeric.value_label);
2438 case PIVOT_VALUE_STRING:
2439 new->string.s = xstrdup (new->string.s);
2440 new->string.var_name = xstrdup_if_nonnull (new->string.var_name);
2441 new->string.value_label = xstrdup_if_nonnull (new->string.value_label);
2444 case PIVOT_VALUE_VARIABLE:
2445 new->variable.var_name = xstrdup_if_nonnull (new->variable.var_name);
2446 new->variable.var_label = xstrdup_if_nonnull (new->variable.var_label);
2449 case PIVOT_VALUE_TEXT:
2450 new->text.local = xstrdup (old->text.local);
2451 new->text.c = (old->text.c == old->text.local ? new->text.local
2452 : xstrdup (old->text.c));
2453 new->text.id = (old->text.id == old->text.local ? new->text.local
2454 : old->text.id == old->text.c ? new->text.c
2455 : xstrdup (old->text.id));
2458 case PIVOT_VALUE_TEMPLATE:
2459 new->template.local = xstrdup (old->template.local);
2460 new->template.id = (old->template.id == old->template.local
2461 ? new->template.local
2462 : xstrdup (old->template.id));
2463 new->template.args = xmalloc (new->template.n_args
2464 * sizeof *new->template.args);
2465 for (size_t i = 0; i < old->template.n_args; i++)
2466 pivot_argument_copy (&new->template.args[i],
2467 &old->template.args[i]);
2476 /* Frees the data owned by V. */
2478 pivot_value_destroy (struct pivot_value *value)
2482 font_style_uninit (value->font_style);
2483 free (value->font_style);
2484 free (value->cell_style);
2485 free (value->footnote_indexes);
2487 for (size_t i = 0; i < value->n_subscripts; i++)
2488 free (value->subscripts[i]);
2489 free (value->subscripts);
2491 switch (value->type)
2493 case PIVOT_VALUE_NUMERIC:
2494 free (value->numeric.var_name);
2495 free (value->numeric.value_label);
2498 case PIVOT_VALUE_STRING:
2499 free (value->string.s);
2500 free (value->string.var_name);
2501 free (value->string.value_label);
2504 case PIVOT_VALUE_VARIABLE:
2505 free (value->variable.var_name);
2506 free (value->variable.var_label);
2509 case PIVOT_VALUE_TEXT:
2510 free (value->text.local);
2511 if (value->text.c != value->text.local)
2512 free (value->text.c);
2513 if (value->text.id != value->text.local
2514 && value->text.id != value->text.c)
2515 free (value->text.id);
2518 case PIVOT_VALUE_TEMPLATE:
2519 free (value->template.local);
2520 if (value->template.id != value->template.local)
2521 free (value->template.id);
2522 for (size_t i = 0; i < value->template.n_args; i++)
2523 pivot_argument_uninit (&value->template.args[i]);
2524 free (value->template.args);
2534 /* Sets AREA to the style to use for VALUE, with defaults coming from
2535 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
2537 pivot_value_get_style (struct pivot_value *value,
2538 const struct font_style *base_font_style,
2539 const struct cell_style *base_cell_style,
2540 struct table_area_style *area)
2542 font_style_copy (NULL, &area->font_style, (value->font_style
2544 : base_font_style));
2545 area->cell_style = *(value->cell_style
2550 /* Copies AREA into VALUE's style. */
2552 pivot_value_set_style (struct pivot_value *value,
2553 const struct table_area_style *area)
2555 pivot_value_set_font_style (value, &area->font_style);
2556 pivot_value_set_cell_style (value, &area->cell_style);
2560 pivot_value_set_font_style (struct pivot_value *value,
2561 const struct font_style *font_style)
2563 if (value->font_style)
2564 font_style_uninit (value->font_style);
2566 value->font_style = xmalloc (sizeof *value->font_style);
2567 font_style_copy (NULL, value->font_style, font_style);
2571 pivot_value_set_cell_style (struct pivot_value *value,
2572 const struct cell_style *cell_style)
2574 if (!value->cell_style)
2575 value->cell_style = xmalloc (sizeof *value->cell_style);
2576 *value->cell_style = *cell_style;
2580 pivot_argument_copy (struct pivot_argument *dst,
2581 const struct pivot_argument *src)
2583 *dst = (struct pivot_argument) {
2585 .values = xmalloc (src->n * sizeof *dst->values),
2588 for (size_t i = 0; i < src->n; i++)
2589 dst->values[i] = pivot_value_clone (src->values[i]);
2592 /* Frees the data owned by ARG (but not ARG itself). */
2594 pivot_argument_uninit (struct pivot_argument *arg)
2598 for (size_t i = 0; i < arg->n; i++)
2599 pivot_value_destroy (arg->values[i]);
2604 /* Creates and returns a new pivot_value whose contents is the null-terminated
2605 string TEXT. Takes ownership of TEXT.
2607 This function is for text strings provided by the user (with the exception
2608 that pivot_value_new_variable() should be used for variable names). For
2609 strings that are part of the PSPP user interface, such as names of
2610 procedures, statistics, annotations, error messages, etc., use
2611 pivot_value_new_text(). */
2612 struct pivot_value *
2613 pivot_value_new_user_text_nocopy (char *text)
2615 struct pivot_value *value = xmalloc (sizeof *value);
2616 *value = (struct pivot_value) {
2617 .type = PIVOT_VALUE_TEXT,
2622 .user_provided = true,
2628 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2629 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2632 This function is for text strings provided by the user (with the exception
2633 that pivot_value_new_variable() should be used for variable names). For
2634 strings that are part of the PSPP user interface, such as names of
2635 procedures, statistics, annotations, error messages, etc., use
2636 pivot_value_new_text().j
2638 The caller retains ownership of TEXT.*/
2639 struct pivot_value *
2640 pivot_value_new_user_text (const char *text, size_t length)
2642 return pivot_value_new_user_text_nocopy (
2643 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2646 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2647 a translatable string, but not actually translated yet, e.g. enclosed in
2648 N_(). This function is for text strings that are part of the PSPP user
2649 interface, such as names of procedures, statistics, annotations, error
2650 messages, etc. For strings that come from the user, use
2651 pivot_value_new_user_text(). */
2652 struct pivot_value *
2653 pivot_value_new_text (const char *text)
2655 char *c = xstrdup (text);
2656 char *local = xstrdup (gettext (c));
2658 struct pivot_value *value = xmalloc (sizeof *value);
2659 *value = (struct pivot_value) {
2660 .type = PIVOT_VALUE_TEXT,
2665 .user_provided = false,
2671 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2673 struct pivot_value * PRINTF_FORMAT (1, 2)
2674 pivot_value_new_text_format (const char *format, ...)
2677 va_start (args, format);
2678 char *c = xvasprintf (format, args);
2681 va_start (args, format);
2682 char *local = xvasprintf (gettext (format), args);
2685 struct pivot_value *value = xmalloc (sizeof *value);
2686 *value = (struct pivot_value) {
2687 .type = PIVOT_VALUE_TEXT,
2692 .user_provided = false,
2698 /* Returns a new pivot_value that represents X.
2700 The format to use for X is unspecified. Usually the easiest way to specify
2701 a format is through assigning a result class to one of the categories that
2702 the pivot_value will end up in. If that is not suitable, then the caller
2703 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2704 struct pivot_value *
2705 pivot_value_new_number (double x)
2707 struct pivot_value *value = xmalloc (sizeof *value);
2708 *value = (struct pivot_value) {
2709 .type = PIVOT_VALUE_NUMERIC,
2710 .numeric = { .x = x, },
2715 /* Returns a new pivot_value that represents X, formatted as an integer. */
2716 struct pivot_value *
2717 pivot_value_new_integer (double x)
2719 struct pivot_value *value = pivot_value_new_number (x);
2720 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2724 /* Returns a new pivot_value that represents VALUE, formatted as for
2726 struct pivot_value *
2727 pivot_value_new_var_value (const struct variable *variable,
2728 const union value *value)
2730 struct pivot_value *pv = pivot_value_new_value (
2731 value, var_get_width (variable), var_get_print_format (variable),
2732 var_get_encoding (variable));
2734 char *var_name = xstrdup (var_get_name (variable));
2735 if (var_is_alpha (variable))
2736 pv->string.var_name = var_name;
2738 pv->numeric.var_name = var_name;
2740 const char *label = var_lookup_value_label (variable, value);
2743 if (var_is_alpha (variable))
2744 pv->string.value_label = xstrdup (label);
2746 pv->numeric.value_label = xstrdup (label);
2752 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2753 formatted with FORMAT. For a string value, ENCODING must be its character
2755 struct pivot_value *
2756 pivot_value_new_value (const union value *value, int width,
2757 const struct fmt_spec *format, const char *encoding)
2759 struct pivot_value *pv = xzalloc (sizeof *pv);
2762 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2764 size_t n = strlen (s);
2765 while (n > 0 && s[n - 1] == ' ')
2768 pv->type = PIVOT_VALUE_STRING;
2770 pv->string.hex = format->type == FMT_AHEX;
2774 pv->type = PIVOT_VALUE_NUMERIC;
2775 pv->numeric.x = value->f;
2776 pv->numeric.format = *format;
2782 /* Returns a new pivot_value for VARIABLE. */
2783 struct pivot_value *
2784 pivot_value_new_variable (const struct variable *variable)
2786 struct pivot_value *value = xmalloc (sizeof *value);
2787 *value = (struct pivot_value) {
2788 .type = PIVOT_VALUE_VARIABLE,
2790 .var_name = xstrdup (var_get_name (variable)),
2791 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2797 /* Attaches a reference to FOOTNOTE to V. */
2799 pivot_value_add_footnote (struct pivot_value *v,
2800 const struct pivot_footnote *footnote)
2802 /* Some legacy tables include numerous duplicate footnotes. Suppress
2804 for (size_t i = 0; i < v->n_footnotes; i++)
2805 if (v->footnote_indexes[i] == footnote->idx)
2808 v->footnote_indexes = xrealloc (
2809 v->footnote_indexes, (v->n_footnotes + 1) * sizeof *v->footnote_indexes);
2810 v->footnote_indexes[v->n_footnotes++] = footnote->idx;
2813 /* If VALUE is a numeric value, and RC is a result class such as
2814 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2816 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2819 if (value->type == PIVOT_VALUE_NUMERIC)
2821 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2823 value->numeric.format = *f;