1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2017, 2018 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "output/pivot-table.h"
23 #include "data/data-out.h"
24 #include "data/settings.h"
25 #include "data/value.h"
26 #include "data/variable.h"
27 #include "libpspp/hash-functions.h"
28 #include "libpspp/i18n.h"
29 #include "output/driver.h"
31 #include "gl/c-ctype.h"
32 #include "gl/intprops.h"
33 #include "gl/minmax.h"
34 #include "gl/xalloc.h"
35 #include "gl/xmemdup0.h"
39 #define _(msgid) gettext (msgid)
40 #define N_(msgid) msgid
42 static const struct fmt_spec *pivot_table_get_format (
43 const struct pivot_table *, const char *s);
45 /* Pivot table display styling. */
47 /* Returns the name of AREA. */
49 pivot_area_to_string (enum pivot_area area)
53 case PIVOT_AREA_TITLE: return "title";
54 case PIVOT_AREA_CAPTION: return "caption";
55 case PIVOT_AREA_FOOTER: return "footer";
56 case PIVOT_AREA_CORNER: return "corner";
57 case PIVOT_AREA_COLUMN_LABELS: return "column labels";
58 case PIVOT_AREA_ROW_LABELS: return "row labels";
59 case PIVOT_AREA_DATA: return "data";
60 case PIVOT_AREA_LAYERS: return "layers";
61 case PIVOT_N_AREAS: default: return "**error**";
65 const struct area_style *
66 pivot_area_get_default_style (enum pivot_area area)
68 #define STYLE(BOLD, H, V, L, R, T, B) { \
70 .halign = TABLE_HALIGN_##H, \
71 .valign = TABLE_VALIGN_##V, \
72 .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
73 [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
77 .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
78 .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
80 .typeface = (char *) "Sans Serif", \
83 static const struct 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 = pivot_value_new_text (subtype);
709 const char *command_id = output_get_command_name ();
710 table->command_c = command_id ? xstrdup (command_id) : NULL;
712 table->sizing[TABLE_HORZ].range[0] = 50;
713 table->sizing[TABLE_HORZ].range[1] = 72;
714 table->sizing[TABLE_VERT].range[0] = 36;
715 table->sizing[TABLE_VERT].range[1] = 120;
717 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
718 area_style_copy (NULL, &table->areas[i], pivot_area_get_default_style (i));
720 /* Set default border styles. */
721 static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
722 [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE,
723 [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE,
724 [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE,
725 [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE,
726 [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
727 [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK,
728 [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK,
729 [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK,
730 [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
731 [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK,
732 [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK,
733 [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
734 [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
735 [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
736 [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
737 [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
738 [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
739 [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
740 [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
742 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
743 table->borders[i] = (struct table_border_style) {
744 .stroke = default_strokes[i],
745 .color = CELL_COLOR_BLACK,
748 table->row_labels_in_corner = true;
749 hmap_init (&table->cells);
754 /* Creates and returns a new pivot table with the given TITLE and a single cell
755 with the given CONTENT.
757 This is really just for error handling. */
759 pivot_table_create_for_text (struct pivot_value *title,
760 struct pivot_value *content)
762 struct pivot_table *table = pivot_table_create__ (title, "Error");
764 struct pivot_dimension *d = pivot_dimension_create (
765 table, PIVOT_AXIS_ROW, N_("Error"));
766 d->hide_all_labels = true;
767 pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
769 pivot_table_put1 (table, 0, content);
774 /* Increases TABLE's reference count, indicating that it has an additional
775 owner. A pivot table that is shared among multiple owners must not be
778 pivot_table_ref (const struct pivot_table *table_)
780 struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
785 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
786 If TABLE no longer has any owners, it is freed. */
788 pivot_table_unref (struct pivot_table *table)
792 assert (table->ref_cnt > 0);
793 if (--table->ref_cnt)
796 free (table->current_layer);
797 free (table->table_look);
799 for (int i = 0; i < TABLE_N_AXES; i++)
800 pivot_table_sizing_uninit (&table->sizing[i]);
802 free (table->continuation);
804 for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
805 free (table->ccs[i]);
807 free (table->command_local);
808 free (table->command_c);
809 free (table->language);
810 free (table->locale);
812 free (table->dataset);
813 free (table->datafile);
815 for (size_t i = 0; i < table->n_footnotes; i++)
816 pivot_footnote_destroy (table->footnotes[i]);
817 free (table->footnotes);
819 pivot_value_destroy (table->title);
820 pivot_value_destroy (table->subtype);
821 pivot_value_destroy (table->corner_text);
822 pivot_value_destroy (table->caption);
824 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
825 area_style_uninit (&table->areas[i]);
827 for (size_t i = 0; i < table->n_dimensions; i++)
828 pivot_dimension_destroy (table->dimensions[i]);
829 free (table->dimensions);
831 for (size_t i = 0; i < PIVOT_N_AXES; i++)
832 free (table->axes[i].dimensions);
834 struct pivot_cell *cell, *next_cell;
835 HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
838 hmap_delete (&table->cells, &cell->hmap_node);
839 pivot_value_destroy (cell->value);
842 hmap_destroy (&table->cells);
847 /* Returns true if TABLE has more than one owner. A pivot table that is shared
848 among multiple owners must not be modified. */
850 pivot_table_is_shared (const struct pivot_table *table)
852 return table->ref_cnt > 1;
855 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
856 WV, which should be the weight variable for the dictionary whose data or
857 statistics are being put into TABLE.
859 This has no effect if WV is NULL. */
861 pivot_table_set_weight_var (struct pivot_table *table,
862 const struct variable *wv)
865 pivot_table_set_weight_format (table, var_get_print_format (wv));
868 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
869 format for the dictionary whose data or statistics are being put into TABLE.
871 This has no effect if WFMT is NULL. */
873 pivot_table_set_weight_format (struct pivot_table *table,
874 const struct fmt_spec *wfmt)
877 table->weight_format = *wfmt;
880 /* Returns true if TABLE has no cells, false otherwise. */
882 pivot_table_is_empty (const struct pivot_table *table)
884 return hmap_is_empty (&table->cells);
888 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
890 return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
894 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
896 for (size_t i = 0; i < n; i++)
903 static struct pivot_cell *
904 pivot_table_lookup_cell__ (const struct pivot_table *table,
905 const size_t *dindexes, unsigned int hash)
907 struct pivot_cell *cell;
908 HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
910 if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
915 static struct pivot_cell *
916 pivot_cell_allocate (size_t n_idx)
918 struct pivot_cell *cell UNUSED;
919 return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
922 static struct pivot_cell *
923 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
925 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
926 struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
929 cell = pivot_cell_allocate (table->n_dimensions);
930 for (size_t i = 0; i < table->n_dimensions; i++)
931 cell->idx[i] = dindexes[i];
933 hmap_insert (&table->cells, &cell->hmap_node, hash);
938 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
939 DINDEXES. N must be the number of dimensions in TABLE. Takes ownership of
942 If VALUE is a numeric value without a specified format, this function checks
943 each of the categories designated by DINDEXES[] and takes the format from
944 the first category with a result class. If none has a result class, uses
945 the overall default numeric format. */
947 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
948 struct pivot_value *value)
950 assert (n == table->n_dimensions);
952 if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
954 for (size_t i = 0; i < table->n_dimensions; i++)
956 const struct pivot_dimension *d = table->dimensions[i];
957 if (dindexes[i] < d->n_leaves)
959 const struct pivot_category *c = d->data_leaves[dindexes[i]];
962 value->numeric.format = c->format;
967 value->numeric.format = *settings_get_format ();
972 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
973 pivot_value_destroy (cell->value);
977 /* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1
978 dimension. Takes ownership of VALUE. */
980 pivot_table_put1 (struct pivot_table *table, size_t idx1,
981 struct pivot_value *value)
983 size_t dindexes[] = { idx1 };
984 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
987 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2
988 dimensions. Takes ownership of VALUE. */
990 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
991 struct pivot_value *value)
993 size_t dindexes[] = { idx1, idx2 };
994 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
997 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must
998 have 3 dimensions. Takes ownership of VALUE. */
1000 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
1001 size_t idx3, struct pivot_value *value)
1003 size_t dindexes[] = { idx1, idx2, idx3 };
1004 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1007 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE
1008 must have 4 dimensions. Takes ownership of VALUE. */
1010 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1011 size_t idx3, size_t idx4, struct pivot_value *value)
1013 size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1014 pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1017 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1018 automatically assigned marker.
1020 The footnote will only appear in output if it is referenced. Use
1021 pivot_value_add_footnote() to add a reference to the footnote. */
1022 struct pivot_footnote *
1023 pivot_table_create_footnote (struct pivot_table *table,
1024 struct pivot_value *content)
1026 return pivot_table_create_footnote__ (table, table->n_footnotes,
1030 static struct pivot_value *
1031 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1033 char text[INT_BUFSIZE_BOUND (size_t)];
1034 if (show_numeric_markers)
1035 snprintf (text, sizeof text, "%d", idx + 1);
1037 str_format_26adic (idx + 1, false, text, sizeof text);
1038 return pivot_value_new_user_text (text, -1);
1041 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1042 all lower indexes as a side effect). If MARKER is nonnull, sets the
1043 footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1044 struct pivot_footnote *
1045 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1046 struct pivot_value *marker,
1047 struct pivot_value *content)
1049 if (idx >= table->n_footnotes)
1051 while (idx >= table->allocated_footnotes)
1052 table->footnotes = x2nrealloc (table->footnotes,
1053 &table->allocated_footnotes,
1054 sizeof *table->footnotes);
1055 while (idx >= table->n_footnotes)
1057 struct pivot_footnote *f = xmalloc (sizeof *f);
1058 f->idx = table->n_footnotes;
1059 f->marker = pivot_make_default_footnote_marker (
1060 f->idx, table->show_numeric_markers);
1064 table->footnotes[table->n_footnotes++] = f;
1068 struct pivot_footnote *f = table->footnotes[idx];
1071 pivot_value_destroy (f->marker);
1076 pivot_value_destroy (f->content);
1077 f->content = content;
1082 /* Frees the data owned by F. */
1084 pivot_footnote_destroy (struct pivot_footnote *f)
1088 pivot_value_destroy (f->content);
1089 pivot_value_destroy (f->marker);
1094 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1095 indexes for each dimension in TABLE in DINDEXES[]. */
1097 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1098 const size_t *pindexes[PIVOT_N_AXES],
1099 size_t dindexes[/* table->n_dimensions */])
1101 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1103 const struct pivot_axis *axis = &table->axes[i];
1105 for (size_t j = 0; j < axis->n_dimensions; j++)
1107 const struct pivot_dimension *d = axis->dimensions[j];
1108 dindexes[d->top_index]
1109 = d->presentation_leaves[pindexes[i][j]]->data_index;
1115 pivot_table_enumerate_axis (const struct pivot_table *table,
1116 enum pivot_axis_type axis_type,
1117 const size_t *layer_indexes, bool omit_empty,
1120 const struct pivot_axis *axis = &table->axes[axis_type];
1121 if (!axis->n_dimensions)
1123 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1125 enumeration[1] = SIZE_MAX;
1130 else if (!axis->extent)
1132 size_t *enumeration = xmalloc (sizeof *enumeration);
1133 *enumeration = SIZE_MAX;
1139 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1140 axis->n_dimensions), 1),
1141 sizeof *enumeration);
1142 size_t *p = enumeration;
1143 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1145 size_t *axis_indexes;
1146 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1150 enum pivot_axis_type axis2_type
1151 = pivot_axis_type_transpose (axis_type);
1153 size_t *axis2_indexes;
1154 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1156 const size_t *pindexes[PIVOT_N_AXES];
1157 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1158 pindexes[axis_type] = axis_indexes;
1159 pindexes[axis2_type] = axis2_indexes;
1160 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1161 if (pivot_table_get (table, dindexes))
1167 free (axis2_indexes);
1170 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1171 p += axis->n_dimensions;
1175 *n = (p - enumeration) / axis->n_dimensions;
1181 static const struct pivot_cell *
1182 pivot_table_lookup_cell (const struct pivot_table *table,
1183 const size_t *dindexes)
1185 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1186 return pivot_table_lookup_cell__ (table, dindexes, hash);
1189 const struct pivot_value *
1190 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1192 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1193 return cell ? cell->value : NULL;
1196 struct pivot_value *
1197 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1199 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1201 cell->value = pivot_value_new_user_text ("", -1);
1206 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1208 if (pivot_category_is_group (category) && category->n_subs)
1209 for (size_t i = 0; i < category->n_subs; i++)
1210 distribute_extra_depth (category->subs[i], extra_depth);
1212 category->extra_depth += extra_depth;
1216 pivot_category_assign_label_depth (struct pivot_category *category,
1217 bool dimension_labels_in_corner)
1219 category->extra_depth = 0;
1221 if (pivot_category_is_group (category))
1224 for (size_t i = 0; i < category->n_subs; i++)
1226 pivot_category_assign_label_depth (category->subs[i], false);
1227 depth = MAX (depth, category->subs[i]->label_depth);
1230 for (size_t i = 0; i < category->n_subs; i++)
1232 struct pivot_category *sub = category->subs[i];
1234 size_t extra_depth = depth - sub->label_depth;
1236 distribute_extra_depth (sub, extra_depth);
1238 sub->label_depth = depth;
1241 category->show_label_in_corner = (category->show_label
1242 && dimension_labels_in_corner);
1243 category->label_depth
1244 = (category->show_label && !category->show_label_in_corner
1245 ? depth + 1 : depth);
1248 category->label_depth = 1;
1252 pivot_axis_assign_label_depth (struct pivot_table *table,
1253 enum pivot_axis_type axis_type,
1254 bool dimension_labels_in_corner)
1256 struct pivot_axis *axis = &table->axes[axis_type];
1257 bool any_label_shown_in_corner = false;
1258 axis->label_depth = 0;
1260 for (size_t i = 0; i < axis->n_dimensions; i++)
1262 struct pivot_dimension *d = axis->dimensions[i];
1263 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1264 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1265 axis->label_depth += d->label_depth;
1266 axis->extent *= d->n_leaves;
1268 if (d->root->show_label_in_corner)
1269 any_label_shown_in_corner = true;
1271 return any_label_shown_in_corner;
1275 pivot_table_assign_label_depth (struct pivot_table *table)
1277 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1278 if (pivot_axis_assign_label_depth (
1279 table, PIVOT_AXIS_ROW, (table->row_labels_in_corner
1280 && !table->corner_text))
1281 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1282 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1283 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1291 indent (int indentation)
1293 for (int i = 0; i < indentation * 2; i++)
1298 pivot_value_dump (const struct pivot_value *value)
1300 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1301 SETTINGS_VALUE_SHOW_DEFAULT);
1307 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1312 indent (indentation);
1313 printf ("%s: ", name);
1314 pivot_value_dump (value);
1320 pivot_table_dump_string (const char *string, const char *name, int indentation)
1324 indent (indentation);
1325 printf ("%s: %s\n", name, string);
1330 pivot_category_dump (const struct pivot_category *c, int indentation)
1332 indent (indentation);
1333 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1334 pivot_value_dump (c->name);
1337 if (pivot_category_is_leaf (c))
1338 printf ("data_index=%zu\n", c->data_index);
1341 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1344 for (size_t i = 0; i < c->n_subs; i++)
1345 pivot_category_dump (c->subs[i], indentation + 1);
1350 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1352 indent (indentation);
1353 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1354 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1356 pivot_category_dump (d->root, indentation + 1);
1360 area_style_dump (enum pivot_area area, const struct area_style *a,
1363 indent (indentation);
1364 printf ("%s: ", pivot_area_to_string (area));
1365 font_style_dump (&a->font_style);
1367 cell_style_dump (&a->cell_style);
1372 table_border_style_dump (enum pivot_border border,
1373 const struct table_border_style *b, int indentation)
1375 indent (indentation);
1376 printf ("%s: %s ", pivot_border_to_string (border),
1377 table_stroke_to_string (b->stroke));
1378 cell_color_dump (&b->color);
1383 compose_headings (const struct pivot_axis *axis,
1384 const size_t *column_enumeration,
1385 enum settings_value_show show_values,
1386 enum settings_value_show show_variables)
1388 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1391 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1392 for (size_t i = 0; i < axis->label_depth; i++)
1393 headings[i] = xcalloc (axis->extent, sizeof **headings);
1395 const size_t *indexes;
1397 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1399 int row = axis->label_depth - 1;
1400 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1402 const struct pivot_dimension *d = axis->dimensions[dim_index];
1403 if (d->hide_all_labels)
1405 for (const struct pivot_category *c
1406 = d->presentation_leaves[indexes[dim_index]];
1410 if (pivot_category_is_leaf (c) || (c->show_label
1411 && !c->show_label_in_corner))
1413 headings[row][column] = pivot_value_to_string (
1414 c->name, show_values, show_variables);
1415 if (!*headings[row][column])
1416 headings[row][column] = xstrdup ("<blank>");
1428 free_headings (const struct pivot_axis *axis, char ***headings)
1430 for (size_t i = 0; i < axis->label_depth; i++)
1432 for (size_t j = 0; j < axis->extent; j++)
1433 free (headings[i][j]);
1440 pivot_table_sizing_dump (const char *name, const struct pivot_table_sizing *s,
1443 indent (indentation);
1444 printf ("%ss: min=%d, max=%d\n", name, s->range[0], s->range[1]);
1447 indent (indentation + 1);
1448 printf ("%s widths:", name);
1449 for (size_t i = 0; i < s->n_widths; i++)
1450 printf (" %d", s->widths[i]);
1455 indent (indentation + 1);
1456 printf ("break after %ss:", name);
1457 for (size_t i = 0; i < s->n_breaks; i++)
1458 printf (" %zu", s->breaks[i]);
1463 indent (indentation + 1);
1464 printf ("keep %ss together:", name);
1465 for (size_t i = 0; i < s->n_keeps; i++)
1466 printf (" [%zu,%zu]",
1468 s->keeps[i].ofs + s->keeps[i].n - 1);
1474 pivot_table_dump (const struct pivot_table *table, int indentation)
1479 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1480 if (table->decimal == '.' || table->decimal == ',')
1481 settings_set_decimal_char (table->decimal);
1483 pivot_table_dump_value (table->title, "title", indentation);
1484 pivot_table_dump_string (table->command_c, "command", indentation);
1485 pivot_table_dump_string (table->dataset, "dataset", indentation);
1486 pivot_table_dump_string (table->datafile, "datafile", indentation);
1487 pivot_table_dump_string (table->notes, "notes", indentation);
1488 pivot_table_dump_string (table->table_look, "table-look", indentation);
1491 indent (indentation);
1493 printf ("date: %s", ctime_r (&table->date, buf));
1496 indent (indentation);
1497 printf ("sizing:\n");
1498 pivot_table_sizing_dump ("column", &table->sizing[TABLE_HORZ],
1500 pivot_table_sizing_dump ("row", &table->sizing[TABLE_VERT],
1503 indent (indentation);
1504 printf ("areas:\n");
1505 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1506 area_style_dump (area, &table->areas[area], indentation + 1);
1508 indent (indentation);
1509 printf ("borders:\n");
1510 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1511 table_border_style_dump (border, &table->borders[border], indentation + 1);
1513 for (size_t i = 0; i < table->n_dimensions; i++)
1514 pivot_dimension_dump (table->dimensions[i], indentation);
1516 /* Presentation and data indexes. */
1517 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1519 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1520 if (layer_axis->n_dimensions)
1522 indent (indentation);
1523 printf ("current layer:");
1525 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1527 const struct pivot_dimension *d = layer_axis->dimensions[i];
1528 char *name = pivot_value_to_string (d->root->name,
1530 table->show_variables);
1531 char *value = pivot_value_to_string (
1532 d->data_leaves[table->current_layer[i]]->name,
1533 table->show_values, table->show_variables);
1534 printf (" %s=%s", name, value);
1542 size_t *layer_indexes;
1543 size_t layer_iteration = 0;
1544 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1546 indent (indentation);
1547 printf ("layer %zu:", layer_iteration++);
1549 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1550 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1552 const struct pivot_dimension *d = layer_axis->dimensions[i];
1554 fputs (i == 0 ? " " : ", ", stdout);
1555 pivot_value_dump (d->root->name);
1556 fputs (" =", stdout);
1558 struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1561 for (const struct pivot_category *c
1562 = d->presentation_leaves[layer_indexes[i]];
1566 if (pivot_category_is_leaf (c) || c->show_label)
1567 names[n_names++] = c->name;
1570 for (size_t i = n_names; i-- > 0; )
1573 pivot_value_dump (names[i]);
1579 size_t *column_enumeration = pivot_table_enumerate_axis (
1580 table, PIVOT_AXIS_COLUMN, layer_indexes, table->omit_empty, NULL);
1581 size_t *row_enumeration = pivot_table_enumerate_axis (
1582 table, PIVOT_AXIS_ROW, layer_indexes, table->omit_empty, NULL);
1584 char ***column_headings = compose_headings (
1585 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1586 table->show_values, table->show_variables);
1587 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1589 indent (indentation + 1);
1590 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1593 fputs ("; ", stdout);
1594 if (column_headings[y][x])
1595 fputs (column_headings[y][x], stdout);
1599 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1601 indent (indentation + 1);
1602 printf ("-----------------------------------------------\n");
1604 char ***row_headings = compose_headings (
1605 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1606 table->show_values, table->show_variables);
1609 const size_t *pindexes[PIVOT_N_AXES]
1610 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1611 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1612 &table->axes[PIVOT_AXIS_ROW])
1614 indent (indentation + 1);
1617 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1620 fputs ("; ", stdout);
1621 if (row_headings[y][x])
1622 fputs (row_headings[y][x], stdout);
1628 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1630 &table->axes[PIVOT_AXIS_COLUMN])
1635 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1636 const struct pivot_value *value = pivot_table_get (
1639 pivot_value_dump (value);
1646 free (column_enumeration);
1647 free (row_enumeration);
1648 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1651 pivot_table_dump_value (table->caption, "caption", indentation);
1653 for (size_t i = 0; i < table->n_footnotes; i++)
1655 const struct pivot_footnote *f = table->footnotes[i];
1656 indent (indentation);
1659 pivot_value_dump (f->marker);
1661 printf ("%zu", f->idx);
1663 pivot_value_dump (f->content);
1668 settings_set_decimal_char (old_decimal);
1672 consume_int (const char *p, size_t *n)
1675 while (c_isdigit (*p))
1676 *n = *n * 10 + (*p++ - '0');
1681 pivot_format_inner_template (struct string *out, const char *template,
1683 struct pivot_value **values, size_t n_values,
1684 enum settings_value_show show_values,
1685 enum settings_value_show show_variables)
1687 size_t args_consumed = 0;
1688 while (*template && *template != ':')
1690 if (*template == '\\' && template[1])
1692 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1695 else if (*template == escape)
1698 template = consume_int (template + 1, &index);
1699 if (index >= 1 && index <= n_values)
1701 pivot_value_format (values[index - 1], show_values,
1702 show_variables, out);
1703 args_consumed = MAX (args_consumed, index);
1707 ds_put_byte (out, *template++);
1709 return args_consumed;
1713 pivot_extract_inner_template (const char *template, const char **p)
1719 if (*template == '\\' && template[1] != '\0')
1721 else if (*template == ':')
1722 return template + 1;
1723 else if (*template == '\0')
1731 pivot_format_template (struct string *out, const char *template,
1732 const struct pivot_argument *args, size_t n_args,
1733 enum settings_value_show show_values,
1734 enum settings_value_show show_variables)
1738 if (*template == '\\' && template[1] != '\0')
1740 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1743 else if (*template == '^')
1746 template = consume_int (template + 1, &index);
1747 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1748 pivot_value_format (args[index - 1].values[0],
1749 show_values, show_variables, out);
1751 else if (*template == '[')
1753 const char *tmpl[2];
1754 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1755 template = pivot_extract_inner_template (template, &tmpl[1]);
1756 template += *template == ']';
1759 template = consume_int (template, &index);
1760 if (index < 1 || index > n_args)
1763 const struct pivot_argument *arg = &args[index - 1];
1764 size_t left = arg->n;
1767 struct pivot_value **values = arg->values + (arg->n - left);
1768 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1769 char escape = "%^"[tmpl_idx];
1770 size_t used = pivot_format_inner_template (
1771 out, tmpl[tmpl_idx], escape, values, left,
1772 show_values, show_variables);
1773 if (!used || used > left)
1779 ds_put_byte (out, *template++);
1783 static enum settings_value_show
1784 interpret_show (enum settings_value_show global_show,
1785 enum settings_value_show table_show,
1786 enum settings_value_show value_show,
1789 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1790 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1791 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1795 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1796 SHOW_VARIABLES control whether variable and value labels are included.
1798 The "body" omits subscripts and superscripts and footnotes. */
1800 pivot_value_format_body (const struct pivot_value *value,
1801 enum settings_value_show show_values,
1802 enum settings_value_show show_variables,
1805 enum settings_value_show show;
1806 bool numeric = false;
1808 switch (value->type)
1810 case PIVOT_VALUE_NUMERIC:
1811 show = interpret_show (settings_get_show_values (),
1813 value->numeric.show,
1814 value->numeric.value_label != NULL);
1815 if (show & SETTINGS_VALUE_SHOW_VALUE)
1817 char *s = data_out (&(union value) { .f = value->numeric.x },
1818 "UTF-8", &value->numeric.format);
1819 ds_put_cstr (out, s + strspn (s, " "));
1822 if (show & SETTINGS_VALUE_SHOW_LABEL)
1824 if (show & SETTINGS_VALUE_SHOW_VALUE)
1825 ds_put_byte (out, ' ');
1826 ds_put_cstr (out, value->numeric.value_label);
1828 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1831 case PIVOT_VALUE_STRING:
1832 show = interpret_show (settings_get_show_values (),
1835 value->string.value_label != NULL);
1836 if (show & SETTINGS_VALUE_SHOW_VALUE)
1838 if (value->string.hex)
1840 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1842 ds_put_format (out, "%02X", *p);
1845 ds_put_cstr (out, value->string.s);
1847 if (show & SETTINGS_VALUE_SHOW_LABEL)
1849 if (show & SETTINGS_VALUE_SHOW_VALUE)
1850 ds_put_byte (out, ' ');
1851 ds_put_cstr (out, value->string.value_label);
1855 case PIVOT_VALUE_VARIABLE:
1856 show = interpret_show (settings_get_show_variables (),
1858 value->variable.show,
1859 value->variable.var_label != NULL);
1860 if (show & SETTINGS_VALUE_SHOW_VALUE)
1861 ds_put_cstr (out, value->variable.var_name);
1862 if (show & SETTINGS_VALUE_SHOW_LABEL)
1864 if (show & SETTINGS_VALUE_SHOW_VALUE)
1865 ds_put_byte (out, ' ');
1866 ds_put_cstr (out, value->variable.var_label);
1870 case PIVOT_VALUE_TEXT:
1871 ds_put_cstr (out, value->text.local);
1874 case PIVOT_VALUE_TEMPLATE:
1875 pivot_format_template (out, value->template.local, value->template.args,
1876 value->template.n_args, show_values,
1884 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
1885 SHOW_VARIABLES control whether variable and value labels are included.
1887 Subscripts and superscripts and footnotes are included. */
1889 pivot_value_format (const struct pivot_value *value,
1890 enum settings_value_show show_values,
1891 enum settings_value_show show_variables,
1894 pivot_value_format_body ( value, show_values, show_variables, out);
1896 if (value->n_subscripts)
1898 for (size_t i = 0; i < value->n_subscripts; i++)
1899 ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
1902 if (value->superscript)
1903 ds_put_format (out, "^%s", value->superscript);
1905 for (size_t i = 0; i < value->n_footnotes; i++)
1907 ds_put_byte (out, '^');
1908 pivot_value_format (value->footnotes[i]->marker,
1909 show_values, show_variables, out);
1913 /* Returns a text representation of VALUE. The caller must free the string,
1916 pivot_value_to_string (const struct pivot_value *value,
1917 enum settings_value_show show_values,
1918 enum settings_value_show show_variables)
1920 struct string s = DS_EMPTY_INITIALIZER;
1921 pivot_value_format (value, show_values, show_variables, &s);
1922 return ds_steal_cstr (&s);
1925 /* Frees the data owned by V. */
1927 pivot_value_destroy (struct pivot_value *value)
1931 font_style_uninit (value->font_style);
1932 free (value->font_style);
1933 free (value->cell_style);
1934 /* Do not free the elements of footnotes because VALUE does not own
1936 free (value->footnotes);
1938 for (size_t i = 0; i < value->n_subscripts; i++)
1939 free (value->subscripts[i]);
1940 free (value->subscripts);
1942 free (value->superscript);
1944 switch (value->type)
1946 case PIVOT_VALUE_NUMERIC:
1947 free (value->numeric.var_name);
1948 free (value->numeric.value_label);
1951 case PIVOT_VALUE_STRING:
1952 free (value->string.s);
1953 free (value->string.var_name);
1954 free (value->string.value_label);
1957 case PIVOT_VALUE_VARIABLE:
1958 free (value->variable.var_name);
1959 free (value->variable.var_label);
1962 case PIVOT_VALUE_TEXT:
1963 free (value->text.local);
1964 if (value->text.c != value->text.local)
1965 free (value->text.c);
1966 if (value->text.id != value->text.local
1967 && value->text.id != value->text.c)
1968 free (value->text.id);
1971 case PIVOT_VALUE_TEMPLATE:
1972 free (value->template.local);
1973 if (value->template.id != value->template.local)
1974 free (value->template.id);
1975 for (size_t i = 0; i < value->template.n_args; i++)
1976 pivot_argument_uninit (&value->template.args[i]);
1977 free (value->template.args);
1984 /* Sets AREA to the style to use for VALUE, with defaults coming from
1985 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
1987 pivot_value_get_style (struct pivot_value *value,
1988 const struct area_style *default_style,
1989 struct area_style *area)
1991 font_style_copy (NULL, &area->font_style, (value->font_style
1993 : &default_style->font_style));
1994 area->cell_style = (value->cell_style
1995 ? *value->cell_style
1996 : default_style->cell_style);
1999 /* Copies AREA into VALUE's style. */
2001 pivot_value_set_style (struct pivot_value *value,
2002 const struct area_style *area)
2004 if (value->font_style)
2005 font_style_uninit (value->font_style);
2007 value->font_style = xmalloc (sizeof *value->font_style);
2008 font_style_copy (NULL, value->font_style, &area->font_style);
2010 if (!value->cell_style)
2011 value->cell_style = xmalloc (sizeof *value->cell_style);
2012 *value->cell_style = area->cell_style;
2015 /* Frees the data owned by ARG (but not ARG itself). */
2017 pivot_argument_uninit (struct pivot_argument *arg)
2021 for (size_t i = 0; i < arg->n; i++)
2022 pivot_value_destroy (arg->values[i]);
2027 /* Creates and returns a new pivot_value whose contents is the null-terminated
2028 string TEXT. Takes ownership of TEXT.
2030 This function is for text strings provided by the user (with the exception
2031 that pivot_value_new_variable() should be used for variable names). For
2032 strings that are part of the PSPP user interface, such as names of
2033 procedures, statistics, annotations, error messages, etc., use
2034 pivot_value_new_text(). */
2035 struct pivot_value *
2036 pivot_value_new_user_text_nocopy (char *text)
2038 struct pivot_value *value = xmalloc (sizeof *value);
2039 *value = (struct pivot_value) {
2040 .type = PIVOT_VALUE_TEXT,
2045 .user_provided = true,
2051 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2052 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2055 This function is for text strings provided by the user (with the exception
2056 that pivot_value_new_variable() should be used for variable names). For
2057 strings that are part of the PSPP user interface, such as names of
2058 procedures, statistics, annotations, error messages, etc., use
2059 pivot_value_new_text().j
2061 The caller retains ownership of TEXT.*/
2062 struct pivot_value *
2063 pivot_value_new_user_text (const char *text, size_t length)
2065 return pivot_value_new_user_text_nocopy (
2066 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2069 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2070 a translatable string, but not actually translated yet, e.g. enclosed in
2071 N_(). This function is for text strings that are part of the PSPP user
2072 interface, such as names of procedures, statistics, annotations, error
2073 messages, etc. For strings that come from the user, use
2074 pivot_value_new_user_text(). */
2075 struct pivot_value *
2076 pivot_value_new_text (const char *text)
2078 char *c = xstrdup (text);
2079 char *local = xstrdup (gettext (c));
2081 struct pivot_value *value = xmalloc (sizeof *value);
2082 *value = (struct pivot_value) {
2083 .type = PIVOT_VALUE_TEXT,
2088 .user_provided = false,
2094 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2096 struct pivot_value * PRINTF_FORMAT (1, 2)
2097 pivot_value_new_text_format (const char *format, ...)
2100 va_start (args, format);
2101 char *c = xvasprintf (format, args);
2104 va_start (args, format);
2105 char *local = xvasprintf (gettext (format), args);
2108 struct pivot_value *value = xmalloc (sizeof *value);
2109 *value = (struct pivot_value) {
2110 .type = PIVOT_VALUE_TEXT,
2115 .user_provided = false,
2122 xstrdup_if_nonempty (const char *s)
2124 return s && s[0] ? xstrdup (s) : NULL;
2127 /* Returns a new pivot_value that represents X.
2129 The format to use for X is unspecified. Usually the easiest way to specify
2130 a format is through assigning a result class to one of the categories that
2131 the pivot_value will end up in. If that is not suitable, then the caller
2132 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2133 struct pivot_value *
2134 pivot_value_new_number (double x)
2136 struct pivot_value *value = xmalloc (sizeof *value);
2137 *value = (struct pivot_value) {
2138 .type = PIVOT_VALUE_NUMERIC,
2139 .numeric = { .x = x, },
2144 /* Returns a new pivot_value that represents X, formatted as an integer. */
2145 struct pivot_value *
2146 pivot_value_new_integer (double x)
2148 struct pivot_value *value = pivot_value_new_number (x);
2149 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2153 /* Returns a new pivot_value that represents VALUE, formatted as for
2155 struct pivot_value *
2156 pivot_value_new_var_value (const struct variable *variable,
2157 const union value *value)
2159 struct pivot_value *pv = pivot_value_new_value (
2160 value, var_get_width (variable), var_get_print_format (variable),
2161 var_get_encoding (variable));
2163 char *var_name = xstrdup (var_get_name (variable));
2164 if (var_is_alpha (variable))
2165 pv->string.var_name = var_name;
2167 pv->numeric.var_name = var_name;
2169 const char *label = var_lookup_value_label (variable, value);
2172 if (var_is_alpha (variable))
2173 pv->string.value_label = xstrdup (label);
2175 pv->numeric.value_label = xstrdup (label);
2181 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2182 formatted with FORMAT. For a string value, ENCODING must be its character
2184 struct pivot_value *
2185 pivot_value_new_value (const union value *value, int width,
2186 const struct fmt_spec *format, const char *encoding)
2188 struct pivot_value *pv = xzalloc (sizeof *pv);
2191 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2193 size_t n = strlen (s);
2194 while (n > 0 && s[n - 1] == ' ')
2197 pv->type = PIVOT_VALUE_STRING;
2199 pv->string.hex = format->type == FMT_AHEX;
2203 pv->type = PIVOT_VALUE_NUMERIC;
2204 pv->numeric.x = value->f;
2205 pv->numeric.format = *format;
2211 /* Returns a new pivot_value for VARIABLE. */
2212 struct pivot_value *
2213 pivot_value_new_variable (const struct variable *variable)
2215 struct pivot_value *value = xmalloc (sizeof *value);
2216 *value = (struct pivot_value) {
2217 .type = PIVOT_VALUE_VARIABLE,
2219 .var_name = xstrdup (var_get_name (variable)),
2220 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2226 /* Attaches a reference to FOOTNOTE to V. */
2228 pivot_value_add_footnote (struct pivot_value *v,
2229 const struct pivot_footnote *footnote)
2231 v->footnotes = xrealloc (v->footnotes,
2232 (v->n_footnotes + 1) * sizeof *v->footnotes);
2233 v->footnotes[v->n_footnotes++] = footnote;
2236 /* If VALUE is a numeric value, and RC is a result class such as
2237 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2239 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2242 if (value->type == PIVOT_VALUE_NUMERIC)
2244 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2246 value->numeric.format = *f;