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 return xcalloc (axis->n_dimensions, sizeof *indexes);
376 for (size_t i = 0; i < axis->n_dimensions; i++)
378 const struct pivot_dimension *d = axis->dimensions[i];
379 if (++indexes[i] < d->n_leaves)
392 pivot_category_set_rc (struct pivot_category *category, const char *s)
394 const struct fmt_spec *format = pivot_table_get_format (
395 category->dimension->table, s);
397 category->format = *format;
401 pivot_category_create_leaves_valist (struct pivot_category *parent,
405 while ((s = va_arg (args, const char *)))
407 if (!strncmp (s, "RC_", 3))
409 assert (parent->n_subs);
410 pivot_category_set_rc (parent->subs[parent->n_subs - 1], s);
413 pivot_category_create_leaf (parent, pivot_value_new_text (s));
417 /* Creates a new dimension with the given NAME in TABLE and returns it. The
418 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
421 NAME should be a translatable name, but not actually translated yet,
422 e.g. enclosed in N_(). To use a different kind of value for a name, use
423 pivot_dimension_create__() instead.
425 The optional varargs parameters may be used to add an initial set of
426 categories to the dimension. Each string should be a translatable category
427 name, but not actually translated yet, e.g. enclosed in N_(). Each string
428 may optionally be followod by a PIVOT_RC_* string that specifies the default
429 numeric format for cells in this category. */
430 struct pivot_dimension * SENTINEL (0)
431 (pivot_dimension_create) (struct pivot_table *table,
432 enum pivot_axis_type axis_type,
433 const char *name, ...)
435 struct pivot_dimension *d = pivot_dimension_create__ (
436 table, axis_type, pivot_value_new_text (name));
439 va_start (args, name);
440 pivot_category_create_leaves_valist (d->root, args);
446 /* Creates a new dimension with the given NAME in TABLE and returns it. The
447 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
449 struct pivot_dimension *
450 pivot_dimension_create__ (struct pivot_table *table,
451 enum pivot_axis_type axis_type,
452 struct pivot_value *name)
454 assert (pivot_table_is_empty (table));
456 struct pivot_dimension *d = xmalloc (sizeof *d);
457 *d = (struct pivot_dimension) {
459 .axis_type = axis_type,
460 .level = table->axes[axis_type].n_dimensions,
461 .top_index = table->n_dimensions,
462 .root = xmalloc (sizeof *d->root),
465 struct pivot_category *root = d->root;
466 *root = (struct pivot_category) {
471 .data_index = SIZE_MAX,
472 .presentation_index = SIZE_MAX,
475 table->dimensions = xrealloc (
476 table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions);
477 table->dimensions[table->n_dimensions++] = d;
479 struct pivot_axis *axis = &table->axes[axis_type];
480 axis->dimensions = xrealloc (
481 axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
482 axis->dimensions[axis->n_dimensions++] = d;
484 if (axis_type == PIVOT_AXIS_LAYER)
486 free (table->current_layer);
487 table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
488 sizeof *table->current_layer);
491 /* axis->extent and axis->label_depth will be calculated later. */
497 pivot_dimension_destroy (struct pivot_dimension *d)
502 pivot_category_destroy (d->root);
503 free (d->data_leaves);
504 free (d->presentation_leaves);
508 /* Returns the first leaf node in an in-order traversal that is a child of
510 static const struct pivot_category * UNUSED
511 pivot_category_first_leaf (const struct pivot_category *cat)
513 if (pivot_category_is_leaf (cat))
516 for (size_t i = 0; i < cat->n_subs; i++)
518 const struct pivot_category *first
519 = pivot_category_first_leaf (cat->subs[i]);
527 /* Returns the next leaf node in an in-order traversal starting at CAT, which
529 static const struct pivot_category * UNUSED
530 pivot_category_next_leaf (const struct pivot_category *cat)
532 assert (pivot_category_is_leaf (cat));
536 const struct pivot_category *parent = cat->parent;
539 for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
541 const struct pivot_category *next
542 = pivot_category_first_leaf (parent->subs[i]);
552 pivot_category_add_child (struct pivot_category *child)
554 struct pivot_category *parent = child->parent;
556 assert (pivot_category_is_group (parent));
557 if (parent->n_subs >= parent->allocated_subs)
558 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
559 sizeof *parent->subs);
560 parent->subs[parent->n_subs++] = child;
563 /* Adds leaf categories as a child of PARENT. To create top-level categories
564 within dimension 'd', pass 'd->root' for PARENT.
566 Each of the varargs parameters should be a string, each of which should be a
567 translatable category name, but not actually translated yet, e.g. enclosed
568 in N_(). Each string may optionally be followod by a PIVOT_RC_* string that
569 specifies the default numeric format for cells in this category.
571 Returns the category index, which is just a 0-based array index, for the
574 Leaves have to be created in in-order, that is, don't create a group and add
575 some leaves, then add leaves outside the group and try to add more leaves
578 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
580 int retval = parent->dimension->n_leaves;
583 va_start (args, parent);
584 pivot_category_create_leaves_valist (parent, args);
590 /* Creates a new leaf category with the given NAME as a child of PARENT. To
591 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
592 Returns the category index, which is just a 0-based array index, for the new
595 Leaves have to be created in in-order, that is, don't create a group and add
596 some leaves, then add leaves outside the group and try to add more leaves
599 pivot_category_create_leaf (struct pivot_category *parent,
600 struct pivot_value *name)
602 return pivot_category_create_leaf_rc (parent, name, NULL);
605 /* Creates a new leaf category with the given NAME as a child of PARENT. To
606 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
607 Returns the category index, which is just a 0-based array index, for the new
610 If RC is nonnull and the name of a result category, the category is assigned
611 that result category.
613 Leaves have to be created in in-order, that is, don't create a group and add
614 some leaves, then add leaves outside the group and try to add more leaves
617 pivot_category_create_leaf_rc (struct pivot_category *parent,
618 struct pivot_value *name, const char *rc)
620 struct pivot_dimension *d = parent->dimension;
622 struct pivot_category *leaf = xmalloc (sizeof *leaf);
623 *leaf = (struct pivot_category) {
627 .group_index = parent->n_subs,
628 .data_index = d->n_leaves,
629 .presentation_index = d->n_leaves,
632 if (d->n_leaves >= d->allocated_leaves)
634 d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
635 sizeof *d->data_leaves);
636 d->presentation_leaves = xrealloc (
637 d->presentation_leaves,
638 d->allocated_leaves * sizeof *d->presentation_leaves);
641 d->data_leaves[d->n_leaves] = leaf;
642 d->presentation_leaves[d->n_leaves] = leaf;
645 pivot_category_add_child (leaf);
647 /* Make sure that the new child is the last in in-order. */
648 assert (!pivot_category_next_leaf (leaf));
650 pivot_category_set_rc (leaf, rc);
652 return leaf->data_index;
655 /* Adds a new category group named NAME as a child of PARENT. To create a
656 top-level group within dimension 'd', pass 'd->root' for PARENT.
658 NAME should be a translatable name, but not actually translated yet,
659 e.g. enclosed in N_(). To use a different kind of value for a name, use
660 pivot_category_create_group__() instead.
662 The optional varargs parameters may be used to add an initial set of
663 categories to the group. Each string should be a translatable category
664 name, but not actually translated yet, e.g. enclosed in N_(). Each string
665 may optionally be followod by a PIVOT_RC_* string that specifies the default
666 numeric format for cells in this category.
668 Returns the new group. */
669 struct pivot_category * SENTINEL (0)
670 (pivot_category_create_group) (struct pivot_category *parent,
671 const char *name, ...)
673 struct pivot_category *group = pivot_category_create_group__ (
674 parent, pivot_value_new_text (name));
677 va_start (args, name);
678 pivot_category_create_leaves_valist (group, args);
684 /* Adds a new category group named NAME as a child of PARENT. To create a
685 top-level group within dimension 'd', pass 'd->root' for PARENT. Returns
687 struct pivot_category *
688 pivot_category_create_group__ (struct pivot_category *parent,
689 struct pivot_value *name)
691 struct pivot_dimension *d = parent->dimension;
693 struct pivot_category *group = xmalloc (sizeof *group);
694 *group = (struct pivot_category) {
699 .group_index = parent->n_subs,
700 .data_index = SIZE_MAX,
701 .presentation_index = SIZE_MAX,
704 pivot_category_add_child (group);
710 pivot_category_destroy (struct pivot_category *c)
715 pivot_value_destroy (c->name);
716 for (size_t i = 0; i < c->n_subs; i++)
717 pivot_category_destroy (c->subs[i]);
724 These are usually the easiest way to control the formatting of numeric data
725 in a pivot table. See pivot_dimension_create() for an explanation of their
729 const char *name; /* "RC_*". */
730 struct fmt_spec format;
733 /* Formats for most of the result classes. */
734 static struct result_class result_classes[] =
736 { PIVOT_RC_INTEGER, { FMT_F, 40, 0 } },
737 { PIVOT_RC_PERCENT, { FMT_PCT, 40, 1 } },
738 { PIVOT_RC_CORRELATION, { FMT_F, 40, 3 } },
739 { PIVOT_RC_SIGNIFICANCE, { FMT_F, 40, 3 } },
740 { PIVOT_RC_RESIDUAL, { FMT_F, 40, 2 } },
741 { PIVOT_RC_COUNT, { 0, 0, 0 } },
742 { PIVOT_RC_OTHER, { 0, 0, 0 } },
745 /* Has PIVOT_RC_COUNT been overridden by the user? */
746 static bool overridden_count_format;
748 static struct result_class *
749 pivot_result_class_find (const char *s)
751 for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
752 if (!strcmp (s, result_classes[i].name))
753 return &result_classes[i];
757 static const struct fmt_spec *
758 pivot_table_get_format (const struct pivot_table *table, const char *s)
762 else if (!strcmp (s, PIVOT_RC_OTHER))
763 return settings_get_format ();
764 else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
765 return &table->weight_format;
768 const struct result_class *rc = pivot_result_class_find (s);
769 return rc ? &rc->format : NULL;
773 /* Sets the format specification for the result class named S (which should not
774 include the RC_ prefix) to *FORMAT. Returns true if successful, false if S
775 does not name a known result class. */
777 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
779 char *s = xasprintf ("RC_%s", s_);
780 struct result_class *rc = pivot_result_class_find (s);
783 rc->format = *format;
784 if (!strcmp (s, PIVOT_RC_COUNT))
785 overridden_count_format = true;
794 /* Creates and returns a new pivot table with the given TITLE. TITLE should be
795 a text string marked for translation but not actually translated yet,
796 e.g. N_("Descriptive Statistics"). The un-translated text string is used as
797 the pivot table's subtype.
799 This function is a shortcut for pivot_table_create__() for the most common
800 case. Use pivot_table_create__() directly if the title should be some kind
801 of value other than an ordinary text string, or if the subtype should be
802 different from the title.
804 See the large comment at the top of pivot-table.h for general advice on
805 creating pivot tables. */
807 pivot_table_create (const char *title)
809 return pivot_table_create__ (pivot_value_new_text (title), title);
812 /* Creates and returns a new pivot table with the given TITLE, and takes
813 ownership of TITLE. The new pivot table's subtype is SUBTYPE, which should
814 be an untranslated English string that describes the contents of the table
815 at a high level without being specific about the variables or other context
818 TITLE and SUBTYPE may be NULL, but in that case the client must add them
819 later because they are both mandatory for a pivot table.
821 See the large comment at the top of pivot-table.h for general advice on
822 creating pivot tables. */
824 pivot_table_create__ (struct pivot_value *title, const char *subtype)
826 struct pivot_table *table = xzalloc (sizeof *table);
828 table->show_title = true;
829 table->show_caption = true;
830 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
831 table->title = title;
832 table->subtype = subtype ? pivot_value_new_text (subtype) : NULL;
833 table->command_c = output_get_command_name ();
834 table->look = pivot_table_look_ref (pivot_table_look_get_default ());
836 hmap_init (&table->cells);
841 /* Creates and returns a new pivot table with the given TITLE and a single cell
842 with the given CONTENT.
844 This is really just for error handling. */
846 pivot_table_create_for_text (struct pivot_value *title,
847 struct pivot_value *content)
849 struct pivot_table *table = pivot_table_create__ (title, "Error");
851 struct pivot_dimension *d = pivot_dimension_create (
852 table, PIVOT_AXIS_ROW, N_("Error"));
853 d->hide_all_labels = true;
854 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
856 pivot_table_put1 (table, 0, content);
861 /* Increases TABLE's reference count, indicating that it has an additional
862 owner. A pivot table that is shared among multiple owners must not be
865 pivot_table_ref (const struct pivot_table *table_)
867 struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
872 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
873 If TABLE no longer has any owners, it is freed. */
875 pivot_table_unref (struct pivot_table *table)
879 assert (table->ref_cnt > 0);
880 if (--table->ref_cnt)
883 free (table->current_layer);
884 pivot_table_look_unref (table->look);
886 for (int i = 0; i < TABLE_N_AXES; i++)
887 pivot_table_sizing_uninit (&table->sizing[i]);
889 for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
890 free (table->ccs[i]);
892 free (table->command_local);
893 free (table->command_c);
894 free (table->language);
895 free (table->locale);
897 free (table->dataset);
898 free (table->datafile);
900 for (size_t i = 0; i < table->n_footnotes; i++)
901 pivot_footnote_destroy (table->footnotes[i]);
902 free (table->footnotes);
904 pivot_value_destroy (table->title);
905 pivot_value_destroy (table->subtype);
906 pivot_value_destroy (table->corner_text);
907 pivot_value_destroy (table->caption);
910 for (size_t i = 0; i < table->n_dimensions; i++)
911 pivot_dimension_destroy (table->dimensions[i]);
912 free (table->dimensions);
914 for (size_t i = 0; i < PIVOT_N_AXES; i++)
915 free (table->axes[i].dimensions);
917 struct pivot_cell *cell, *next_cell;
918 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
921 hmap_delete (&table->cells, &cell->hmap_node);
922 pivot_value_destroy (cell->value);
925 hmap_destroy (&table->cells);
930 /* Returns true if TABLE has more than one owner. A pivot table that is shared
931 among multiple owners must not be modified. */
933 pivot_table_is_shared (const struct pivot_table *table)
935 return table->ref_cnt > 1;
938 const struct pivot_table_look *
939 pivot_table_get_look (const struct pivot_table *table)
945 pivot_table_set_look (struct pivot_table *table,
946 const struct pivot_table_look *look)
948 pivot_table_look_unref (table->look);
949 table->look = pivot_table_look_ref (look);
952 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
953 WV, which should be the weight variable for the dictionary whose data or
954 statistics are being put into TABLE.
956 This has no effect if WV is NULL. */
958 pivot_table_set_weight_var (struct pivot_table *table,
959 const struct variable *wv)
962 pivot_table_set_weight_format (table, var_get_print_format (wv));
965 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
966 format for the dictionary whose data or statistics are being put into TABLE.
968 This has no effect if WFMT is NULL. */
970 pivot_table_set_weight_format (struct pivot_table *table,
971 const struct fmt_spec *wfmt)
974 table->weight_format = *wfmt;
977 /* Returns true if TABLE has no cells, false otherwise. */
979 pivot_table_is_empty (const struct pivot_table *table)
981 return hmap_is_empty (&table->cells);
985 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
987 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
991 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
993 for (size_t i = 0; i < n; i++)
1000 static struct pivot_cell *
1001 pivot_table_lookup_cell__ (const struct pivot_table *table,
1002 const size_t *dindexes, unsigned int hash)
1004 struct pivot_cell *cell;
1005 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
1007 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
1012 static struct pivot_cell *
1013 pivot_cell_allocate (size_t n_idx)
1015 struct pivot_cell *cell UNUSED;
1016 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
1019 static struct pivot_cell *
1020 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
1022 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1023 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
1026 cell = pivot_cell_allocate (table->n_dimensions);
1027 for (size_t i = 0; i < table->n_dimensions; i++)
1028 cell->idx[i] = dindexes[i];
1030 hmap_insert (&table->cells, &cell->hmap_node, hash);
1035 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
1036 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
1039 If VALUE is a numeric value without a specified format, this function checks
1040 each of the categories designated by DINDEXES[] and takes the format from
1041 the first category with a result class. If none has a result class, uses
1042 the overall default numeric format. */
1044 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
1045 struct pivot_value *value)
1047 assert (n == table->n_dimensions);
1048 for (size_t i = 0; i < n; i++)
1049 assert (dindexes[i] < table->dimensions[i]->n_leaves);
1051 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
1053 for (size_t i = 0; i < table->n_dimensions; i++)
1055 const struct pivot_dimension *d = table->dimensions[i];
1056 if (dindexes[i] < d->n_leaves)
1058 const struct pivot_category *c = d->data_leaves[dindexes[i]];
1061 value->numeric.format = c->format;
1066 value->numeric.format = *settings_get_format ();
1071 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1072 pivot_value_destroy (cell->value);
1073 cell->value = value;
1076 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
1077 dimension. Takes ownership of VALUE. */
1079 pivot_table_put1 (struct pivot_table *table, size_t idx1,
1080 struct pivot_value *value)
1082 size_t dindexes[] = { idx1 };
1083 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1086 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
1087 dimensions. Takes ownership of VALUE. */
1089 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
1090 struct pivot_value *value)
1092 size_t dindexes[] = { idx1, idx2 };
1093 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1096 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
1097 have 3 dimensions. Takes ownership of VALUE. */
1099 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
1100 size_t idx3, struct pivot_value *value)
1102 size_t dindexes[] = { idx1, idx2, idx3 };
1103 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1106 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
1107 must have 4 dimensions. Takes ownership of VALUE. */
1109 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1110 size_t idx3, size_t idx4, struct pivot_value *value)
1112 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1113 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1116 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1117 automatically assigned marker.
1119 The footnote will only appear in output if it is referenced. Use
1120 pivot_value_add_footnote() to add a reference to the footnote. */
1121 struct pivot_footnote *
1122 pivot_table_create_footnote (struct pivot_table *table,
1123 struct pivot_value *content)
1125 return pivot_table_create_footnote__ (table, table->n_footnotes,
1129 static struct pivot_value *
1130 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1132 char text[INT_BUFSIZE_BOUND (size_t)];
1133 if (show_numeric_markers)
1134 snprintf (text, sizeof text, "%d", idx + 1);
1136 str_format_26adic (idx + 1, false, text, sizeof text);
1137 return pivot_value_new_user_text (text, -1);
1140 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1141 all lower indexes as a side effect). If MARKER is nonnull, sets the
1142 footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1143 struct pivot_footnote *
1144 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1145 struct pivot_value *marker,
1146 struct pivot_value *content)
1148 if (idx >= table->n_footnotes)
1150 while (idx >= table->allocated_footnotes)
1151 table->footnotes = x2nrealloc (table->footnotes,
1152 &table->allocated_footnotes,
1153 sizeof *table->footnotes);
1154 while (idx >= table->n_footnotes)
1156 struct pivot_footnote *f = xmalloc (sizeof *f);
1157 f->idx = table->n_footnotes;
1158 f->marker = pivot_make_default_footnote_marker (
1159 f->idx, table->look->show_numeric_markers);
1163 table->footnotes[table->n_footnotes++] = f;
1167 struct pivot_footnote *f = table->footnotes[idx];
1170 pivot_value_destroy (f->marker);
1175 pivot_value_destroy (f->content);
1176 f->content = content;
1181 /* Frees the data owned by F. */
1183 pivot_footnote_destroy (struct pivot_footnote *f)
1187 pivot_value_destroy (f->content);
1188 pivot_value_destroy (f->marker);
1193 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1194 indexes for each dimension in TABLE in DINDEXES[]. */
1196 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1197 const size_t *pindexes[PIVOT_N_AXES],
1198 size_t dindexes[/* table->n_dimensions */])
1200 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1202 const struct pivot_axis *axis = &table->axes[i];
1204 for (size_t j = 0; j < axis->n_dimensions; j++)
1206 const struct pivot_dimension *d = axis->dimensions[j];
1207 dindexes[d->top_index]
1208 = d->presentation_leaves[pindexes[i][j]]->data_index;
1214 pivot_table_enumerate_axis (const struct pivot_table *table,
1215 enum pivot_axis_type axis_type,
1216 const size_t *layer_indexes, bool omit_empty,
1219 const struct pivot_axis *axis = &table->axes[axis_type];
1220 if (!axis->n_dimensions)
1222 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1224 enumeration[1] = SIZE_MAX;
1229 else if (!axis->extent)
1231 size_t *enumeration = xmalloc (sizeof *enumeration);
1232 *enumeration = SIZE_MAX;
1238 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1239 axis->n_dimensions), 1),
1240 sizeof *enumeration);
1241 size_t *p = enumeration;
1242 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1244 size_t *axis_indexes;
1245 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1249 enum pivot_axis_type axis2_type
1250 = pivot_axis_type_transpose (axis_type);
1252 size_t *axis2_indexes;
1253 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1255 const size_t *pindexes[PIVOT_N_AXES];
1256 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1257 pindexes[axis_type] = axis_indexes;
1258 pindexes[axis2_type] = axis2_indexes;
1259 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1260 if (pivot_table_get (table, dindexes))
1266 free (axis2_indexes);
1269 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1270 p += axis->n_dimensions;
1272 if (omit_empty && p == enumeration)
1274 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1276 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1277 p += axis->n_dimensions;
1282 *n = (p - enumeration) / axis->n_dimensions;
1288 static const struct pivot_cell *
1289 pivot_table_lookup_cell (const struct pivot_table *table,
1290 const size_t *dindexes)
1292 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1293 return pivot_table_lookup_cell__ (table, dindexes, hash);
1296 const struct pivot_value *
1297 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1299 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1300 return cell ? cell->value : NULL;
1303 struct pivot_value *
1304 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1306 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1308 cell->value = pivot_value_new_user_text ("", -1);
1313 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1315 if (pivot_category_is_group (category) && category->n_subs)
1316 for (size_t i = 0; i < category->n_subs; i++)
1317 distribute_extra_depth (category->subs[i], extra_depth);
1319 category->extra_depth += extra_depth;
1323 pivot_category_assign_label_depth (struct pivot_category *category,
1324 bool dimension_labels_in_corner)
1326 category->extra_depth = 0;
1328 if (pivot_category_is_group (category))
1331 for (size_t i = 0; i < category->n_subs; i++)
1333 pivot_category_assign_label_depth (category->subs[i], false);
1334 depth = MAX (depth, category->subs[i]->label_depth);
1337 for (size_t i = 0; i < category->n_subs; i++)
1339 struct pivot_category *sub = category->subs[i];
1341 size_t extra_depth = depth - sub->label_depth;
1343 distribute_extra_depth (sub, extra_depth);
1345 sub->label_depth = depth;
1348 category->show_label_in_corner = (category->show_label
1349 && dimension_labels_in_corner);
1350 category->label_depth
1351 = (category->show_label && !category->show_label_in_corner
1352 ? depth + 1 : depth);
1355 category->label_depth = 1;
1359 pivot_axis_assign_label_depth (struct pivot_table *table,
1360 enum pivot_axis_type axis_type,
1361 bool dimension_labels_in_corner)
1363 struct pivot_axis *axis = &table->axes[axis_type];
1364 bool any_label_shown_in_corner = false;
1365 axis->label_depth = 0;
1367 for (size_t i = 0; i < axis->n_dimensions; i++)
1369 struct pivot_dimension *d = axis->dimensions[i];
1370 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1371 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1372 axis->label_depth += d->label_depth;
1373 axis->extent *= d->n_leaves;
1375 if (d->root->show_label_in_corner)
1376 any_label_shown_in_corner = true;
1378 return any_label_shown_in_corner;
1382 pivot_table_assign_label_depth (struct pivot_table *table)
1384 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1385 if (pivot_axis_assign_label_depth (
1386 table, PIVOT_AXIS_ROW, (table->look->row_labels_in_corner
1387 && !table->corner_text))
1388 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1389 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1390 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1394 indent (int indentation)
1396 for (int i = 0; i < indentation * 2; i++)
1401 pivot_value_dump (const struct pivot_value *value)
1403 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1404 SETTINGS_VALUE_SHOW_DEFAULT);
1410 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1415 indent (indentation);
1416 printf ("%s: ", name);
1417 pivot_value_dump (value);
1423 pivot_table_dump_string (const char *string, const char *name, int indentation)
1427 indent (indentation);
1428 printf ("%s: %s\n", name, string);
1433 pivot_category_dump (const struct pivot_category *c, int indentation)
1435 indent (indentation);
1436 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1437 pivot_value_dump (c->name);
1440 if (pivot_category_is_leaf (c))
1441 printf ("data_index=%zu\n", c->data_index);
1444 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1447 for (size_t i = 0; i < c->n_subs; i++)
1448 pivot_category_dump (c->subs[i], indentation + 1);
1453 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1455 indent (indentation);
1456 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1457 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1459 pivot_category_dump (d->root, indentation + 1);
1463 table_area_style_dump (enum pivot_area area, const struct table_area_style *a,
1466 indent (indentation);
1467 printf ("%s: ", pivot_area_to_string (area));
1468 font_style_dump (&a->font_style);
1470 cell_style_dump (&a->cell_style);
1475 table_border_style_dump (enum pivot_border border,
1476 const struct table_border_style *b, int indentation)
1478 indent (indentation);
1479 printf ("%s: %s ", pivot_border_to_string (border),
1480 table_stroke_to_string (b->stroke));
1481 cell_color_dump (&b->color);
1486 compose_headings (const struct pivot_axis *axis,
1487 const size_t *column_enumeration,
1488 enum settings_value_show show_values,
1489 enum settings_value_show show_variables)
1491 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1494 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1495 for (size_t i = 0; i < axis->label_depth; i++)
1496 headings[i] = xcalloc (axis->extent, sizeof **headings);
1498 const size_t *indexes;
1500 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1502 int row = axis->label_depth - 1;
1503 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1505 const struct pivot_dimension *d = axis->dimensions[dim_index];
1506 if (d->hide_all_labels)
1508 for (const struct pivot_category *c
1509 = d->presentation_leaves[indexes[dim_index]];
1513 if (pivot_category_is_leaf (c) || (c->show_label
1514 && !c->show_label_in_corner))
1516 headings[row][column] = pivot_value_to_string (
1517 c->name, show_values, show_variables);
1518 if (!*headings[row][column])
1519 headings[row][column] = xstrdup ("<blank>");
1531 free_headings (const struct pivot_axis *axis, char ***headings)
1533 for (size_t i = 0; i < axis->label_depth; i++)
1535 for (size_t j = 0; j < axis->extent; j++)
1536 free (headings[i][j]);
1543 pivot_table_sizing_dump (const char *name,
1544 const int width_ranges[2],
1545 const struct pivot_table_sizing *s,
1548 indent (indentation);
1549 printf ("%ss: min=%d, max=%d\n", name, width_ranges[0], width_ranges[1]);
1552 indent (indentation + 1);
1553 printf ("%s widths:", name);
1554 for (size_t i = 0; i < s->n_widths; i++)
1555 printf (" %d", s->widths[i]);
1560 indent (indentation + 1);
1561 printf ("break after %ss:", name);
1562 for (size_t i = 0; i < s->n_breaks; i++)
1563 printf (" %zu", s->breaks[i]);
1568 indent (indentation + 1);
1569 printf ("keep %ss together:", name);
1570 for (size_t i = 0; i < s->n_keeps; i++)
1571 printf (" [%zu,%zu]",
1573 s->keeps[i].ofs + s->keeps[i].n - 1);
1579 pivot_table_dump (const struct pivot_table *table, int indentation)
1584 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1585 if (table->decimal == '.' || table->decimal == ',')
1586 settings_set_decimal_char (table->decimal);
1588 pivot_table_dump_value (table->title, "title", indentation);
1589 pivot_table_dump_value (table->subtype, "subtype", indentation);
1590 pivot_table_dump_string (table->command_c, "command", indentation);
1591 pivot_table_dump_string (table->dataset, "dataset", indentation);
1592 pivot_table_dump_string (table->datafile, "datafile", indentation);
1593 pivot_table_dump_string (table->notes, "notes", indentation);
1594 pivot_table_dump_string (table->look->name, "table-look", indentation);
1597 indent (indentation);
1599 struct tm *tm = localtime (&table->date);
1600 printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
1601 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
1605 indent (indentation);
1606 printf ("sizing:\n");
1607 pivot_table_sizing_dump ("column", table->look->width_ranges[TABLE_HORZ],
1608 &table->sizing[TABLE_HORZ], indentation + 1);
1609 pivot_table_sizing_dump ("row", table->look->width_ranges[TABLE_VERT],
1610 &table->sizing[TABLE_VERT], indentation + 1);
1612 indent (indentation);
1613 printf ("areas:\n");
1614 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1615 table_area_style_dump (area, &table->look->areas[area], indentation + 1);
1617 indent (indentation);
1618 printf ("borders:\n");
1619 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1620 table_border_style_dump (border, &table->look->borders[border],
1623 for (size_t i = 0; i < table->n_dimensions; i++)
1624 pivot_dimension_dump (table->dimensions[i], indentation);
1626 /* Presentation and data indexes. */
1627 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1629 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1630 if (layer_axis->n_dimensions)
1632 indent (indentation);
1633 printf ("current layer:");
1635 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1637 const struct pivot_dimension *d = layer_axis->dimensions[i];
1638 char *name = pivot_value_to_string (d->root->name,
1640 table->show_variables);
1641 char *value = pivot_value_to_string (
1642 d->data_leaves[table->current_layer[i]]->name,
1643 table->show_values, table->show_variables);
1644 printf (" %s=%s", name, value);
1652 size_t *layer_indexes;
1653 size_t layer_iteration = 0;
1654 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1656 indent (indentation);
1657 printf ("layer %zu:", layer_iteration++);
1659 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1660 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1662 const struct pivot_dimension *d = layer_axis->dimensions[i];
1664 fputs (i == 0 ? " " : ", ", stdout);
1665 pivot_value_dump (d->root->name);
1666 fputs (" =", stdout);
1668 struct pivot_value **names = xnmalloc (d->n_leaves, sizeof *names);
1670 for (const struct pivot_category *c
1671 = d->presentation_leaves[layer_indexes[i]];
1675 if (pivot_category_is_leaf (c) || c->show_label)
1676 names[n_names++] = c->name;
1679 for (size_t i = n_names; i-- > 0;)
1682 pivot_value_dump (names[i]);
1688 size_t *column_enumeration = pivot_table_enumerate_axis (
1689 table, PIVOT_AXIS_COLUMN, layer_indexes, table->look->omit_empty, NULL);
1690 size_t *row_enumeration = pivot_table_enumerate_axis (
1691 table, PIVOT_AXIS_ROW, layer_indexes, table->look->omit_empty, NULL);
1693 char ***column_headings = compose_headings (
1694 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1695 table->show_values, table->show_variables);
1696 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1698 indent (indentation + 1);
1699 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1702 fputs ("; ", stdout);
1703 if (column_headings[y][x])
1704 fputs (column_headings[y][x], stdout);
1708 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1710 indent (indentation + 1);
1711 printf ("-----------------------------------------------\n");
1713 char ***row_headings = compose_headings (
1714 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1715 table->show_values, table->show_variables);
1718 const size_t *pindexes[PIVOT_N_AXES]
1719 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1720 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1721 &table->axes[PIVOT_AXIS_ROW])
1723 indent (indentation + 1);
1726 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1729 fputs ("; ", stdout);
1730 if (row_headings[y][x])
1731 fputs (row_headings[y][x], stdout);
1737 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1739 &table->axes[PIVOT_AXIS_COLUMN])
1744 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1745 const struct pivot_value *value = pivot_table_get (
1748 pivot_value_dump (value);
1755 free (column_enumeration);
1756 free (row_enumeration);
1757 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1760 pivot_table_dump_value (table->caption, "caption", indentation);
1762 for (size_t i = 0; i < table->n_footnotes; i++)
1764 const struct pivot_footnote *f = table->footnotes[i];
1765 indent (indentation);
1768 pivot_value_dump (f->marker);
1770 printf ("%zu", f->idx);
1772 pivot_value_dump (f->content);
1777 settings_set_decimal_char (old_decimal);
1781 consume_int (const char *p, size_t *n)
1784 while (c_isdigit (*p))
1785 *n = *n * 10 + (*p++ - '0');
1790 pivot_format_inner_template (struct string *out, const char *template,
1792 struct pivot_value **values, size_t n_values,
1793 enum settings_value_show show_values,
1794 enum settings_value_show show_variables)
1796 size_t args_consumed = 0;
1797 while (*template && *template != ':')
1799 if (*template == '\\' && template[1])
1801 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1804 else if (*template == escape)
1807 template = consume_int (template + 1, &index);
1808 if (index >= 1 && index <= n_values)
1810 pivot_value_format (values[index - 1], show_values,
1811 show_variables, out);
1812 args_consumed = MAX (args_consumed, index);
1816 ds_put_byte (out, *template++);
1818 return args_consumed;
1822 pivot_extract_inner_template (const char *template, const char **p)
1828 if (*template == '\\' && template[1] != '\0')
1830 else if (*template == ':')
1831 return template + 1;
1832 else if (*template == '\0')
1840 pivot_format_template (struct string *out, const char *template,
1841 const struct pivot_argument *args, size_t n_args,
1842 enum settings_value_show show_values,
1843 enum settings_value_show show_variables)
1847 if (*template == '\\' && template[1] != '\0')
1849 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1852 else if (*template == '^')
1855 template = consume_int (template + 1, &index);
1856 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1857 pivot_value_format (args[index - 1].values[0],
1858 show_values, show_variables, out);
1860 else if (*template == '[')
1862 const char *tmpl[2];
1863 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1864 template = pivot_extract_inner_template (template, &tmpl[1]);
1865 template += *template == ']';
1868 template = consume_int (template, &index);
1869 if (index < 1 || index > n_args)
1872 const struct pivot_argument *arg = &args[index - 1];
1873 size_t left = arg->n;
1876 struct pivot_value **values = arg->values + (arg->n - left);
1877 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1878 char escape = "%^"[tmpl_idx];
1879 size_t used = pivot_format_inner_template (
1880 out, tmpl[tmpl_idx], escape, values, left,
1881 show_values, show_variables);
1882 if (!used || used > left)
1888 ds_put_byte (out, *template++);
1892 static enum settings_value_show
1893 interpret_show (enum settings_value_show global_show,
1894 enum settings_value_show table_show,
1895 enum settings_value_show value_show,
1898 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1899 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1900 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1904 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1905 SHOW_VARIABLES control whether variable and value labels are included.
1907 The "body" omits subscripts and superscripts and footnotes.
1909 Returns true if OUT is a number (or a number plus a value label), false
1912 pivot_value_format_body (const struct pivot_value *value,
1913 enum settings_value_show show_values,
1914 enum settings_value_show show_variables,
1917 enum settings_value_show show;
1918 bool numeric = false;
1920 switch (value->type)
1922 case PIVOT_VALUE_NUMERIC:
1923 show = interpret_show (settings_get_show_values (),
1925 value->numeric.show,
1926 value->numeric.value_label != NULL);
1927 if (show & SETTINGS_VALUE_SHOW_VALUE)
1929 char *s = data_out (&(union value) { .f = value->numeric.x },
1930 "UTF-8", &value->numeric.format);
1931 ds_put_cstr (out, s + strspn (s, " "));
1934 if (show & SETTINGS_VALUE_SHOW_LABEL)
1936 if (show & SETTINGS_VALUE_SHOW_VALUE)
1937 ds_put_byte (out, ' ');
1938 ds_put_cstr (out, value->numeric.value_label);
1940 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1943 case PIVOT_VALUE_STRING:
1944 show = interpret_show (settings_get_show_values (),
1947 value->string.value_label != NULL);
1948 if (show & SETTINGS_VALUE_SHOW_VALUE)
1950 if (value->string.hex)
1952 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1954 ds_put_format (out, "%02X", *p);
1957 ds_put_cstr (out, value->string.s);
1959 if (show & SETTINGS_VALUE_SHOW_LABEL)
1961 if (show & SETTINGS_VALUE_SHOW_VALUE)
1962 ds_put_byte (out, ' ');
1963 ds_put_cstr (out, value->string.value_label);
1967 case PIVOT_VALUE_VARIABLE:
1968 show = interpret_show (settings_get_show_variables (),
1970 value->variable.show,
1971 value->variable.var_label != NULL);
1972 if (show & SETTINGS_VALUE_SHOW_VALUE)
1973 ds_put_cstr (out, value->variable.var_name);
1974 if (show & SETTINGS_VALUE_SHOW_LABEL)
1976 if (show & SETTINGS_VALUE_SHOW_VALUE)
1977 ds_put_byte (out, ' ');
1978 ds_put_cstr (out, value->variable.var_label);
1982 case PIVOT_VALUE_TEXT:
1983 ds_put_cstr (out, value->text.local);
1986 case PIVOT_VALUE_TEMPLATE:
1987 pivot_format_template (out, value->template.local, value->template.args,
1988 value->template.n_args, show_values,
1996 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
1997 SHOW_VARIABLES control whether variable and value labels are included.
1999 Subscripts and footnotes are included. */
2001 pivot_value_format (const struct pivot_value *value,
2002 enum settings_value_show show_values,
2003 enum settings_value_show show_variables,
2006 pivot_value_format_body (value, show_values, show_variables, out);
2008 if (value->n_subscripts)
2010 for (size_t i = 0; i < value->n_subscripts; i++)
2011 ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
2014 for (size_t i = 0; i < value->n_footnotes; i++)
2016 ds_put_byte (out, '^');
2017 pivot_value_format (value->footnotes[i]->marker,
2018 show_values, show_variables, out);
2022 /* Returns a text representation of VALUE. The caller must free the string,
2025 pivot_value_to_string (const struct pivot_value *value,
2026 enum settings_value_show show_values,
2027 enum settings_value_show show_variables)
2029 struct string s = DS_EMPTY_INITIALIZER;
2030 pivot_value_format (value, show_values, show_variables, &s);
2031 return ds_steal_cstr (&s);
2034 /* Frees the data owned by V. */
2036 pivot_value_destroy (struct pivot_value *value)
2040 font_style_uninit (value->font_style);
2041 free (value->font_style);
2042 free (value->cell_style);
2043 /* Do not free the elements of footnotes because VALUE does not own
2045 free (value->footnotes);
2047 for (size_t i = 0; i < value->n_subscripts; i++)
2048 free (value->subscripts[i]);
2049 free (value->subscripts);
2051 switch (value->type)
2053 case PIVOT_VALUE_NUMERIC:
2054 free (value->numeric.var_name);
2055 free (value->numeric.value_label);
2058 case PIVOT_VALUE_STRING:
2059 free (value->string.s);
2060 free (value->string.var_name);
2061 free (value->string.value_label);
2064 case PIVOT_VALUE_VARIABLE:
2065 free (value->variable.var_name);
2066 free (value->variable.var_label);
2069 case PIVOT_VALUE_TEXT:
2070 free (value->text.local);
2071 if (value->text.c != value->text.local)
2072 free (value->text.c);
2073 if (value->text.id != value->text.local
2074 && value->text.id != value->text.c)
2075 free (value->text.id);
2078 case PIVOT_VALUE_TEMPLATE:
2079 free (value->template.local);
2080 if (value->template.id != value->template.local)
2081 free (value->template.id);
2082 for (size_t i = 0; i < value->template.n_args; i++)
2083 pivot_argument_uninit (&value->template.args[i]);
2084 free (value->template.args);
2091 /* Sets AREA to the style to use for VALUE, with defaults coming from
2092 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
2094 pivot_value_get_style (struct pivot_value *value,
2095 const struct font_style *base_font_style,
2096 const struct cell_style *base_cell_style,
2097 struct table_area_style *area)
2099 font_style_copy (NULL, &area->font_style, (value->font_style
2101 : base_font_style));
2102 area->cell_style = *(value->cell_style
2107 /* Copies AREA into VALUE's style. */
2109 pivot_value_set_style (struct pivot_value *value,
2110 const struct table_area_style *area)
2112 if (value->font_style)
2113 font_style_uninit (value->font_style);
2115 value->font_style = xmalloc (sizeof *value->font_style);
2116 font_style_copy (NULL, value->font_style, &area->font_style);
2118 if (!value->cell_style)
2119 value->cell_style = xmalloc (sizeof *value->cell_style);
2120 *value->cell_style = area->cell_style;
2123 /* Frees the data owned by ARG (but not ARG itself). */
2125 pivot_argument_uninit (struct pivot_argument *arg)
2129 for (size_t i = 0; i < arg->n; i++)
2130 pivot_value_destroy (arg->values[i]);
2135 /* Creates and returns a new pivot_value whose contents is the null-terminated
2136 string TEXT. Takes ownership of TEXT.
2138 This function is for text strings provided by the user (with the exception
2139 that pivot_value_new_variable() should be used for variable names). For
2140 strings that are part of the PSPP user interface, such as names of
2141 procedures, statistics, annotations, error messages, etc., use
2142 pivot_value_new_text(). */
2143 struct pivot_value *
2144 pivot_value_new_user_text_nocopy (char *text)
2146 struct pivot_value *value = xmalloc (sizeof *value);
2147 *value = (struct pivot_value) {
2148 .type = PIVOT_VALUE_TEXT,
2153 .user_provided = true,
2159 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2160 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2163 This function is for text strings provided by the user (with the exception
2164 that pivot_value_new_variable() should be used for variable names). For
2165 strings that are part of the PSPP user interface, such as names of
2166 procedures, statistics, annotations, error messages, etc., use
2167 pivot_value_new_text().j
2169 The caller retains ownership of TEXT.*/
2170 struct pivot_value *
2171 pivot_value_new_user_text (const char *text, size_t length)
2173 return pivot_value_new_user_text_nocopy (
2174 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2177 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2178 a translatable string, but not actually translated yet, e.g. enclosed in
2179 N_(). This function is for text strings that are part of the PSPP user
2180 interface, such as names of procedures, statistics, annotations, error
2181 messages, etc. For strings that come from the user, use
2182 pivot_value_new_user_text(). */
2183 struct pivot_value *
2184 pivot_value_new_text (const char *text)
2186 char *c = xstrdup (text);
2187 char *local = xstrdup (gettext (c));
2189 struct pivot_value *value = xmalloc (sizeof *value);
2190 *value = (struct pivot_value) {
2191 .type = PIVOT_VALUE_TEXT,
2196 .user_provided = false,
2202 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2204 struct pivot_value * PRINTF_FORMAT (1, 2)
2205 pivot_value_new_text_format (const char *format, ...)
2208 va_start (args, format);
2209 char *c = xvasprintf (format, args);
2212 va_start (args, format);
2213 char *local = xvasprintf (gettext (format), args);
2216 struct pivot_value *value = xmalloc (sizeof *value);
2217 *value = (struct pivot_value) {
2218 .type = PIVOT_VALUE_TEXT,
2223 .user_provided = false,
2229 /* Returns a new pivot_value that represents X.
2231 The format to use for X is unspecified. Usually the easiest way to specify
2232 a format is through assigning a result class to one of the categories that
2233 the pivot_value will end up in. If that is not suitable, then the caller
2234 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2235 struct pivot_value *
2236 pivot_value_new_number (double x)
2238 struct pivot_value *value = xmalloc (sizeof *value);
2239 *value = (struct pivot_value) {
2240 .type = PIVOT_VALUE_NUMERIC,
2241 .numeric = { .x = x, },
2246 /* Returns a new pivot_value that represents X, formatted as an integer. */
2247 struct pivot_value *
2248 pivot_value_new_integer (double x)
2250 struct pivot_value *value = pivot_value_new_number (x);
2251 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2255 /* Returns a new pivot_value that represents VALUE, formatted as for
2257 struct pivot_value *
2258 pivot_value_new_var_value (const struct variable *variable,
2259 const union value *value)
2261 struct pivot_value *pv = pivot_value_new_value (
2262 value, var_get_width (variable), var_get_print_format (variable),
2263 var_get_encoding (variable));
2265 char *var_name = xstrdup (var_get_name (variable));
2266 if (var_is_alpha (variable))
2267 pv->string.var_name = var_name;
2269 pv->numeric.var_name = var_name;
2271 const char *label = var_lookup_value_label (variable, value);
2274 if (var_is_alpha (variable))
2275 pv->string.value_label = xstrdup (label);
2277 pv->numeric.value_label = xstrdup (label);
2283 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2284 formatted with FORMAT. For a string value, ENCODING must be its character
2286 struct pivot_value *
2287 pivot_value_new_value (const union value *value, int width,
2288 const struct fmt_spec *format, const char *encoding)
2290 struct pivot_value *pv = xzalloc (sizeof *pv);
2293 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2295 size_t n = strlen (s);
2296 while (n > 0 && s[n - 1] == ' ')
2299 pv->type = PIVOT_VALUE_STRING;
2301 pv->string.hex = format->type == FMT_AHEX;
2305 pv->type = PIVOT_VALUE_NUMERIC;
2306 pv->numeric.x = value->f;
2307 pv->numeric.format = *format;
2313 /* Returns a new pivot_value for VARIABLE. */
2314 struct pivot_value *
2315 pivot_value_new_variable (const struct variable *variable)
2317 struct pivot_value *value = xmalloc (sizeof *value);
2318 *value = (struct pivot_value) {
2319 .type = PIVOT_VALUE_VARIABLE,
2321 .var_name = xstrdup (var_get_name (variable)),
2322 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2328 /* Attaches a reference to FOOTNOTE to V. */
2330 pivot_value_add_footnote (struct pivot_value *v,
2331 const struct pivot_footnote *footnote)
2333 /* Some legacy tables include numerous duplicate footnotes. Suppress
2335 for (size_t i = 0; i < v->n_footnotes; i++)
2336 if (v->footnotes[i] == footnote)
2339 v->footnotes = xrealloc (v->footnotes,
2340 (v->n_footnotes + 1) * sizeof *v->footnotes);
2341 v->footnotes[v->n_footnotes++] = footnote;
2344 /* If VALUE is a numeric value, and RC is a result class such as
2345 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2347 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2350 if (value->type == PIVOT_VALUE_NUMERIC)
2352 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2354 value->numeric.format = *f;