pivot-table: Improve comments.
[pspp] / src / output / pivot-table.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2017, 2018 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include "output/pivot-table.h"
20
21 #include <stdlib.h>
22
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
30 #include "gl/c-ctype.h"
31 #include "gl/intprops.h"
32 #include "gl/minmax.h"
33 #include "gl/xalloc.h"
34 #include "gl/xmemdup0.h"
35 #include "gl/xsize.h"
36
37 #include "gettext.h"
38 #define _(msgid) gettext (msgid)
39 #define N_(msgid) msgid
40
41 static const struct fmt_spec *pivot_table_get_format (
42   const struct pivot_table *, const char *s);
43 \f
44 /* Pivot table display styling. */
45
46 /* Returns the name of AREA. */
47 const char *
48 pivot_area_to_string (enum pivot_area area)
49 {
50   switch (area)
51     {
52     case PIVOT_AREA_TITLE: return "title";
53     case PIVOT_AREA_CAPTION: return "caption";
54     case PIVOT_AREA_FOOTER: return "footer";
55     case PIVOT_AREA_CORNER: return "corner";
56     case PIVOT_AREA_COLUMN_LABELS: return "column labels";
57     case PIVOT_AREA_ROW_LABELS: return "row labels";
58     case PIVOT_AREA_DATA: return "data";
59     case PIVOT_AREA_LAYERS: return "layers";
60     case PIVOT_N_AREAS: default: return "**error**";
61     }
62 }
63
64 /* Returns the name of BORDER. */
65 const char *
66 pivot_border_to_string (enum pivot_border border)
67 {
68   switch (border)
69     {
70     case PIVOT_BORDER_TITLE:
71       return "title";
72
73     case PIVOT_BORDER_OUTER_LEFT:
74       return "left outer frame";
75     case PIVOT_BORDER_OUTER_TOP:
76       return "top outer frame";
77     case PIVOT_BORDER_OUTER_RIGHT:
78       return "right outer frame";
79     case PIVOT_BORDER_OUTER_BOTTOM:
80       return "bottom outer frame";
81
82     case PIVOT_BORDER_INNER_LEFT:
83       return "left inner frame";
84     case PIVOT_BORDER_INNER_TOP:
85       return "top inner frame";
86     case PIVOT_BORDER_INNER_RIGHT:
87       return "right inner frame";
88     case PIVOT_BORDER_INNER_BOTTOM:
89       return "bottom inner frame";
90
91     case PIVOT_BORDER_DATA_LEFT:
92       return "data area left";
93     case PIVOT_BORDER_DATA_TOP:
94       return "data area top";
95
96     case PIVOT_BORDER_DIM_ROW_HORZ:
97       return "row label horizontal dimension border";
98     case PIVOT_BORDER_DIM_ROW_VERT:
99       return "row label vertical dimension border";
100     case PIVOT_BORDER_DIM_COL_HORZ:
101       return "column label horizontal dimension border";
102     case PIVOT_BORDER_DIM_COL_VERT:
103       return "column label vertical dimension border";
104
105     case PIVOT_BORDER_CAT_ROW_HORZ:
106       return "row label horizontal category border";
107     case PIVOT_BORDER_CAT_ROW_VERT:
108       return "row label vertical category border";
109     case PIVOT_BORDER_CAT_COL_HORZ:
110       return "column label horizontal category border";
111     case PIVOT_BORDER_CAT_COL_VERT:
112       return "column label vertical category border";
113
114     case PIVOT_N_BORDERS:
115     default:
116       return "**error**";
117     }
118 }
119
120 void
121 pivot_table_sizing_uninit (struct pivot_table_sizing *sizing)
122 {
123   if (sizing)
124     {
125       free (sizing->widths);
126       free (sizing->breaks);
127       free (sizing->keeps);
128     }
129 }
130 \f
131 /* Axes. */
132
133 /* Returns the name of AXIS_TYPE. */
134 const char *
135 pivot_axis_type_to_string (enum pivot_axis_type axis_type)
136 {
137   switch (axis_type)
138     {
139     case PIVOT_AXIS_LAYER:
140       return "layer";
141
142     case PIVOT_AXIS_ROW:
143       return "row";
144
145     case PIVOT_AXIS_COLUMN:
146       return "column";
147
148     default:
149       return "<error>";
150     }
151 }
152
153 static enum pivot_axis_type
154 pivot_axis_type_transpose (enum pivot_axis_type axis_type)
155 {
156   assert (axis_type == PIVOT_AXIS_ROW || axis_type == PIVOT_AXIS_COLUMN);
157   return (axis_type == PIVOT_AXIS_ROW ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW);
158 }
159
160 /* Implementation of PIVOT_AXIS_FOR_EACH. */
161 size_t *
162 pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis)
163 {
164   if (!indexes)
165     {
166       if (axis->n_dimensions)
167         for (size_t i = 0; i < axis->n_dimensions; i++)
168           if (axis->dimensions[i]->n_leaves == 0)
169             return NULL;
170
171       return xcalloc (axis->n_dimensions, sizeof *indexes);
172     }
173
174   for (size_t i = 0; i < axis->n_dimensions; i++)
175     {
176       const struct pivot_dimension *d = axis->dimensions[i];
177       if (++indexes[i] < d->n_leaves)
178         return indexes;
179
180       indexes[i] = 0;
181     }
182
183   free (indexes);
184   return NULL;
185 }
186 \f
187 /* Dimensions. */
188
189 static void
190 pivot_category_set_rc (struct pivot_category *category, const char *s)
191 {
192   const struct fmt_spec *format = pivot_table_get_format (
193     category->dimension->table, s);
194   if (format)
195     category->format = *format;
196 }
197
198 static void
199 pivot_category_create_leaves_valist (struct pivot_category *parent,
200                                      va_list args)
201 {
202   const char *s;
203   while ((s = va_arg (args, const char *)))
204     {
205       if (!strncmp (s, "RC_", 3))
206         {
207           assert (parent->n_subs);
208           pivot_category_set_rc (parent->subs[parent->n_subs - 1], s);
209         }
210       else
211         pivot_category_create_leaf (parent, pivot_value_new_text (s));
212     }
213 }
214
215 /* Creates a new dimension with the given NAME in TABLE and returns it.  The
216    dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
217    that axis.
218
219    NAME should be a translatable name, but not actually translated yet,
220    e.g. enclosed in N_().  To use a different kind of value for a name, use
221    pivot_dimension_create__() instead.
222
223    The optional varargs parameters may be used to add an initial set of
224    categories to the dimension.  Each string should be a translatable category
225    name, but not actually translated yet, e.g. enclosed in N_().  Each string
226    may optionally be followod by a PIVOT_RC_* string that specifies the default
227    numeric format for cells in this category. */
228 struct pivot_dimension * SENTINEL (0)
229 (pivot_dimension_create) (struct pivot_table *table,
230                           enum pivot_axis_type axis_type,
231                           const char *name, ...)
232 {
233   struct pivot_dimension *d = pivot_dimension_create__ (
234     table, axis_type, pivot_value_new_text (name));
235
236   va_list args;
237   va_start (args, name);
238   pivot_category_create_leaves_valist (d->root, args);
239   va_end (args);
240
241   return d;
242 }
243
244 /* Creates a new dimension with the given NAME in TABLE and returns it.  The
245    dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
246    that axis. */
247 struct pivot_dimension *
248 pivot_dimension_create__ (struct pivot_table *table,
249                           enum pivot_axis_type axis_type,
250                           struct pivot_value *name)
251 {
252   assert (pivot_table_is_empty (table));
253
254   struct pivot_dimension *d = xmalloc (sizeof *d);
255   *d = (struct pivot_dimension) {
256     .table = table,
257     .axis_type = axis_type,
258     .level = table->axes[axis_type].n_dimensions,
259     .top_index = table->n_dimensions,
260     .root = xmalloc (sizeof *d->root),
261   };
262
263   struct pivot_category *root = d->root;
264   *root = (struct pivot_category) {
265     .name = name,
266     .parent = NULL,
267     .dimension = d,
268     .show_label = false,
269     .data_index = SIZE_MAX,
270     .presentation_index = SIZE_MAX,
271   };
272
273   table->dimensions = xrealloc (
274     table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions);
275   table->dimensions[table->n_dimensions++] = d;
276
277   struct pivot_axis *axis = &table->axes[axis_type];
278   axis->dimensions = xrealloc (
279     axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
280   axis->dimensions[axis->n_dimensions++] = d;
281
282   if (axis_type == PIVOT_AXIS_LAYER)
283     {
284       free (table->current_layer);
285       table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
286                                       sizeof *table->current_layer);
287     }
288
289   /* XXX extent and label_depth need to be calculated later. */
290
291   return d;
292 }
293
294 void
295 pivot_dimension_destroy (struct pivot_dimension *d)
296 {
297   if (!d)
298     return;
299
300   pivot_category_destroy (d->root);
301   free (d->data_leaves);
302   free (d->presentation_leaves);
303   free (d);
304 }
305
306 /* Returns the first leaf node in an in-order traversal that is a child of
307    CAT. */
308 static const struct pivot_category * UNUSED
309 pivot_category_first_leaf (const struct pivot_category *cat)
310 {
311   if (pivot_category_is_leaf (cat))
312     return cat;
313
314   for (size_t i = 0; i < cat->n_subs; i++)
315     {
316       const struct pivot_category *first
317         = pivot_category_first_leaf (cat->subs[i]);
318       if (first)
319         return first;
320     }
321
322   return NULL;
323 }
324
325 /* Returns the next leaf node in an in-order traversal starting at CAT, which
326    must be a leaf. */
327 static const struct pivot_category * UNUSED
328 pivot_category_next_leaf (const struct pivot_category *cat)
329 {
330   assert (pivot_category_is_leaf (cat));
331
332   for (;;)
333     {
334       const struct pivot_category *parent = cat->parent;
335       if (!parent)
336         return NULL;
337       for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
338         {
339           const struct pivot_category *next
340             = pivot_category_first_leaf (parent->subs[i]);
341           if (next)
342             return next;
343         }
344
345       cat = cat->parent;
346     }
347 }
348
349 static void
350 pivot_category_add_child (struct pivot_category *child)
351 {
352   struct pivot_category *parent = child->parent;
353
354   assert (pivot_category_is_group (parent));
355   if (parent->n_subs >= parent->allocated_subs)
356     parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
357                                sizeof *parent->subs);
358   parent->subs[parent->n_subs++] = child;
359 }
360
361 /* Adds leaf categories as a child of PARENT.  To create top-level categories
362    within dimension 'd', pass 'd->root' for PARENT.
363
364    Each of the varargs parameters should be a string, each of which should be a
365    translatable category name, but not actually translated yet, e.g. enclosed
366    in N_().  Each string may optionally be followod by a PIVOT_RC_* string that
367    specifies the default numeric format for cells in this category.
368
369    Returns the category index, which is just a 0-based array index, for the
370    first new category.
371
372    Leaves have to be created in in-order, that is, don't create a group and add
373    some leaves, then add leaves outside the group and try to add more leaves
374    inside it. */
375 int SENTINEL (0)
376 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
377 {
378   int retval = parent->dimension->n_leaves;
379
380   va_list args;
381   va_start (args, parent);
382   pivot_category_create_leaves_valist (parent, args);
383   va_end (args);
384
385   return retval;
386 }
387
388 /* Creates a new leaf category with the given NAME as a child of PARENT.  To
389    create a top-level category within dimension 'd', pass 'd->root' for PARENT.
390    Returns the category index, which is just a 0-based array index, for the new
391    category.
392
393    Leaves have to be created in in-order, that is, don't create a group and add
394    some leaves, then add leaves outside the group and try to add more leaves
395    inside it. */
396 int
397 pivot_category_create_leaf (struct pivot_category *parent,
398                             struct pivot_value *name)
399 {
400   return pivot_category_create_leaf_rc (parent, name, NULL);
401 }
402
403 /* Creates a new leaf category with the given NAME as a child of PARENT.  To
404    create a top-level category within dimension 'd', pass 'd->root' for PARENT.
405    Returns the category index, which is just a 0-based array index, for the new
406    category.
407
408    If RC is nonnull and the name of a result category, the category is assigned
409    that result category.
410
411    Leaves have to be created in in-order, that is, don't create a group and add
412    some leaves, then add leaves outside the group and try to add more leaves
413    inside it. */
414 int
415 pivot_category_create_leaf_rc (struct pivot_category *parent,
416                                struct pivot_value *name, const char *rc)
417 {
418   struct pivot_dimension *d = parent->dimension;
419
420   struct pivot_category *leaf = xmalloc (sizeof *leaf);
421   *leaf = (struct pivot_category) {
422     .name = name,
423     .parent = parent,
424     .dimension = d,
425     .group_index = parent->n_subs,
426     .data_index = d->n_leaves,
427     .presentation_index = d->n_leaves,
428   };
429
430   if (d->n_leaves >= d->allocated_leaves)
431     {
432       d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
433                                    sizeof *d->data_leaves);
434       d->presentation_leaves = xrealloc (
435         d->presentation_leaves,
436         d->allocated_leaves * sizeof *d->presentation_leaves);
437     }
438
439   d->data_leaves[d->n_leaves] = leaf;
440   d->presentation_leaves[d->n_leaves] = leaf;
441   d->n_leaves++;
442
443   pivot_category_add_child (leaf);
444
445   /* Make sure that the new child is the last in in-order. */
446   assert (!pivot_category_next_leaf (leaf));
447
448   pivot_category_set_rc (leaf, rc);
449
450   return leaf->data_index;
451 }
452
453 /* Adds a new category group named NAME as a child of PARENT.  To create a
454    top-level group within dimension 'd', pass 'd->root' for PARENT.
455
456    NAME should be a translatable name, but not actually translated yet,
457    e.g. enclosed in N_().  To use a different kind of value for a name, use
458    pivot_category_create_group__() instead.
459
460    The optional varargs parameters may be used to add an initial set of
461    categories to the group.  Each string should be a translatable category
462    name, but not actually translated yet, e.g. enclosed in N_().  Each string
463    may optionally be followod by a PIVOT_RC_* string that specifies the default
464    numeric format for cells in this category.
465
466    Returns the new group. */
467 struct pivot_category * SENTINEL (0)
468 (pivot_category_create_group) (struct pivot_category *parent,
469                                const char *name, ...)
470 {
471   struct pivot_category *group = pivot_category_create_group__ (
472     parent, pivot_value_new_text (name));
473
474   va_list args;
475   va_start (args, name);
476   pivot_category_create_leaves_valist (group, args);
477   va_end (args);
478
479   return group;
480 }
481
482 /* Adds a new category group named NAME as a child of PARENT.  To create a
483    top-level group within dimension 'd', pass 'd->root' for PARENT.  Returns
484    the new group. */
485 struct pivot_category *
486 pivot_category_create_group__ (struct pivot_category *parent,
487                                struct pivot_value *name)
488 {
489   struct pivot_dimension *d = parent->dimension;
490
491   struct pivot_category *group = xmalloc (sizeof *group);
492   *group = (struct pivot_category) {
493     .name = name,
494     .parent = parent,
495     .dimension = d,
496     .show_label = true,
497     .group_index = parent->n_subs,
498     .data_index = SIZE_MAX,
499     .presentation_index = SIZE_MAX,
500   };
501
502   pivot_category_add_child (group);
503
504   return group;
505 }
506
507 void
508 pivot_category_destroy (struct pivot_category *c)
509 {
510   if (!c)
511     return;
512
513   pivot_value_destroy (c->name);
514   for (size_t i = 0; i < c->n_subs; i++)
515     pivot_category_destroy (c->subs[i]);
516   free (c->subs);
517   free (c);
518 }
519 \f
520 /* Result classes.
521
522    These are usually the easiest way to control the formatting of numeric data
523    in a pivot table.  See pivot_dimension_create() for an explanation of their
524    use.  */
525 struct result_class
526   {
527     const char *name;           /* "RC_*". */
528     struct fmt_spec format;
529   };
530
531 /* Formats for most of the result classes. */
532 static struct result_class result_classes[] =
533   {
534     { PIVOT_RC_INTEGER,      { FMT_F,   40, 0 } },
535     { PIVOT_RC_PERCENT,      { FMT_PCT, 40, 1 } },
536     { PIVOT_RC_CORRELATION,  { FMT_F,   40, 3 } },
537     { PIVOT_RC_SIGNIFICANCE, { FMT_F,   40, 3 } },
538     { PIVOT_RC_RESIDUAL,     { FMT_F,   40, 2 } },
539     { PIVOT_RC_COUNT,        { 0, 0, 0 } },
540     { PIVOT_RC_OTHER,        { 0, 0, 0 } },
541   };
542
543 /* Has PIVOT_RC_COUNT been overridden by the user? */
544 static bool overridden_count_format;
545
546 static struct result_class *
547 pivot_result_class_find (const char *s)
548 {
549   for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
550     if (!strcmp (s, result_classes[i].name))
551       return &result_classes[i];
552   return NULL;
553 }
554
555 static const struct fmt_spec *
556 pivot_table_get_format (const struct pivot_table *table, const char *s)
557 {
558   if (!s)
559     return NULL;
560   else if (!strcmp (s, PIVOT_RC_OTHER))
561     return settings_get_format ();
562   else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
563     return &table->weight_format;
564   else
565     {
566       const struct result_class *rc = pivot_result_class_find (s);
567       return rc ? &rc->format : NULL;
568     }
569 }
570
571 /* Sets the format specification for the result class named S (which should not
572    include the RC_ prefix) to *FORMAT.  Returns true if successful, false if S
573    does not name a known result class. */
574 bool
575 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
576 {
577   char *s = xasprintf ("RC_%s", s_);
578   struct result_class *rc = pivot_result_class_find (s);
579   if (rc)
580     {
581       rc->format = *format;
582       if (!strcmp (s, PIVOT_RC_COUNT))
583         overridden_count_format = true;
584     }
585   free (s);
586
587   return rc != NULL;
588 }
589 \f
590 /* One piece of data within a pivot table. */
591 struct pivot_cell
592   {
593     struct hmap_node hmap_node; /* In struct pivot_table's 'cells' hmap. */
594     struct pivot_value *value;
595     unsigned int idx[];         /* One index per table dimension. */
596   };
597
598 /* Pivot tables. */
599
600 /* Creates and returns a new pivot table with the given TITLE.  TITLE should be
601    a text string marked for translation but not actually translated yet,
602    e.g. N_("Descriptive Statistics").
603
604    Operations commonly performed on the new pivot_table:
605
606    - If empty rows or columns should not be displayed, set ->omit_empty to
607      true.
608
609    - Set the format to use for "count" values with pivot_table_set_weight_var()
610      or pivot_table_set_weight_format().
611
612    This function is a shortcut for pivot_table_create__() for the most common
613    case.  Use pivot_table_create__() directly if the title should be some kind
614    of value other than an ordinary text string.
615
616    See the large comment at the top of pivot-table.h for general advice on
617    creating pivot tables. */
618 struct pivot_table *
619 pivot_table_create (const char *title)
620 {
621   return pivot_table_create__ (pivot_value_new_text (title));
622 }
623
624 /* Creates and returns a new pivot table with the given TITLE, and takes
625    ownership of TITLE.
626
627    Operations commonly performed on the new pivot_table:
628
629    - If empty rows or columns should not be displayed, set ->omit_empty to
630      true.
631
632    - Set the format to use for "count" values with pivot_table_set_weight_var()
633      or pivot_table_set_weight_format().
634
635    See the large comment at the top of pivot-table.h for general advice on
636    creating pivot tables. */
637 struct pivot_table *
638 pivot_table_create__ (struct pivot_value *title)
639 {
640   struct pivot_table *table = xzalloc (sizeof *table);
641   table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
642   table->title = title;
643
644   /* Set default area styles. */
645 #define STYLE(BOLD, H, V, L, R, T, B) {                         \
646     .cell_style = {                                             \
647       .halign = TABLE_HALIGN_##H,                               \
648       .valign = TABLE_VALIGN_##V,                               \
649       .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R,     \
650                   [TABLE_VERT][0] = T, [TABLE_VERT][1] = B },   \
651     },                                                          \
652       .font_style = {                                           \
653       .bold = BOLD,                                             \
654       .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK},  \
655       .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE},  \
656     },                                                          \
657          }
658   static const struct area_style default_area_styles[PIVOT_N_AREAS] = {
659     [PIVOT_AREA_TITLE]         = STYLE( true, CENTER, CENTER,  8,11,1,8),
660     [PIVOT_AREA_CAPTION]       = STYLE(false, LEFT,   TOP,     8,11,1,1),
661     [PIVOT_AREA_FOOTER]        = STYLE(false, LEFT,   TOP,    11, 8,2,3),
662     [PIVOT_AREA_CORNER]        = STYLE(false, LEFT,   BOTTOM,  8,11,1,1),
663     [PIVOT_AREA_COLUMN_LABELS] = STYLE(false, CENTER, BOTTOM,  8,11,1,3),
664     [PIVOT_AREA_ROW_LABELS]    = STYLE(false, LEFT,   TOP,     8,11,1,3),
665     [PIVOT_AREA_DATA]          = STYLE(false, MIXED,  TOP,     8,11,1,1),
666     [PIVOT_AREA_LAYERS]        = STYLE(false, LEFT,   BOTTOM,  8,11,1,3),
667     };
668 #undef STYLE
669   for (size_t i = 0; i < PIVOT_N_AREAS; i++)
670     table->areas[i] = default_area_styles[i];
671
672   /* Set default border styles. */
673   static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
674     [PIVOT_BORDER_TITLE]        = TABLE_STROKE_NONE,
675     [PIVOT_BORDER_OUTER_LEFT]   = TABLE_STROKE_NONE,
676     [PIVOT_BORDER_OUTER_TOP]    = TABLE_STROKE_NONE,
677     [PIVOT_BORDER_OUTER_RIGHT]  = TABLE_STROKE_NONE,
678     [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
679     [PIVOT_BORDER_INNER_LEFT]   = TABLE_STROKE_THICK,
680     [PIVOT_BORDER_INNER_TOP]    = TABLE_STROKE_THICK,
681     [PIVOT_BORDER_INNER_RIGHT]  = TABLE_STROKE_THICK,
682     [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
683     [PIVOT_BORDER_DATA_LEFT]    = TABLE_STROKE_THICK,
684     [PIVOT_BORDER_DATA_TOP]     = TABLE_STROKE_THICK,
685     [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
686     [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
687     [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
688     [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
689     [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
690     [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
691     [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
692     [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
693   };
694   for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
695     table->borders[i] = (struct table_border_style) {
696       .stroke = default_strokes[i],
697       .color = CELL_COLOR_BLACK,
698     };
699
700   table->row_labels_in_corner = true;
701   hmap_init (&table->cells);
702
703   return table;
704 }
705
706 /* Creates and returns a new pivot table with the given TITLE and a single cell
707    with the given CONTENT.
708
709    This is really just for error handling. */
710 struct pivot_table *
711 pivot_table_create_for_text (struct pivot_value *title,
712                              struct pivot_value *content)
713 {
714   struct pivot_table *table = pivot_table_create__ (title);
715
716   struct pivot_dimension *d = pivot_dimension_create (
717     table, PIVOT_AXIS_ROW, N_("Error"));
718   d->hide_all_labels = true;
719   pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
720
721   pivot_table_put1 (table, 0, content);
722
723   return table;
724 }
725
726 /* Destroys TABLE and frees everything it points to. */
727 void
728 pivot_table_destroy (struct pivot_table *table)
729 {
730   if (!table)
731     return;
732
733   free (table->current_layer);
734   free (table->table_look);
735
736   for (int i = 0; i < TABLE_N_AXES; i++)
737     pivot_table_sizing_uninit (&table->sizing[i]);
738
739   free (table->continuation);
740
741   for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
742     free (table->ccs[i]);
743
744   free (table->command_local);
745   free (table->command_c);
746   free (table->language);
747   free (table->locale);
748
749   free (table->dataset);
750   free (table->datafile);
751
752   for (size_t i = 0; i < table->n_footnotes; i++)
753     pivot_footnote_destroy (table->footnotes[i]);
754   free (table->footnotes);
755
756   pivot_value_destroy (table->title);
757   pivot_value_destroy (table->subtype);
758   pivot_value_destroy (table->corner_text);
759   pivot_value_destroy (table->caption);
760
761   for (size_t i = 0; i < PIVOT_N_AREAS; i++)
762     area_style_uninit (&table->areas[i]);
763
764   for (size_t i = 0; i < table->n_dimensions; i++)
765     pivot_dimension_destroy (table->dimensions[i]);
766   free (table->dimensions);
767
768   for (size_t i = 0; i < PIVOT_N_AXES; i++)
769     free (table->axes[i].dimensions);
770
771   struct pivot_cell *cell, *next_cell;
772   HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
773                       &table->cells)
774     {
775       hmap_delete (&table->cells, &cell->hmap_node);
776       pivot_value_destroy (cell->value);
777       free (cell);
778     }
779   hmap_destroy (&table->cells);
780
781   free (table);
782 }
783
784 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
785    WV, which should be the weight variable for the dictionary whose data or
786    statistics are being put into TABLE.
787
788    This has no effect if WV is NULL. */
789 void
790 pivot_table_set_weight_var (struct pivot_table *table,
791                             const struct variable *wv)
792 {
793   if (wv)
794     pivot_table_set_weight_format (table, var_get_print_format (wv));
795 }
796
797 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
798    format for the dictionary whose data or statistics are being put into TABLE.
799
800    This has no effect if WFMT is NULL. */
801 void
802 pivot_table_set_weight_format (struct pivot_table *table,
803                                const struct fmt_spec *wfmt)
804 {
805   if (wfmt)
806     table->weight_format = *wfmt;
807 }
808
809 /* Returns true if TABLE has no cells, false otherwise. */
810 bool
811 pivot_table_is_empty (const struct pivot_table *table)
812 {
813   return hmap_is_empty (&table->cells);
814 }
815
816 static unsigned int
817 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
818 {
819   return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
820 }
821
822 static bool
823 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
824 {
825   for (size_t i = 0; i < n; i++)
826     if (a[i] != b[i])
827       return false;
828
829   return true;
830 }
831
832 static struct pivot_cell *
833 pivot_table_lookup_cell__ (const struct pivot_table *table,
834                             const size_t *dindexes, unsigned int hash)
835 {
836   struct pivot_cell *cell;
837   HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
838                            &table->cells)
839     if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
840       return cell;
841   return false;
842 }
843
844 static struct pivot_cell *
845 pivot_cell_allocate (size_t n_idx)
846 {
847   struct pivot_cell *cell UNUSED;
848   return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
849 }
850
851 static struct pivot_cell *
852 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
853 {
854   unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
855   struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
856   if (!cell)
857     {
858       cell = pivot_cell_allocate (table->n_dimensions);
859       for (size_t i = 0; i < table->n_dimensions; i++)
860         cell->idx[i] = dindexes[i];
861       cell->value = NULL;
862       hmap_insert (&table->cells, &cell->hmap_node, hash);
863     }
864   return cell;
865 }
866
867 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
868    DINDEXES.  N must be the number of dimensions in TABLE.  Takes ownership of
869    VALUE.
870
871    If VALUE is a numeric value without a specified format, this function checks
872    each of the categories designated by DINDEXES[] and takes the format from
873    the first category with a result class.  If none has a result class, uses
874    the overall default numeric format. */
875 void
876 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
877                  struct pivot_value *value)
878 {
879   assert (n == table->n_dimensions);
880
881   if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
882     {
883       for (size_t i = 0; i < table->n_dimensions; i++)
884         {
885           const struct pivot_dimension *d = table->dimensions[i];
886           if (dindexes[i] < d->n_leaves)
887             {
888               const struct pivot_category *c = d->data_leaves[dindexes[i]];
889               if (c->format.w)
890                 {
891                   value->numeric.format = c->format;
892                   goto done;
893                 }
894             }
895         }
896       value->numeric.format = *settings_get_format ();
897
898     done:;
899     }
900
901   struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
902   pivot_value_destroy (cell->value);
903   cell->value = value;
904 }
905
906 /* Puts VALUE in the cell in TABLE with index IDX1.  TABLE must have 1
907    dimension.  Takes ownership of VALUE.  */
908 void
909 pivot_table_put1 (struct pivot_table *table, size_t idx1,
910                   struct pivot_value *value)
911 {
912   size_t dindexes[] = { idx1 };
913   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
914 }
915
916 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2).  TABLE must have 2
917    dimensions.  Takes ownership of VALUE.  */
918 void
919 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
920                   struct pivot_value *value)
921 {
922   size_t dindexes[] = { idx1, idx2 };
923   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
924 }
925
926 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3).  TABLE must
927    have 3 dimensions.  Takes ownership of VALUE.  */
928 void
929 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
930                   size_t idx3, struct pivot_value *value)
931 {
932   size_t dindexes[] = { idx1, idx2, idx3 };
933   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
934 }
935
936 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4).  TABLE
937    must have 4 dimensions.  Takes ownership of VALUE.  */
938 void
939 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
940                   size_t idx3, size_t idx4, struct pivot_value *value)
941 {
942   size_t dindexes[] = { idx1, idx2, idx3, idx4 };
943   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
944 }
945
946 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
947    automatically assigned marker.
948
949    The footnote will only appear in output if it is referenced.  Use
950    pivot_value_add_footnote() to add a reference to the footnote. */
951 struct pivot_footnote *
952 pivot_table_create_footnote (struct pivot_table *table,
953                              struct pivot_value *content)
954 {
955   return pivot_table_create_footnote__ (table, table->n_footnotes,
956                                         NULL, content);
957 }
958
959 static struct pivot_value *
960 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
961 {
962   char text[INT_BUFSIZE_BOUND (size_t)];
963   if (show_numeric_markers)
964     snprintf (text, sizeof text, "%d", idx + 1);
965   else
966     str_format_26adic (idx + 1, false, text, sizeof text);
967   return pivot_value_new_user_text (text, -1);
968 }
969
970 /* Creates or modifies a footnote in TABLE with 0-based number IDX.  If MARKER
971    is nonnull, sets the footnote's marker; if CONTENT is nonnull, sets the
972    footnote's content. */
973 struct pivot_footnote *
974 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
975                                struct pivot_value *marker,
976                                struct pivot_value *content)
977 {
978   if (idx >= table->n_footnotes)
979     {
980       while (idx >= table->allocated_footnotes)
981         table->footnotes = x2nrealloc (table->footnotes,
982                                        &table->allocated_footnotes,
983                                        sizeof *table->footnotes);
984       while (idx >= table->n_footnotes)
985         {
986           struct pivot_footnote *f = xmalloc (sizeof *f);
987           f->idx = table->n_footnotes;
988           f->marker = pivot_make_default_footnote_marker (
989             f->idx, table->show_numeric_markers);
990           f->content = NULL;
991
992           table->footnotes[table->n_footnotes++] = f;
993         }
994     }
995
996   struct pivot_footnote *f = table->footnotes[idx];
997   if (marker)
998     {
999       pivot_value_destroy (f->marker);
1000       f->marker = marker;
1001     }
1002   if (content)
1003     {
1004       pivot_value_destroy (f->content);
1005       f->content = content;
1006     }
1007   return f;
1008 }
1009
1010 /* Frees the data owned by F. */
1011 void
1012 pivot_footnote_destroy (struct pivot_footnote *f)
1013 {
1014   if (f)
1015     {
1016       pivot_value_destroy (f->content);
1017       pivot_value_destroy (f->marker);
1018       free (f);
1019     }
1020 }
1021
1022 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1023    indexes for each dimension in TABLE in DINDEXES[]. */
1024 void
1025 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1026                                   const size_t *pindexes[PIVOT_N_AXES],
1027                                   size_t dindexes[/* table->n_dimensions */])
1028 {
1029   for (size_t i = 0; i < PIVOT_N_AXES; i++)
1030     {
1031       const struct pivot_axis *axis = &table->axes[i];
1032
1033       for (size_t j = 0; j < axis->n_dimensions; j++)
1034         {
1035           const struct pivot_dimension *d = axis->dimensions[j];
1036           dindexes[d->top_index]
1037             = d->presentation_leaves[pindexes[i][j]]->data_index;
1038         }
1039     }
1040 }
1041
1042 size_t *
1043 pivot_table_enumerate_axis (const struct pivot_table *table,
1044                             enum pivot_axis_type axis_type,
1045                             const size_t *layer_indexes, bool omit_empty,
1046                             size_t *n)
1047 {
1048   const struct pivot_axis *axis = &table->axes[axis_type];
1049   if (!axis->n_dimensions)
1050     {
1051       size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1052       enumeration[0] = 0;
1053       enumeration[1] = SIZE_MAX;
1054       if (n)
1055         *n = 1;
1056       return enumeration;
1057     }
1058   else if (!axis->extent)
1059     {
1060       size_t *enumeration = xmalloc (sizeof *enumeration);
1061       *enumeration = SIZE_MAX;
1062       if (n)
1063         *n = 0;
1064       return enumeration;
1065     }
1066
1067   size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1068                                                 axis->n_dimensions), 1),
1069                                   sizeof *enumeration);
1070   size_t *p = enumeration;
1071   size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1072
1073   size_t *axis_indexes;
1074   PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1075     {
1076       if (omit_empty)
1077         {
1078           enum pivot_axis_type axis2_type
1079             = pivot_axis_type_transpose (axis_type);
1080
1081           size_t *axis2_indexes;
1082           PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1083             {
1084               const size_t *pindexes[PIVOT_N_AXES];
1085               pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1086               pindexes[axis_type] = axis_indexes;
1087               pindexes[axis2_type] = axis2_indexes;
1088               pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1089               if (pivot_table_get (table, dindexes))
1090                 goto found;
1091             }
1092           continue;
1093
1094         found:
1095           free (axis2_indexes);
1096         }
1097
1098       memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1099       p += axis->n_dimensions;
1100     }
1101   *p = SIZE_MAX;
1102   if (n)
1103     *n = (p - enumeration) / axis->n_dimensions;
1104
1105   free (dindexes);
1106   return enumeration;
1107 }
1108
1109 static const struct pivot_cell *
1110 pivot_table_lookup_cell (const struct pivot_table *table,
1111                           const size_t *dindexes)
1112 {
1113   unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1114   return pivot_table_lookup_cell__ (table, dindexes, hash);
1115 }
1116
1117 const struct pivot_value *
1118 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1119 {
1120   const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1121   return cell ? cell->value : NULL;
1122 }
1123
1124 struct pivot_value *
1125 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1126 {
1127   struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1128   if (!cell->value)
1129     cell->value = pivot_value_new_user_text ("", -1);
1130   return cell->value;
1131 }
1132
1133 static void
1134 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1135 {
1136   if (pivot_category_is_group (category) && category->n_subs)
1137     for (size_t i = 0; i < category->n_subs; i++)
1138       distribute_extra_depth (category->subs[i], extra_depth);
1139   else
1140     category->extra_depth += extra_depth;
1141 }
1142
1143 static void
1144 pivot_category_assign_label_depth (struct pivot_category *category,
1145                                    bool dimension_labels_in_corner)
1146 {
1147   category->extra_depth = 0;
1148
1149   if (pivot_category_is_group (category))
1150     {
1151       size_t depth = 0;
1152       for (size_t i = 0; i < category->n_subs; i++)
1153         {
1154           pivot_category_assign_label_depth (category->subs[i], false);
1155           depth = MAX (depth, category->subs[i]->label_depth);
1156         }
1157
1158       for (size_t i = 0; i < category->n_subs; i++)
1159         {
1160           struct pivot_category *sub = category->subs[i];
1161
1162           size_t extra_depth = depth - sub->label_depth;
1163           if (extra_depth)
1164             distribute_extra_depth (sub, extra_depth);
1165
1166           sub->label_depth = depth;
1167         }
1168
1169       category->show_label_in_corner = (category->show_label
1170                                         && dimension_labels_in_corner);
1171       category->label_depth
1172         = (category->show_label && !category->show_label_in_corner
1173            ? depth + 1 : depth);
1174     }
1175   else
1176     category->label_depth = 1;
1177 }
1178
1179 static bool
1180 pivot_axis_assign_label_depth (struct pivot_table *table,
1181                              enum pivot_axis_type axis_type,
1182                              bool dimension_labels_in_corner)
1183 {
1184   struct pivot_axis *axis = &table->axes[axis_type];
1185   bool any_label_shown_in_corner = false;
1186   axis->label_depth = 0;
1187   axis->extent = 1;
1188   for (size_t i = 0; i < axis->n_dimensions; i++)
1189     {
1190       struct pivot_dimension *d = axis->dimensions[i];
1191       pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1192       d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1193       axis->label_depth += d->label_depth;
1194       axis->extent *= d->n_leaves;
1195
1196       if (d->root->show_label_in_corner)
1197         any_label_shown_in_corner = true;
1198     }
1199   return any_label_shown_in_corner;
1200 }
1201
1202 void
1203 pivot_table_assign_label_depth (struct pivot_table *table)
1204 {
1205   pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1206   if (pivot_axis_assign_label_depth (
1207         table, PIVOT_AXIS_ROW, (table->row_labels_in_corner
1208                                 && !table->corner_text))
1209       && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1210     table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1211   pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1212 }
1213 \f
1214 /* Footnotes. */
1215
1216 \f
1217 \f
1218 static void
1219 indent (int indentation)
1220 {
1221   for (int i = 0; i < indentation * 2; i++)
1222     putchar (' ');
1223 }
1224
1225 static void
1226 pivot_value_dump (const struct pivot_value *value)
1227 {
1228   char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1229                                    SETTINGS_VALUE_SHOW_DEFAULT);
1230   fputs (s, stdout);
1231   free (s);
1232 }
1233
1234 static void
1235 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1236                       int indentation)
1237 {
1238   if (value)
1239     {
1240       indent (indentation);
1241       printf ("%s: ", name);
1242       pivot_value_dump (value);
1243       putchar ('\n');
1244     }
1245 }
1246
1247 static void
1248 pivot_table_dump_string (const char *string, const char *name, int indentation)
1249 {
1250   if (string)
1251     {
1252       indent (indentation);
1253       printf ("%s: %s\n", name, string);
1254     }
1255 }
1256
1257 static void
1258 pivot_category_dump (const struct pivot_category *c, int indentation)
1259 {
1260   indent (indentation);
1261   printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1262   pivot_value_dump (c->name);
1263   printf ("\" ");
1264
1265   if (pivot_category_is_leaf (c))
1266     printf ("data_index=%zu\n", c->data_index);
1267   else
1268     {
1269       printf (" (label %s)", c->show_label ? "shown" : "hidden");
1270       printf ("\n");
1271
1272       for (size_t i = 0; i < c->n_subs; i++)
1273         pivot_category_dump (c->subs[i], indentation + 1);
1274     }
1275 }
1276
1277 void
1278 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1279 {
1280   indent (indentation);
1281   printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1282           pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1283
1284   pivot_category_dump (d->root, indentation + 1);
1285 }
1286
1287 static void
1288 area_style_dump (enum pivot_area area, const struct area_style *a,
1289                  int indentation)
1290 {
1291   indent (indentation);
1292   printf ("%s: ", pivot_area_to_string (area));
1293   font_style_dump (&a->font_style);
1294   putchar (' ');
1295   cell_style_dump (&a->cell_style);
1296   putchar ('\n');
1297 }
1298
1299 static void
1300 table_border_style_dump (enum pivot_border border,
1301                          const struct table_border_style *b, int indentation)
1302 {
1303   indent (indentation);
1304   printf ("%s: %s ", pivot_border_to_string (border),
1305           table_stroke_to_string (b->stroke));
1306   cell_color_dump (&b->color);
1307   putchar ('\n');
1308 }
1309
1310 static char ***
1311 compose_headings (const struct pivot_axis *axis,
1312                   const size_t *column_enumeration,
1313                   enum settings_value_show show_values,
1314                   enum settings_value_show show_variables)
1315 {
1316   if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1317     return NULL;
1318
1319   char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1320   for (size_t i = 0; i < axis->label_depth; i++)
1321     headings[i] = xcalloc (axis->extent, sizeof **headings);
1322
1323   const size_t *indexes;
1324   size_t column = 0;
1325   PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1326     {
1327       int row = axis->label_depth - 1;
1328       for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1329         {
1330           const struct pivot_dimension *d = axis->dimensions[dim_index];
1331           if (d->hide_all_labels)
1332             continue;
1333           for (const struct pivot_category *c
1334                  = d->presentation_leaves[indexes[dim_index]];
1335                c;
1336                c = c->parent)
1337             {
1338               if (pivot_category_is_leaf (c) || (c->show_label
1339                                                  && !c->show_label_in_corner))
1340                 {
1341                   headings[row][column] = pivot_value_to_string (
1342                     c->name, show_values, show_variables);
1343                   if (!*headings[row][column])
1344                     headings[row][column] = xstrdup ("<blank>");
1345                   row--;
1346                 }
1347             }
1348         }
1349       column++;
1350     }
1351
1352   return headings;
1353 }
1354
1355 void
1356 pivot_table_dump (const struct pivot_table *table, int indentation)
1357 {
1358   if (!table)
1359     return;
1360
1361   int old_decimal = settings_get_decimal_char (FMT_COMMA);
1362   if (table->decimal == '.' || table->decimal == ',')
1363     settings_set_decimal_char (table->decimal);
1364
1365   pivot_table_dump_value (table->title, "title", indentation);
1366   pivot_table_dump_string (table->command_c, "command", indentation);
1367   pivot_table_dump_string (table->dataset, "dataset", indentation);
1368   pivot_table_dump_string (table->datafile, "datafile", indentation);
1369   pivot_table_dump_string (table->notes, "notes", indentation);
1370   pivot_table_dump_string (table->table_look, "table-look", indentation);
1371   if (table->date)
1372     {
1373       indent (indentation);
1374       printf ("date: %s", ctime (&table->date)); /* XXX thread unsafe */
1375     }
1376
1377   indent (indentation);
1378   printf ("areas:\n");
1379   for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1380     area_style_dump (area, &table->areas[area], indentation + 1);
1381
1382   indent (indentation);
1383   printf ("borders:\n");
1384   for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1385     table_border_style_dump (border, &table->borders[border], indentation + 1);
1386
1387   for (size_t i = 0; i < table->n_dimensions; i++)
1388     pivot_dimension_dump (table->dimensions[i], indentation);
1389
1390   /* Presentation and data indexes. */
1391   size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1392
1393   const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1394   if (layer_axis->n_dimensions)
1395     {
1396       indent (indentation);
1397       printf ("current layer:");
1398
1399       for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1400         {
1401           const struct pivot_dimension *d = layer_axis->dimensions[i];
1402           char *name = pivot_value_to_string (d->root->name,
1403                                               table->show_values,
1404                                               table->show_variables);
1405           char *value = pivot_value_to_string (
1406             d->data_leaves[table->current_layer[i]]->name,
1407             table->show_values, table->show_variables);
1408           printf (" %s=%s", name, value);
1409           free (value);
1410           free (name);
1411         }
1412
1413       putchar ('\n');
1414     }
1415
1416   size_t *layer_indexes;
1417   size_t layer_iteration = 0;
1418   PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1419     {
1420       indent (indentation);
1421       printf ("layer %zu:", layer_iteration++);
1422
1423       const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1424       for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1425         {
1426           const struct pivot_dimension *d = layer_axis->dimensions[i];
1427
1428           fputs (i == 0 ? " " : ", ", stdout);
1429           pivot_value_dump (d->root->name);
1430           fputs (" =", stdout);
1431
1432           struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1433                                                sizeof *names);
1434           size_t n_names = 0;
1435           for (const struct pivot_category *c
1436                  = d->presentation_leaves[layer_indexes[i]];
1437                c;
1438                c = c->parent)
1439             {
1440               if (pivot_category_is_leaf (c) || c->show_label)
1441                 names[n_names++] = c->name;
1442             }
1443
1444           for (size_t i = n_names; i-- > 0; )
1445             {
1446               putchar (' ');
1447               pivot_value_dump (names[i]);
1448             }
1449           free (names);
1450         }
1451       putchar ('\n');
1452
1453       size_t *column_enumeration = pivot_table_enumerate_axis (
1454         table, PIVOT_AXIS_COLUMN, layer_indexes, table->omit_empty, NULL);
1455       size_t *row_enumeration = pivot_table_enumerate_axis (
1456         table, PIVOT_AXIS_ROW, layer_indexes, table->omit_empty, NULL);
1457
1458       char ***column_headings = compose_headings (
1459         &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1460         table->show_values, table->show_variables);
1461       for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1462         {
1463           indent (indentation + 1);
1464           for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1465             {
1466               if (x)
1467                 fputs ("; ", stdout);
1468               if (column_headings[y][x])
1469                 fputs (column_headings[y][x], stdout);
1470             }
1471           putchar ('\n');
1472         }
1473
1474       indent (indentation + 1);
1475       printf ("-----------------------------------------------\n");
1476
1477       char ***row_headings = compose_headings (
1478         &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1479         table->show_values, table->show_variables);
1480
1481       size_t x = 0;
1482       const size_t *pindexes[PIVOT_N_AXES]
1483         = { [PIVOT_AXIS_LAYER] = layer_indexes };
1484       PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1485                                   &table->axes[PIVOT_AXIS_ROW])
1486         {
1487           indent (indentation + 1);
1488
1489           size_t i = 0;
1490           for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1491             {
1492               if (i++)
1493                 fputs ("; ", stdout);
1494               if (row_headings[y][x])
1495                 fputs (row_headings[y][x], stdout);
1496             }
1497
1498           printf (" | ");
1499
1500           i = 0;
1501           PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1502                                       column_enumeration,
1503                                       &table->axes[PIVOT_AXIS_COLUMN])
1504             {
1505               if (i++)
1506                 printf ("; ");
1507
1508               pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1509               const struct pivot_value *value = pivot_table_get (
1510                 table, dindexes);
1511               if (value)
1512                 pivot_value_dump (value);
1513             }
1514           printf ("\n");
1515
1516           x++;
1517         }
1518
1519       free (column_enumeration);
1520       free (row_enumeration);
1521     }
1522
1523   pivot_table_dump_value (table->caption, "caption", indentation);
1524
1525   for (size_t i = 0; i < table->n_footnotes; i++)
1526     {
1527       const struct pivot_footnote *f = table->footnotes[i];
1528       indent (indentation);
1529       putchar ('[');
1530       if (f->marker)
1531         pivot_value_dump (f->marker);
1532       else
1533         printf ("%zu", f->idx);
1534       putchar (']');
1535       pivot_value_dump (f->content);
1536       putchar ('\n');
1537     }
1538
1539   settings_set_decimal_char (old_decimal);
1540 }
1541 \f
1542 static const char *
1543 consume_int (const char *p, size_t *n)
1544 {
1545   *n = 0;
1546   while (c_isdigit (*p))
1547     *n = *n * 10 + (*p++ - '0');
1548   return p;
1549 }
1550
1551 static size_t
1552 pivot_format_inner_template (struct string *out, const char *template,
1553                              char escape,
1554                              struct pivot_value **values, size_t n_values,
1555                              enum settings_value_show show_values,
1556                              enum settings_value_show show_variables)
1557 {
1558   size_t args_consumed = 0;
1559   while (*template && *template != ':')
1560     {
1561       if (*template == '\\' && template[1])
1562         {
1563           ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1564           template += 2;
1565         }
1566       else if (*template == escape)
1567         {
1568           size_t index;
1569           template = consume_int (template + 1, &index);
1570           if (index >= 1 && index <= n_values)
1571             {
1572               pivot_value_format (values[index - 1], show_values,
1573                                   show_variables, out);
1574               args_consumed = MAX (args_consumed, index);
1575             }
1576         }
1577       else
1578         ds_put_byte (out, *template++);
1579     }
1580   return args_consumed;
1581 }
1582
1583 static const char *
1584 pivot_extract_inner_template (const char *template, const char **p)
1585 {
1586   *p = template;
1587
1588   for (;;)
1589     {
1590       if (*template == '\\' && template[1] != '\0')
1591         template += 2;
1592       else if (*template == ':')
1593         return template + 1;
1594       else if (*template == '\0')
1595         return template;
1596       else
1597         template++;
1598     }
1599 }
1600
1601 static void
1602 pivot_format_template (struct string *out, const char *template,
1603                        const struct pivot_argument *args, size_t n_args,
1604                        enum settings_value_show show_values,
1605                        enum settings_value_show show_variables)
1606 {
1607   while (*template)
1608     {
1609       if (*template == '\\' && template[1] != '\0')
1610         {
1611           ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1612           template += 2;
1613         }
1614       else if (*template == '^')
1615         {
1616           size_t index;
1617           template = consume_int (template + 1, &index);
1618           if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1619             pivot_value_format (args[index - 1].values[0],
1620                                 show_values, show_variables, out);
1621         }
1622       else if (*template == '[')
1623         {
1624           const char *tmpl[2];
1625           template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1626           template = pivot_extract_inner_template (template, &tmpl[1]);
1627           template += *template == ']';
1628
1629           size_t index;
1630           template = consume_int (template, &index);
1631           if (index < 1 || index > n_args)
1632             continue;
1633
1634           const struct pivot_argument *arg = &args[index - 1];
1635           size_t left = arg->n;
1636           while (left)
1637             {
1638               struct pivot_value **values = arg->values + (arg->n - left);
1639               int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1640               char escape = "%^"[tmpl_idx];
1641               size_t used = pivot_format_inner_template (
1642                 out, tmpl[tmpl_idx], escape, values, left,
1643                 show_values, show_variables);
1644               if (!used || used > left)
1645                 break;
1646               left -= used;
1647             }
1648         }
1649       else
1650         ds_put_byte (out, *template++);
1651     }
1652 }
1653
1654 static enum settings_value_show
1655 interpret_show (enum settings_value_show global_show,
1656                 enum settings_value_show table_show,
1657                 enum settings_value_show value_show,
1658                 bool has_label)
1659 {
1660   return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1661           : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1662           : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1663           : global_show);
1664 }
1665
1666 /* Appends a text representation of the body of VALUE to OUT.  SHOW_VALUES and
1667    SHOW_VARIABLES control whether variable and value labels are included.
1668
1669    The "body" omits subscripts and superscripts and footnotes. */
1670 bool
1671 pivot_value_format_body (const struct pivot_value *value,
1672                          enum settings_value_show show_values,
1673                          enum settings_value_show show_variables,
1674                          struct string *out)
1675 {
1676   enum settings_value_show show;
1677   bool numeric = false;
1678
1679   switch (value->type)
1680     {
1681     case PIVOT_VALUE_NUMERIC:
1682       show = interpret_show (settings_get_show_values (),
1683                              show_values,
1684                              value->numeric.show,
1685                              value->numeric.value_label != NULL);
1686       if (show & SETTINGS_VALUE_SHOW_VALUE)
1687         {
1688           char *s = data_out (&(union value) { .f = value->numeric.x },
1689                               "UTF-8", &value->numeric.format);
1690           ds_put_cstr (out, s + strspn (s, " "));
1691           free (s);
1692         }
1693       if (show & SETTINGS_VALUE_SHOW_LABEL)
1694         {
1695           if (show & SETTINGS_VALUE_SHOW_VALUE)
1696             ds_put_byte (out, ' ');
1697           ds_put_cstr (out, value->numeric.value_label);
1698         }
1699       numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1700       break;
1701
1702     case PIVOT_VALUE_STRING:
1703       show = interpret_show (settings_get_show_values (),
1704                              show_values,
1705                              value->string.show,
1706                              value->string.value_label != NULL);
1707       if (show & SETTINGS_VALUE_SHOW_VALUE)
1708         {
1709           if (value->string.hex)
1710             {
1711               for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1712                    *p; p++)
1713                 ds_put_format (out, "%02X", *p);
1714             }
1715           else
1716             ds_put_cstr (out, value->string.s);
1717         }
1718       if (show & SETTINGS_VALUE_SHOW_LABEL)
1719         {
1720           if (show & SETTINGS_VALUE_SHOW_VALUE)
1721             ds_put_byte (out, ' ');
1722           ds_put_cstr (out, value->string.value_label);
1723         }
1724       break;
1725
1726     case PIVOT_VALUE_VARIABLE:
1727       show = interpret_show (settings_get_show_variables (),
1728                              show_variables,
1729                              value->variable.show,
1730                              value->variable.var_label != NULL);
1731       if (show & SETTINGS_VALUE_SHOW_VALUE)
1732         ds_put_cstr (out, value->variable.var_name);
1733       if (show & SETTINGS_VALUE_SHOW_LABEL)
1734         {
1735           if (show & SETTINGS_VALUE_SHOW_VALUE)
1736             ds_put_byte (out, ' ');
1737           ds_put_cstr (out, value->variable.var_label);
1738         }
1739       break;
1740
1741     case PIVOT_VALUE_TEXT:
1742       ds_put_cstr (out, value->text.local);
1743       break;
1744
1745     case PIVOT_VALUE_TEMPLATE:
1746       pivot_format_template (out, value->template.s, value->template.args,
1747                              value->template.n_args, show_values,
1748                              show_variables);
1749       break;
1750     }
1751
1752   return numeric;
1753 }
1754
1755 /* Appends a text representation of VALUE to OUT.  SHOW_VALUES and
1756    SHOW_VARIABLES control whether variable and value labels are included.
1757
1758    Subscripts and superscripts and footnotes are included. */
1759 void
1760 pivot_value_format (const struct pivot_value *value,
1761                     enum settings_value_show show_values,
1762                     enum settings_value_show show_variables,
1763                     struct string *out)
1764 {
1765   pivot_value_format_body ( value, show_values, show_variables, out);
1766
1767   if (value->subscript)
1768     ds_put_format (out, "_%s", value->subscript);
1769
1770   if (value->superscript)
1771     ds_put_format (out, "^%s", value->superscript);
1772
1773   for (size_t i = 0; i < value->n_footnotes; i++)
1774     {
1775       ds_put_byte (out, '^');
1776       pivot_value_format (value->footnotes[i]->marker,
1777                           show_values, show_variables, out);
1778     }
1779 }
1780
1781 /* Returns a text representation of VALUE.  The caller must free the string,
1782    with free(). */
1783 char *
1784 pivot_value_to_string (const struct pivot_value *value,
1785                        enum settings_value_show show_values,
1786                        enum settings_value_show show_variables)
1787 {
1788   struct string s = DS_EMPTY_INITIALIZER;
1789   pivot_value_format (value, show_values, show_variables, &s);
1790   return ds_steal_cstr (&s);
1791 }
1792
1793 /* Frees the data owned by V. */
1794 void
1795 pivot_value_destroy (struct pivot_value *value)
1796 {
1797   if (value)
1798     {
1799       font_style_uninit (value->font_style);
1800       free (value->font_style);
1801       free (value->cell_style);
1802       /* Do not free the elements of footnotes because VALUE does not own
1803          them. */
1804       free (value->footnotes);
1805
1806       switch (value->type)
1807         {
1808         case PIVOT_VALUE_NUMERIC:
1809           free (value->numeric.var_name);
1810           free (value->numeric.value_label);
1811           break;
1812
1813         case PIVOT_VALUE_STRING:
1814           free (value->string.s);
1815           free (value->string.var_name);
1816           free (value->string.value_label);
1817           break;
1818
1819         case PIVOT_VALUE_VARIABLE:
1820           free (value->variable.var_name);
1821           free (value->variable.var_label);
1822           break;
1823
1824         case PIVOT_VALUE_TEXT:
1825           free (value->text.local);
1826           if (value->text.c != value->text.local)
1827             free (value->text.c);
1828           if (value->text.id != value->text.local
1829               && value->text.id != value->text.c)
1830             free (value->text.id);
1831           break;
1832
1833         case PIVOT_VALUE_TEMPLATE:
1834           free (value->template.s);
1835           for (size_t i = 0; i < value->template.n_args; i++)
1836             pivot_argument_uninit (&value->template.args[i]);
1837           free (value->template.args);
1838           break;
1839         }
1840       free (value);
1841     }
1842 }
1843
1844 /* Sets AREA to the style to use for VALUE, with defaults coming from
1845    DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
1846 void
1847 pivot_value_get_style (struct pivot_value *value,
1848                        const struct area_style *default_style,
1849                        struct area_style *area)
1850 {
1851   font_style_copy (&area->font_style, (value->font_style
1852                                        ? value->font_style
1853                                        : &default_style->font_style));
1854   area->cell_style = (value->cell_style
1855                       ? *value->cell_style
1856                       : default_style->cell_style);
1857 }
1858
1859 /* Copies AREA into VALUE's style. */
1860 void
1861 pivot_value_set_style (struct pivot_value *value,
1862                        const struct area_style *area)
1863 {
1864   if (value->font_style)
1865     font_style_uninit (value->font_style);
1866   else
1867     value->font_style = xmalloc (sizeof *value->font_style);
1868   font_style_copy (value->font_style, &area->font_style);
1869
1870   if (!value->cell_style)
1871     value->cell_style = xmalloc (sizeof *value->cell_style);
1872   *value->cell_style = area->cell_style;
1873 }
1874
1875 /* Frees the data owned by ARG (but not ARG itself). */
1876 void
1877 pivot_argument_uninit (struct pivot_argument *arg)
1878 {
1879   if (arg)
1880     {
1881       for (size_t i = 0; i < arg->n; i++)
1882         pivot_value_destroy (arg->values[i]);
1883       free (arg->values);
1884     }
1885 }
1886
1887 /* Creates and returns a new pivot_value whose contents is the null-terminated
1888    string TEXT.  Takes ownership of TEXT.
1889
1890    This function is for text strings provided by the user (with the exception
1891    that pivot_value_new_variable() should be used for variable names).  For
1892    strings that are part of the PSPP user interface, such as names of
1893    procedures, statistics, annotations, error messages, etc., use
1894    pivot_value_new_text(). */
1895 struct pivot_value *
1896 pivot_value_new_user_text_nocopy (char *text)
1897 {
1898   struct pivot_value *value = xmalloc (sizeof *value);
1899   *value = (struct pivot_value) {
1900     .type = PIVOT_VALUE_TEXT,
1901     .text = {
1902       .local = text,
1903       .c = text,
1904       .id = text,
1905       .user_provided = true,
1906     }
1907   };
1908   return value;
1909 }
1910
1911 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
1912    TEXT.  Use SIZE_MAX if TEXT is null-teriminated and its length is not known
1913    in advance.
1914
1915    This function is for text strings provided by the user (with the exception
1916    that pivot_value_new_variable() should be used for variable names).  For
1917    strings that are part of the PSPP user interface, such as names of
1918    procedures, statistics, annotations, error messages, etc., use
1919    pivot_value_new_text().j
1920
1921    The caller retains ownership of TEXT.*/
1922 struct pivot_value *
1923 pivot_value_new_user_text (const char *text, size_t length)
1924 {
1925   return pivot_value_new_user_text_nocopy (
1926     xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
1927 }
1928
1929 /* Creates and returns new pivot_value whose contents is TEXT, which should be
1930    a translatable string, but not actually translated yet, e.g. enclosed in
1931    N_().  This function is for text strings that are part of the PSPP user
1932    interface, such as names of procedures, statistics, annotations, error
1933    messages, etc.  For strings that come from the user, use
1934    pivot_value_new_user_text(). */
1935 struct pivot_value *
1936 pivot_value_new_text (const char *text)
1937 {
1938   char *c = xstrdup (text);
1939   char *local = xstrdup (gettext (c));
1940
1941   struct pivot_value *value = xmalloc (sizeof *value);
1942   *value = (struct pivot_value) {
1943     .type = PIVOT_VALUE_TEXT,
1944     .text = {
1945       .local = local,
1946       .c = c,
1947       .id = c,
1948       .user_provided = false,
1949     }
1950   };
1951   return value;
1952 }
1953
1954 /* Same as pivot_value_new_text() but its argument is a printf()-like format
1955    string. */
1956 struct pivot_value * PRINTF_FORMAT (1, 2)
1957 pivot_value_new_text_format (const char *format, ...)
1958 {
1959   va_list args;
1960   va_start (args, format);
1961   char *c = xvasprintf (format, args);
1962   va_end (args);
1963
1964   va_start (args, format);
1965   char *local = xvasprintf (gettext (format), args);
1966   va_end (args);
1967
1968   struct pivot_value *value = xmalloc (sizeof *value);
1969   *value = (struct pivot_value) {
1970     .type = PIVOT_VALUE_TEXT,
1971     .text = {
1972       .local = local,
1973       .c = c,
1974       .id = xstrdup (c),
1975       .user_provided = false,
1976     }
1977   };
1978   return value;
1979 }
1980
1981 static char *
1982 xstrdup_if_nonempty (const char *s)
1983 {
1984   return s && s[0] ? xstrdup (s) : NULL;
1985 }
1986
1987 /* Returns a new pivot_value that represents X.
1988
1989    The format to use for X is unspecified.  Usually the easiest way to specify
1990    a format is through assigning a result class to one of the categories that
1991    the pivot_value will end up in.  If that is not suitable, then the caller
1992    can use pivot_value_set_rc() or assign directly to value->numeric.format. */
1993 struct pivot_value *
1994 pivot_value_new_number (double x)
1995 {
1996   struct pivot_value *value = xmalloc (sizeof *value);
1997   *value = (struct pivot_value) {
1998     .type = PIVOT_VALUE_NUMERIC,
1999     .numeric = { .x = x, },
2000   };
2001   return value;
2002 }
2003
2004 /* Returns a new pivot_value that represents X, formatted as an integer. */
2005 struct pivot_value *
2006 pivot_value_new_integer (double x)
2007 {
2008   struct pivot_value *value = pivot_value_new_number (x);
2009   value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2010   return value;
2011 }
2012
2013 /* Returns a new pivot_value that represents VALUE, formatted as for
2014    VARIABLE. */
2015 struct pivot_value *
2016 pivot_value_new_var_value (const struct variable *variable,
2017                            const union value *value)
2018 {
2019   struct pivot_value *pv = pivot_value_new_value (
2020     value, var_get_width (variable), var_get_print_format (variable),
2021     var_get_encoding (variable));
2022
2023   char *var_name = xstrdup (var_get_name (variable));
2024   if (var_is_alpha (variable))
2025     pv->string.var_name = var_name;
2026   else
2027     pv->numeric.var_name = var_name;
2028
2029   const char *label = var_lookup_value_label (variable, value);
2030   if (label)
2031     {
2032       if (var_is_alpha (variable))
2033         pv->string.value_label = xstrdup (label);
2034       else
2035         pv->numeric.value_label = xstrdup (label);
2036     }
2037
2038   return pv;
2039 }
2040
2041 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2042    formatted with FORMAT.  For a string value, ENCODING must be its character
2043    encoding. */
2044 struct pivot_value *
2045 pivot_value_new_value (const union value *value, int width,
2046                        const struct fmt_spec *format, const char *encoding)
2047 {
2048   struct pivot_value *pv = xzalloc (sizeof *pv);
2049   if (width > 0)
2050     {
2051       char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2052                                width);
2053       size_t n = strlen (s);
2054       while (n > 0 && s[n - 1] == ' ')
2055         s[--n] = '\0';
2056
2057       pv->type = PIVOT_VALUE_STRING;
2058       pv->string.s = s;
2059       pv->string.hex = format->type == FMT_AHEX;
2060     }
2061   else
2062     {
2063       pv->type = PIVOT_VALUE_NUMERIC;
2064       pv->numeric.x = value->f;
2065       pv->numeric.format = *format;
2066     }
2067
2068   return pv;
2069 }
2070
2071 /* Returns a new pivot_value for VARIABLE. */
2072 struct pivot_value *
2073 pivot_value_new_variable (const struct variable *variable)
2074 {
2075   struct pivot_value *value = xmalloc (sizeof *value);
2076   *value = (struct pivot_value) {
2077     .type = PIVOT_VALUE_VARIABLE,
2078     .variable = {
2079       .var_name = xstrdup (var_get_name (variable)),
2080       .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2081     },
2082   };
2083   return value;
2084 }
2085
2086 /* Attaches a reference to FOOTNOTE to V. */
2087 void
2088 pivot_value_add_footnote (struct pivot_value *v,
2089                           const struct pivot_footnote *footnote)
2090 {
2091   v->footnotes = xrealloc (v->footnotes,
2092                            (v->n_footnotes + 1) * sizeof *v->footnotes);
2093   v->footnotes[v->n_footnotes++] = footnote;
2094 }
2095
2096 /* If VALUE is a numeric value, and RC is a result class such as
2097    PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2098 void
2099 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2100                     const char *rc)
2101 {
2102   if (value->type == PIVOT_VALUE_NUMERIC)
2103     {
2104       const struct fmt_spec *f = pivot_table_get_format (table, rc);
2105       if (f)
2106         value->numeric.format = *f;
2107     }
2108 }
2109