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->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
705 table->title = title;
706 table->subtype = pivot_value_new_text (subtype);
708 const char *command_id = output_get_command_name ();
709 table->command_c = command_id ? xstrdup (command_id) : NULL;
711 table->sizing[TABLE_HORZ].range[0] = 50;
712 table->sizing[TABLE_HORZ].range[1] = 72;
713 table->sizing[TABLE_VERT].range[0] = 36;
714 table->sizing[TABLE_VERT].range[1] = 120;
716 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
717 area_style_copy (NULL, &table->areas[i], 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 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);
1062 table->footnotes[table->n_footnotes++] = f;
1066 struct pivot_footnote *f = table->footnotes[idx];
1069 pivot_value_destroy (f->marker);
1074 pivot_value_destroy (f->content);
1075 f->content = content;
1080 /* Frees the data owned by F. */
1082 pivot_footnote_destroy (struct pivot_footnote *f)
1086 pivot_value_destroy (f->content);
1087 pivot_value_destroy (f->marker);
1092 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1093 indexes for each dimension in TABLE in DINDEXES[]. */
1095 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1096 const size_t *pindexes[PIVOT_N_AXES],
1097 size_t dindexes[/* table->n_dimensions */])
1099 for (size_t i = 0; i < PIVOT_N_AXES; i++)
1101 const struct pivot_axis *axis = &table->axes[i];
1103 for (size_t j = 0; j < axis->n_dimensions; j++)
1105 const struct pivot_dimension *d = axis->dimensions[j];
1106 dindexes[d->top_index]
1107 = d->presentation_leaves[pindexes[i][j]]->data_index;
1113 pivot_table_enumerate_axis (const struct pivot_table *table,
1114 enum pivot_axis_type axis_type,
1115 const size_t *layer_indexes, bool omit_empty,
1118 const struct pivot_axis *axis = &table->axes[axis_type];
1119 if (!axis->n_dimensions)
1121 size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1123 enumeration[1] = SIZE_MAX;
1128 else if (!axis->extent)
1130 size_t *enumeration = xmalloc (sizeof *enumeration);
1131 *enumeration = SIZE_MAX;
1137 size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1138 axis->n_dimensions), 1),
1139 sizeof *enumeration);
1140 size_t *p = enumeration;
1141 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1143 size_t *axis_indexes;
1144 PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1148 enum pivot_axis_type axis2_type
1149 = pivot_axis_type_transpose (axis_type);
1151 size_t *axis2_indexes;
1152 PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1154 const size_t *pindexes[PIVOT_N_AXES];
1155 pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1156 pindexes[axis_type] = axis_indexes;
1157 pindexes[axis2_type] = axis2_indexes;
1158 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1159 if (pivot_table_get (table, dindexes))
1165 free (axis2_indexes);
1168 memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1169 p += axis->n_dimensions;
1173 *n = (p - enumeration) / axis->n_dimensions;
1179 static const struct pivot_cell *
1180 pivot_table_lookup_cell (const struct pivot_table *table,
1181 const size_t *dindexes)
1183 unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1184 return pivot_table_lookup_cell__ (table, dindexes, hash);
1187 const struct pivot_value *
1188 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1190 const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1191 return cell ? cell->value : NULL;
1194 struct pivot_value *
1195 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1197 struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1199 cell->value = pivot_value_new_user_text ("", -1);
1204 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1206 if (pivot_category_is_group (category) && category->n_subs)
1207 for (size_t i = 0; i < category->n_subs; i++)
1208 distribute_extra_depth (category->subs[i], extra_depth);
1210 category->extra_depth += extra_depth;
1214 pivot_category_assign_label_depth (struct pivot_category *category,
1215 bool dimension_labels_in_corner)
1217 category->extra_depth = 0;
1219 if (pivot_category_is_group (category))
1222 for (size_t i = 0; i < category->n_subs; i++)
1224 pivot_category_assign_label_depth (category->subs[i], false);
1225 depth = MAX (depth, category->subs[i]->label_depth);
1228 for (size_t i = 0; i < category->n_subs; i++)
1230 struct pivot_category *sub = category->subs[i];
1232 size_t extra_depth = depth - sub->label_depth;
1234 distribute_extra_depth (sub, extra_depth);
1236 sub->label_depth = depth;
1239 category->show_label_in_corner = (category->show_label
1240 && dimension_labels_in_corner);
1241 category->label_depth
1242 = (category->show_label && !category->show_label_in_corner
1243 ? depth + 1 : depth);
1246 category->label_depth = 1;
1250 pivot_axis_assign_label_depth (struct pivot_table *table,
1251 enum pivot_axis_type axis_type,
1252 bool dimension_labels_in_corner)
1254 struct pivot_axis *axis = &table->axes[axis_type];
1255 bool any_label_shown_in_corner = false;
1256 axis->label_depth = 0;
1258 for (size_t i = 0; i < axis->n_dimensions; i++)
1260 struct pivot_dimension *d = axis->dimensions[i];
1261 pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1262 d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1263 axis->label_depth += d->label_depth;
1264 axis->extent *= d->n_leaves;
1266 if (d->root->show_label_in_corner)
1267 any_label_shown_in_corner = true;
1269 return any_label_shown_in_corner;
1273 pivot_table_assign_label_depth (struct pivot_table *table)
1275 pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1276 if (pivot_axis_assign_label_depth (
1277 table, PIVOT_AXIS_ROW, (table->row_labels_in_corner
1278 && !table->corner_text))
1279 && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1280 table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1281 pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1289 indent (int indentation)
1291 for (int i = 0; i < indentation * 2; i++)
1296 pivot_value_dump (const struct pivot_value *value)
1298 char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1299 SETTINGS_VALUE_SHOW_DEFAULT);
1305 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1310 indent (indentation);
1311 printf ("%s: ", name);
1312 pivot_value_dump (value);
1318 pivot_table_dump_string (const char *string, const char *name, int indentation)
1322 indent (indentation);
1323 printf ("%s: %s\n", name, string);
1328 pivot_category_dump (const struct pivot_category *c, int indentation)
1330 indent (indentation);
1331 printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1332 pivot_value_dump (c->name);
1335 if (pivot_category_is_leaf (c))
1336 printf ("data_index=%zu\n", c->data_index);
1339 printf (" (label %s)", c->show_label ? "shown" : "hidden");
1342 for (size_t i = 0; i < c->n_subs; i++)
1343 pivot_category_dump (c->subs[i], indentation + 1);
1348 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1350 indent (indentation);
1351 printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1352 pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1354 pivot_category_dump (d->root, indentation + 1);
1358 area_style_dump (enum pivot_area area, const struct area_style *a,
1361 indent (indentation);
1362 printf ("%s: ", pivot_area_to_string (area));
1363 font_style_dump (&a->font_style);
1365 cell_style_dump (&a->cell_style);
1370 table_border_style_dump (enum pivot_border border,
1371 const struct table_border_style *b, int indentation)
1373 indent (indentation);
1374 printf ("%s: %s ", pivot_border_to_string (border),
1375 table_stroke_to_string (b->stroke));
1376 cell_color_dump (&b->color);
1381 compose_headings (const struct pivot_axis *axis,
1382 const size_t *column_enumeration,
1383 enum settings_value_show show_values,
1384 enum settings_value_show show_variables)
1386 if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1389 char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1390 for (size_t i = 0; i < axis->label_depth; i++)
1391 headings[i] = xcalloc (axis->extent, sizeof **headings);
1393 const size_t *indexes;
1395 PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1397 int row = axis->label_depth - 1;
1398 for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1400 const struct pivot_dimension *d = axis->dimensions[dim_index];
1401 if (d->hide_all_labels)
1403 for (const struct pivot_category *c
1404 = d->presentation_leaves[indexes[dim_index]];
1408 if (pivot_category_is_leaf (c) || (c->show_label
1409 && !c->show_label_in_corner))
1411 headings[row][column] = pivot_value_to_string (
1412 c->name, show_values, show_variables);
1413 if (!*headings[row][column])
1414 headings[row][column] = xstrdup ("<blank>");
1426 free_headings (const struct pivot_axis *axis, char ***headings)
1428 for (size_t i = 0; i < axis->label_depth; i++)
1430 for (size_t j = 0; j < axis->extent; j++)
1431 free (headings[i][j]);
1438 pivot_table_sizing_dump (const char *name, const struct pivot_table_sizing *s,
1441 indent (indentation);
1442 printf ("%ss: min=%d, max=%d\n", name, s->range[0], s->range[1]);
1445 indent (indentation + 1);
1446 printf ("%s widths:", name);
1447 for (size_t i = 0; i < s->n_widths; i++)
1448 printf (" %d", s->widths[i]);
1453 indent (indentation + 1);
1454 printf ("break after %ss:", name);
1455 for (size_t i = 0; i < s->n_breaks; i++)
1456 printf (" %zu", s->breaks[i]);
1461 indent (indentation + 1);
1462 printf ("keep %ss together:", name);
1463 for (size_t i = 0; i < s->n_keeps; i++)
1464 printf (" [%zu,%zu]",
1466 s->keeps[i].ofs + s->keeps[i].n - 1);
1472 pivot_table_dump (const struct pivot_table *table, int indentation)
1477 int old_decimal = settings_get_decimal_char (FMT_COMMA);
1478 if (table->decimal == '.' || table->decimal == ',')
1479 settings_set_decimal_char (table->decimal);
1481 pivot_table_dump_value (table->title, "title", indentation);
1482 pivot_table_dump_string (table->command_c, "command", indentation);
1483 pivot_table_dump_string (table->dataset, "dataset", indentation);
1484 pivot_table_dump_string (table->datafile, "datafile", indentation);
1485 pivot_table_dump_string (table->notes, "notes", indentation);
1486 pivot_table_dump_string (table->table_look, "table-look", indentation);
1489 indent (indentation);
1491 printf ("date: %s", ctime_r (&table->date, buf));
1494 indent (indentation);
1495 printf ("sizing:\n");
1496 pivot_table_sizing_dump ("column", &table->sizing[TABLE_HORZ],
1498 pivot_table_sizing_dump ("row", &table->sizing[TABLE_VERT],
1501 indent (indentation);
1502 printf ("areas:\n");
1503 for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1504 area_style_dump (area, &table->areas[area], indentation + 1);
1506 indent (indentation);
1507 printf ("borders:\n");
1508 for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1509 table_border_style_dump (border, &table->borders[border], indentation + 1);
1511 for (size_t i = 0; i < table->n_dimensions; i++)
1512 pivot_dimension_dump (table->dimensions[i], indentation);
1514 /* Presentation and data indexes. */
1515 size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1517 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1518 if (layer_axis->n_dimensions)
1520 indent (indentation);
1521 printf ("current layer:");
1523 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1525 const struct pivot_dimension *d = layer_axis->dimensions[i];
1526 char *name = pivot_value_to_string (d->root->name,
1528 table->show_variables);
1529 char *value = pivot_value_to_string (
1530 d->data_leaves[table->current_layer[i]]->name,
1531 table->show_values, table->show_variables);
1532 printf (" %s=%s", name, value);
1540 size_t *layer_indexes;
1541 size_t layer_iteration = 0;
1542 PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1544 indent (indentation);
1545 printf ("layer %zu:", layer_iteration++);
1547 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1548 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1550 const struct pivot_dimension *d = layer_axis->dimensions[i];
1552 fputs (i == 0 ? " " : ", ", stdout);
1553 pivot_value_dump (d->root->name);
1554 fputs (" =", stdout);
1556 struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1559 for (const struct pivot_category *c
1560 = d->presentation_leaves[layer_indexes[i]];
1564 if (pivot_category_is_leaf (c) || c->show_label)
1565 names[n_names++] = c->name;
1568 for (size_t i = n_names; i-- > 0; )
1571 pivot_value_dump (names[i]);
1577 size_t *column_enumeration = pivot_table_enumerate_axis (
1578 table, PIVOT_AXIS_COLUMN, layer_indexes, table->omit_empty, NULL);
1579 size_t *row_enumeration = pivot_table_enumerate_axis (
1580 table, PIVOT_AXIS_ROW, layer_indexes, table->omit_empty, NULL);
1582 char ***column_headings = compose_headings (
1583 &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1584 table->show_values, table->show_variables);
1585 for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1587 indent (indentation + 1);
1588 for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1591 fputs ("; ", stdout);
1592 if (column_headings[y][x])
1593 fputs (column_headings[y][x], stdout);
1597 free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1599 indent (indentation + 1);
1600 printf ("-----------------------------------------------\n");
1602 char ***row_headings = compose_headings (
1603 &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1604 table->show_values, table->show_variables);
1607 const size_t *pindexes[PIVOT_N_AXES]
1608 = { [PIVOT_AXIS_LAYER] = layer_indexes };
1609 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1610 &table->axes[PIVOT_AXIS_ROW])
1612 indent (indentation + 1);
1615 for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1618 fputs ("; ", stdout);
1619 if (row_headings[y][x])
1620 fputs (row_headings[y][x], stdout);
1626 PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1628 &table->axes[PIVOT_AXIS_COLUMN])
1633 pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1634 const struct pivot_value *value = pivot_table_get (
1637 pivot_value_dump (value);
1644 free (column_enumeration);
1645 free (row_enumeration);
1646 free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1649 pivot_table_dump_value (table->caption, "caption", indentation);
1651 for (size_t i = 0; i < table->n_footnotes; i++)
1653 const struct pivot_footnote *f = table->footnotes[i];
1654 indent (indentation);
1657 pivot_value_dump (f->marker);
1659 printf ("%zu", f->idx);
1661 pivot_value_dump (f->content);
1666 settings_set_decimal_char (old_decimal);
1670 consume_int (const char *p, size_t *n)
1673 while (c_isdigit (*p))
1674 *n = *n * 10 + (*p++ - '0');
1679 pivot_format_inner_template (struct string *out, const char *template,
1681 struct pivot_value **values, size_t n_values,
1682 enum settings_value_show show_values,
1683 enum settings_value_show show_variables)
1685 size_t args_consumed = 0;
1686 while (*template && *template != ':')
1688 if (*template == '\\' && template[1])
1690 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1693 else if (*template == escape)
1696 template = consume_int (template + 1, &index);
1697 if (index >= 1 && index <= n_values)
1699 pivot_value_format (values[index - 1], show_values,
1700 show_variables, out);
1701 args_consumed = MAX (args_consumed, index);
1705 ds_put_byte (out, *template++);
1707 return args_consumed;
1711 pivot_extract_inner_template (const char *template, const char **p)
1717 if (*template == '\\' && template[1] != '\0')
1719 else if (*template == ':')
1720 return template + 1;
1721 else if (*template == '\0')
1729 pivot_format_template (struct string *out, const char *template,
1730 const struct pivot_argument *args, size_t n_args,
1731 enum settings_value_show show_values,
1732 enum settings_value_show show_variables)
1736 if (*template == '\\' && template[1] != '\0')
1738 ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1741 else if (*template == '^')
1744 template = consume_int (template + 1, &index);
1745 if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1746 pivot_value_format (args[index - 1].values[0],
1747 show_values, show_variables, out);
1749 else if (*template == '[')
1751 const char *tmpl[2];
1752 template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1753 template = pivot_extract_inner_template (template, &tmpl[1]);
1754 template += *template == ']';
1757 template = consume_int (template, &index);
1758 if (index < 1 || index > n_args)
1761 const struct pivot_argument *arg = &args[index - 1];
1762 size_t left = arg->n;
1765 struct pivot_value **values = arg->values + (arg->n - left);
1766 int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1767 char escape = "%^"[tmpl_idx];
1768 size_t used = pivot_format_inner_template (
1769 out, tmpl[tmpl_idx], escape, values, left,
1770 show_values, show_variables);
1771 if (!used || used > left)
1777 ds_put_byte (out, *template++);
1781 static enum settings_value_show
1782 interpret_show (enum settings_value_show global_show,
1783 enum settings_value_show table_show,
1784 enum settings_value_show value_show,
1787 return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1788 : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1789 : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1793 /* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
1794 SHOW_VARIABLES control whether variable and value labels are included.
1796 The "body" omits subscripts and superscripts and footnotes. */
1798 pivot_value_format_body (const struct pivot_value *value,
1799 enum settings_value_show show_values,
1800 enum settings_value_show show_variables,
1803 enum settings_value_show show;
1804 bool numeric = false;
1806 switch (value->type)
1808 case PIVOT_VALUE_NUMERIC:
1809 show = interpret_show (settings_get_show_values (),
1811 value->numeric.show,
1812 value->numeric.value_label != NULL);
1813 if (show & SETTINGS_VALUE_SHOW_VALUE)
1815 char *s = data_out (&(union value) { .f = value->numeric.x },
1816 "UTF-8", &value->numeric.format);
1817 ds_put_cstr (out, s + strspn (s, " "));
1820 if (show & SETTINGS_VALUE_SHOW_LABEL)
1822 if (show & SETTINGS_VALUE_SHOW_VALUE)
1823 ds_put_byte (out, ' ');
1824 ds_put_cstr (out, value->numeric.value_label);
1826 numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1829 case PIVOT_VALUE_STRING:
1830 show = interpret_show (settings_get_show_values (),
1833 value->string.value_label != NULL);
1834 if (show & SETTINGS_VALUE_SHOW_VALUE)
1836 if (value->string.hex)
1838 for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1840 ds_put_format (out, "%02X", *p);
1843 ds_put_cstr (out, value->string.s);
1845 if (show & SETTINGS_VALUE_SHOW_LABEL)
1847 if (show & SETTINGS_VALUE_SHOW_VALUE)
1848 ds_put_byte (out, ' ');
1849 ds_put_cstr (out, value->string.value_label);
1853 case PIVOT_VALUE_VARIABLE:
1854 show = interpret_show (settings_get_show_variables (),
1856 value->variable.show,
1857 value->variable.var_label != NULL);
1858 if (show & SETTINGS_VALUE_SHOW_VALUE)
1859 ds_put_cstr (out, value->variable.var_name);
1860 if (show & SETTINGS_VALUE_SHOW_LABEL)
1862 if (show & SETTINGS_VALUE_SHOW_VALUE)
1863 ds_put_byte (out, ' ');
1864 ds_put_cstr (out, value->variable.var_label);
1868 case PIVOT_VALUE_TEXT:
1869 ds_put_cstr (out, value->text.local);
1872 case PIVOT_VALUE_TEMPLATE:
1873 pivot_format_template (out, value->template.local, value->template.args,
1874 value->template.n_args, show_values,
1882 /* Appends a text representation of VALUE to OUT. SHOW_VALUES and
1883 SHOW_VARIABLES control whether variable and value labels are included.
1885 Subscripts and superscripts and footnotes are included. */
1887 pivot_value_format (const struct pivot_value *value,
1888 enum settings_value_show show_values,
1889 enum settings_value_show show_variables,
1892 pivot_value_format_body ( value, show_values, show_variables, out);
1894 if (value->n_subscripts)
1896 for (size_t i = 0; i < value->n_subscripts; i++)
1897 ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
1900 if (value->superscript)
1901 ds_put_format (out, "^%s", value->superscript);
1903 for (size_t i = 0; i < value->n_footnotes; i++)
1905 ds_put_byte (out, '^');
1906 pivot_value_format (value->footnotes[i]->marker,
1907 show_values, show_variables, out);
1911 /* Returns a text representation of VALUE. The caller must free the string,
1914 pivot_value_to_string (const struct pivot_value *value,
1915 enum settings_value_show show_values,
1916 enum settings_value_show show_variables)
1918 struct string s = DS_EMPTY_INITIALIZER;
1919 pivot_value_format (value, show_values, show_variables, &s);
1920 return ds_steal_cstr (&s);
1923 /* Frees the data owned by V. */
1925 pivot_value_destroy (struct pivot_value *value)
1929 font_style_uninit (value->font_style);
1930 free (value->font_style);
1931 free (value->cell_style);
1932 /* Do not free the elements of footnotes because VALUE does not own
1934 free (value->footnotes);
1936 for (size_t i = 0; i < value->n_subscripts; i++)
1937 free (value->subscripts[i]);
1938 free (value->subscripts);
1940 free (value->superscript);
1942 switch (value->type)
1944 case PIVOT_VALUE_NUMERIC:
1945 free (value->numeric.var_name);
1946 free (value->numeric.value_label);
1949 case PIVOT_VALUE_STRING:
1950 free (value->string.s);
1951 free (value->string.var_name);
1952 free (value->string.value_label);
1955 case PIVOT_VALUE_VARIABLE:
1956 free (value->variable.var_name);
1957 free (value->variable.var_label);
1960 case PIVOT_VALUE_TEXT:
1961 free (value->text.local);
1962 if (value->text.c != value->text.local)
1963 free (value->text.c);
1964 if (value->text.id != value->text.local
1965 && value->text.id != value->text.c)
1966 free (value->text.id);
1969 case PIVOT_VALUE_TEMPLATE:
1970 free (value->template.local);
1971 if (value->template.id != value->template.local)
1972 free (value->template.id);
1973 for (size_t i = 0; i < value->template.n_args; i++)
1974 pivot_argument_uninit (&value->template.args[i]);
1975 free (value->template.args);
1982 /* Sets AREA to the style to use for VALUE, with defaults coming from
1983 DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
1985 pivot_value_get_style (struct pivot_value *value,
1986 const struct area_style *default_style,
1987 struct area_style *area)
1989 font_style_copy (NULL, &area->font_style, (value->font_style
1991 : &default_style->font_style));
1992 area->cell_style = (value->cell_style
1993 ? *value->cell_style
1994 : default_style->cell_style);
1997 /* Copies AREA into VALUE's style. */
1999 pivot_value_set_style (struct pivot_value *value,
2000 const struct area_style *area)
2002 if (value->font_style)
2003 font_style_uninit (value->font_style);
2005 value->font_style = xmalloc (sizeof *value->font_style);
2006 font_style_copy (NULL, value->font_style, &area->font_style);
2008 if (!value->cell_style)
2009 value->cell_style = xmalloc (sizeof *value->cell_style);
2010 *value->cell_style = area->cell_style;
2013 /* Frees the data owned by ARG (but not ARG itself). */
2015 pivot_argument_uninit (struct pivot_argument *arg)
2019 for (size_t i = 0; i < arg->n; i++)
2020 pivot_value_destroy (arg->values[i]);
2025 /* Creates and returns a new pivot_value whose contents is the null-terminated
2026 string TEXT. Takes ownership of TEXT.
2028 This function is for text strings provided by the user (with the exception
2029 that pivot_value_new_variable() should be used for variable names). For
2030 strings that are part of the PSPP user interface, such as names of
2031 procedures, statistics, annotations, error messages, etc., use
2032 pivot_value_new_text(). */
2033 struct pivot_value *
2034 pivot_value_new_user_text_nocopy (char *text)
2036 struct pivot_value *value = xmalloc (sizeof *value);
2037 *value = (struct pivot_value) {
2038 .type = PIVOT_VALUE_TEXT,
2043 .user_provided = true,
2049 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2050 TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2053 This function is for text strings provided by the user (with the exception
2054 that pivot_value_new_variable() should be used for variable names). For
2055 strings that are part of the PSPP user interface, such as names of
2056 procedures, statistics, annotations, error messages, etc., use
2057 pivot_value_new_text().j
2059 The caller retains ownership of TEXT.*/
2060 struct pivot_value *
2061 pivot_value_new_user_text (const char *text, size_t length)
2063 return pivot_value_new_user_text_nocopy (
2064 xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2067 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2068 a translatable string, but not actually translated yet, e.g. enclosed in
2069 N_(). This function is for text strings that are part of the PSPP user
2070 interface, such as names of procedures, statistics, annotations, error
2071 messages, etc. For strings that come from the user, use
2072 pivot_value_new_user_text(). */
2073 struct pivot_value *
2074 pivot_value_new_text (const char *text)
2076 char *c = xstrdup (text);
2077 char *local = xstrdup (gettext (c));
2079 struct pivot_value *value = xmalloc (sizeof *value);
2080 *value = (struct pivot_value) {
2081 .type = PIVOT_VALUE_TEXT,
2086 .user_provided = false,
2092 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2094 struct pivot_value * PRINTF_FORMAT (1, 2)
2095 pivot_value_new_text_format (const char *format, ...)
2098 va_start (args, format);
2099 char *c = xvasprintf (format, args);
2102 va_start (args, format);
2103 char *local = xvasprintf (gettext (format), args);
2106 struct pivot_value *value = xmalloc (sizeof *value);
2107 *value = (struct pivot_value) {
2108 .type = PIVOT_VALUE_TEXT,
2113 .user_provided = false,
2120 xstrdup_if_nonempty (const char *s)
2122 return s && s[0] ? xstrdup (s) : NULL;
2125 /* Returns a new pivot_value that represents X.
2127 The format to use for X is unspecified. Usually the easiest way to specify
2128 a format is through assigning a result class to one of the categories that
2129 the pivot_value will end up in. If that is not suitable, then the caller
2130 can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2131 struct pivot_value *
2132 pivot_value_new_number (double x)
2134 struct pivot_value *value = xmalloc (sizeof *value);
2135 *value = (struct pivot_value) {
2136 .type = PIVOT_VALUE_NUMERIC,
2137 .numeric = { .x = x, },
2142 /* Returns a new pivot_value that represents X, formatted as an integer. */
2143 struct pivot_value *
2144 pivot_value_new_integer (double x)
2146 struct pivot_value *value = pivot_value_new_number (x);
2147 value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2151 /* Returns a new pivot_value that represents VALUE, formatted as for
2153 struct pivot_value *
2154 pivot_value_new_var_value (const struct variable *variable,
2155 const union value *value)
2157 struct pivot_value *pv = pivot_value_new_value (
2158 value, var_get_width (variable), var_get_print_format (variable),
2159 var_get_encoding (variable));
2161 char *var_name = xstrdup (var_get_name (variable));
2162 if (var_is_alpha (variable))
2163 pv->string.var_name = var_name;
2165 pv->numeric.var_name = var_name;
2167 const char *label = var_lookup_value_label (variable, value);
2170 if (var_is_alpha (variable))
2171 pv->string.value_label = xstrdup (label);
2173 pv->numeric.value_label = xstrdup (label);
2179 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2180 formatted with FORMAT. For a string value, ENCODING must be its character
2182 struct pivot_value *
2183 pivot_value_new_value (const union value *value, int width,
2184 const struct fmt_spec *format, const char *encoding)
2186 struct pivot_value *pv = xzalloc (sizeof *pv);
2189 char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2191 size_t n = strlen (s);
2192 while (n > 0 && s[n - 1] == ' ')
2195 pv->type = PIVOT_VALUE_STRING;
2197 pv->string.hex = format->type == FMT_AHEX;
2201 pv->type = PIVOT_VALUE_NUMERIC;
2202 pv->numeric.x = value->f;
2203 pv->numeric.format = *format;
2209 /* Returns a new pivot_value for VARIABLE. */
2210 struct pivot_value *
2211 pivot_value_new_variable (const struct variable *variable)
2213 struct pivot_value *value = xmalloc (sizeof *value);
2214 *value = (struct pivot_value) {
2215 .type = PIVOT_VALUE_VARIABLE,
2217 .var_name = xstrdup (var_get_name (variable)),
2218 .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2224 /* Attaches a reference to FOOTNOTE to V. */
2226 pivot_value_add_footnote (struct pivot_value *v,
2227 const struct pivot_footnote *footnote)
2229 v->footnotes = xrealloc (v->footnotes,
2230 (v->n_footnotes + 1) * sizeof *v->footnotes);
2231 v->footnotes[v->n_footnotes++] = footnote;
2234 /* If VALUE is a numeric value, and RC is a result class such as
2235 PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2237 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2240 if (value->type == PIVOT_VALUE_NUMERIC)
2242 const struct fmt_spec *f = pivot_table_get_format (table, rc);
2244 value->numeric.format = *f;