1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2017, 2018 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "output/pivot-table.h"
23 #include "data/data-out.h"
24 #include "data/settings.h"
25 #include "data/value.h"
26 #include "data/variable.h"
27 #include "data/file-name.h"
28 #include "libpspp/hash-functions.h"
29 #include "libpspp/i18n.h"
30 #include "output/driver.h"
31 #include "output/spv/spv-table-look.h"
33 #include "gl/c-ctype.h"
34 #include "gl/configmake.h"
35 #include "gl/intprops.h"
36 #include "gl/minmax.h"
37 #include "gl/relocatable.h"
38 #include "gl/xalloc.h"
39 #include "gl/xmemdup0.h"
43 #define _(msgid) gettext (msgid)
44 #define N_(msgid) msgid
46 static const struct fmt_spec *pivot_table_get_format (
47 const struct pivot_table *, const char *s);
49 /* Pivot table display styling. */
51 /* Returns the name of AREA. */
53 pivot_area_to_string (enum pivot_area area)
57 case PIVOT_AREA_TITLE: return "title";
58 case PIVOT_AREA_CAPTION: return "caption";
59 case PIVOT_AREA_FOOTER: return "footer";
60 case PIVOT_AREA_CORNER: return "corner";
61 case PIVOT_AREA_COLUMN_LABELS: return "column labels";
62 case PIVOT_AREA_ROW_LABELS: return "row labels";
63 case PIVOT_AREA_DATA: return "data";
64 case PIVOT_AREA_LAYERS: return "layers";
65 case PIVOT_N_AREAS: default: return "**error**";
69 /* Returns the name of BORDER. */
71 pivot_border_to_string (enum pivot_border border)
75 case PIVOT_BORDER_TITLE:
78 case PIVOT_BORDER_OUTER_LEFT:
79 return "left outer frame";
80 case PIVOT_BORDER_OUTER_TOP:
81 return "top outer frame";
82 case PIVOT_BORDER_OUTER_RIGHT:
83 return "right outer frame";
84 case PIVOT_BORDER_OUTER_BOTTOM:
85 return "bottom outer frame";
87 case PIVOT_BORDER_INNER_LEFT:
88 return "left inner frame";
89 case PIVOT_BORDER_INNER_TOP:
90 return "top inner frame";
91 case PIVOT_BORDER_INNER_RIGHT:
92 return "right inner frame";
93 case PIVOT_BORDER_INNER_BOTTOM:
94 return "bottom inner frame";
96 case PIVOT_BORDER_DATA_LEFT:
97 return "data area left";
98 case PIVOT_BORDER_DATA_TOP:
99 return "data area top";
101 case PIVOT_BORDER_DIM_ROW_HORZ:
102 return "row label horizontal dimension border";
103 case PIVOT_BORDER_DIM_ROW_VERT:
104 return "row label vertical dimension border";
105 case PIVOT_BORDER_DIM_COL_HORZ:
106 return "column label horizontal dimension border";
107 case PIVOT_BORDER_DIM_COL_VERT:
108 return "column label vertical dimension border";
110 case PIVOT_BORDER_CAT_ROW_HORZ:
111 return "row label horizontal category border";
112 case PIVOT_BORDER_CAT_ROW_VERT:
113 return "row label vertical category border";
114 case PIVOT_BORDER_CAT_COL_HORZ:
115 return "column label horizontal category border";
116 case PIVOT_BORDER_CAT_COL_VERT:
117 return "column label vertical category border";
119 case PIVOT_N_BORDERS:
126 pivot_table_sizing_uninit (struct pivot_table_sizing *sizing)
130 free (sizing->widths);
131 free (sizing->breaks);
132 free (sizing->keeps);
136 /* Pivot table looks. */
138 static const struct pivot_table_look *
139 default_look (const struct pivot_table_look *new)
141 static struct pivot_table_look *look;
144 pivot_table_look_unref (look);
145 look = pivot_table_look_ref (new);
149 char *error = pivot_table_look_read ("default.stt", &look);
153 look = pivot_table_look_ref (pivot_table_look_builtin_default ());
159 const struct pivot_table_look *
160 pivot_table_look_get_default (void)
162 return default_look (NULL);
166 pivot_table_look_set_default (const struct pivot_table_look *look)
171 char * WARN_UNUSED_RESULT
172 pivot_table_look_read (const char *name, struct pivot_table_look **lookp)
176 /* Construct search path. */
180 const char *home = getenv ("HOME");
181 char *allocated = NULL;
183 path[n++] = allocated = xasprintf ("%s/.pspp/looks", home);
185 path[n++] = relocate2 (PKGDATADIR "/looks", &allocated2);
189 char *file = fn_search_path (name, (char **) path);
192 char *name2 = xasprintf ("%s.stt", name);
193 file = fn_search_path (name2, (char **) path);
199 return xasprintf ("%s: not found", name);
202 char *error = spv_table_look_read (file, lookp);
207 const struct pivot_table_look *
208 pivot_table_look_builtin_default (void)
210 static struct pivot_table_look look = {
214 .row_labels_in_corner = true,
216 [TABLE_HORZ] = { 36, 72 },
217 [TABLE_VERT] = { 36, 120 },
221 #define AREA(BOLD, H, V, L, R, T, B) { \
223 .halign = TABLE_HALIGN_##H, \
224 .valign = TABLE_VALIGN_##V, \
225 .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
226 [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
230 .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
231 .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
233 .typeface = (char *) "Sans Serif", \
236 [PIVOT_AREA_TITLE] = AREA(true, CENTER, CENTER, 8,11,1,8),
237 [PIVOT_AREA_CAPTION] = AREA(false, LEFT, TOP, 8,11,1,1),
238 [PIVOT_AREA_FOOTER] = AREA(false, LEFT, TOP, 11, 8,2,3),
239 [PIVOT_AREA_CORNER] = AREA(false, LEFT, BOTTOM, 8,11,1,1),
240 [PIVOT_AREA_COLUMN_LABELS] = AREA(false, CENTER, BOTTOM, 8,11,1,3),
241 [PIVOT_AREA_ROW_LABELS] = AREA(false, LEFT, TOP, 8,11,1,3),
242 [PIVOT_AREA_DATA] = AREA(false, MIXED, TOP, 8,11,1,1),
243 [PIVOT_AREA_LAYERS] = AREA(false, LEFT, BOTTOM, 8,11,1,3),
248 #define BORDER(STROKE) { .stroke = STROKE, .color = CELL_COLOR_BLACK }
249 [PIVOT_BORDER_TITLE] = BORDER(TABLE_STROKE_NONE),
250 [PIVOT_BORDER_OUTER_LEFT] = BORDER(TABLE_STROKE_NONE),
251 [PIVOT_BORDER_OUTER_TOP] = BORDER(TABLE_STROKE_NONE),
252 [PIVOT_BORDER_OUTER_RIGHT] = BORDER(TABLE_STROKE_NONE),
253 [PIVOT_BORDER_OUTER_BOTTOM] = BORDER(TABLE_STROKE_NONE),
254 [PIVOT_BORDER_INNER_LEFT] = BORDER(TABLE_STROKE_THICK),
255 [PIVOT_BORDER_INNER_TOP] = BORDER(TABLE_STROKE_THICK),
256 [PIVOT_BORDER_INNER_RIGHT] = BORDER(TABLE_STROKE_THICK),
257 [PIVOT_BORDER_INNER_BOTTOM] = BORDER(TABLE_STROKE_THICK),
258 [PIVOT_BORDER_DATA_LEFT] = BORDER(TABLE_STROKE_THICK),
259 [PIVOT_BORDER_DATA_TOP] = BORDER(TABLE_STROKE_THICK),
260 [PIVOT_BORDER_DIM_ROW_HORZ] = BORDER(TABLE_STROKE_SOLID),
261 [PIVOT_BORDER_DIM_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
262 [PIVOT_BORDER_DIM_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
263 [PIVOT_BORDER_DIM_COL_VERT] = BORDER(TABLE_STROKE_SOLID),
264 [PIVOT_BORDER_CAT_ROW_HORZ] = BORDER(TABLE_STROKE_NONE),
265 [PIVOT_BORDER_CAT_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
266 [PIVOT_BORDER_CAT_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
267 [PIVOT_BORDER_CAT_COL_VERT] = BORDER(TABLE_STROKE_SOLID),
274 struct pivot_table_look *
275 pivot_table_look_new_builtin_default (void)
277 return pivot_table_look_unshare (
278 pivot_table_look_ref (pivot_table_look_builtin_default ()));
281 struct pivot_table_look *
282 pivot_table_look_ref (const struct pivot_table_look *look_)
284 assert (look_->ref_cnt > 0);
286 struct pivot_table_look *look = CONST_CAST (struct pivot_table_look *, look_);
292 xstrdup_if_nonempty (const char *s)
294 return s && s[0] ? xstrdup (s) : NULL;
297 struct pivot_table_look *
298 pivot_table_look_unshare (struct pivot_table_look *old)
300 assert (old->ref_cnt > 0);
301 if (old->ref_cnt == 1)
304 pivot_table_look_unref (old);
306 struct pivot_table_look *new = xmemdup (old, sizeof *old);
308 new->name = xstrdup_if_nonempty (old->name);
309 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
310 table_area_style_copy (NULL, &new->areas[i], &old->areas[i]);
311 new->continuation = xstrdup_if_nonempty (old->continuation);
317 pivot_table_look_unref (struct pivot_table_look *look)
321 assert (look->ref_cnt > 0);
322 if (!--look->ref_cnt)
325 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
326 table_area_style_uninit (&look->areas[i]);
327 free (look->continuation);
335 /* Returns the name of AXIS_TYPE. */
337 pivot_axis_type_to_string (enum pivot_axis_type axis_type)
341 case PIVOT_AXIS_LAYER:
347 case PIVOT_AXIS_COLUMN:
355 static enum pivot_axis_type
356 pivot_axis_type_transpose (enum pivot_axis_type axis_type)
358 assert (axis_type == PIVOT_AXIS_ROW || axis_type == PIVOT_AXIS_COLUMN);
359 return (axis_type == PIVOT_AXIS_ROW ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW);
362 /* Implementation of PIVOT_AXIS_FOR_EACH. */
364 pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis)
368 if (axis->n_dimensions)
369 for (size_t i = 0; i < axis->n_dimensions; i++)
370 if (axis->dimensions[i]->n_leaves == 0)
373 size_t size = axis->n_dimensions * sizeof *indexes;
374 return xzalloc (MAX (size, 1));
377 for (size_t i = 0; i < axis->n_dimensions; i++)
379 const struct pivot_dimension *d = axis->dimensions[i];
380 if (++indexes[i] < d->n_leaves)
393 pivot_category_set_rc (struct pivot_category *category, const char *s)
395 const struct fmt_spec *format = pivot_table_get_format (
396 category->dimension->table, s);
398 category->format = *format;
402 pivot_category_create_leaves_valist (struct pivot_category *parent,
406 while ((s = va_arg (args, const char *)))
408 if (!strncmp (s, "RC_", 3))
410 assert (parent->n_subs);
411 pivot_category_set_rc (parent->subs[parent->n_subs - 1], s);
414 pivot_category_create_leaf (parent, pivot_value_new_text (s));
418 /* Creates a new dimension with the given NAME in TABLE and returns it. The
419 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
422 NAME should be a translatable name, but not actually translated yet,
423 e.g. enclosed in N_(). To use a different kind of value for a name, use
424 pivot_dimension_create__() instead.
426 The optional varargs parameters may be used to add an initial set of
427 categories to the dimension. Each string should be a translatable category
428 name, but not actually translated yet, e.g. enclosed in N_(). Each string
429 may optionally be followod by a PIVOT_RC_* string that specifies the default
430 numeric format for cells in this category. */
431 struct pivot_dimension * SENTINEL (0)
432 (pivot_dimension_create) (struct pivot_table *table,
433 enum pivot_axis_type axis_type,
434 const char *name, ...)
436 struct pivot_dimension *d = pivot_dimension_create__ (
437 table, axis_type, pivot_value_new_text (name));
440 va_start (args, name);
441 pivot_category_create_leaves_valist (d->root, args);
447 /* Creates a new dimension with the given NAME in TABLE and returns it. The
448 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
450 struct pivot_dimension *
451 pivot_dimension_create__ (struct pivot_table *table,
452 enum pivot_axis_type axis_type,
453 struct pivot_value *name)
455 assert (pivot_table_is_empty (table));
457 struct pivot_dimension *d = xmalloc (sizeof *d);
458 *d = (struct pivot_dimension) {
460 .axis_type = axis_type,
461 .level = table->axes[axis_type].n_dimensions,
462 .top_index = table->n_dimensions,
463 .root = xmalloc (sizeof *d->root),
466 struct pivot_category *root = d->root;
467 *root = (struct pivot_category) {
472 .data_index = SIZE_MAX,
473 .presentation_index = SIZE_MAX,
476 table->dimensions = xrealloc (
477 table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions);
478 table->dimensions[table->n_dimensions++] = d;
480 struct pivot_axis *axis = &table->axes[axis_type];
481 axis->dimensions = xrealloc (
482 axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
483 axis->dimensions[axis->n_dimensions++] = d;
485 if (axis_type == PIVOT_AXIS_LAYER)
487 free (table->current_layer);
488 table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
489 sizeof *table->current_layer);
492 /* axis->extent and axis->label_depth will be calculated later. */
498 pivot_dimension_destroy (struct pivot_dimension *d)
503 pivot_category_destroy (d->root);
504 free (d->data_leaves);
505 free (d->presentation_leaves);
509 /* Returns the first leaf node in an in-order traversal that is a child of
511 static const struct pivot_category * UNUSED
512 pivot_category_first_leaf (const struct pivot_category *cat)
514 if (pivot_category_is_leaf (cat))
517 for (size_t i = 0; i < cat->n_subs; i++)
519 const struct pivot_category *first
520 = pivot_category_first_leaf (cat->subs[i]);
528 /* Returns the next leaf node in an in-order traversal starting at CAT, which
530 static const struct pivot_category * UNUSED
531 pivot_category_next_leaf (const struct pivot_category *cat)
533 assert (pivot_category_is_leaf (cat));
537 const struct pivot_category *parent = cat->parent;
540 for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
542 const struct pivot_category *next
543 = pivot_category_first_leaf (parent->subs[i]);
553 pivot_category_add_child (struct pivot_category *child)
555 struct pivot_category *parent = child->parent;
557 assert (pivot_category_is_group (parent));
558 if (parent->n_subs >= parent->allocated_subs)
559 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
560 sizeof *parent->subs);
561 parent->subs[parent->n_subs++] = child;
564 /* Adds leaf categories as a child of PARENT. To create top-level categories
565 within dimension 'd', pass 'd->root' for PARENT.
567 Each of the varargs parameters should be a string, each of which should be a
568 translatable category name, but not actually translated yet, e.g. enclosed
569 in N_(). Each string may optionally be followod by a PIVOT_RC_* string that
570 specifies the default numeric format for cells in this category.
572 Returns the category index, which is just a 0-based array index, for the
575 Leaves have to be created in in-order, that is, don't create a group and add
576 some leaves, then add leaves outside the group and try to add more leaves
579 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
581 int retval = parent->dimension->n_leaves;
584 va_start (args, parent);
585 pivot_category_create_leaves_valist (parent, args);
591 /* Creates a new leaf category with the given NAME as a child of PARENT. To
592 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
593 Returns the category index, which is just a 0-based array index, for the new
596 Leaves have to be created in in-order, that is, don't create a group and add
597 some leaves, then add leaves outside the group and try to add more leaves
600 pivot_category_create_leaf (struct pivot_category *parent,
601 struct pivot_value *name)
603 return pivot_category_create_leaf_rc (parent, name, NULL);
606 /* Creates a new leaf category with the given NAME as a child of PARENT. To
607 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
608 Returns the category index, which is just a 0-based array index, for the new
611 If RC is nonnull and the name of a result category, the category is assigned
612 that result category.
614 Leaves have to be created in in-order, that is, don't create a group and add
615 some leaves, then add leaves outside the group and try to add more leaves
618 pivot_category_create_leaf_rc (struct pivot_category *parent,
619 struct pivot_value *name, const char *rc)
621 struct pivot_dimension *d = parent->dimension;
623 struct pivot_category *leaf = xmalloc (sizeof *leaf);
624 *leaf = (struct pivot_category) {
628 .group_index = parent->n_subs,
629 .data_index = d->n_leaves,
630 .presentation_index = d->n_leaves,
633 if (d->n_leaves >= d->allocated_leaves)
635 d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
636 sizeof *d->data_leaves);
637 d->presentation_leaves = xrealloc (
638 d->presentation_leaves,
639 d->allocated_leaves * sizeof *d->presentation_leaves);
642 d->data_leaves[d->n_leaves] = leaf;
643 d->presentation_leaves[d->n_leaves] = leaf;
646 pivot_category_add_child (leaf);
648 /* Make sure that the new child is the last in in-order. */
649 assert (!pivot_category_next_leaf (leaf));
651 pivot_category_set_rc (leaf, rc);
653 return leaf->data_index;
656 /* Adds a new category group named NAME as a child of PARENT. To create a
657 top-level group within dimension 'd', pass 'd->root' for PARENT.
659 NAME should be a translatable name, but not actually translated yet,
660 e.g. enclosed in N_(). To use a different kind of value for a name, use
661 pivot_category_create_group__() instead.
663 The optional varargs parameters may be used to add an initial set of
664 categories to the group. Each string should be a translatable category
665 name, but not actually translated yet, e.g. enclosed in N_(). Each string
666 may optionally be followod by a PIVOT_RC_* string that specifies the default
667 numeric format for cells in this category.
669 Returns the new group. */
670 struct pivot_category * SENTINEL (0)
671 (pivot_category_create_group) (struct pivot_category *parent,
672 const char *name, ...)
674 struct pivot_category *group = pivot_category_create_group__ (
675 parent, pivot_value_new_text (name));
678 va_start (args, name);
679 pivot_category_create_leaves_valist (group, args);
685 /* Adds a new category group named NAME as a child of PARENT. To create a
686 top-level group within dimension 'd', pass 'd->root' for PARENT. Returns
688 struct pivot_category *
689 pivot_category_create_group__ (struct pivot_category *parent,
690 struct pivot_value *name)
692 struct pivot_dimension *d = parent->dimension;
694 struct pivot_category *group = xmalloc (sizeof *group);
695 *group = (struct pivot_category) {
700 .group_index = parent->n_subs,
701 .data_index = SIZE_MAX,
702 .presentation_index = SIZE_MAX,
705 pivot_category_add_child (group);
711 pivot_category_destroy (struct pivot_category *c)
716 pivot_value_destroy (c->name);
717 for (size_t i = 0; i < c->n_subs; i++)
718 pivot_category_destroy (c->subs[i]);
725 These are usually the easiest way to control the formatting of numeric data
726 in a pivot table. See pivot_dimension_create() for an explanation of their
730 const char *name; /* "RC_*". */
731 struct fmt_spec format;
734 /* Formats for most of the result classes. */
735 static struct result_class result_classes[] =
737 { PIVOT_RC_INTEGER, { FMT_F, 40, 0 } },
738 { PIVOT_RC_PERCENT, { FMT_PCT, 40, 1 } },
739 { PIVOT_RC_CORRELATION, { FMT_F, 40, 3 } },
740 { PIVOT_RC_SIGNIFICANCE, { FMT_F, 40, 3 } },
741 { PIVOT_RC_RESIDUAL, { FMT_F, 40, 2 } },
742 { PIVOT_RC_COUNT, { 0, 0, 0 } },
743 { PIVOT_RC_OTHER, { 0, 0, 0 } },
746 /* Has PIVOT_RC_COUNT been overridden by the user? */
747 static bool overridden_count_format;
749 static struct result_class *
750 pivot_result_class_find (const char *s)
752 for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
753 if (!strcmp (s, result_classes[i].name))
754 return &result_classes[i];
758 static const struct fmt_spec *
759 pivot_table_get_format (const struct pivot_table *table, const char *s)
763 else if (!strcmp (s, PIVOT_RC_OTHER))
764 return settings_get_format ();
765 else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
766 return &table->weight_format;
769 const struct result_class *rc = pivot_result_class_find (s);
770 return rc ? &rc->format : NULL;
774 /* Sets the format specification for the result class named S (which should not
775 include the RC_ prefix) to *FORMAT. Returns true if successful, false if S
776 does not name a known result class. */
778 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
780 char *s = xasprintf ("RC_%s", s_);
781 struct result_class *rc = pivot_result_class_find (s);
784 rc->format = *format;
785 if (!strcmp (s, PIVOT_RC_COUNT))
786 overridden_count_format = true;
795 /* Creates and returns a new pivot table with the given TITLE. TITLE should be
796 a text string marked for translation but not actually translated yet,
797 e.g. N_("Descriptive Statistics"). The un-translated text string is used as
798 the pivot table's subtype.
800 Operations commonly performed on the new pivot_table:
802 - If empty rows or columns should not be displayed, set ->omit_empty to
805 - Set the format to use for "count" values with pivot_table_set_weight_var()
806 or pivot_table_set_weight_format().
808 This function is a shortcut for pivot_table_create__() for the most common
809 case. Use pivot_table_create__() directly if the title should be some kind
810 of value other than an ordinary text string, or if the subtype should be
811 different from the title.
813 See the large comment at the top of pivot-table.h for general advice on
814 creating pivot tables. */
816 pivot_table_create (const char *title)
818 return pivot_table_create__ (pivot_value_new_text (title), title);
821 /* Creates and returns a new pivot table with the given TITLE, and takes
822 ownership of TITLE. The new pivot table's subtype is SUBTYPE, which
823 should be an untranslated English string that describes the contents of
824 the table at a high level without being specific about the variables or
825 other context involved.
827 Operations commonly performed on the new pivot_table:
829 - If empty rows or columns should not be displayed, set ->omit_empty to
832 - Set the format to use for "count" values with pivot_table_set_weight_var()
833 or pivot_table_set_weight_format().
835 See the large comment at the top of pivot-table.h for general advice on
836 creating pivot tables. */
838 pivot_table_create__ (struct pivot_value *title, const char *subtype)
840 struct pivot_table *table = xzalloc (sizeof *table);
842 table->show_title = true;
843 table->show_caption = true;
844 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
845 table->title = title;
846 table->subtype = subtype ? pivot_value_new_text (subtype) : NULL;
847 table->command_c = output_get_command_name ();
848 table->look = pivot_table_look_ref (pivot_table_look_get_default ());
850 hmap_init (&table->cells);
855 /* Creates and returns a new pivot table with the given TITLE and a single cell
856 with the given CONTENT.
858 This is really just for error handling. */
860 pivot_table_create_for_text (struct pivot_value *title,
861 struct pivot_value *content)
863 struct pivot_table *table = pivot_table_create__ (title, "Error");
865 struct pivot_dimension *d = pivot_dimension_create (
866 table, PIVOT_AXIS_ROW, N_("Error"));
867 d->hide_all_labels = true;
868 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
870 pivot_table_put1 (table, 0, content);
875 /* Increases TABLE's reference count, indicating that it has an additional
876 owner. A pivot table that is shared among multiple owners must not be
879 pivot_table_ref (const struct pivot_table *table_)
881 struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
886 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
887 If TABLE no longer has any owners, it is freed. */
889 pivot_table_unref (struct pivot_table *table)
893 assert (table->ref_cnt > 0);
894 if (--table->ref_cnt)
897 free (table->current_layer);
898 pivot_table_look_unref (table->look);
900 for (int i = 0; i < TABLE_N_AXES; i++)
901 pivot_table_sizing_uninit (&table->sizing[i]);
903 for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
904 free (table->ccs[i]);
906 free (table->command_local);
907 free (table->command_c);
908 free (table->language);
909 free (table->locale);
911 free (table->dataset);
912 free (table->datafile);
914 for (size_t i = 0; i < table->n_footnotes; i++)
915 pivot_footnote_destroy (table->footnotes[i]);
916 free (table->footnotes);
918 pivot_value_destroy (table->title);
919 pivot_value_destroy (table->subtype);
920 pivot_value_destroy (table->corner_text);
921 pivot_value_destroy (table->caption);
923 for (size_t i = 0; i < table->n_dimensions; i++)
924 pivot_dimension_destroy (table->dimensions[i]);
925 free (table->dimensions);
927 for (size_t i = 0; i < PIVOT_N_AXES; i++)
928 free (table->axes[i].dimensions);
930 struct pivot_cell *cell, *next_cell;
931 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
934 hmap_delete (&table->cells, &cell->hmap_node);
935 pivot_value_destroy (cell->value);
938 hmap_destroy (&table->cells);
943 /* Returns true if TABLE has more than one owner. A pivot table that is shared
944 among multiple owners must not be modified. */
946 pivot_table_is_shared (const struct pivot_table *table)
948 return table->ref_cnt > 1;
951 const struct pivot_table_look *
952 pivot_table_get_look (const struct pivot_table *table)
958 pivot_table_set_look (struct pivot_table *table,
959 const struct pivot_table_look *look)
961 pivot_table_look_unref (table->look);
962 table->look = pivot_table_look_ref (look);
965 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
966 WV, which should be the weight variable for the dictionary whose data or
967 statistics are being put into TABLE.
969 This has no effect if WV is NULL. */
971 pivot_table_set_weight_var (struct pivot_table *table,
972 const struct variable *wv)
975 pivot_table_set_weight_format (table, var_get_print_format (wv));
978 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
979 format for the dictionary whose data or statistics are being put into TABLE.
981 This has no effect if WFMT is NULL. */
983 pivot_table_set_weight_format (struct pivot_table *table,
984 const struct fmt_spec *wfmt)
987 table->weight_format = *wfmt;
990 /* Returns true if TABLE has no cells, false otherwise. */
992 pivot_table_is_empty (const struct pivot_table *table)
994 return hmap_is_empty (&table->cells);
998 pivot_table_next_display_layer (const struct pivot_table *pt, size_t *indexes,
1001 const struct pivot_axis *layer_axis = &pt->axes[PIVOT_AXIS_LAYER];
1002 if (print && pt->look->print_all_layers)
1003 return pivot_axis_iterator_next (indexes, layer_axis);
1006 size_t size = layer_axis->n_dimensions * sizeof *pt->current_layer;
1007 return xmemdup (pt->current_layer, MAX (size, 1));
1017 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
1019 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
1023 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
1025 for (size_t i = 0; i < n; i++)
1032 static struct pivot_cell *
1033 pivot_table_lookup_cell__ (const struct pivot_table *table,
1034 const size_t *dindexes, unsigned int hash)
1036 struct pivot_cell *cell;
1037 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
1039 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
1044 static struct pivot_cell *
1045 pivot_cell_allocate (size_t n_idx)
1047 struct pivot_cell *cell UNUSED;
1048 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
1051 static struct pivot_cell *
1052 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
1054 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1055 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
1058 cell = pivot_cell_allocate (table->n_dimensions);
1059 for (size_t i = 0; i < table->n_dimensions; i++)
1060 cell->idx[i] = dindexes[i];
1062 hmap_insert (&table->cells, &cell->hmap_node, hash);
1067 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
1068 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
1071 If VALUE is a numeric value without a specified format, this function checks
1072 each of the categories designated by DINDEXES[] and takes the format from
1073 the first category with a result class. If none has a result class, uses
1074 the overall default numeric format. */
1076 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
1077 struct pivot_value *value)
1079 assert (n == table->n_dimensions);
1081 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
1083 for (size_t i = 0; i < table->n_dimensions; i++)
1085 const struct pivot_dimension *d = table->dimensions[i];
1086 if (dindexes[i] < d->n_leaves)
1088 const struct pivot_category *c = d->data_leaves[dindexes[i]];
1091 value->numeric.format = c->format;
1096 value->numeric.format = *settings_get_format ();
1101 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1102 pivot_value_destroy (cell->value);
1103 cell->value = value;
1106 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
1107 dimension. Takes ownership of VALUE. */
1109 pivot_table_put1 (struct pivot_table *table, size_t idx1,
1110 struct pivot_value *value)
1112 size_t dindexes[] = { idx1 };
1113 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1116 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
1117 dimensions. Takes ownership of VALUE. */
1119 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
1120 struct pivot_value *value)
1122 size_t dindexes[] = { idx1, idx2 };
1123 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1126 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
1127 have 3 dimensions. Takes ownership of VALUE. */
1129 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
1130 size_t idx3, struct pivot_value *value)
1132 size_t dindexes[] = { idx1, idx2, idx3 };
1133 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1136 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
1137 must have 4 dimensions. Takes ownership of VALUE. */
1139 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1140 size_t idx3, size_t idx4, struct pivot_value *value)
1142 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1143 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1146 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1147 automatically assigned marker.
1149 The footnote will only appear in output if it is referenced. Use
1150 pivot_value_add_footnote() to add a reference to the footnote. */
1151 struct pivot_footnote *
1152 pivot_table_create_footnote (struct pivot_table *table,
1153 struct pivot_value *content)
1155 return pivot_table_create_footnote__ (table, table->n_footnotes,
1159 static struct pivot_value *
1160 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1162 char text[INT_BUFSIZE_BOUND (size_t)];
1163 if (show_numeric_markers)
1164 snprintf (text, sizeof text, "%d", idx + 1);
1166 str_format_26adic (idx + 1, false, text, sizeof text);
1167 return pivot_value_new_user_text (text, -1);
1170 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1171 all lower indexes as a side effect). If MARKER is nonnull, sets the
1172 footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1173 struct pivot_footnote *
1174 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1175 struct pivot_value *marker,
1176 struct pivot_value *content)
1178 if (idx >= table->n_footnotes)
1180 while (idx >= table->allocated_footnotes)
1181 table->footnotes = x2nrealloc (table->footnotes,
1182 &table->allocated_footnotes,
1183 sizeof *table->footnotes);
1184 while (idx >= table->n_footnotes)
1186 struct pivot_footnote *f = xmalloc (sizeof *f);
1187 f->idx = table->n_footnotes;
1188 f->marker = pivot_make_default_footnote_marker (
1189 f->idx, table->look->show_numeric_markers);
1193 table->footnotes[table->n_footnotes++] = f;
1197 struct pivot_footnote *f = table->footnotes[idx];
1200 pivot_value_destroy (f->marker);
1205 pivot_value_destroy (f->content);
1206 f->content = content;
1211 /* Frees the data owned by F. */
1213 pivot_footnote_destroy (struct pivot_footnote *f)
1217 pivot_value_destroy (f->content);
1218 pivot_value_destroy (f->marker);
1223 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1224 indexes for each dimension in TABLE in DINDEXES[]. */
1226 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1227 const size_t *pindexes[PIVOT_N_AXES],
1228 size_t dindexes[/* table->n_dimensions */])
1230 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1232 const struct pivot_axis *axis = &table->axes[i];
1234 for (size_t j = 0; j < axis->n_dimensions; j++)
1236 const struct pivot_dimension *d = axis->dimensions[j];
1237 dindexes[d->top_index]
1238 = d->presentation_leaves[pindexes[i][j]]->data_index;
1244 pivot_table_enumerate_axis (const struct pivot_table *table,
1245 enum pivot_axis_type axis_type,
1246 const size_t *layer_indexes, bool omit_empty,
1249 const struct pivot_axis *axis = &table->axes[axis_type];
1250 if (!axis->n_dimensions)
1252 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1254 enumeration[1] = SIZE_MAX;
1259 else if (!axis->extent)
1261 size_t *enumeration = xmalloc (sizeof *enumeration);
1262 *enumeration = SIZE_MAX;
1268 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1269 axis->n_dimensions), 1),
1270 sizeof *enumeration);
1271 size_t *p = enumeration;
1272 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1274 size_t *axis_indexes;
1275 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1279 enum pivot_axis_type axis2_type
1280 = pivot_axis_type_transpose (axis_type);
1282 size_t *axis2_indexes;
1283 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1285 const size_t *pindexes[PIVOT_N_AXES];
1286 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1287 pindexes[axis_type] = axis_indexes;
1288 pindexes[axis2_type] = axis2_indexes;
1289 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1290 if (pivot_table_get (table, dindexes))
1296 free (axis2_indexes);
1299 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1300 p += axis->n_dimensions;
1302 if (omit_empty && p == enumeration)
1304 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1306 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1307 p += axis->n_dimensions;
1312 *n = (p - enumeration) / axis->n_dimensions;
1318 static const struct pivot_cell *
1319 pivot_table_lookup_cell (const struct pivot_table *table,
1320 const size_t *dindexes)
1322 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1323 return pivot_table_lookup_cell__ (table, dindexes, hash);
1326 const struct pivot_value *
1327 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1329 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1330 return cell ? cell->value : NULL;
1333 struct pivot_value *
1334 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1336 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1338 cell->value = pivot_value_new_user_text ("", -1);
1343 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1345 if (pivot_category_is_group (category) && category->n_subs)
1346 for (size_t i = 0; i < category->n_subs; i++)
1347 distribute_extra_depth (category->subs[i], extra_depth);
1349 category->extra_depth += extra_depth;
1353 pivot_category_assign_label_depth (struct pivot_category *category,
1354 bool dimension_labels_in_corner)
1356 category->extra_depth = 0;
1358 if (pivot_category_is_group (category))
1361 for (size_t i = 0; i < category->n_subs; i++)
1363 pivot_category_assign_label_depth (category->subs[i], false);
1364 depth = MAX (depth, category->subs[i]->label_depth);
1367 for (size_t i = 0; i < category->n_subs; i++)
1369 struct pivot_category *sub = category->subs[i];
1371 size_t extra_depth = depth - sub->label_depth;
1373 distribute_extra_depth (sub, extra_depth);
1375 sub->label_depth = depth;
1378 category->show_label_in_corner = (category->show_label
1379 && dimension_labels_in_corner);
1380 category->label_depth
1381 = (category->show_label && !category->show_label_in_corner
1382 ? depth + 1 : depth);
1385 category->label_depth = 1;
1389 pivot_axis_assign_label_depth (struct pivot_table *table,
1390 enum pivot_axis_type axis_type,
1391 bool dimension_labels_in_corner)
1393 struct pivot_axis *axis = &table->axes[axis_type];
1394 bool any_label_shown_in_corner = false;
1395 axis->label_depth = 0;
1397 for (size_t i = 0; i < axis->n_dimensions; i++)
1399 struct pivot_dimension *d = axis->dimensions[i];
1400 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1401 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1402 axis->label_depth += d->label_depth;
1403 axis->extent *= d->n_leaves;
1405 if (d->root->show_label_in_corner)
1406 any_label_shown_in_corner = true;
1408 return any_label_shown_in_corner;
1412 pivot_table_assign_label_depth (struct pivot_table *table)
1414 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1415 if (pivot_axis_assign_label_depth (
1416 table, PIVOT_AXIS_ROW, (table->look->row_labels_in_corner
1417 && !table->corner_text))
1418 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1419 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1420 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1428 indent (int indentation)
1430 for (int i = 0; i < indentation * 2; i++)
1435 pivot_value_dump (const struct pivot_value *value)
1437 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1438 SETTINGS_VALUE_SHOW_DEFAULT);
1444 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1449 indent (indentation);
1450 printf ("%s: ", name);
1451 pivot_value_dump (value);
1457 pivot_table_dump_string (const char *string, const char *name, int indentation)
1461 indent (indentation);
1462 printf ("%s: %s\n", name, string);
1467 pivot_category_dump (const struct pivot_category *c, int indentation)
1469 indent (indentation);
1470 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1471 pivot_value_dump (c->name);
1474 if (pivot_category_is_leaf (c))
1475 printf ("data_index=%zu\n", c->data_index);
1478 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1481 for (size_t i = 0; i < c->n_subs; i++)
1482 pivot_category_dump (c->subs[i], indentation + 1);
1487 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1489 indent (indentation);
1490 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1491 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1493 pivot_category_dump (d->root, indentation + 1);
1497 table_area_style_dump (enum pivot_area area, const struct table_area_style *a,
1500 indent (indentation);
1501 printf ("%s: ", pivot_area_to_string (area));
1502 font_style_dump (&a->font_style);
1504 cell_style_dump (&a->cell_style);
1509 table_border_style_dump (enum pivot_border border,
1510 const struct table_border_style *b, int indentation)
1512 indent (indentation);
1513 printf ("%s: %s ", pivot_border_to_string (border),
1514 table_stroke_to_string (b->stroke));
1515 cell_color_dump (&b->color);
1520 compose_headings (const struct pivot_axis *axis,
1521 const size_t *column_enumeration,
1522 enum settings_value_show show_values,
1523 enum settings_value_show show_variables)
1525 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1528 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1529 for (size_t i = 0; i < axis->label_depth; i++)
1530 headings[i] = xcalloc (axis->extent, sizeof **headings);
1532 const size_t *indexes;
1534 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1536 int row = axis->label_depth - 1;
1537 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1539 const struct pivot_dimension *d = axis->dimensions[dim_index];
1540 if (d->hide_all_labels)
1542 for (const struct pivot_category *c
1543 = d->presentation_leaves[indexes[dim_index]];
1547 if (pivot_category_is_leaf (c) || (c->show_label
1548 && !c->show_label_in_corner))
1550 headings[row][column] = pivot_value_to_string (
1551 c->name, show_values, show_variables);
1552 if (!*headings[row][column])
1553 headings[row][column] = xstrdup ("<blank>");
1565 free_headings (const struct pivot_axis *axis, char ***headings)
1567 for (size_t i = 0; i < axis->label_depth; i++)
1569 for (size_t j = 0; j < axis->extent; j++)
1570 free (headings[i][j]);
1577 pivot_table_sizing_dump (const char *name,
1578 const int width_ranges[2],
1579 const struct pivot_table_sizing *s,
1582 indent (indentation);
1583 printf ("%ss: min=%d, max=%d\n", name, width_ranges[0], width_ranges[1]);
1586 indent (indentation + 1);
1587 printf ("%s widths:", name);
1588 for (size_t i = 0; i < s->n_widths; i++)
1589 printf (" %d", s->widths[i]);
1594 indent (indentation + 1);
1595 printf ("break after %ss:", name);
1596 for (size_t i = 0; i < s->n_breaks; i++)
1597 printf (" %zu", s->breaks[i]);
1602 indent (indentation + 1);
1603 printf ("keep %ss together:", name);
1604 for (size_t i = 0; i < s->n_keeps; i++)
1605 printf (" [%zu,%zu]",
1607 s->keeps[i].ofs + s->keeps[i].n - 1);
1613 pivot_table_dump (const struct pivot_table *table, int indentation)
1618 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1619 if (table->decimal == '.' || table->decimal == ',')
1620 settings_set_decimal_char (table->decimal);
1622 pivot_table_dump_value (table->title, "title", indentation);
1623 pivot_table_dump_value (table->subtype, "subtype", indentation);
1624 pivot_table_dump_string (table->command_c, "command", indentation);
1625 pivot_table_dump_string (table->dataset, "dataset", indentation);
1626 pivot_table_dump_string (table->datafile, "datafile", indentation);
1627 pivot_table_dump_string (table->notes, "notes", indentation);
1628 pivot_table_dump_string (table->look->name, "table-look", indentation);
1631 indent (indentation);
1633 struct tm *tm = localtime (&table->date);
1634 printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
1635 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
1639 indent (indentation);
1640 printf ("sizing:\n");
1641 pivot_table_sizing_dump ("column", table->look->width_ranges[TABLE_HORZ],
1642 &table->sizing[TABLE_HORZ], indentation + 1);
1643 pivot_table_sizing_dump ("row", table->look->width_ranges[TABLE_VERT],
1644 &table->sizing[TABLE_VERT], indentation + 1);
1646 indent (indentation);
1647 printf ("areas:\n");
1648 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1649 table_area_style_dump (area, &table->look->areas[area], indentation + 1);
1651 indent (indentation);
1652 printf ("borders:\n");
1653 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1654 table_border_style_dump (border, &table->look->borders[border],
1657 for (size_t i = 0; i < table->n_dimensions; i++)
1658 pivot_dimension_dump (table->dimensions[i], indentation);
1660 /* Presentation and data indexes. */
1661 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1663 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1664 if (layer_axis->n_dimensions)
1666 indent (indentation);
1667 printf ("current layer:");
1669 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1671 const struct pivot_dimension *d = layer_axis->dimensions[i];
1672 char *name = pivot_value_to_string (d->root->name,
1674 table->show_variables);
1675 char *value = pivot_value_to_string (
1676 d->data_leaves[table->current_layer[i]]->name,
1677 table->show_values, table->show_variables);
1678 printf (" %s=%s", name, value);
1686 size_t *layer_indexes;
1687 size_t layer_iteration = 0;
1688 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1690 indent (indentation);
1691 printf ("layer %zu:", layer_iteration++);
1693 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1694 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1696 const struct pivot_dimension *d = layer_axis->dimensions[i];
1698 fputs (i == 0 ? " " : ", ", stdout);
1699 pivot_value_dump (d->root->name);
1700 fputs (" =", stdout);
1702 struct pivot_value **names = xnmalloc (d->n_leaves, sizeof *names);
1704 for (const struct pivot_category *c
1705 = d->presentation_leaves[layer_indexes[i]];
1709 if (pivot_category_is_leaf (c) || c->show_label)
1710 names[n_names++] = c->name;
1713 for (size_t i = n_names; i-- > 0;)
1716 pivot_value_dump (names[i]);
1722 size_t *column_enumeration = pivot_table_enumerate_axis (
1723 table, PIVOT_AXIS_COLUMN, layer_indexes, table->look->omit_empty, NULL);
1724 size_t *row_enumeration = pivot_table_enumerate_axis (
1725 table, PIVOT_AXIS_ROW, layer_indexes, table->look->omit_empty, NULL);
1727 char ***column_headings = compose_headings (
1728 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1729 table->show_values, table->show_variables);
1730 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1732 indent (indentation + 1);
1733 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1736 fputs ("; ", stdout);
1737 if (column_headings[y][x])
1738 fputs (column_headings[y][x], stdout);
1742 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1744 indent (indentation + 1);
1745 printf ("-----------------------------------------------\n");
1747 char ***row_headings = compose_headings (
1748 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1749 table->show_values, table->show_variables);
1752 const size_t *pindexes[PIVOT_N_AXES]
1753 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1754 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1755 &table->axes[PIVOT_AXIS_ROW])
1757 indent (indentation + 1);
1760 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1763 fputs ("; ", stdout);
1764 if (row_headings[y][x])
1765 fputs (row_headings[y][x], stdout);
1771 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1773 &table->axes[PIVOT_AXIS_COLUMN])
1778 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1779 const struct pivot_value *value = pivot_table_get (
1782 pivot_value_dump (value);
1789 free (column_enumeration);
1790 free (row_enumeration);
1791 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1794 pivot_table_dump_value (table->caption, "caption", indentation);
1796 for (size_t i = 0; i < table->n_footnotes; i++)
1798 const struct pivot_footnote *f = table->footnotes[i];
1799 indent (indentation);
1802 pivot_value_dump (f->marker);
1804 printf ("%zu", f->idx);
1806 pivot_value_dump (f->content);
1811 settings_set_decimal_char (old_decimal);
1815 consume_int (const char *p, size_t *n)
1818 while (c_isdigit (*p))
1819 *n = *n * 10 + (*p++ - '0');
1824 pivot_format_inner_template (struct string *out, const char *template,
1826 struct pivot_value **values, size_t n_values,
1827 enum settings_value_show show_values,
1828 enum settings_value_show show_variables)
1830 size_t args_consumed = 0;
1831 while (*template && *template != ':')
1833 if (*template == '\\' && template[1])
1835 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1838 else if (*template == escape)
1841 template = consume_int (template + 1, &index);
1842 if (index >= 1 && index <= n_values)
1844 pivot_value_format (values[index - 1], show_values,
1845 show_variables, out);
1846 args_consumed = MAX (args_consumed, index);
1850 ds_put_byte (out, *template++);
1852 return args_consumed;
1856 pivot_extract_inner_template (const char *template, const char **p)
1862 if (*template == '\\' && template[1] != '\0')
1864 else if (*template == ':')
1865 return template + 1;
1866 else if (*template == '\0')
1874 pivot_format_template (struct string *out, const char *template,
1875 const struct pivot_argument *args, size_t n_args,
1876 enum settings_value_show show_values,
1877 enum settings_value_show show_variables)
1881 if (*template == '\\' && template[1] != '\0')
1883 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1886 else if (*template == '^')
1889 template = consume_int (template + 1, &index);
1890 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1891 pivot_value_format (args[index - 1].values[0],
1892 show_values, show_variables, out);
1894 else if (*template == '[')
1896 const char *tmpl[2];
1897 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1898 template = pivot_extract_inner_template (template, &tmpl[1]);
1899 template += *template == ']';
1902 template = consume_int (template, &index);
1903 if (index < 1 || index > n_args)
1906 const struct pivot_argument *arg = &args[index - 1];
1907 size_t left = arg->n;
1910 struct pivot_value **values = arg->values + (arg->n - left);
1911 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1912 char escape = "%^"[tmpl_idx];
1913 size_t used = pivot_format_inner_template (
1914 out, tmpl[tmpl_idx], escape, values, left,
1915 show_values, show_variables);
1916 if (!used || used > left)
1922 ds_put_byte (out, *template++);
1926 static enum settings_value_show
1927 interpret_show (enum settings_value_show global_show,
1928 enum settings_value_show table_show,
1929 enum settings_value_show value_show,
1932 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1933 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1934 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1938 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1939 SHOW_VARIABLES control whether variable and value labels are included.
1941 The "body" omits subscripts and superscripts and footnotes. */
1943 pivot_value_format_body (const struct pivot_value *value,
1944 enum settings_value_show show_values,
1945 enum settings_value_show show_variables,
1948 enum settings_value_show show;
1949 bool numeric = false;
1951 switch (value->type)
1953 case PIVOT_VALUE_NUMERIC:
1954 show = interpret_show (settings_get_show_values (),
1956 value->numeric.show,
1957 value->numeric.value_label != NULL);
1958 if (show & SETTINGS_VALUE_SHOW_VALUE)
1960 char *s = data_out (&(union value) { .f = value->numeric.x },
1961 "UTF-8", &value->numeric.format);
1962 ds_put_cstr (out, s + strspn (s, " "));
1965 if (show & SETTINGS_VALUE_SHOW_LABEL)
1967 if (show & SETTINGS_VALUE_SHOW_VALUE)
1968 ds_put_byte (out, ' ');
1969 ds_put_cstr (out, value->numeric.value_label);
1971 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1974 case PIVOT_VALUE_STRING:
1975 show = interpret_show (settings_get_show_values (),
1978 value->string.value_label != NULL);
1979 if (show & SETTINGS_VALUE_SHOW_VALUE)
1981 if (value->string.hex)
1983 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1985 ds_put_format (out, "%02X", *p);
1988 ds_put_cstr (out, value->string.s);
1990 if (show & SETTINGS_VALUE_SHOW_LABEL)
1992 if (show & SETTINGS_VALUE_SHOW_VALUE)
1993 ds_put_byte (out, ' ');
1994 ds_put_cstr (out, value->string.value_label);
1998 case PIVOT_VALUE_VARIABLE:
1999 show = interpret_show (settings_get_show_variables (),
2001 value->variable.show,
2002 value->variable.var_label != NULL);
2003 if (show & SETTINGS_VALUE_SHOW_VALUE)
2004 ds_put_cstr (out, value->variable.var_name);
2005 if (show & SETTINGS_VALUE_SHOW_LABEL)
2007 if (show & SETTINGS_VALUE_SHOW_VALUE)
2008 ds_put_byte (out, ' ');
2009 ds_put_cstr (out, value->variable.var_label);
2013 case PIVOT_VALUE_TEXT:
2014 ds_put_cstr (out, value->text.local);
2017 case PIVOT_VALUE_TEMPLATE:
2018 pivot_format_template (out, value->template.local, value->template.args,
2019 value->template.n_args, show_values,
2027 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
2028 SHOW_VARIABLES control whether variable and value labels are included.
2030 Subscripts and footnotes are included. */
2032 pivot_value_format (const struct pivot_value *value,
2033 enum settings_value_show show_values,
2034 enum settings_value_show show_variables,
2037 pivot_value_format_body (value, show_values, show_variables, out);
2039 if (value->n_subscripts)
2041 for (size_t i = 0; i < value->n_subscripts; i++)
2042 ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
2045 for (size_t i = 0; i < value->n_footnotes; i++)
2047 ds_put_byte (out, '^');
2048 pivot_value_format (value->footnotes[i]->marker,
2049 show_values, show_variables, out);
2053 /* Returns a text representation of VALUE. The caller must free the string,
2056 pivot_value_to_string (const struct pivot_value *value,
2057 enum settings_value_show show_values,
2058 enum settings_value_show show_variables)
2060 struct string s = DS_EMPTY_INITIALIZER;
2061 pivot_value_format (value, show_values, show_variables, &s);
2062 return ds_steal_cstr (&s);
2065 /* Frees the data owned by V. */
2067 pivot_value_destroy (struct pivot_value *value)
2071 font_style_uninit (value->font_style);
2072 free (value->font_style);
2073 free (value->cell_style);
2074 /* Do not free the elements of footnotes because VALUE does not own
2076 free (value->footnotes);
2078 for (size_t i = 0; i < value->n_subscripts; i++)
2079 free (value->subscripts[i]);
2080 free (value->subscripts);
2082 switch (value->type)
2084 case PIVOT_VALUE_NUMERIC:
2085 free (value->numeric.var_name);
2086 free (value->numeric.value_label);
2089 case PIVOT_VALUE_STRING:
2090 free (value->string.s);
2091 free (value->string.var_name);
2092 free (value->string.value_label);
2095 case PIVOT_VALUE_VARIABLE:
2096 free (value->variable.var_name);
2097 free (value->variable.var_label);
2100 case PIVOT_VALUE_TEXT:
2101 free (value->text.local);
2102 if (value->text.c != value->text.local)
2103 free (value->text.c);
2104 if (value->text.id != value->text.local
2105 && value->text.id != value->text.c)
2106 free (value->text.id);
2109 case PIVOT_VALUE_TEMPLATE:
2110 free (value->template.local);
2111 if (value->template.id != value->template.local)
2112 free (value->template.id);
2113 for (size_t i = 0; i < value->template.n_args; i++)
2114 pivot_argument_uninit (&value->template.args[i]);
2115 free (value->template.args);
2122 /* Sets AREA to the style to use for VALUE, with defaults coming from
2123 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
2125 pivot_value_get_style (struct pivot_value *value,
2126 const struct font_style *base_font_style,
2127 const struct cell_style *base_cell_style,
2128 struct table_area_style *area)
2130 font_style_copy (NULL, &area->font_style, (value->font_style
2132 : base_font_style));
2133 area->cell_style = *(value->cell_style
2138 /* Copies AREA into VALUE's style. */
2140 pivot_value_set_style (struct pivot_value *value,
2141 const struct table_area_style *area)
2143 if (value->font_style)
2144 font_style_uninit (value->font_style);
2146 value->font_style = xmalloc (sizeof *value->font_style);
2147 font_style_copy (NULL, value->font_style, &area->font_style);
2149 if (!value->cell_style)
2150 value->cell_style = xmalloc (sizeof *value->cell_style);
2151 *value->cell_style = area->cell_style;
2154 /* Frees the data owned by ARG (but not ARG itself). */
2156 pivot_argument_uninit (struct pivot_argument *arg)
2160 for (size_t i = 0; i < arg->n; i++)
2161 pivot_value_destroy (arg->values[i]);
2166 /* Creates and returns a new pivot_value whose contents is the null-terminated
2167 string TEXT. Takes ownership of TEXT.
2169 This function is for text strings provided by the user (with the exception
2170 that pivot_value_new_variable() should be used for variable names). For
2171 strings that are part of the PSPP user interface, such as names of
2172 procedures, statistics, annotations, error messages, etc., use
2173 pivot_value_new_text(). */
2174 struct pivot_value *
2175 pivot_value_new_user_text_nocopy (char *text)
2177 struct pivot_value *value = xmalloc (sizeof *value);
2178 *value = (struct pivot_value) {
2179 .type = PIVOT_VALUE_TEXT,
2184 .user_provided = true,
2190 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2191 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2194 This function is for text strings provided by the user (with the exception
2195 that pivot_value_new_variable() should be used for variable names). For
2196 strings that are part of the PSPP user interface, such as names of
2197 procedures, statistics, annotations, error messages, etc., use
2198 pivot_value_new_text().j
2200 The caller retains ownership of TEXT.*/
2201 struct pivot_value *
2202 pivot_value_new_user_text (const char *text, size_t length)
2204 return pivot_value_new_user_text_nocopy (
2205 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2208 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2209 a translatable string, but not actually translated yet, e.g. enclosed in
2210 N_(). This function is for text strings that are part of the PSPP user
2211 interface, such as names of procedures, statistics, annotations, error
2212 messages, etc. For strings that come from the user, use
2213 pivot_value_new_user_text(). */
2214 struct pivot_value *
2215 pivot_value_new_text (const char *text)
2217 char *c = xstrdup (text);
2218 char *local = xstrdup (gettext (c));
2220 struct pivot_value *value = xmalloc (sizeof *value);
2221 *value = (struct pivot_value) {
2222 .type = PIVOT_VALUE_TEXT,
2227 .user_provided = false,
2233 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2235 struct pivot_value * PRINTF_FORMAT (1, 2)
2236 pivot_value_new_text_format (const char *format, ...)
2239 va_start (args, format);
2240 char *c = xvasprintf (format, args);
2243 va_start (args, format);
2244 char *local = xvasprintf (gettext (format), args);
2247 struct pivot_value *value = xmalloc (sizeof *value);
2248 *value = (struct pivot_value) {
2249 .type = PIVOT_VALUE_TEXT,
2254 .user_provided = false,
2260 /* Returns a new pivot_value that represents X.
2262 The format to use for X is unspecified. Usually the easiest way to specify
2263 a format is through assigning a result class to one of the categories that
2264 the pivot_value will end up in. If that is not suitable, then the caller
2265 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2266 struct pivot_value *
2267 pivot_value_new_number (double x)
2269 struct pivot_value *value = xmalloc (sizeof *value);
2270 *value = (struct pivot_value) {
2271 .type = PIVOT_VALUE_NUMERIC,
2272 .numeric = { .x = x, },
2277 /* Returns a new pivot_value that represents X, formatted as an integer. */
2278 struct pivot_value *
2279 pivot_value_new_integer (double x)
2281 struct pivot_value *value = pivot_value_new_number (x);
2282 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2286 /* Returns a new pivot_value that represents VALUE, formatted as for
2288 struct pivot_value *
2289 pivot_value_new_var_value (const struct variable *variable,
2290 const union value *value)
2292 struct pivot_value *pv = pivot_value_new_value (
2293 value, var_get_width (variable), var_get_print_format (variable),
2294 var_get_encoding (variable));
2296 char *var_name = xstrdup (var_get_name (variable));
2297 if (var_is_alpha (variable))
2298 pv->string.var_name = var_name;
2300 pv->numeric.var_name = var_name;
2302 const char *label = var_lookup_value_label (variable, value);
2305 if (var_is_alpha (variable))
2306 pv->string.value_label = xstrdup (label);
2308 pv->numeric.value_label = xstrdup (label);
2314 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2315 formatted with FORMAT. For a string value, ENCODING must be its character
2317 struct pivot_value *
2318 pivot_value_new_value (const union value *value, int width,
2319 const struct fmt_spec *format, const char *encoding)
2321 struct pivot_value *pv = xzalloc (sizeof *pv);
2324 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2326 size_t n = strlen (s);
2327 while (n > 0 && s[n - 1] == ' ')
2330 pv->type = PIVOT_VALUE_STRING;
2332 pv->string.hex = format->type == FMT_AHEX;
2336 pv->type = PIVOT_VALUE_NUMERIC;
2337 pv->numeric.x = value->f;
2338 pv->numeric.format = *format;
2344 /* Returns a new pivot_value for VARIABLE. */
2345 struct pivot_value *
2346 pivot_value_new_variable (const struct variable *variable)
2348 struct pivot_value *value = xmalloc (sizeof *value);
2349 *value = (struct pivot_value) {
2350 .type = PIVOT_VALUE_VARIABLE,
2352 .var_name = xstrdup (var_get_name (variable)),
2353 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2359 /* Attaches a reference to FOOTNOTE to V. */
2361 pivot_value_add_footnote (struct pivot_value *v,
2362 const struct pivot_footnote *footnote)
2364 /* Some legacy tables include numerous duplicate footnotes. Suppress
2366 for (size_t i = 0; i < v->n_footnotes; i++)
2367 if (v->footnotes[i] == footnote)
2370 v->footnotes = xrealloc (v->footnotes,
2371 (v->n_footnotes + 1) * sizeof *v->footnotes);
2372 v->footnotes[v->n_footnotes++] = footnote;
2375 /* If VALUE is a numeric value, and RC is a result class such as
2376 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2378 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2381 if (value->type == PIVOT_VALUE_NUMERIC)
2383 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2385 value->numeric.format = *f;