1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2017, 2018 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "output/pivot-table.h"
23 #include "data/data-out.h"
24 #include "data/settings.h"
25 #include "data/value.h"
26 #include "data/variable.h"
27 #include "data/file-name.h"
28 #include "libpspp/hash-functions.h"
29 #include "libpspp/i18n.h"
30 #include "output/driver.h"
31 #include "output/spv/spv-table-look.h"
33 #include "gl/c-ctype.h"
34 #include "gl/configmake.h"
35 #include "gl/intprops.h"
36 #include "gl/minmax.h"
37 #include "gl/relocatable.h"
38 #include "gl/xalloc.h"
39 #include "gl/xmemdup0.h"
43 #define _(msgid) gettext (msgid)
44 #define N_(msgid) msgid
46 static const struct fmt_spec *pivot_table_get_format (
47 const struct pivot_table *, const char *s);
49 /* Pivot table display styling. */
51 /* Returns the name of AREA. */
53 pivot_area_to_string (enum pivot_area area)
57 case PIVOT_AREA_TITLE: return "title";
58 case PIVOT_AREA_CAPTION: return "caption";
59 case PIVOT_AREA_FOOTER: return "footer";
60 case PIVOT_AREA_CORNER: return "corner";
61 case PIVOT_AREA_COLUMN_LABELS: return "column labels";
62 case PIVOT_AREA_ROW_LABELS: return "row labels";
63 case PIVOT_AREA_DATA: return "data";
64 case PIVOT_AREA_LAYERS: return "layers";
65 case PIVOT_N_AREAS: default: return "**error**";
69 /* Returns the name of BORDER. */
71 pivot_border_to_string (enum pivot_border border)
75 case PIVOT_BORDER_TITLE:
78 case PIVOT_BORDER_OUTER_LEFT:
79 return "left outer frame";
80 case PIVOT_BORDER_OUTER_TOP:
81 return "top outer frame";
82 case PIVOT_BORDER_OUTER_RIGHT:
83 return "right outer frame";
84 case PIVOT_BORDER_OUTER_BOTTOM:
85 return "bottom outer frame";
87 case PIVOT_BORDER_INNER_LEFT:
88 return "left inner frame";
89 case PIVOT_BORDER_INNER_TOP:
90 return "top inner frame";
91 case PIVOT_BORDER_INNER_RIGHT:
92 return "right inner frame";
93 case PIVOT_BORDER_INNER_BOTTOM:
94 return "bottom inner frame";
96 case PIVOT_BORDER_DATA_LEFT:
97 return "data area left";
98 case PIVOT_BORDER_DATA_TOP:
99 return "data area top";
101 case PIVOT_BORDER_DIM_ROW_HORZ:
102 return "row label horizontal dimension border";
103 case PIVOT_BORDER_DIM_ROW_VERT:
104 return "row label vertical dimension border";
105 case PIVOT_BORDER_DIM_COL_HORZ:
106 return "column label horizontal dimension border";
107 case PIVOT_BORDER_DIM_COL_VERT:
108 return "column label vertical dimension border";
110 case PIVOT_BORDER_CAT_ROW_HORZ:
111 return "row label horizontal category border";
112 case PIVOT_BORDER_CAT_ROW_VERT:
113 return "row label vertical category border";
114 case PIVOT_BORDER_CAT_COL_HORZ:
115 return "column label horizontal category border";
116 case PIVOT_BORDER_CAT_COL_VERT:
117 return "column label vertical category border";
119 case PIVOT_N_BORDERS:
126 pivot_table_sizing_uninit (struct pivot_table_sizing *sizing)
130 free (sizing->widths);
131 free (sizing->breaks);
132 free (sizing->keeps);
136 /* Pivot table looks. */
138 static const struct pivot_table_look *
139 default_look (const struct pivot_table_look *new)
141 static struct pivot_table_look *look;
144 pivot_table_look_unref (look);
145 look = pivot_table_look_ref (new);
149 char *error = pivot_table_look_read ("default.stt", &look);
153 look = pivot_table_look_ref (pivot_table_look_builtin_default ());
159 const struct pivot_table_look *
160 pivot_table_look_get_default (void)
162 return default_look (NULL);
166 pivot_table_look_set_default (const struct pivot_table_look *look)
171 char * WARN_UNUSED_RESULT
172 pivot_table_look_read (const char *name, struct pivot_table_look **lookp)
176 /* Construct search path. */
180 const char *home = getenv ("HOME");
181 char *allocated = NULL;
183 path[n++] = allocated = xasprintf ("%s/.pspp/looks", home);
185 path[n++] = relocate2 (PKGDATADIR "/looks", &allocated2);
189 char *file = fn_search_path (name, (char **) path);
192 char *name2 = xasprintf ("%s.stt", name);
193 file = fn_search_path (name2, (char **) path);
199 return xasprintf ("%s: not found", name);
202 char *error = spv_table_look_read (file, lookp);
207 const struct pivot_table_look *
208 pivot_table_look_builtin_default (void)
210 static struct pivot_table_look look = {
214 .row_labels_in_corner = true,
216 [TABLE_HORZ] = { 36, 72 },
217 [TABLE_VERT] = { 36, 120 },
221 #define AREA(BOLD, H, V, L, R, T, B) { \
223 .halign = TABLE_HALIGN_##H, \
224 .valign = TABLE_VALIGN_##V, \
225 .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
226 [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
230 .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
231 .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
233 .typeface = (char *) "Sans Serif", \
236 [PIVOT_AREA_TITLE] = AREA(true, CENTER, CENTER, 8,11,1,8),
237 [PIVOT_AREA_CAPTION] = AREA(false, LEFT, TOP, 8,11,1,1),
238 [PIVOT_AREA_FOOTER] = AREA(false, LEFT, TOP, 11, 8,2,3),
239 [PIVOT_AREA_CORNER] = AREA(false, LEFT, BOTTOM, 8,11,1,1),
240 [PIVOT_AREA_COLUMN_LABELS] = AREA(false, CENTER, BOTTOM, 8,11,1,3),
241 [PIVOT_AREA_ROW_LABELS] = AREA(false, LEFT, TOP, 8,11,1,3),
242 [PIVOT_AREA_DATA] = AREA(false, MIXED, TOP, 8,11,1,1),
243 [PIVOT_AREA_LAYERS] = AREA(false, LEFT, BOTTOM, 8,11,1,3),
248 #define BORDER(STROKE) { .stroke = STROKE, .color = CELL_COLOR_BLACK }
249 [PIVOT_BORDER_TITLE] = BORDER(TABLE_STROKE_NONE),
250 [PIVOT_BORDER_OUTER_LEFT] = BORDER(TABLE_STROKE_NONE),
251 [PIVOT_BORDER_OUTER_TOP] = BORDER(TABLE_STROKE_NONE),
252 [PIVOT_BORDER_OUTER_RIGHT] = BORDER(TABLE_STROKE_NONE),
253 [PIVOT_BORDER_OUTER_BOTTOM] = BORDER(TABLE_STROKE_NONE),
254 [PIVOT_BORDER_INNER_LEFT] = BORDER(TABLE_STROKE_THICK),
255 [PIVOT_BORDER_INNER_TOP] = BORDER(TABLE_STROKE_THICK),
256 [PIVOT_BORDER_INNER_RIGHT] = BORDER(TABLE_STROKE_THICK),
257 [PIVOT_BORDER_INNER_BOTTOM] = BORDER(TABLE_STROKE_THICK),
258 [PIVOT_BORDER_DATA_LEFT] = BORDER(TABLE_STROKE_THICK),
259 [PIVOT_BORDER_DATA_TOP] = BORDER(TABLE_STROKE_THICK),
260 [PIVOT_BORDER_DIM_ROW_HORZ] = BORDER(TABLE_STROKE_SOLID),
261 [PIVOT_BORDER_DIM_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
262 [PIVOT_BORDER_DIM_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
263 [PIVOT_BORDER_DIM_COL_VERT] = BORDER(TABLE_STROKE_SOLID),
264 [PIVOT_BORDER_CAT_ROW_HORZ] = BORDER(TABLE_STROKE_NONE),
265 [PIVOT_BORDER_CAT_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
266 [PIVOT_BORDER_CAT_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
267 [PIVOT_BORDER_CAT_COL_VERT] = BORDER(TABLE_STROKE_SOLID),
274 struct pivot_table_look *
275 pivot_table_look_new_builtin_default (void)
277 return pivot_table_look_unshare (
278 pivot_table_look_ref (pivot_table_look_builtin_default ()));
281 struct pivot_table_look *
282 pivot_table_look_ref (const struct pivot_table_look *look_)
284 assert (look_->ref_cnt > 0);
286 struct pivot_table_look *look = CONST_CAST (struct pivot_table_look *, look_);
292 xstrdup_if_nonempty (const char *s)
294 return s && s[0] ? xstrdup (s) : NULL;
297 struct pivot_table_look *
298 pivot_table_look_unshare (struct pivot_table_look *old)
300 assert (old->ref_cnt > 0);
301 if (old->ref_cnt == 1)
304 pivot_table_look_unref (old);
306 struct pivot_table_look *new = xmemdup (old, sizeof *old);
308 new->name = xstrdup_if_nonempty (old->name);
309 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
310 table_area_style_copy (NULL, &new->areas[i], &old->areas[i]);
311 new->continuation = xstrdup_if_nonempty (old->continuation);
317 pivot_table_look_unref (struct pivot_table_look *look)
321 assert (look->ref_cnt > 0);
322 if (!--look->ref_cnt)
325 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
326 table_area_style_uninit (&look->areas[i]);
327 free (look->continuation);
335 /* Returns the name of AXIS_TYPE. */
337 pivot_axis_type_to_string (enum pivot_axis_type axis_type)
341 case PIVOT_AXIS_LAYER:
347 case PIVOT_AXIS_COLUMN:
355 static enum pivot_axis_type
356 pivot_axis_type_transpose (enum pivot_axis_type axis_type)
358 assert (axis_type == PIVOT_AXIS_ROW || axis_type == PIVOT_AXIS_COLUMN);
359 return (axis_type == PIVOT_AXIS_ROW ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW);
362 /* Implementation of PIVOT_AXIS_FOR_EACH. */
364 pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis)
368 if (axis->n_dimensions)
369 for (size_t i = 0; i < axis->n_dimensions; i++)
370 if (axis->dimensions[i]->n_leaves == 0)
373 return xcalloc (axis->n_dimensions, sizeof *indexes);
376 for (size_t i = 0; i < axis->n_dimensions; i++)
378 const struct pivot_dimension *d = axis->dimensions[i];
379 if (++indexes[i] < d->n_leaves)
392 pivot_category_set_rc (struct pivot_category *category, const char *s)
394 const struct fmt_spec *format = pivot_table_get_format (
395 category->dimension->table, s);
397 category->format = *format;
401 pivot_category_create_leaves_valist (struct pivot_category *parent,
405 while ((s = va_arg (args, const char *)))
407 if (!strncmp (s, "RC_", 3))
409 assert (parent->n_subs);
410 pivot_category_set_rc (parent->subs[parent->n_subs - 1], s);
413 pivot_category_create_leaf (parent, pivot_value_new_text (s));
417 /* Creates a new dimension with the given NAME in TABLE and returns it. The
418 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
421 NAME should be a translatable name, but not actually translated yet,
422 e.g. enclosed in N_(). To use a different kind of value for a name, use
423 pivot_dimension_create__() instead.
425 The optional varargs parameters may be used to add an initial set of
426 categories to the dimension. Each string should be a translatable category
427 name, but not actually translated yet, e.g. enclosed in N_(). Each string
428 may optionally be followod by a PIVOT_RC_* string that specifies the default
429 numeric format for cells in this category. */
430 struct pivot_dimension * SENTINEL (0)
431 (pivot_dimension_create) (struct pivot_table *table,
432 enum pivot_axis_type axis_type,
433 const char *name, ...)
435 struct pivot_dimension *d = pivot_dimension_create__ (
436 table, axis_type, pivot_value_new_text (name));
439 va_start (args, name);
440 pivot_category_create_leaves_valist (d->root, args);
446 /* Creates a new dimension with the given NAME in TABLE and returns it. The
447 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
449 struct pivot_dimension *
450 pivot_dimension_create__ (struct pivot_table *table,
451 enum pivot_axis_type axis_type,
452 struct pivot_value *name)
454 assert (pivot_table_is_empty (table));
456 struct pivot_dimension *d = xmalloc (sizeof *d);
457 *d = (struct pivot_dimension) {
459 .axis_type = axis_type,
460 .level = table->axes[axis_type].n_dimensions,
461 .top_index = table->n_dimensions,
462 .root = xmalloc (sizeof *d->root),
465 struct pivot_category *root = d->root;
466 *root = (struct pivot_category) {
471 .data_index = SIZE_MAX,
472 .presentation_index = SIZE_MAX,
475 table->dimensions = xrealloc (
476 table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions);
477 table->dimensions[table->n_dimensions++] = d;
479 struct pivot_axis *axis = &table->axes[axis_type];
480 axis->dimensions = xrealloc (
481 axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
482 axis->dimensions[axis->n_dimensions++] = d;
484 if (axis_type == PIVOT_AXIS_LAYER)
486 free (table->current_layer);
487 table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
488 sizeof *table->current_layer);
491 /* axis->extent and axis->label_depth will be calculated later. */
497 pivot_dimension_destroy (struct pivot_dimension *d)
502 pivot_category_destroy (d->root);
503 free (d->data_leaves);
504 free (d->presentation_leaves);
508 /* Returns the first leaf node in an in-order traversal that is a child of
510 static const struct pivot_category * UNUSED
511 pivot_category_first_leaf (const struct pivot_category *cat)
513 if (pivot_category_is_leaf (cat))
516 for (size_t i = 0; i < cat->n_subs; i++)
518 const struct pivot_category *first
519 = pivot_category_first_leaf (cat->subs[i]);
527 /* Returns the next leaf node in an in-order traversal starting at CAT, which
529 static const struct pivot_category * UNUSED
530 pivot_category_next_leaf (const struct pivot_category *cat)
532 assert (pivot_category_is_leaf (cat));
536 const struct pivot_category *parent = cat->parent;
539 for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
541 const struct pivot_category *next
542 = pivot_category_first_leaf (parent->subs[i]);
552 pivot_category_add_child (struct pivot_category *child)
554 struct pivot_category *parent = child->parent;
556 assert (pivot_category_is_group (parent));
557 if (parent->n_subs >= parent->allocated_subs)
558 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
559 sizeof *parent->subs);
560 parent->subs[parent->n_subs++] = child;
563 /* Adds leaf categories as a child of PARENT. To create top-level categories
564 within dimension 'd', pass 'd->root' for PARENT.
566 Each of the varargs parameters should be a string, each of which should be a
567 translatable category name, but not actually translated yet, e.g. enclosed
568 in N_(). Each string may optionally be followod by a PIVOT_RC_* string that
569 specifies the default numeric format for cells in this category.
571 Returns the category index, which is just a 0-based array index, for the
574 Leaves have to be created in in-order, that is, don't create a group and add
575 some leaves, then add leaves outside the group and try to add more leaves
578 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
580 int retval = parent->dimension->n_leaves;
583 va_start (args, parent);
584 pivot_category_create_leaves_valist (parent, args);
590 /* Creates a new leaf category with the given NAME as a child of PARENT. To
591 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
592 Returns the category index, which is just a 0-based array index, for the new
595 Leaves have to be created in in-order, that is, don't create a group and add
596 some leaves, then add leaves outside the group and try to add more leaves
599 pivot_category_create_leaf (struct pivot_category *parent,
600 struct pivot_value *name)
602 return pivot_category_create_leaf_rc (parent, name, NULL);
605 /* Creates a new leaf category with the given NAME as a child of PARENT. To
606 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
607 Returns the category index, which is just a 0-based array index, for the new
610 If RC is nonnull and the name of a result category, the category is assigned
611 that result category.
613 Leaves have to be created in in-order, that is, don't create a group and add
614 some leaves, then add leaves outside the group and try to add more leaves
617 pivot_category_create_leaf_rc (struct pivot_category *parent,
618 struct pivot_value *name, const char *rc)
620 struct pivot_dimension *d = parent->dimension;
622 struct pivot_category *leaf = xmalloc (sizeof *leaf);
623 *leaf = (struct pivot_category) {
627 .group_index = parent->n_subs,
628 .data_index = d->n_leaves,
629 .presentation_index = d->n_leaves,
632 if (d->n_leaves >= d->allocated_leaves)
634 d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
635 sizeof *d->data_leaves);
636 d->presentation_leaves = xrealloc (
637 d->presentation_leaves,
638 d->allocated_leaves * sizeof *d->presentation_leaves);
641 d->data_leaves[d->n_leaves] = leaf;
642 d->presentation_leaves[d->n_leaves] = leaf;
645 pivot_category_add_child (leaf);
647 /* Make sure that the new child is the last in in-order. */
648 assert (!pivot_category_next_leaf (leaf));
650 pivot_category_set_rc (leaf, rc);
652 return leaf->data_index;
655 /* Adds a new category group named NAME as a child of PARENT. To create a
656 top-level group within dimension 'd', pass 'd->root' for PARENT.
658 NAME should be a translatable name, but not actually translated yet,
659 e.g. enclosed in N_(). To use a different kind of value for a name, use
660 pivot_category_create_group__() instead.
662 The optional varargs parameters may be used to add an initial set of
663 categories to the group. Each string should be a translatable category
664 name, but not actually translated yet, e.g. enclosed in N_(). Each string
665 may optionally be followod by a PIVOT_RC_* string that specifies the default
666 numeric format for cells in this category.
668 Returns the new group. */
669 struct pivot_category * SENTINEL (0)
670 (pivot_category_create_group) (struct pivot_category *parent,
671 const char *name, ...)
673 struct pivot_category *group = pivot_category_create_group__ (
674 parent, pivot_value_new_text (name));
677 va_start (args, name);
678 pivot_category_create_leaves_valist (group, args);
684 /* Adds a new category group named NAME as a child of PARENT. To create a
685 top-level group within dimension 'd', pass 'd->root' for PARENT. Returns
687 struct pivot_category *
688 pivot_category_create_group__ (struct pivot_category *parent,
689 struct pivot_value *name)
691 struct pivot_dimension *d = parent->dimension;
693 struct pivot_category *group = xmalloc (sizeof *group);
694 *group = (struct pivot_category) {
699 .group_index = parent->n_subs,
700 .data_index = SIZE_MAX,
701 .presentation_index = SIZE_MAX,
704 pivot_category_add_child (group);
710 pivot_category_destroy (struct pivot_category *c)
715 pivot_value_destroy (c->name);
716 for (size_t i = 0; i < c->n_subs; i++)
717 pivot_category_destroy (c->subs[i]);
724 These are usually the easiest way to control the formatting of numeric data
725 in a pivot table. See pivot_dimension_create() for an explanation of their
729 const char *name; /* "RC_*". */
730 struct fmt_spec format;
733 /* Formats for most of the result classes. */
734 static struct result_class result_classes[] =
736 { PIVOT_RC_INTEGER, { FMT_F, 40, 0 } },
737 { PIVOT_RC_PERCENT, { FMT_PCT, 40, 1 } },
738 { PIVOT_RC_CORRELATION, { FMT_F, 40, 3 } },
739 { PIVOT_RC_SIGNIFICANCE, { FMT_F, 40, 3 } },
740 { PIVOT_RC_RESIDUAL, { FMT_F, 40, 2 } },
741 { PIVOT_RC_COUNT, { 0, 0, 0 } },
742 { PIVOT_RC_OTHER, { 0, 0, 0 } },
745 /* Has PIVOT_RC_COUNT been overridden by the user? */
746 static bool overridden_count_format;
748 static struct result_class *
749 pivot_result_class_find (const char *s)
751 for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
752 if (!strcmp (s, result_classes[i].name))
753 return &result_classes[i];
757 static const struct fmt_spec *
758 pivot_table_get_format (const struct pivot_table *table, const char *s)
762 else if (!strcmp (s, PIVOT_RC_OTHER))
763 return settings_get_format ();
764 else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
765 return &table->weight_format;
768 const struct result_class *rc = pivot_result_class_find (s);
769 return rc ? &rc->format : NULL;
773 /* Sets the format specification for the result class named S (which should not
774 include the RC_ prefix) to *FORMAT. Returns true if successful, false if S
775 does not name a known result class. */
777 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
779 char *s = xasprintf ("RC_%s", s_);
780 struct result_class *rc = pivot_result_class_find (s);
783 rc->format = *format;
784 if (!strcmp (s, PIVOT_RC_COUNT))
785 overridden_count_format = true;
794 /* Creates and returns a new pivot table with the given TITLE. TITLE should be
795 a text string marked for translation but not actually translated yet,
796 e.g. N_("Descriptive Statistics"). The un-translated text string is used as
797 the pivot table's subtype.
799 Operations commonly performed on the new pivot_table:
801 - If empty rows or columns should not be displayed, set ->omit_empty to
804 - Set the format to use for "count" values with pivot_table_set_weight_var()
805 or pivot_table_set_weight_format().
807 This function is a shortcut for pivot_table_create__() for the most common
808 case. Use pivot_table_create__() directly if the title should be some kind
809 of value other than an ordinary text string, or if the subtype should be
810 different from the title.
812 See the large comment at the top of pivot-table.h for general advice on
813 creating pivot tables. */
815 pivot_table_create (const char *title)
817 return pivot_table_create__ (pivot_value_new_text (title), title);
820 /* Creates and returns a new pivot table with the given TITLE, and takes
821 ownership of TITLE. The new pivot table's subtype is SUBTYPE, which
822 should be an untranslated English string that describes the contents of
823 the table at a high level without being specific about the variables or
824 other context involved.
826 Operations commonly performed on the new pivot_table:
828 - If empty rows or columns should not be displayed, set ->omit_empty to
831 - Set the format to use for "count" values with pivot_table_set_weight_var()
832 or pivot_table_set_weight_format().
834 See the large comment at the top of pivot-table.h for general advice on
835 creating pivot tables. */
837 pivot_table_create__ (struct pivot_value *title, const char *subtype)
839 struct pivot_table *table = xzalloc (sizeof *table);
841 table->show_title = true;
842 table->show_caption = true;
843 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
844 table->title = title;
845 table->subtype = subtype ? pivot_value_new_text (subtype) : NULL;
846 table->command_c = output_get_command_name ();
847 table->look = pivot_table_look_ref (pivot_table_look_get_default ());
849 hmap_init (&table->cells);
854 /* Creates and returns a new pivot table with the given TITLE and a single cell
855 with the given CONTENT.
857 This is really just for error handling. */
859 pivot_table_create_for_text (struct pivot_value *title,
860 struct pivot_value *content)
862 struct pivot_table *table = pivot_table_create__ (title, "Error");
864 struct pivot_dimension *d = pivot_dimension_create (
865 table, PIVOT_AXIS_ROW, N_("Error"));
866 d->hide_all_labels = true;
867 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
869 pivot_table_put1 (table, 0, content);
874 /* Increases TABLE's reference count, indicating that it has an additional
875 owner. A pivot table that is shared among multiple owners must not be
878 pivot_table_ref (const struct pivot_table *table_)
880 struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
885 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
886 If TABLE no longer has any owners, it is freed. */
888 pivot_table_unref (struct pivot_table *table)
892 assert (table->ref_cnt > 0);
893 if (--table->ref_cnt)
896 free (table->current_layer);
897 pivot_table_look_unref (table->look);
899 for (int i = 0; i < TABLE_N_AXES; i++)
900 pivot_table_sizing_uninit (&table->sizing[i]);
902 for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
903 free (table->ccs[i]);
905 free (table->command_local);
906 free (table->command_c);
907 free (table->language);
908 free (table->locale);
910 free (table->dataset);
911 free (table->datafile);
913 for (size_t i = 0; i < table->n_footnotes; i++)
914 pivot_footnote_destroy (table->footnotes[i]);
915 free (table->footnotes);
917 pivot_value_destroy (table->title);
918 pivot_value_destroy (table->subtype);
919 pivot_value_destroy (table->corner_text);
920 pivot_value_destroy (table->caption);
922 for (size_t i = 0; i < table->n_dimensions; i++)
923 pivot_dimension_destroy (table->dimensions[i]);
924 free (table->dimensions);
926 for (size_t i = 0; i < PIVOT_N_AXES; i++)
927 free (table->axes[i].dimensions);
929 struct pivot_cell *cell, *next_cell;
930 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
933 hmap_delete (&table->cells, &cell->hmap_node);
934 pivot_value_destroy (cell->value);
937 hmap_destroy (&table->cells);
942 /* Returns true if TABLE has more than one owner. A pivot table that is shared
943 among multiple owners must not be modified. */
945 pivot_table_is_shared (const struct pivot_table *table)
947 return table->ref_cnt > 1;
950 const struct pivot_table_look *
951 pivot_table_get_look (const struct pivot_table *table)
957 pivot_table_set_look (struct pivot_table *table,
958 const struct pivot_table_look *look)
960 pivot_table_look_unref (table->look);
961 table->look = pivot_table_look_ref (look);
964 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
965 WV, which should be the weight variable for the dictionary whose data or
966 statistics are being put into TABLE.
968 This has no effect if WV is NULL. */
970 pivot_table_set_weight_var (struct pivot_table *table,
971 const struct variable *wv)
974 pivot_table_set_weight_format (table, var_get_print_format (wv));
977 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
978 format for the dictionary whose data or statistics are being put into TABLE.
980 This has no effect if WFMT is NULL. */
982 pivot_table_set_weight_format (struct pivot_table *table,
983 const struct fmt_spec *wfmt)
986 table->weight_format = *wfmt;
989 /* Returns true if TABLE has no cells, false otherwise. */
991 pivot_table_is_empty (const struct pivot_table *table)
993 return hmap_is_empty (&table->cells);
997 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
999 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
1003 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
1005 for (size_t i = 0; i < n; i++)
1012 static struct pivot_cell *
1013 pivot_table_lookup_cell__ (const struct pivot_table *table,
1014 const size_t *dindexes, unsigned int hash)
1016 struct pivot_cell *cell;
1017 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
1019 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
1024 static struct pivot_cell *
1025 pivot_cell_allocate (size_t n_idx)
1027 struct pivot_cell *cell UNUSED;
1028 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
1031 static struct pivot_cell *
1032 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
1034 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1035 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
1038 cell = pivot_cell_allocate (table->n_dimensions);
1039 for (size_t i = 0; i < table->n_dimensions; i++)
1040 cell->idx[i] = dindexes[i];
1042 hmap_insert (&table->cells, &cell->hmap_node, hash);
1047 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
1048 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
1051 If VALUE is a numeric value without a specified format, this function checks
1052 each of the categories designated by DINDEXES[] and takes the format from
1053 the first category with a result class. If none has a result class, uses
1054 the overall default numeric format. */
1056 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
1057 struct pivot_value *value)
1059 assert (n == table->n_dimensions);
1060 for (size_t i = 0; i < n; i++)
1061 assert (dindexes[i] < table->dimensions[i]->n_leaves);
1063 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
1065 for (size_t i = 0; i < table->n_dimensions; i++)
1067 const struct pivot_dimension *d = table->dimensions[i];
1068 if (dindexes[i] < d->n_leaves)
1070 const struct pivot_category *c = d->data_leaves[dindexes[i]];
1073 value->numeric.format = c->format;
1078 value->numeric.format = *settings_get_format ();
1083 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1084 pivot_value_destroy (cell->value);
1085 cell->value = value;
1088 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
1089 dimension. Takes ownership of VALUE. */
1091 pivot_table_put1 (struct pivot_table *table, size_t idx1,
1092 struct pivot_value *value)
1094 size_t dindexes[] = { idx1 };
1095 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1098 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
1099 dimensions. Takes ownership of VALUE. */
1101 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
1102 struct pivot_value *value)
1104 size_t dindexes[] = { idx1, idx2 };
1105 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1108 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
1109 have 3 dimensions. Takes ownership of VALUE. */
1111 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
1112 size_t idx3, struct pivot_value *value)
1114 size_t dindexes[] = { idx1, idx2, idx3 };
1115 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1118 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
1119 must have 4 dimensions. Takes ownership of VALUE. */
1121 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1122 size_t idx3, size_t idx4, struct pivot_value *value)
1124 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1125 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1128 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1129 automatically assigned marker.
1131 The footnote will only appear in output if it is referenced. Use
1132 pivot_value_add_footnote() to add a reference to the footnote. */
1133 struct pivot_footnote *
1134 pivot_table_create_footnote (struct pivot_table *table,
1135 struct pivot_value *content)
1137 return pivot_table_create_footnote__ (table, table->n_footnotes,
1141 static struct pivot_value *
1142 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1144 char text[INT_BUFSIZE_BOUND (size_t)];
1145 if (show_numeric_markers)
1146 snprintf (text, sizeof text, "%d", idx + 1);
1148 str_format_26adic (idx + 1, false, text, sizeof text);
1149 return pivot_value_new_user_text (text, -1);
1152 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1153 all lower indexes as a side effect). If MARKER is nonnull, sets the
1154 footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1155 struct pivot_footnote *
1156 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1157 struct pivot_value *marker,
1158 struct pivot_value *content)
1160 if (idx >= table->n_footnotes)
1162 while (idx >= table->allocated_footnotes)
1163 table->footnotes = x2nrealloc (table->footnotes,
1164 &table->allocated_footnotes,
1165 sizeof *table->footnotes);
1166 while (idx >= table->n_footnotes)
1168 struct pivot_footnote *f = xmalloc (sizeof *f);
1169 f->idx = table->n_footnotes;
1170 f->marker = pivot_make_default_footnote_marker (
1171 f->idx, table->look->show_numeric_markers);
1175 table->footnotes[table->n_footnotes++] = f;
1179 struct pivot_footnote *f = table->footnotes[idx];
1182 pivot_value_destroy (f->marker);
1187 pivot_value_destroy (f->content);
1188 f->content = content;
1193 /* Frees the data owned by F. */
1195 pivot_footnote_destroy (struct pivot_footnote *f)
1199 pivot_value_destroy (f->content);
1200 pivot_value_destroy (f->marker);
1205 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1206 indexes for each dimension in TABLE in DINDEXES[]. */
1208 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1209 const size_t *pindexes[PIVOT_N_AXES],
1210 size_t dindexes[/* table->n_dimensions */])
1212 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1214 const struct pivot_axis *axis = &table->axes[i];
1216 for (size_t j = 0; j < axis->n_dimensions; j++)
1218 const struct pivot_dimension *d = axis->dimensions[j];
1219 dindexes[d->top_index]
1220 = d->presentation_leaves[pindexes[i][j]]->data_index;
1226 pivot_table_enumerate_axis (const struct pivot_table *table,
1227 enum pivot_axis_type axis_type,
1228 const size_t *layer_indexes, bool omit_empty,
1231 const struct pivot_axis *axis = &table->axes[axis_type];
1232 if (!axis->n_dimensions)
1234 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1236 enumeration[1] = SIZE_MAX;
1241 else if (!axis->extent)
1243 size_t *enumeration = xmalloc (sizeof *enumeration);
1244 *enumeration = SIZE_MAX;
1250 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1251 axis->n_dimensions), 1),
1252 sizeof *enumeration);
1253 size_t *p = enumeration;
1254 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1256 size_t *axis_indexes;
1257 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1261 enum pivot_axis_type axis2_type
1262 = pivot_axis_type_transpose (axis_type);
1264 size_t *axis2_indexes;
1265 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1267 const size_t *pindexes[PIVOT_N_AXES];
1268 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1269 pindexes[axis_type] = axis_indexes;
1270 pindexes[axis2_type] = axis2_indexes;
1271 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1272 if (pivot_table_get (table, dindexes))
1278 free (axis2_indexes);
1281 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1282 p += axis->n_dimensions;
1284 if (omit_empty && p == enumeration)
1286 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1288 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1289 p += axis->n_dimensions;
1294 *n = (p - enumeration) / axis->n_dimensions;
1300 static const struct pivot_cell *
1301 pivot_table_lookup_cell (const struct pivot_table *table,
1302 const size_t *dindexes)
1304 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1305 return pivot_table_lookup_cell__ (table, dindexes, hash);
1308 const struct pivot_value *
1309 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1311 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1312 return cell ? cell->value : NULL;
1315 struct pivot_value *
1316 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1318 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1320 cell->value = pivot_value_new_user_text ("", -1);
1325 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1327 if (pivot_category_is_group (category) && category->n_subs)
1328 for (size_t i = 0; i < category->n_subs; i++)
1329 distribute_extra_depth (category->subs[i], extra_depth);
1331 category->extra_depth += extra_depth;
1335 pivot_category_assign_label_depth (struct pivot_category *category,
1336 bool dimension_labels_in_corner)
1338 category->extra_depth = 0;
1340 if (pivot_category_is_group (category))
1343 for (size_t i = 0; i < category->n_subs; i++)
1345 pivot_category_assign_label_depth (category->subs[i], false);
1346 depth = MAX (depth, category->subs[i]->label_depth);
1349 for (size_t i = 0; i < category->n_subs; i++)
1351 struct pivot_category *sub = category->subs[i];
1353 size_t extra_depth = depth - sub->label_depth;
1355 distribute_extra_depth (sub, extra_depth);
1357 sub->label_depth = depth;
1360 category->show_label_in_corner = (category->show_label
1361 && dimension_labels_in_corner);
1362 category->label_depth
1363 = (category->show_label && !category->show_label_in_corner
1364 ? depth + 1 : depth);
1367 category->label_depth = 1;
1371 pivot_axis_assign_label_depth (struct pivot_table *table,
1372 enum pivot_axis_type axis_type,
1373 bool dimension_labels_in_corner)
1375 struct pivot_axis *axis = &table->axes[axis_type];
1376 bool any_label_shown_in_corner = false;
1377 axis->label_depth = 0;
1379 for (size_t i = 0; i < axis->n_dimensions; i++)
1381 struct pivot_dimension *d = axis->dimensions[i];
1382 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1383 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1384 axis->label_depth += d->label_depth;
1385 axis->extent *= d->n_leaves;
1387 if (d->root->show_label_in_corner)
1388 any_label_shown_in_corner = true;
1390 return any_label_shown_in_corner;
1394 pivot_table_assign_label_depth (struct pivot_table *table)
1396 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1397 if (pivot_axis_assign_label_depth (
1398 table, PIVOT_AXIS_ROW, (table->look->row_labels_in_corner
1399 && !table->corner_text))
1400 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1401 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1402 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1410 indent (int indentation)
1412 for (int i = 0; i < indentation * 2; i++)
1417 pivot_value_dump (const struct pivot_value *value)
1419 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1420 SETTINGS_VALUE_SHOW_DEFAULT);
1426 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1431 indent (indentation);
1432 printf ("%s: ", name);
1433 pivot_value_dump (value);
1439 pivot_table_dump_string (const char *string, const char *name, int indentation)
1443 indent (indentation);
1444 printf ("%s: %s\n", name, string);
1449 pivot_category_dump (const struct pivot_category *c, int indentation)
1451 indent (indentation);
1452 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1453 pivot_value_dump (c->name);
1456 if (pivot_category_is_leaf (c))
1457 printf ("data_index=%zu\n", c->data_index);
1460 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1463 for (size_t i = 0; i < c->n_subs; i++)
1464 pivot_category_dump (c->subs[i], indentation + 1);
1469 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1471 indent (indentation);
1472 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1473 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1475 pivot_category_dump (d->root, indentation + 1);
1479 table_area_style_dump (enum pivot_area area, const struct table_area_style *a,
1482 indent (indentation);
1483 printf ("%s: ", pivot_area_to_string (area));
1484 font_style_dump (&a->font_style);
1486 cell_style_dump (&a->cell_style);
1491 table_border_style_dump (enum pivot_border border,
1492 const struct table_border_style *b, int indentation)
1494 indent (indentation);
1495 printf ("%s: %s ", pivot_border_to_string (border),
1496 table_stroke_to_string (b->stroke));
1497 cell_color_dump (&b->color);
1502 compose_headings (const struct pivot_axis *axis,
1503 const size_t *column_enumeration,
1504 enum settings_value_show show_values,
1505 enum settings_value_show show_variables)
1507 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1510 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1511 for (size_t i = 0; i < axis->label_depth; i++)
1512 headings[i] = xcalloc (axis->extent, sizeof **headings);
1514 const size_t *indexes;
1516 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1518 int row = axis->label_depth - 1;
1519 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1521 const struct pivot_dimension *d = axis->dimensions[dim_index];
1522 if (d->hide_all_labels)
1524 for (const struct pivot_category *c
1525 = d->presentation_leaves[indexes[dim_index]];
1529 if (pivot_category_is_leaf (c) || (c->show_label
1530 && !c->show_label_in_corner))
1532 headings[row][column] = pivot_value_to_string (
1533 c->name, show_values, show_variables);
1534 if (!*headings[row][column])
1535 headings[row][column] = xstrdup ("<blank>");
1547 free_headings (const struct pivot_axis *axis, char ***headings)
1549 for (size_t i = 0; i < axis->label_depth; i++)
1551 for (size_t j = 0; j < axis->extent; j++)
1552 free (headings[i][j]);
1559 pivot_table_sizing_dump (const char *name,
1560 const int width_ranges[2],
1561 const struct pivot_table_sizing *s,
1564 indent (indentation);
1565 printf ("%ss: min=%d, max=%d\n", name, width_ranges[0], width_ranges[1]);
1568 indent (indentation + 1);
1569 printf ("%s widths:", name);
1570 for (size_t i = 0; i < s->n_widths; i++)
1571 printf (" %d", s->widths[i]);
1576 indent (indentation + 1);
1577 printf ("break after %ss:", name);
1578 for (size_t i = 0; i < s->n_breaks; i++)
1579 printf (" %zu", s->breaks[i]);
1584 indent (indentation + 1);
1585 printf ("keep %ss together:", name);
1586 for (size_t i = 0; i < s->n_keeps; i++)
1587 printf (" [%zu,%zu]",
1589 s->keeps[i].ofs + s->keeps[i].n - 1);
1595 pivot_table_dump (const struct pivot_table *table, int indentation)
1600 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1601 if (table->decimal == '.' || table->decimal == ',')
1602 settings_set_decimal_char (table->decimal);
1604 pivot_table_dump_value (table->title, "title", indentation);
1605 pivot_table_dump_value (table->subtype, "subtype", indentation);
1606 pivot_table_dump_string (table->command_c, "command", indentation);
1607 pivot_table_dump_string (table->dataset, "dataset", indentation);
1608 pivot_table_dump_string (table->datafile, "datafile", indentation);
1609 pivot_table_dump_string (table->notes, "notes", indentation);
1610 pivot_table_dump_string (table->look->name, "table-look", indentation);
1613 indent (indentation);
1615 struct tm *tm = localtime (&table->date);
1616 printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
1617 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
1621 indent (indentation);
1622 printf ("sizing:\n");
1623 pivot_table_sizing_dump ("column", table->look->width_ranges[TABLE_HORZ],
1624 &table->sizing[TABLE_HORZ], indentation + 1);
1625 pivot_table_sizing_dump ("row", table->look->width_ranges[TABLE_VERT],
1626 &table->sizing[TABLE_VERT], indentation + 1);
1628 indent (indentation);
1629 printf ("areas:\n");
1630 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1631 table_area_style_dump (area, &table->look->areas[area], indentation + 1);
1633 indent (indentation);
1634 printf ("borders:\n");
1635 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1636 table_border_style_dump (border, &table->look->borders[border],
1639 for (size_t i = 0; i < table->n_dimensions; i++)
1640 pivot_dimension_dump (table->dimensions[i], indentation);
1642 /* Presentation and data indexes. */
1643 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1645 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1646 if (layer_axis->n_dimensions)
1648 indent (indentation);
1649 printf ("current layer:");
1651 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1653 const struct pivot_dimension *d = layer_axis->dimensions[i];
1654 char *name = pivot_value_to_string (d->root->name,
1656 table->show_variables);
1657 char *value = pivot_value_to_string (
1658 d->data_leaves[table->current_layer[i]]->name,
1659 table->show_values, table->show_variables);
1660 printf (" %s=%s", name, value);
1668 size_t *layer_indexes;
1669 size_t layer_iteration = 0;
1670 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1672 indent (indentation);
1673 printf ("layer %zu:", layer_iteration++);
1675 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1676 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1678 const struct pivot_dimension *d = layer_axis->dimensions[i];
1680 fputs (i == 0 ? " " : ", ", stdout);
1681 pivot_value_dump (d->root->name);
1682 fputs (" =", stdout);
1684 struct pivot_value **names = xnmalloc (d->n_leaves, sizeof *names);
1686 for (const struct pivot_category *c
1687 = d->presentation_leaves[layer_indexes[i]];
1691 if (pivot_category_is_leaf (c) || c->show_label)
1692 names[n_names++] = c->name;
1695 for (size_t i = n_names; i-- > 0;)
1698 pivot_value_dump (names[i]);
1704 size_t *column_enumeration = pivot_table_enumerate_axis (
1705 table, PIVOT_AXIS_COLUMN, layer_indexes, table->look->omit_empty, NULL);
1706 size_t *row_enumeration = pivot_table_enumerate_axis (
1707 table, PIVOT_AXIS_ROW, layer_indexes, table->look->omit_empty, NULL);
1709 char ***column_headings = compose_headings (
1710 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1711 table->show_values, table->show_variables);
1712 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1714 indent (indentation + 1);
1715 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1718 fputs ("; ", stdout);
1719 if (column_headings[y][x])
1720 fputs (column_headings[y][x], stdout);
1724 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1726 indent (indentation + 1);
1727 printf ("-----------------------------------------------\n");
1729 char ***row_headings = compose_headings (
1730 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1731 table->show_values, table->show_variables);
1734 const size_t *pindexes[PIVOT_N_AXES]
1735 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1736 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1737 &table->axes[PIVOT_AXIS_ROW])
1739 indent (indentation + 1);
1742 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1745 fputs ("; ", stdout);
1746 if (row_headings[y][x])
1747 fputs (row_headings[y][x], stdout);
1753 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1755 &table->axes[PIVOT_AXIS_COLUMN])
1760 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1761 const struct pivot_value *value = pivot_table_get (
1764 pivot_value_dump (value);
1771 free (column_enumeration);
1772 free (row_enumeration);
1773 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1776 pivot_table_dump_value (table->caption, "caption", indentation);
1778 for (size_t i = 0; i < table->n_footnotes; i++)
1780 const struct pivot_footnote *f = table->footnotes[i];
1781 indent (indentation);
1784 pivot_value_dump (f->marker);
1786 printf ("%zu", f->idx);
1788 pivot_value_dump (f->content);
1793 settings_set_decimal_char (old_decimal);
1797 consume_int (const char *p, size_t *n)
1800 while (c_isdigit (*p))
1801 *n = *n * 10 + (*p++ - '0');
1806 pivot_format_inner_template (struct string *out, const char *template,
1808 struct pivot_value **values, size_t n_values,
1809 enum settings_value_show show_values,
1810 enum settings_value_show show_variables)
1812 size_t args_consumed = 0;
1813 while (*template && *template != ':')
1815 if (*template == '\\' && template[1])
1817 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1820 else if (*template == escape)
1823 template = consume_int (template + 1, &index);
1824 if (index >= 1 && index <= n_values)
1826 pivot_value_format (values[index - 1], show_values,
1827 show_variables, out);
1828 args_consumed = MAX (args_consumed, index);
1832 ds_put_byte (out, *template++);
1834 return args_consumed;
1838 pivot_extract_inner_template (const char *template, const char **p)
1844 if (*template == '\\' && template[1] != '\0')
1846 else if (*template == ':')
1847 return template + 1;
1848 else if (*template == '\0')
1856 pivot_format_template (struct string *out, const char *template,
1857 const struct pivot_argument *args, size_t n_args,
1858 enum settings_value_show show_values,
1859 enum settings_value_show show_variables)
1863 if (*template == '\\' && template[1] != '\0')
1865 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1868 else if (*template == '^')
1871 template = consume_int (template + 1, &index);
1872 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1873 pivot_value_format (args[index - 1].values[0],
1874 show_values, show_variables, out);
1876 else if (*template == '[')
1878 const char *tmpl[2];
1879 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1880 template = pivot_extract_inner_template (template, &tmpl[1]);
1881 template += *template == ']';
1884 template = consume_int (template, &index);
1885 if (index < 1 || index > n_args)
1888 const struct pivot_argument *arg = &args[index - 1];
1889 size_t left = arg->n;
1892 struct pivot_value **values = arg->values + (arg->n - left);
1893 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1894 char escape = "%^"[tmpl_idx];
1895 size_t used = pivot_format_inner_template (
1896 out, tmpl[tmpl_idx], escape, values, left,
1897 show_values, show_variables);
1898 if (!used || used > left)
1904 ds_put_byte (out, *template++);
1908 static enum settings_value_show
1909 interpret_show (enum settings_value_show global_show,
1910 enum settings_value_show table_show,
1911 enum settings_value_show value_show,
1914 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1915 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1916 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1920 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1921 SHOW_VARIABLES control whether variable and value labels are included.
1923 The "body" omits subscripts and superscripts and footnotes. */
1925 pivot_value_format_body (const struct pivot_value *value,
1926 enum settings_value_show show_values,
1927 enum settings_value_show show_variables,
1930 enum settings_value_show show;
1931 bool numeric = false;
1933 switch (value->type)
1935 case PIVOT_VALUE_NUMERIC:
1936 show = interpret_show (settings_get_show_values (),
1938 value->numeric.show,
1939 value->numeric.value_label != NULL);
1940 if (show & SETTINGS_VALUE_SHOW_VALUE)
1942 char *s = data_out (&(union value) { .f = value->numeric.x },
1943 "UTF-8", &value->numeric.format);
1944 ds_put_cstr (out, s + strspn (s, " "));
1947 if (show & SETTINGS_VALUE_SHOW_LABEL)
1949 if (show & SETTINGS_VALUE_SHOW_VALUE)
1950 ds_put_byte (out, ' ');
1951 ds_put_cstr (out, value->numeric.value_label);
1953 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1956 case PIVOT_VALUE_STRING:
1957 show = interpret_show (settings_get_show_values (),
1960 value->string.value_label != NULL);
1961 if (show & SETTINGS_VALUE_SHOW_VALUE)
1963 if (value->string.hex)
1965 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1967 ds_put_format (out, "%02X", *p);
1970 ds_put_cstr (out, value->string.s);
1972 if (show & SETTINGS_VALUE_SHOW_LABEL)
1974 if (show & SETTINGS_VALUE_SHOW_VALUE)
1975 ds_put_byte (out, ' ');
1976 ds_put_cstr (out, value->string.value_label);
1980 case PIVOT_VALUE_VARIABLE:
1981 show = interpret_show (settings_get_show_variables (),
1983 value->variable.show,
1984 value->variable.var_label != NULL);
1985 if (show & SETTINGS_VALUE_SHOW_VALUE)
1986 ds_put_cstr (out, value->variable.var_name);
1987 if (show & SETTINGS_VALUE_SHOW_LABEL)
1989 if (show & SETTINGS_VALUE_SHOW_VALUE)
1990 ds_put_byte (out, ' ');
1991 ds_put_cstr (out, value->variable.var_label);
1995 case PIVOT_VALUE_TEXT:
1996 ds_put_cstr (out, value->text.local);
1999 case PIVOT_VALUE_TEMPLATE:
2000 pivot_format_template (out, value->template.local, value->template.args,
2001 value->template.n_args, show_values,
2009 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
2010 SHOW_VARIABLES control whether variable and value labels are included.
2012 Subscripts and footnotes are included. */
2014 pivot_value_format (const struct pivot_value *value,
2015 enum settings_value_show show_values,
2016 enum settings_value_show show_variables,
2019 pivot_value_format_body (value, show_values, show_variables, out);
2021 if (value->n_subscripts)
2023 for (size_t i = 0; i < value->n_subscripts; i++)
2024 ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
2027 for (size_t i = 0; i < value->n_footnotes; i++)
2029 ds_put_byte (out, '^');
2030 pivot_value_format (value->footnotes[i]->marker,
2031 show_values, show_variables, out);
2035 /* Returns a text representation of VALUE. The caller must free the string,
2038 pivot_value_to_string (const struct pivot_value *value,
2039 enum settings_value_show show_values,
2040 enum settings_value_show show_variables)
2042 struct string s = DS_EMPTY_INITIALIZER;
2043 pivot_value_format (value, show_values, show_variables, &s);
2044 return ds_steal_cstr (&s);
2047 /* Frees the data owned by V. */
2049 pivot_value_destroy (struct pivot_value *value)
2053 font_style_uninit (value->font_style);
2054 free (value->font_style);
2055 free (value->cell_style);
2056 /* Do not free the elements of footnotes because VALUE does not own
2058 free (value->footnotes);
2060 for (size_t i = 0; i < value->n_subscripts; i++)
2061 free (value->subscripts[i]);
2062 free (value->subscripts);
2064 switch (value->type)
2066 case PIVOT_VALUE_NUMERIC:
2067 free (value->numeric.var_name);
2068 free (value->numeric.value_label);
2071 case PIVOT_VALUE_STRING:
2072 free (value->string.s);
2073 free (value->string.var_name);
2074 free (value->string.value_label);
2077 case PIVOT_VALUE_VARIABLE:
2078 free (value->variable.var_name);
2079 free (value->variable.var_label);
2082 case PIVOT_VALUE_TEXT:
2083 free (value->text.local);
2084 if (value->text.c != value->text.local)
2085 free (value->text.c);
2086 if (value->text.id != value->text.local
2087 && value->text.id != value->text.c)
2088 free (value->text.id);
2091 case PIVOT_VALUE_TEMPLATE:
2092 free (value->template.local);
2093 if (value->template.id != value->template.local)
2094 free (value->template.id);
2095 for (size_t i = 0; i < value->template.n_args; i++)
2096 pivot_argument_uninit (&value->template.args[i]);
2097 free (value->template.args);
2104 /* Sets AREA to the style to use for VALUE, with defaults coming from
2105 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
2107 pivot_value_get_style (struct pivot_value *value,
2108 const struct font_style *base_font_style,
2109 const struct cell_style *base_cell_style,
2110 struct table_area_style *area)
2112 font_style_copy (NULL, &area->font_style, (value->font_style
2114 : base_font_style));
2115 area->cell_style = *(value->cell_style
2120 /* Copies AREA into VALUE's style. */
2122 pivot_value_set_style (struct pivot_value *value,
2123 const struct table_area_style *area)
2125 if (value->font_style)
2126 font_style_uninit (value->font_style);
2128 value->font_style = xmalloc (sizeof *value->font_style);
2129 font_style_copy (NULL, value->font_style, &area->font_style);
2131 if (!value->cell_style)
2132 value->cell_style = xmalloc (sizeof *value->cell_style);
2133 *value->cell_style = area->cell_style;
2136 /* Frees the data owned by ARG (but not ARG itself). */
2138 pivot_argument_uninit (struct pivot_argument *arg)
2142 for (size_t i = 0; i < arg->n; i++)
2143 pivot_value_destroy (arg->values[i]);
2148 /* Creates and returns a new pivot_value whose contents is the null-terminated
2149 string TEXT. Takes ownership of TEXT.
2151 This function is for text strings provided by the user (with the exception
2152 that pivot_value_new_variable() should be used for variable names). For
2153 strings that are part of the PSPP user interface, such as names of
2154 procedures, statistics, annotations, error messages, etc., use
2155 pivot_value_new_text(). */
2156 struct pivot_value *
2157 pivot_value_new_user_text_nocopy (char *text)
2159 struct pivot_value *value = xmalloc (sizeof *value);
2160 *value = (struct pivot_value) {
2161 .type = PIVOT_VALUE_TEXT,
2166 .user_provided = true,
2172 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2173 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2176 This function is for text strings provided by the user (with the exception
2177 that pivot_value_new_variable() should be used for variable names). For
2178 strings that are part of the PSPP user interface, such as names of
2179 procedures, statistics, annotations, error messages, etc., use
2180 pivot_value_new_text().j
2182 The caller retains ownership of TEXT.*/
2183 struct pivot_value *
2184 pivot_value_new_user_text (const char *text, size_t length)
2186 return pivot_value_new_user_text_nocopy (
2187 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2190 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2191 a translatable string, but not actually translated yet, e.g. enclosed in
2192 N_(). This function is for text strings that are part of the PSPP user
2193 interface, such as names of procedures, statistics, annotations, error
2194 messages, etc. For strings that come from the user, use
2195 pivot_value_new_user_text(). */
2196 struct pivot_value *
2197 pivot_value_new_text (const char *text)
2199 char *c = xstrdup (text);
2200 char *local = xstrdup (gettext (c));
2202 struct pivot_value *value = xmalloc (sizeof *value);
2203 *value = (struct pivot_value) {
2204 .type = PIVOT_VALUE_TEXT,
2209 .user_provided = false,
2215 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2217 struct pivot_value * PRINTF_FORMAT (1, 2)
2218 pivot_value_new_text_format (const char *format, ...)
2221 va_start (args, format);
2222 char *c = xvasprintf (format, args);
2225 va_start (args, format);
2226 char *local = xvasprintf (gettext (format), args);
2229 struct pivot_value *value = xmalloc (sizeof *value);
2230 *value = (struct pivot_value) {
2231 .type = PIVOT_VALUE_TEXT,
2236 .user_provided = false,
2242 /* Returns a new pivot_value that represents X.
2244 The format to use for X is unspecified. Usually the easiest way to specify
2245 a format is through assigning a result class to one of the categories that
2246 the pivot_value will end up in. If that is not suitable, then the caller
2247 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2248 struct pivot_value *
2249 pivot_value_new_number (double x)
2251 struct pivot_value *value = xmalloc (sizeof *value);
2252 *value = (struct pivot_value) {
2253 .type = PIVOT_VALUE_NUMERIC,
2254 .numeric = { .x = x, },
2259 /* Returns a new pivot_value that represents X, formatted as an integer. */
2260 struct pivot_value *
2261 pivot_value_new_integer (double x)
2263 struct pivot_value *value = pivot_value_new_number (x);
2264 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2268 /* Returns a new pivot_value that represents VALUE, formatted as for
2270 struct pivot_value *
2271 pivot_value_new_var_value (const struct variable *variable,
2272 const union value *value)
2274 struct pivot_value *pv = pivot_value_new_value (
2275 value, var_get_width (variable), var_get_print_format (variable),
2276 var_get_encoding (variable));
2278 char *var_name = xstrdup (var_get_name (variable));
2279 if (var_is_alpha (variable))
2280 pv->string.var_name = var_name;
2282 pv->numeric.var_name = var_name;
2284 const char *label = var_lookup_value_label (variable, value);
2287 if (var_is_alpha (variable))
2288 pv->string.value_label = xstrdup (label);
2290 pv->numeric.value_label = xstrdup (label);
2296 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2297 formatted with FORMAT. For a string value, ENCODING must be its character
2299 struct pivot_value *
2300 pivot_value_new_value (const union value *value, int width,
2301 const struct fmt_spec *format, const char *encoding)
2303 struct pivot_value *pv = xzalloc (sizeof *pv);
2306 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2308 size_t n = strlen (s);
2309 while (n > 0 && s[n - 1] == ' ')
2312 pv->type = PIVOT_VALUE_STRING;
2314 pv->string.hex = format->type == FMT_AHEX;
2318 pv->type = PIVOT_VALUE_NUMERIC;
2319 pv->numeric.x = value->f;
2320 pv->numeric.format = *format;
2326 /* Returns a new pivot_value for VARIABLE. */
2327 struct pivot_value *
2328 pivot_value_new_variable (const struct variable *variable)
2330 struct pivot_value *value = xmalloc (sizeof *value);
2331 *value = (struct pivot_value) {
2332 .type = PIVOT_VALUE_VARIABLE,
2334 .var_name = xstrdup (var_get_name (variable)),
2335 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2341 /* Attaches a reference to FOOTNOTE to V. */
2343 pivot_value_add_footnote (struct pivot_value *v,
2344 const struct pivot_footnote *footnote)
2346 /* Some legacy tables include numerous duplicate footnotes. Suppress
2348 for (size_t i = 0; i < v->n_footnotes; i++)
2349 if (v->footnotes[i] == footnote)
2352 v->footnotes = xrealloc (v->footnotes,
2353 (v->n_footnotes + 1) * sizeof *v->footnotes);
2354 v->footnotes[v->n_footnotes++] = footnote;
2357 /* If VALUE is a numeric value, and RC is a result class such as
2358 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2360 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2363 if (value->type == PIVOT_VALUE_NUMERIC)
2365 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2367 value->numeric.format = *f;