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 Operations commonly performed on the new pivot_table:
801 - If empty rows or columns should not be displayed, set ->omit_empty to
804 - Set the format to use for "count" values with pivot_table_set_weight_var()
805 or pivot_table_set_weight_format().
807 This function is a shortcut for pivot_table_create__() for the most common
808 case. Use pivot_table_create__() directly if the title should be some kind
809 of value other than an ordinary text string, or if the subtype should be
810 different from the title.
812 See the large comment at the top of pivot-table.h for general advice on
813 creating pivot tables. */
815 pivot_table_create (const char *title)
817 return pivot_table_create__ (pivot_value_new_text (title), title);
820 /* Creates and returns a new pivot table with the given TITLE, and takes
821 ownership of TITLE. The new pivot table's subtype is SUBTYPE, which
822 should be an untranslated English string that describes the contents of
823 the table at a high level without being specific about the variables or
824 other context involved.
826 Operations commonly performed on the new pivot_table:
828 - If empty rows or columns should not be displayed, set ->omit_empty to
831 - Set the format to use for "count" values with pivot_table_set_weight_var()
832 or pivot_table_set_weight_format().
834 See the large comment at the top of pivot-table.h for general advice on
835 creating pivot tables. */
837 pivot_table_create__ (struct pivot_value *title, const char *subtype)
839 struct pivot_table *table = xzalloc (sizeof *table);
841 table->show_caption = true;
842 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
843 table->title = title;
844 table->subtype = subtype ? pivot_value_new_text (subtype) : NULL;
845 table->command_c = output_get_command_name ();
846 table->look = pivot_table_look_ref (pivot_table_look_get_default ());
848 hmap_init (&table->cells);
853 /* Creates and returns a new pivot table with the given TITLE and a single cell
854 with the given CONTENT.
856 This is really just for error handling. */
858 pivot_table_create_for_text (struct pivot_value *title,
859 struct pivot_value *content)
861 struct pivot_table *table = pivot_table_create__ (title, "Error");
863 struct pivot_dimension *d = pivot_dimension_create (
864 table, PIVOT_AXIS_ROW, N_("Error"));
865 d->hide_all_labels = true;
866 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
868 pivot_table_put1 (table, 0, content);
873 /* Increases TABLE's reference count, indicating that it has an additional
874 owner. A pivot table that is shared among multiple owners must not be
877 pivot_table_ref (const struct pivot_table *table_)
879 struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
884 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
885 If TABLE no longer has any owners, it is freed. */
887 pivot_table_unref (struct pivot_table *table)
891 assert (table->ref_cnt > 0);
892 if (--table->ref_cnt)
895 free (table->current_layer);
896 pivot_table_look_unref (table->look);
898 for (int i = 0; i < TABLE_N_AXES; i++)
899 pivot_table_sizing_uninit (&table->sizing[i]);
901 for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
902 free (table->ccs[i]);
904 free (table->command_local);
905 free (table->command_c);
906 free (table->language);
907 free (table->locale);
909 free (table->dataset);
910 free (table->datafile);
912 for (size_t i = 0; i < table->n_footnotes; i++)
913 pivot_footnote_destroy (table->footnotes[i]);
914 free (table->footnotes);
916 pivot_value_destroy (table->title);
917 pivot_value_destroy (table->subtype);
918 pivot_value_destroy (table->corner_text);
919 pivot_value_destroy (table->caption);
921 for (size_t i = 0; i < table->n_dimensions; i++)
922 pivot_dimension_destroy (table->dimensions[i]);
923 free (table->dimensions);
925 for (size_t i = 0; i < PIVOT_N_AXES; i++)
926 free (table->axes[i].dimensions);
928 struct pivot_cell *cell, *next_cell;
929 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
932 hmap_delete (&table->cells, &cell->hmap_node);
933 pivot_value_destroy (cell->value);
936 hmap_destroy (&table->cells);
941 /* Returns true if TABLE has more than one owner. A pivot table that is shared
942 among multiple owners must not be modified. */
944 pivot_table_is_shared (const struct pivot_table *table)
946 return table->ref_cnt > 1;
949 const struct pivot_table_look *
950 pivot_table_get_look (const struct pivot_table *table)
956 pivot_table_set_look (struct pivot_table *table,
957 const struct pivot_table_look *look)
959 pivot_table_look_unref (table->look);
960 table->look = pivot_table_look_ref (look);
963 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
964 WV, which should be the weight variable for the dictionary whose data or
965 statistics are being put into TABLE.
967 This has no effect if WV is NULL. */
969 pivot_table_set_weight_var (struct pivot_table *table,
970 const struct variable *wv)
973 pivot_table_set_weight_format (table, var_get_print_format (wv));
976 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
977 format for the dictionary whose data or statistics are being put into TABLE.
979 This has no effect if WFMT is NULL. */
981 pivot_table_set_weight_format (struct pivot_table *table,
982 const struct fmt_spec *wfmt)
985 table->weight_format = *wfmt;
988 /* Returns true if TABLE has no cells, false otherwise. */
990 pivot_table_is_empty (const struct pivot_table *table)
992 return hmap_is_empty (&table->cells);
996 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
998 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
1002 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
1004 for (size_t i = 0; i < n; i++)
1011 static struct pivot_cell *
1012 pivot_table_lookup_cell__ (const struct pivot_table *table,
1013 const size_t *dindexes, unsigned int hash)
1015 struct pivot_cell *cell;
1016 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
1018 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
1023 static struct pivot_cell *
1024 pivot_cell_allocate (size_t n_idx)
1026 struct pivot_cell *cell UNUSED;
1027 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
1030 static struct pivot_cell *
1031 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
1033 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1034 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
1037 cell = pivot_cell_allocate (table->n_dimensions);
1038 for (size_t i = 0; i < table->n_dimensions; i++)
1039 cell->idx[i] = dindexes[i];
1041 hmap_insert (&table->cells, &cell->hmap_node, hash);
1046 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
1047 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
1050 If VALUE is a numeric value without a specified format, this function checks
1051 each of the categories designated by DINDEXES[] and takes the format from
1052 the first category with a result class. If none has a result class, uses
1053 the overall default numeric format. */
1055 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
1056 struct pivot_value *value)
1058 assert (n == table->n_dimensions);
1060 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
1062 for (size_t i = 0; i < table->n_dimensions; i++)
1064 const struct pivot_dimension *d = table->dimensions[i];
1065 if (dindexes[i] < d->n_leaves)
1067 const struct pivot_category *c = d->data_leaves[dindexes[i]];
1070 value->numeric.format = c->format;
1075 value->numeric.format = *settings_get_format ();
1080 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1081 pivot_value_destroy (cell->value);
1082 cell->value = value;
1085 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
1086 dimension. Takes ownership of VALUE. */
1088 pivot_table_put1 (struct pivot_table *table, size_t idx1,
1089 struct pivot_value *value)
1091 size_t dindexes[] = { idx1 };
1092 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1095 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
1096 dimensions. Takes ownership of VALUE. */
1098 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
1099 struct pivot_value *value)
1101 size_t dindexes[] = { idx1, idx2 };
1102 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1105 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
1106 have 3 dimensions. Takes ownership of VALUE. */
1108 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
1109 size_t idx3, struct pivot_value *value)
1111 size_t dindexes[] = { idx1, idx2, idx3 };
1112 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1115 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
1116 must have 4 dimensions. Takes ownership of VALUE. */
1118 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1119 size_t idx3, size_t idx4, struct pivot_value *value)
1121 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1122 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1125 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1126 automatically assigned marker.
1128 The footnote will only appear in output if it is referenced. Use
1129 pivot_value_add_footnote() to add a reference to the footnote. */
1130 struct pivot_footnote *
1131 pivot_table_create_footnote (struct pivot_table *table,
1132 struct pivot_value *content)
1134 return pivot_table_create_footnote__ (table, table->n_footnotes,
1138 static struct pivot_value *
1139 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1141 char text[INT_BUFSIZE_BOUND (size_t)];
1142 if (show_numeric_markers)
1143 snprintf (text, sizeof text, "%d", idx + 1);
1145 str_format_26adic (idx + 1, false, text, sizeof text);
1146 return pivot_value_new_user_text (text, -1);
1149 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1150 all lower indexes as a side effect). If MARKER is nonnull, sets the
1151 footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1152 struct pivot_footnote *
1153 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1154 struct pivot_value *marker,
1155 struct pivot_value *content)
1157 if (idx >= table->n_footnotes)
1159 while (idx >= table->allocated_footnotes)
1160 table->footnotes = x2nrealloc (table->footnotes,
1161 &table->allocated_footnotes,
1162 sizeof *table->footnotes);
1163 while (idx >= table->n_footnotes)
1165 struct pivot_footnote *f = xmalloc (sizeof *f);
1166 f->idx = table->n_footnotes;
1167 f->marker = pivot_make_default_footnote_marker (
1168 f->idx, table->look->show_numeric_markers);
1172 table->footnotes[table->n_footnotes++] = f;
1176 struct pivot_footnote *f = table->footnotes[idx];
1179 pivot_value_destroy (f->marker);
1184 pivot_value_destroy (f->content);
1185 f->content = content;
1190 /* Frees the data owned by F. */
1192 pivot_footnote_destroy (struct pivot_footnote *f)
1196 pivot_value_destroy (f->content);
1197 pivot_value_destroy (f->marker);
1202 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1203 indexes for each dimension in TABLE in DINDEXES[]. */
1205 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1206 const size_t *pindexes[PIVOT_N_AXES],
1207 size_t dindexes[/* table->n_dimensions */])
1209 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1211 const struct pivot_axis *axis = &table->axes[i];
1213 for (size_t j = 0; j < axis->n_dimensions; j++)
1215 const struct pivot_dimension *d = axis->dimensions[j];
1216 dindexes[d->top_index]
1217 = d->presentation_leaves[pindexes[i][j]]->data_index;
1223 pivot_table_enumerate_axis (const struct pivot_table *table,
1224 enum pivot_axis_type axis_type,
1225 const size_t *layer_indexes, bool omit_empty,
1228 const struct pivot_axis *axis = &table->axes[axis_type];
1229 if (!axis->n_dimensions)
1231 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1233 enumeration[1] = SIZE_MAX;
1238 else if (!axis->extent)
1240 size_t *enumeration = xmalloc (sizeof *enumeration);
1241 *enumeration = SIZE_MAX;
1247 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1248 axis->n_dimensions), 1),
1249 sizeof *enumeration);
1250 size_t *p = enumeration;
1251 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1253 size_t *axis_indexes;
1254 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1258 enum pivot_axis_type axis2_type
1259 = pivot_axis_type_transpose (axis_type);
1261 size_t *axis2_indexes;
1262 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1264 const size_t *pindexes[PIVOT_N_AXES];
1265 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1266 pindexes[axis_type] = axis_indexes;
1267 pindexes[axis2_type] = axis2_indexes;
1268 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1269 if (pivot_table_get (table, dindexes))
1275 free (axis2_indexes);
1278 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1279 p += axis->n_dimensions;
1281 if (omit_empty && p == enumeration)
1283 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1285 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1286 p += axis->n_dimensions;
1291 *n = (p - enumeration) / axis->n_dimensions;
1297 static const struct pivot_cell *
1298 pivot_table_lookup_cell (const struct pivot_table *table,
1299 const size_t *dindexes)
1301 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1302 return pivot_table_lookup_cell__ (table, dindexes, hash);
1305 const struct pivot_value *
1306 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1308 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1309 return cell ? cell->value : NULL;
1312 struct pivot_value *
1313 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1315 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1317 cell->value = pivot_value_new_user_text ("", -1);
1322 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1324 if (pivot_category_is_group (category) && category->n_subs)
1325 for (size_t i = 0; i < category->n_subs; i++)
1326 distribute_extra_depth (category->subs[i], extra_depth);
1328 category->extra_depth += extra_depth;
1332 pivot_category_assign_label_depth (struct pivot_category *category,
1333 bool dimension_labels_in_corner)
1335 category->extra_depth = 0;
1337 if (pivot_category_is_group (category))
1340 for (size_t i = 0; i < category->n_subs; i++)
1342 pivot_category_assign_label_depth (category->subs[i], false);
1343 depth = MAX (depth, category->subs[i]->label_depth);
1346 for (size_t i = 0; i < category->n_subs; i++)
1348 struct pivot_category *sub = category->subs[i];
1350 size_t extra_depth = depth - sub->label_depth;
1352 distribute_extra_depth (sub, extra_depth);
1354 sub->label_depth = depth;
1357 category->show_label_in_corner = (category->show_label
1358 && dimension_labels_in_corner);
1359 category->label_depth
1360 = (category->show_label && !category->show_label_in_corner
1361 ? depth + 1 : depth);
1364 category->label_depth = 1;
1368 pivot_axis_assign_label_depth (struct pivot_table *table,
1369 enum pivot_axis_type axis_type,
1370 bool dimension_labels_in_corner)
1372 struct pivot_axis *axis = &table->axes[axis_type];
1373 bool any_label_shown_in_corner = false;
1374 axis->label_depth = 0;
1376 for (size_t i = 0; i < axis->n_dimensions; i++)
1378 struct pivot_dimension *d = axis->dimensions[i];
1379 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1380 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1381 axis->label_depth += d->label_depth;
1382 axis->extent *= d->n_leaves;
1384 if (d->root->show_label_in_corner)
1385 any_label_shown_in_corner = true;
1387 return any_label_shown_in_corner;
1391 pivot_table_assign_label_depth (struct pivot_table *table)
1393 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1394 if (pivot_axis_assign_label_depth (
1395 table, PIVOT_AXIS_ROW, (table->look->row_labels_in_corner
1396 && !table->corner_text))
1397 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1398 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1399 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1407 indent (int indentation)
1409 for (int i = 0; i < indentation * 2; i++)
1414 pivot_value_dump (const struct pivot_value *value)
1416 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1417 SETTINGS_VALUE_SHOW_DEFAULT);
1423 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1428 indent (indentation);
1429 printf ("%s: ", name);
1430 pivot_value_dump (value);
1436 pivot_table_dump_string (const char *string, const char *name, int indentation)
1440 indent (indentation);
1441 printf ("%s: %s\n", name, string);
1446 pivot_category_dump (const struct pivot_category *c, int indentation)
1448 indent (indentation);
1449 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1450 pivot_value_dump (c->name);
1453 if (pivot_category_is_leaf (c))
1454 printf ("data_index=%zu\n", c->data_index);
1457 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1460 for (size_t i = 0; i < c->n_subs; i++)
1461 pivot_category_dump (c->subs[i], indentation + 1);
1466 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1468 indent (indentation);
1469 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1470 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1472 pivot_category_dump (d->root, indentation + 1);
1476 table_area_style_dump (enum pivot_area area, const struct table_area_style *a,
1479 indent (indentation);
1480 printf ("%s: ", pivot_area_to_string (area));
1481 font_style_dump (&a->font_style);
1483 cell_style_dump (&a->cell_style);
1488 table_border_style_dump (enum pivot_border border,
1489 const struct table_border_style *b, int indentation)
1491 indent (indentation);
1492 printf ("%s: %s ", pivot_border_to_string (border),
1493 table_stroke_to_string (b->stroke));
1494 cell_color_dump (&b->color);
1499 compose_headings (const struct pivot_axis *axis,
1500 const size_t *column_enumeration,
1501 enum settings_value_show show_values,
1502 enum settings_value_show show_variables)
1504 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1507 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1508 for (size_t i = 0; i < axis->label_depth; i++)
1509 headings[i] = xcalloc (axis->extent, sizeof **headings);
1511 const size_t *indexes;
1513 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1515 int row = axis->label_depth - 1;
1516 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1518 const struct pivot_dimension *d = axis->dimensions[dim_index];
1519 if (d->hide_all_labels)
1521 for (const struct pivot_category *c
1522 = d->presentation_leaves[indexes[dim_index]];
1526 if (pivot_category_is_leaf (c) || (c->show_label
1527 && !c->show_label_in_corner))
1529 headings[row][column] = pivot_value_to_string (
1530 c->name, show_values, show_variables);
1531 if (!*headings[row][column])
1532 headings[row][column] = xstrdup ("<blank>");
1544 free_headings (const struct pivot_axis *axis, char ***headings)
1546 for (size_t i = 0; i < axis->label_depth; i++)
1548 for (size_t j = 0; j < axis->extent; j++)
1549 free (headings[i][j]);
1556 pivot_table_sizing_dump (const char *name,
1557 const int width_ranges[2],
1558 const struct pivot_table_sizing *s,
1561 indent (indentation);
1562 printf ("%ss: min=%d, max=%d\n", name, width_ranges[0], width_ranges[1]);
1565 indent (indentation + 1);
1566 printf ("%s widths:", name);
1567 for (size_t i = 0; i < s->n_widths; i++)
1568 printf (" %d", s->widths[i]);
1573 indent (indentation + 1);
1574 printf ("break after %ss:", name);
1575 for (size_t i = 0; i < s->n_breaks; i++)
1576 printf (" %zu", s->breaks[i]);
1581 indent (indentation + 1);
1582 printf ("keep %ss together:", name);
1583 for (size_t i = 0; i < s->n_keeps; i++)
1584 printf (" [%zu,%zu]",
1586 s->keeps[i].ofs + s->keeps[i].n - 1);
1592 pivot_table_dump (const struct pivot_table *table, int indentation)
1597 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1598 if (table->decimal == '.' || table->decimal == ',')
1599 settings_set_decimal_char (table->decimal);
1601 pivot_table_dump_value (table->title, "title", indentation);
1602 pivot_table_dump_value (table->subtype, "subtype", indentation);
1603 pivot_table_dump_string (table->command_c, "command", indentation);
1604 pivot_table_dump_string (table->dataset, "dataset", indentation);
1605 pivot_table_dump_string (table->datafile, "datafile", indentation);
1606 pivot_table_dump_string (table->notes, "notes", indentation);
1607 pivot_table_dump_string (table->look->name, "table-look", indentation);
1610 indent (indentation);
1612 struct tm *tm = localtime (&table->date);
1613 printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
1614 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
1618 indent (indentation);
1619 printf ("sizing:\n");
1620 pivot_table_sizing_dump ("column", table->look->width_ranges[TABLE_HORZ],
1621 &table->sizing[TABLE_HORZ], indentation + 1);
1622 pivot_table_sizing_dump ("row", table->look->width_ranges[TABLE_VERT],
1623 &table->sizing[TABLE_VERT], indentation + 1);
1625 indent (indentation);
1626 printf ("areas:\n");
1627 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1628 table_area_style_dump (area, &table->look->areas[area], indentation + 1);
1630 indent (indentation);
1631 printf ("borders:\n");
1632 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1633 table_border_style_dump (border, &table->look->borders[border],
1636 for (size_t i = 0; i < table->n_dimensions; i++)
1637 pivot_dimension_dump (table->dimensions[i], indentation);
1639 /* Presentation and data indexes. */
1640 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1642 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1643 if (layer_axis->n_dimensions)
1645 indent (indentation);
1646 printf ("current layer:");
1648 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1650 const struct pivot_dimension *d = layer_axis->dimensions[i];
1651 char *name = pivot_value_to_string (d->root->name,
1653 table->show_variables);
1654 char *value = pivot_value_to_string (
1655 d->data_leaves[table->current_layer[i]]->name,
1656 table->show_values, table->show_variables);
1657 printf (" %s=%s", name, value);
1665 size_t *layer_indexes;
1666 size_t layer_iteration = 0;
1667 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1669 indent (indentation);
1670 printf ("layer %zu:", layer_iteration++);
1672 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1673 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1675 const struct pivot_dimension *d = layer_axis->dimensions[i];
1677 fputs (i == 0 ? " " : ", ", stdout);
1678 pivot_value_dump (d->root->name);
1679 fputs (" =", stdout);
1681 struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1684 for (const struct pivot_category *c
1685 = d->presentation_leaves[layer_indexes[i]];
1689 if (pivot_category_is_leaf (c) || c->show_label)
1690 names[n_names++] = c->name;
1693 for (size_t i = n_names; i-- > 0;)
1696 pivot_value_dump (names[i]);
1702 size_t *column_enumeration = pivot_table_enumerate_axis (
1703 table, PIVOT_AXIS_COLUMN, layer_indexes, table->look->omit_empty, NULL);
1704 size_t *row_enumeration = pivot_table_enumerate_axis (
1705 table, PIVOT_AXIS_ROW, layer_indexes, table->look->omit_empty, NULL);
1707 char ***column_headings = compose_headings (
1708 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1709 table->show_values, table->show_variables);
1710 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1712 indent (indentation + 1);
1713 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1716 fputs ("; ", stdout);
1717 if (column_headings[y][x])
1718 fputs (column_headings[y][x], stdout);
1722 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1724 indent (indentation + 1);
1725 printf ("-----------------------------------------------\n");
1727 char ***row_headings = compose_headings (
1728 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1729 table->show_values, table->show_variables);
1732 const size_t *pindexes[PIVOT_N_AXES]
1733 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1734 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1735 &table->axes[PIVOT_AXIS_ROW])
1737 indent (indentation + 1);
1740 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1743 fputs ("; ", stdout);
1744 if (row_headings[y][x])
1745 fputs (row_headings[y][x], stdout);
1751 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1753 &table->axes[PIVOT_AXIS_COLUMN])
1758 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1759 const struct pivot_value *value = pivot_table_get (
1762 pivot_value_dump (value);
1769 free (column_enumeration);
1770 free (row_enumeration);
1771 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1774 pivot_table_dump_value (table->caption, "caption", indentation);
1776 for (size_t i = 0; i < table->n_footnotes; i++)
1778 const struct pivot_footnote *f = table->footnotes[i];
1779 indent (indentation);
1782 pivot_value_dump (f->marker);
1784 printf ("%zu", f->idx);
1786 pivot_value_dump (f->content);
1791 settings_set_decimal_char (old_decimal);
1795 consume_int (const char *p, size_t *n)
1798 while (c_isdigit (*p))
1799 *n = *n * 10 + (*p++ - '0');
1804 pivot_format_inner_template (struct string *out, const char *template,
1806 struct pivot_value **values, size_t n_values,
1807 enum settings_value_show show_values,
1808 enum settings_value_show show_variables)
1810 size_t args_consumed = 0;
1811 while (*template && *template != ':')
1813 if (*template == '\\' && template[1])
1815 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1818 else if (*template == escape)
1821 template = consume_int (template + 1, &index);
1822 if (index >= 1 && index <= n_values)
1824 pivot_value_format (values[index - 1], show_values,
1825 show_variables, out);
1826 args_consumed = MAX (args_consumed, index);
1830 ds_put_byte (out, *template++);
1832 return args_consumed;
1836 pivot_extract_inner_template (const char *template, const char **p)
1842 if (*template == '\\' && template[1] != '\0')
1844 else if (*template == ':')
1845 return template + 1;
1846 else if (*template == '\0')
1854 pivot_format_template (struct string *out, const char *template,
1855 const struct pivot_argument *args, size_t n_args,
1856 enum settings_value_show show_values,
1857 enum settings_value_show show_variables)
1861 if (*template == '\\' && template[1] != '\0')
1863 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1866 else if (*template == '^')
1869 template = consume_int (template + 1, &index);
1870 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1871 pivot_value_format (args[index - 1].values[0],
1872 show_values, show_variables, out);
1874 else if (*template == '[')
1876 const char *tmpl[2];
1877 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1878 template = pivot_extract_inner_template (template, &tmpl[1]);
1879 template += *template == ']';
1882 template = consume_int (template, &index);
1883 if (index < 1 || index > n_args)
1886 const struct pivot_argument *arg = &args[index - 1];
1887 size_t left = arg->n;
1890 struct pivot_value **values = arg->values + (arg->n - left);
1891 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1892 char escape = "%^"[tmpl_idx];
1893 size_t used = pivot_format_inner_template (
1894 out, tmpl[tmpl_idx], escape, values, left,
1895 show_values, show_variables);
1896 if (!used || used > left)
1902 ds_put_byte (out, *template++);
1906 static enum settings_value_show
1907 interpret_show (enum settings_value_show global_show,
1908 enum settings_value_show table_show,
1909 enum settings_value_show value_show,
1912 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1913 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1914 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1918 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1919 SHOW_VARIABLES control whether variable and value labels are included.
1921 The "body" omits subscripts and superscripts and footnotes. */
1923 pivot_value_format_body (const struct pivot_value *value,
1924 enum settings_value_show show_values,
1925 enum settings_value_show show_variables,
1928 enum settings_value_show show;
1929 bool numeric = false;
1931 switch (value->type)
1933 case PIVOT_VALUE_NUMERIC:
1934 show = interpret_show (settings_get_show_values (),
1936 value->numeric.show,
1937 value->numeric.value_label != NULL);
1938 if (show & SETTINGS_VALUE_SHOW_VALUE)
1940 char *s = data_out (&(union value) { .f = value->numeric.x },
1941 "UTF-8", &value->numeric.format);
1942 ds_put_cstr (out, s + strspn (s, " "));
1945 if (show & SETTINGS_VALUE_SHOW_LABEL)
1947 if (show & SETTINGS_VALUE_SHOW_VALUE)
1948 ds_put_byte (out, ' ');
1949 ds_put_cstr (out, value->numeric.value_label);
1951 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1954 case PIVOT_VALUE_STRING:
1955 show = interpret_show (settings_get_show_values (),
1958 value->string.value_label != NULL);
1959 if (show & SETTINGS_VALUE_SHOW_VALUE)
1961 if (value->string.hex)
1963 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1965 ds_put_format (out, "%02X", *p);
1968 ds_put_cstr (out, value->string.s);
1970 if (show & SETTINGS_VALUE_SHOW_LABEL)
1972 if (show & SETTINGS_VALUE_SHOW_VALUE)
1973 ds_put_byte (out, ' ');
1974 ds_put_cstr (out, value->string.value_label);
1978 case PIVOT_VALUE_VARIABLE:
1979 show = interpret_show (settings_get_show_variables (),
1981 value->variable.show,
1982 value->variable.var_label != NULL);
1983 if (show & SETTINGS_VALUE_SHOW_VALUE)
1984 ds_put_cstr (out, value->variable.var_name);
1985 if (show & SETTINGS_VALUE_SHOW_LABEL)
1987 if (show & SETTINGS_VALUE_SHOW_VALUE)
1988 ds_put_byte (out, ' ');
1989 ds_put_cstr (out, value->variable.var_label);
1993 case PIVOT_VALUE_TEXT:
1994 ds_put_cstr (out, value->text.local);
1997 case PIVOT_VALUE_TEMPLATE:
1998 pivot_format_template (out, value->template.local, value->template.args,
1999 value->template.n_args, show_values,
2007 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
2008 SHOW_VARIABLES control whether variable and value labels are included.
2010 Subscripts and superscripts and footnotes are included. */
2012 pivot_value_format (const struct pivot_value *value,
2013 enum settings_value_show show_values,
2014 enum settings_value_show show_variables,
2017 pivot_value_format_body (value, show_values, show_variables, out);
2019 if (value->n_subscripts)
2021 for (size_t i = 0; i < value->n_subscripts; i++)
2022 ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
2025 if (value->superscript)
2026 ds_put_format (out, "^%s", value->superscript);
2028 for (size_t i = 0; i < value->n_footnotes; i++)
2030 ds_put_byte (out, '^');
2031 pivot_value_format (value->footnotes[i]->marker,
2032 show_values, show_variables, out);
2036 /* Returns a text representation of VALUE. The caller must free the string,
2039 pivot_value_to_string (const struct pivot_value *value,
2040 enum settings_value_show show_values,
2041 enum settings_value_show show_variables)
2043 struct string s = DS_EMPTY_INITIALIZER;
2044 pivot_value_format (value, show_values, show_variables, &s);
2045 return ds_steal_cstr (&s);
2048 /* Frees the data owned by V. */
2050 pivot_value_destroy (struct pivot_value *value)
2054 font_style_uninit (value->font_style);
2055 free (value->font_style);
2056 free (value->cell_style);
2057 /* Do not free the elements of footnotes because VALUE does not own
2059 free (value->footnotes);
2061 for (size_t i = 0; i < value->n_subscripts; i++)
2062 free (value->subscripts[i]);
2063 free (value->subscripts);
2065 free (value->superscript);
2067 switch (value->type)
2069 case PIVOT_VALUE_NUMERIC:
2070 free (value->numeric.var_name);
2071 free (value->numeric.value_label);
2074 case PIVOT_VALUE_STRING:
2075 free (value->string.s);
2076 free (value->string.var_name);
2077 free (value->string.value_label);
2080 case PIVOT_VALUE_VARIABLE:
2081 free (value->variable.var_name);
2082 free (value->variable.var_label);
2085 case PIVOT_VALUE_TEXT:
2086 free (value->text.local);
2087 if (value->text.c != value->text.local)
2088 free (value->text.c);
2089 if (value->text.id != value->text.local
2090 && value->text.id != value->text.c)
2091 free (value->text.id);
2094 case PIVOT_VALUE_TEMPLATE:
2095 free (value->template.local);
2096 if (value->template.id != value->template.local)
2097 free (value->template.id);
2098 for (size_t i = 0; i < value->template.n_args; i++)
2099 pivot_argument_uninit (&value->template.args[i]);
2100 free (value->template.args);
2107 /* Sets AREA to the style to use for VALUE, with defaults coming from
2108 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
2110 pivot_value_get_style (struct pivot_value *value,
2111 const struct font_style *base_font_style,
2112 const struct cell_style *base_cell_style,
2113 struct table_area_style *area)
2115 font_style_copy (NULL, &area->font_style, (value->font_style
2117 : base_font_style));
2118 area->cell_style = *(value->cell_style
2123 /* Copies AREA into VALUE's style. */
2125 pivot_value_set_style (struct pivot_value *value,
2126 const struct table_area_style *area)
2128 if (value->font_style)
2129 font_style_uninit (value->font_style);
2131 value->font_style = xmalloc (sizeof *value->font_style);
2132 font_style_copy (NULL, value->font_style, &area->font_style);
2134 if (!value->cell_style)
2135 value->cell_style = xmalloc (sizeof *value->cell_style);
2136 *value->cell_style = area->cell_style;
2139 /* Frees the data owned by ARG (but not ARG itself). */
2141 pivot_argument_uninit (struct pivot_argument *arg)
2145 for (size_t i = 0; i < arg->n; i++)
2146 pivot_value_destroy (arg->values[i]);
2151 /* Creates and returns a new pivot_value whose contents is the null-terminated
2152 string TEXT. Takes ownership of TEXT.
2154 This function is for text strings provided by the user (with the exception
2155 that pivot_value_new_variable() should be used for variable names). For
2156 strings that are part of the PSPP user interface, such as names of
2157 procedures, statistics, annotations, error messages, etc., use
2158 pivot_value_new_text(). */
2159 struct pivot_value *
2160 pivot_value_new_user_text_nocopy (char *text)
2162 struct pivot_value *value = xmalloc (sizeof *value);
2163 *value = (struct pivot_value) {
2164 .type = PIVOT_VALUE_TEXT,
2169 .user_provided = true,
2175 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2176 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2179 This function is for text strings provided by the user (with the exception
2180 that pivot_value_new_variable() should be used for variable names). For
2181 strings that are part of the PSPP user interface, such as names of
2182 procedures, statistics, annotations, error messages, etc., use
2183 pivot_value_new_text().j
2185 The caller retains ownership of TEXT.*/
2186 struct pivot_value *
2187 pivot_value_new_user_text (const char *text, size_t length)
2189 return pivot_value_new_user_text_nocopy (
2190 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2193 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2194 a translatable string, but not actually translated yet, e.g. enclosed in
2195 N_(). This function is for text strings that are part of the PSPP user
2196 interface, such as names of procedures, statistics, annotations, error
2197 messages, etc. For strings that come from the user, use
2198 pivot_value_new_user_text(). */
2199 struct pivot_value *
2200 pivot_value_new_text (const char *text)
2202 char *c = xstrdup (text);
2203 char *local = xstrdup (gettext (c));
2205 struct pivot_value *value = xmalloc (sizeof *value);
2206 *value = (struct pivot_value) {
2207 .type = PIVOT_VALUE_TEXT,
2212 .user_provided = false,
2218 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2220 struct pivot_value * PRINTF_FORMAT (1, 2)
2221 pivot_value_new_text_format (const char *format, ...)
2224 va_start (args, format);
2225 char *c = xvasprintf (format, args);
2228 va_start (args, format);
2229 char *local = xvasprintf (gettext (format), args);
2232 struct pivot_value *value = xmalloc (sizeof *value);
2233 *value = (struct pivot_value) {
2234 .type = PIVOT_VALUE_TEXT,
2239 .user_provided = false,
2245 /* Returns a new pivot_value that represents X.
2247 The format to use for X is unspecified. Usually the easiest way to specify
2248 a format is through assigning a result class to one of the categories that
2249 the pivot_value will end up in. If that is not suitable, then the caller
2250 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2251 struct pivot_value *
2252 pivot_value_new_number (double x)
2254 struct pivot_value *value = xmalloc (sizeof *value);
2255 *value = (struct pivot_value) {
2256 .type = PIVOT_VALUE_NUMERIC,
2257 .numeric = { .x = x, },
2262 /* Returns a new pivot_value that represents X, formatted as an integer. */
2263 struct pivot_value *
2264 pivot_value_new_integer (double x)
2266 struct pivot_value *value = pivot_value_new_number (x);
2267 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2271 /* Returns a new pivot_value that represents VALUE, formatted as for
2273 struct pivot_value *
2274 pivot_value_new_var_value (const struct variable *variable,
2275 const union value *value)
2277 struct pivot_value *pv = pivot_value_new_value (
2278 value, var_get_width (variable), var_get_print_format (variable),
2279 var_get_encoding (variable));
2281 char *var_name = xstrdup (var_get_name (variable));
2282 if (var_is_alpha (variable))
2283 pv->string.var_name = var_name;
2285 pv->numeric.var_name = var_name;
2287 const char *label = var_lookup_value_label (variable, value);
2290 if (var_is_alpha (variable))
2291 pv->string.value_label = xstrdup (label);
2293 pv->numeric.value_label = xstrdup (label);
2299 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2300 formatted with FORMAT. For a string value, ENCODING must be its character
2302 struct pivot_value *
2303 pivot_value_new_value (const union value *value, int width,
2304 const struct fmt_spec *format, const char *encoding)
2306 struct pivot_value *pv = xzalloc (sizeof *pv);
2309 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2311 size_t n = strlen (s);
2312 while (n > 0 && s[n - 1] == ' ')
2315 pv->type = PIVOT_VALUE_STRING;
2317 pv->string.hex = format->type == FMT_AHEX;
2321 pv->type = PIVOT_VALUE_NUMERIC;
2322 pv->numeric.x = value->f;
2323 pv->numeric.format = *format;
2329 /* Returns a new pivot_value for VARIABLE. */
2330 struct pivot_value *
2331 pivot_value_new_variable (const struct variable *variable)
2333 struct pivot_value *value = xmalloc (sizeof *value);
2334 *value = (struct pivot_value) {
2335 .type = PIVOT_VALUE_VARIABLE,
2337 .var_name = xstrdup (var_get_name (variable)),
2338 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2344 /* Attaches a reference to FOOTNOTE to V. */
2346 pivot_value_add_footnote (struct pivot_value *v,
2347 const struct pivot_footnote *footnote)
2349 /* Some legacy tables include numerous duplicate footnotes. Suppress
2351 for (size_t i = 0; i < v->n_footnotes; i++)
2352 if (v->footnotes[i] == footnote)
2355 v->footnotes = xrealloc (v->footnotes,
2356 (v->n_footnotes + 1) * sizeof *v->footnotes);
2357 v->footnotes[v->n_footnotes++] = footnote;
2360 /* If VALUE is a numeric value, and RC is a result class such as
2361 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2363 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2366 if (value->type == PIVOT_VALUE_NUMERIC)
2368 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2370 value->numeric.format = *f;