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/hash-functions.h"
29 #include "libpspp/i18n.h"
30 #include "output/driver.h"
31 #include "output/spv/spv-table-look.h"
33 #include "gl/c-ctype.h"
34 #include "gl/configmake.h"
35 #include "gl/intprops.h"
36 #include "gl/minmax.h"
37 #include "gl/relocatable.h"
38 #include "gl/xalloc.h"
39 #include "gl/xmemdup0.h"
43 #define _(msgid) gettext (msgid)
44 #define N_(msgid) msgid
46 static const struct fmt_spec *pivot_table_get_format (
47 const struct pivot_table *, const char *s);
49 /* Pivot table display styling. */
51 /* Returns the name of AREA. */
53 pivot_area_to_string (enum pivot_area area)
57 case PIVOT_AREA_TITLE: return "title";
58 case PIVOT_AREA_CAPTION: return "caption";
59 case PIVOT_AREA_FOOTER: return "footer";
60 case PIVOT_AREA_CORNER: return "corner";
61 case PIVOT_AREA_COLUMN_LABELS: return "column labels";
62 case PIVOT_AREA_ROW_LABELS: return "row labels";
63 case PIVOT_AREA_DATA: return "data";
64 case PIVOT_AREA_LAYERS: return "layers";
65 case PIVOT_N_AREAS: default: return "**error**";
69 /* Returns the name of BORDER. */
71 pivot_border_to_string (enum pivot_border border)
75 case PIVOT_BORDER_TITLE:
78 case PIVOT_BORDER_OUTER_LEFT:
79 return "left outer frame";
80 case PIVOT_BORDER_OUTER_TOP:
81 return "top outer frame";
82 case PIVOT_BORDER_OUTER_RIGHT:
83 return "right outer frame";
84 case PIVOT_BORDER_OUTER_BOTTOM:
85 return "bottom outer frame";
87 case PIVOT_BORDER_INNER_LEFT:
88 return "left inner frame";
89 case PIVOT_BORDER_INNER_TOP:
90 return "top inner frame";
91 case PIVOT_BORDER_INNER_RIGHT:
92 return "right inner frame";
93 case PIVOT_BORDER_INNER_BOTTOM:
94 return "bottom inner frame";
96 case PIVOT_BORDER_DATA_LEFT:
97 return "data area left";
98 case PIVOT_BORDER_DATA_TOP:
99 return "data area top";
101 case PIVOT_BORDER_DIM_ROW_HORZ:
102 return "row label horizontal dimension border";
103 case PIVOT_BORDER_DIM_ROW_VERT:
104 return "row label vertical dimension border";
105 case PIVOT_BORDER_DIM_COL_HORZ:
106 return "column label horizontal dimension border";
107 case PIVOT_BORDER_DIM_COL_VERT:
108 return "column label vertical dimension border";
110 case PIVOT_BORDER_CAT_ROW_HORZ:
111 return "row label horizontal category border";
112 case PIVOT_BORDER_CAT_ROW_VERT:
113 return "row label vertical category border";
114 case PIVOT_BORDER_CAT_COL_HORZ:
115 return "column label horizontal category border";
116 case PIVOT_BORDER_CAT_COL_VERT:
117 return "column label vertical category border";
119 case PIVOT_N_BORDERS:
126 pivot_table_sizing_uninit (struct pivot_table_sizing *sizing)
130 free (sizing->widths);
131 free (sizing->breaks);
132 free (sizing->keeps);
136 /* Pivot table looks. */
138 static const struct pivot_table_look *
139 default_look (const struct pivot_table_look *new)
141 static struct pivot_table_look *look;
144 pivot_table_look_unref (look);
145 look = pivot_table_look_ref (new);
149 char *error = pivot_table_look_read ("default.stt", &look);
153 look = pivot_table_look_ref (pivot_table_look_builtin_default ());
159 const struct pivot_table_look *
160 pivot_table_look_get_default (void)
162 return default_look (NULL);
166 pivot_table_look_set_default (const struct pivot_table_look *look)
171 char * WARN_UNUSED_RESULT
172 pivot_table_look_read (const char *name, struct pivot_table_look **lookp)
176 /* Construct search path. */
180 const char *home = getenv ("HOME");
181 char *allocated = NULL;
183 path[n++] = allocated = xasprintf ("%s/.pspp/looks", home);
185 path[n++] = relocate2 (PKGDATADIR "/looks", &allocated2);
189 char *file = fn_search_path (name, (char **) path);
192 char *name2 = xasprintf ("%s.stt", name);
193 file = fn_search_path (name2, (char **) path);
199 return xasprintf ("%s: not found", name);
202 char *error = spv_table_look_read (file, lookp);
207 const struct pivot_table_look *
208 pivot_table_look_builtin_default (void)
210 static struct pivot_table_look look = {
214 .row_labels_in_corner = true,
216 [TABLE_HORZ] = { 36, 72 },
217 [TABLE_VERT] = { 36, 120 },
221 #define AREA(BOLD, H, V, L, R, T, B) { \
223 .halign = TABLE_HALIGN_##H, \
224 .valign = TABLE_VALIGN_##V, \
225 .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
226 [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
230 .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
231 .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
233 .typeface = (char *) "Sans Serif", \
236 [PIVOT_AREA_TITLE] = AREA(true, CENTER, CENTER, 8,11,1,8),
237 [PIVOT_AREA_CAPTION] = AREA(false, LEFT, TOP, 8,11,1,1),
238 [PIVOT_AREA_FOOTER] = AREA(false, LEFT, TOP, 11, 8,2,3),
239 [PIVOT_AREA_CORNER] = AREA(false, LEFT, BOTTOM, 8,11,1,1),
240 [PIVOT_AREA_COLUMN_LABELS] = AREA(false, CENTER, BOTTOM, 8,11,1,3),
241 [PIVOT_AREA_ROW_LABELS] = AREA(false, LEFT, TOP, 8,11,1,3),
242 [PIVOT_AREA_DATA] = AREA(false, MIXED, TOP, 8,11,1,1),
243 [PIVOT_AREA_LAYERS] = AREA(false, LEFT, BOTTOM, 8,11,1,3),
248 #define BORDER(STROKE) { .stroke = STROKE, .color = CELL_COLOR_BLACK }
249 [PIVOT_BORDER_TITLE] = BORDER(TABLE_STROKE_NONE),
250 [PIVOT_BORDER_OUTER_LEFT] = BORDER(TABLE_STROKE_NONE),
251 [PIVOT_BORDER_OUTER_TOP] = BORDER(TABLE_STROKE_NONE),
252 [PIVOT_BORDER_OUTER_RIGHT] = BORDER(TABLE_STROKE_NONE),
253 [PIVOT_BORDER_OUTER_BOTTOM] = BORDER(TABLE_STROKE_NONE),
254 [PIVOT_BORDER_INNER_LEFT] = BORDER(TABLE_STROKE_THICK),
255 [PIVOT_BORDER_INNER_TOP] = BORDER(TABLE_STROKE_THICK),
256 [PIVOT_BORDER_INNER_RIGHT] = BORDER(TABLE_STROKE_THICK),
257 [PIVOT_BORDER_INNER_BOTTOM] = BORDER(TABLE_STROKE_THICK),
258 [PIVOT_BORDER_DATA_LEFT] = BORDER(TABLE_STROKE_THICK),
259 [PIVOT_BORDER_DATA_TOP] = BORDER(TABLE_STROKE_THICK),
260 [PIVOT_BORDER_DIM_ROW_HORZ] = BORDER(TABLE_STROKE_SOLID),
261 [PIVOT_BORDER_DIM_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
262 [PIVOT_BORDER_DIM_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
263 [PIVOT_BORDER_DIM_COL_VERT] = BORDER(TABLE_STROKE_SOLID),
264 [PIVOT_BORDER_CAT_ROW_HORZ] = BORDER(TABLE_STROKE_NONE),
265 [PIVOT_BORDER_CAT_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
266 [PIVOT_BORDER_CAT_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
267 [PIVOT_BORDER_CAT_COL_VERT] = BORDER(TABLE_STROKE_SOLID),
274 struct pivot_table_look *
275 pivot_table_look_new_builtin_default (void)
277 return pivot_table_look_unshare (
278 pivot_table_look_ref (pivot_table_look_builtin_default ()));
281 struct pivot_table_look *
282 pivot_table_look_ref (const struct pivot_table_look *look_)
284 assert (look_->ref_cnt > 0);
286 struct pivot_table_look *look = CONST_CAST (struct pivot_table_look *, look_);
292 xstrdup_if_nonempty (const char *s)
294 return s && s[0] ? xstrdup (s) : NULL;
297 struct pivot_table_look *
298 pivot_table_look_unshare (struct pivot_table_look *old)
300 assert (old->ref_cnt > 0);
301 if (old->ref_cnt == 1)
304 pivot_table_look_unref (old);
306 struct pivot_table_look *new = xmemdup (old, sizeof *old);
308 new->name = xstrdup_if_nonempty (old->name);
309 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
310 table_area_style_copy (NULL, &new->areas[i], &old->areas[i]);
311 new->continuation = xstrdup_if_nonempty (old->continuation);
317 pivot_table_look_unref (struct pivot_table_look *look)
321 assert (look->ref_cnt > 0);
322 if (!--look->ref_cnt)
325 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
326 table_area_style_uninit (&look->areas[i]);
327 free (look->continuation);
335 /* Returns the name of AXIS_TYPE. */
337 pivot_axis_type_to_string (enum pivot_axis_type axis_type)
341 case PIVOT_AXIS_LAYER:
347 case PIVOT_AXIS_COLUMN:
355 static enum pivot_axis_type
356 pivot_axis_type_transpose (enum pivot_axis_type axis_type)
358 assert (axis_type == PIVOT_AXIS_ROW || axis_type == PIVOT_AXIS_COLUMN);
359 return (axis_type == PIVOT_AXIS_ROW ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW);
362 /* Implementation of PIVOT_AXIS_FOR_EACH. */
364 pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis)
368 if (axis->n_dimensions)
369 for (size_t i = 0; i < axis->n_dimensions; i++)
370 if (axis->dimensions[i]->n_leaves == 0)
373 size_t size = axis->n_dimensions * sizeof *indexes;
374 return xzalloc (MAX (size, 1));
377 for (size_t i = 0; i < axis->n_dimensions; i++)
379 const struct pivot_dimension *d = axis->dimensions[i];
380 if (++indexes[i] < d->n_leaves)
393 pivot_category_set_rc (struct pivot_category *category, const char *s)
395 const struct fmt_spec *format = pivot_table_get_format (
396 category->dimension->table, s);
398 category->format = *format;
402 pivot_category_create_leaves_valist (struct pivot_category *parent,
406 while ((s = va_arg (args, const char *)))
408 if (!strncmp (s, "RC_", 3))
410 assert (parent->n_subs);
411 pivot_category_set_rc (parent->subs[parent->n_subs - 1], s);
414 pivot_category_create_leaf (parent, pivot_value_new_text (s));
418 /* Creates a new dimension with the given NAME in TABLE and returns it. The
419 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
422 NAME should be a translatable name, but not actually translated yet,
423 e.g. enclosed in N_(). To use a different kind of value for a name, use
424 pivot_dimension_create__() instead.
426 The optional varargs parameters may be used to add an initial set of
427 categories to the dimension. Each string should be a translatable category
428 name, but not actually translated yet, e.g. enclosed in N_(). Each string
429 may optionally be followod by a PIVOT_RC_* string that specifies the default
430 numeric format for cells in this category. */
431 struct pivot_dimension * SENTINEL (0)
432 (pivot_dimension_create) (struct pivot_table *table,
433 enum pivot_axis_type axis_type,
434 const char *name, ...)
436 struct pivot_dimension *d = pivot_dimension_create__ (
437 table, axis_type, pivot_value_new_text (name));
440 va_start (args, name);
441 pivot_category_create_leaves_valist (d->root, args);
447 /* Creates a new dimension with the given NAME in TABLE and returns it. The
448 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
450 struct pivot_dimension *
451 pivot_dimension_create__ (struct pivot_table *table,
452 enum pivot_axis_type axis_type,
453 struct pivot_value *name)
455 assert (pivot_table_is_empty (table));
457 struct pivot_dimension *d = xmalloc (sizeof *d);
458 *d = (struct pivot_dimension) {
460 .axis_type = axis_type,
461 .level = table->axes[axis_type].n_dimensions,
462 .top_index = table->n_dimensions,
463 .root = xmalloc (sizeof *d->root),
466 struct pivot_category *root = d->root;
467 *root = (struct pivot_category) {
472 .data_index = SIZE_MAX,
473 .presentation_index = SIZE_MAX,
476 table->dimensions = xrealloc (
477 table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions);
478 table->dimensions[table->n_dimensions++] = d;
480 struct pivot_axis *axis = &table->axes[axis_type];
481 axis->dimensions = xrealloc (
482 axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
483 axis->dimensions[axis->n_dimensions++] = d;
485 if (axis_type == PIVOT_AXIS_LAYER)
487 free (table->current_layer);
488 table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
489 sizeof *table->current_layer);
492 /* axis->extent and axis->label_depth will be calculated later. */
498 pivot_dimension_destroy (struct pivot_dimension *d)
503 pivot_category_destroy (d->root);
504 free (d->data_leaves);
505 free (d->presentation_leaves);
509 /* Returns the first leaf node in an in-order traversal that is a child of
511 static const struct pivot_category * UNUSED
512 pivot_category_first_leaf (const struct pivot_category *cat)
514 if (pivot_category_is_leaf (cat))
517 for (size_t i = 0; i < cat->n_subs; i++)
519 const struct pivot_category *first
520 = pivot_category_first_leaf (cat->subs[i]);
528 /* Returns the next leaf node in an in-order traversal starting at CAT, which
530 static const struct pivot_category * UNUSED
531 pivot_category_next_leaf (const struct pivot_category *cat)
533 assert (pivot_category_is_leaf (cat));
537 const struct pivot_category *parent = cat->parent;
540 for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
542 const struct pivot_category *next
543 = pivot_category_first_leaf (parent->subs[i]);
553 pivot_category_add_child (struct pivot_category *child)
555 struct pivot_category *parent = child->parent;
557 assert (pivot_category_is_group (parent));
558 if (parent->n_subs >= parent->allocated_subs)
559 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
560 sizeof *parent->subs);
561 parent->subs[parent->n_subs++] = child;
564 /* Adds leaf categories as a child of PARENT. To create top-level categories
565 within dimension 'd', pass 'd->root' for PARENT.
567 Each of the varargs parameters should be a string, each of which should be a
568 translatable category name, but not actually translated yet, e.g. enclosed
569 in N_(). Each string may optionally be followod by a PIVOT_RC_* string that
570 specifies the default numeric format for cells in this category.
572 Returns the category index, which is just a 0-based array index, for the
575 Leaves have to be created in in-order, that is, don't create a group and add
576 some leaves, then add leaves outside the group and try to add more leaves
579 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
581 int retval = parent->dimension->n_leaves;
584 va_start (args, parent);
585 pivot_category_create_leaves_valist (parent, args);
591 /* Creates a new leaf category with the given NAME as a child of PARENT. To
592 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
593 Returns the category index, which is just a 0-based array index, for the new
596 Leaves have to be created in in-order, that is, don't create a group and add
597 some leaves, then add leaves outside the group and try to add more leaves
600 pivot_category_create_leaf (struct pivot_category *parent,
601 struct pivot_value *name)
603 return pivot_category_create_leaf_rc (parent, name, NULL);
606 /* Creates a new leaf category with the given NAME as a child of PARENT. To
607 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
608 Returns the category index, which is just a 0-based array index, for the new
611 If RC is nonnull and the name of a result category, the category is assigned
612 that result category.
614 Leaves have to be created in in-order, that is, don't create a group and add
615 some leaves, then add leaves outside the group and try to add more leaves
618 pivot_category_create_leaf_rc (struct pivot_category *parent,
619 struct pivot_value *name, const char *rc)
621 struct pivot_dimension *d = parent->dimension;
623 struct pivot_category *leaf = xmalloc (sizeof *leaf);
624 *leaf = (struct pivot_category) {
628 .group_index = parent->n_subs,
629 .data_index = d->n_leaves,
630 .presentation_index = d->n_leaves,
633 if (d->n_leaves >= d->allocated_leaves)
635 d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
636 sizeof *d->data_leaves);
637 d->presentation_leaves = xrealloc (
638 d->presentation_leaves,
639 d->allocated_leaves * sizeof *d->presentation_leaves);
642 d->data_leaves[d->n_leaves] = leaf;
643 d->presentation_leaves[d->n_leaves] = leaf;
646 pivot_category_add_child (leaf);
648 /* Make sure that the new child is the last in in-order. */
649 assert (!pivot_category_next_leaf (leaf));
651 pivot_category_set_rc (leaf, rc);
653 return leaf->data_index;
656 /* Adds a new category group named NAME as a child of PARENT. To create a
657 top-level group within dimension 'd', pass 'd->root' for PARENT.
659 NAME should be a translatable name, but not actually translated yet,
660 e.g. enclosed in N_(). To use a different kind of value for a name, use
661 pivot_category_create_group__() instead.
663 The optional varargs parameters may be used to add an initial set of
664 categories to the group. Each string should be a translatable category
665 name, but not actually translated yet, e.g. enclosed in N_(). Each string
666 may optionally be followod by a PIVOT_RC_* string that specifies the default
667 numeric format for cells in this category.
669 Returns the new group. */
670 struct pivot_category * SENTINEL (0)
671 (pivot_category_create_group) (struct pivot_category *parent,
672 const char *name, ...)
674 struct pivot_category *group = pivot_category_create_group__ (
675 parent, pivot_value_new_text (name));
678 va_start (args, name);
679 pivot_category_create_leaves_valist (group, args);
685 /* Adds a new category group named NAME as a child of PARENT. To create a
686 top-level group within dimension 'd', pass 'd->root' for PARENT. Returns
688 struct pivot_category *
689 pivot_category_create_group__ (struct pivot_category *parent,
690 struct pivot_value *name)
692 struct pivot_dimension *d = parent->dimension;
694 struct pivot_category *group = xmalloc (sizeof *group);
695 *group = (struct pivot_category) {
700 .group_index = parent->n_subs,
701 .data_index = SIZE_MAX,
702 .presentation_index = SIZE_MAX,
705 pivot_category_add_child (group);
711 pivot_category_destroy (struct pivot_category *c)
716 pivot_value_destroy (c->name);
717 for (size_t i = 0; i < c->n_subs; i++)
718 pivot_category_destroy (c->subs[i]);
725 These are usually the easiest way to control the formatting of numeric data
726 in a pivot table. See pivot_dimension_create() for an explanation of their
730 const char *name; /* "RC_*". */
731 struct fmt_spec format;
734 /* Formats for most of the result classes. */
735 static struct result_class result_classes[] =
737 { PIVOT_RC_INTEGER, { FMT_F, 40, 0 } },
738 { PIVOT_RC_PERCENT, { FMT_PCT, 40, 1 } },
739 { PIVOT_RC_CORRELATION, { FMT_F, 40, 3 } },
740 { PIVOT_RC_SIGNIFICANCE, { FMT_F, 40, 3 } },
741 { PIVOT_RC_RESIDUAL, { FMT_F, 40, 2 } },
742 { PIVOT_RC_COUNT, { 0, 0, 0 } },
743 { PIVOT_RC_OTHER, { 0, 0, 0 } },
746 /* Has PIVOT_RC_COUNT been overridden by the user? */
747 static bool overridden_count_format;
749 static struct result_class *
750 pivot_result_class_find (const char *s)
752 for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
753 if (!strcmp (s, result_classes[i].name))
754 return &result_classes[i];
758 static const struct fmt_spec *
759 pivot_table_get_format (const struct pivot_table *table, const char *s)
763 else if (!strcmp (s, PIVOT_RC_OTHER))
764 return settings_get_format ();
765 else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
766 return &table->weight_format;
769 const struct result_class *rc = pivot_result_class_find (s);
770 return rc ? &rc->format : NULL;
774 /* Sets the format specification for the result class named S (which should not
775 include the RC_ prefix) to *FORMAT. Returns true if successful, false if S
776 does not name a known result class. */
778 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
780 char *s = xasprintf ("RC_%s", s_);
781 struct result_class *rc = pivot_result_class_find (s);
784 rc->format = *format;
785 if (!strcmp (s, PIVOT_RC_COUNT))
786 overridden_count_format = true;
795 /* Creates and returns a new pivot table with the given TITLE. TITLE should be
796 a text string marked for translation but not actually translated yet,
797 e.g. N_("Descriptive Statistics"). The un-translated text string is used as
798 the pivot table's subtype.
800 This function is a shortcut for pivot_table_create__() for the most common
801 case. Use pivot_table_create__() directly if the title should be some kind
802 of value other than an ordinary text string, or if the subtype should be
803 different from the title.
805 See the large comment at the top of pivot-table.h for general advice on
806 creating pivot tables. */
808 pivot_table_create (const char *title)
810 return pivot_table_create__ (pivot_value_new_text (title), title);
813 /* Creates and returns a new pivot table with the given TITLE, and takes
814 ownership of TITLE. The new pivot table's subtype is SUBTYPE, which should
815 be an untranslated English string that describes the contents of the table
816 at a high level without being specific about the variables or other context
819 TITLE and SUBTYPE may be NULL, but in that case the client must add them
820 later because they are both mandatory for a pivot table.
822 See the large comment at the top of pivot-table.h for general advice on
823 creating pivot tables. */
825 pivot_table_create__ (struct pivot_value *title, const char *subtype)
827 struct pivot_table *table = xzalloc (sizeof *table);
829 table->show_title = true;
830 table->show_caption = true;
831 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
832 table->title = title;
833 table->subtype = subtype ? pivot_value_new_text (subtype) : NULL;
834 table->command_c = output_get_command_name ();
835 table->look = pivot_table_look_ref (pivot_table_look_get_default ());
837 hmap_init (&table->cells);
842 /* Creates and returns a new pivot table with the given TITLE and a single cell
843 with the given CONTENT.
845 This is really just for error handling. */
847 pivot_table_create_for_text (struct pivot_value *title,
848 struct pivot_value *content)
850 struct pivot_table *table = pivot_table_create__ (title, "Error");
852 struct pivot_dimension *d = pivot_dimension_create (
853 table, PIVOT_AXIS_ROW, N_("Error"));
854 d->hide_all_labels = true;
855 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
857 pivot_table_put1 (table, 0, content);
862 /* Increases TABLE's reference count, indicating that it has an additional
863 owner. A pivot table that is shared among multiple owners must not be
866 pivot_table_ref (const struct pivot_table *table_)
868 struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
873 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
874 If TABLE no longer has any owners, it is freed. */
876 pivot_table_unref (struct pivot_table *table)
880 assert (table->ref_cnt > 0);
881 if (--table->ref_cnt)
884 free (table->current_layer);
885 pivot_table_look_unref (table->look);
887 for (int i = 0; i < TABLE_N_AXES; i++)
888 pivot_table_sizing_uninit (&table->sizing[i]);
890 for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
891 free (table->ccs[i]);
893 free (table->command_local);
894 free (table->command_c);
895 free (table->language);
896 free (table->locale);
898 free (table->dataset);
899 free (table->datafile);
901 for (size_t i = 0; i < table->n_footnotes; i++)
902 pivot_footnote_destroy (table->footnotes[i]);
903 free (table->footnotes);
905 pivot_value_destroy (table->title);
906 pivot_value_destroy (table->subtype);
907 pivot_value_destroy (table->corner_text);
908 pivot_value_destroy (table->caption);
911 for (size_t i = 0; i < table->n_dimensions; i++)
912 pivot_dimension_destroy (table->dimensions[i]);
913 free (table->dimensions);
915 for (size_t i = 0; i < PIVOT_N_AXES; i++)
916 free (table->axes[i].dimensions);
918 struct pivot_cell *cell, *next_cell;
919 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
922 hmap_delete (&table->cells, &cell->hmap_node);
923 pivot_value_destroy (cell->value);
926 hmap_destroy (&table->cells);
931 /* Returns true if TABLE has more than one owner. A pivot table that is shared
932 among multiple owners must not be modified. */
934 pivot_table_is_shared (const struct pivot_table *table)
936 return table->ref_cnt > 1;
939 const struct pivot_table_look *
940 pivot_table_get_look (const struct pivot_table *table)
946 pivot_table_set_look (struct pivot_table *table,
947 const struct pivot_table_look *look)
949 pivot_table_look_unref (table->look);
950 table->look = pivot_table_look_ref (look);
953 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
954 WV, which should be the weight variable for the dictionary whose data or
955 statistics are being put into TABLE.
957 This has no effect if WV is NULL. */
959 pivot_table_set_weight_var (struct pivot_table *table,
960 const struct variable *wv)
963 pivot_table_set_weight_format (table, var_get_print_format (wv));
966 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
967 format for the dictionary whose data or statistics are being put into TABLE.
969 This has no effect if WFMT is NULL. */
971 pivot_table_set_weight_format (struct pivot_table *table,
972 const struct fmt_spec *wfmt)
975 table->weight_format = *wfmt;
978 /* Returns true if TABLE has no cells, false otherwise. */
980 pivot_table_is_empty (const struct pivot_table *table)
982 return hmap_is_empty (&table->cells);
986 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
988 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
992 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
994 for (size_t i = 0; i < n; i++)
1001 static struct pivot_cell *
1002 pivot_table_lookup_cell__ (const struct pivot_table *table,
1003 const size_t *dindexes, unsigned int hash)
1005 struct pivot_cell *cell;
1006 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
1008 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
1013 static struct pivot_cell *
1014 pivot_cell_allocate (size_t n_idx)
1016 struct pivot_cell *cell UNUSED;
1017 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
1020 static struct pivot_cell *
1021 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
1023 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1024 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
1027 cell = pivot_cell_allocate (table->n_dimensions);
1028 for (size_t i = 0; i < table->n_dimensions; i++)
1029 cell->idx[i] = dindexes[i];
1031 hmap_insert (&table->cells, &cell->hmap_node, hash);
1036 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
1037 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
1040 If VALUE is a numeric value without a specified format, this function checks
1041 each of the categories designated by DINDEXES[] and takes the format from
1042 the first category with a result class. If none has a result class, uses
1043 the overall default numeric format. */
1045 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
1046 struct pivot_value *value)
1048 assert (n == table->n_dimensions);
1049 for (size_t i = 0; i < n; i++)
1050 assert (dindexes[i] < table->dimensions[i]->n_leaves);
1052 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
1054 for (size_t i = 0; i < table->n_dimensions; i++)
1056 const struct pivot_dimension *d = table->dimensions[i];
1057 if (dindexes[i] < d->n_leaves)
1059 const struct pivot_category *c = d->data_leaves[dindexes[i]];
1062 value->numeric.format = c->format;
1067 value->numeric.format = *settings_get_format ();
1072 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1073 pivot_value_destroy (cell->value);
1074 cell->value = value;
1077 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
1078 dimension. Takes ownership of VALUE. */
1080 pivot_table_put1 (struct pivot_table *table, size_t idx1,
1081 struct pivot_value *value)
1083 size_t dindexes[] = { idx1 };
1084 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1087 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
1088 dimensions. Takes ownership of VALUE. */
1090 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
1091 struct pivot_value *value)
1093 size_t dindexes[] = { idx1, idx2 };
1094 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1097 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
1098 have 3 dimensions. Takes ownership of VALUE. */
1100 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
1101 size_t idx3, struct pivot_value *value)
1103 size_t dindexes[] = { idx1, idx2, idx3 };
1104 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1107 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
1108 must have 4 dimensions. Takes ownership of VALUE. */
1110 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1111 size_t idx3, size_t idx4, struct pivot_value *value)
1113 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1114 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1117 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1118 automatically assigned marker.
1120 The footnote will only appear in output if it is referenced. Use
1121 pivot_value_add_footnote() to add a reference to the footnote. */
1122 struct pivot_footnote *
1123 pivot_table_create_footnote (struct pivot_table *table,
1124 struct pivot_value *content)
1126 return pivot_table_create_footnote__ (table, table->n_footnotes,
1130 static struct pivot_value *
1131 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1133 char text[INT_BUFSIZE_BOUND (size_t)];
1134 if (show_numeric_markers)
1135 snprintf (text, sizeof text, "%d", idx + 1);
1137 str_format_26adic (idx + 1, false, text, sizeof text);
1138 return pivot_value_new_user_text (text, -1);
1141 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1142 all lower indexes as a side effect). If MARKER is nonnull, sets the
1143 footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1144 struct pivot_footnote *
1145 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1146 struct pivot_value *marker,
1147 struct pivot_value *content)
1149 if (idx >= table->n_footnotes)
1151 while (idx >= table->allocated_footnotes)
1152 table->footnotes = x2nrealloc (table->footnotes,
1153 &table->allocated_footnotes,
1154 sizeof *table->footnotes);
1155 while (idx >= table->n_footnotes)
1157 struct pivot_footnote *f = xmalloc (sizeof *f);
1158 f->idx = table->n_footnotes;
1159 f->marker = pivot_make_default_footnote_marker (
1160 f->idx, table->look->show_numeric_markers);
1164 table->footnotes[table->n_footnotes++] = f;
1168 struct pivot_footnote *f = table->footnotes[idx];
1171 pivot_value_destroy (f->marker);
1176 pivot_value_destroy (f->content);
1177 f->content = content;
1182 /* Frees the data owned by F. */
1184 pivot_footnote_destroy (struct pivot_footnote *f)
1188 pivot_value_destroy (f->content);
1189 pivot_value_destroy (f->marker);
1194 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1195 indexes for each dimension in TABLE in DINDEXES[]. */
1197 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1198 const size_t *pindexes[PIVOT_N_AXES],
1199 size_t dindexes[/* table->n_dimensions */])
1201 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1203 const struct pivot_axis *axis = &table->axes[i];
1205 for (size_t j = 0; j < axis->n_dimensions; j++)
1207 const struct pivot_dimension *d = axis->dimensions[j];
1208 dindexes[d->top_index]
1209 = d->presentation_leaves[pindexes[i][j]]->data_index;
1215 pivot_table_enumerate_axis (const struct pivot_table *table,
1216 enum pivot_axis_type axis_type,
1217 const size_t *layer_indexes, bool omit_empty,
1220 const struct pivot_axis *axis = &table->axes[axis_type];
1221 if (!axis->n_dimensions)
1223 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1225 enumeration[1] = SIZE_MAX;
1230 else if (!axis->extent)
1232 size_t *enumeration = xmalloc (sizeof *enumeration);
1233 *enumeration = SIZE_MAX;
1239 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1240 axis->n_dimensions), 1),
1241 sizeof *enumeration);
1242 size_t *p = enumeration;
1243 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1245 size_t *axis_indexes;
1246 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1250 enum pivot_axis_type axis2_type
1251 = pivot_axis_type_transpose (axis_type);
1253 size_t *axis2_indexes;
1254 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1256 const size_t *pindexes[PIVOT_N_AXES];
1257 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1258 pindexes[axis_type] = axis_indexes;
1259 pindexes[axis2_type] = axis2_indexes;
1260 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1261 if (pivot_table_get (table, dindexes))
1267 free (axis2_indexes);
1270 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1271 p += axis->n_dimensions;
1273 if (omit_empty && p == enumeration)
1275 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1277 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1278 p += axis->n_dimensions;
1283 *n = (p - enumeration) / axis->n_dimensions;
1289 static const struct pivot_cell *
1290 pivot_table_lookup_cell (const struct pivot_table *table,
1291 const size_t *dindexes)
1293 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1294 return pivot_table_lookup_cell__ (table, dindexes, hash);
1297 const struct pivot_value *
1298 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1300 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1301 return cell ? cell->value : NULL;
1304 struct pivot_value *
1305 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1307 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1309 cell->value = pivot_value_new_user_text ("", -1);
1314 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1316 if (pivot_category_is_group (category) && category->n_subs)
1317 for (size_t i = 0; i < category->n_subs; i++)
1318 distribute_extra_depth (category->subs[i], extra_depth);
1320 category->extra_depth += extra_depth;
1324 pivot_category_assign_label_depth (struct pivot_category *category,
1325 bool dimension_labels_in_corner)
1327 category->extra_depth = 0;
1329 if (pivot_category_is_group (category))
1332 for (size_t i = 0; i < category->n_subs; i++)
1334 pivot_category_assign_label_depth (category->subs[i], false);
1335 depth = MAX (depth, category->subs[i]->label_depth);
1338 for (size_t i = 0; i < category->n_subs; i++)
1340 struct pivot_category *sub = category->subs[i];
1342 size_t extra_depth = depth - sub->label_depth;
1344 distribute_extra_depth (sub, extra_depth);
1346 sub->label_depth = depth;
1349 category->show_label_in_corner = (category->show_label
1350 && dimension_labels_in_corner);
1351 category->label_depth
1352 = (category->show_label && !category->show_label_in_corner
1353 ? depth + 1 : depth);
1356 category->label_depth = 1;
1360 pivot_axis_assign_label_depth (struct pivot_table *table,
1361 enum pivot_axis_type axis_type,
1362 bool dimension_labels_in_corner)
1364 struct pivot_axis *axis = &table->axes[axis_type];
1365 bool any_label_shown_in_corner = false;
1366 axis->label_depth = 0;
1368 for (size_t i = 0; i < axis->n_dimensions; i++)
1370 struct pivot_dimension *d = axis->dimensions[i];
1371 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1372 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1373 axis->label_depth += d->label_depth;
1374 axis->extent *= d->n_leaves;
1376 if (d->root->show_label_in_corner)
1377 any_label_shown_in_corner = true;
1379 return any_label_shown_in_corner;
1383 pivot_table_assign_label_depth (struct pivot_table *table)
1385 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1386 if (pivot_axis_assign_label_depth (
1387 table, PIVOT_AXIS_ROW, (table->look->row_labels_in_corner
1388 && !table->corner_text))
1389 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1390 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1391 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1395 indent (int indentation)
1397 for (int i = 0; i < indentation * 2; i++)
1402 pivot_value_dump (const struct pivot_value *value)
1404 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1405 SETTINGS_VALUE_SHOW_DEFAULT);
1411 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1416 indent (indentation);
1417 printf ("%s: ", name);
1418 pivot_value_dump (value);
1424 pivot_table_dump_string (const char *string, const char *name, int indentation)
1428 indent (indentation);
1429 printf ("%s: %s\n", name, string);
1434 pivot_category_dump (const struct pivot_category *c, int indentation)
1436 indent (indentation);
1437 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1438 pivot_value_dump (c->name);
1441 if (pivot_category_is_leaf (c))
1442 printf ("data_index=%zu\n", c->data_index);
1445 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1448 for (size_t i = 0; i < c->n_subs; i++)
1449 pivot_category_dump (c->subs[i], indentation + 1);
1454 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1456 indent (indentation);
1457 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1458 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1460 pivot_category_dump (d->root, indentation + 1);
1464 table_area_style_dump (enum pivot_area area, const struct table_area_style *a,
1467 indent (indentation);
1468 printf ("%s: ", pivot_area_to_string (area));
1469 font_style_dump (&a->font_style);
1471 cell_style_dump (&a->cell_style);
1476 table_border_style_dump (enum pivot_border border,
1477 const struct table_border_style *b, int indentation)
1479 indent (indentation);
1480 printf ("%s: %s ", pivot_border_to_string (border),
1481 table_stroke_to_string (b->stroke));
1482 cell_color_dump (&b->color);
1487 compose_headings (const struct pivot_axis *axis,
1488 const size_t *column_enumeration,
1489 enum settings_value_show show_values,
1490 enum settings_value_show show_variables)
1492 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1495 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1496 for (size_t i = 0; i < axis->label_depth; i++)
1497 headings[i] = xcalloc (axis->extent, sizeof **headings);
1499 const size_t *indexes;
1501 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1503 int row = axis->label_depth - 1;
1504 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1506 const struct pivot_dimension *d = axis->dimensions[dim_index];
1507 if (d->hide_all_labels)
1509 for (const struct pivot_category *c
1510 = d->presentation_leaves[indexes[dim_index]];
1514 if (pivot_category_is_leaf (c) || (c->show_label
1515 && !c->show_label_in_corner))
1517 headings[row][column] = pivot_value_to_string (
1518 c->name, show_values, show_variables);
1519 if (!*headings[row][column])
1520 headings[row][column] = xstrdup ("<blank>");
1532 free_headings (const struct pivot_axis *axis, char ***headings)
1534 for (size_t i = 0; i < axis->label_depth; i++)
1536 for (size_t j = 0; j < axis->extent; j++)
1537 free (headings[i][j]);
1544 pivot_table_sizing_dump (const char *name,
1545 const int width_ranges[2],
1546 const struct pivot_table_sizing *s,
1549 indent (indentation);
1550 printf ("%ss: min=%d, max=%d\n", name, width_ranges[0], width_ranges[1]);
1553 indent (indentation + 1);
1554 printf ("%s widths:", name);
1555 for (size_t i = 0; i < s->n_widths; i++)
1556 printf (" %d", s->widths[i]);
1561 indent (indentation + 1);
1562 printf ("break after %ss:", name);
1563 for (size_t i = 0; i < s->n_breaks; i++)
1564 printf (" %zu", s->breaks[i]);
1569 indent (indentation + 1);
1570 printf ("keep %ss together:", name);
1571 for (size_t i = 0; i < s->n_keeps; i++)
1572 printf (" [%zu,%zu]",
1574 s->keeps[i].ofs + s->keeps[i].n - 1);
1580 pivot_table_dump (const struct pivot_table *table, int indentation)
1585 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1586 if (table->decimal == '.' || table->decimal == ',')
1587 settings_set_decimal_char (table->decimal);
1589 pivot_table_dump_value (table->title, "title", indentation);
1590 pivot_table_dump_value (table->subtype, "subtype", indentation);
1591 pivot_table_dump_string (table->command_c, "command", indentation);
1592 pivot_table_dump_string (table->dataset, "dataset", indentation);
1593 pivot_table_dump_string (table->datafile, "datafile", indentation);
1594 pivot_table_dump_string (table->notes, "notes", indentation);
1595 pivot_table_dump_string (table->look->name, "table-look", indentation);
1598 indent (indentation);
1600 struct tm *tm = localtime (&table->date);
1601 printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
1602 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
1606 indent (indentation);
1607 printf ("sizing:\n");
1608 pivot_table_sizing_dump ("column", table->look->width_ranges[TABLE_HORZ],
1609 &table->sizing[TABLE_HORZ], indentation + 1);
1610 pivot_table_sizing_dump ("row", table->look->width_ranges[TABLE_VERT],
1611 &table->sizing[TABLE_VERT], indentation + 1);
1613 indent (indentation);
1614 printf ("areas:\n");
1615 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1616 table_area_style_dump (area, &table->look->areas[area], indentation + 1);
1618 indent (indentation);
1619 printf ("borders:\n");
1620 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1621 table_border_style_dump (border, &table->look->borders[border],
1624 for (size_t i = 0; i < table->n_dimensions; i++)
1625 pivot_dimension_dump (table->dimensions[i], indentation);
1627 /* Presentation and data indexes. */
1628 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1630 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1631 if (layer_axis->n_dimensions)
1633 indent (indentation);
1634 printf ("current layer:");
1636 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1638 const struct pivot_dimension *d = layer_axis->dimensions[i];
1639 char *name = pivot_value_to_string (d->root->name,
1641 table->show_variables);
1642 char *value = pivot_value_to_string (
1643 d->data_leaves[table->current_layer[i]]->name,
1644 table->show_values, table->show_variables);
1645 printf (" %s=%s", name, value);
1653 size_t *layer_indexes;
1654 size_t layer_iteration = 0;
1655 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1657 indent (indentation);
1658 printf ("layer %zu:", layer_iteration++);
1660 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1661 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1663 const struct pivot_dimension *d = layer_axis->dimensions[i];
1665 fputs (i == 0 ? " " : ", ", stdout);
1666 pivot_value_dump (d->root->name);
1667 fputs (" =", stdout);
1669 struct pivot_value **names = xnmalloc (d->n_leaves, sizeof *names);
1671 for (const struct pivot_category *c
1672 = d->presentation_leaves[layer_indexes[i]];
1676 if (pivot_category_is_leaf (c) || c->show_label)
1677 names[n_names++] = c->name;
1680 for (size_t i = n_names; i-- > 0;)
1683 pivot_value_dump (names[i]);
1689 size_t *column_enumeration = pivot_table_enumerate_axis (
1690 table, PIVOT_AXIS_COLUMN, layer_indexes, table->look->omit_empty, NULL);
1691 size_t *row_enumeration = pivot_table_enumerate_axis (
1692 table, PIVOT_AXIS_ROW, layer_indexes, table->look->omit_empty, NULL);
1694 char ***column_headings = compose_headings (
1695 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1696 table->show_values, table->show_variables);
1697 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1699 indent (indentation + 1);
1700 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1703 fputs ("; ", stdout);
1704 if (column_headings[y][x])
1705 fputs (column_headings[y][x], stdout);
1709 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1711 indent (indentation + 1);
1712 printf ("-----------------------------------------------\n");
1714 char ***row_headings = compose_headings (
1715 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1716 table->show_values, table->show_variables);
1719 const size_t *pindexes[PIVOT_N_AXES]
1720 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1721 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1722 &table->axes[PIVOT_AXIS_ROW])
1724 indent (indentation + 1);
1727 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1730 fputs ("; ", stdout);
1731 if (row_headings[y][x])
1732 fputs (row_headings[y][x], stdout);
1738 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1740 &table->axes[PIVOT_AXIS_COLUMN])
1745 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1746 const struct pivot_value *value = pivot_table_get (
1749 pivot_value_dump (value);
1756 free (column_enumeration);
1757 free (row_enumeration);
1758 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1761 pivot_table_dump_value (table->caption, "caption", indentation);
1763 for (size_t i = 0; i < table->n_footnotes; i++)
1765 const struct pivot_footnote *f = table->footnotes[i];
1766 indent (indentation);
1769 pivot_value_dump (f->marker);
1771 printf ("%zu", f->idx);
1773 pivot_value_dump (f->content);
1778 settings_set_decimal_char (old_decimal);
1782 consume_int (const char *p, size_t *n)
1785 while (c_isdigit (*p))
1786 *n = *n * 10 + (*p++ - '0');
1791 pivot_format_inner_template (struct string *out, const char *template,
1793 struct pivot_value **values, size_t n_values,
1794 enum settings_value_show show_values,
1795 enum settings_value_show show_variables)
1797 size_t args_consumed = 0;
1798 while (*template && *template != ':')
1800 if (*template == '\\' && template[1])
1802 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1805 else if (*template == escape)
1808 template = consume_int (template + 1, &index);
1809 if (index >= 1 && index <= n_values)
1811 pivot_value_format (values[index - 1], show_values,
1812 show_variables, out);
1813 args_consumed = MAX (args_consumed, index);
1817 ds_put_byte (out, *template++);
1819 return args_consumed;
1823 pivot_extract_inner_template (const char *template, const char **p)
1829 if (*template == '\\' && template[1] != '\0')
1831 else if (*template == ':')
1832 return template + 1;
1833 else if (*template == '\0')
1841 pivot_format_template (struct string *out, const char *template,
1842 const struct pivot_argument *args, size_t n_args,
1843 enum settings_value_show show_values,
1844 enum settings_value_show show_variables)
1848 if (*template == '\\' && template[1] != '\0')
1850 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1853 else if (*template == '^')
1856 template = consume_int (template + 1, &index);
1857 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1858 pivot_value_format (args[index - 1].values[0],
1859 show_values, show_variables, out);
1861 else if (*template == '[')
1863 const char *tmpl[2];
1864 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1865 template = pivot_extract_inner_template (template, &tmpl[1]);
1866 template += *template == ']';
1869 template = consume_int (template, &index);
1870 if (index < 1 || index > n_args)
1873 const struct pivot_argument *arg = &args[index - 1];
1874 size_t left = arg->n;
1877 struct pivot_value **values = arg->values + (arg->n - left);
1878 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1879 char escape = "%^"[tmpl_idx];
1880 size_t used = pivot_format_inner_template (
1881 out, tmpl[tmpl_idx], escape, values, left,
1882 show_values, show_variables);
1883 if (!used || used > left)
1889 ds_put_byte (out, *template++);
1893 static enum settings_value_show
1894 interpret_show (enum settings_value_show global_show,
1895 enum settings_value_show table_show,
1896 enum settings_value_show value_show,
1899 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1900 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1901 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1905 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1906 SHOW_VARIABLES control whether variable and value labels are included.
1908 The "body" omits subscripts and superscripts and footnotes.
1910 Returns true if OUT is a number (or a number plus a value label), false
1913 pivot_value_format_body (const struct pivot_value *value,
1914 enum settings_value_show show_values,
1915 enum settings_value_show show_variables,
1918 enum settings_value_show show;
1919 bool numeric = false;
1921 switch (value->type)
1923 case PIVOT_VALUE_NUMERIC:
1924 show = interpret_show (settings_get_show_values (),
1926 value->numeric.show,
1927 value->numeric.value_label != NULL);
1928 if (show & SETTINGS_VALUE_SHOW_VALUE)
1930 char *s = data_out (&(union value) { .f = value->numeric.x },
1931 "UTF-8", &value->numeric.format);
1932 ds_put_cstr (out, s + strspn (s, " "));
1935 if (show & SETTINGS_VALUE_SHOW_LABEL)
1937 if (show & SETTINGS_VALUE_SHOW_VALUE)
1938 ds_put_byte (out, ' ');
1939 ds_put_cstr (out, value->numeric.value_label);
1941 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1944 case PIVOT_VALUE_STRING:
1945 show = interpret_show (settings_get_show_values (),
1948 value->string.value_label != NULL);
1949 if (show & SETTINGS_VALUE_SHOW_VALUE)
1951 if (value->string.hex)
1953 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1955 ds_put_format (out, "%02X", *p);
1958 ds_put_cstr (out, value->string.s);
1960 if (show & SETTINGS_VALUE_SHOW_LABEL)
1962 if (show & SETTINGS_VALUE_SHOW_VALUE)
1963 ds_put_byte (out, ' ');
1964 ds_put_cstr (out, value->string.value_label);
1968 case PIVOT_VALUE_VARIABLE:
1969 show = interpret_show (settings_get_show_variables (),
1971 value->variable.show,
1972 value->variable.var_label != NULL);
1973 if (show & SETTINGS_VALUE_SHOW_VALUE)
1974 ds_put_cstr (out, value->variable.var_name);
1975 if (show & SETTINGS_VALUE_SHOW_LABEL)
1977 if (show & SETTINGS_VALUE_SHOW_VALUE)
1978 ds_put_byte (out, ' ');
1979 ds_put_cstr (out, value->variable.var_label);
1983 case PIVOT_VALUE_TEXT:
1984 ds_put_cstr (out, value->text.local);
1987 case PIVOT_VALUE_TEMPLATE:
1988 pivot_format_template (out, value->template.local, value->template.args,
1989 value->template.n_args, show_values,
1997 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
1998 SHOW_VARIABLES control whether variable and value labels are included.
2000 Subscripts and footnotes are included. */
2002 pivot_value_format (const struct pivot_value *value,
2003 enum settings_value_show show_values,
2004 enum settings_value_show show_variables,
2007 pivot_value_format_body (value, show_values, show_variables, out);
2009 if (value->n_subscripts)
2011 for (size_t i = 0; i < value->n_subscripts; i++)
2012 ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
2015 for (size_t i = 0; i < value->n_footnotes; i++)
2017 ds_put_byte (out, '^');
2018 pivot_value_format (value->footnotes[i]->marker,
2019 show_values, show_variables, out);
2023 /* Returns a text representation of VALUE. The caller must free the string,
2026 pivot_value_to_string (const struct pivot_value *value,
2027 enum settings_value_show show_values,
2028 enum settings_value_show show_variables)
2030 struct string s = DS_EMPTY_INITIALIZER;
2031 pivot_value_format (value, show_values, show_variables, &s);
2032 return ds_steal_cstr (&s);
2035 /* Frees the data owned by V. */
2037 pivot_value_destroy (struct pivot_value *value)
2041 font_style_uninit (value->font_style);
2042 free (value->font_style);
2043 free (value->cell_style);
2044 /* Do not free the elements of footnotes because VALUE does not own
2046 free (value->footnotes);
2048 for (size_t i = 0; i < value->n_subscripts; i++)
2049 free (value->subscripts[i]);
2050 free (value->subscripts);
2052 switch (value->type)
2054 case PIVOT_VALUE_NUMERIC:
2055 free (value->numeric.var_name);
2056 free (value->numeric.value_label);
2059 case PIVOT_VALUE_STRING:
2060 free (value->string.s);
2061 free (value->string.var_name);
2062 free (value->string.value_label);
2065 case PIVOT_VALUE_VARIABLE:
2066 free (value->variable.var_name);
2067 free (value->variable.var_label);
2070 case PIVOT_VALUE_TEXT:
2071 free (value->text.local);
2072 if (value->text.c != value->text.local)
2073 free (value->text.c);
2074 if (value->text.id != value->text.local
2075 && value->text.id != value->text.c)
2076 free (value->text.id);
2079 case PIVOT_VALUE_TEMPLATE:
2080 free (value->template.local);
2081 if (value->template.id != value->template.local)
2082 free (value->template.id);
2083 for (size_t i = 0; i < value->template.n_args; i++)
2084 pivot_argument_uninit (&value->template.args[i]);
2085 free (value->template.args);
2092 /* Sets AREA to the style to use for VALUE, with defaults coming from
2093 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
2095 pivot_value_get_style (struct pivot_value *value,
2096 const struct font_style *base_font_style,
2097 const struct cell_style *base_cell_style,
2098 struct table_area_style *area)
2100 font_style_copy (NULL, &area->font_style, (value->font_style
2102 : base_font_style));
2103 area->cell_style = *(value->cell_style
2108 /* Copies AREA into VALUE's style. */
2110 pivot_value_set_style (struct pivot_value *value,
2111 const struct table_area_style *area)
2113 if (value->font_style)
2114 font_style_uninit (value->font_style);
2116 value->font_style = xmalloc (sizeof *value->font_style);
2117 font_style_copy (NULL, value->font_style, &area->font_style);
2119 if (!value->cell_style)
2120 value->cell_style = xmalloc (sizeof *value->cell_style);
2121 *value->cell_style = area->cell_style;
2124 /* Frees the data owned by ARG (but not ARG itself). */
2126 pivot_argument_uninit (struct pivot_argument *arg)
2130 for (size_t i = 0; i < arg->n; i++)
2131 pivot_value_destroy (arg->values[i]);
2136 /* Creates and returns a new pivot_value whose contents is the null-terminated
2137 string TEXT. Takes ownership of TEXT.
2139 This function is for text strings provided by the user (with the exception
2140 that pivot_value_new_variable() should be used for variable names). For
2141 strings that are part of the PSPP user interface, such as names of
2142 procedures, statistics, annotations, error messages, etc., use
2143 pivot_value_new_text(). */
2144 struct pivot_value *
2145 pivot_value_new_user_text_nocopy (char *text)
2147 struct pivot_value *value = xmalloc (sizeof *value);
2148 *value = (struct pivot_value) {
2149 .type = PIVOT_VALUE_TEXT,
2154 .user_provided = true,
2160 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2161 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2164 This function is for text strings provided by the user (with the exception
2165 that pivot_value_new_variable() should be used for variable names). For
2166 strings that are part of the PSPP user interface, such as names of
2167 procedures, statistics, annotations, error messages, etc., use
2168 pivot_value_new_text().j
2170 The caller retains ownership of TEXT.*/
2171 struct pivot_value *
2172 pivot_value_new_user_text (const char *text, size_t length)
2174 return pivot_value_new_user_text_nocopy (
2175 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2178 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2179 a translatable string, but not actually translated yet, e.g. enclosed in
2180 N_(). This function is for text strings that are part of the PSPP user
2181 interface, such as names of procedures, statistics, annotations, error
2182 messages, etc. For strings that come from the user, use
2183 pivot_value_new_user_text(). */
2184 struct pivot_value *
2185 pivot_value_new_text (const char *text)
2187 char *c = xstrdup (text);
2188 char *local = xstrdup (gettext (c));
2190 struct pivot_value *value = xmalloc (sizeof *value);
2191 *value = (struct pivot_value) {
2192 .type = PIVOT_VALUE_TEXT,
2197 .user_provided = false,
2203 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2205 struct pivot_value * PRINTF_FORMAT (1, 2)
2206 pivot_value_new_text_format (const char *format, ...)
2209 va_start (args, format);
2210 char *c = xvasprintf (format, args);
2213 va_start (args, format);
2214 char *local = xvasprintf (gettext (format), args);
2217 struct pivot_value *value = xmalloc (sizeof *value);
2218 *value = (struct pivot_value) {
2219 .type = PIVOT_VALUE_TEXT,
2224 .user_provided = false,
2230 /* Returns a new pivot_value that represents X.
2232 The format to use for X is unspecified. Usually the easiest way to specify
2233 a format is through assigning a result class to one of the categories that
2234 the pivot_value will end up in. If that is not suitable, then the caller
2235 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2236 struct pivot_value *
2237 pivot_value_new_number (double x)
2239 struct pivot_value *value = xmalloc (sizeof *value);
2240 *value = (struct pivot_value) {
2241 .type = PIVOT_VALUE_NUMERIC,
2242 .numeric = { .x = x, },
2247 /* Returns a new pivot_value that represents X, formatted as an integer. */
2248 struct pivot_value *
2249 pivot_value_new_integer (double x)
2251 struct pivot_value *value = pivot_value_new_number (x);
2252 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2256 /* Returns a new pivot_value that represents VALUE, formatted as for
2258 struct pivot_value *
2259 pivot_value_new_var_value (const struct variable *variable,
2260 const union value *value)
2262 struct pivot_value *pv = pivot_value_new_value (
2263 value, var_get_width (variable), var_get_print_format (variable),
2264 var_get_encoding (variable));
2266 char *var_name = xstrdup (var_get_name (variable));
2267 if (var_is_alpha (variable))
2268 pv->string.var_name = var_name;
2270 pv->numeric.var_name = var_name;
2272 const char *label = var_lookup_value_label (variable, value);
2275 if (var_is_alpha (variable))
2276 pv->string.value_label = xstrdup (label);
2278 pv->numeric.value_label = xstrdup (label);
2284 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2285 formatted with FORMAT. For a string value, ENCODING must be its character
2287 struct pivot_value *
2288 pivot_value_new_value (const union value *value, int width,
2289 const struct fmt_spec *format, const char *encoding)
2291 struct pivot_value *pv = xzalloc (sizeof *pv);
2294 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2296 size_t n = strlen (s);
2297 while (n > 0 && s[n - 1] == ' ')
2300 pv->type = PIVOT_VALUE_STRING;
2302 pv->string.hex = format->type == FMT_AHEX;
2306 pv->type = PIVOT_VALUE_NUMERIC;
2307 pv->numeric.x = value->f;
2308 pv->numeric.format = *format;
2314 /* Returns a new pivot_value for VARIABLE. */
2315 struct pivot_value *
2316 pivot_value_new_variable (const struct variable *variable)
2318 struct pivot_value *value = xmalloc (sizeof *value);
2319 *value = (struct pivot_value) {
2320 .type = PIVOT_VALUE_VARIABLE,
2322 .var_name = xstrdup (var_get_name (variable)),
2323 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2329 /* Attaches a reference to FOOTNOTE to V. */
2331 pivot_value_add_footnote (struct pivot_value *v,
2332 const struct pivot_footnote *footnote)
2334 /* Some legacy tables include numerous duplicate footnotes. Suppress
2336 for (size_t i = 0; i < v->n_footnotes; i++)
2337 if (v->footnotes[i] == footnote)
2340 v->footnotes = xrealloc (v->footnotes,
2341 (v->n_footnotes + 1) * sizeof *v->footnotes);
2342 v->footnotes[v->n_footnotes++] = footnote;
2345 /* If VALUE is a numeric value, and RC is a result class such as
2346 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2348 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2351 if (value->type == PIVOT_VALUE_NUMERIC)
2353 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2355 value->numeric.format = *f;