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 table_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}, \
80 .typeface = (char *) "Sans Serif", \
83 static const struct table_area_style default_area_styles[PIVOT_N_AREAS] = {
84 [PIVOT_AREA_TITLE] = STYLE(true, CENTER, CENTER, 8,11,1,8),
85 [PIVOT_AREA_CAPTION] = STYLE(false, LEFT, TOP, 8,11,1,1),
86 [PIVOT_AREA_FOOTER] = STYLE(false, LEFT, TOP, 11, 8,2,3),
87 [PIVOT_AREA_CORNER] = STYLE(false, LEFT, BOTTOM, 8,11,1,1),
88 [PIVOT_AREA_COLUMN_LABELS] = STYLE(false, CENTER, BOTTOM, 8,11,1,3),
89 [PIVOT_AREA_ROW_LABELS] = STYLE(false, LEFT, TOP, 8,11,1,3),
90 [PIVOT_AREA_DATA] = STYLE(false, MIXED, TOP, 8,11,1,1),
91 [PIVOT_AREA_LAYERS] = STYLE(false, LEFT, BOTTOM, 8,11,1,3),
95 return &default_area_styles[area];
99 pivot_border_get_default_style (enum pivot_border border,
100 struct table_border_style *style)
102 static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
103 [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE,
104 [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE,
105 [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE,
106 [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE,
107 [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
108 [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK,
109 [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK,
110 [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK,
111 [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
112 [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK,
113 [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK,
114 [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
115 [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
116 [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
117 [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
118 [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
119 [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
120 [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
121 [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
123 *style = (struct table_border_style) {
124 .stroke = default_strokes[border],
125 .color = CELL_COLOR_BLACK,
129 /* Returns the name of BORDER. */
131 pivot_border_to_string (enum pivot_border border)
135 case PIVOT_BORDER_TITLE:
138 case PIVOT_BORDER_OUTER_LEFT:
139 return "left outer frame";
140 case PIVOT_BORDER_OUTER_TOP:
141 return "top outer frame";
142 case PIVOT_BORDER_OUTER_RIGHT:
143 return "right outer frame";
144 case PIVOT_BORDER_OUTER_BOTTOM:
145 return "bottom outer frame";
147 case PIVOT_BORDER_INNER_LEFT:
148 return "left inner frame";
149 case PIVOT_BORDER_INNER_TOP:
150 return "top inner frame";
151 case PIVOT_BORDER_INNER_RIGHT:
152 return "right inner frame";
153 case PIVOT_BORDER_INNER_BOTTOM:
154 return "bottom inner frame";
156 case PIVOT_BORDER_DATA_LEFT:
157 return "data area left";
158 case PIVOT_BORDER_DATA_TOP:
159 return "data area top";
161 case PIVOT_BORDER_DIM_ROW_HORZ:
162 return "row label horizontal dimension border";
163 case PIVOT_BORDER_DIM_ROW_VERT:
164 return "row label vertical dimension border";
165 case PIVOT_BORDER_DIM_COL_HORZ:
166 return "column label horizontal dimension border";
167 case PIVOT_BORDER_DIM_COL_VERT:
168 return "column label vertical dimension border";
170 case PIVOT_BORDER_CAT_ROW_HORZ:
171 return "row label horizontal category border";
172 case PIVOT_BORDER_CAT_ROW_VERT:
173 return "row label vertical category border";
174 case PIVOT_BORDER_CAT_COL_HORZ:
175 return "column label horizontal category border";
176 case PIVOT_BORDER_CAT_COL_VERT:
177 return "column label vertical category border";
179 case PIVOT_N_BORDERS:
186 pivot_table_sizing_uninit (struct pivot_table_sizing *sizing)
190 free (sizing->widths);
191 free (sizing->breaks);
192 free (sizing->keeps);
198 /* Returns the name of AXIS_TYPE. */
200 pivot_axis_type_to_string (enum pivot_axis_type axis_type)
204 case PIVOT_AXIS_LAYER:
210 case PIVOT_AXIS_COLUMN:
218 static enum pivot_axis_type
219 pivot_axis_type_transpose (enum pivot_axis_type axis_type)
221 assert (axis_type == PIVOT_AXIS_ROW || axis_type == PIVOT_AXIS_COLUMN);
222 return (axis_type == PIVOT_AXIS_ROW ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW);
225 /* Implementation of PIVOT_AXIS_FOR_EACH. */
227 pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis)
231 if (axis->n_dimensions)
232 for (size_t i = 0; i < axis->n_dimensions; i++)
233 if (axis->dimensions[i]->n_leaves == 0)
236 return xcalloc (axis->n_dimensions, sizeof *indexes);
239 for (size_t i = 0; i < axis->n_dimensions; i++)
241 const struct pivot_dimension *d = axis->dimensions[i];
242 if (++indexes[i] < d->n_leaves)
255 pivot_category_set_rc (struct pivot_category *category, const char *s)
257 const struct fmt_spec *format = pivot_table_get_format (
258 category->dimension->table, s);
260 category->format = *format;
264 pivot_category_create_leaves_valist (struct pivot_category *parent,
268 while ((s = va_arg (args, const char *)))
270 if (!strncmp (s, "RC_", 3))
272 assert (parent->n_subs);
273 pivot_category_set_rc (parent->subs[parent->n_subs - 1], s);
276 pivot_category_create_leaf (parent, pivot_value_new_text (s));
280 /* Creates a new dimension with the given NAME in TABLE and returns it. The
281 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
284 NAME should be a translatable name, but not actually translated yet,
285 e.g. enclosed in N_(). To use a different kind of value for a name, use
286 pivot_dimension_create__() instead.
288 The optional varargs parameters may be used to add an initial set of
289 categories to the dimension. Each string should be a translatable category
290 name, but not actually translated yet, e.g. enclosed in N_(). Each string
291 may optionally be followod by a PIVOT_RC_* string that specifies the default
292 numeric format for cells in this category. */
293 struct pivot_dimension * SENTINEL (0)
294 (pivot_dimension_create) (struct pivot_table *table,
295 enum pivot_axis_type axis_type,
296 const char *name, ...)
298 struct pivot_dimension *d = pivot_dimension_create__ (
299 table, axis_type, pivot_value_new_text (name));
302 va_start (args, name);
303 pivot_category_create_leaves_valist (d->root, args);
309 /* Creates a new dimension with the given NAME in TABLE and returns it. The
310 dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
312 struct pivot_dimension *
313 pivot_dimension_create__ (struct pivot_table *table,
314 enum pivot_axis_type axis_type,
315 struct pivot_value *name)
317 assert (pivot_table_is_empty (table));
319 struct pivot_dimension *d = xmalloc (sizeof *d);
320 *d = (struct pivot_dimension) {
322 .axis_type = axis_type,
323 .level = table->axes[axis_type].n_dimensions,
324 .top_index = table->n_dimensions,
325 .root = xmalloc (sizeof *d->root),
328 struct pivot_category *root = d->root;
329 *root = (struct pivot_category) {
334 .data_index = SIZE_MAX,
335 .presentation_index = SIZE_MAX,
338 table->dimensions = xrealloc (
339 table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions);
340 table->dimensions[table->n_dimensions++] = d;
342 struct pivot_axis *axis = &table->axes[axis_type];
343 axis->dimensions = xrealloc (
344 axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
345 axis->dimensions[axis->n_dimensions++] = d;
347 if (axis_type == PIVOT_AXIS_LAYER)
349 free (table->current_layer);
350 table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
351 sizeof *table->current_layer);
354 /* axis->extent and axis->label_depth will be calculated later. */
360 pivot_dimension_destroy (struct pivot_dimension *d)
365 pivot_category_destroy (d->root);
366 free (d->data_leaves);
367 free (d->presentation_leaves);
371 /* Returns the first leaf node in an in-order traversal that is a child of
373 static const struct pivot_category * UNUSED
374 pivot_category_first_leaf (const struct pivot_category *cat)
376 if (pivot_category_is_leaf (cat))
379 for (size_t i = 0; i < cat->n_subs; i++)
381 const struct pivot_category *first
382 = pivot_category_first_leaf (cat->subs[i]);
390 /* Returns the next leaf node in an in-order traversal starting at CAT, which
392 static const struct pivot_category * UNUSED
393 pivot_category_next_leaf (const struct pivot_category *cat)
395 assert (pivot_category_is_leaf (cat));
399 const struct pivot_category *parent = cat->parent;
402 for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
404 const struct pivot_category *next
405 = pivot_category_first_leaf (parent->subs[i]);
415 pivot_category_add_child (struct pivot_category *child)
417 struct pivot_category *parent = child->parent;
419 assert (pivot_category_is_group (parent));
420 if (parent->n_subs >= parent->allocated_subs)
421 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
422 sizeof *parent->subs);
423 parent->subs[parent->n_subs++] = child;
426 /* Adds leaf categories as a child of PARENT. To create top-level categories
427 within dimension 'd', pass 'd->root' for PARENT.
429 Each of the varargs parameters should be a string, each of which should be a
430 translatable category name, but not actually translated yet, e.g. enclosed
431 in N_(). Each string may optionally be followod by a PIVOT_RC_* string that
432 specifies the default numeric format for cells in this category.
434 Returns the category index, which is just a 0-based array index, for the
437 Leaves have to be created in in-order, that is, don't create a group and add
438 some leaves, then add leaves outside the group and try to add more leaves
441 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
443 int retval = parent->dimension->n_leaves;
446 va_start (args, parent);
447 pivot_category_create_leaves_valist (parent, args);
453 /* Creates a new leaf category with the given NAME as a child of PARENT. To
454 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
455 Returns the category index, which is just a 0-based array index, for the new
458 Leaves have to be created in in-order, that is, don't create a group and add
459 some leaves, then add leaves outside the group and try to add more leaves
462 pivot_category_create_leaf (struct pivot_category *parent,
463 struct pivot_value *name)
465 return pivot_category_create_leaf_rc (parent, name, NULL);
468 /* Creates a new leaf category with the given NAME as a child of PARENT. To
469 create a top-level category within dimension 'd', pass 'd->root' for PARENT.
470 Returns the category index, which is just a 0-based array index, for the new
473 If RC is nonnull and the name of a result category, the category is assigned
474 that result category.
476 Leaves have to be created in in-order, that is, don't create a group and add
477 some leaves, then add leaves outside the group and try to add more leaves
480 pivot_category_create_leaf_rc (struct pivot_category *parent,
481 struct pivot_value *name, const char *rc)
483 struct pivot_dimension *d = parent->dimension;
485 struct pivot_category *leaf = xmalloc (sizeof *leaf);
486 *leaf = (struct pivot_category) {
490 .group_index = parent->n_subs,
491 .data_index = d->n_leaves,
492 .presentation_index = d->n_leaves,
495 if (d->n_leaves >= d->allocated_leaves)
497 d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
498 sizeof *d->data_leaves);
499 d->presentation_leaves = xrealloc (
500 d->presentation_leaves,
501 d->allocated_leaves * sizeof *d->presentation_leaves);
504 d->data_leaves[d->n_leaves] = leaf;
505 d->presentation_leaves[d->n_leaves] = leaf;
508 pivot_category_add_child (leaf);
510 /* Make sure that the new child is the last in in-order. */
511 assert (!pivot_category_next_leaf (leaf));
513 pivot_category_set_rc (leaf, rc);
515 return leaf->data_index;
518 /* Adds a new category group named NAME as a child of PARENT. To create a
519 top-level group within dimension 'd', pass 'd->root' for PARENT.
521 NAME should be a translatable name, but not actually translated yet,
522 e.g. enclosed in N_(). To use a different kind of value for a name, use
523 pivot_category_create_group__() instead.
525 The optional varargs parameters may be used to add an initial set of
526 categories to the group. Each string should be a translatable category
527 name, but not actually translated yet, e.g. enclosed in N_(). Each string
528 may optionally be followod by a PIVOT_RC_* string that specifies the default
529 numeric format for cells in this category.
531 Returns the new group. */
532 struct pivot_category * SENTINEL (0)
533 (pivot_category_create_group) (struct pivot_category *parent,
534 const char *name, ...)
536 struct pivot_category *group = pivot_category_create_group__ (
537 parent, pivot_value_new_text (name));
540 va_start (args, name);
541 pivot_category_create_leaves_valist (group, args);
547 /* Adds a new category group named NAME as a child of PARENT. To create a
548 top-level group within dimension 'd', pass 'd->root' for PARENT. Returns
550 struct pivot_category *
551 pivot_category_create_group__ (struct pivot_category *parent,
552 struct pivot_value *name)
554 struct pivot_dimension *d = parent->dimension;
556 struct pivot_category *group = xmalloc (sizeof *group);
557 *group = (struct pivot_category) {
562 .group_index = parent->n_subs,
563 .data_index = SIZE_MAX,
564 .presentation_index = SIZE_MAX,
567 pivot_category_add_child (group);
573 pivot_category_destroy (struct pivot_category *c)
578 pivot_value_destroy (c->name);
579 for (size_t i = 0; i < c->n_subs; i++)
580 pivot_category_destroy (c->subs[i]);
587 These are usually the easiest way to control the formatting of numeric data
588 in a pivot table. See pivot_dimension_create() for an explanation of their
592 const char *name; /* "RC_*". */
593 struct fmt_spec format;
596 /* Formats for most of the result classes. */
597 static struct result_class result_classes[] =
599 { PIVOT_RC_INTEGER, { FMT_F, 40, 0 } },
600 { PIVOT_RC_PERCENT, { FMT_PCT, 40, 1 } },
601 { PIVOT_RC_CORRELATION, { FMT_F, 40, 3 } },
602 { PIVOT_RC_SIGNIFICANCE, { FMT_F, 40, 3 } },
603 { PIVOT_RC_RESIDUAL, { FMT_F, 40, 2 } },
604 { PIVOT_RC_COUNT, { 0, 0, 0 } },
605 { PIVOT_RC_OTHER, { 0, 0, 0 } },
608 /* Has PIVOT_RC_COUNT been overridden by the user? */
609 static bool overridden_count_format;
611 static struct result_class *
612 pivot_result_class_find (const char *s)
614 for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
615 if (!strcmp (s, result_classes[i].name))
616 return &result_classes[i];
620 static const struct fmt_spec *
621 pivot_table_get_format (const struct pivot_table *table, const char *s)
625 else if (!strcmp (s, PIVOT_RC_OTHER))
626 return settings_get_format ();
627 else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
628 return &table->weight_format;
631 const struct result_class *rc = pivot_result_class_find (s);
632 return rc ? &rc->format : NULL;
636 /* Sets the format specification for the result class named S (which should not
637 include the RC_ prefix) to *FORMAT. Returns true if successful, false if S
638 does not name a known result class. */
640 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
642 char *s = xasprintf ("RC_%s", s_);
643 struct result_class *rc = pivot_result_class_find (s);
646 rc->format = *format;
647 if (!strcmp (s, PIVOT_RC_COUNT))
648 overridden_count_format = true;
657 /* Creates and returns a new pivot table with the given TITLE. TITLE should be
658 a text string marked for translation but not actually translated yet,
659 e.g. N_("Descriptive Statistics"). The un-translated text string is used as
660 the pivot table's subtype.
662 Operations commonly performed on the new pivot_table:
664 - If empty rows or columns should not be displayed, set ->omit_empty to
667 - Set the format to use for "count" values with pivot_table_set_weight_var()
668 or pivot_table_set_weight_format().
670 This function is a shortcut for pivot_table_create__() for the most common
671 case. Use pivot_table_create__() directly if the title should be some kind
672 of value other than an ordinary text string, or if the subtype should be
673 different from the title.
675 See the large comment at the top of pivot-table.h for general advice on
676 creating pivot tables. */
678 pivot_table_create (const char *title)
680 return pivot_table_create__ (pivot_value_new_text (title), title);
683 /* Creates and returns a new pivot table with the given TITLE, and takes
684 ownership of TITLE. The new pivot table's subtype is SUBTYPE, which
685 should be an untranslated English string that describes the contents of
686 the table at a high level without being specific about the variables or
687 other context involved.
689 Operations commonly performed on the new pivot_table:
691 - If empty rows or columns should not be displayed, set ->omit_empty to
694 - Set the format to use for "count" values with pivot_table_set_weight_var()
695 or pivot_table_set_weight_format().
697 See the large comment at the top of pivot-table.h for general advice on
698 creating pivot tables. */
700 pivot_table_create__ (struct pivot_value *title, const char *subtype)
702 struct pivot_table *table = xzalloc (sizeof *table);
704 table->show_caption = true;
705 table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
706 table->title = title;
707 table->subtype = subtype ? pivot_value_new_text (subtype) : NULL;
708 table->command_c = output_get_command_name ();
710 table->sizing[TABLE_HORZ].range[0] = 50;
711 table->sizing[TABLE_HORZ].range[1] = 72;
712 table->sizing[TABLE_VERT].range[0] = 36;
713 table->sizing[TABLE_VERT].range[1] = 120;
715 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
716 table_area_style_copy (NULL, &table->areas[i],
717 pivot_area_get_default_style (i));
719 /* Set default border styles. */
720 static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
721 [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE,
722 [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE,
723 [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE,
724 [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE,
725 [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
726 [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK,
727 [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK,
728 [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK,
729 [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
730 [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK,
731 [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK,
732 [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
733 [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
734 [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
735 [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
736 [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
737 [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
738 [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
739 [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
741 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
742 table->borders[i] = (struct table_border_style) {
743 .stroke = default_strokes[i],
744 .color = CELL_COLOR_BLACK,
747 table->row_labels_in_corner = true;
748 hmap_init (&table->cells);
753 /* Creates and returns a new pivot table with the given TITLE and a single cell
754 with the given CONTENT.
756 This is really just for error handling. */
758 pivot_table_create_for_text (struct pivot_value *title,
759 struct pivot_value *content)
761 struct pivot_table *table = pivot_table_create__ (title, "Error");
763 struct pivot_dimension *d = pivot_dimension_create (
764 table, PIVOT_AXIS_ROW, N_("Error"));
765 d->hide_all_labels = true;
766 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
768 pivot_table_put1 (table, 0, content);
773 /* Increases TABLE's reference count, indicating that it has an additional
774 owner. A pivot table that is shared among multiple owners must not be
777 pivot_table_ref (const struct pivot_table *table_)
779 struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
784 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
785 If TABLE no longer has any owners, it is freed. */
787 pivot_table_unref (struct pivot_table *table)
791 assert (table->ref_cnt > 0);
792 if (--table->ref_cnt)
795 free (table->current_layer);
796 free (table->table_look);
798 for (int i = 0; i < TABLE_N_AXES; i++)
799 pivot_table_sizing_uninit (&table->sizing[i]);
801 free (table->continuation);
803 for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
804 free (table->ccs[i]);
806 free (table->command_local);
807 free (table->command_c);
808 free (table->language);
809 free (table->locale);
811 free (table->dataset);
812 free (table->datafile);
814 for (size_t i = 0; i < table->n_footnotes; i++)
815 pivot_footnote_destroy (table->footnotes[i]);
816 free (table->footnotes);
818 pivot_value_destroy (table->title);
819 pivot_value_destroy (table->subtype);
820 pivot_value_destroy (table->corner_text);
821 pivot_value_destroy (table->caption);
823 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
824 table_area_style_uninit (&table->areas[i]);
826 for (size_t i = 0; i < table->n_dimensions; i++)
827 pivot_dimension_destroy (table->dimensions[i]);
828 free (table->dimensions);
830 for (size_t i = 0; i < PIVOT_N_AXES; i++)
831 free (table->axes[i].dimensions);
833 struct pivot_cell *cell, *next_cell;
834 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
837 hmap_delete (&table->cells, &cell->hmap_node);
838 pivot_value_destroy (cell->value);
841 hmap_destroy (&table->cells);
846 /* Returns true if TABLE has more than one owner. A pivot table that is shared
847 among multiple owners must not be modified. */
849 pivot_table_is_shared (const struct pivot_table *table)
851 return table->ref_cnt > 1;
854 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
855 WV, which should be the weight variable for the dictionary whose data or
856 statistics are being put into TABLE.
858 This has no effect if WV is NULL. */
860 pivot_table_set_weight_var (struct pivot_table *table,
861 const struct variable *wv)
864 pivot_table_set_weight_format (table, var_get_print_format (wv));
867 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
868 format for the dictionary whose data or statistics are being put into TABLE.
870 This has no effect if WFMT is NULL. */
872 pivot_table_set_weight_format (struct pivot_table *table,
873 const struct fmt_spec *wfmt)
876 table->weight_format = *wfmt;
879 /* Returns true if TABLE has no cells, false otherwise. */
881 pivot_table_is_empty (const struct pivot_table *table)
883 return hmap_is_empty (&table->cells);
887 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
889 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
893 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
895 for (size_t i = 0; i < n; i++)
902 static struct pivot_cell *
903 pivot_table_lookup_cell__ (const struct pivot_table *table,
904 const size_t *dindexes, unsigned int hash)
906 struct pivot_cell *cell;
907 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
909 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
914 static struct pivot_cell *
915 pivot_cell_allocate (size_t n_idx)
917 struct pivot_cell *cell UNUSED;
918 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
921 static struct pivot_cell *
922 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
924 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
925 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
928 cell = pivot_cell_allocate (table->n_dimensions);
929 for (size_t i = 0; i < table->n_dimensions; i++)
930 cell->idx[i] = dindexes[i];
932 hmap_insert (&table->cells, &cell->hmap_node, hash);
937 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
938 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
941 If VALUE is a numeric value without a specified format, this function checks
942 each of the categories designated by DINDEXES[] and takes the format from
943 the first category with a result class. If none has a result class, uses
944 the overall default numeric format. */
946 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
947 struct pivot_value *value)
949 assert (n == table->n_dimensions);
951 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
953 for (size_t i = 0; i < table->n_dimensions; i++)
955 const struct pivot_dimension *d = table->dimensions[i];
956 if (dindexes[i] < d->n_leaves)
958 const struct pivot_category *c = d->data_leaves[dindexes[i]];
961 value->numeric.format = c->format;
966 value->numeric.format = *settings_get_format ();
971 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
972 pivot_value_destroy (cell->value);
976 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
977 dimension. Takes ownership of VALUE. */
979 pivot_table_put1 (struct pivot_table *table, size_t idx1,
980 struct pivot_value *value)
982 size_t dindexes[] = { idx1 };
983 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
986 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
987 dimensions. Takes ownership of VALUE. */
989 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
990 struct pivot_value *value)
992 size_t dindexes[] = { idx1, idx2 };
993 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
996 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
997 have 3 dimensions. Takes ownership of VALUE. */
999 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
1000 size_t idx3, struct pivot_value *value)
1002 size_t dindexes[] = { idx1, idx2, idx3 };
1003 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1006 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
1007 must have 4 dimensions. Takes ownership of VALUE. */
1009 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1010 size_t idx3, size_t idx4, struct pivot_value *value)
1012 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1013 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1016 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1017 automatically assigned marker.
1019 The footnote will only appear in output if it is referenced. Use
1020 pivot_value_add_footnote() to add a reference to the footnote. */
1021 struct pivot_footnote *
1022 pivot_table_create_footnote (struct pivot_table *table,
1023 struct pivot_value *content)
1025 return pivot_table_create_footnote__ (table, table->n_footnotes,
1029 static struct pivot_value *
1030 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1032 char text[INT_BUFSIZE_BOUND (size_t)];
1033 if (show_numeric_markers)
1034 snprintf (text, sizeof text, "%d", idx + 1);
1036 str_format_26adic (idx + 1, false, text, sizeof text);
1037 return pivot_value_new_user_text (text, -1);
1040 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1041 all lower indexes as a side effect). If MARKER is nonnull, sets the
1042 footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1043 struct pivot_footnote *
1044 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1045 struct pivot_value *marker,
1046 struct pivot_value *content)
1048 if (idx >= table->n_footnotes)
1050 while (idx >= table->allocated_footnotes)
1051 table->footnotes = x2nrealloc (table->footnotes,
1052 &table->allocated_footnotes,
1053 sizeof *table->footnotes);
1054 while (idx >= table->n_footnotes)
1056 struct pivot_footnote *f = xmalloc (sizeof *f);
1057 f->idx = table->n_footnotes;
1058 f->marker = pivot_make_default_footnote_marker (
1059 f->idx, table->show_numeric_markers);
1063 table->footnotes[table->n_footnotes++] = f;
1067 struct pivot_footnote *f = table->footnotes[idx];
1070 pivot_value_destroy (f->marker);
1075 pivot_value_destroy (f->content);
1076 f->content = content;
1081 /* Frees the data owned by F. */
1083 pivot_footnote_destroy (struct pivot_footnote *f)
1087 pivot_value_destroy (f->content);
1088 pivot_value_destroy (f->marker);
1093 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1094 indexes for each dimension in TABLE in DINDEXES[]. */
1096 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1097 const size_t *pindexes[PIVOT_N_AXES],
1098 size_t dindexes[/* table->n_dimensions */])
1100 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1102 const struct pivot_axis *axis = &table->axes[i];
1104 for (size_t j = 0; j < axis->n_dimensions; j++)
1106 const struct pivot_dimension *d = axis->dimensions[j];
1107 dindexes[d->top_index]
1108 = d->presentation_leaves[pindexes[i][j]]->data_index;
1114 pivot_table_enumerate_axis (const struct pivot_table *table,
1115 enum pivot_axis_type axis_type,
1116 const size_t *layer_indexes, bool omit_empty,
1119 const struct pivot_axis *axis = &table->axes[axis_type];
1120 if (!axis->n_dimensions)
1122 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1124 enumeration[1] = SIZE_MAX;
1129 else if (!axis->extent)
1131 size_t *enumeration = xmalloc (sizeof *enumeration);
1132 *enumeration = SIZE_MAX;
1138 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1139 axis->n_dimensions), 1),
1140 sizeof *enumeration);
1141 size_t *p = enumeration;
1142 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1144 size_t *axis_indexes;
1145 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1149 enum pivot_axis_type axis2_type
1150 = pivot_axis_type_transpose (axis_type);
1152 size_t *axis2_indexes;
1153 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1155 const size_t *pindexes[PIVOT_N_AXES];
1156 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1157 pindexes[axis_type] = axis_indexes;
1158 pindexes[axis2_type] = axis2_indexes;
1159 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1160 if (pivot_table_get (table, dindexes))
1166 free (axis2_indexes);
1169 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1170 p += axis->n_dimensions;
1174 *n = (p - enumeration) / axis->n_dimensions;
1180 static const struct pivot_cell *
1181 pivot_table_lookup_cell (const struct pivot_table *table,
1182 const size_t *dindexes)
1184 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1185 return pivot_table_lookup_cell__ (table, dindexes, hash);
1188 const struct pivot_value *
1189 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1191 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1192 return cell ? cell->value : NULL;
1195 struct pivot_value *
1196 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1198 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1200 cell->value = pivot_value_new_user_text ("", -1);
1205 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1207 if (pivot_category_is_group (category) && category->n_subs)
1208 for (size_t i = 0; i < category->n_subs; i++)
1209 distribute_extra_depth (category->subs[i], extra_depth);
1211 category->extra_depth += extra_depth;
1215 pivot_category_assign_label_depth (struct pivot_category *category,
1216 bool dimension_labels_in_corner)
1218 category->extra_depth = 0;
1220 if (pivot_category_is_group (category))
1223 for (size_t i = 0; i < category->n_subs; i++)
1225 pivot_category_assign_label_depth (category->subs[i], false);
1226 depth = MAX (depth, category->subs[i]->label_depth);
1229 for (size_t i = 0; i < category->n_subs; i++)
1231 struct pivot_category *sub = category->subs[i];
1233 size_t extra_depth = depth - sub->label_depth;
1235 distribute_extra_depth (sub, extra_depth);
1237 sub->label_depth = depth;
1240 category->show_label_in_corner = (category->show_label
1241 && dimension_labels_in_corner);
1242 category->label_depth
1243 = (category->show_label && !category->show_label_in_corner
1244 ? depth + 1 : depth);
1247 category->label_depth = 1;
1251 pivot_axis_assign_label_depth (struct pivot_table *table,
1252 enum pivot_axis_type axis_type,
1253 bool dimension_labels_in_corner)
1255 struct pivot_axis *axis = &table->axes[axis_type];
1256 bool any_label_shown_in_corner = false;
1257 axis->label_depth = 0;
1259 for (size_t i = 0; i < axis->n_dimensions; i++)
1261 struct pivot_dimension *d = axis->dimensions[i];
1262 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1263 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1264 axis->label_depth += d->label_depth;
1265 axis->extent *= d->n_leaves;
1267 if (d->root->show_label_in_corner)
1268 any_label_shown_in_corner = true;
1270 return any_label_shown_in_corner;
1274 pivot_table_assign_label_depth (struct pivot_table *table)
1276 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1277 if (pivot_axis_assign_label_depth (
1278 table, PIVOT_AXIS_ROW, (table->row_labels_in_corner
1279 && !table->corner_text))
1280 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1281 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1282 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1290 indent (int indentation)
1292 for (int i = 0; i < indentation * 2; i++)
1297 pivot_value_dump (const struct pivot_value *value)
1299 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1300 SETTINGS_VALUE_SHOW_DEFAULT);
1306 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1311 indent (indentation);
1312 printf ("%s: ", name);
1313 pivot_value_dump (value);
1319 pivot_table_dump_string (const char *string, const char *name, int indentation)
1323 indent (indentation);
1324 printf ("%s: %s\n", name, string);
1329 pivot_category_dump (const struct pivot_category *c, int indentation)
1331 indent (indentation);
1332 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1333 pivot_value_dump (c->name);
1336 if (pivot_category_is_leaf (c))
1337 printf ("data_index=%zu\n", c->data_index);
1340 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1343 for (size_t i = 0; i < c->n_subs; i++)
1344 pivot_category_dump (c->subs[i], indentation + 1);
1349 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1351 indent (indentation);
1352 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1353 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1355 pivot_category_dump (d->root, indentation + 1);
1359 table_area_style_dump (enum pivot_area area, const struct table_area_style *a,
1362 indent (indentation);
1363 printf ("%s: ", pivot_area_to_string (area));
1364 font_style_dump (&a->font_style);
1366 cell_style_dump (&a->cell_style);
1371 table_border_style_dump (enum pivot_border border,
1372 const struct table_border_style *b, int indentation)
1374 indent (indentation);
1375 printf ("%s: %s ", pivot_border_to_string (border),
1376 table_stroke_to_string (b->stroke));
1377 cell_color_dump (&b->color);
1382 compose_headings (const struct pivot_axis *axis,
1383 const size_t *column_enumeration,
1384 enum settings_value_show show_values,
1385 enum settings_value_show show_variables)
1387 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1390 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1391 for (size_t i = 0; i < axis->label_depth; i++)
1392 headings[i] = xcalloc (axis->extent, sizeof **headings);
1394 const size_t *indexes;
1396 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1398 int row = axis->label_depth - 1;
1399 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1401 const struct pivot_dimension *d = axis->dimensions[dim_index];
1402 if (d->hide_all_labels)
1404 for (const struct pivot_category *c
1405 = d->presentation_leaves[indexes[dim_index]];
1409 if (pivot_category_is_leaf (c) || (c->show_label
1410 && !c->show_label_in_corner))
1412 headings[row][column] = pivot_value_to_string (
1413 c->name, show_values, show_variables);
1414 if (!*headings[row][column])
1415 headings[row][column] = xstrdup ("<blank>");
1427 free_headings (const struct pivot_axis *axis, char ***headings)
1429 for (size_t i = 0; i < axis->label_depth; i++)
1431 for (size_t j = 0; j < axis->extent; j++)
1432 free (headings[i][j]);
1439 pivot_table_sizing_dump (const char *name, const struct pivot_table_sizing *s,
1442 indent (indentation);
1443 printf ("%ss: min=%d, max=%d\n", name, s->range[0], s->range[1]);
1446 indent (indentation + 1);
1447 printf ("%s widths:", name);
1448 for (size_t i = 0; i < s->n_widths; i++)
1449 printf (" %d", s->widths[i]);
1454 indent (indentation + 1);
1455 printf ("break after %ss:", name);
1456 for (size_t i = 0; i < s->n_breaks; i++)
1457 printf (" %zu", s->breaks[i]);
1462 indent (indentation + 1);
1463 printf ("keep %ss together:", name);
1464 for (size_t i = 0; i < s->n_keeps; i++)
1465 printf (" [%zu,%zu]",
1467 s->keeps[i].ofs + s->keeps[i].n - 1);
1473 pivot_table_dump (const struct pivot_table *table, int indentation)
1478 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1479 if (table->decimal == '.' || table->decimal == ',')
1480 settings_set_decimal_char (table->decimal);
1482 pivot_table_dump_value (table->title, "title", indentation);
1483 pivot_table_dump_string (table->command_c, "command", indentation);
1484 pivot_table_dump_string (table->dataset, "dataset", indentation);
1485 pivot_table_dump_string (table->datafile, "datafile", indentation);
1486 pivot_table_dump_string (table->notes, "notes", indentation);
1487 pivot_table_dump_string (table->table_look, "table-look", indentation);
1490 indent (indentation);
1492 struct tm *tm = localtime (&table->date);
1493 printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
1494 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
1498 indent (indentation);
1499 printf ("sizing:\n");
1500 pivot_table_sizing_dump ("column", &table->sizing[TABLE_HORZ],
1502 pivot_table_sizing_dump ("row", &table->sizing[TABLE_VERT],
1505 indent (indentation);
1506 printf ("areas:\n");
1507 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1508 table_area_style_dump (area, &table->areas[area], indentation + 1);
1510 indent (indentation);
1511 printf ("borders:\n");
1512 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1513 table_border_style_dump (border, &table->borders[border], indentation + 1);
1515 for (size_t i = 0; i < table->n_dimensions; i++)
1516 pivot_dimension_dump (table->dimensions[i], indentation);
1518 /* Presentation and data indexes. */
1519 size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1521 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1522 if (layer_axis->n_dimensions)
1524 indent (indentation);
1525 printf ("current layer:");
1527 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1529 const struct pivot_dimension *d = layer_axis->dimensions[i];
1530 char *name = pivot_value_to_string (d->root->name,
1532 table->show_variables);
1533 char *value = pivot_value_to_string (
1534 d->data_leaves[table->current_layer[i]]->name,
1535 table->show_values, table->show_variables);
1536 printf (" %s=%s", name, value);
1544 size_t *layer_indexes;
1545 size_t layer_iteration = 0;
1546 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1548 indent (indentation);
1549 printf ("layer %zu:", layer_iteration++);
1551 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1552 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1554 const struct pivot_dimension *d = layer_axis->dimensions[i];
1556 fputs (i == 0 ? " " : ", ", stdout);
1557 pivot_value_dump (d->root->name);
1558 fputs (" =", stdout);
1560 struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1563 for (const struct pivot_category *c
1564 = d->presentation_leaves[layer_indexes[i]];
1568 if (pivot_category_is_leaf (c) || c->show_label)
1569 names[n_names++] = c->name;
1572 for (size_t i = n_names; i-- > 0;)
1575 pivot_value_dump (names[i]);
1581 size_t *column_enumeration = pivot_table_enumerate_axis (
1582 table, PIVOT_AXIS_COLUMN, layer_indexes, table->omit_empty, NULL);
1583 size_t *row_enumeration = pivot_table_enumerate_axis (
1584 table, PIVOT_AXIS_ROW, layer_indexes, table->omit_empty, NULL);
1586 char ***column_headings = compose_headings (
1587 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1588 table->show_values, table->show_variables);
1589 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1591 indent (indentation + 1);
1592 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1595 fputs ("; ", stdout);
1596 if (column_headings[y][x])
1597 fputs (column_headings[y][x], stdout);
1601 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1603 indent (indentation + 1);
1604 printf ("-----------------------------------------------\n");
1606 char ***row_headings = compose_headings (
1607 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1608 table->show_values, table->show_variables);
1611 const size_t *pindexes[PIVOT_N_AXES]
1612 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1613 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1614 &table->axes[PIVOT_AXIS_ROW])
1616 indent (indentation + 1);
1619 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1622 fputs ("; ", stdout);
1623 if (row_headings[y][x])
1624 fputs (row_headings[y][x], stdout);
1630 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1632 &table->axes[PIVOT_AXIS_COLUMN])
1637 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1638 const struct pivot_value *value = pivot_table_get (
1641 pivot_value_dump (value);
1648 free (column_enumeration);
1649 free (row_enumeration);
1650 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1653 pivot_table_dump_value (table->caption, "caption", indentation);
1655 for (size_t i = 0; i < table->n_footnotes; i++)
1657 const struct pivot_footnote *f = table->footnotes[i];
1658 indent (indentation);
1661 pivot_value_dump (f->marker);
1663 printf ("%zu", f->idx);
1665 pivot_value_dump (f->content);
1670 settings_set_decimal_char (old_decimal);
1674 consume_int (const char *p, size_t *n)
1677 while (c_isdigit (*p))
1678 *n = *n * 10 + (*p++ - '0');
1683 pivot_format_inner_template (struct string *out, const char *template,
1685 struct pivot_value **values, size_t n_values,
1686 enum settings_value_show show_values,
1687 enum settings_value_show show_variables)
1689 size_t args_consumed = 0;
1690 while (*template && *template != ':')
1692 if (*template == '\\' && template[1])
1694 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1697 else if (*template == escape)
1700 template = consume_int (template + 1, &index);
1701 if (index >= 1 && index <= n_values)
1703 pivot_value_format (values[index - 1], show_values,
1704 show_variables, out);
1705 args_consumed = MAX (args_consumed, index);
1709 ds_put_byte (out, *template++);
1711 return args_consumed;
1715 pivot_extract_inner_template (const char *template, const char **p)
1721 if (*template == '\\' && template[1] != '\0')
1723 else if (*template == ':')
1724 return template + 1;
1725 else if (*template == '\0')
1733 pivot_format_template (struct string *out, const char *template,
1734 const struct pivot_argument *args, size_t n_args,
1735 enum settings_value_show show_values,
1736 enum settings_value_show show_variables)
1740 if (*template == '\\' && template[1] != '\0')
1742 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1745 else if (*template == '^')
1748 template = consume_int (template + 1, &index);
1749 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1750 pivot_value_format (args[index - 1].values[0],
1751 show_values, show_variables, out);
1753 else if (*template == '[')
1755 const char *tmpl[2];
1756 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1757 template = pivot_extract_inner_template (template, &tmpl[1]);
1758 template += *template == ']';
1761 template = consume_int (template, &index);
1762 if (index < 1 || index > n_args)
1765 const struct pivot_argument *arg = &args[index - 1];
1766 size_t left = arg->n;
1769 struct pivot_value **values = arg->values + (arg->n - left);
1770 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1771 char escape = "%^"[tmpl_idx];
1772 size_t used = pivot_format_inner_template (
1773 out, tmpl[tmpl_idx], escape, values, left,
1774 show_values, show_variables);
1775 if (!used || used > left)
1781 ds_put_byte (out, *template++);
1785 static enum settings_value_show
1786 interpret_show (enum settings_value_show global_show,
1787 enum settings_value_show table_show,
1788 enum settings_value_show value_show,
1791 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1792 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1793 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1797 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1798 SHOW_VARIABLES control whether variable and value labels are included.
1800 The "body" omits subscripts and superscripts and footnotes. */
1802 pivot_value_format_body (const struct pivot_value *value,
1803 enum settings_value_show show_values,
1804 enum settings_value_show show_variables,
1807 enum settings_value_show show;
1808 bool numeric = false;
1810 switch (value->type)
1812 case PIVOT_VALUE_NUMERIC:
1813 show = interpret_show (settings_get_show_values (),
1815 value->numeric.show,
1816 value->numeric.value_label != NULL);
1817 if (show & SETTINGS_VALUE_SHOW_VALUE)
1819 char *s = data_out (&(union value) { .f = value->numeric.x },
1820 "UTF-8", &value->numeric.format);
1821 ds_put_cstr (out, s + strspn (s, " "));
1824 if (show & SETTINGS_VALUE_SHOW_LABEL)
1826 if (show & SETTINGS_VALUE_SHOW_VALUE)
1827 ds_put_byte (out, ' ');
1828 ds_put_cstr (out, value->numeric.value_label);
1830 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1833 case PIVOT_VALUE_STRING:
1834 show = interpret_show (settings_get_show_values (),
1837 value->string.value_label != NULL);
1838 if (show & SETTINGS_VALUE_SHOW_VALUE)
1840 if (value->string.hex)
1842 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1844 ds_put_format (out, "%02X", *p);
1847 ds_put_cstr (out, value->string.s);
1849 if (show & SETTINGS_VALUE_SHOW_LABEL)
1851 if (show & SETTINGS_VALUE_SHOW_VALUE)
1852 ds_put_byte (out, ' ');
1853 ds_put_cstr (out, value->string.value_label);
1857 case PIVOT_VALUE_VARIABLE:
1858 show = interpret_show (settings_get_show_variables (),
1860 value->variable.show,
1861 value->variable.var_label != NULL);
1862 if (show & SETTINGS_VALUE_SHOW_VALUE)
1863 ds_put_cstr (out, value->variable.var_name);
1864 if (show & SETTINGS_VALUE_SHOW_LABEL)
1866 if (show & SETTINGS_VALUE_SHOW_VALUE)
1867 ds_put_byte (out, ' ');
1868 ds_put_cstr (out, value->variable.var_label);
1872 case PIVOT_VALUE_TEXT:
1873 ds_put_cstr (out, value->text.local);
1876 case PIVOT_VALUE_TEMPLATE:
1877 pivot_format_template (out, value->template.local, value->template.args,
1878 value->template.n_args, show_values,
1886 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
1887 SHOW_VARIABLES control whether variable and value labels are included.
1889 Subscripts and superscripts and footnotes are included. */
1891 pivot_value_format (const struct pivot_value *value,
1892 enum settings_value_show show_values,
1893 enum settings_value_show show_variables,
1896 pivot_value_format_body (value, show_values, show_variables, out);
1898 if (value->n_subscripts)
1900 for (size_t i = 0; i < value->n_subscripts; i++)
1901 ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
1904 if (value->superscript)
1905 ds_put_format (out, "^%s", value->superscript);
1907 for (size_t i = 0; i < value->n_footnotes; i++)
1909 ds_put_byte (out, '^');
1910 pivot_value_format (value->footnotes[i]->marker,
1911 show_values, show_variables, out);
1915 /* Returns a text representation of VALUE. The caller must free the string,
1918 pivot_value_to_string (const struct pivot_value *value,
1919 enum settings_value_show show_values,
1920 enum settings_value_show show_variables)
1922 struct string s = DS_EMPTY_INITIALIZER;
1923 pivot_value_format (value, show_values, show_variables, &s);
1924 return ds_steal_cstr (&s);
1927 /* Frees the data owned by V. */
1929 pivot_value_destroy (struct pivot_value *value)
1933 font_style_uninit (value->font_style);
1934 free (value->font_style);
1935 free (value->cell_style);
1936 /* Do not free the elements of footnotes because VALUE does not own
1938 free (value->footnotes);
1940 for (size_t i = 0; i < value->n_subscripts; i++)
1941 free (value->subscripts[i]);
1942 free (value->subscripts);
1944 free (value->superscript);
1946 switch (value->type)
1948 case PIVOT_VALUE_NUMERIC:
1949 free (value->numeric.var_name);
1950 free (value->numeric.value_label);
1953 case PIVOT_VALUE_STRING:
1954 free (value->string.s);
1955 free (value->string.var_name);
1956 free (value->string.value_label);
1959 case PIVOT_VALUE_VARIABLE:
1960 free (value->variable.var_name);
1961 free (value->variable.var_label);
1964 case PIVOT_VALUE_TEXT:
1965 free (value->text.local);
1966 if (value->text.c != value->text.local)
1967 free (value->text.c);
1968 if (value->text.id != value->text.local
1969 && value->text.id != value->text.c)
1970 free (value->text.id);
1973 case PIVOT_VALUE_TEMPLATE:
1974 free (value->template.local);
1975 if (value->template.id != value->template.local)
1976 free (value->template.id);
1977 for (size_t i = 0; i < value->template.n_args; i++)
1978 pivot_argument_uninit (&value->template.args[i]);
1979 free (value->template.args);
1986 /* Sets AREA to the style to use for VALUE, with defaults coming from
1987 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
1989 pivot_value_get_style (struct pivot_value *value,
1990 const struct font_style *base_font_style,
1991 const struct cell_style *base_cell_style,
1992 struct table_area_style *area)
1994 font_style_copy (NULL, &area->font_style, (value->font_style
1996 : base_font_style));
1997 area->cell_style = *(value->cell_style
2002 /* Copies AREA into VALUE's style. */
2004 pivot_value_set_style (struct pivot_value *value,
2005 const struct table_area_style *area)
2007 if (value->font_style)
2008 font_style_uninit (value->font_style);
2010 value->font_style = xmalloc (sizeof *value->font_style);
2011 font_style_copy (NULL, value->font_style, &area->font_style);
2013 if (!value->cell_style)
2014 value->cell_style = xmalloc (sizeof *value->cell_style);
2015 *value->cell_style = area->cell_style;
2018 /* Frees the data owned by ARG (but not ARG itself). */
2020 pivot_argument_uninit (struct pivot_argument *arg)
2024 for (size_t i = 0; i < arg->n; i++)
2025 pivot_value_destroy (arg->values[i]);
2030 /* Creates and returns a new pivot_value whose contents is the null-terminated
2031 string TEXT. Takes ownership of TEXT.
2033 This function is for text strings provided by the user (with the exception
2034 that pivot_value_new_variable() should be used for variable names). For
2035 strings that are part of the PSPP user interface, such as names of
2036 procedures, statistics, annotations, error messages, etc., use
2037 pivot_value_new_text(). */
2038 struct pivot_value *
2039 pivot_value_new_user_text_nocopy (char *text)
2041 struct pivot_value *value = xmalloc (sizeof *value);
2042 *value = (struct pivot_value) {
2043 .type = PIVOT_VALUE_TEXT,
2048 .user_provided = true,
2054 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2055 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2058 This function is for text strings provided by the user (with the exception
2059 that pivot_value_new_variable() should be used for variable names). For
2060 strings that are part of the PSPP user interface, such as names of
2061 procedures, statistics, annotations, error messages, etc., use
2062 pivot_value_new_text().j
2064 The caller retains ownership of TEXT.*/
2065 struct pivot_value *
2066 pivot_value_new_user_text (const char *text, size_t length)
2068 return pivot_value_new_user_text_nocopy (
2069 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2072 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2073 a translatable string, but not actually translated yet, e.g. enclosed in
2074 N_(). This function is for text strings that are part of the PSPP user
2075 interface, such as names of procedures, statistics, annotations, error
2076 messages, etc. For strings that come from the user, use
2077 pivot_value_new_user_text(). */
2078 struct pivot_value *
2079 pivot_value_new_text (const char *text)
2081 char *c = xstrdup (text);
2082 char *local = xstrdup (gettext (c));
2084 struct pivot_value *value = xmalloc (sizeof *value);
2085 *value = (struct pivot_value) {
2086 .type = PIVOT_VALUE_TEXT,
2091 .user_provided = false,
2097 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2099 struct pivot_value * PRINTF_FORMAT (1, 2)
2100 pivot_value_new_text_format (const char *format, ...)
2103 va_start (args, format);
2104 char *c = xvasprintf (format, args);
2107 va_start (args, format);
2108 char *local = xvasprintf (gettext (format), args);
2111 struct pivot_value *value = xmalloc (sizeof *value);
2112 *value = (struct pivot_value) {
2113 .type = PIVOT_VALUE_TEXT,
2118 .user_provided = false,
2125 xstrdup_if_nonempty (const char *s)
2127 return s && s[0] ? xstrdup (s) : NULL;
2130 /* Returns a new pivot_value that represents X.
2132 The format to use for X is unspecified. Usually the easiest way to specify
2133 a format is through assigning a result class to one of the categories that
2134 the pivot_value will end up in. If that is not suitable, then the caller
2135 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2136 struct pivot_value *
2137 pivot_value_new_number (double x)
2139 struct pivot_value *value = xmalloc (sizeof *value);
2140 *value = (struct pivot_value) {
2141 .type = PIVOT_VALUE_NUMERIC,
2142 .numeric = { .x = x, },
2147 /* Returns a new pivot_value that represents X, formatted as an integer. */
2148 struct pivot_value *
2149 pivot_value_new_integer (double x)
2151 struct pivot_value *value = pivot_value_new_number (x);
2152 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2156 /* Returns a new pivot_value that represents VALUE, formatted as for
2158 struct pivot_value *
2159 pivot_value_new_var_value (const struct variable *variable,
2160 const union value *value)
2162 struct pivot_value *pv = pivot_value_new_value (
2163 value, var_get_width (variable), var_get_print_format (variable),
2164 var_get_encoding (variable));
2166 char *var_name = xstrdup (var_get_name (variable));
2167 if (var_is_alpha (variable))
2168 pv->string.var_name = var_name;
2170 pv->numeric.var_name = var_name;
2172 const char *label = var_lookup_value_label (variable, value);
2175 if (var_is_alpha (variable))
2176 pv->string.value_label = xstrdup (label);
2178 pv->numeric.value_label = xstrdup (label);
2184 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2185 formatted with FORMAT. For a string value, ENCODING must be its character
2187 struct pivot_value *
2188 pivot_value_new_value (const union value *value, int width,
2189 const struct fmt_spec *format, const char *encoding)
2191 struct pivot_value *pv = xzalloc (sizeof *pv);
2194 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2196 size_t n = strlen (s);
2197 while (n > 0 && s[n - 1] == ' ')
2200 pv->type = PIVOT_VALUE_STRING;
2202 pv->string.hex = format->type == FMT_AHEX;
2206 pv->type = PIVOT_VALUE_NUMERIC;
2207 pv->numeric.x = value->f;
2208 pv->numeric.format = *format;
2214 /* Returns a new pivot_value for VARIABLE. */
2215 struct pivot_value *
2216 pivot_value_new_variable (const struct variable *variable)
2218 struct pivot_value *value = xmalloc (sizeof *value);
2219 *value = (struct pivot_value) {
2220 .type = PIVOT_VALUE_VARIABLE,
2222 .var_name = xstrdup (var_get_name (variable)),
2223 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2229 /* Attaches a reference to FOOTNOTE to V. */
2231 pivot_value_add_footnote (struct pivot_value *v,
2232 const struct pivot_footnote *footnote)
2234 /* Some legacy tables include numerous duplicate footnotes. Suppress
2236 for (size_t i = 0; i < v->n_footnotes; i++)
2237 if (v->footnotes[i] == footnote)
2240 v->footnotes = xrealloc (v->footnotes,
2241 (v->n_footnotes + 1) * sizeof *v->footnotes);
2242 v->footnotes[v->n_footnotes++] = footnote;
2245 /* If VALUE is a numeric value, and RC is a result class such as
2246 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2248 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2251 if (value->type == PIVOT_VALUE_NUMERIC)
2253 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2255 value->numeric.format = *f;