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"
30 #include "gl/c-ctype.h"
31 #include "gl/intprops.h"
32 #include "gl/minmax.h"
33 #include "gl/xalloc.h"
34 #include "gl/xmemdup0.h"
38 #define _(msgid) gettext (msgid)
39 #define N_(msgid) msgid
41 static const struct fmt_spec *pivot_table_get_format (
42 const struct pivot_table *, const char *s);
44 /* Pivot table display styling. */
46 /* Returns the name of AREA. */
48 pivot_area_to_string (enum pivot_area area)
52 case PIVOT_AREA_TITLE: return "title";
53 case PIVOT_AREA_CAPTION: return "caption";
54 case PIVOT_AREA_FOOTER: return "footer";
55 case PIVOT_AREA_CORNER: return "corner";
56 case PIVOT_AREA_COLUMN_LABELS: return "column labels";
57 case PIVOT_AREA_ROW_LABELS: return "row labels";
58 case PIVOT_AREA_DATA: return "data";
59 case PIVOT_AREA_LAYERS: return "layers";
60 case PIVOT_N_AREAS: default: return "**error**";
65 pivot_area_get_default_style (enum pivot_area area, struct area_style *style)
67 #define STYLE(BOLD, H, V, L, R, T, B) { \
69 .halign = TABLE_HALIGN_##H, \
70 .valign = TABLE_VALIGN_##V, \
71 .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
72 [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
76 .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
77 .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
81 static const struct area_style default_area_styles[PIVOT_N_AREAS] = {
82 [PIVOT_AREA_TITLE] = STYLE( true, CENTER, CENTER, 8,11,1,8),
83 [PIVOT_AREA_CAPTION] = STYLE(false, LEFT, TOP, 8,11,1,1),
84 [PIVOT_AREA_FOOTER] = STYLE(false, LEFT, TOP, 11, 8,2,3),
85 [PIVOT_AREA_CORNER] = STYLE(false, LEFT, BOTTOM, 8,11,1,1),
86 [PIVOT_AREA_COLUMN_LABELS] = STYLE(false, CENTER, BOTTOM, 8,11,1,3),
87 [PIVOT_AREA_ROW_LABELS] = STYLE(false, LEFT, TOP, 8,11,1,3),
88 [PIVOT_AREA_DATA] = STYLE(false, MIXED, TOP, 8,11,1,1),
89 [PIVOT_AREA_LAYERS] = STYLE(false, LEFT, BOTTOM, 8,11,1,3),
93 *style = default_area_styles[area];
94 style->font_style.typeface = xstrdup ("SansSerif");
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 /* axis->extent and axis->label_depth will be calculated later. */
352 pivot_dimension_destroy (struct pivot_dimension *d)
357 pivot_category_destroy (d->root);
358 free (d->data_leaves);
359 free (d->presentation_leaves);
363 /* Returns the first leaf node in an in-order traversal that is a child of
365 static const struct pivot_category * UNUSED
366 pivot_category_first_leaf (const struct pivot_category *cat)
368 if (pivot_category_is_leaf (cat))
371 for (size_t i = 0; i < cat->n_subs; i++)
373 const struct pivot_category *first
374 = pivot_category_first_leaf (cat->subs[i]);
382 /* Returns the next leaf node in an in-order traversal starting at CAT, which
384 static const struct pivot_category * UNUSED
385 pivot_category_next_leaf (const struct pivot_category *cat)
387 assert (pivot_category_is_leaf (cat));
391 const struct pivot_category *parent = cat->parent;
394 for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
396 const struct pivot_category *next
397 = pivot_category_first_leaf (parent->subs[i]);
407 pivot_category_add_child (struct pivot_category *child)
409 struct pivot_category *parent = child->parent;
411 assert (pivot_category_is_group (parent));
412 if (parent->n_subs >= parent->allocated_subs)
413 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
414 sizeof *parent->subs);
415 parent->subs[parent->n_subs++] = child;
418 /* Adds leaf categories as a child of PARENT. To create top-level categories
419 within dimension 'd', pass 'd->root' for PARENT.
421 Each of the varargs parameters should be a string, each of which should be a
422 translatable category name, but not actually translated yet, e.g. enclosed
423 in N_(). Each string may optionally be followod by a PIVOT_RC_* string that
424 specifies the default numeric format for cells in this category.
426 Returns the category index, which is just a 0-based array index, for the
429 Leaves have to be created in in-order, that is, don't create a group and add
430 some leaves, then add leaves outside the group and try to add more leaves
433 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
435 int retval = parent->dimension->n_leaves;
438 va_start (args, parent);
439 pivot_category_create_leaves_valist (parent, args);
445 /* Creates a new leaf category with the given NAME as a child of PARENT. To
446 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
447 Returns the category index, which is just a 0-based array index, for the new
450 Leaves have to be created in in-order, that is, don't create a group and add
451 some leaves, then add leaves outside the group and try to add more leaves
454 pivot_category_create_leaf (struct pivot_category *parent,
455 struct pivot_value *name)
457 return pivot_category_create_leaf_rc (parent, name, NULL);
460 /* Creates a new leaf category with the given NAME as a child of PARENT. To
461 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
462 Returns the category index, which is just a 0-based array index, for the new
465 If RC is nonnull and the name of a result category, the category is assigned
466 that result category.
468 Leaves have to be created in in-order, that is, don't create a group and add
469 some leaves, then add leaves outside the group and try to add more leaves
472 pivot_category_create_leaf_rc (struct pivot_category *parent,
473 struct pivot_value *name, const char *rc)
475 struct pivot_dimension *d = parent->dimension;
477 struct pivot_category *leaf = xmalloc (sizeof *leaf);
478 *leaf = (struct pivot_category) {
482 .group_index = parent->n_subs,
483 .data_index = d->n_leaves,
484 .presentation_index = d->n_leaves,
487 if (d->n_leaves >= d->allocated_leaves)
489 d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
490 sizeof *d->data_leaves);
491 d->presentation_leaves = xrealloc (
492 d->presentation_leaves,
493 d->allocated_leaves * sizeof *d->presentation_leaves);
496 d->data_leaves[d->n_leaves] = leaf;
497 d->presentation_leaves[d->n_leaves] = leaf;
500 pivot_category_add_child (leaf);
502 /* Make sure that the new child is the last in in-order. */
503 assert (!pivot_category_next_leaf (leaf));
505 pivot_category_set_rc (leaf, rc);
507 return leaf->data_index;
510 /* Adds a new category group named NAME as a child of PARENT. To create a
511 top-level group within dimension 'd', pass 'd->root' for PARENT.
513 NAME should be a translatable name, but not actually translated yet,
514 e.g. enclosed in N_(). To use a different kind of value for a name, use
515 pivot_category_create_group__() instead.
517 The optional varargs parameters may be used to add an initial set of
518 categories to the group. Each string should be a translatable category
519 name, but not actually translated yet, e.g. enclosed in N_(). Each string
520 may optionally be followod by a PIVOT_RC_* string that specifies the default
521 numeric format for cells in this category.
523 Returns the new group. */
524 struct pivot_category * SENTINEL (0)
525 (pivot_category_create_group) (struct pivot_category *parent,
526 const char *name, ...)
528 struct pivot_category *group = pivot_category_create_group__ (
529 parent, pivot_value_new_text (name));
532 va_start (args, name);
533 pivot_category_create_leaves_valist (group, args);
539 /* Adds a new category group named NAME as a child of PARENT. To create a
540 top-level group within dimension 'd', pass 'd->root' for PARENT. Returns
542 struct pivot_category *
543 pivot_category_create_group__ (struct pivot_category *parent,
544 struct pivot_value *name)
546 struct pivot_dimension *d = parent->dimension;
548 struct pivot_category *group = xmalloc (sizeof *group);
549 *group = (struct pivot_category) {
554 .group_index = parent->n_subs,
555 .data_index = SIZE_MAX,
556 .presentation_index = SIZE_MAX,
559 pivot_category_add_child (group);
565 pivot_category_destroy (struct pivot_category *c)
570 pivot_value_destroy (c->name);
571 for (size_t i = 0; i < c->n_subs; i++)
572 pivot_category_destroy (c->subs[i]);
579 These are usually the easiest way to control the formatting of numeric data
580 in a pivot table. See pivot_dimension_create() for an explanation of their
584 const char *name; /* "RC_*". */
585 struct fmt_spec format;
588 /* Formats for most of the result classes. */
589 static struct result_class result_classes[] =
591 { PIVOT_RC_INTEGER, { FMT_F, 40, 0 } },
592 { PIVOT_RC_PERCENT, { FMT_PCT, 40, 1 } },
593 { PIVOT_RC_CORRELATION, { FMT_F, 40, 3 } },
594 { PIVOT_RC_SIGNIFICANCE, { FMT_F, 40, 3 } },
595 { PIVOT_RC_RESIDUAL, { FMT_F, 40, 2 } },
596 { PIVOT_RC_COUNT, { 0, 0, 0 } },
597 { PIVOT_RC_OTHER, { 0, 0, 0 } },
600 /* Has PIVOT_RC_COUNT been overridden by the user? */
601 static bool overridden_count_format;
603 static struct result_class *
604 pivot_result_class_find (const char *s)
606 for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
607 if (!strcmp (s, result_classes[i].name))
608 return &result_classes[i];
612 static const struct fmt_spec *
613 pivot_table_get_format (const struct pivot_table *table, const char *s)
617 else if (!strcmp (s, PIVOT_RC_OTHER))
618 return settings_get_format ();
619 else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
620 return &table->weight_format;
623 const struct result_class *rc = pivot_result_class_find (s);
624 return rc ? &rc->format : NULL;
628 /* Sets the format specification for the result class named S (which should not
629 include the RC_ prefix) to *FORMAT. Returns true if successful, false if S
630 does not name a known result class. */
632 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
634 char *s = xasprintf ("RC_%s", s_);
635 struct result_class *rc = pivot_result_class_find (s);
638 rc->format = *format;
639 if (!strcmp (s, PIVOT_RC_COUNT))
640 overridden_count_format = true;
649 /* Creates and returns a new pivot table with the given TITLE. TITLE should be
650 a text string marked for translation but not actually translated yet,
651 e.g. N_("Descriptive Statistics").
653 Operations commonly performed on the new pivot_table:
655 - If empty rows or columns should not be displayed, set ->omit_empty to
658 - Set the format to use for "count" values with pivot_table_set_weight_var()
659 or pivot_table_set_weight_format().
661 This function is a shortcut for pivot_table_create__() for the most common
662 case. Use pivot_table_create__() directly if the title should be some kind
663 of value other than an ordinary text string.
665 See the large comment at the top of pivot-table.h for general advice on
666 creating pivot tables. */
668 pivot_table_create (const char *title)
670 return pivot_table_create__ (pivot_value_new_text (title));
673 /* Creates and returns a new pivot table with the given TITLE.
675 Operations commonly performed on the new pivot_table:
677 - If empty rows or columns should not be displayed, set ->omit_empty to
680 - Set the format to use for "count" values with pivot_table_set_weight_var()
681 or pivot_table_set_weight_format().
683 See the large comment at the top of pivot-table.h for general advice on
684 creating pivot tables. */
686 pivot_table_create__ (struct pivot_value *title)
688 struct pivot_table *table = xzalloc (sizeof *table);
690 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
691 table->title = title;
693 table->sizing[TABLE_HORZ].range[0] = 50;
694 table->sizing[TABLE_HORZ].range[1] = 72;
695 table->sizing[TABLE_VERT].range[0] = 36;
696 table->sizing[TABLE_VERT].range[1] = 120;
698 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
699 pivot_area_get_default_style (i, &table->areas[i]);
701 /* Set default border styles. */
702 static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
703 [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE,
704 [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE,
705 [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE,
706 [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE,
707 [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
708 [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK,
709 [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK,
710 [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK,
711 [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
712 [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK,
713 [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK,
714 [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
715 [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
716 [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
717 [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
718 [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
719 [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
720 [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
721 [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
723 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
724 table->borders[i] = (struct table_border_style) {
725 .stroke = default_strokes[i],
726 .color = CELL_COLOR_BLACK,
729 table->row_labels_in_corner = true;
730 hmap_init (&table->cells);
735 /* Creates and returns a new pivot table with the given TITLE and a single cell
736 with the given CONTENT. */
738 pivot_table_create_for_text (struct pivot_value *title,
739 struct pivot_value *content)
741 struct pivot_table *table = pivot_table_create__ (title);
743 struct pivot_dimension *d = pivot_dimension_create (
744 table, PIVOT_AXIS_ROW, N_("Error"));
745 d->hide_all_labels = true;
746 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
748 pivot_table_put1 (table, 0, content);
753 /* Increases TABLE's reference count, indicating that it has an additional
754 owner. A pivot table that is shared among multiple owners must not be
757 pivot_table_ref (const struct pivot_table *table_)
759 struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
764 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
765 If TABLE no longer has any owners, it is freed. */
767 pivot_table_unref (struct pivot_table *table)
771 assert (table->ref_cnt > 0);
772 if (--table->ref_cnt)
775 free (table->current_layer);
776 free (table->table_look);
778 for (int i = 0; i < TABLE_N_AXES; i++)
779 pivot_table_sizing_uninit (&table->sizing[i]);
781 free (table->continuation);
783 for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
784 free (table->ccs[i]);
786 free (table->command_local);
787 free (table->command_c);
788 free (table->language);
789 free (table->locale);
791 free (table->dataset);
792 free (table->datafile);
794 for (size_t i = 0; i < table->n_footnotes; i++)
795 pivot_footnote_destroy (table->footnotes[i]);
796 free (table->footnotes);
798 pivot_value_destroy (table->title);
799 pivot_value_destroy (table->subtype);
800 pivot_value_destroy (table->corner_text);
801 pivot_value_destroy (table->caption);
803 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
804 area_style_uninit (&table->areas[i]);
806 for (size_t i = 0; i < table->n_dimensions; i++)
807 pivot_dimension_destroy (table->dimensions[i]);
808 free (table->dimensions);
810 for (size_t i = 0; i < PIVOT_N_AXES; i++)
811 free (table->axes[i].dimensions);
813 struct pivot_cell *cell, *next_cell;
814 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
817 hmap_delete (&table->cells, &cell->hmap_node);
818 pivot_value_destroy (cell->value);
821 hmap_destroy (&table->cells);
826 /* Returns true if TABLE has more than one owner. A pivot table that is shared
827 among multiple owners must not be modified. */
829 pivot_table_is_shared (const struct pivot_table *table)
831 return table->ref_cnt > 1;
834 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
835 WV, which should be the weight variable for the dictionary whose data or
836 statistics are being put into TABLE.
838 This has no effect if WV is NULL. */
840 pivot_table_set_weight_var (struct pivot_table *table,
841 const struct variable *wv)
844 pivot_table_set_weight_format (table, var_get_print_format (wv));
847 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
848 format for the dictionary whose data or statistics are being put into TABLE.
850 This has no effect if WFMT is NULL. */
852 pivot_table_set_weight_format (struct pivot_table *table,
853 const struct fmt_spec *wfmt)
856 table->weight_format = *wfmt;
859 /* Returns true if TABLE has no cells, false otherwise. */
861 pivot_table_is_empty (const struct pivot_table *table)
863 return hmap_is_empty (&table->cells);
867 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
869 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
873 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
875 for (size_t i = 0; i < n; i++)
882 static struct pivot_cell *
883 pivot_table_lookup_cell__ (const struct pivot_table *table,
884 const size_t *dindexes, unsigned int hash)
886 struct pivot_cell *cell;
887 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
889 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
894 static struct pivot_cell *
895 pivot_cell_allocate (size_t n_idx)
897 struct pivot_cell *cell UNUSED;
898 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
901 static struct pivot_cell *
902 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
904 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
905 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
908 cell = pivot_cell_allocate (table->n_dimensions);
909 for (size_t i = 0; i < table->n_dimensions; i++)
910 cell->idx[i] = dindexes[i];
912 hmap_insert (&table->cells, &cell->hmap_node, hash);
917 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
918 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
921 If VALUE is a numeric value without a specified format, this function checks
922 each of the categories designated by DINDEXES[] and takes the format from
923 the first category with a result class. If none has a result class, uses
924 the overall default numeric format. */
926 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
927 struct pivot_value *value)
929 assert (n == table->n_dimensions);
931 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
933 for (size_t i = 0; i < table->n_dimensions; i++)
935 const struct pivot_dimension *d = table->dimensions[i];
936 if (dindexes[i] < d->n_leaves)
938 const struct pivot_category *c = d->data_leaves[dindexes[i]];
941 value->numeric.format = c->format;
946 value->numeric.format = *settings_get_format ();
951 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
952 pivot_value_destroy (cell->value);
956 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
957 dimension. Takes ownership of VALUE. */
959 pivot_table_put1 (struct pivot_table *table, size_t idx1,
960 struct pivot_value *value)
962 size_t dindexes[] = { idx1 };
963 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
966 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
967 dimensions. Takes ownership of VALUE. */
969 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
970 struct pivot_value *value)
972 size_t dindexes[] = { idx1, idx2 };
973 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
976 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
977 have 3 dimensions. Takes ownership of VALUE. */
979 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
980 size_t idx3, struct pivot_value *value)
982 size_t dindexes[] = { idx1, idx2, idx3 };
983 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
986 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
987 must have 4 dimensions. Takes ownership of VALUE. */
989 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
990 size_t idx3, size_t idx4, struct pivot_value *value)
992 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
993 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
996 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
997 automatically assigned marker.
999 The footnote will only appear in output if it is referenced. Use
1000 pivot_value_add_footnote() to add a reference to the footnote. */
1001 struct pivot_footnote *
1002 pivot_table_create_footnote (struct pivot_table *table,
1003 struct pivot_value *content)
1005 return pivot_table_create_footnote__ (table, table->n_footnotes,
1009 static struct pivot_value *
1010 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1012 char text[INT_BUFSIZE_BOUND (size_t)];
1013 if (show_numeric_markers)
1014 snprintf (text, sizeof text, "%d", idx + 1);
1016 str_format_26adic (idx + 1, false, text, sizeof text);
1017 return pivot_value_new_user_text (text, -1);
1020 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1021 all lower indexes as a side effect). If MARKER is nonnull, sets the
1022 footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1023 struct pivot_footnote *
1024 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1025 struct pivot_value *marker,
1026 struct pivot_value *content)
1028 if (idx >= table->n_footnotes)
1030 while (idx >= table->allocated_footnotes)
1031 table->footnotes = x2nrealloc (table->footnotes,
1032 &table->allocated_footnotes,
1033 sizeof *table->footnotes);
1034 while (idx >= table->n_footnotes)
1036 struct pivot_footnote *f = xmalloc (sizeof *f);
1037 f->idx = table->n_footnotes;
1038 f->marker = pivot_make_default_footnote_marker (
1039 f->idx, table->show_numeric_markers);
1042 table->footnotes[table->n_footnotes++] = f;
1046 struct pivot_footnote *f = table->footnotes[idx];
1049 pivot_value_destroy (f->marker);
1054 pivot_value_destroy (f->content);
1055 f->content = content;
1060 /* Frees the data owned by F. */
1062 pivot_footnote_destroy (struct pivot_footnote *f)
1066 pivot_value_destroy (f->content);
1067 pivot_value_destroy (f->marker);
1072 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1073 indexes for each dimension in TABLE in DINDEXES[]. */
1075 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1076 const size_t *pindexes[PIVOT_N_AXES],
1077 size_t dindexes[/* table->n_dimensions */])
1079 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1081 const struct pivot_axis *axis = &table->axes[i];
1083 for (size_t j = 0; j < axis->n_dimensions; j++)
1085 const struct pivot_dimension *d = axis->dimensions[j];
1086 dindexes[d->top_index]
1087 = d->presentation_leaves[pindexes[i][j]]->data_index;
1093 pivot_table_enumerate_axis (const struct pivot_table *table,
1094 enum pivot_axis_type axis_type,
1095 const size_t *layer_indexes, bool omit_empty,
1098 const struct pivot_axis *axis = &table->axes[axis_type];
1099 if (!axis->n_dimensions)
1101 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1103 enumeration[1] = SIZE_MAX;
1108 else if (!axis->extent)
1110 size_t *enumeration = xmalloc (sizeof *enumeration);
1111 *enumeration = SIZE_MAX;
1117 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1118 axis->n_dimensions), 1),
1119 sizeof *enumeration);
1120 size_t *p = enumeration;
1121 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1123 size_t *axis_indexes;
1124 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1128 enum pivot_axis_type axis2_type
1129 = pivot_axis_type_transpose (axis_type);
1131 size_t *axis2_indexes;
1132 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1134 const size_t *pindexes[PIVOT_N_AXES];
1135 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1136 pindexes[axis_type] = axis_indexes;
1137 pindexes[axis2_type] = axis2_indexes;
1138 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1139 if (pivot_table_get (table, dindexes))
1145 free (axis2_indexes);
1148 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1149 p += axis->n_dimensions;
1153 *n = (p - enumeration) / axis->n_dimensions;
1159 static const struct pivot_cell *
1160 pivot_table_lookup_cell (const struct pivot_table *table,
1161 const size_t *dindexes)
1163 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1164 return pivot_table_lookup_cell__ (table, dindexes, hash);
1167 const struct pivot_value *
1168 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1170 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1171 return cell ? cell->value : NULL;
1174 struct pivot_value *
1175 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1177 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1179 cell->value = pivot_value_new_user_text ("", -1);
1184 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1186 if (pivot_category_is_group (category) && category->n_subs)
1187 for (size_t i = 0; i < category->n_subs; i++)
1188 distribute_extra_depth (category->subs[i], extra_depth);
1190 category->extra_depth += extra_depth;
1194 pivot_category_assign_label_depth (struct pivot_category *category,
1195 bool dimension_labels_in_corner)
1197 category->extra_depth = 0;
1199 if (pivot_category_is_group (category))
1202 for (size_t i = 0; i < category->n_subs; i++)
1204 pivot_category_assign_label_depth (category->subs[i], false);
1205 depth = MAX (depth, category->subs[i]->label_depth);
1208 for (size_t i = 0; i < category->n_subs; i++)
1210 struct pivot_category *sub = category->subs[i];
1212 size_t extra_depth = depth - sub->label_depth;
1214 distribute_extra_depth (sub, extra_depth);
1216 sub->label_depth = depth;
1219 category->show_label_in_corner = (category->show_label
1220 && dimension_labels_in_corner);
1221 category->label_depth
1222 = (category->show_label && !category->show_label_in_corner
1223 ? depth + 1 : depth);
1226 category->label_depth = 1;
1230 pivot_axis_assign_label_depth (struct pivot_table *table,
1231 enum pivot_axis_type axis_type,
1232 bool dimension_labels_in_corner)
1234 struct pivot_axis *axis = &table->axes[axis_type];
1235 bool any_label_shown_in_corner = false;
1236 axis->label_depth = 0;
1238 for (size_t i = 0; i < axis->n_dimensions; i++)
1240 struct pivot_dimension *d = axis->dimensions[i];
1241 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1242 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1243 axis->label_depth += d->label_depth;
1244 axis->extent *= d->n_leaves;
1246 if (d->root->show_label_in_corner)
1247 any_label_shown_in_corner = true;
1249 return any_label_shown_in_corner;
1253 pivot_table_assign_label_depth (struct pivot_table *table)
1255 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1256 if (pivot_axis_assign_label_depth (
1257 table, PIVOT_AXIS_ROW, (table->row_labels_in_corner
1258 && !table->corner_text))
1259 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1260 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1261 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1265 pivot_table_submit (struct pivot_table *pt)
1267 pivot_table_assign_label_depth (CONST_CAST (struct pivot_table *, pt));
1268 table_item_submit (table_item_create (pt));
1271 indent (int indentation)
1273 for (int i = 0; i < indentation * 2; i++)
1278 pivot_value_dump (const struct pivot_value *value)
1280 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1281 SETTINGS_VALUE_SHOW_DEFAULT);
1287 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1292 indent (indentation);
1293 printf ("%s: ", name);
1294 pivot_value_dump (value);
1300 pivot_table_dump_string (const char *string, const char *name, int indentation)
1304 indent (indentation);
1305 printf ("%s: %s\n", name, string);
1310 pivot_category_dump (const struct pivot_category *c, int indentation)
1312 indent (indentation);
1313 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1314 pivot_value_dump (c->name);
1317 if (pivot_category_is_leaf (c))
1318 printf ("data_index=%zu\n", c->data_index);
1321 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1324 for (size_t i = 0; i < c->n_subs; i++)
1325 pivot_category_dump (c->subs[i], indentation + 1);
1330 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1332 indent (indentation);
1333 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1334 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1336 pivot_category_dump (d->root, indentation + 1);
1340 area_style_dump (enum pivot_area area, const struct area_style *a,
1343 indent (indentation);
1344 printf ("%s: ", pivot_area_to_string (area));
1345 font_style_dump (&a->font_style);
1347 cell_style_dump (&a->cell_style);
1352 table_border_style_dump (enum pivot_border border,
1353 const struct table_border_style *b, int indentation)
1355 indent (indentation);
1356 printf ("%s: %s ", pivot_border_to_string (border),
1357 table_stroke_to_string (b->stroke));
1358 cell_color_dump (&b->color);
1363 compose_headings (const struct pivot_axis *axis,
1364 const size_t *column_enumeration,
1365 enum settings_value_show show_values,
1366 enum settings_value_show show_variables)
1368 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1371 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1372 for (size_t i = 0; i < axis->label_depth; i++)
1373 headings[i] = xcalloc (axis->extent, sizeof **headings);
1375 const size_t *indexes;
1377 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1379 int row = axis->label_depth - 1;
1380 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1382 const struct pivot_dimension *d = axis->dimensions[dim_index];
1383 if (d->hide_all_labels)
1385 for (const struct pivot_category *c
1386 = d->presentation_leaves[indexes[dim_index]];
1390 if (pivot_category_is_leaf (c) || (c->show_label
1391 && !c->show_label_in_corner))
1393 headings[row][column] = pivot_value_to_string (
1394 c->name, show_values, show_variables);
1395 if (!*headings[row][column])
1396 headings[row][column] = xstrdup ("<blank>");
1408 free_headings (const struct pivot_axis *axis, char ***headings)
1410 for (size_t i = 0; i < axis->label_depth; i++)
1412 for (size_t j = 0; j < axis->extent; j++)
1413 free (headings[i][j]);
1420 pivot_table_sizing_dump (const char *name, const struct pivot_table_sizing *s,
1423 indent (indentation);
1424 printf ("%ss: min=%d, max=%d\n", name, s->range[0], s->range[1]);
1427 indent (indentation + 1);
1428 printf ("%s widths:", name);
1429 for (size_t i = 0; i < s->n_widths; i++)
1430 printf (" %d", s->widths[i]);
1435 indent (indentation + 1);
1436 printf ("break after %ss:", name);
1437 for (size_t i = 0; i < s->n_breaks; i++)
1438 printf (" %zu", s->breaks[i]);
1443 indent (indentation + 1);
1444 printf ("keep %ss together:", name);
1445 for (size_t i = 0; i < s->n_keeps; i++)
1446 printf (" [%zu,%zu]",
1448 s->keeps[i].ofs + s->keeps[i].n - 1);
1454 pivot_table_dump (const struct pivot_table *table, int indentation)
1459 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1460 if (table->decimal == '.' || table->decimal == ',')
1461 settings_set_decimal_char (table->decimal);
1463 pivot_table_dump_value (table->title, "title", indentation);
1464 pivot_table_dump_string (table->command_c, "command", indentation);
1465 pivot_table_dump_string (table->dataset, "dataset", indentation);
1466 pivot_table_dump_string (table->datafile, "datafile", indentation);
1467 pivot_table_dump_string (table->notes, "notes", indentation);
1468 pivot_table_dump_string (table->table_look, "table-look", indentation);
1471 indent (indentation);
1473 printf ("date: %s", ctime_r (&table->date, buf));
1476 indent (indentation);
1477 printf ("sizing:\n");
1478 pivot_table_sizing_dump ("column", &table->sizing[TABLE_HORZ],
1480 pivot_table_sizing_dump ("row", &table->sizing[TABLE_VERT],
1483 indent (indentation);
1484 printf ("areas:\n");
1485 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1486 area_style_dump (area, &table->areas[area], indentation + 1);
1488 indent (indentation);
1489 printf ("borders:\n");
1490 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1491 table_border_style_dump (border, &table->borders[border], indentation + 1);
1493 for (size_t i = 0; i < table->n_dimensions; i++)
1494 pivot_dimension_dump (table->dimensions[i], indentation);
1496 /* Presentation and data indexes. */
1497 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1499 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1500 if (layer_axis->n_dimensions)
1502 indent (indentation);
1503 printf ("current layer:");
1505 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1507 const struct pivot_dimension *d = layer_axis->dimensions[i];
1508 char *name = pivot_value_to_string (d->root->name,
1510 table->show_variables);
1511 char *value = pivot_value_to_string (
1512 d->data_leaves[table->current_layer[i]]->name,
1513 table->show_values, table->show_variables);
1514 printf (" %s=%s", name, value);
1522 size_t *layer_indexes;
1523 size_t layer_iteration = 0;
1524 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1526 indent (indentation);
1527 printf ("layer %zu:", layer_iteration++);
1529 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1530 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1532 const struct pivot_dimension *d = layer_axis->dimensions[i];
1534 fputs (i == 0 ? " " : ", ", stdout);
1535 pivot_value_dump (d->root->name);
1536 fputs (" =", stdout);
1538 struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1541 for (const struct pivot_category *c
1542 = d->presentation_leaves[layer_indexes[i]];
1546 if (pivot_category_is_leaf (c) || c->show_label)
1547 names[n_names++] = c->name;
1550 for (size_t i = n_names; i-- > 0; )
1553 pivot_value_dump (names[i]);
1559 size_t *column_enumeration = pivot_table_enumerate_axis (
1560 table, PIVOT_AXIS_COLUMN, layer_indexes, table->omit_empty, NULL);
1561 size_t *row_enumeration = pivot_table_enumerate_axis (
1562 table, PIVOT_AXIS_ROW, layer_indexes, table->omit_empty, NULL);
1564 char ***column_headings = compose_headings (
1565 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1566 table->show_values, table->show_variables);
1567 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1569 indent (indentation + 1);
1570 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1573 fputs ("; ", stdout);
1574 if (column_headings[y][x])
1575 fputs (column_headings[y][x], stdout);
1579 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1581 indent (indentation + 1);
1582 printf ("-----------------------------------------------\n");
1584 char ***row_headings = compose_headings (
1585 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1586 table->show_values, table->show_variables);
1589 const size_t *pindexes[PIVOT_N_AXES]
1590 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1591 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1592 &table->axes[PIVOT_AXIS_ROW])
1594 indent (indentation + 1);
1597 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1600 fputs ("; ", stdout);
1601 if (row_headings[y][x])
1602 fputs (row_headings[y][x], stdout);
1608 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1610 &table->axes[PIVOT_AXIS_COLUMN])
1615 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1616 const struct pivot_value *value = pivot_table_get (
1619 pivot_value_dump (value);
1626 free (column_enumeration);
1627 free (row_enumeration);
1628 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1631 pivot_table_dump_value (table->caption, "caption", indentation);
1633 for (size_t i = 0; i < table->n_footnotes; i++)
1635 const struct pivot_footnote *f = table->footnotes[i];
1636 indent (indentation);
1639 pivot_value_dump (f->marker);
1641 printf ("%zu", f->idx);
1643 pivot_value_dump (f->content);
1648 settings_set_decimal_char (old_decimal);
1652 consume_int (const char *p, size_t *n)
1655 while (c_isdigit (*p))
1656 *n = *n * 10 + (*p++ - '0');
1661 pivot_format_inner_template (struct string *out, const char *template,
1663 struct pivot_value **values, size_t n_values,
1664 enum settings_value_show show_values,
1665 enum settings_value_show show_variables)
1667 size_t args_consumed = 0;
1668 while (*template && *template != ':')
1670 if (*template == '\\' && template[1])
1672 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1675 else if (*template == escape)
1678 template = consume_int (template + 1, &index);
1679 if (index >= 1 && index <= n_values)
1681 pivot_value_format (values[index - 1], show_values,
1682 show_variables, out);
1683 args_consumed = MAX (args_consumed, index);
1687 ds_put_byte (out, *template++);
1689 return args_consumed;
1693 pivot_extract_inner_template (const char *template, const char **p)
1699 if (*template == '\\' && template[1] != '\0')
1701 else if (*template == ':')
1702 return template + 1;
1703 else if (*template == '\0')
1711 pivot_format_template (struct string *out, const char *template,
1712 const struct pivot_argument *args, size_t n_args,
1713 enum settings_value_show show_values,
1714 enum settings_value_show show_variables)
1718 if (*template == '\\' && template[1] != '\0')
1720 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1723 else if (*template == '^')
1726 template = consume_int (template + 1, &index);
1727 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1728 pivot_value_format (args[index - 1].values[0],
1729 show_values, show_variables, out);
1731 else if (*template == '[')
1733 const char *tmpl[2];
1734 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1735 template = pivot_extract_inner_template (template, &tmpl[1]);
1736 template += *template == ']';
1739 template = consume_int (template, &index);
1740 if (index < 1 || index > n_args)
1743 const struct pivot_argument *arg = &args[index - 1];
1744 size_t left = arg->n;
1747 struct pivot_value **values = arg->values + (arg->n - left);
1748 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1749 char escape = "%^"[tmpl_idx];
1750 size_t used = pivot_format_inner_template (
1751 out, tmpl[tmpl_idx], escape, values, left,
1752 show_values, show_variables);
1753 if (!used || used > left)
1759 ds_put_byte (out, *template++);
1763 static enum settings_value_show
1764 interpret_show (enum settings_value_show global_show,
1765 enum settings_value_show table_show,
1766 enum settings_value_show value_show,
1769 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1770 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1771 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1775 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1776 SHOW_VARIABLES control whether variable and value labels are included.
1778 The "body" omits subscripts and superscripts and footnotes. */
1780 pivot_value_format_body (const struct pivot_value *value,
1781 enum settings_value_show show_values,
1782 enum settings_value_show show_variables,
1785 enum settings_value_show show;
1786 bool numeric = false;
1788 switch (value->type)
1790 case PIVOT_VALUE_NUMERIC:
1791 show = interpret_show (settings_get_show_values (),
1793 value->numeric.show,
1794 value->numeric.value_label != NULL);
1795 if (show & SETTINGS_VALUE_SHOW_VALUE)
1797 char *s = data_out (&(union value) { .f = value->numeric.x },
1798 "UTF-8", &value->numeric.format);
1799 ds_put_cstr (out, s + strspn (s, " "));
1802 if (show & SETTINGS_VALUE_SHOW_LABEL)
1804 if (show & SETTINGS_VALUE_SHOW_VALUE)
1805 ds_put_byte (out, ' ');
1806 ds_put_cstr (out, value->numeric.value_label);
1808 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1811 case PIVOT_VALUE_STRING:
1812 show = interpret_show (settings_get_show_values (),
1815 value->string.value_label != NULL);
1816 if (show & SETTINGS_VALUE_SHOW_VALUE)
1818 if (value->string.hex)
1820 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1822 ds_put_format (out, "%02X", *p);
1825 ds_put_cstr (out, value->string.s);
1827 if (show & SETTINGS_VALUE_SHOW_LABEL)
1829 if (show & SETTINGS_VALUE_SHOW_VALUE)
1830 ds_put_byte (out, ' ');
1831 ds_put_cstr (out, value->string.value_label);
1835 case PIVOT_VALUE_VARIABLE:
1836 show = interpret_show (settings_get_show_variables (),
1838 value->variable.show,
1839 value->variable.var_label != NULL);
1840 if (show & SETTINGS_VALUE_SHOW_VALUE)
1841 ds_put_cstr (out, value->variable.var_name);
1842 if (show & SETTINGS_VALUE_SHOW_LABEL)
1844 if (show & SETTINGS_VALUE_SHOW_VALUE)
1845 ds_put_byte (out, ' ');
1846 ds_put_cstr (out, value->variable.var_label);
1850 case PIVOT_VALUE_TEXT:
1851 ds_put_cstr (out, value->text.local);
1854 case PIVOT_VALUE_TEMPLATE:
1855 pivot_format_template (out, value->template.local, value->template.args,
1856 value->template.n_args, show_values,
1864 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
1865 SHOW_VARIABLES control whether variable and value labels are included.
1867 Subscripts and superscripts and footnotes are included. */
1869 pivot_value_format (const struct pivot_value *value,
1870 enum settings_value_show show_values,
1871 enum settings_value_show show_variables,
1874 pivot_value_format_body ( value, show_values, show_variables, out);
1876 if (value->subscript)
1877 ds_put_format (out, "_%s", value->subscript);
1879 if (value->superscript)
1880 ds_put_format (out, "^%s", value->superscript);
1882 for (size_t i = 0; i < value->n_footnotes; i++)
1884 ds_put_byte (out, '^');
1885 pivot_value_format (value->footnotes[i]->marker,
1886 show_values, show_variables, out);
1890 /* Returns a text representation of VALUE. The caller must free the string,
1893 pivot_value_to_string (const struct pivot_value *value,
1894 enum settings_value_show show_values,
1895 enum settings_value_show show_variables)
1897 struct string s = DS_EMPTY_INITIALIZER;
1898 pivot_value_format (value, show_values, show_variables, &s);
1899 return ds_steal_cstr (&s);
1902 /* Frees the data owned by V. */
1904 pivot_value_destroy (struct pivot_value *value)
1908 font_style_uninit (value->font_style);
1909 free (value->font_style);
1910 free (value->cell_style);
1911 /* Do not free the elements of footnotes because VALUE does not own
1913 free (value->footnotes);
1914 free (value->subscript);
1916 switch (value->type)
1918 case PIVOT_VALUE_NUMERIC:
1919 free (value->numeric.var_name);
1920 free (value->numeric.value_label);
1923 case PIVOT_VALUE_STRING:
1924 free (value->string.s);
1925 free (value->string.var_name);
1926 free (value->string.value_label);
1929 case PIVOT_VALUE_VARIABLE:
1930 free (value->variable.var_name);
1931 free (value->variable.var_label);
1934 case PIVOT_VALUE_TEXT:
1935 free (value->text.local);
1936 if (value->text.c != value->text.local)
1937 free (value->text.c);
1938 if (value->text.id != value->text.local
1939 && value->text.id != value->text.c)
1940 free (value->text.id);
1943 case PIVOT_VALUE_TEMPLATE:
1944 free (value->template.local);
1945 if (value->template.id != value->template.local)
1946 free (value->template.id);
1947 for (size_t i = 0; i < value->template.n_args; i++)
1948 pivot_argument_uninit (&value->template.args[i]);
1949 free (value->template.args);
1956 /* Sets AREA to the style to use for VALUE, with defaults coming from
1957 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
1959 pivot_value_get_style (struct pivot_value *value,
1960 const struct font_style *base_font_style,
1961 const struct cell_style *base_cell_style,
1962 struct area_style *area)
1964 font_style_copy (&area->font_style, (value->font_style
1966 : base_font_style));
1967 area->cell_style = *(value->cell_style
1972 /* Copies AREA into VALUE's style. */
1974 pivot_value_set_style (struct pivot_value *value,
1975 const struct area_style *area)
1977 if (value->font_style)
1978 font_style_uninit (value->font_style);
1980 value->font_style = xmalloc (sizeof *value->font_style);
1981 font_style_copy (value->font_style, &area->font_style);
1983 if (!value->cell_style)
1984 value->cell_style = xmalloc (sizeof *value->cell_style);
1985 *value->cell_style = area->cell_style;
1988 /* Frees the data owned by ARG (but not ARG itself). */
1990 pivot_argument_uninit (struct pivot_argument *arg)
1994 for (size_t i = 0; i < arg->n; i++)
1995 pivot_value_destroy (arg->values[i]);
2000 struct pivot_value *
2001 pivot_value_new_user_text_nocopy (char *text)
2003 struct pivot_value *value = xmalloc (sizeof *value);
2004 *value = (struct pivot_value) {
2005 .type = PIVOT_VALUE_TEXT,
2010 .user_provided = true,
2016 struct pivot_value *
2017 pivot_value_new_user_text (const char *text, size_t length)
2019 return pivot_value_new_user_text_nocopy (
2020 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2023 /* TEXT should be a translatable string, but not actually translated yet,
2024 e.g. enclosed in N_(). */
2025 struct pivot_value *
2026 pivot_value_new_text (const char *text)
2028 char *c = xstrdup (text);
2029 char *local = xstrdup (gettext (c));
2031 struct pivot_value *value = xmalloc (sizeof *value);
2032 *value = (struct pivot_value) {
2033 .type = PIVOT_VALUE_TEXT,
2038 .user_provided = false,
2044 /* FORMAT should be a translatable string, but not actually translated yet,
2045 e.g. enclosed in N_(). */
2046 struct pivot_value * PRINTF_FORMAT (1, 2)
2047 pivot_value_new_text_format (const char *format, ...)
2050 va_start (args, format);
2051 char *c = xvasprintf (format, args);
2054 va_start (args, format);
2055 char *local = xvasprintf (gettext (format), args);
2058 struct pivot_value *value = xmalloc (sizeof *value);
2059 *value = (struct pivot_value) {
2060 .type = PIVOT_VALUE_TEXT,
2065 .user_provided = false,
2072 xstrdup_if_nonempty (const char *s)
2074 return s && s[0] ? xstrdup (s) : NULL;
2077 /* Returns a new pivot_value that represents X.
2079 The format to use for X is unspecified. Usually the easiest way to specify
2080 a format is through assigning a result class to one of the categories that
2081 the pivot_value will end up in. If that is not suitable, then the caller
2082 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2083 struct pivot_value *
2084 pivot_value_new_number (double x)
2086 struct pivot_value *value = xmalloc (sizeof *value);
2087 *value = (struct pivot_value) {
2088 .type = PIVOT_VALUE_NUMERIC,
2089 .numeric = { .x = x, },
2094 /* Returns a new pivot_value that represents X, formatted as an integer. */
2095 struct pivot_value *
2096 pivot_value_new_integer (double x)
2098 struct pivot_value *value = pivot_value_new_number (x);
2099 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2103 /* Returns a new pivot_value that represents VALUE, formatted as for
2105 struct pivot_value *
2106 pivot_value_new_var_value (const struct variable *variable,
2107 const union value *value)
2109 struct pivot_value *pv = pivot_value_new_value (
2110 value, var_get_width (variable), var_get_print_format (variable),
2111 var_get_encoding (variable));
2113 char *var_name = xstrdup (var_get_name (variable));
2114 if (var_is_alpha (variable))
2115 pv->string.var_name = var_name;
2117 pv->numeric.var_name = var_name;
2119 const char *label = var_lookup_value_label (variable, value);
2122 if (var_is_alpha (variable))
2123 pv->string.value_label = xstrdup (label);
2125 pv->numeric.value_label = xstrdup (label);
2131 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2132 formatted with FORMAT. For a string value, ENCODING must be its character
2134 struct pivot_value *
2135 pivot_value_new_value (const union value *value, int width,
2136 const struct fmt_spec *format, const char *encoding)
2138 struct pivot_value *pv = xzalloc (sizeof *pv);
2141 char *s = recode_string (UTF8, encoding,
2142 CHAR_CAST (char *, value_str (value, width)),
2144 size_t n = strlen (s);
2145 while (n > 0 && s[n - 1] == ' ')
2148 pv->type = PIVOT_VALUE_STRING;
2150 pv->string.hex = format->type == FMT_AHEX;
2154 pv->type = PIVOT_VALUE_NUMERIC;
2155 pv->numeric.x = value->f;
2156 pv->numeric.format = *format;
2162 /* Returns a new pivot_value for VARIABLE. */
2163 struct pivot_value *
2164 pivot_value_new_variable (const struct variable *variable)
2166 struct pivot_value *value = xmalloc (sizeof *value);
2167 *value = (struct pivot_value) {
2168 .type = PIVOT_VALUE_VARIABLE,
2170 .var_name = xstrdup (var_get_name (variable)),
2171 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2177 /* Attaches a reference to FOOTNOTE to V. */
2179 pivot_value_add_footnote (struct pivot_value *v,
2180 struct pivot_footnote *footnote)
2182 /* Some legacy tables include numerous duplicate footnotes. Suppress
2184 for (size_t i = 0; i < v->n_footnotes; i++)
2185 if (v->footnotes[i] == footnote)
2188 v->footnotes = xrealloc (v->footnotes,
2189 (v->n_footnotes + 1) * sizeof *v->footnotes);
2190 v->footnotes[v->n_footnotes++] = footnote;
2193 /* If VALUE is a numeric value, and RC is a result class such as
2194 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2196 pivot_value_set_rc (struct pivot_table *table, struct pivot_value *value,
2199 if (value->type == PIVOT_VALUE_NUMERIC)
2201 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2203 value->numeric.format = *f;