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;
400 /* Ensure that the category itself, in addition to the cells within it, takes
401 the format. (It's kind of rare for a category to have a numeric format
403 struct pivot_value *name = category->name;
404 if (name->type == PIVOT_VALUE_NUMERIC && !name->numeric.format.w)
405 name->numeric.format = format ? *format : *settings_get_format ();
409 pivot_category_create_leaves_valist (struct pivot_category *parent,
413 while ((s = va_arg (args, const char *)))
415 if (!strncmp (s, "RC_", 3))
417 assert (parent->n_subs);
418 pivot_category_set_rc (parent->subs[parent->n_subs - 1], s);
421 pivot_category_create_leaf (parent, pivot_value_new_text (s));
425 /* Creates a new dimension with the given NAME in TABLE and returns it. The
426 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
429 NAME should be a translatable name, but not actually translated yet,
430 e.g. enclosed in N_(). To use a different kind of value for a name, use
431 pivot_dimension_create__() instead.
433 The optional varargs parameters may be used to add an initial set of
434 categories to the dimension. Each string should be a translatable category
435 name, but not actually translated yet, e.g. enclosed in N_(). Each string
436 may optionally be followod by a PIVOT_RC_* string that specifies the default
437 numeric format for cells in this category. */
438 struct pivot_dimension * SENTINEL (0)
439 (pivot_dimension_create) (struct pivot_table *table,
440 enum pivot_axis_type axis_type,
441 const char *name, ...)
443 struct pivot_dimension *d = pivot_dimension_create__ (
444 table, axis_type, pivot_value_new_text (name));
447 va_start (args, name);
448 pivot_category_create_leaves_valist (d->root, args);
454 /* Creates a new dimension with the given NAME in TABLE and returns it. The
455 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
457 struct pivot_dimension *
458 pivot_dimension_create__ (struct pivot_table *table,
459 enum pivot_axis_type axis_type,
460 struct pivot_value *name)
462 assert (pivot_table_is_empty (table));
464 struct pivot_dimension *d = xmalloc (sizeof *d);
465 *d = (struct pivot_dimension) {
467 .axis_type = axis_type,
468 .level = table->axes[axis_type].n_dimensions,
469 .top_index = table->n_dimensions,
470 .root = xmalloc (sizeof *d->root),
473 struct pivot_category *root = d->root;
474 *root = (struct pivot_category) {
479 .data_index = SIZE_MAX,
480 .presentation_index = SIZE_MAX,
483 table->dimensions = xrealloc (
484 table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions);
485 table->dimensions[table->n_dimensions++] = d;
487 struct pivot_axis *axis = &table->axes[axis_type];
488 axis->dimensions = xrealloc (
489 axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
490 axis->dimensions[axis->n_dimensions++] = d;
492 if (axis_type == PIVOT_AXIS_LAYER)
494 free (table->current_layer);
495 table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
496 sizeof *table->current_layer);
499 /* axis->extent and axis->label_depth will be calculated later. */
505 pivot_dimension_destroy (struct pivot_dimension *d)
510 pivot_category_destroy (d->root);
511 free (d->data_leaves);
512 free (d->presentation_leaves);
516 /* Returns the first leaf node in an in-order traversal that is a child of
518 static const struct pivot_category * UNUSED
519 pivot_category_first_leaf (const struct pivot_category *cat)
521 if (pivot_category_is_leaf (cat))
524 for (size_t i = 0; i < cat->n_subs; i++)
526 const struct pivot_category *first
527 = pivot_category_first_leaf (cat->subs[i]);
535 /* Returns the next leaf node in an in-order traversal starting at CAT, which
537 static const struct pivot_category * UNUSED
538 pivot_category_next_leaf (const struct pivot_category *cat)
540 assert (pivot_category_is_leaf (cat));
544 const struct pivot_category *parent = cat->parent;
547 for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
549 const struct pivot_category *next
550 = pivot_category_first_leaf (parent->subs[i]);
560 pivot_category_add_child (struct pivot_category *child)
562 struct pivot_category *parent = child->parent;
564 assert (pivot_category_is_group (parent));
565 if (parent->n_subs >= parent->allocated_subs)
566 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
567 sizeof *parent->subs);
568 parent->subs[parent->n_subs++] = child;
571 /* Adds leaf categories as a child of PARENT. To create top-level categories
572 within dimension 'd', pass 'd->root' for PARENT.
574 Each of the varargs parameters should be a string, each of which should be a
575 translatable category name, but not actually translated yet, e.g. enclosed
576 in N_(). Each string may optionally be followod by a PIVOT_RC_* string that
577 specifies the default numeric format for cells in this category.
579 Returns the category index, which is just a 0-based array index, for the
582 Leaves have to be created in in-order, that is, don't create a group and add
583 some leaves, then add leaves outside the group and try to add more leaves
586 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
588 int retval = parent->dimension->n_leaves;
591 va_start (args, parent);
592 pivot_category_create_leaves_valist (parent, args);
598 /* Creates a new leaf category with the given NAME as a child of PARENT. To
599 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
600 Returns the category index, which is just a 0-based array index, for the new
603 Leaves have to be created in in-order, that is, don't create a group and add
604 some leaves, then add leaves outside the group and try to add more leaves
607 pivot_category_create_leaf (struct pivot_category *parent,
608 struct pivot_value *name)
610 return pivot_category_create_leaf_rc (parent, name, NULL);
613 /* Creates a new leaf category with the given NAME as a child of PARENT. To
614 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
615 Returns the category index, which is just a 0-based array index, for the new
618 If RC is nonnull and the name of a result category, the category is assigned
619 that result category.
621 Leaves have to be created in in-order, that is, don't create a group and add
622 some leaves, then add leaves outside the group and try to add more leaves
625 pivot_category_create_leaf_rc (struct pivot_category *parent,
626 struct pivot_value *name, const char *rc)
628 struct pivot_dimension *d = parent->dimension;
630 struct pivot_category *leaf = xmalloc (sizeof *leaf);
631 *leaf = (struct pivot_category) {
635 .group_index = parent->n_subs,
636 .data_index = d->n_leaves,
637 .presentation_index = d->n_leaves,
640 if (d->n_leaves >= d->allocated_leaves)
642 d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
643 sizeof *d->data_leaves);
644 d->presentation_leaves = xrealloc (
645 d->presentation_leaves,
646 d->allocated_leaves * sizeof *d->presentation_leaves);
649 d->data_leaves[d->n_leaves] = leaf;
650 d->presentation_leaves[d->n_leaves] = leaf;
653 pivot_category_add_child (leaf);
655 /* Make sure that the new child is the last in in-order. */
656 assert (!pivot_category_next_leaf (leaf));
658 pivot_category_set_rc (leaf, rc);
660 return leaf->data_index;
663 /* Adds a new category group named NAME as a child of PARENT. To create a
664 top-level group within dimension 'd', pass 'd->root' for PARENT.
666 NAME should be a translatable name, but not actually translated yet,
667 e.g. enclosed in N_(). To use a different kind of value for a name, use
668 pivot_category_create_group__() instead.
670 The optional varargs parameters may be used to add an initial set of
671 categories to the group. Each string should be a translatable category
672 name, but not actually translated yet, e.g. enclosed in N_(). Each string
673 may optionally be followod by a PIVOT_RC_* string that specifies the default
674 numeric format for cells in this category.
676 Returns the new group. */
677 struct pivot_category * SENTINEL (0)
678 (pivot_category_create_group) (struct pivot_category *parent,
679 const char *name, ...)
681 struct pivot_category *group = pivot_category_create_group__ (
682 parent, pivot_value_new_text (name));
685 va_start (args, name);
686 pivot_category_create_leaves_valist (group, args);
692 /* Adds a new category group named NAME as a child of PARENT. To create a
693 top-level group within dimension 'd', pass 'd->root' for PARENT. Returns
695 struct pivot_category *
696 pivot_category_create_group__ (struct pivot_category *parent,
697 struct pivot_value *name)
699 struct pivot_dimension *d = parent->dimension;
701 struct pivot_category *group = xmalloc (sizeof *group);
702 *group = (struct pivot_category) {
707 .group_index = parent->n_subs,
708 .data_index = SIZE_MAX,
709 .presentation_index = SIZE_MAX,
712 pivot_category_add_child (group);
718 pivot_category_destroy (struct pivot_category *c)
723 pivot_value_destroy (c->name);
724 for (size_t i = 0; i < c->n_subs; i++)
725 pivot_category_destroy (c->subs[i]);
732 These are usually the easiest way to control the formatting of numeric data
733 in a pivot table. See pivot_dimension_create() for an explanation of their
737 const char *name; /* "RC_*". */
738 struct fmt_spec format;
741 /* Formats for most of the result classes. */
742 static struct result_class result_classes[] =
744 { PIVOT_RC_INTEGER, { FMT_F, 40, 0 } },
745 { PIVOT_RC_PERCENT, { FMT_PCT, 40, 1 } },
746 { PIVOT_RC_CORRELATION, { FMT_F, 40, 3 } },
747 { PIVOT_RC_SIGNIFICANCE, { FMT_F, 40, 3 } },
748 { PIVOT_RC_RESIDUAL, { FMT_F, 40, 2 } },
749 { PIVOT_RC_COUNT, { 0, 0, 0 } },
750 { PIVOT_RC_OTHER, { 0, 0, 0 } },
753 /* Has PIVOT_RC_COUNT been overridden by the user? */
754 static bool overridden_count_format;
756 static struct result_class *
757 pivot_result_class_find (const char *s)
759 for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
760 if (!strcmp (s, result_classes[i].name))
761 return &result_classes[i];
765 static const struct fmt_spec *
766 pivot_table_get_format (const struct pivot_table *table, const char *s)
770 else if (!strcmp (s, PIVOT_RC_OTHER))
771 return settings_get_format ();
772 else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
773 return &table->weight_format;
776 const struct result_class *rc = pivot_result_class_find (s);
777 return rc ? &rc->format : NULL;
781 /* Sets the format specification for the result class named S (which should not
782 include the RC_ prefix) to *FORMAT. Returns true if successful, false if S
783 does not name a known result class. */
785 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
787 char *s = xasprintf ("RC_%s", s_);
788 struct result_class *rc = pivot_result_class_find (s);
791 rc->format = *format;
792 if (!strcmp (s, PIVOT_RC_COUNT))
793 overridden_count_format = true;
802 /* Creates and returns a new pivot table with the given TITLE. TITLE should be
803 a text string marked for translation but not actually translated yet,
804 e.g. N_("Descriptive Statistics"). The un-translated text string is used as
805 the pivot table's subtype.
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 should
822 be an untranslated English string that describes the contents of the table
823 at a high level without being specific about the variables or other context
826 TITLE and SUBTYPE may be NULL, but in that case the client must add them
827 later because they are both mandatory for a pivot table.
829 See the large comment at the top of pivot-table.h for general advice on
830 creating pivot tables. */
832 pivot_table_create__ (struct pivot_value *title, const char *subtype)
834 struct pivot_table *table = xzalloc (sizeof *table);
836 table->show_title = true;
837 table->show_caption = true;
838 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
839 table->title = title;
840 table->subtype = subtype ? pivot_value_new_text (subtype) : NULL;
841 table->command_c = output_get_command_name ();
842 table->look = pivot_table_look_ref (pivot_table_look_get_default ());
844 hmap_init (&table->cells);
849 /* Creates and returns a new pivot table with the given TITLE and a single cell
850 with the given CONTENT.
852 This is really just for error handling. */
854 pivot_table_create_for_text (struct pivot_value *title,
855 struct pivot_value *content)
857 struct pivot_table *table = pivot_table_create__ (title, "Error");
859 struct pivot_dimension *d = pivot_dimension_create (
860 table, PIVOT_AXIS_ROW, N_("Error"));
861 d->hide_all_labels = true;
862 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
864 pivot_table_put1 (table, 0, content);
869 /* Increases TABLE's reference count, indicating that it has an additional
870 owner. A pivot table that is shared among multiple owners must not be
873 pivot_table_ref (const struct pivot_table *table_)
875 struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
880 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
881 If TABLE no longer has any owners, it is freed. */
883 pivot_table_unref (struct pivot_table *table)
887 assert (table->ref_cnt > 0);
888 if (--table->ref_cnt)
891 free (table->current_layer);
892 pivot_table_look_unref (table->look);
894 for (int i = 0; i < TABLE_N_AXES; i++)
895 pivot_table_sizing_uninit (&table->sizing[i]);
897 for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
898 free (table->ccs[i]);
900 free (table->command_local);
901 free (table->command_c);
902 free (table->language);
903 free (table->locale);
905 free (table->dataset);
906 free (table->datafile);
908 for (size_t i = 0; i < table->n_footnotes; i++)
909 pivot_footnote_destroy (table->footnotes[i]);
910 free (table->footnotes);
912 pivot_value_destroy (table->title);
913 pivot_value_destroy (table->subtype);
914 pivot_value_destroy (table->corner_text);
915 pivot_value_destroy (table->caption);
918 for (size_t i = 0; i < table->n_dimensions; i++)
919 pivot_dimension_destroy (table->dimensions[i]);
920 free (table->dimensions);
922 for (size_t i = 0; i < PIVOT_N_AXES; i++)
923 free (table->axes[i].dimensions);
925 struct pivot_cell *cell, *next_cell;
926 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
929 hmap_delete (&table->cells, &cell->hmap_node);
930 pivot_value_destroy (cell->value);
933 hmap_destroy (&table->cells);
938 /* Returns true if TABLE has more than one owner. A pivot table that is shared
939 among multiple owners must not be modified. */
941 pivot_table_is_shared (const struct pivot_table *table)
943 return table->ref_cnt > 1;
946 const struct pivot_table_look *
947 pivot_table_get_look (const struct pivot_table *table)
953 pivot_table_set_look (struct pivot_table *table,
954 const struct pivot_table_look *look)
956 pivot_table_look_unref (table->look);
957 table->look = pivot_table_look_ref (look);
960 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
961 WV, which should be the weight variable for the dictionary whose data or
962 statistics are being put into TABLE.
964 This has no effect if WV is NULL. */
966 pivot_table_set_weight_var (struct pivot_table *table,
967 const struct variable *wv)
970 pivot_table_set_weight_format (table, var_get_print_format (wv));
973 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
974 format for the dictionary whose data or statistics are being put into TABLE.
976 This has no effect if WFMT is NULL. */
978 pivot_table_set_weight_format (struct pivot_table *table,
979 const struct fmt_spec *wfmt)
982 table->weight_format = *wfmt;
985 /* Returns true if TABLE has no cells, false otherwise. */
987 pivot_table_is_empty (const struct pivot_table *table)
989 return hmap_is_empty (&table->cells);
993 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
995 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
999 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
1001 for (size_t i = 0; i < n; i++)
1008 static struct pivot_cell *
1009 pivot_table_lookup_cell__ (const struct pivot_table *table,
1010 const size_t *dindexes, unsigned int hash)
1012 struct pivot_cell *cell;
1013 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
1015 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
1020 static struct pivot_cell *
1021 pivot_cell_allocate (size_t n_idx)
1023 struct pivot_cell *cell UNUSED;
1024 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
1027 static struct pivot_cell *
1028 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
1030 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1031 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
1034 cell = pivot_cell_allocate (table->n_dimensions);
1035 for (size_t i = 0; i < table->n_dimensions; i++)
1036 cell->idx[i] = dindexes[i];
1038 hmap_insert (&table->cells, &cell->hmap_node, hash);
1043 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
1044 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
1047 If VALUE is a numeric value without a specified format, this function checks
1048 each of the categories designated by DINDEXES[] and takes the format from
1049 the first category with a result class. If none has a result class, uses
1050 the overall default numeric format. */
1052 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
1053 struct pivot_value *value)
1055 assert (n == table->n_dimensions);
1056 for (size_t i = 0; i < n; i++)
1057 assert (dindexes[i] < table->dimensions[i]->n_leaves);
1059 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
1061 for (size_t i = 0; i < table->n_dimensions; i++)
1063 const struct pivot_dimension *d = table->dimensions[i];
1064 if (dindexes[i] < d->n_leaves)
1066 const struct pivot_category *c = d->data_leaves[dindexes[i]];
1069 value->numeric.format = c->format;
1074 value->numeric.format = *settings_get_format ();
1079 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1080 pivot_value_destroy (cell->value);
1081 cell->value = value;
1084 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
1085 dimension. Takes ownership of VALUE. */
1087 pivot_table_put1 (struct pivot_table *table, size_t idx1,
1088 struct pivot_value *value)
1090 size_t dindexes[] = { idx1 };
1091 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1094 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
1095 dimensions. Takes ownership of VALUE. */
1097 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
1098 struct pivot_value *value)
1100 size_t dindexes[] = { idx1, idx2 };
1101 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1104 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
1105 have 3 dimensions. Takes ownership of VALUE. */
1107 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
1108 size_t idx3, struct pivot_value *value)
1110 size_t dindexes[] = { idx1, idx2, idx3 };
1111 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1114 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
1115 must have 4 dimensions. Takes ownership of VALUE. */
1117 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1118 size_t idx3, size_t idx4, struct pivot_value *value)
1120 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1121 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1124 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1125 automatically assigned marker.
1127 The footnote will only appear in output if it is referenced. Use
1128 pivot_value_add_footnote() to add a reference to the footnote. */
1129 struct pivot_footnote *
1130 pivot_table_create_footnote (struct pivot_table *table,
1131 struct pivot_value *content)
1133 return pivot_table_create_footnote__ (table, table->n_footnotes,
1137 static struct pivot_value *
1138 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1140 char text[INT_BUFSIZE_BOUND (size_t)];
1141 if (show_numeric_markers)
1142 snprintf (text, sizeof text, "%d", idx + 1);
1144 str_format_26adic (idx + 1, false, text, sizeof text);
1145 return pivot_value_new_user_text (text, -1);
1148 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1149 all lower indexes as a side effect). If MARKER is nonnull, sets the
1150 footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1151 struct pivot_footnote *
1152 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1153 struct pivot_value *marker,
1154 struct pivot_value *content)
1156 if (idx >= table->n_footnotes)
1158 while (idx >= table->allocated_footnotes)
1159 table->footnotes = x2nrealloc (table->footnotes,
1160 &table->allocated_footnotes,
1161 sizeof *table->footnotes);
1162 while (idx >= table->n_footnotes)
1164 struct pivot_footnote *f = xmalloc (sizeof *f);
1165 f->idx = table->n_footnotes;
1166 f->marker = pivot_make_default_footnote_marker (
1167 f->idx, table->look->show_numeric_markers);
1171 table->footnotes[table->n_footnotes++] = f;
1175 struct pivot_footnote *f = table->footnotes[idx];
1178 pivot_value_destroy (f->marker);
1183 pivot_value_destroy (f->content);
1184 f->content = content;
1189 /* Frees the data owned by F. */
1191 pivot_footnote_destroy (struct pivot_footnote *f)
1195 pivot_value_destroy (f->content);
1196 pivot_value_destroy (f->marker);
1201 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1202 indexes for each dimension in TABLE in DINDEXES[]. */
1204 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1205 const size_t *pindexes[PIVOT_N_AXES],
1206 size_t dindexes[/* table->n_dimensions */])
1208 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1210 const struct pivot_axis *axis = &table->axes[i];
1212 for (size_t j = 0; j < axis->n_dimensions; j++)
1214 const struct pivot_dimension *d = axis->dimensions[j];
1215 dindexes[d->top_index]
1216 = d->presentation_leaves[pindexes[i][j]]->data_index;
1222 pivot_table_enumerate_axis (const struct pivot_table *table,
1223 enum pivot_axis_type axis_type,
1224 const size_t *layer_indexes, bool omit_empty,
1227 const struct pivot_axis *axis = &table->axes[axis_type];
1228 if (!axis->n_dimensions)
1230 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1232 enumeration[1] = SIZE_MAX;
1237 else if (!axis->extent)
1239 size_t *enumeration = xmalloc (sizeof *enumeration);
1240 *enumeration = SIZE_MAX;
1246 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1247 axis->n_dimensions), 1),
1248 sizeof *enumeration);
1249 size_t *p = enumeration;
1250 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1252 size_t *axis_indexes;
1253 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1257 enum pivot_axis_type axis2_type
1258 = pivot_axis_type_transpose (axis_type);
1260 size_t *axis2_indexes;
1261 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1263 const size_t *pindexes[PIVOT_N_AXES];
1264 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1265 pindexes[axis_type] = axis_indexes;
1266 pindexes[axis2_type] = axis2_indexes;
1267 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1268 if (pivot_table_get (table, dindexes))
1274 free (axis2_indexes);
1277 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1278 p += axis->n_dimensions;
1280 if (omit_empty && p == enumeration)
1282 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1284 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1285 p += axis->n_dimensions;
1290 *n = (p - enumeration) / axis->n_dimensions;
1296 static const struct pivot_cell *
1297 pivot_table_lookup_cell (const struct pivot_table *table,
1298 const size_t *dindexes)
1300 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1301 return pivot_table_lookup_cell__ (table, dindexes, hash);
1304 const struct pivot_value *
1305 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1307 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1308 return cell ? cell->value : NULL;
1311 struct pivot_value *
1312 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1314 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1316 cell->value = pivot_value_new_user_text ("", -1);
1321 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1323 if (pivot_category_is_group (category) && category->n_subs)
1324 for (size_t i = 0; i < category->n_subs; i++)
1325 distribute_extra_depth (category->subs[i], extra_depth);
1327 category->extra_depth += extra_depth;
1331 pivot_category_assign_label_depth (struct pivot_category *category,
1332 bool dimension_labels_in_corner)
1334 category->extra_depth = 0;
1336 if (pivot_category_is_group (category))
1339 for (size_t i = 0; i < category->n_subs; i++)
1341 pivot_category_assign_label_depth (category->subs[i], false);
1342 depth = MAX (depth, category->subs[i]->label_depth);
1345 for (size_t i = 0; i < category->n_subs; i++)
1347 struct pivot_category *sub = category->subs[i];
1349 size_t extra_depth = depth - sub->label_depth;
1351 distribute_extra_depth (sub, extra_depth);
1353 sub->label_depth = depth;
1356 category->show_label_in_corner = (category->show_label
1357 && dimension_labels_in_corner);
1358 category->label_depth
1359 = (category->show_label && !category->show_label_in_corner
1360 ? depth + 1 : depth);
1363 category->label_depth = 1;
1367 pivot_axis_assign_label_depth (struct pivot_table *table,
1368 enum pivot_axis_type axis_type,
1369 bool dimension_labels_in_corner)
1371 struct pivot_axis *axis = &table->axes[axis_type];
1372 bool any_label_shown_in_corner = false;
1373 axis->label_depth = 0;
1375 for (size_t i = 0; i < axis->n_dimensions; i++)
1377 struct pivot_dimension *d = axis->dimensions[i];
1378 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1379 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1380 axis->label_depth += d->label_depth;
1381 axis->extent *= d->n_leaves;
1383 if (d->root->show_label_in_corner)
1384 any_label_shown_in_corner = true;
1386 return any_label_shown_in_corner;
1390 pivot_table_assign_label_depth (struct pivot_table *table)
1392 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1393 if (pivot_axis_assign_label_depth (
1394 table, PIVOT_AXIS_ROW, (table->look->row_labels_in_corner
1395 && !table->corner_text))
1396 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1397 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1398 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1402 indent (int indentation)
1404 for (int i = 0; i < indentation * 2; i++)
1409 pivot_value_dump (const struct pivot_value *value)
1411 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1412 SETTINGS_VALUE_SHOW_DEFAULT);
1418 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1423 indent (indentation);
1424 printf ("%s: ", name);
1425 pivot_value_dump (value);
1431 pivot_table_dump_string (const char *string, const char *name, int indentation)
1435 indent (indentation);
1436 printf ("%s: %s\n", name, string);
1441 pivot_category_dump (const struct pivot_category *c, int indentation)
1443 indent (indentation);
1444 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1445 pivot_value_dump (c->name);
1448 if (pivot_category_is_leaf (c))
1449 printf ("data_index=%zu\n", c->data_index);
1452 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1455 for (size_t i = 0; i < c->n_subs; i++)
1456 pivot_category_dump (c->subs[i], indentation + 1);
1461 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1463 indent (indentation);
1464 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1465 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1467 pivot_category_dump (d->root, indentation + 1);
1471 table_area_style_dump (enum pivot_area area, const struct table_area_style *a,
1474 indent (indentation);
1475 printf ("%s: ", pivot_area_to_string (area));
1476 font_style_dump (&a->font_style);
1478 cell_style_dump (&a->cell_style);
1483 table_border_style_dump (enum pivot_border border,
1484 const struct table_border_style *b, int indentation)
1486 indent (indentation);
1487 printf ("%s: %s ", pivot_border_to_string (border),
1488 table_stroke_to_string (b->stroke));
1489 cell_color_dump (&b->color);
1494 compose_headings (const struct pivot_axis *axis,
1495 const size_t *column_enumeration,
1496 enum settings_value_show show_values,
1497 enum settings_value_show show_variables)
1499 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1502 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1503 for (size_t i = 0; i < axis->label_depth; i++)
1504 headings[i] = xcalloc (axis->extent, sizeof **headings);
1506 const size_t *indexes;
1508 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1510 int row = axis->label_depth - 1;
1511 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1513 const struct pivot_dimension *d = axis->dimensions[dim_index];
1514 if (d->hide_all_labels)
1516 for (const struct pivot_category *c
1517 = d->presentation_leaves[indexes[dim_index]];
1521 if (pivot_category_is_leaf (c) || (c->show_label
1522 && !c->show_label_in_corner))
1524 headings[row][column] = pivot_value_to_string (
1525 c->name, show_values, show_variables);
1526 if (!*headings[row][column])
1527 headings[row][column] = xstrdup ("<blank>");
1539 free_headings (const struct pivot_axis *axis, char ***headings)
1541 for (size_t i = 0; i < axis->label_depth; i++)
1543 for (size_t j = 0; j < axis->extent; j++)
1544 free (headings[i][j]);
1551 pivot_table_sizing_dump (const char *name,
1552 const int width_ranges[2],
1553 const struct pivot_table_sizing *s,
1556 indent (indentation);
1557 printf ("%ss: min=%d, max=%d\n", name, width_ranges[0], width_ranges[1]);
1560 indent (indentation + 1);
1561 printf ("%s widths:", name);
1562 for (size_t i = 0; i < s->n_widths; i++)
1563 printf (" %d", s->widths[i]);
1568 indent (indentation + 1);
1569 printf ("break after %ss:", name);
1570 for (size_t i = 0; i < s->n_breaks; i++)
1571 printf (" %zu", s->breaks[i]);
1576 indent (indentation + 1);
1577 printf ("keep %ss together:", name);
1578 for (size_t i = 0; i < s->n_keeps; i++)
1579 printf (" [%zu,%zu]",
1581 s->keeps[i].ofs + s->keeps[i].n - 1);
1587 pivot_table_dump (const struct pivot_table *table, int indentation)
1592 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1593 if (table->decimal == '.' || table->decimal == ',')
1594 settings_set_decimal_char (table->decimal);
1596 pivot_table_dump_value (table->title, "title", indentation);
1597 pivot_table_dump_value (table->subtype, "subtype", indentation);
1598 pivot_table_dump_string (table->command_c, "command", indentation);
1599 pivot_table_dump_string (table->dataset, "dataset", indentation);
1600 pivot_table_dump_string (table->datafile, "datafile", indentation);
1601 pivot_table_dump_string (table->notes, "notes", indentation);
1602 pivot_table_dump_string (table->look->name, "table-look", indentation);
1605 indent (indentation);
1607 struct tm *tm = localtime (&table->date);
1608 printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
1609 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
1613 indent (indentation);
1614 printf ("sizing:\n");
1615 pivot_table_sizing_dump ("column", table->look->width_ranges[TABLE_HORZ],
1616 &table->sizing[TABLE_HORZ], indentation + 1);
1617 pivot_table_sizing_dump ("row", table->look->width_ranges[TABLE_VERT],
1618 &table->sizing[TABLE_VERT], indentation + 1);
1620 indent (indentation);
1621 printf ("areas:\n");
1622 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1623 table_area_style_dump (area, &table->look->areas[area], indentation + 1);
1625 indent (indentation);
1626 printf ("borders:\n");
1627 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1628 table_border_style_dump (border, &table->look->borders[border],
1631 for (size_t i = 0; i < table->n_dimensions; i++)
1632 pivot_dimension_dump (table->dimensions[i], indentation);
1634 /* Presentation and data indexes. */
1635 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1637 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1638 if (layer_axis->n_dimensions)
1640 indent (indentation);
1641 printf ("current layer:");
1643 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1645 const struct pivot_dimension *d = layer_axis->dimensions[i];
1646 char *name = pivot_value_to_string (d->root->name,
1648 table->show_variables);
1649 char *value = pivot_value_to_string (
1650 d->data_leaves[table->current_layer[i]]->name,
1651 table->show_values, table->show_variables);
1652 printf (" %s=%s", name, value);
1660 size_t *layer_indexes;
1661 size_t layer_iteration = 0;
1662 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1664 indent (indentation);
1665 printf ("layer %zu:", layer_iteration++);
1667 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1668 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1670 const struct pivot_dimension *d = layer_axis->dimensions[i];
1672 fputs (i == 0 ? " " : ", ", stdout);
1673 pivot_value_dump (d->root->name);
1674 fputs (" =", stdout);
1676 struct pivot_value **names = xnmalloc (d->n_leaves, sizeof *names);
1678 for (const struct pivot_category *c
1679 = d->presentation_leaves[layer_indexes[i]];
1683 if (pivot_category_is_leaf (c) || c->show_label)
1684 names[n_names++] = c->name;
1687 for (size_t i = n_names; i-- > 0;)
1690 pivot_value_dump (names[i]);
1696 size_t *column_enumeration = pivot_table_enumerate_axis (
1697 table, PIVOT_AXIS_COLUMN, layer_indexes, table->look->omit_empty, NULL);
1698 size_t *row_enumeration = pivot_table_enumerate_axis (
1699 table, PIVOT_AXIS_ROW, layer_indexes, table->look->omit_empty, NULL);
1701 char ***column_headings = compose_headings (
1702 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1703 table->show_values, table->show_variables);
1704 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1706 indent (indentation + 1);
1707 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1710 fputs ("; ", stdout);
1711 if (column_headings[y][x])
1712 fputs (column_headings[y][x], stdout);
1716 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1718 indent (indentation + 1);
1719 printf ("-----------------------------------------------\n");
1721 char ***row_headings = compose_headings (
1722 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1723 table->show_values, table->show_variables);
1726 const size_t *pindexes[PIVOT_N_AXES]
1727 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1728 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1729 &table->axes[PIVOT_AXIS_ROW])
1731 indent (indentation + 1);
1734 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1737 fputs ("; ", stdout);
1738 if (row_headings[y][x])
1739 fputs (row_headings[y][x], stdout);
1745 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1747 &table->axes[PIVOT_AXIS_COLUMN])
1752 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1753 const struct pivot_value *value = pivot_table_get (
1756 pivot_value_dump (value);
1763 free (column_enumeration);
1764 free (row_enumeration);
1765 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1768 pivot_table_dump_value (table->caption, "caption", indentation);
1770 for (size_t i = 0; i < table->n_footnotes; i++)
1772 const struct pivot_footnote *f = table->footnotes[i];
1773 indent (indentation);
1776 pivot_value_dump (f->marker);
1778 printf ("%zu", f->idx);
1780 pivot_value_dump (f->content);
1785 settings_set_decimal_char (old_decimal);
1789 consume_int (const char *p, size_t *n)
1792 while (c_isdigit (*p))
1793 *n = *n * 10 + (*p++ - '0');
1798 pivot_format_inner_template (struct string *out, const char *template,
1800 struct pivot_value **values, size_t n_values,
1801 enum settings_value_show show_values,
1802 enum settings_value_show show_variables)
1804 size_t args_consumed = 0;
1805 while (*template && *template != ':')
1807 if (*template == '\\' && template[1])
1809 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1812 else if (*template == escape)
1815 template = consume_int (template + 1, &index);
1816 if (index >= 1 && index <= n_values)
1818 pivot_value_format (values[index - 1], show_values,
1819 show_variables, out);
1820 args_consumed = MAX (args_consumed, index);
1824 ds_put_byte (out, *template++);
1826 return args_consumed;
1830 pivot_extract_inner_template (const char *template, const char **p)
1836 if (*template == '\\' && template[1] != '\0')
1838 else if (*template == ':')
1839 return template + 1;
1840 else if (*template == '\0')
1848 pivot_format_template (struct string *out, const char *template,
1849 const struct pivot_argument *args, size_t n_args,
1850 enum settings_value_show show_values,
1851 enum settings_value_show show_variables)
1855 if (*template == '\\' && template[1] != '\0')
1857 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1860 else if (*template == '^')
1863 template = consume_int (template + 1, &index);
1864 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1865 pivot_value_format (args[index - 1].values[0],
1866 show_values, show_variables, out);
1868 else if (*template == '[')
1870 const char *tmpl[2];
1871 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1872 template = pivot_extract_inner_template (template, &tmpl[1]);
1873 template += *template == ']';
1876 template = consume_int (template, &index);
1877 if (index < 1 || index > n_args)
1880 const struct pivot_argument *arg = &args[index - 1];
1881 size_t left = arg->n;
1884 struct pivot_value **values = arg->values + (arg->n - left);
1885 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1886 char escape = "%^"[tmpl_idx];
1887 size_t used = pivot_format_inner_template (
1888 out, tmpl[tmpl_idx], escape, values, left,
1889 show_values, show_variables);
1890 if (!used || used > left)
1896 ds_put_byte (out, *template++);
1900 static enum settings_value_show
1901 interpret_show (enum settings_value_show global_show,
1902 enum settings_value_show table_show,
1903 enum settings_value_show value_show,
1906 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1907 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1908 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1912 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1913 SHOW_VARIABLES control whether variable and value labels are included.
1915 The "body" omits subscripts and superscripts and footnotes.
1917 Returns true if OUT is a number (or a number plus a value label), false
1920 pivot_value_format_body (const struct pivot_value *value,
1921 enum settings_value_show show_values,
1922 enum settings_value_show show_variables,
1925 enum settings_value_show show;
1926 bool numeric = false;
1928 switch (value->type)
1930 case PIVOT_VALUE_NUMERIC:
1931 show = interpret_show (settings_get_show_values (),
1933 value->numeric.show,
1934 value->numeric.value_label != NULL);
1935 if (show & SETTINGS_VALUE_SHOW_VALUE)
1937 char *s = data_out (&(union value) { .f = value->numeric.x },
1938 "UTF-8", &value->numeric.format);
1939 ds_put_cstr (out, s + strspn (s, " "));
1942 if (show & SETTINGS_VALUE_SHOW_LABEL)
1944 if (show & SETTINGS_VALUE_SHOW_VALUE)
1945 ds_put_byte (out, ' ');
1946 ds_put_cstr (out, value->numeric.value_label);
1948 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1951 case PIVOT_VALUE_STRING:
1952 show = interpret_show (settings_get_show_values (),
1955 value->string.value_label != NULL);
1956 if (show & SETTINGS_VALUE_SHOW_VALUE)
1958 if (value->string.hex)
1960 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1962 ds_put_format (out, "%02X", *p);
1965 ds_put_cstr (out, value->string.s);
1967 if (show & SETTINGS_VALUE_SHOW_LABEL)
1969 if (show & SETTINGS_VALUE_SHOW_VALUE)
1970 ds_put_byte (out, ' ');
1971 ds_put_cstr (out, value->string.value_label);
1975 case PIVOT_VALUE_VARIABLE:
1976 show = interpret_show (settings_get_show_variables (),
1978 value->variable.show,
1979 value->variable.var_label != NULL);
1980 if (show & SETTINGS_VALUE_SHOW_VALUE)
1981 ds_put_cstr (out, value->variable.var_name);
1982 if (show & SETTINGS_VALUE_SHOW_LABEL)
1984 if (show & SETTINGS_VALUE_SHOW_VALUE)
1985 ds_put_byte (out, ' ');
1986 ds_put_cstr (out, value->variable.var_label);
1990 case PIVOT_VALUE_TEXT:
1991 ds_put_cstr (out, value->text.local);
1994 case PIVOT_VALUE_TEMPLATE:
1995 pivot_format_template (out, value->template.local, value->template.args,
1996 value->template.n_args, show_values,
2004 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
2005 SHOW_VARIABLES control whether variable and value labels are included.
2007 Subscripts and footnotes are included. */
2009 pivot_value_format (const struct pivot_value *value,
2010 enum settings_value_show show_values,
2011 enum settings_value_show show_variables,
2014 pivot_value_format_body (value, show_values, show_variables, out);
2016 if (value->n_subscripts)
2018 for (size_t i = 0; i < value->n_subscripts; i++)
2019 ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
2022 for (size_t i = 0; i < value->n_footnotes; i++)
2024 ds_put_byte (out, '^');
2025 pivot_value_format (value->footnotes[i]->marker,
2026 show_values, show_variables, out);
2030 /* Returns a text representation of VALUE. The caller must free the string,
2033 pivot_value_to_string (const struct pivot_value *value,
2034 enum settings_value_show show_values,
2035 enum settings_value_show show_variables)
2037 struct string s = DS_EMPTY_INITIALIZER;
2038 pivot_value_format (value, show_values, show_variables, &s);
2039 return ds_steal_cstr (&s);
2042 /* Frees the data owned by V. */
2044 pivot_value_destroy (struct pivot_value *value)
2048 font_style_uninit (value->font_style);
2049 free (value->font_style);
2050 free (value->cell_style);
2051 /* Do not free the elements of footnotes because VALUE does not own
2053 free (value->footnotes);
2055 for (size_t i = 0; i < value->n_subscripts; i++)
2056 free (value->subscripts[i]);
2057 free (value->subscripts);
2059 switch (value->type)
2061 case PIVOT_VALUE_NUMERIC:
2062 free (value->numeric.var_name);
2063 free (value->numeric.value_label);
2066 case PIVOT_VALUE_STRING:
2067 free (value->string.s);
2068 free (value->string.var_name);
2069 free (value->string.value_label);
2072 case PIVOT_VALUE_VARIABLE:
2073 free (value->variable.var_name);
2074 free (value->variable.var_label);
2077 case PIVOT_VALUE_TEXT:
2078 free (value->text.local);
2079 if (value->text.c != value->text.local)
2080 free (value->text.c);
2081 if (value->text.id != value->text.local
2082 && value->text.id != value->text.c)
2083 free (value->text.id);
2086 case PIVOT_VALUE_TEMPLATE:
2087 free (value->template.local);
2088 if (value->template.id != value->template.local)
2089 free (value->template.id);
2090 for (size_t i = 0; i < value->template.n_args; i++)
2091 pivot_argument_uninit (&value->template.args[i]);
2092 free (value->template.args);
2099 /* Sets AREA to the style to use for VALUE, with defaults coming from
2100 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
2102 pivot_value_get_style (struct pivot_value *value,
2103 const struct font_style *base_font_style,
2104 const struct cell_style *base_cell_style,
2105 struct table_area_style *area)
2107 font_style_copy (NULL, &area->font_style, (value->font_style
2109 : base_font_style));
2110 area->cell_style = *(value->cell_style
2115 /* Copies AREA into VALUE's style. */
2117 pivot_value_set_style (struct pivot_value *value,
2118 const struct table_area_style *area)
2120 if (value->font_style)
2121 font_style_uninit (value->font_style);
2123 value->font_style = xmalloc (sizeof *value->font_style);
2124 font_style_copy (NULL, value->font_style, &area->font_style);
2126 if (!value->cell_style)
2127 value->cell_style = xmalloc (sizeof *value->cell_style);
2128 *value->cell_style = area->cell_style;
2131 /* Frees the data owned by ARG (but not ARG itself). */
2133 pivot_argument_uninit (struct pivot_argument *arg)
2137 for (size_t i = 0; i < arg->n; i++)
2138 pivot_value_destroy (arg->values[i]);
2143 /* Creates and returns a new pivot_value whose contents is the null-terminated
2144 string TEXT. Takes ownership of TEXT.
2146 This function is for text strings provided by the user (with the exception
2147 that pivot_value_new_variable() should be used for variable names). For
2148 strings that are part of the PSPP user interface, such as names of
2149 procedures, statistics, annotations, error messages, etc., use
2150 pivot_value_new_text(). */
2151 struct pivot_value *
2152 pivot_value_new_user_text_nocopy (char *text)
2154 struct pivot_value *value = xmalloc (sizeof *value);
2155 *value = (struct pivot_value) {
2156 .type = PIVOT_VALUE_TEXT,
2161 .user_provided = true,
2167 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2168 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2171 This function is for text strings provided by the user (with the exception
2172 that pivot_value_new_variable() should be used for variable names). For
2173 strings that are part of the PSPP user interface, such as names of
2174 procedures, statistics, annotations, error messages, etc., use
2175 pivot_value_new_text().j
2177 The caller retains ownership of TEXT.*/
2178 struct pivot_value *
2179 pivot_value_new_user_text (const char *text, size_t length)
2181 return pivot_value_new_user_text_nocopy (
2182 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2185 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2186 a translatable string, but not actually translated yet, e.g. enclosed in
2187 N_(). This function is for text strings that are part of the PSPP user
2188 interface, such as names of procedures, statistics, annotations, error
2189 messages, etc. For strings that come from the user, use
2190 pivot_value_new_user_text(). */
2191 struct pivot_value *
2192 pivot_value_new_text (const char *text)
2194 char *c = xstrdup (text);
2195 char *local = xstrdup (gettext (c));
2197 struct pivot_value *value = xmalloc (sizeof *value);
2198 *value = (struct pivot_value) {
2199 .type = PIVOT_VALUE_TEXT,
2204 .user_provided = false,
2210 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2212 struct pivot_value * PRINTF_FORMAT (1, 2)
2213 pivot_value_new_text_format (const char *format, ...)
2216 va_start (args, format);
2217 char *c = xvasprintf (format, args);
2220 va_start (args, format);
2221 char *local = xvasprintf (gettext (format), args);
2224 struct pivot_value *value = xmalloc (sizeof *value);
2225 *value = (struct pivot_value) {
2226 .type = PIVOT_VALUE_TEXT,
2231 .user_provided = false,
2237 /* Returns a new pivot_value that represents X.
2239 The format to use for X is unspecified. Usually the easiest way to specify
2240 a format is through assigning a result class to one of the categories that
2241 the pivot_value will end up in. If that is not suitable, then the caller
2242 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2243 struct pivot_value *
2244 pivot_value_new_number (double x)
2246 struct pivot_value *value = xmalloc (sizeof *value);
2247 *value = (struct pivot_value) {
2248 .type = PIVOT_VALUE_NUMERIC,
2249 .numeric = { .x = x, },
2254 /* Returns a new pivot_value that represents X, formatted as an integer. */
2255 struct pivot_value *
2256 pivot_value_new_integer (double x)
2258 struct pivot_value *value = pivot_value_new_number (x);
2259 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2263 /* Returns a new pivot_value that represents VALUE, formatted as for
2265 struct pivot_value *
2266 pivot_value_new_var_value (const struct variable *variable,
2267 const union value *value)
2269 struct pivot_value *pv = pivot_value_new_value (
2270 value, var_get_width (variable), var_get_print_format (variable),
2271 var_get_encoding (variable));
2273 char *var_name = xstrdup (var_get_name (variable));
2274 if (var_is_alpha (variable))
2275 pv->string.var_name = var_name;
2277 pv->numeric.var_name = var_name;
2279 const char *label = var_lookup_value_label (variable, value);
2282 if (var_is_alpha (variable))
2283 pv->string.value_label = xstrdup (label);
2285 pv->numeric.value_label = xstrdup (label);
2291 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2292 formatted with FORMAT. For a string value, ENCODING must be its character
2294 struct pivot_value *
2295 pivot_value_new_value (const union value *value, int width,
2296 const struct fmt_spec *format, const char *encoding)
2298 struct pivot_value *pv = xzalloc (sizeof *pv);
2301 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2303 size_t n = strlen (s);
2304 while (n > 0 && s[n - 1] == ' ')
2307 pv->type = PIVOT_VALUE_STRING;
2309 pv->string.hex = format->type == FMT_AHEX;
2313 pv->type = PIVOT_VALUE_NUMERIC;
2314 pv->numeric.x = value->f;
2315 pv->numeric.format = *format;
2321 /* Returns a new pivot_value for VARIABLE. */
2322 struct pivot_value *
2323 pivot_value_new_variable (const struct variable *variable)
2325 struct pivot_value *value = xmalloc (sizeof *value);
2326 *value = (struct pivot_value) {
2327 .type = PIVOT_VALUE_VARIABLE,
2329 .var_name = xstrdup (var_get_name (variable)),
2330 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2336 /* Attaches a reference to FOOTNOTE to V. */
2338 pivot_value_add_footnote (struct pivot_value *v,
2339 const struct pivot_footnote *footnote)
2341 /* Some legacy tables include numerous duplicate footnotes. Suppress
2343 for (size_t i = 0; i < v->n_footnotes; i++)
2344 if (v->footnotes[i] == footnote)
2347 v->footnotes = xrealloc (v->footnotes,
2348 (v->n_footnotes + 1) * sizeof *v->footnotes);
2349 v->footnotes[v->n_footnotes++] = footnote;
2352 /* If VALUE is a numeric value, and RC is a result class such as
2353 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2355 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2358 if (value->type == PIVOT_VALUE_NUMERIC)
2360 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2362 value->numeric.format = *f;