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 ());
857 hmap_init (&table->cells);
862 /* Creates and returns a new pivot table with the given TITLE and a single cell
863 with the given CONTENT.
865 This is really just for error handling. */
867 pivot_table_create_for_text (struct pivot_value *title,
868 struct pivot_value *content)
870 struct pivot_table *table = pivot_table_create__ (title, "Error");
872 struct pivot_dimension *d = pivot_dimension_create (
873 table, PIVOT_AXIS_ROW, N_("Error"));
874 d->hide_all_labels = true;
875 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
877 pivot_table_put1 (table, 0, content);
882 /* Increases TABLE's reference count, indicating that it has an additional
883 owner. A pivot table that is shared among multiple owners must not be
886 pivot_table_ref (const struct pivot_table *table_)
888 struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
894 xstrdup_if_nonnull (const char *s)
896 return s ? xstrdup (s) : NULL;
899 static struct pivot_table_sizing
900 clone_sizing (const struct pivot_table_sizing *s)
902 return (struct pivot_table_sizing) {
903 .widths = (s->n_widths
904 ? xmemdup (s->widths, s->n_widths * sizeof *s->widths)
906 .n_widths = s->n_widths,
908 .breaks = (s->n_breaks
909 ? xmemdup (s->breaks, s->n_breaks * sizeof *s->breaks)
911 .n_breaks = s->n_breaks,
914 ? xmemdup (s->keeps, s->n_keeps * sizeof *s->keeps)
916 .n_keeps = s->n_keeps,
920 static struct pivot_footnote **
921 clone_footnotes (struct pivot_footnote **old, size_t n)
926 struct pivot_footnote **new = xmalloc (n * sizeof *new);
927 for (size_t i = 0; i < n; i++)
929 new[i] = xmalloc (sizeof *new[i]);
930 *new[i] = (struct pivot_footnote) {
932 .content = pivot_value_clone (old[i]->content),
933 .marker = pivot_value_clone (old[i]->marker),
934 .show = old[i]->show,
940 static struct pivot_category *
941 clone_category (struct pivot_category *old,
942 struct pivot_dimension *new_dimension,
943 struct pivot_category *new_parent)
945 struct pivot_category *new = xmalloc (sizeof *new);
946 *new = (struct pivot_category) {
947 .name = pivot_value_clone (old->name),
948 .parent = new_parent,
949 .dimension = new_dimension,
950 .label_depth = old->label_depth,
951 .extra_depth = old->extra_depth,
954 ? xzalloc (old->n_subs * sizeof *new->subs)
956 .n_subs = old->n_subs,
957 .allocated_subs = old->n_subs,
959 .show_label = old->show_label,
960 .show_label_in_corner = old->show_label_in_corner,
962 .format = old->format,
963 .group_index = old->group_index,
964 .data_index = old->data_index,
965 .presentation_index = old->presentation_index,
968 if (pivot_category_is_leaf (old))
970 new->dimension->data_leaves[new->data_index] = new;
971 new->dimension->presentation_leaves[new->presentation_index] = new;
974 for (size_t i = 0; i < new->n_subs; i++)
975 new->subs[i] = clone_category (old->subs[i], new_dimension, new);
980 static struct pivot_dimension *
981 clone_dimension (struct pivot_dimension *old, struct pivot_table *new_pt)
983 struct pivot_dimension *new = xmalloc (sizeof *new);
984 *new = (struct pivot_dimension) {
986 .axis_type = old->axis_type,
988 .top_index = old->top_index,
989 .data_leaves = xzalloc (old->n_leaves * sizeof *new->data_leaves),
990 .presentation_leaves = xzalloc (old->n_leaves
991 * sizeof *new->presentation_leaves),
992 .n_leaves = old->n_leaves,
993 .allocated_leaves = old->n_leaves,
994 .hide_all_labels = old->hide_all_labels,
995 .label_depth = old->label_depth,
998 new->root = clone_category (old->root, new, NULL);
1003 static struct pivot_dimension **
1004 clone_dimensions (struct pivot_dimension **old, size_t n,
1005 struct pivot_table *new_pt)
1010 struct pivot_dimension **new = xmalloc (n * sizeof *new);
1011 for (size_t i = 0; i < n; i++)
1012 new[i] = clone_dimension (old[i], new_pt);
1016 struct pivot_table *
1017 pivot_table_unshare (struct pivot_table *old)
1019 assert (old->ref_cnt > 0);
1020 if (old->ref_cnt == 1)
1023 pivot_table_unref (old);
1025 struct pivot_table *new = xmalloc (sizeof *new);
1026 *new = (struct pivot_table) {
1029 .look = pivot_table_look_ref (old->look),
1031 .rotate_inner_column_labels = old->rotate_inner_column_labels,
1032 .rotate_outer_row_labels = old->rotate_outer_row_labels,
1033 .show_grid_lines = old->show_grid_lines,
1034 .show_title = old->show_title,
1035 .show_caption = old->show_caption,
1036 .current_layer = (old->current_layer
1037 ? xmemdup (old->current_layer,
1038 old->axes[PIVOT_AXIS_LAYER].n_dimensions
1039 * sizeof *new->current_layer)
1041 .show_values = old->show_values,
1042 .show_variables = old->show_variables,
1043 .weight_format = old->weight_format,
1046 [TABLE_HORZ] = clone_sizing (&old->sizing[TABLE_HORZ]),
1047 [TABLE_VERT] = clone_sizing (&old->sizing[TABLE_VERT]),
1050 .epoch = old->epoch,
1051 .decimal = old->decimal,
1052 .grouping = old->grouping,
1054 [0] = xstrdup_if_nonnull (old->ccs[0]),
1055 [1] = xstrdup_if_nonnull (old->ccs[1]),
1056 [2] = xstrdup_if_nonnull (old->ccs[2]),
1057 [3] = xstrdup_if_nonnull (old->ccs[3]),
1058 [4] = xstrdup_if_nonnull (old->ccs[4]),
1060 .small = old->small,
1062 .command_local = xstrdup_if_nonnull (old->command_local),
1063 .command_c = xstrdup_if_nonnull (old->command_c),
1064 .language = xstrdup_if_nonnull (old->language),
1065 .locale = xstrdup_if_nonnull (old->locale),
1067 .dataset = xstrdup_if_nonnull (old->dataset),
1068 .datafile = xstrdup_if_nonnull (old->datafile),
1071 .footnotes = clone_footnotes (old->footnotes, old->n_footnotes),
1072 .n_footnotes = old->n_footnotes,
1073 .allocated_footnotes = old->n_footnotes,
1075 .title = pivot_value_clone (old->title),
1076 .subtype = pivot_value_clone (old->subtype),
1077 .corner_text = pivot_value_clone (old->corner_text),
1078 .caption = pivot_value_clone (old->caption),
1079 .notes = xstrdup_if_nonnull (old->notes),
1081 .dimensions = clone_dimensions (old->dimensions, old->n_dimensions, new),
1082 .n_dimensions = old->n_dimensions,
1084 .cells = HMAP_INITIALIZER (new->cells),
1087 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1089 struct pivot_axis *new_axis = &new->axes[i];
1090 const struct pivot_axis *old_axis = &old->axes[i];
1092 *new_axis = (struct pivot_axis) {
1093 .dimensions = xmalloc (old_axis->n_dimensions
1094 * sizeof *new_axis->dimensions),
1095 .n_dimensions = old_axis->n_dimensions,
1096 .extent = old_axis->extent,
1097 .label_depth = old_axis->label_depth,
1100 for (size_t i = 0; i < new_axis->n_dimensions; i++)
1101 new_axis->dimensions[i] = new->dimensions[
1102 old_axis->dimensions[i]->top_index];
1105 const struct pivot_cell *old_cell;
1106 size_t *dindexes = xmalloc (old->n_dimensions * sizeof *dindexes);
1107 HMAP_FOR_EACH (old_cell, struct pivot_cell, hmap_node, &old->cells)
1109 for (size_t i = 0; i < old->n_dimensions; i++)
1110 dindexes[i] = old_cell->idx[i];
1111 struct pivot_cell *new_cell
1112 = pivot_table_insert_cell (new, dindexes);
1113 new_cell->value = pivot_value_clone (old_cell->value);
1120 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
1121 If TABLE no longer has any owners, it is freed. */
1123 pivot_table_unref (struct pivot_table *table)
1127 assert (table->ref_cnt > 0);
1128 if (--table->ref_cnt)
1131 free (table->current_layer);
1132 pivot_table_look_unref (table->look);
1134 for (int i = 0; i < TABLE_N_AXES; i++)
1135 pivot_table_sizing_uninit (&table->sizing[i]);
1137 for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
1138 free (table->ccs[i]);
1140 free (table->command_local);
1141 free (table->command_c);
1142 free (table->language);
1143 free (table->locale);
1145 free (table->dataset);
1146 free (table->datafile);
1148 for (size_t i = 0; i < table->n_footnotes; i++)
1149 pivot_footnote_destroy (table->footnotes[i]);
1150 free (table->footnotes);
1152 pivot_value_destroy (table->title);
1153 pivot_value_destroy (table->subtype);
1154 pivot_value_destroy (table->corner_text);
1155 pivot_value_destroy (table->caption);
1156 free (table->notes);
1158 for (size_t i = 0; i < table->n_dimensions; i++)
1159 pivot_dimension_destroy (table->dimensions[i]);
1160 free (table->dimensions);
1162 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1163 free (table->axes[i].dimensions);
1165 struct pivot_cell *cell, *next_cell;
1166 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
1168 pivot_table_delete_cell (table, cell);
1170 hmap_destroy (&table->cells);
1175 /* Returns true if TABLE has more than one owner. A pivot table that is shared
1176 among multiple owners must not be modified. */
1178 pivot_table_is_shared (const struct pivot_table *table)
1180 return table->ref_cnt > 1;
1183 /* Swaps axes A and B in TABLE. */
1185 pivot_table_swap_axes (struct pivot_table *table,
1186 enum pivot_axis_type a, enum pivot_axis_type b)
1191 struct pivot_axis tmp = table->axes[a];
1192 table->axes[a] = table->axes[b];
1193 table->axes[b] = tmp;
1195 for (int a = 0; a < PIVOT_N_AXES; a++)
1197 struct pivot_axis *axis = &table->axes[a];
1198 for (size_t d = 0; d < axis->n_dimensions; d++)
1199 axis->dimensions[d]->axis_type = a;
1202 if (a == PIVOT_AXIS_LAYER || b == PIVOT_AXIS_LAYER)
1204 free (table->current_layer);
1205 table->current_layer = xzalloc (
1206 table->axes[PIVOT_AXIS_LAYER].n_dimensions
1207 * sizeof *table->current_layer);
1211 /* Swaps the row and column axes in TABLE. */
1213 pivot_table_transpose (struct pivot_table *table)
1215 pivot_table_swap_axes (table, PIVOT_AXIS_ROW, PIVOT_AXIS_COLUMN);
1219 pivot_table_update_axes (struct pivot_table *table)
1221 for (int a = 0; a < PIVOT_N_AXES; a++)
1223 struct pivot_axis *axis = &table->axes[a];
1225 for (size_t d = 0; d < axis->n_dimensions; d++)
1227 struct pivot_dimension *dim = axis->dimensions[d];
1234 /* Moves DIM from its current location in TABLE to POS within AXIS. POS of 0
1235 is the innermost dimension, 1 is the next one out, and so on. */
1237 pivot_table_move_dimension (struct pivot_table *table,
1238 struct pivot_dimension *dim,
1239 enum pivot_axis_type axis, size_t pos)
1241 assert (dim->table == table);
1243 struct pivot_axis *old_axis = &table->axes[dim->axis_type];
1244 struct pivot_axis *new_axis = &table->axes[axis];
1245 pos = MIN (pos, new_axis->n_dimensions);
1247 if (old_axis == new_axis && pos == dim->level)
1254 /* Update the current layer, if necessary. If we're moving within the layer
1255 axis, preserve the current layer. */
1256 if (dim->axis_type == PIVOT_AXIS_LAYER)
1258 if (axis == PIVOT_AXIS_LAYER)
1260 /* Rearranging the layer axis. */
1261 move_element (table->current_layer, old_axis->n_dimensions,
1262 sizeof *table->current_layer,
1267 /* A layer is becoming a row or column. */
1268 remove_element (table->current_layer, old_axis->n_dimensions,
1269 sizeof *table->current_layer, dim->level);
1272 else if (axis == PIVOT_AXIS_LAYER)
1274 /* A row or column is becoming a layer. */
1275 table->current_layer = xrealloc (
1276 table->current_layer,
1277 (new_axis->n_dimensions + 1) * sizeof *table->current_layer);
1278 insert_element (table->current_layer, new_axis->n_dimensions,
1279 sizeof *table->current_layer, pos);
1280 table->current_layer[pos] = 0;
1283 /* Remove DIM from its current axis. */
1284 remove_element (old_axis->dimensions, old_axis->n_dimensions,
1285 sizeof *old_axis->dimensions, dim->level);
1286 old_axis->n_dimensions--;
1288 /* Insert DIM into its new axis. */
1289 new_axis->dimensions = xrealloc (
1290 new_axis->dimensions,
1291 (new_axis->n_dimensions + 1) * sizeof *new_axis->dimensions);
1292 insert_element (new_axis->dimensions, new_axis->n_dimensions,
1293 sizeof *new_axis->dimensions, pos);
1294 new_axis->dimensions[pos] = dim;
1295 new_axis->n_dimensions++;
1297 pivot_table_update_axes (table);
1301 const struct pivot_table_look *
1302 pivot_table_get_look (const struct pivot_table *table)
1308 pivot_table_set_look (struct pivot_table *table,
1309 const struct pivot_table_look *look)
1311 pivot_table_look_unref (table->look);
1312 table->look = pivot_table_look_ref (look);
1315 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
1316 WV, which should be the weight variable for the dictionary whose data or
1317 statistics are being put into TABLE.
1319 This has no effect if WV is NULL. */
1321 pivot_table_set_weight_var (struct pivot_table *table,
1322 const struct variable *wv)
1325 pivot_table_set_weight_format (table, var_get_print_format (wv));
1328 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
1329 format for the dictionary whose data or statistics are being put into TABLE.
1331 This has no effect if WFMT is NULL. */
1333 pivot_table_set_weight_format (struct pivot_table *table,
1334 const struct fmt_spec *wfmt)
1337 table->weight_format = *wfmt;
1340 /* Returns true if TABLE has no cells, false otherwise. */
1342 pivot_table_is_empty (const struct pivot_table *table)
1344 return hmap_is_empty (&table->cells);
1348 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
1350 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
1354 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
1356 for (size_t i = 0; i < n; i++)
1363 static struct pivot_cell *
1364 pivot_table_lookup_cell__ (const struct pivot_table *table,
1365 const size_t *dindexes, unsigned int hash)
1367 struct pivot_cell *cell;
1368 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
1370 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
1375 static struct pivot_cell *
1376 pivot_cell_allocate (size_t n_idx)
1378 struct pivot_cell *cell UNUSED;
1379 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
1382 static struct pivot_cell *
1383 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
1385 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1386 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
1389 cell = pivot_cell_allocate (table->n_dimensions);
1390 for (size_t i = 0; i < table->n_dimensions; i++)
1391 cell->idx[i] = dindexes[i];
1393 hmap_insert (&table->cells, &cell->hmap_node, hash);
1398 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
1399 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
1402 If VALUE is a numeric value without a specified format, this function checks
1403 each of the categories designated by DINDEXES[] and takes the format from
1404 the first category with a result class. If none has a result class, uses
1405 the overall default numeric format. */
1407 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
1408 struct pivot_value *value)
1410 assert (n == table->n_dimensions);
1411 for (size_t i = 0; i < n; i++)
1412 assert (dindexes[i] < table->dimensions[i]->n_leaves);
1414 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
1416 for (size_t i = 0; i < table->n_dimensions; i++)
1418 const struct pivot_dimension *d = table->dimensions[i];
1419 if (dindexes[i] < d->n_leaves)
1421 const struct pivot_category *c = d->data_leaves[dindexes[i]];
1424 value->numeric.format = c->format;
1429 value->numeric.format = *settings_get_format ();
1434 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1435 pivot_value_destroy (cell->value);
1436 cell->value = value;
1439 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
1440 dimension. Takes ownership of VALUE. */
1442 pivot_table_put1 (struct pivot_table *table, size_t idx1,
1443 struct pivot_value *value)
1445 size_t dindexes[] = { idx1 };
1446 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1449 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
1450 dimensions. Takes ownership of VALUE. */
1452 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
1453 struct pivot_value *value)
1455 size_t dindexes[] = { idx1, idx2 };
1456 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1459 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
1460 have 3 dimensions. Takes ownership of VALUE. */
1462 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
1463 size_t idx3, struct pivot_value *value)
1465 size_t dindexes[] = { idx1, idx2, idx3 };
1466 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1469 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
1470 must have 4 dimensions. Takes ownership of VALUE. */
1472 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1473 size_t idx3, size_t idx4, struct pivot_value *value)
1475 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1476 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1479 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1480 automatically assigned marker.
1482 The footnote will only appear in output if it is referenced. Use
1483 pivot_value_add_footnote() to add a reference to the footnote. */
1484 struct pivot_footnote *
1485 pivot_table_create_footnote (struct pivot_table *table,
1486 struct pivot_value *content)
1488 return pivot_table_create_footnote__ (table, table->n_footnotes,
1492 static struct pivot_value *
1493 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1495 char text[INT_BUFSIZE_BOUND (size_t)];
1496 if (show_numeric_markers)
1497 snprintf (text, sizeof text, "%d", idx + 1);
1499 str_format_26adic (idx + 1, false, text, sizeof text);
1500 return pivot_value_new_user_text (text, -1);
1503 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1504 all lower indexes as a side effect). If MARKER is nonnull, sets the
1505 footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1506 struct pivot_footnote *
1507 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1508 struct pivot_value *marker,
1509 struct pivot_value *content)
1511 if (idx >= table->n_footnotes)
1513 while (idx >= table->allocated_footnotes)
1514 table->footnotes = x2nrealloc (table->footnotes,
1515 &table->allocated_footnotes,
1516 sizeof *table->footnotes);
1517 while (idx >= table->n_footnotes)
1519 struct pivot_footnote *f = xmalloc (sizeof *f);
1520 f->idx = table->n_footnotes;
1521 f->marker = pivot_make_default_footnote_marker (
1522 f->idx, table->look->show_numeric_markers);
1526 table->footnotes[table->n_footnotes++] = f;
1530 struct pivot_footnote *f = table->footnotes[idx];
1533 pivot_value_destroy (f->marker);
1538 pivot_value_destroy (f->content);
1539 f->content = content;
1544 /* Frees the data owned by F. */
1546 pivot_footnote_destroy (struct pivot_footnote *f)
1550 pivot_value_destroy (f->content);
1551 pivot_value_destroy (f->marker);
1556 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1557 indexes for each dimension in TABLE in DINDEXES[]. */
1559 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1560 const size_t *pindexes[PIVOT_N_AXES],
1561 size_t dindexes[/* table->n_dimensions */])
1563 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1565 const struct pivot_axis *axis = &table->axes[i];
1567 for (size_t j = 0; j < axis->n_dimensions; j++)
1569 const struct pivot_dimension *d = axis->dimensions[j];
1570 dindexes[d->top_index]
1571 = d->presentation_leaves[pindexes[i][j]]->data_index;
1577 pivot_table_enumerate_axis (const struct pivot_table *table,
1578 enum pivot_axis_type axis_type,
1579 const size_t *layer_indexes, bool omit_empty,
1582 const struct pivot_axis *axis = &table->axes[axis_type];
1583 if (!axis->n_dimensions)
1585 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1587 enumeration[1] = SIZE_MAX;
1592 else if (!axis->extent)
1594 size_t *enumeration = xmalloc (sizeof *enumeration);
1595 *enumeration = SIZE_MAX;
1601 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1602 axis->n_dimensions), 1),
1603 sizeof *enumeration);
1604 size_t *p = enumeration;
1605 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1607 size_t *axis_indexes;
1608 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1612 enum pivot_axis_type axis2_type
1613 = pivot_axis_type_transpose (axis_type);
1615 size_t *axis2_indexes;
1616 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1618 const size_t *pindexes[PIVOT_N_AXES];
1619 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1620 pindexes[axis_type] = axis_indexes;
1621 pindexes[axis2_type] = axis2_indexes;
1622 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1623 if (pivot_table_get (table, dindexes))
1629 free (axis2_indexes);
1632 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1633 p += axis->n_dimensions;
1635 if (omit_empty && p == enumeration)
1637 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1639 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1640 p += axis->n_dimensions;
1645 *n = (p - enumeration) / axis->n_dimensions;
1651 static struct pivot_cell *
1652 pivot_table_lookup_cell (const struct pivot_table *table,
1653 const size_t *dindexes)
1655 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1656 return pivot_table_lookup_cell__ (table, dindexes, hash);
1659 const struct pivot_value *
1660 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1662 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1663 return cell ? cell->value : NULL;
1666 struct pivot_value *
1667 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1669 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1671 cell->value = pivot_value_new_user_text ("", -1);
1676 pivot_table_delete_cell (struct pivot_table *table, struct pivot_cell *cell)
1678 hmap_delete (&table->cells, &cell->hmap_node);
1679 pivot_value_destroy (cell->value);
1684 pivot_table_delete (struct pivot_table *table, const size_t *dindexes)
1686 struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1689 pivot_table_delete_cell (table, cell);
1697 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1699 if (pivot_category_is_group (category) && category->n_subs)
1700 for (size_t i = 0; i < category->n_subs; i++)
1701 distribute_extra_depth (category->subs[i], extra_depth);
1703 category->extra_depth += extra_depth;
1707 pivot_category_assign_label_depth (struct pivot_category *category,
1708 bool dimension_labels_in_corner)
1710 category->extra_depth = 0;
1712 if (pivot_category_is_group (category))
1715 for (size_t i = 0; i < category->n_subs; i++)
1717 pivot_category_assign_label_depth (category->subs[i], false);
1718 depth = MAX (depth, category->subs[i]->label_depth);
1721 for (size_t i = 0; i < category->n_subs; i++)
1723 struct pivot_category *sub = category->subs[i];
1725 size_t extra_depth = depth - sub->label_depth;
1727 distribute_extra_depth (sub, extra_depth);
1729 sub->label_depth = depth;
1732 category->show_label_in_corner = (category->show_label
1733 && dimension_labels_in_corner);
1734 category->label_depth
1735 = (category->show_label && !category->show_label_in_corner
1736 ? depth + 1 : depth);
1739 category->label_depth = 1;
1743 pivot_axis_assign_label_depth (struct pivot_table *table,
1744 enum pivot_axis_type axis_type,
1745 bool dimension_labels_in_corner)
1747 struct pivot_axis *axis = &table->axes[axis_type];
1748 bool any_label_shown_in_corner = false;
1749 axis->label_depth = 0;
1751 for (size_t i = 0; i < axis->n_dimensions; i++)
1753 struct pivot_dimension *d = axis->dimensions[i];
1754 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1755 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1756 axis->label_depth += d->label_depth;
1757 axis->extent *= d->n_leaves;
1759 if (d->root->show_label_in_corner)
1760 any_label_shown_in_corner = true;
1762 return any_label_shown_in_corner;
1766 pivot_table_assign_label_depth (struct pivot_table *table)
1768 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1769 if (pivot_axis_assign_label_depth (
1770 table, PIVOT_AXIS_ROW, (table->look->row_labels_in_corner
1771 && !table->corner_text))
1772 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1773 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1774 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1778 indent (int indentation)
1780 for (int i = 0; i < indentation * 2; i++)
1785 pivot_value_dump (const struct pivot_value *value)
1787 char *s = pivot_value_to_string_defaults (value);
1793 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1798 indent (indentation);
1799 printf ("%s: ", name);
1800 pivot_value_dump (value);
1806 pivot_table_dump_string (const char *string, const char *name, int indentation)
1810 indent (indentation);
1811 printf ("%s: %s\n", name, string);
1816 pivot_category_dump (const struct pivot_category *c, int indentation)
1818 indent (indentation);
1819 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1820 pivot_value_dump (c->name);
1823 if (pivot_category_is_leaf (c))
1824 printf ("data_index=%zu\n", c->data_index);
1827 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1830 for (size_t i = 0; i < c->n_subs; i++)
1831 pivot_category_dump (c->subs[i], indentation + 1);
1836 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1838 indent (indentation);
1839 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1840 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1842 pivot_category_dump (d->root, indentation + 1);
1846 table_area_style_dump (enum pivot_area area, const struct table_area_style *a,
1849 indent (indentation);
1850 printf ("%s: ", pivot_area_to_string (area));
1851 font_style_dump (&a->font_style);
1853 cell_style_dump (&a->cell_style);
1858 table_border_style_dump (enum pivot_border border,
1859 const struct table_border_style *b, int indentation)
1861 indent (indentation);
1862 printf ("%s: %s ", pivot_border_to_string (border),
1863 table_stroke_to_string (b->stroke));
1864 cell_color_dump (&b->color);
1869 compose_headings (const struct pivot_table *pt,
1870 const struct pivot_axis *axis,
1871 const size_t *column_enumeration)
1873 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1876 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1877 for (size_t i = 0; i < axis->label_depth; i++)
1878 headings[i] = xcalloc (axis->extent, sizeof **headings);
1880 const size_t *indexes;
1882 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1884 int row = axis->label_depth - 1;
1885 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1887 const struct pivot_dimension *d = axis->dimensions[dim_index];
1888 if (d->hide_all_labels)
1890 for (const struct pivot_category *c
1891 = d->presentation_leaves[indexes[dim_index]];
1895 if (pivot_category_is_leaf (c) || (c->show_label
1896 && !c->show_label_in_corner))
1898 headings[row][column] = pivot_value_to_string (c->name, pt);
1899 if (!*headings[row][column])
1900 headings[row][column] = xstrdup ("<blank>");
1912 free_headings (const struct pivot_axis *axis, char ***headings)
1914 for (size_t i = 0; i < axis->label_depth; i++)
1916 for (size_t j = 0; j < axis->extent; j++)
1917 free (headings[i][j]);
1924 pivot_table_sizing_dump (const char *name,
1925 const int width_ranges[2],
1926 const struct pivot_table_sizing *s,
1929 indent (indentation);
1930 printf ("%ss: min=%d, max=%d\n", name, width_ranges[0], width_ranges[1]);
1933 indent (indentation + 1);
1934 printf ("%s widths:", name);
1935 for (size_t i = 0; i < s->n_widths; i++)
1936 printf (" %d", s->widths[i]);
1941 indent (indentation + 1);
1942 printf ("break after %ss:", name);
1943 for (size_t i = 0; i < s->n_breaks; i++)
1944 printf (" %zu", s->breaks[i]);
1949 indent (indentation + 1);
1950 printf ("keep %ss together:", name);
1951 for (size_t i = 0; i < s->n_keeps; i++)
1952 printf (" [%zu,%zu]",
1954 s->keeps[i].ofs + s->keeps[i].n - 1);
1960 pivot_table_dump (const struct pivot_table *table, int indentation)
1965 pivot_table_assign_label_depth (CONST_CAST (struct pivot_table *, table));
1967 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1968 if (table->decimal == '.' || table->decimal == ',')
1969 settings_set_decimal_char (table->decimal);
1971 pivot_table_dump_value (table->title, "title", indentation);
1972 pivot_table_dump_value (table->subtype, "subtype", indentation);
1973 pivot_table_dump_string (table->command_c, "command", indentation);
1974 pivot_table_dump_string (table->dataset, "dataset", indentation);
1975 pivot_table_dump_string (table->datafile, "datafile", indentation);
1976 pivot_table_dump_string (table->notes, "notes", indentation);
1977 pivot_table_dump_string (table->look->name, "table-look", indentation);
1980 indent (indentation);
1982 struct tm *tm = localtime (&table->date);
1983 printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
1984 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
1988 indent (indentation);
1989 printf ("sizing:\n");
1990 pivot_table_sizing_dump ("column", table->look->width_ranges[TABLE_HORZ],
1991 &table->sizing[TABLE_HORZ], indentation + 1);
1992 pivot_table_sizing_dump ("row", table->look->width_ranges[TABLE_VERT],
1993 &table->sizing[TABLE_VERT], indentation + 1);
1995 indent (indentation);
1996 printf ("areas:\n");
1997 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1998 table_area_style_dump (area, &table->look->areas[area], indentation + 1);
2000 indent (indentation);
2001 printf ("borders:\n");
2002 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
2003 table_border_style_dump (border, &table->look->borders[border],
2006 for (size_t i = 0; i < table->n_dimensions; i++)
2007 pivot_dimension_dump (table->dimensions[i], indentation);
2009 /* Presentation and data indexes. */
2010 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
2012 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
2013 if (layer_axis->n_dimensions)
2015 indent (indentation);
2016 printf ("current layer:");
2018 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
2020 const struct pivot_dimension *d = layer_axis->dimensions[i];
2021 char *name = pivot_value_to_string (d->root->name, table);
2022 char *value = pivot_value_to_string (
2023 d->data_leaves[table->current_layer[i]]->name, table);
2024 printf (" %s=%s", name, value);
2032 size_t *layer_indexes;
2033 size_t layer_iteration = 0;
2034 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
2036 indent (indentation);
2037 printf ("layer %zu:", layer_iteration++);
2039 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
2040 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
2042 const struct pivot_dimension *d = layer_axis->dimensions[i];
2044 fputs (i == 0 ? " " : ", ", stdout);
2045 pivot_value_dump (d->root->name);
2046 fputs (" =", stdout);
2048 struct pivot_value **names = xnmalloc (d->n_leaves, sizeof *names);
2050 for (const struct pivot_category *c
2051 = d->presentation_leaves[layer_indexes[i]];
2055 if (pivot_category_is_leaf (c) || c->show_label)
2056 names[n_names++] = c->name;
2059 for (size_t i = n_names; i-- > 0;)
2062 pivot_value_dump (names[i]);
2068 size_t *column_enumeration = pivot_table_enumerate_axis (
2069 table, PIVOT_AXIS_COLUMN, layer_indexes, table->look->omit_empty, NULL);
2070 size_t *row_enumeration = pivot_table_enumerate_axis (
2071 table, PIVOT_AXIS_ROW, layer_indexes, table->look->omit_empty, NULL);
2073 char ***column_headings = compose_headings (
2074 table, &table->axes[PIVOT_AXIS_COLUMN], column_enumeration);
2075 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
2077 indent (indentation + 1);
2078 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
2081 fputs ("; ", stdout);
2082 if (column_headings[y][x])
2083 fputs (column_headings[y][x], stdout);
2087 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
2089 indent (indentation + 1);
2090 printf ("-----------------------------------------------\n");
2092 char ***row_headings = compose_headings (
2093 table, &table->axes[PIVOT_AXIS_ROW], row_enumeration);
2096 const size_t *pindexes[PIVOT_N_AXES]
2097 = { [PIVOT_AXIS_LAYER] = layer_indexes };
2098 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
2099 &table->axes[PIVOT_AXIS_ROW])
2101 indent (indentation + 1);
2104 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
2107 fputs ("; ", stdout);
2108 if (row_headings[y][x])
2109 fputs (row_headings[y][x], stdout);
2115 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
2117 &table->axes[PIVOT_AXIS_COLUMN])
2122 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
2123 const struct pivot_value *value = pivot_table_get (
2126 pivot_value_dump (value);
2133 free (column_enumeration);
2134 free (row_enumeration);
2135 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
2138 pivot_table_dump_value (table->caption, "caption", indentation);
2140 for (size_t i = 0; i < table->n_footnotes; i++)
2142 const struct pivot_footnote *f = table->footnotes[i];
2143 indent (indentation);
2146 pivot_value_dump (f->marker);
2148 printf ("%zu", f->idx);
2150 pivot_value_dump (f->content);
2155 settings_set_decimal_char (old_decimal);
2159 consume_int (const char *p, size_t *n)
2162 while (c_isdigit (*p))
2163 *n = *n * 10 + (*p++ - '0');
2168 pivot_format_inner_template (struct string *out, const char *template,
2170 struct pivot_value **values, size_t n_values,
2171 const struct pivot_table *pt)
2173 size_t args_consumed = 0;
2174 while (*template && *template != ':')
2176 if (*template == '\\' && template[1])
2178 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
2181 else if (*template == escape)
2184 template = consume_int (template + 1, &index);
2185 if (index >= 1 && index <= n_values)
2187 pivot_value_format (values[index - 1], pt, out);
2188 args_consumed = MAX (args_consumed, index);
2192 ds_put_byte (out, *template++);
2194 return args_consumed;
2198 pivot_extract_inner_template (const char *template, const char **p)
2204 if (*template == '\\' && template[1] != '\0')
2206 else if (*template == ':')
2207 return template + 1;
2208 else if (*template == '\0')
2216 pivot_format_template (struct string *out, const char *template,
2217 const struct pivot_argument *args, size_t n_args,
2218 const struct pivot_table *pt)
2222 if (*template == '\\' && template[1] != '\0')
2224 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
2227 else if (*template == '^')
2230 template = consume_int (template + 1, &index);
2231 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
2232 pivot_value_format (args[index - 1].values[0], pt, out);
2234 else if (*template == '[')
2236 const char *tmpl[2];
2237 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
2238 template = pivot_extract_inner_template (template, &tmpl[1]);
2239 template += *template == ']';
2242 template = consume_int (template, &index);
2243 if (index < 1 || index > n_args)
2246 const struct pivot_argument *arg = &args[index - 1];
2247 size_t left = arg->n;
2250 struct pivot_value **values = arg->values + (arg->n - left);
2251 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
2252 char escape = "%^"[tmpl_idx];
2253 size_t used = pivot_format_inner_template (
2254 out, tmpl[tmpl_idx], escape, values, left, pt);
2255 if (!used || used > left)
2261 ds_put_byte (out, *template++);
2265 static enum settings_value_show
2266 interpret_show (enum settings_value_show global_show,
2267 enum settings_value_show table_show,
2268 enum settings_value_show value_show,
2271 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
2272 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
2273 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
2277 /* Appends a text representation of the body of VALUE to OUT. Settings on
2278 PT control whether variable and value labels are included.
2280 The "body" omits subscripts and superscripts and footnotes.
2282 Returns true if OUT is a number (or a number plus a value label), false
2285 pivot_value_format_body (const struct pivot_value *value,
2286 const struct pivot_table *pt,
2289 enum settings_value_show show;
2290 bool numeric = false;
2292 switch (value->type)
2294 case PIVOT_VALUE_NUMERIC:
2295 show = interpret_show (settings_get_show_values (),
2297 value->numeric.show,
2298 value->numeric.value_label != NULL);
2299 if (show & SETTINGS_VALUE_SHOW_VALUE)
2301 char *s = data_out (&(union value) { .f = value->numeric.x },
2302 "UTF-8", &value->numeric.format);
2303 ds_put_cstr (out, s + strspn (s, " "));
2306 if (show & SETTINGS_VALUE_SHOW_LABEL)
2308 if (show & SETTINGS_VALUE_SHOW_VALUE)
2309 ds_put_byte (out, ' ');
2310 ds_put_cstr (out, value->numeric.value_label);
2312 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
2315 case PIVOT_VALUE_STRING:
2316 show = interpret_show (settings_get_show_values (),
2319 value->string.value_label != NULL);
2320 if (show & SETTINGS_VALUE_SHOW_VALUE)
2322 if (value->string.hex)
2324 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
2326 ds_put_format (out, "%02X", *p);
2329 ds_put_cstr (out, value->string.s);
2331 if (show & SETTINGS_VALUE_SHOW_LABEL)
2333 if (show & SETTINGS_VALUE_SHOW_VALUE)
2334 ds_put_byte (out, ' ');
2335 ds_put_cstr (out, value->string.value_label);
2339 case PIVOT_VALUE_VARIABLE:
2340 show = interpret_show (settings_get_show_variables (),
2342 value->variable.show,
2343 value->variable.var_label != NULL);
2344 if (show & SETTINGS_VALUE_SHOW_VALUE)
2345 ds_put_cstr (out, value->variable.var_name);
2346 if (show & SETTINGS_VALUE_SHOW_LABEL)
2348 if (show & SETTINGS_VALUE_SHOW_VALUE)
2349 ds_put_byte (out, ' ');
2350 ds_put_cstr (out, value->variable.var_label);
2354 case PIVOT_VALUE_TEXT:
2355 ds_put_cstr (out, value->text.local);
2358 case PIVOT_VALUE_TEMPLATE:
2359 pivot_format_template (out, value->template.local, value->template.args,
2360 value->template.n_args, pt);
2367 /* Appends a text representation of VALUE to OUT. Settings on
2368 PT control whether variable and value labels are included.
2370 Subscripts and footnotes are included. */
2372 pivot_value_format (const struct pivot_value *value,
2373 const struct pivot_table *pt,
2376 pivot_value_format_body (value, pt, out);
2378 if (value->n_subscripts)
2380 for (size_t i = 0; i < value->n_subscripts; i++)
2381 ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
2384 for (size_t i = 0; i < value->n_footnotes; i++)
2386 ds_put_byte (out, '[');
2388 size_t idx = value->footnote_indexes[i];
2389 const struct pivot_footnote *f = pt->footnotes[idx];
2390 pivot_value_format (f->marker, pt, out);
2392 ds_put_byte (out, ']');
2396 /* Returns a text representation of VALUE. The caller must free the string,
2399 pivot_value_to_string (const struct pivot_value *value,
2400 const struct pivot_table *pt)
2402 struct string s = DS_EMPTY_INITIALIZER;
2403 pivot_value_format (value, pt, &s);
2404 return ds_steal_cstr (&s);
2408 pivot_value_to_string_defaults (const struct pivot_value *value)
2410 static const struct pivot_table pt = {
2411 .show_values = SETTINGS_VALUE_SHOW_DEFAULT,
2412 .show_variables = SETTINGS_VALUE_SHOW_DEFAULT,
2414 return pivot_value_to_string (value, &pt);
2417 struct pivot_value *
2418 pivot_value_clone (const struct pivot_value *old)
2423 struct pivot_value *new = xmemdup (old, sizeof *new);
2424 if (old->font_style)
2426 new->font_style = xmalloc (sizeof *new->font_style);
2427 font_style_copy (NULL, new->font_style, old->font_style);
2429 if (old->cell_style)
2430 new->font_style = xmemdup (old->font_style, sizeof *new->font_style);
2431 if (old->n_subscripts)
2433 new->subscripts = xnmalloc (old->n_subscripts, sizeof *new->subscripts);
2434 for (size_t i = 0; i < old->n_subscripts; i++)
2435 new->subscripts[i] = xstrdup (old->subscripts[i]);
2437 if (old->n_footnotes)
2438 new->footnote_indexes = xmemdup (
2439 old->footnote_indexes, old->n_footnotes * sizeof *new->footnote_indexes);
2443 case PIVOT_VALUE_NUMERIC:
2444 new->numeric.var_name = xstrdup_if_nonnull (new->numeric.var_name);
2445 new->numeric.value_label = xstrdup_if_nonnull (new->numeric.value_label);
2448 case PIVOT_VALUE_STRING:
2449 new->string.s = xstrdup (new->string.s);
2450 new->string.var_name = xstrdup_if_nonnull (new->string.var_name);
2451 new->string.value_label = xstrdup_if_nonnull (new->string.value_label);
2454 case PIVOT_VALUE_VARIABLE:
2455 new->variable.var_name = xstrdup_if_nonnull (new->variable.var_name);
2456 new->variable.var_label = xstrdup_if_nonnull (new->variable.var_label);
2459 case PIVOT_VALUE_TEXT:
2460 new->text.local = xstrdup (old->text.local);
2461 new->text.c = (old->text.c == old->text.local ? new->text.local
2462 : xstrdup (old->text.c));
2463 new->text.id = (old->text.id == old->text.local ? new->text.local
2464 : old->text.id == old->text.c ? new->text.c
2465 : xstrdup (old->text.id));
2468 case PIVOT_VALUE_TEMPLATE:
2469 new->template.local = xstrdup (old->template.local);
2470 new->template.id = (old->template.id == old->template.local
2471 ? new->template.local
2472 : xstrdup (old->template.id));
2473 new->template.args = xmalloc (new->template.n_args
2474 * sizeof *new->template.args);
2475 for (size_t i = 0; i < old->template.n_args; i++)
2476 pivot_argument_copy (&new->template.args[i],
2477 &old->template.args[i]);
2486 /* Frees the data owned by V. */
2488 pivot_value_destroy (struct pivot_value *value)
2492 font_style_uninit (value->font_style);
2493 free (value->font_style);
2494 free (value->cell_style);
2495 free (value->footnote_indexes);
2497 for (size_t i = 0; i < value->n_subscripts; i++)
2498 free (value->subscripts[i]);
2499 free (value->subscripts);
2501 switch (value->type)
2503 case PIVOT_VALUE_NUMERIC:
2504 free (value->numeric.var_name);
2505 free (value->numeric.value_label);
2508 case PIVOT_VALUE_STRING:
2509 free (value->string.s);
2510 free (value->string.var_name);
2511 free (value->string.value_label);
2514 case PIVOT_VALUE_VARIABLE:
2515 free (value->variable.var_name);
2516 free (value->variable.var_label);
2519 case PIVOT_VALUE_TEXT:
2520 free (value->text.local);
2521 if (value->text.c != value->text.local)
2522 free (value->text.c);
2523 if (value->text.id != value->text.local
2524 && value->text.id != value->text.c)
2525 free (value->text.id);
2528 case PIVOT_VALUE_TEMPLATE:
2529 free (value->template.local);
2530 if (value->template.id != value->template.local)
2531 free (value->template.id);
2532 for (size_t i = 0; i < value->template.n_args; i++)
2533 pivot_argument_uninit (&value->template.args[i]);
2534 free (value->template.args);
2544 /* Sets AREA to the style to use for VALUE, with defaults coming from
2545 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
2547 pivot_value_get_style (struct pivot_value *value,
2548 const struct font_style *base_font_style,
2549 const struct cell_style *base_cell_style,
2550 struct table_area_style *area)
2552 font_style_copy (NULL, &area->font_style, (value->font_style
2554 : base_font_style));
2555 area->cell_style = *(value->cell_style
2560 /* Copies AREA into VALUE's style. */
2562 pivot_value_set_style (struct pivot_value *value,
2563 const struct table_area_style *area)
2565 pivot_value_set_font_style (value, &area->font_style);
2566 pivot_value_set_cell_style (value, &area->cell_style);
2570 pivot_value_set_font_style (struct pivot_value *value,
2571 const struct font_style *font_style)
2573 if (value->font_style)
2574 font_style_uninit (value->font_style);
2576 value->font_style = xmalloc (sizeof *value->font_style);
2577 font_style_copy (NULL, value->font_style, font_style);
2581 pivot_value_set_cell_style (struct pivot_value *value,
2582 const struct cell_style *cell_style)
2584 if (!value->cell_style)
2585 value->cell_style = xmalloc (sizeof *value->cell_style);
2586 *value->cell_style = *cell_style;
2590 pivot_argument_copy (struct pivot_argument *dst,
2591 const struct pivot_argument *src)
2593 *dst = (struct pivot_argument) {
2595 .values = xmalloc (src->n * sizeof *dst->values),
2598 for (size_t i = 0; i < src->n; i++)
2599 dst->values[i] = pivot_value_clone (src->values[i]);
2602 /* Frees the data owned by ARG (but not ARG itself). */
2604 pivot_argument_uninit (struct pivot_argument *arg)
2608 for (size_t i = 0; i < arg->n; i++)
2609 pivot_value_destroy (arg->values[i]);
2614 /* Creates and returns a new pivot_value whose contents is the null-terminated
2615 string TEXT. Takes ownership of TEXT.
2617 This function is for text strings provided by the user (with the exception
2618 that pivot_value_new_variable() should be used for variable names). For
2619 strings that are part of the PSPP user interface, such as names of
2620 procedures, statistics, annotations, error messages, etc., use
2621 pivot_value_new_text(). */
2622 struct pivot_value *
2623 pivot_value_new_user_text_nocopy (char *text)
2625 struct pivot_value *value = xmalloc (sizeof *value);
2626 *value = (struct pivot_value) {
2627 .type = PIVOT_VALUE_TEXT,
2632 .user_provided = true,
2638 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2639 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2642 This function is for text strings provided by the user (with the exception
2643 that pivot_value_new_variable() should be used for variable names). For
2644 strings that are part of the PSPP user interface, such as names of
2645 procedures, statistics, annotations, error messages, etc., use
2646 pivot_value_new_text().j
2648 The caller retains ownership of TEXT.*/
2649 struct pivot_value *
2650 pivot_value_new_user_text (const char *text, size_t length)
2652 return pivot_value_new_user_text_nocopy (
2653 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2656 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2657 a translatable string, but not actually translated yet, e.g. enclosed in
2658 N_(). This function is for text strings that are part of the PSPP user
2659 interface, such as names of procedures, statistics, annotations, error
2660 messages, etc. For strings that come from the user, use
2661 pivot_value_new_user_text(). */
2662 struct pivot_value *
2663 pivot_value_new_text (const char *text)
2665 char *c = xstrdup (text);
2666 char *local = xstrdup (gettext (c));
2668 struct pivot_value *value = xmalloc (sizeof *value);
2669 *value = (struct pivot_value) {
2670 .type = PIVOT_VALUE_TEXT,
2675 .user_provided = false,
2681 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2683 struct pivot_value * PRINTF_FORMAT (1, 2)
2684 pivot_value_new_text_format (const char *format, ...)
2687 va_start (args, format);
2688 char *c = xvasprintf (format, args);
2691 va_start (args, format);
2692 char *local = xvasprintf (gettext (format), args);
2695 struct pivot_value *value = xmalloc (sizeof *value);
2696 *value = (struct pivot_value) {
2697 .type = PIVOT_VALUE_TEXT,
2702 .user_provided = false,
2708 /* Returns a new pivot_value that represents X.
2710 The format to use for X is unspecified. Usually the easiest way to specify
2711 a format is through assigning a result class to one of the categories that
2712 the pivot_value will end up in. If that is not suitable, then the caller
2713 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2714 struct pivot_value *
2715 pivot_value_new_number (double x)
2717 struct pivot_value *value = xmalloc (sizeof *value);
2718 *value = (struct pivot_value) {
2719 .type = PIVOT_VALUE_NUMERIC,
2720 .numeric = { .x = x, },
2725 /* Returns a new pivot_value that represents X, formatted as an integer. */
2726 struct pivot_value *
2727 pivot_value_new_integer (double x)
2729 struct pivot_value *value = pivot_value_new_number (x);
2730 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2734 /* Returns a new pivot_value that represents VALUE, formatted as for
2736 struct pivot_value *
2737 pivot_value_new_var_value (const struct variable *variable,
2738 const union value *value)
2740 struct pivot_value *pv = pivot_value_new_value (
2741 value, var_get_width (variable), var_get_print_format (variable),
2742 var_get_encoding (variable));
2744 char *var_name = xstrdup (var_get_name (variable));
2745 if (var_is_alpha (variable))
2746 pv->string.var_name = var_name;
2748 pv->numeric.var_name = var_name;
2750 const char *label = var_lookup_value_label (variable, value);
2753 if (var_is_alpha (variable))
2754 pv->string.value_label = xstrdup (label);
2756 pv->numeric.value_label = xstrdup (label);
2762 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2763 formatted with FORMAT. For a string value, ENCODING must be its character
2765 struct pivot_value *
2766 pivot_value_new_value (const union value *value, int width,
2767 const struct fmt_spec *format, const char *encoding)
2769 struct pivot_value *pv = xzalloc (sizeof *pv);
2772 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2774 size_t n = strlen (s);
2775 while (n > 0 && s[n - 1] == ' ')
2778 pv->type = PIVOT_VALUE_STRING;
2780 pv->string.hex = format->type == FMT_AHEX;
2784 pv->type = PIVOT_VALUE_NUMERIC;
2785 pv->numeric.x = value->f;
2786 pv->numeric.format = *format;
2792 /* Returns a new pivot_value for VARIABLE. */
2793 struct pivot_value *
2794 pivot_value_new_variable (const struct variable *variable)
2796 struct pivot_value *value = xmalloc (sizeof *value);
2797 *value = (struct pivot_value) {
2798 .type = PIVOT_VALUE_VARIABLE,
2800 .var_name = xstrdup (var_get_name (variable)),
2801 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2807 /* Attaches a reference to FOOTNOTE to V. */
2809 pivot_value_add_footnote (struct pivot_value *v,
2810 const struct pivot_footnote *footnote)
2812 /* Some legacy tables include numerous duplicate footnotes. Suppress
2814 for (size_t i = 0; i < v->n_footnotes; i++)
2815 if (v->footnote_indexes[i] == footnote->idx)
2818 v->footnote_indexes = xrealloc (
2819 v->footnote_indexes, (v->n_footnotes + 1) * sizeof *v->footnote_indexes);
2820 v->footnote_indexes[v->n_footnotes++] = footnote->idx;
2823 /* If VALUE is a numeric value, and RC is a result class such as
2824 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2826 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2829 if (value->type == PIVOT_VALUE_NUMERIC)
2831 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2833 value->numeric.format = *f;