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 "libpspp/hash-functions.h"
28 #include "libpspp/i18n.h"
29 #include "output/driver.h"
31 #include "gl/c-ctype.h"
32 #include "gl/intprops.h"
33 #include "gl/minmax.h"
34 #include "gl/xalloc.h"
35 #include "gl/xmemdup0.h"
39 #define _(msgid) gettext (msgid)
40 #define N_(msgid) msgid
42 static const struct fmt_spec *pivot_table_get_format (
43 const struct pivot_table *, const char *s);
45 /* Pivot table display styling. */
47 /* Returns the name of AREA. */
49 pivot_area_to_string (enum pivot_area area)
53 case PIVOT_AREA_TITLE: return "title";
54 case PIVOT_AREA_CAPTION: return "caption";
55 case PIVOT_AREA_FOOTER: return "footer";
56 case PIVOT_AREA_CORNER: return "corner";
57 case PIVOT_AREA_COLUMN_LABELS: return "column labels";
58 case PIVOT_AREA_ROW_LABELS: return "row labels";
59 case PIVOT_AREA_DATA: return "data";
60 case PIVOT_AREA_LAYERS: return "layers";
61 case PIVOT_N_AREAS: default: return "**error**";
65 const struct area_style *
66 pivot_area_get_default_style (enum pivot_area area)
68 #define STYLE(BOLD, H, V, L, R, T, B) { \
70 .halign = TABLE_HALIGN_##H, \
71 .valign = TABLE_VALIGN_##V, \
72 .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
73 [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
77 .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
78 .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
79 .typeface = (char *) "Sans Serif", \
82 static const struct area_style default_area_styles[PIVOT_N_AREAS] = {
83 [PIVOT_AREA_TITLE] = STYLE( true, CENTER, CENTER, 8,11,1,8),
84 [PIVOT_AREA_CAPTION] = STYLE(false, LEFT, TOP, 8,11,1,1),
85 [PIVOT_AREA_FOOTER] = STYLE(false, LEFT, TOP, 11, 8,2,3),
86 [PIVOT_AREA_CORNER] = STYLE(false, LEFT, BOTTOM, 8,11,1,1),
87 [PIVOT_AREA_COLUMN_LABELS] = STYLE(false, CENTER, BOTTOM, 8,11,1,3),
88 [PIVOT_AREA_ROW_LABELS] = STYLE(false, LEFT, TOP, 8,11,1,3),
89 [PIVOT_AREA_DATA] = STYLE(false, MIXED, TOP, 8,11,1,1),
90 [PIVOT_AREA_LAYERS] = STYLE(false, LEFT, BOTTOM, 8,11,1,3),
94 return &default_area_styles[area];
98 pivot_border_get_default_style (enum pivot_border border,
99 struct table_border_style *style)
101 static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
102 [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE,
103 [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE,
104 [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE,
105 [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE,
106 [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
107 [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK,
108 [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK,
109 [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK,
110 [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
111 [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK,
112 [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK,
113 [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
114 [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
115 [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
116 [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
117 [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
118 [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
119 [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
120 [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
122 *style = (struct table_border_style) {
123 .stroke = default_strokes[border],
124 .color = CELL_COLOR_BLACK,
128 /* Returns the name of BORDER. */
130 pivot_border_to_string (enum pivot_border border)
134 case PIVOT_BORDER_TITLE:
137 case PIVOT_BORDER_OUTER_LEFT:
138 return "left outer frame";
139 case PIVOT_BORDER_OUTER_TOP:
140 return "top outer frame";
141 case PIVOT_BORDER_OUTER_RIGHT:
142 return "right outer frame";
143 case PIVOT_BORDER_OUTER_BOTTOM:
144 return "bottom outer frame";
146 case PIVOT_BORDER_INNER_LEFT:
147 return "left inner frame";
148 case PIVOT_BORDER_INNER_TOP:
149 return "top inner frame";
150 case PIVOT_BORDER_INNER_RIGHT:
151 return "right inner frame";
152 case PIVOT_BORDER_INNER_BOTTOM:
153 return "bottom inner frame";
155 case PIVOT_BORDER_DATA_LEFT:
156 return "data area left";
157 case PIVOT_BORDER_DATA_TOP:
158 return "data area top";
160 case PIVOT_BORDER_DIM_ROW_HORZ:
161 return "row label horizontal dimension border";
162 case PIVOT_BORDER_DIM_ROW_VERT:
163 return "row label vertical dimension border";
164 case PIVOT_BORDER_DIM_COL_HORZ:
165 return "column label horizontal dimension border";
166 case PIVOT_BORDER_DIM_COL_VERT:
167 return "column label vertical dimension border";
169 case PIVOT_BORDER_CAT_ROW_HORZ:
170 return "row label horizontal category border";
171 case PIVOT_BORDER_CAT_ROW_VERT:
172 return "row label vertical category border";
173 case PIVOT_BORDER_CAT_COL_HORZ:
174 return "column label horizontal category border";
175 case PIVOT_BORDER_CAT_COL_VERT:
176 return "column label vertical category border";
178 case PIVOT_N_BORDERS:
185 pivot_table_sizing_uninit (struct pivot_table_sizing *sizing)
189 free (sizing->widths);
190 free (sizing->breaks);
191 free (sizing->keeps);
197 /* Returns the name of AXIS_TYPE. */
199 pivot_axis_type_to_string (enum pivot_axis_type axis_type)
203 case PIVOT_AXIS_LAYER:
209 case PIVOT_AXIS_COLUMN:
217 static enum pivot_axis_type
218 pivot_axis_type_transpose (enum pivot_axis_type axis_type)
220 assert (axis_type == PIVOT_AXIS_ROW || axis_type == PIVOT_AXIS_COLUMN);
221 return (axis_type == PIVOT_AXIS_ROW ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW);
224 /* Implementation of PIVOT_AXIS_FOR_EACH. */
226 pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis)
230 if (axis->n_dimensions)
231 for (size_t i = 0; i < axis->n_dimensions; i++)
232 if (axis->dimensions[i]->n_leaves == 0)
235 return xcalloc (axis->n_dimensions, sizeof *indexes);
238 for (size_t i = 0; i < axis->n_dimensions; i++)
240 const struct pivot_dimension *d = axis->dimensions[i];
241 if (++indexes[i] < d->n_leaves)
254 pivot_category_set_rc (struct pivot_category *category, const char *s)
256 const struct fmt_spec *format = pivot_table_get_format (
257 category->dimension->table, s);
259 category->format = *format;
263 pivot_category_create_leaves_valist (struct pivot_category *parent,
267 while ((s = va_arg (args, const char *)))
269 if (!strncmp (s, "RC_", 3))
271 assert (parent->n_subs);
272 pivot_category_set_rc (parent->subs[parent->n_subs - 1], s);
275 pivot_category_create_leaf (parent, pivot_value_new_text (s));
279 /* Creates a new dimension with the given NAME in TABLE and returns it. The
280 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
283 NAME should be a translatable name, but not actually translated yet,
284 e.g. enclosed in N_(). To use a different kind of value for a name, use
285 pivot_dimension_create__() instead.
287 The optional varargs parameters may be used to add an initial set of
288 categories to the dimension. Each string should be a translatable category
289 name, but not actually translated yet, e.g. enclosed in N_(). Each string
290 may optionally be followod by a PIVOT_RC_* string that specifies the default
291 numeric format for cells in this category. */
292 struct pivot_dimension * SENTINEL (0)
293 (pivot_dimension_create) (struct pivot_table *table,
294 enum pivot_axis_type axis_type,
295 const char *name, ...)
297 struct pivot_dimension *d = pivot_dimension_create__ (
298 table, axis_type, pivot_value_new_text (name));
301 va_start (args, name);
302 pivot_category_create_leaves_valist (d->root, args);
308 /* Creates a new dimension with the given NAME in TABLE and returns it. The
309 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
311 struct pivot_dimension *
312 pivot_dimension_create__ (struct pivot_table *table,
313 enum pivot_axis_type axis_type,
314 struct pivot_value *name)
316 assert (pivot_table_is_empty (table));
318 struct pivot_dimension *d = xmalloc (sizeof *d);
319 *d = (struct pivot_dimension) {
321 .axis_type = axis_type,
322 .level = table->axes[axis_type].n_dimensions,
323 .top_index = table->n_dimensions,
324 .root = xmalloc (sizeof *d->root),
327 struct pivot_category *root = d->root;
328 *root = (struct pivot_category) {
333 .data_index = SIZE_MAX,
334 .presentation_index = SIZE_MAX,
337 table->dimensions = xrealloc (
338 table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions);
339 table->dimensions[table->n_dimensions++] = d;
341 struct pivot_axis *axis = &table->axes[axis_type];
342 axis->dimensions = xrealloc (
343 axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
344 axis->dimensions[axis->n_dimensions++] = d;
346 if (axis_type == PIVOT_AXIS_LAYER)
348 free (table->current_layer);
349 table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
350 sizeof *table->current_layer);
353 /* axis->extent and axis->label_depth will be calculated later. */
359 pivot_dimension_destroy (struct pivot_dimension *d)
364 pivot_category_destroy (d->root);
365 free (d->data_leaves);
366 free (d->presentation_leaves);
370 /* Returns the first leaf node in an in-order traversal that is a child of
372 static const struct pivot_category * UNUSED
373 pivot_category_first_leaf (const struct pivot_category *cat)
375 if (pivot_category_is_leaf (cat))
378 for (size_t i = 0; i < cat->n_subs; i++)
380 const struct pivot_category *first
381 = pivot_category_first_leaf (cat->subs[i]);
389 /* Returns the next leaf node in an in-order traversal starting at CAT, which
391 static const struct pivot_category * UNUSED
392 pivot_category_next_leaf (const struct pivot_category *cat)
394 assert (pivot_category_is_leaf (cat));
398 const struct pivot_category *parent = cat->parent;
401 for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
403 const struct pivot_category *next
404 = pivot_category_first_leaf (parent->subs[i]);
414 pivot_category_add_child (struct pivot_category *child)
416 struct pivot_category *parent = child->parent;
418 assert (pivot_category_is_group (parent));
419 if (parent->n_subs >= parent->allocated_subs)
420 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
421 sizeof *parent->subs);
422 parent->subs[parent->n_subs++] = child;
425 /* Adds leaf categories as a child of PARENT. To create top-level categories
426 within dimension 'd', pass 'd->root' for PARENT.
428 Each of the varargs parameters should be a string, each of which should be a
429 translatable category name, but not actually translated yet, e.g. enclosed
430 in N_(). Each string may optionally be followod by a PIVOT_RC_* string that
431 specifies the default numeric format for cells in this category.
433 Returns the category index, which is just a 0-based array index, for the
436 Leaves have to be created in in-order, that is, don't create a group and add
437 some leaves, then add leaves outside the group and try to add more leaves
440 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
442 int retval = parent->dimension->n_leaves;
445 va_start (args, parent);
446 pivot_category_create_leaves_valist (parent, args);
452 /* Creates a new leaf category with the given NAME as a child of PARENT. To
453 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
454 Returns the category index, which is just a 0-based array index, for the new
457 Leaves have to be created in in-order, that is, don't create a group and add
458 some leaves, then add leaves outside the group and try to add more leaves
461 pivot_category_create_leaf (struct pivot_category *parent,
462 struct pivot_value *name)
464 return pivot_category_create_leaf_rc (parent, name, NULL);
467 /* Creates a new leaf category with the given NAME as a child of PARENT. To
468 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
469 Returns the category index, which is just a 0-based array index, for the new
472 If RC is nonnull and the name of a result category, the category is assigned
473 that result category.
475 Leaves have to be created in in-order, that is, don't create a group and add
476 some leaves, then add leaves outside the group and try to add more leaves
479 pivot_category_create_leaf_rc (struct pivot_category *parent,
480 struct pivot_value *name, const char *rc)
482 struct pivot_dimension *d = parent->dimension;
484 struct pivot_category *leaf = xmalloc (sizeof *leaf);
485 *leaf = (struct pivot_category) {
489 .group_index = parent->n_subs,
490 .data_index = d->n_leaves,
491 .presentation_index = d->n_leaves,
494 if (d->n_leaves >= d->allocated_leaves)
496 d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
497 sizeof *d->data_leaves);
498 d->presentation_leaves = xrealloc (
499 d->presentation_leaves,
500 d->allocated_leaves * sizeof *d->presentation_leaves);
503 d->data_leaves[d->n_leaves] = leaf;
504 d->presentation_leaves[d->n_leaves] = leaf;
507 pivot_category_add_child (leaf);
509 /* Make sure that the new child is the last in in-order. */
510 assert (!pivot_category_next_leaf (leaf));
512 pivot_category_set_rc (leaf, rc);
514 return leaf->data_index;
517 /* Adds a new category group named NAME as a child of PARENT. To create a
518 top-level group within dimension 'd', pass 'd->root' for PARENT.
520 NAME should be a translatable name, but not actually translated yet,
521 e.g. enclosed in N_(). To use a different kind of value for a name, use
522 pivot_category_create_group__() instead.
524 The optional varargs parameters may be used to add an initial set of
525 categories to the group. Each string should be a translatable category
526 name, but not actually translated yet, e.g. enclosed in N_(). Each string
527 may optionally be followod by a PIVOT_RC_* string that specifies the default
528 numeric format for cells in this category.
530 Returns the new group. */
531 struct pivot_category * SENTINEL (0)
532 (pivot_category_create_group) (struct pivot_category *parent,
533 const char *name, ...)
535 struct pivot_category *group = pivot_category_create_group__ (
536 parent, pivot_value_new_text (name));
539 va_start (args, name);
540 pivot_category_create_leaves_valist (group, args);
546 /* Adds a new category group named NAME as a child of PARENT. To create a
547 top-level group within dimension 'd', pass 'd->root' for PARENT. Returns
549 struct pivot_category *
550 pivot_category_create_group__ (struct pivot_category *parent,
551 struct pivot_value *name)
553 struct pivot_dimension *d = parent->dimension;
555 struct pivot_category *group = xmalloc (sizeof *group);
556 *group = (struct pivot_category) {
561 .group_index = parent->n_subs,
562 .data_index = SIZE_MAX,
563 .presentation_index = SIZE_MAX,
566 pivot_category_add_child (group);
572 pivot_category_destroy (struct pivot_category *c)
577 pivot_value_destroy (c->name);
578 for (size_t i = 0; i < c->n_subs; i++)
579 pivot_category_destroy (c->subs[i]);
586 These are usually the easiest way to control the formatting of numeric data
587 in a pivot table. See pivot_dimension_create() for an explanation of their
591 const char *name; /* "RC_*". */
592 struct fmt_spec format;
595 /* Formats for most of the result classes. */
596 static struct result_class result_classes[] =
598 { PIVOT_RC_INTEGER, { FMT_F, 40, 0 } },
599 { PIVOT_RC_PERCENT, { FMT_PCT, 40, 1 } },
600 { PIVOT_RC_CORRELATION, { FMT_F, 40, 3 } },
601 { PIVOT_RC_SIGNIFICANCE, { FMT_F, 40, 3 } },
602 { PIVOT_RC_RESIDUAL, { FMT_F, 40, 2 } },
603 { PIVOT_RC_COUNT, { 0, 0, 0 } },
604 { PIVOT_RC_OTHER, { 0, 0, 0 } },
607 /* Has PIVOT_RC_COUNT been overridden by the user? */
608 static bool overridden_count_format;
610 static struct result_class *
611 pivot_result_class_find (const char *s)
613 for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
614 if (!strcmp (s, result_classes[i].name))
615 return &result_classes[i];
619 static const struct fmt_spec *
620 pivot_table_get_format (const struct pivot_table *table, const char *s)
624 else if (!strcmp (s, PIVOT_RC_OTHER))
625 return settings_get_format ();
626 else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
627 return &table->weight_format;
630 const struct result_class *rc = pivot_result_class_find (s);
631 return rc ? &rc->format : NULL;
635 /* Sets the format specification for the result class named S (which should not
636 include the RC_ prefix) to *FORMAT. Returns true if successful, false if S
637 does not name a known result class. */
639 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
641 char *s = xasprintf ("RC_%s", s_);
642 struct result_class *rc = pivot_result_class_find (s);
645 rc->format = *format;
646 if (!strcmp (s, PIVOT_RC_COUNT))
647 overridden_count_format = true;
656 /* Creates and returns a new pivot table with the given TITLE. TITLE should be
657 a text string marked for translation but not actually translated yet,
658 e.g. N_("Descriptive Statistics"). The un-translated text string is used as
659 the pivot table's subtype.
661 Operations commonly performed on the new pivot_table:
663 - If empty rows or columns should not be displayed, set ->omit_empty to
666 - Set the format to use for "count" values with pivot_table_set_weight_var()
667 or pivot_table_set_weight_format().
669 This function is a shortcut for pivot_table_create__() for the most common
670 case. Use pivot_table_create__() directly if the title should be some kind
671 of value other than an ordinary text string, or if the subtype should be
672 different from the title.
674 See the large comment at the top of pivot-table.h for general advice on
675 creating pivot tables. */
677 pivot_table_create (const char *title)
679 return pivot_table_create__ (pivot_value_new_text (title), title);
682 /* Creates and returns a new pivot table with the given TITLE, and takes
683 ownership of TITLE. The new pivot table's subtype is SUBTYPE, which
684 should be an untranslated English string that describes the contents of
685 the table at a high level without being specific about the variables or
686 other context involved.
688 Operations commonly performed on the new pivot_table:
690 - If empty rows or columns should not be displayed, set ->omit_empty to
693 - Set the format to use for "count" values with pivot_table_set_weight_var()
694 or pivot_table_set_weight_format().
696 See the large comment at the top of pivot-table.h for general advice on
697 creating pivot tables. */
699 pivot_table_create__ (struct pivot_value *title, const char *subtype)
701 struct pivot_table *table = xzalloc (sizeof *table);
703 table->show_caption = true;
704 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
705 table->title = title;
706 table->subtype = subtype ? pivot_value_new_text (subtype) : NULL;
707 table->command_c = output_get_command_name ();
709 table->sizing[TABLE_HORZ].range[0] = 50;
710 table->sizing[TABLE_HORZ].range[1] = 72;
711 table->sizing[TABLE_VERT].range[0] = 36;
712 table->sizing[TABLE_VERT].range[1] = 120;
714 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
715 area_style_copy (NULL, &table->areas[i], pivot_area_get_default_style (i));
717 /* Set default border styles. */
718 static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
719 [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE,
720 [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE,
721 [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE,
722 [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE,
723 [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
724 [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK,
725 [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK,
726 [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK,
727 [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
728 [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK,
729 [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK,
730 [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
731 [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
732 [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
733 [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
734 [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
735 [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
736 [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
737 [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
739 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
740 table->borders[i] = (struct table_border_style) {
741 .stroke = default_strokes[i],
742 .color = CELL_COLOR_BLACK,
745 table->row_labels_in_corner = true;
746 hmap_init (&table->cells);
751 /* Creates and returns a new pivot table with the given TITLE and a single cell
752 with the given CONTENT.
754 This is really just for error handling. */
756 pivot_table_create_for_text (struct pivot_value *title,
757 struct pivot_value *content)
759 struct pivot_table *table = pivot_table_create__ (title, "Error");
761 struct pivot_dimension *d = pivot_dimension_create (
762 table, PIVOT_AXIS_ROW, N_("Error"));
763 d->hide_all_labels = true;
764 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
766 pivot_table_put1 (table, 0, content);
771 /* Increases TABLE's reference count, indicating that it has an additional
772 owner. A pivot table that is shared among multiple owners must not be
775 pivot_table_ref (const struct pivot_table *table_)
777 struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
782 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
783 If TABLE no longer has any owners, it is freed. */
785 pivot_table_unref (struct pivot_table *table)
789 assert (table->ref_cnt > 0);
790 if (--table->ref_cnt)
793 free (table->current_layer);
794 free (table->table_look);
796 for (int i = 0; i < TABLE_N_AXES; i++)
797 pivot_table_sizing_uninit (&table->sizing[i]);
799 free (table->continuation);
801 for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
802 free (table->ccs[i]);
804 free (table->command_local);
805 free (table->command_c);
806 free (table->language);
807 free (table->locale);
809 free (table->dataset);
810 free (table->datafile);
812 for (size_t i = 0; i < table->n_footnotes; i++)
813 pivot_footnote_destroy (table->footnotes[i]);
814 free (table->footnotes);
816 pivot_value_destroy (table->title);
817 pivot_value_destroy (table->subtype);
818 pivot_value_destroy (table->corner_text);
819 pivot_value_destroy (table->caption);
821 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
822 area_style_uninit (&table->areas[i]);
824 for (size_t i = 0; i < table->n_dimensions; i++)
825 pivot_dimension_destroy (table->dimensions[i]);
826 free (table->dimensions);
828 for (size_t i = 0; i < PIVOT_N_AXES; i++)
829 free (table->axes[i].dimensions);
831 struct pivot_cell *cell, *next_cell;
832 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
835 hmap_delete (&table->cells, &cell->hmap_node);
836 pivot_value_destroy (cell->value);
839 hmap_destroy (&table->cells);
844 /* Returns true if TABLE has more than one owner. A pivot table that is shared
845 among multiple owners must not be modified. */
847 pivot_table_is_shared (const struct pivot_table *table)
849 return table->ref_cnt > 1;
852 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
853 WV, which should be the weight variable for the dictionary whose data or
854 statistics are being put into TABLE.
856 This has no effect if WV is NULL. */
858 pivot_table_set_weight_var (struct pivot_table *table,
859 const struct variable *wv)
862 pivot_table_set_weight_format (table, var_get_print_format (wv));
865 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
866 format for the dictionary whose data or statistics are being put into TABLE.
868 This has no effect if WFMT is NULL. */
870 pivot_table_set_weight_format (struct pivot_table *table,
871 const struct fmt_spec *wfmt)
874 table->weight_format = *wfmt;
877 /* Returns true if TABLE has no cells, false otherwise. */
879 pivot_table_is_empty (const struct pivot_table *table)
881 return hmap_is_empty (&table->cells);
885 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
887 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
891 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
893 for (size_t i = 0; i < n; i++)
900 static struct pivot_cell *
901 pivot_table_lookup_cell__ (const struct pivot_table *table,
902 const size_t *dindexes, unsigned int hash)
904 struct pivot_cell *cell;
905 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
907 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
912 static struct pivot_cell *
913 pivot_cell_allocate (size_t n_idx)
915 struct pivot_cell *cell UNUSED;
916 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
919 static struct pivot_cell *
920 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
922 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
923 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
926 cell = pivot_cell_allocate (table->n_dimensions);
927 for (size_t i = 0; i < table->n_dimensions; i++)
928 cell->idx[i] = dindexes[i];
930 hmap_insert (&table->cells, &cell->hmap_node, hash);
935 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
936 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
939 If VALUE is a numeric value without a specified format, this function checks
940 each of the categories designated by DINDEXES[] and takes the format from
941 the first category with a result class. If none has a result class, uses
942 the overall default numeric format. */
944 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
945 struct pivot_value *value)
947 assert (n == table->n_dimensions);
949 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
951 for (size_t i = 0; i < table->n_dimensions; i++)
953 const struct pivot_dimension *d = table->dimensions[i];
954 if (dindexes[i] < d->n_leaves)
956 const struct pivot_category *c = d->data_leaves[dindexes[i]];
959 value->numeric.format = c->format;
964 value->numeric.format = *settings_get_format ();
969 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
970 pivot_value_destroy (cell->value);
974 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
975 dimension. Takes ownership of VALUE. */
977 pivot_table_put1 (struct pivot_table *table, size_t idx1,
978 struct pivot_value *value)
980 size_t dindexes[] = { idx1 };
981 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
984 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
985 dimensions. Takes ownership of VALUE. */
987 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
988 struct pivot_value *value)
990 size_t dindexes[] = { idx1, idx2 };
991 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
994 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
995 have 3 dimensions. Takes ownership of VALUE. */
997 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
998 size_t idx3, struct pivot_value *value)
1000 size_t dindexes[] = { idx1, idx2, idx3 };
1001 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1004 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
1005 must have 4 dimensions. Takes ownership of VALUE. */
1007 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1008 size_t idx3, size_t idx4, struct pivot_value *value)
1010 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1011 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1014 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1015 automatically assigned marker.
1017 The footnote will only appear in output if it is referenced. Use
1018 pivot_value_add_footnote() to add a reference to the footnote. */
1019 struct pivot_footnote *
1020 pivot_table_create_footnote (struct pivot_table *table,
1021 struct pivot_value *content)
1023 return pivot_table_create_footnote__ (table, table->n_footnotes,
1027 static struct pivot_value *
1028 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1030 char text[INT_BUFSIZE_BOUND (size_t)];
1031 if (show_numeric_markers)
1032 snprintf (text, sizeof text, "%d", idx + 1);
1034 str_format_26adic (idx + 1, false, text, sizeof text);
1035 return pivot_value_new_user_text (text, -1);
1038 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1039 all lower indexes as a side effect). If MARKER is nonnull, sets the
1040 footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1041 struct pivot_footnote *
1042 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1043 struct pivot_value *marker,
1044 struct pivot_value *content)
1046 if (idx >= table->n_footnotes)
1048 while (idx >= table->allocated_footnotes)
1049 table->footnotes = x2nrealloc (table->footnotes,
1050 &table->allocated_footnotes,
1051 sizeof *table->footnotes);
1052 while (idx >= table->n_footnotes)
1054 struct pivot_footnote *f = xmalloc (sizeof *f);
1055 f->idx = table->n_footnotes;
1056 f->marker = pivot_make_default_footnote_marker (
1057 f->idx, table->show_numeric_markers);
1061 table->footnotes[table->n_footnotes++] = f;
1065 struct pivot_footnote *f = table->footnotes[idx];
1068 pivot_value_destroy (f->marker);
1073 pivot_value_destroy (f->content);
1074 f->content = content;
1079 /* Frees the data owned by F. */
1081 pivot_footnote_destroy (struct pivot_footnote *f)
1085 pivot_value_destroy (f->content);
1086 pivot_value_destroy (f->marker);
1091 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1092 indexes for each dimension in TABLE in DINDEXES[]. */
1094 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1095 const size_t *pindexes[PIVOT_N_AXES],
1096 size_t dindexes[/* table->n_dimensions */])
1098 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1100 const struct pivot_axis *axis = &table->axes[i];
1102 for (size_t j = 0; j < axis->n_dimensions; j++)
1104 const struct pivot_dimension *d = axis->dimensions[j];
1105 dindexes[d->top_index]
1106 = d->presentation_leaves[pindexes[i][j]]->data_index;
1112 pivot_table_enumerate_axis (const struct pivot_table *table,
1113 enum pivot_axis_type axis_type,
1114 const size_t *layer_indexes, bool omit_empty,
1117 const struct pivot_axis *axis = &table->axes[axis_type];
1118 if (!axis->n_dimensions)
1120 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1122 enumeration[1] = SIZE_MAX;
1127 else if (!axis->extent)
1129 size_t *enumeration = xmalloc (sizeof *enumeration);
1130 *enumeration = SIZE_MAX;
1136 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1137 axis->n_dimensions), 1),
1138 sizeof *enumeration);
1139 size_t *p = enumeration;
1140 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1142 size_t *axis_indexes;
1143 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1147 enum pivot_axis_type axis2_type
1148 = pivot_axis_type_transpose (axis_type);
1150 size_t *axis2_indexes;
1151 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1153 const size_t *pindexes[PIVOT_N_AXES];
1154 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1155 pindexes[axis_type] = axis_indexes;
1156 pindexes[axis2_type] = axis2_indexes;
1157 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1158 if (pivot_table_get (table, dindexes))
1164 free (axis2_indexes);
1167 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1168 p += axis->n_dimensions;
1172 *n = (p - enumeration) / axis->n_dimensions;
1178 static const struct pivot_cell *
1179 pivot_table_lookup_cell (const struct pivot_table *table,
1180 const size_t *dindexes)
1182 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1183 return pivot_table_lookup_cell__ (table, dindexes, hash);
1186 const struct pivot_value *
1187 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1189 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1190 return cell ? cell->value : NULL;
1193 struct pivot_value *
1194 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1196 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1198 cell->value = pivot_value_new_user_text ("", -1);
1203 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1205 if (pivot_category_is_group (category) && category->n_subs)
1206 for (size_t i = 0; i < category->n_subs; i++)
1207 distribute_extra_depth (category->subs[i], extra_depth);
1209 category->extra_depth += extra_depth;
1213 pivot_category_assign_label_depth (struct pivot_category *category,
1214 bool dimension_labels_in_corner)
1216 category->extra_depth = 0;
1218 if (pivot_category_is_group (category))
1221 for (size_t i = 0; i < category->n_subs; i++)
1223 pivot_category_assign_label_depth (category->subs[i], false);
1224 depth = MAX (depth, category->subs[i]->label_depth);
1227 for (size_t i = 0; i < category->n_subs; i++)
1229 struct pivot_category *sub = category->subs[i];
1231 size_t extra_depth = depth - sub->label_depth;
1233 distribute_extra_depth (sub, extra_depth);
1235 sub->label_depth = depth;
1238 category->show_label_in_corner = (category->show_label
1239 && dimension_labels_in_corner);
1240 category->label_depth
1241 = (category->show_label && !category->show_label_in_corner
1242 ? depth + 1 : depth);
1245 category->label_depth = 1;
1249 pivot_axis_assign_label_depth (struct pivot_table *table,
1250 enum pivot_axis_type axis_type,
1251 bool dimension_labels_in_corner)
1253 struct pivot_axis *axis = &table->axes[axis_type];
1254 bool any_label_shown_in_corner = false;
1255 axis->label_depth = 0;
1257 for (size_t i = 0; i < axis->n_dimensions; i++)
1259 struct pivot_dimension *d = axis->dimensions[i];
1260 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1261 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1262 axis->label_depth += d->label_depth;
1263 axis->extent *= d->n_leaves;
1265 if (d->root->show_label_in_corner)
1266 any_label_shown_in_corner = true;
1268 return any_label_shown_in_corner;
1272 pivot_table_assign_label_depth (struct pivot_table *table)
1274 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1275 if (pivot_axis_assign_label_depth (
1276 table, PIVOT_AXIS_ROW, (table->row_labels_in_corner
1277 && !table->corner_text))
1278 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1279 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1280 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1288 indent (int indentation)
1290 for (int i = 0; i < indentation * 2; i++)
1295 pivot_value_dump (const struct pivot_value *value)
1297 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1298 SETTINGS_VALUE_SHOW_DEFAULT);
1304 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1309 indent (indentation);
1310 printf ("%s: ", name);
1311 pivot_value_dump (value);
1317 pivot_table_dump_string (const char *string, const char *name, int indentation)
1321 indent (indentation);
1322 printf ("%s: %s\n", name, string);
1327 pivot_category_dump (const struct pivot_category *c, int indentation)
1329 indent (indentation);
1330 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1331 pivot_value_dump (c->name);
1334 if (pivot_category_is_leaf (c))
1335 printf ("data_index=%zu\n", c->data_index);
1338 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1341 for (size_t i = 0; i < c->n_subs; i++)
1342 pivot_category_dump (c->subs[i], indentation + 1);
1347 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1349 indent (indentation);
1350 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1351 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1353 pivot_category_dump (d->root, indentation + 1);
1357 area_style_dump (enum pivot_area area, const struct area_style *a,
1360 indent (indentation);
1361 printf ("%s: ", pivot_area_to_string (area));
1362 font_style_dump (&a->font_style);
1364 cell_style_dump (&a->cell_style);
1369 table_border_style_dump (enum pivot_border border,
1370 const struct table_border_style *b, int indentation)
1372 indent (indentation);
1373 printf ("%s: %s ", pivot_border_to_string (border),
1374 table_stroke_to_string (b->stroke));
1375 cell_color_dump (&b->color);
1380 compose_headings (const struct pivot_axis *axis,
1381 const size_t *column_enumeration,
1382 enum settings_value_show show_values,
1383 enum settings_value_show show_variables)
1385 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1388 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1389 for (size_t i = 0; i < axis->label_depth; i++)
1390 headings[i] = xcalloc (axis->extent, sizeof **headings);
1392 const size_t *indexes;
1394 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1396 int row = axis->label_depth - 1;
1397 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1399 const struct pivot_dimension *d = axis->dimensions[dim_index];
1400 if (d->hide_all_labels)
1402 for (const struct pivot_category *c
1403 = d->presentation_leaves[indexes[dim_index]];
1407 if (pivot_category_is_leaf (c) || (c->show_label
1408 && !c->show_label_in_corner))
1410 headings[row][column] = pivot_value_to_string (
1411 c->name, show_values, show_variables);
1412 if (!*headings[row][column])
1413 headings[row][column] = xstrdup ("<blank>");
1425 free_headings (const struct pivot_axis *axis, char ***headings)
1427 for (size_t i = 0; i < axis->label_depth; i++)
1429 for (size_t j = 0; j < axis->extent; j++)
1430 free (headings[i][j]);
1437 pivot_table_sizing_dump (const char *name, const struct pivot_table_sizing *s,
1440 indent (indentation);
1441 printf ("%ss: min=%d, max=%d\n", name, s->range[0], s->range[1]);
1444 indent (indentation + 1);
1445 printf ("%s widths:", name);
1446 for (size_t i = 0; i < s->n_widths; i++)
1447 printf (" %d", s->widths[i]);
1452 indent (indentation + 1);
1453 printf ("break after %ss:", name);
1454 for (size_t i = 0; i < s->n_breaks; i++)
1455 printf (" %zu", s->breaks[i]);
1460 indent (indentation + 1);
1461 printf ("keep %ss together:", name);
1462 for (size_t i = 0; i < s->n_keeps; i++)
1463 printf (" [%zu,%zu]",
1465 s->keeps[i].ofs + s->keeps[i].n - 1);
1471 pivot_table_dump (const struct pivot_table *table, int indentation)
1476 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1477 if (table->decimal == '.' || table->decimal == ',')
1478 settings_set_decimal_char (table->decimal);
1480 pivot_table_dump_value (table->title, "title", indentation);
1481 pivot_table_dump_string (table->command_c, "command", indentation);
1482 pivot_table_dump_string (table->dataset, "dataset", indentation);
1483 pivot_table_dump_string (table->datafile, "datafile", indentation);
1484 pivot_table_dump_string (table->notes, "notes", indentation);
1485 pivot_table_dump_string (table->table_look, "table-look", indentation);
1488 indent (indentation);
1490 printf ("date: %s", ctime_r (&table->date, buf));
1493 indent (indentation);
1494 printf ("sizing:\n");
1495 pivot_table_sizing_dump ("column", &table->sizing[TABLE_HORZ],
1497 pivot_table_sizing_dump ("row", &table->sizing[TABLE_VERT],
1500 indent (indentation);
1501 printf ("areas:\n");
1502 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1503 area_style_dump (area, &table->areas[area], indentation + 1);
1505 indent (indentation);
1506 printf ("borders:\n");
1507 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1508 table_border_style_dump (border, &table->borders[border], indentation + 1);
1510 for (size_t i = 0; i < table->n_dimensions; i++)
1511 pivot_dimension_dump (table->dimensions[i], indentation);
1513 /* Presentation and data indexes. */
1514 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1516 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1517 if (layer_axis->n_dimensions)
1519 indent (indentation);
1520 printf ("current layer:");
1522 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1524 const struct pivot_dimension *d = layer_axis->dimensions[i];
1525 char *name = pivot_value_to_string (d->root->name,
1527 table->show_variables);
1528 char *value = pivot_value_to_string (
1529 d->data_leaves[table->current_layer[i]]->name,
1530 table->show_values, table->show_variables);
1531 printf (" %s=%s", name, value);
1539 size_t *layer_indexes;
1540 size_t layer_iteration = 0;
1541 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1543 indent (indentation);
1544 printf ("layer %zu:", layer_iteration++);
1546 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1547 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1549 const struct pivot_dimension *d = layer_axis->dimensions[i];
1551 fputs (i == 0 ? " " : ", ", stdout);
1552 pivot_value_dump (d->root->name);
1553 fputs (" =", stdout);
1555 struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1558 for (const struct pivot_category *c
1559 = d->presentation_leaves[layer_indexes[i]];
1563 if (pivot_category_is_leaf (c) || c->show_label)
1564 names[n_names++] = c->name;
1567 for (size_t i = n_names; i-- > 0; )
1570 pivot_value_dump (names[i]);
1576 size_t *column_enumeration = pivot_table_enumerate_axis (
1577 table, PIVOT_AXIS_COLUMN, layer_indexes, table->omit_empty, NULL);
1578 size_t *row_enumeration = pivot_table_enumerate_axis (
1579 table, PIVOT_AXIS_ROW, layer_indexes, table->omit_empty, NULL);
1581 char ***column_headings = compose_headings (
1582 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1583 table->show_values, table->show_variables);
1584 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1586 indent (indentation + 1);
1587 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1590 fputs ("; ", stdout);
1591 if (column_headings[y][x])
1592 fputs (column_headings[y][x], stdout);
1596 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1598 indent (indentation + 1);
1599 printf ("-----------------------------------------------\n");
1601 char ***row_headings = compose_headings (
1602 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1603 table->show_values, table->show_variables);
1606 const size_t *pindexes[PIVOT_N_AXES]
1607 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1608 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1609 &table->axes[PIVOT_AXIS_ROW])
1611 indent (indentation + 1);
1614 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1617 fputs ("; ", stdout);
1618 if (row_headings[y][x])
1619 fputs (row_headings[y][x], stdout);
1625 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1627 &table->axes[PIVOT_AXIS_COLUMN])
1632 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1633 const struct pivot_value *value = pivot_table_get (
1636 pivot_value_dump (value);
1643 free (column_enumeration);
1644 free (row_enumeration);
1645 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1648 pivot_table_dump_value (table->caption, "caption", indentation);
1650 for (size_t i = 0; i < table->n_footnotes; i++)
1652 const struct pivot_footnote *f = table->footnotes[i];
1653 indent (indentation);
1656 pivot_value_dump (f->marker);
1658 printf ("%zu", f->idx);
1660 pivot_value_dump (f->content);
1665 settings_set_decimal_char (old_decimal);
1669 consume_int (const char *p, size_t *n)
1672 while (c_isdigit (*p))
1673 *n = *n * 10 + (*p++ - '0');
1678 pivot_format_inner_template (struct string *out, const char *template,
1680 struct pivot_value **values, size_t n_values,
1681 enum settings_value_show show_values,
1682 enum settings_value_show show_variables)
1684 size_t args_consumed = 0;
1685 while (*template && *template != ':')
1687 if (*template == '\\' && template[1])
1689 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1692 else if (*template == escape)
1695 template = consume_int (template + 1, &index);
1696 if (index >= 1 && index <= n_values)
1698 pivot_value_format (values[index - 1], show_values,
1699 show_variables, out);
1700 args_consumed = MAX (args_consumed, index);
1704 ds_put_byte (out, *template++);
1706 return args_consumed;
1710 pivot_extract_inner_template (const char *template, const char **p)
1716 if (*template == '\\' && template[1] != '\0')
1718 else if (*template == ':')
1719 return template + 1;
1720 else if (*template == '\0')
1728 pivot_format_template (struct string *out, const char *template,
1729 const struct pivot_argument *args, size_t n_args,
1730 enum settings_value_show show_values,
1731 enum settings_value_show show_variables)
1735 if (*template == '\\' && template[1] != '\0')
1737 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1740 else if (*template == '^')
1743 template = consume_int (template + 1, &index);
1744 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1745 pivot_value_format (args[index - 1].values[0],
1746 show_values, show_variables, out);
1748 else if (*template == '[')
1750 const char *tmpl[2];
1751 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1752 template = pivot_extract_inner_template (template, &tmpl[1]);
1753 template += *template == ']';
1756 template = consume_int (template, &index);
1757 if (index < 1 || index > n_args)
1760 const struct pivot_argument *arg = &args[index - 1];
1761 size_t left = arg->n;
1764 struct pivot_value **values = arg->values + (arg->n - left);
1765 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1766 char escape = "%^"[tmpl_idx];
1767 size_t used = pivot_format_inner_template (
1768 out, tmpl[tmpl_idx], escape, values, left,
1769 show_values, show_variables);
1770 if (!used || used > left)
1776 ds_put_byte (out, *template++);
1780 static enum settings_value_show
1781 interpret_show (enum settings_value_show global_show,
1782 enum settings_value_show table_show,
1783 enum settings_value_show value_show,
1786 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1787 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1788 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1792 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1793 SHOW_VARIABLES control whether variable and value labels are included.
1795 The "body" omits subscripts and superscripts and footnotes. */
1797 pivot_value_format_body (const struct pivot_value *value,
1798 enum settings_value_show show_values,
1799 enum settings_value_show show_variables,
1802 enum settings_value_show show;
1803 bool numeric = false;
1805 switch (value->type)
1807 case PIVOT_VALUE_NUMERIC:
1808 show = interpret_show (settings_get_show_values (),
1810 value->numeric.show,
1811 value->numeric.value_label != NULL);
1812 if (show & SETTINGS_VALUE_SHOW_VALUE)
1814 char *s = data_out (&(union value) { .f = value->numeric.x },
1815 "UTF-8", &value->numeric.format);
1816 ds_put_cstr (out, s + strspn (s, " "));
1819 if (show & SETTINGS_VALUE_SHOW_LABEL)
1821 if (show & SETTINGS_VALUE_SHOW_VALUE)
1822 ds_put_byte (out, ' ');
1823 ds_put_cstr (out, value->numeric.value_label);
1825 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1828 case PIVOT_VALUE_STRING:
1829 show = interpret_show (settings_get_show_values (),
1832 value->string.value_label != NULL);
1833 if (show & SETTINGS_VALUE_SHOW_VALUE)
1835 if (value->string.hex)
1837 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1839 ds_put_format (out, "%02X", *p);
1842 ds_put_cstr (out, value->string.s);
1844 if (show & SETTINGS_VALUE_SHOW_LABEL)
1846 if (show & SETTINGS_VALUE_SHOW_VALUE)
1847 ds_put_byte (out, ' ');
1848 ds_put_cstr (out, value->string.value_label);
1852 case PIVOT_VALUE_VARIABLE:
1853 show = interpret_show (settings_get_show_variables (),
1855 value->variable.show,
1856 value->variable.var_label != NULL);
1857 if (show & SETTINGS_VALUE_SHOW_VALUE)
1858 ds_put_cstr (out, value->variable.var_name);
1859 if (show & SETTINGS_VALUE_SHOW_LABEL)
1861 if (show & SETTINGS_VALUE_SHOW_VALUE)
1862 ds_put_byte (out, ' ');
1863 ds_put_cstr (out, value->variable.var_label);
1867 case PIVOT_VALUE_TEXT:
1868 ds_put_cstr (out, value->text.local);
1871 case PIVOT_VALUE_TEMPLATE:
1872 pivot_format_template (out, value->template.local, value->template.args,
1873 value->template.n_args, show_values,
1881 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
1882 SHOW_VARIABLES control whether variable and value labels are included.
1884 Subscripts and superscripts and footnotes are included. */
1886 pivot_value_format (const struct pivot_value *value,
1887 enum settings_value_show show_values,
1888 enum settings_value_show show_variables,
1891 pivot_value_format_body ( value, show_values, show_variables, out);
1893 if (value->n_subscripts)
1895 for (size_t i = 0; i < value->n_subscripts; i++)
1896 ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
1899 if (value->superscript)
1900 ds_put_format (out, "^%s", value->superscript);
1902 for (size_t i = 0; i < value->n_footnotes; i++)
1904 ds_put_byte (out, '^');
1905 pivot_value_format (value->footnotes[i]->marker,
1906 show_values, show_variables, out);
1910 /* Returns a text representation of VALUE. The caller must free the string,
1913 pivot_value_to_string (const struct pivot_value *value,
1914 enum settings_value_show show_values,
1915 enum settings_value_show show_variables)
1917 struct string s = DS_EMPTY_INITIALIZER;
1918 pivot_value_format (value, show_values, show_variables, &s);
1919 return ds_steal_cstr (&s);
1922 /* Frees the data owned by V. */
1924 pivot_value_destroy (struct pivot_value *value)
1928 font_style_uninit (value->font_style);
1929 free (value->font_style);
1930 free (value->cell_style);
1931 /* Do not free the elements of footnotes because VALUE does not own
1933 free (value->footnotes);
1935 for (size_t i = 0; i < value->n_subscripts; i++)
1936 free (value->subscripts[i]);
1937 free (value->subscripts);
1939 free (value->superscript);
1941 switch (value->type)
1943 case PIVOT_VALUE_NUMERIC:
1944 free (value->numeric.var_name);
1945 free (value->numeric.value_label);
1948 case PIVOT_VALUE_STRING:
1949 free (value->string.s);
1950 free (value->string.var_name);
1951 free (value->string.value_label);
1954 case PIVOT_VALUE_VARIABLE:
1955 free (value->variable.var_name);
1956 free (value->variable.var_label);
1959 case PIVOT_VALUE_TEXT:
1960 free (value->text.local);
1961 if (value->text.c != value->text.local)
1962 free (value->text.c);
1963 if (value->text.id != value->text.local
1964 && value->text.id != value->text.c)
1965 free (value->text.id);
1968 case PIVOT_VALUE_TEMPLATE:
1969 free (value->template.local);
1970 if (value->template.id != value->template.local)
1971 free (value->template.id);
1972 for (size_t i = 0; i < value->template.n_args; i++)
1973 pivot_argument_uninit (&value->template.args[i]);
1974 free (value->template.args);
1981 /* Sets AREA to the style to use for VALUE, with defaults coming from
1982 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
1984 pivot_value_get_style (struct pivot_value *value,
1985 const struct font_style *base_font_style,
1986 const struct cell_style *base_cell_style,
1987 struct area_style *area)
1989 font_style_copy (NULL, &area->font_style, (value->font_style
1991 : base_font_style));
1992 area->cell_style = *(value->cell_style
1997 /* Copies AREA into VALUE's style. */
1999 pivot_value_set_style (struct pivot_value *value,
2000 const struct area_style *area)
2002 if (value->font_style)
2003 font_style_uninit (value->font_style);
2005 value->font_style = xmalloc (sizeof *value->font_style);
2006 font_style_copy (NULL, value->font_style, &area->font_style);
2008 if (!value->cell_style)
2009 value->cell_style = xmalloc (sizeof *value->cell_style);
2010 *value->cell_style = area->cell_style;
2013 /* Frees the data owned by ARG (but not ARG itself). */
2015 pivot_argument_uninit (struct pivot_argument *arg)
2019 for (size_t i = 0; i < arg->n; i++)
2020 pivot_value_destroy (arg->values[i]);
2025 /* Creates and returns a new pivot_value whose contents is the null-terminated
2026 string TEXT. Takes ownership of TEXT.
2028 This function is for text strings provided by the user (with the exception
2029 that pivot_value_new_variable() should be used for variable names). For
2030 strings that are part of the PSPP user interface, such as names of
2031 procedures, statistics, annotations, error messages, etc., use
2032 pivot_value_new_text(). */
2033 struct pivot_value *
2034 pivot_value_new_user_text_nocopy (char *text)
2036 struct pivot_value *value = xmalloc (sizeof *value);
2037 *value = (struct pivot_value) {
2038 .type = PIVOT_VALUE_TEXT,
2043 .user_provided = true,
2049 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2050 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2053 This function is for text strings provided by the user (with the exception
2054 that pivot_value_new_variable() should be used for variable names). For
2055 strings that are part of the PSPP user interface, such as names of
2056 procedures, statistics, annotations, error messages, etc., use
2057 pivot_value_new_text().j
2059 The caller retains ownership of TEXT.*/
2060 struct pivot_value *
2061 pivot_value_new_user_text (const char *text, size_t length)
2063 return pivot_value_new_user_text_nocopy (
2064 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2067 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2068 a translatable string, but not actually translated yet, e.g. enclosed in
2069 N_(). This function is for text strings that are part of the PSPP user
2070 interface, such as names of procedures, statistics, annotations, error
2071 messages, etc. For strings that come from the user, use
2072 pivot_value_new_user_text(). */
2073 struct pivot_value *
2074 pivot_value_new_text (const char *text)
2076 char *c = xstrdup (text);
2077 char *local = xstrdup (gettext (c));
2079 struct pivot_value *value = xmalloc (sizeof *value);
2080 *value = (struct pivot_value) {
2081 .type = PIVOT_VALUE_TEXT,
2086 .user_provided = false,
2092 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2094 struct pivot_value * PRINTF_FORMAT (1, 2)
2095 pivot_value_new_text_format (const char *format, ...)
2098 va_start (args, format);
2099 char *c = xvasprintf (format, args);
2102 va_start (args, format);
2103 char *local = xvasprintf (gettext (format), args);
2106 struct pivot_value *value = xmalloc (sizeof *value);
2107 *value = (struct pivot_value) {
2108 .type = PIVOT_VALUE_TEXT,
2113 .user_provided = false,
2120 xstrdup_if_nonempty (const char *s)
2122 return s && s[0] ? xstrdup (s) : NULL;
2125 /* Returns a new pivot_value that represents X.
2127 The format to use for X is unspecified. Usually the easiest way to specify
2128 a format is through assigning a result class to one of the categories that
2129 the pivot_value will end up in. If that is not suitable, then the caller
2130 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2131 struct pivot_value *
2132 pivot_value_new_number (double x)
2134 struct pivot_value *value = xmalloc (sizeof *value);
2135 *value = (struct pivot_value) {
2136 .type = PIVOT_VALUE_NUMERIC,
2137 .numeric = { .x = x, },
2142 /* Returns a new pivot_value that represents X, formatted as an integer. */
2143 struct pivot_value *
2144 pivot_value_new_integer (double x)
2146 struct pivot_value *value = pivot_value_new_number (x);
2147 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2151 /* Returns a new pivot_value that represents VALUE, formatted as for
2153 struct pivot_value *
2154 pivot_value_new_var_value (const struct variable *variable,
2155 const union value *value)
2157 struct pivot_value *pv = pivot_value_new_value (
2158 value, var_get_width (variable), var_get_print_format (variable),
2159 var_get_encoding (variable));
2161 char *var_name = xstrdup (var_get_name (variable));
2162 if (var_is_alpha (variable))
2163 pv->string.var_name = var_name;
2165 pv->numeric.var_name = var_name;
2167 const char *label = var_lookup_value_label (variable, value);
2170 if (var_is_alpha (variable))
2171 pv->string.value_label = xstrdup (label);
2173 pv->numeric.value_label = xstrdup (label);
2179 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2180 formatted with FORMAT. For a string value, ENCODING must be its character
2182 struct pivot_value *
2183 pivot_value_new_value (const union value *value, int width,
2184 const struct fmt_spec *format, const char *encoding)
2186 struct pivot_value *pv = xzalloc (sizeof *pv);
2189 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2191 size_t n = strlen (s);
2192 while (n > 0 && s[n - 1] == ' ')
2195 pv->type = PIVOT_VALUE_STRING;
2197 pv->string.hex = format->type == FMT_AHEX;
2201 pv->type = PIVOT_VALUE_NUMERIC;
2202 pv->numeric.x = value->f;
2203 pv->numeric.format = *format;
2209 /* Returns a new pivot_value for VARIABLE. */
2210 struct pivot_value *
2211 pivot_value_new_variable (const struct variable *variable)
2213 struct pivot_value *value = xmalloc (sizeof *value);
2214 *value = (struct pivot_value) {
2215 .type = PIVOT_VALUE_VARIABLE,
2217 .var_name = xstrdup (var_get_name (variable)),
2218 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2224 /* Attaches a reference to FOOTNOTE to V. */
2226 pivot_value_add_footnote (struct pivot_value *v,
2227 const struct pivot_footnote *footnote)
2229 /* Some legacy tables include numerous duplicate footnotes. Suppress
2231 for (size_t i = 0; i < v->n_footnotes; i++)
2232 if (v->footnotes[i] == footnote)
2235 v->footnotes = xrealloc (v->footnotes,
2236 (v->n_footnotes + 1) * sizeof *v->footnotes);
2237 v->footnotes[v->n_footnotes++] = footnote;
2240 /* If VALUE is a numeric value, and RC is a result class such as
2241 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2243 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2246 if (value->type == PIVOT_VALUE_NUMERIC)
2248 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2250 value->numeric.format = *f;