pivot-table: Incorporate format settings.
[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 "data/file-name.h"
28 #include "libpspp/array.h"
29 #include "libpspp/assertion.h"
30 #include "libpspp/hash-functions.h"
31 #include "libpspp/i18n.h"
32 #include "output/driver.h"
33 #include "output/spv/spv-table-look.h"
34
35 #include "gl/c-ctype.h"
36 #include "gl/configmake.h"
37 #include "gl/intprops.h"
38 #include "gl/minmax.h"
39 #include "gl/relocatable.h"
40 #include "gl/xalloc.h"
41 #include "gl/xmemdup0.h"
42 #include "gl/xsize.h"
43
44 #include "gettext.h"
45 #define _(msgid) gettext (msgid)
46 #define N_(msgid) msgid
47
48 static const struct fmt_spec *pivot_table_get_format (
49   const struct pivot_table *, const char *s);
50 \f
51 /* Pivot table display styling. */
52
53 /* Returns the name of AREA. */
54 const char *
55 pivot_area_to_string (enum pivot_area area)
56 {
57   switch (area)
58     {
59     case PIVOT_AREA_TITLE: return "title";
60     case PIVOT_AREA_CAPTION: return "caption";
61     case PIVOT_AREA_FOOTER: return "footer";
62     case PIVOT_AREA_CORNER: return "corner";
63     case PIVOT_AREA_COLUMN_LABELS: return "column labels";
64     case PIVOT_AREA_ROW_LABELS: return "row labels";
65     case PIVOT_AREA_DATA: return "data";
66     case PIVOT_AREA_LAYERS: return "layers";
67     case PIVOT_N_AREAS: default: return "**error**";
68     }
69 }
70
71 /* Returns the name of BORDER. */
72 const char *
73 pivot_border_to_string (enum pivot_border border)
74 {
75   switch (border)
76     {
77     case PIVOT_BORDER_TITLE:
78       return "title";
79
80     case PIVOT_BORDER_OUTER_LEFT:
81       return "left outer frame";
82     case PIVOT_BORDER_OUTER_TOP:
83       return "top outer frame";
84     case PIVOT_BORDER_OUTER_RIGHT:
85       return "right outer frame";
86     case PIVOT_BORDER_OUTER_BOTTOM:
87       return "bottom outer frame";
88
89     case PIVOT_BORDER_INNER_LEFT:
90       return "left inner frame";
91     case PIVOT_BORDER_INNER_TOP:
92       return "top inner frame";
93     case PIVOT_BORDER_INNER_RIGHT:
94       return "right inner frame";
95     case PIVOT_BORDER_INNER_BOTTOM:
96       return "bottom inner frame";
97
98     case PIVOT_BORDER_DATA_LEFT:
99       return "data area left";
100     case PIVOT_BORDER_DATA_TOP:
101       return "data area top";
102
103     case PIVOT_BORDER_DIM_ROW_HORZ:
104       return "row label horizontal dimension border";
105     case PIVOT_BORDER_DIM_ROW_VERT:
106       return "row label vertical dimension border";
107     case PIVOT_BORDER_DIM_COL_HORZ:
108       return "column label horizontal dimension border";
109     case PIVOT_BORDER_DIM_COL_VERT:
110       return "column label vertical dimension border";
111
112     case PIVOT_BORDER_CAT_ROW_HORZ:
113       return "row label horizontal category border";
114     case PIVOT_BORDER_CAT_ROW_VERT:
115       return "row label vertical category border";
116     case PIVOT_BORDER_CAT_COL_HORZ:
117       return "column label horizontal category border";
118     case PIVOT_BORDER_CAT_COL_VERT:
119       return "column label vertical category border";
120
121     case PIVOT_N_BORDERS:
122     default:
123       return "**error**";
124     }
125 }
126
127 void
128 pivot_table_sizing_uninit (struct pivot_table_sizing *sizing)
129 {
130   if (sizing)
131     {
132       free (sizing->widths);
133       free (sizing->breaks);
134       free (sizing->keeps);
135     }
136 }
137 \f
138 /* Pivot table looks. */
139
140 static const struct pivot_table_look *
141 default_look (const struct pivot_table_look *new)
142 {
143   static struct pivot_table_look *look;
144   if (new)
145     {
146       pivot_table_look_unref (look);
147       look = pivot_table_look_ref (new);
148     }
149   else if (!look)
150     {
151       char *error = pivot_table_look_read ("default.stt", &look);
152       if (error)
153         {
154           free (error);
155           look = pivot_table_look_ref (pivot_table_look_builtin_default ());
156         }
157     }
158   return look;
159 }
160
161 const struct pivot_table_look *
162 pivot_table_look_get_default (void)
163 {
164   return default_look (NULL);
165 }
166
167 void
168 pivot_table_look_set_default (const struct pivot_table_look *look)
169 {
170   default_look (look);
171 }
172
173 char * WARN_UNUSED_RESULT
174 pivot_table_look_read (const char *name, struct pivot_table_look **lookp)
175 {
176   *lookp = NULL;
177
178   /* Construct search path. */
179   const char *path[4];
180   size_t n = 0;
181   path[n++] = ".";
182   const char *home = getenv ("HOME");
183   char *allocated = NULL;
184   if (home != NULL)
185     path[n++] = allocated = xasprintf ("%s/.pspp/looks", home);
186   char *allocated2;
187   path[n++] = relocate2 (PKGDATADIR "/looks", &allocated2);
188   path[n++] = NULL;
189
190   /* Search path. */
191   char *file = fn_search_path (name, (char **) path);
192   if (!file)
193     {
194       char *name2 = xasprintf ("%s.stt", name);
195       file = fn_search_path (name2, (char **) path);
196       free (name2);
197     }
198   free (allocated);
199   free (allocated2);
200   if (!file)
201     return xasprintf ("%s: not found", name);
202
203   /* Read file. */
204   char *error = spv_table_look_read (file, lookp);
205   free (file);
206   return error;
207 }
208
209 const struct pivot_table_look *
210 pivot_table_look_builtin_default (void)
211 {
212   static struct pivot_table_look look = {
213     .ref_cnt = 1,
214
215     .omit_empty = true,
216     .row_labels_in_corner = true,
217     .width_ranges = {
218       [TABLE_HORZ] = { 36, 72 },
219       [TABLE_VERT] = { 36, 120 },
220     },
221
222     .areas = {
223 #define AREA(BOLD, H, V, L, R, T, B) {                         \
224     .cell_style = {                                             \
225       .halign = TABLE_HALIGN_##H,                               \
226       .valign = TABLE_VALIGN_##V,                               \
227       .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R,     \
228                   [TABLE_VERT][0] = T, [TABLE_VERT][1] = B },   \
229     },                                                          \
230     .font_style = {                                             \
231       .bold = BOLD,                                             \
232       .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK},  \
233       .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE},  \
234       .size = 9,                                                \
235       .typeface = (char *) "Sans Serif",                        \
236     },                                                          \
237   }
238       [PIVOT_AREA_TITLE]         = AREA(true,  CENTER, CENTER,  8,11,1,8),
239       [PIVOT_AREA_CAPTION]       = AREA(false, LEFT,   TOP,     8,11,1,1),
240       [PIVOT_AREA_FOOTER]        = AREA(false, LEFT,   TOP,    11, 8,2,3),
241       [PIVOT_AREA_CORNER]        = AREA(false, LEFT,   BOTTOM,  8,11,1,1),
242       [PIVOT_AREA_COLUMN_LABELS] = AREA(false, CENTER, BOTTOM,  8,11,1,3),
243       [PIVOT_AREA_ROW_LABELS]    = AREA(false, LEFT,   TOP,     8,11,1,3),
244       [PIVOT_AREA_DATA]          = AREA(false, MIXED,  TOP,     8,11,1,1),
245       [PIVOT_AREA_LAYERS]        = AREA(false, LEFT,   BOTTOM,  8,11,1,3),
246 #undef AREA
247     },
248
249     .borders = {
250 #define BORDER(STROKE) { .stroke = STROKE, .color = CELL_COLOR_BLACK }
251       [PIVOT_BORDER_TITLE]        = BORDER(TABLE_STROKE_NONE),
252       [PIVOT_BORDER_OUTER_LEFT]   = BORDER(TABLE_STROKE_NONE),
253       [PIVOT_BORDER_OUTER_TOP]    = BORDER(TABLE_STROKE_NONE),
254       [PIVOT_BORDER_OUTER_RIGHT]  = BORDER(TABLE_STROKE_NONE),
255       [PIVOT_BORDER_OUTER_BOTTOM] = BORDER(TABLE_STROKE_NONE),
256       [PIVOT_BORDER_INNER_LEFT]   = BORDER(TABLE_STROKE_THICK),
257       [PIVOT_BORDER_INNER_TOP]    = BORDER(TABLE_STROKE_THICK),
258       [PIVOT_BORDER_INNER_RIGHT]  = BORDER(TABLE_STROKE_THICK),
259       [PIVOT_BORDER_INNER_BOTTOM] = BORDER(TABLE_STROKE_THICK),
260       [PIVOT_BORDER_DATA_LEFT]    = BORDER(TABLE_STROKE_THICK),
261       [PIVOT_BORDER_DATA_TOP]     = BORDER(TABLE_STROKE_THICK),
262       [PIVOT_BORDER_DIM_ROW_HORZ] = BORDER(TABLE_STROKE_SOLID),
263       [PIVOT_BORDER_DIM_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
264       [PIVOT_BORDER_DIM_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
265       [PIVOT_BORDER_DIM_COL_VERT] = BORDER(TABLE_STROKE_SOLID),
266       [PIVOT_BORDER_CAT_ROW_HORZ] = BORDER(TABLE_STROKE_NONE),
267       [PIVOT_BORDER_CAT_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
268       [PIVOT_BORDER_CAT_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
269       [PIVOT_BORDER_CAT_COL_VERT] = BORDER(TABLE_STROKE_SOLID),
270     },
271   };
272
273   return &look;
274 }
275
276 struct pivot_table_look *
277 pivot_table_look_new_builtin_default (void)
278 {
279   return pivot_table_look_unshare (
280     pivot_table_look_ref (pivot_table_look_builtin_default ()));
281 }
282
283 struct pivot_table_look *
284 pivot_table_look_ref (const struct pivot_table_look *look_)
285 {
286   assert (look_->ref_cnt > 0);
287
288   struct pivot_table_look *look = CONST_CAST (struct pivot_table_look *, look_);
289   look->ref_cnt++;
290   return look;
291 }
292
293 static char *
294 xstrdup_if_nonempty (const char *s)
295 {
296   return s && s[0] ? xstrdup (s) : NULL;
297 }
298
299 struct pivot_table_look *
300 pivot_table_look_unshare (struct pivot_table_look *old)
301 {
302   assert (old->ref_cnt > 0);
303   if (old->ref_cnt == 1)
304     return old;
305
306   pivot_table_look_unref (old);
307
308   struct pivot_table_look *new = xmemdup (old, sizeof *old);
309   new->ref_cnt = 1;
310   new->name = xstrdup_if_nonempty (old->name);
311   for (size_t i = 0; i < PIVOT_N_AREAS; i++)
312     table_area_style_copy (NULL, &new->areas[i], &old->areas[i]);
313   new->continuation = xstrdup_if_nonempty (old->continuation);
314
315   return new;
316 }
317
318 void
319 pivot_table_look_unref (struct pivot_table_look *look)
320 {
321   if (look)
322     {
323       assert (look->ref_cnt > 0);
324       if (!--look->ref_cnt)
325         {
326           free (look->name);
327           for (size_t i = 0; i < PIVOT_N_AREAS; i++)
328             table_area_style_uninit (&look->areas[i]);
329           free (look->continuation);
330           free (look);
331         }
332     }
333 }
334 \f
335 /* Axes. */
336
337 /* Returns the name of AXIS_TYPE. */
338 const char *
339 pivot_axis_type_to_string (enum pivot_axis_type axis_type)
340 {
341   switch (axis_type)
342     {
343     case PIVOT_AXIS_LAYER:
344       return "layer";
345
346     case PIVOT_AXIS_ROW:
347       return "row";
348
349     case PIVOT_AXIS_COLUMN:
350       return "column";
351
352     default:
353       return "<error>";
354     }
355 }
356
357 static enum pivot_axis_type
358 pivot_axis_type_transpose (enum pivot_axis_type axis_type)
359 {
360   assert (axis_type == PIVOT_AXIS_ROW || axis_type == PIVOT_AXIS_COLUMN);
361   return (axis_type == PIVOT_AXIS_ROW ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW);
362 }
363
364 /* Implementation of PIVOT_AXIS_FOR_EACH. */
365 size_t *
366 pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis)
367 {
368   if (!indexes)
369     {
370       if (axis->n_dimensions)
371         for (size_t i = 0; i < axis->n_dimensions; i++)
372           if (axis->dimensions[i]->n_leaves == 0)
373             return NULL;
374
375       size_t size = axis->n_dimensions * sizeof *indexes;
376       return xzalloc (MAX (size, 1));
377     }
378
379   for (size_t i = 0; i < axis->n_dimensions; i++)
380     {
381       const struct pivot_dimension *d = axis->dimensions[i];
382       if (++indexes[i] < d->n_leaves)
383         return indexes;
384
385       indexes[i] = 0;
386     }
387
388   free (indexes);
389   return NULL;
390 }
391 \f
392 /* Dimensions. */
393
394 static void
395 pivot_category_set_rc (struct pivot_category *category, const char *s)
396 {
397   const struct fmt_spec *format = pivot_table_get_format (
398     category->dimension->table, s);
399   if (format)
400     category->format = *format;
401
402   /* Ensure that the category itself, in addition to the cells within it, takes
403      the format.  (It's kind of rare for a category to have a numeric format
404      though.) */
405   struct pivot_value *name = category->name;
406   if (name->type == PIVOT_VALUE_NUMERIC && !name->numeric.format.w)
407     name->numeric.format = format ? *format : *settings_get_format ();
408 }
409
410 static void
411 pivot_category_create_leaves_valist (struct pivot_category *parent,
412                                      va_list args)
413 {
414   const char *s;
415   while ((s = va_arg (args, const char *)))
416     {
417       if (!strncmp (s, "RC_", 3))
418         {
419           assert (parent->n_subs);
420           pivot_category_set_rc (parent->subs[parent->n_subs - 1], s);
421         }
422       else
423         pivot_category_create_leaf (parent, pivot_value_new_text (s));
424     }
425 }
426
427 /* Creates a new dimension with the given NAME in TABLE and returns it.  The
428    dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
429    that axis.
430
431    NAME should be a translatable name, but not actually translated yet,
432    e.g. enclosed in N_().  To use a different kind of value for a name, use
433    pivot_dimension_create__() instead.
434
435    The optional varargs parameters may be used to add an initial set of
436    categories to the dimension.  Each string should be a translatable category
437    name, but not actually translated yet, e.g. enclosed in N_().  Each string
438    may optionally be followod by a PIVOT_RC_* string that specifies the default
439    numeric format for cells in this category. */
440 struct pivot_dimension * SENTINEL (0)
441 (pivot_dimension_create) (struct pivot_table *table,
442                           enum pivot_axis_type axis_type,
443                           const char *name, ...)
444 {
445   struct pivot_dimension *d = pivot_dimension_create__ (
446     table, axis_type, pivot_value_new_text (name));
447
448   va_list args;
449   va_start (args, name);
450   pivot_category_create_leaves_valist (d->root, args);
451   va_end (args);
452
453   return d;
454 }
455
456 /* Creates a new dimension with the given NAME in TABLE and returns it.  The
457    dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
458    that axis. */
459 struct pivot_dimension *
460 pivot_dimension_create__ (struct pivot_table *table,
461                           enum pivot_axis_type axis_type,
462                           struct pivot_value *name)
463 {
464   assert (pivot_table_is_empty (table));
465
466   struct pivot_dimension *d = xmalloc (sizeof *d);
467   *d = (struct pivot_dimension) {
468     .table = table,
469     .axis_type = axis_type,
470     .level = table->axes[axis_type].n_dimensions,
471     .top_index = table->n_dimensions,
472     .root = xmalloc (sizeof *d->root),
473   };
474
475   struct pivot_category *root = d->root;
476   *root = (struct pivot_category) {
477     .name = name,
478     .parent = NULL,
479     .dimension = d,
480     .show_label = false,
481     .data_index = SIZE_MAX,
482     .presentation_index = SIZE_MAX,
483   };
484
485   table->dimensions = xrealloc (
486     table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions);
487   table->dimensions[table->n_dimensions++] = d;
488
489   struct pivot_axis *axis = &table->axes[axis_type];
490   axis->dimensions = xrealloc (
491     axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
492   axis->dimensions[axis->n_dimensions++] = d;
493
494   if (axis_type == PIVOT_AXIS_LAYER)
495     {
496       free (table->current_layer);
497       table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
498                                       sizeof *table->current_layer);
499     }
500
501   /* axis->extent and axis->label_depth will be calculated later. */
502
503   return d;
504 }
505
506 void
507 pivot_dimension_destroy (struct pivot_dimension *d)
508 {
509   if (!d)
510     return;
511
512   pivot_category_destroy (d->root);
513   free (d->data_leaves);
514   free (d->presentation_leaves);
515   free (d);
516 }
517
518 /* Returns the first leaf node in an in-order traversal that is a child of
519    CAT. */
520 static const struct pivot_category * UNUSED
521 pivot_category_first_leaf (const struct pivot_category *cat)
522 {
523   if (pivot_category_is_leaf (cat))
524     return cat;
525
526   for (size_t i = 0; i < cat->n_subs; i++)
527     {
528       const struct pivot_category *first
529         = pivot_category_first_leaf (cat->subs[i]);
530       if (first)
531         return first;
532     }
533
534   return NULL;
535 }
536
537 /* Returns the next leaf node in an in-order traversal starting at CAT, which
538    must be a leaf. */
539 static const struct pivot_category * UNUSED
540 pivot_category_next_leaf (const struct pivot_category *cat)
541 {
542   assert (pivot_category_is_leaf (cat));
543
544   for (;;)
545     {
546       const struct pivot_category *parent = cat->parent;
547       if (!parent)
548         return NULL;
549       for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
550         {
551           const struct pivot_category *next
552             = pivot_category_first_leaf (parent->subs[i]);
553           if (next)
554             return next;
555         }
556
557       cat = cat->parent;
558     }
559 }
560
561 static void
562 pivot_category_add_child (struct pivot_category *child)
563 {
564   struct pivot_category *parent = child->parent;
565
566   assert (pivot_category_is_group (parent));
567   if (parent->n_subs >= parent->allocated_subs)
568     parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
569                                sizeof *parent->subs);
570   parent->subs[parent->n_subs++] = child;
571 }
572
573 /* Adds leaf categories as a child of PARENT.  To create top-level categories
574    within dimension 'd', pass 'd->root' for PARENT.
575
576    Each of the varargs parameters should be a string, each of which should be a
577    translatable category name, but not actually translated yet, e.g. enclosed
578    in N_().  Each string may optionally be followod by a PIVOT_RC_* string that
579    specifies the default numeric format for cells in this category.
580
581    Returns the category index, which is just a 0-based array index, for the
582    first new category.
583
584    Leaves have to be created in in-order, that is, don't create a group and add
585    some leaves, then add leaves outside the group and try to add more leaves
586    inside it. */
587 int SENTINEL (0)
588 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
589 {
590   int retval = parent->dimension->n_leaves;
591
592   va_list args;
593   va_start (args, parent);
594   pivot_category_create_leaves_valist (parent, args);
595   va_end (args);
596
597   return retval;
598 }
599
600 /* Creates a new leaf category with the given NAME as a child of PARENT.  To
601    create a top-level category within dimension 'd', pass 'd->root' for PARENT.
602    Returns the category index, which is just a 0-based array index, for the new
603    category.
604
605    Leaves have to be created in in-order, that is, don't create a group and add
606    some leaves, then add leaves outside the group and try to add more leaves
607    inside it. */
608 int
609 pivot_category_create_leaf (struct pivot_category *parent,
610                             struct pivot_value *name)
611 {
612   return pivot_category_create_leaf_rc (parent, name, NULL);
613 }
614
615 /* Creates a new leaf category with the given NAME as a child of PARENT.  To
616    create a top-level category within dimension 'd', pass 'd->root' for PARENT.
617    Returns the category index, which is just a 0-based array index, for the new
618    category.
619
620    If RC is nonnull and the name of a result category, the category is assigned
621    that result category.
622
623    Leaves have to be created in in-order, that is, don't create a group and add
624    some leaves, then add leaves outside the group and try to add more leaves
625    inside it. */
626 int
627 pivot_category_create_leaf_rc (struct pivot_category *parent,
628                                struct pivot_value *name, const char *rc)
629 {
630   struct pivot_dimension *d = parent->dimension;
631
632   struct pivot_category *leaf = xmalloc (sizeof *leaf);
633   *leaf = (struct pivot_category) {
634     .name = name,
635     .parent = parent,
636     .dimension = d,
637     .group_index = parent->n_subs,
638     .data_index = d->n_leaves,
639     .presentation_index = d->n_leaves,
640   };
641
642   if (d->n_leaves >= d->allocated_leaves)
643     {
644       d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
645                                    sizeof *d->data_leaves);
646       d->presentation_leaves = xrealloc (
647         d->presentation_leaves,
648         d->allocated_leaves * sizeof *d->presentation_leaves);
649     }
650
651   d->data_leaves[d->n_leaves] = leaf;
652   d->presentation_leaves[d->n_leaves] = leaf;
653   d->n_leaves++;
654
655   pivot_category_add_child (leaf);
656
657   /* Make sure that the new child is the last in in-order. */
658   assert (!pivot_category_next_leaf (leaf));
659
660   pivot_category_set_rc (leaf, rc);
661
662   return leaf->data_index;
663 }
664
665 /* Adds a new category group named NAME as a child of PARENT.  To create a
666    top-level group within dimension 'd', pass 'd->root' for PARENT.
667
668    NAME should be a translatable name, but not actually translated yet,
669    e.g. enclosed in N_().  To use a different kind of value for a name, use
670    pivot_category_create_group__() instead.
671
672    The optional varargs parameters may be used to add an initial set of
673    categories to the group.  Each string should be a translatable category
674    name, but not actually translated yet, e.g. enclosed in N_().  Each string
675    may optionally be followod by a PIVOT_RC_* string that specifies the default
676    numeric format for cells in this category.
677
678    Returns the new group. */
679 struct pivot_category * SENTINEL (0)
680 (pivot_category_create_group) (struct pivot_category *parent,
681                                const char *name, ...)
682 {
683   struct pivot_category *group = pivot_category_create_group__ (
684     parent, pivot_value_new_text (name));
685
686   va_list args;
687   va_start (args, name);
688   pivot_category_create_leaves_valist (group, args);
689   va_end (args);
690
691   return group;
692 }
693
694 /* Adds a new category group named NAME as a child of PARENT.  To create a
695    top-level group within dimension 'd', pass 'd->root' for PARENT.  Returns
696    the new group. */
697 struct pivot_category *
698 pivot_category_create_group__ (struct pivot_category *parent,
699                                struct pivot_value *name)
700 {
701   struct pivot_dimension *d = parent->dimension;
702
703   struct pivot_category *group = xmalloc (sizeof *group);
704   *group = (struct pivot_category) {
705     .name = name,
706     .parent = parent,
707     .dimension = d,
708     .show_label = true,
709     .group_index = parent->n_subs,
710     .data_index = SIZE_MAX,
711     .presentation_index = SIZE_MAX,
712   };
713
714   pivot_category_add_child (group);
715
716   return group;
717 }
718
719 void
720 pivot_category_destroy (struct pivot_category *c)
721 {
722   if (!c)
723     return;
724
725   pivot_value_destroy (c->name);
726   for (size_t i = 0; i < c->n_subs; i++)
727     pivot_category_destroy (c->subs[i]);
728   free (c->subs);
729   free (c);
730 }
731 \f
732 /* Result classes.
733
734    These are usually the easiest way to control the formatting of numeric data
735    in a pivot table.  See pivot_dimension_create() for an explanation of their
736    use.  */
737 struct result_class
738   {
739     const char *name;           /* "RC_*". */
740     struct fmt_spec format;
741   };
742
743 /* Formats for most of the result classes. */
744 static struct result_class result_classes[] =
745   {
746     { PIVOT_RC_INTEGER,      { FMT_F,   40, 0 } },
747     { PIVOT_RC_PERCENT,      { FMT_PCT, 40, 1 } },
748     { PIVOT_RC_CORRELATION,  { FMT_F,   40, 3 } },
749     { PIVOT_RC_SIGNIFICANCE, { FMT_F,   40, 3 } },
750     { PIVOT_RC_RESIDUAL,     { FMT_F,   40, 2 } },
751     { PIVOT_RC_COUNT,        { 0, 0, 0 } },
752     { PIVOT_RC_OTHER,        { 0, 0, 0 } },
753   };
754
755 /* Has PIVOT_RC_COUNT been overridden by the user? */
756 static bool overridden_count_format;
757
758 static struct result_class *
759 pivot_result_class_find (const char *s)
760 {
761   for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
762     if (!strcmp (s, result_classes[i].name))
763       return &result_classes[i];
764   return NULL;
765 }
766
767 static const struct fmt_spec *
768 pivot_table_get_format (const struct pivot_table *table, const char *s)
769 {
770   if (!s)
771     return NULL;
772   else if (!strcmp (s, PIVOT_RC_OTHER))
773     return settings_get_format ();
774   else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
775     return &table->weight_format;
776   else
777     {
778       const struct result_class *rc = pivot_result_class_find (s);
779       return rc ? &rc->format : NULL;
780     }
781 }
782
783 /* Sets the format specification for the result class named S (which should not
784    include the RC_ prefix) to *FORMAT.  Returns true if successful, false if S
785    does not name a known result class. */
786 bool
787 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
788 {
789   char *s = xasprintf ("RC_%s", s_);
790   struct result_class *rc = pivot_result_class_find (s);
791   if (rc)
792     {
793       rc->format = *format;
794       if (!strcmp (s, PIVOT_RC_COUNT))
795         overridden_count_format = true;
796     }
797   free (s);
798
799   return rc != NULL;
800 }
801
802 bool
803 is_pivot_result_class (const char *s)
804 {
805   return pivot_result_class_find (s) != NULL;
806 }
807 \f
808 /* Pivot tables. */
809
810 static struct pivot_cell *pivot_table_insert_cell (struct pivot_table *,
811                                                    const size_t *dindexes);
812 static void pivot_table_delete_cell (struct pivot_table *,
813                                      struct pivot_cell *);
814
815 /* Creates and returns a new pivot table with the given TITLE.  TITLE should be
816    a text string marked for translation but not actually translated yet,
817    e.g. N_("Descriptive Statistics").  The un-translated text string is used as
818    the pivot table's subtype.
819
820    This function is a shortcut for pivot_table_create__() for the most common
821    case.  Use pivot_table_create__() directly if the title should be some kind
822    of value other than an ordinary text string, or if the subtype should be
823    different from the title.
824
825    See the large comment at the top of pivot-table.h for general advice on
826    creating pivot tables. */
827 struct pivot_table *
828 pivot_table_create (const char *title)
829 {
830   return pivot_table_create__ (pivot_value_new_text (title), title);
831 }
832
833 /* Creates and returns a new pivot table with the given TITLE, and takes
834    ownership of TITLE.  The new pivot table's subtype is SUBTYPE, which should
835    be an untranslated English string that describes the contents of the table
836    at a high level without being specific about the variables or other context
837    involved.
838
839    TITLE and SUBTYPE may be NULL, but in that case the client must add them
840    later because they are both mandatory for a pivot table.
841
842    See the large comment at the top of pivot-table.h for general advice on
843    creating pivot tables. */
844 struct pivot_table *
845 pivot_table_create__ (struct pivot_value *title, const char *subtype)
846 {
847   struct pivot_table *table = xzalloc (sizeof *table);
848   table->ref_cnt = 1;
849   table->show_title = true;
850   table->show_caption = true;
851   table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
852   table->title = title;
853   table->subtype = subtype ? pivot_value_new_text (subtype) : NULL;
854   table->command_c = output_get_command_name ();
855   table->look = pivot_table_look_ref (pivot_table_look_get_default ());
856   table->settings = fmt_settings_copy (settings_get_fmt_settings ());
857
858   hmap_init (&table->cells);
859
860   return table;
861 }
862
863 /* Creates and returns a new pivot table with the given TITLE and a single cell
864    with the given CONTENT.
865
866    This is really just for error handling. */
867 struct pivot_table *
868 pivot_table_create_for_text (struct pivot_value *title,
869                              struct pivot_value *content)
870 {
871   struct pivot_table *table = pivot_table_create__ (title, "Error");
872
873   struct pivot_dimension *d = pivot_dimension_create (
874     table, PIVOT_AXIS_ROW, N_("Error"));
875   d->hide_all_labels = true;
876   pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
877
878   pivot_table_put1 (table, 0, content);
879
880   return table;
881 }
882
883 /* Increases TABLE's reference count, indicating that it has an additional
884    owner.  A pivot table that is shared among multiple owners must not be
885    modified. */
886 struct pivot_table *
887 pivot_table_ref (const struct pivot_table *table_)
888 {
889   struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
890   table->ref_cnt++;
891   return table;
892 }
893
894 static char *
895 xstrdup_if_nonnull (const char *s)
896 {
897   return s ? xstrdup (s) : NULL;
898 }
899
900 static struct pivot_table_sizing
901 clone_sizing (const struct pivot_table_sizing *s)
902 {
903   return (struct pivot_table_sizing) {
904     .widths = (s->n_widths
905                ? xmemdup (s->widths, s->n_widths * sizeof *s->widths)
906                : NULL),
907     .n_widths = s->n_widths,
908
909     .breaks = (s->n_breaks
910                ? xmemdup (s->breaks, s->n_breaks * sizeof *s->breaks)
911                : NULL),
912     .n_breaks = s->n_breaks,
913
914     .keeps = (s->n_keeps
915               ? xmemdup (s->keeps, s->n_keeps * sizeof *s->keeps)
916               : NULL),
917     .n_keeps = s->n_keeps,
918   };
919 }
920
921 static struct pivot_footnote **
922 clone_footnotes (struct pivot_footnote **old, size_t n)
923 {
924   if (!n)
925     return NULL;
926
927   struct pivot_footnote **new = xmalloc (n * sizeof *new);
928   for (size_t i = 0; i < n; i++)
929     {
930       new[i] = xmalloc (sizeof *new[i]);
931       *new[i] = (struct pivot_footnote) {
932         .idx = old[i]->idx,
933         .content = pivot_value_clone (old[i]->content),
934         .marker = pivot_value_clone (old[i]->marker),
935         .show = old[i]->show,
936       };
937     }
938   return new;
939 }
940
941 static struct pivot_category *
942 clone_category (struct pivot_category *old,
943                 struct pivot_dimension *new_dimension,
944                 struct pivot_category *new_parent)
945 {
946   struct pivot_category *new = xmalloc (sizeof *new);
947   *new = (struct pivot_category) {
948     .name = pivot_value_clone (old->name),
949     .parent = new_parent,
950     .dimension = new_dimension,
951     .label_depth = old->label_depth,
952     .extra_depth = old->extra_depth,
953
954     .subs = (old->n_subs
955              ? xzalloc (old->n_subs * sizeof *new->subs)
956              : NULL),
957     .n_subs = old->n_subs,
958     .allocated_subs = old->n_subs,
959
960     .show_label = old->show_label,
961     .show_label_in_corner = old->show_label_in_corner,
962
963     .format = old->format,
964     .group_index = old->group_index,
965     .data_index = old->data_index,
966     .presentation_index = old->presentation_index,
967   };
968
969   if (pivot_category_is_leaf (old))
970     {
971       new->dimension->data_leaves[new->data_index] = new;
972       new->dimension->presentation_leaves[new->presentation_index] = new;
973     }
974
975   for (size_t i = 0; i < new->n_subs; i++)
976     new->subs[i] = clone_category (old->subs[i], new_dimension, new);
977
978   return new;
979 }
980
981 static struct pivot_dimension *
982 clone_dimension (struct pivot_dimension *old, struct pivot_table *new_pt)
983 {
984   struct pivot_dimension *new = xmalloc (sizeof *new);
985   *new = (struct pivot_dimension) {
986     .table = new_pt,
987     .axis_type = old->axis_type,
988     .level = old->level,
989     .top_index = old->top_index,
990     .data_leaves = xzalloc (old->n_leaves * sizeof *new->data_leaves),
991     .presentation_leaves = xzalloc (old->n_leaves
992                                     * sizeof *new->presentation_leaves),
993     .n_leaves = old->n_leaves,
994     .allocated_leaves = old->n_leaves,
995     .hide_all_labels = old->hide_all_labels,
996     .label_depth = old->label_depth,
997   };
998
999   new->root = clone_category (old->root, new, NULL);
1000
1001   return new;
1002 }
1003
1004 static struct pivot_dimension **
1005 clone_dimensions (struct pivot_dimension **old, size_t n,
1006                   struct pivot_table *new_pt)
1007 {
1008   if (!n)
1009     return NULL;
1010
1011   struct pivot_dimension **new = xmalloc (n * sizeof *new);
1012   for (size_t i = 0; i < n; i++)
1013     new[i] = clone_dimension (old[i], new_pt);
1014   return new;
1015 }
1016
1017 struct pivot_table *
1018 pivot_table_unshare (struct pivot_table *old)
1019 {
1020   assert (old->ref_cnt > 0);
1021   if (old->ref_cnt == 1)
1022     return old;
1023
1024   pivot_table_unref (old);
1025
1026   struct pivot_table *new = xmalloc (sizeof *new);
1027   *new = (struct pivot_table) {
1028     .ref_cnt = 1,
1029
1030     .look = pivot_table_look_ref (old->look),
1031
1032     .rotate_inner_column_labels = old->rotate_inner_column_labels,
1033     .rotate_outer_row_labels = old->rotate_outer_row_labels,
1034     .show_grid_lines = old->show_grid_lines,
1035     .show_title = old->show_title,
1036     .show_caption = old->show_caption,
1037     .current_layer = (old->current_layer
1038                       ? xmemdup (old->current_layer,
1039                                  old->axes[PIVOT_AXIS_LAYER].n_dimensions
1040                                  * sizeof *new->current_layer)
1041                       : NULL),
1042     .show_values = old->show_values,
1043     .show_variables = old->show_variables,
1044     .weight_format = old->weight_format,
1045
1046     .sizing = {
1047       [TABLE_HORZ] = clone_sizing (&old->sizing[TABLE_HORZ]),
1048       [TABLE_VERT] = clone_sizing (&old->sizing[TABLE_VERT]),
1049     },
1050
1051     .settings = fmt_settings_copy (&old->settings),
1052     .grouping = old->grouping,
1053     .small = old->small,
1054
1055     .command_local = xstrdup_if_nonnull (old->command_local),
1056     .command_c = xstrdup_if_nonnull (old->command_c),
1057     .language = xstrdup_if_nonnull (old->language),
1058     .locale = xstrdup_if_nonnull (old->locale),
1059
1060     .dataset = xstrdup_if_nonnull (old->dataset),
1061     .datafile = xstrdup_if_nonnull (old->datafile),
1062     .date = old->date,
1063
1064     .footnotes = clone_footnotes (old->footnotes, old->n_footnotes),
1065     .n_footnotes = old->n_footnotes,
1066     .allocated_footnotes = old->n_footnotes,
1067
1068     .title = pivot_value_clone (old->title),
1069     .subtype = pivot_value_clone (old->subtype),
1070     .corner_text = pivot_value_clone (old->corner_text),
1071     .caption = pivot_value_clone (old->caption),
1072     .notes = xstrdup_if_nonnull (old->notes),
1073
1074     .dimensions = clone_dimensions (old->dimensions, old->n_dimensions, new),
1075     .n_dimensions = old->n_dimensions,
1076
1077     .cells = HMAP_INITIALIZER (new->cells),
1078   };
1079
1080   for (size_t i = 0; i < PIVOT_N_AXES; i++)
1081     {
1082       struct pivot_axis *new_axis = &new->axes[i];
1083       const struct pivot_axis *old_axis = &old->axes[i];
1084
1085       *new_axis = (struct pivot_axis) {
1086         .dimensions = xmalloc (old_axis->n_dimensions
1087                                * sizeof *new_axis->dimensions),
1088         .n_dimensions = old_axis->n_dimensions,
1089         .extent = old_axis->extent,
1090         .label_depth = old_axis->label_depth,
1091       };
1092
1093       for (size_t i = 0; i < new_axis->n_dimensions; i++)
1094         new_axis->dimensions[i] = new->dimensions[
1095           old_axis->dimensions[i]->top_index];
1096     }
1097
1098   const struct pivot_cell *old_cell;
1099   size_t *dindexes = xmalloc (old->n_dimensions * sizeof *dindexes);
1100   HMAP_FOR_EACH (old_cell, struct pivot_cell, hmap_node, &old->cells)
1101     {
1102       for (size_t i = 0; i < old->n_dimensions; i++)
1103         dindexes[i] = old_cell->idx[i];
1104       struct pivot_cell *new_cell
1105         = pivot_table_insert_cell (new, dindexes);
1106       new_cell->value = pivot_value_clone (old_cell->value);
1107     }
1108   free (dindexes);
1109
1110   return new;
1111 }
1112
1113 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
1114    If TABLE no longer has any owners, it is freed. */
1115 void
1116 pivot_table_unref (struct pivot_table *table)
1117 {
1118   if (!table)
1119     return;
1120   assert (table->ref_cnt > 0);
1121   if (--table->ref_cnt)
1122     return;
1123
1124   free (table->current_layer);
1125   pivot_table_look_unref (table->look);
1126
1127   for (int i = 0; i < TABLE_N_AXES; i++)
1128     pivot_table_sizing_uninit (&table->sizing[i]);
1129
1130   fmt_settings_uninit (&table->settings);
1131
1132   free (table->command_local);
1133   free (table->command_c);
1134   free (table->language);
1135   free (table->locale);
1136
1137   free (table->dataset);
1138   free (table->datafile);
1139
1140   for (size_t i = 0; i < table->n_footnotes; i++)
1141     pivot_footnote_destroy (table->footnotes[i]);
1142   free (table->footnotes);
1143
1144   pivot_value_destroy (table->title);
1145   pivot_value_destroy (table->subtype);
1146   pivot_value_destroy (table->corner_text);
1147   pivot_value_destroy (table->caption);
1148   free (table->notes);
1149
1150   for (size_t i = 0; i < table->n_dimensions; i++)
1151     pivot_dimension_destroy (table->dimensions[i]);
1152   free (table->dimensions);
1153
1154   for (size_t i = 0; i < PIVOT_N_AXES; i++)
1155     free (table->axes[i].dimensions);
1156
1157   struct pivot_cell *cell, *next_cell;
1158   HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
1159                       &table->cells)
1160     pivot_table_delete_cell (table, cell);
1161
1162   hmap_destroy (&table->cells);
1163
1164   free (table);
1165 }
1166
1167 /* Returns true if TABLE has more than one owner.  A pivot table that is shared
1168    among multiple owners must not be modified. */
1169 bool
1170 pivot_table_is_shared (const struct pivot_table *table)
1171 {
1172   return table->ref_cnt > 1;
1173 }
1174
1175 /* Swaps axes A and B in TABLE. */
1176 void
1177 pivot_table_swap_axes (struct pivot_table *table,
1178                        enum pivot_axis_type a, enum pivot_axis_type b)
1179 {
1180   if (a == b)
1181     return;
1182
1183   struct pivot_axis tmp = table->axes[a];
1184   table->axes[a] = table->axes[b];
1185   table->axes[b] = tmp;
1186
1187   for (int a = 0; a < PIVOT_N_AXES; a++)
1188     {
1189       struct pivot_axis *axis = &table->axes[a];
1190       for (size_t d = 0; d < axis->n_dimensions; d++)
1191         axis->dimensions[d]->axis_type = a;
1192     }
1193
1194   if (a == PIVOT_AXIS_LAYER || b == PIVOT_AXIS_LAYER)
1195     {
1196       free (table->current_layer);
1197       table->current_layer = xzalloc (
1198         table->axes[PIVOT_AXIS_LAYER].n_dimensions
1199         * sizeof *table->current_layer);
1200     }
1201 }
1202
1203 /* Swaps the row and column axes in TABLE. */
1204 void
1205 pivot_table_transpose (struct pivot_table *table)
1206 {
1207   pivot_table_swap_axes (table, PIVOT_AXIS_ROW, PIVOT_AXIS_COLUMN);
1208 }
1209
1210 static void
1211 pivot_table_update_axes (struct pivot_table *table)
1212 {
1213   for (int a = 0; a < PIVOT_N_AXES; a++)
1214     {
1215       struct pivot_axis *axis = &table->axes[a];
1216
1217       for (size_t d = 0; d < axis->n_dimensions; d++)
1218         {
1219           struct pivot_dimension *dim = axis->dimensions[d];
1220           dim->axis_type = a;
1221           dim->level = d;
1222         }
1223     }
1224 }
1225
1226 /* Moves DIM from its current location in TABLE to POS within AXIS.  POS of 0
1227    is the innermost dimension, 1 is the next one out, and so on. */
1228 void
1229 pivot_table_move_dimension (struct pivot_table *table,
1230                             struct pivot_dimension *dim,
1231                             enum pivot_axis_type axis, size_t pos)
1232 {
1233   assert (dim->table == table);
1234
1235   struct pivot_axis *old_axis = &table->axes[dim->axis_type];
1236   struct pivot_axis *new_axis = &table->axes[axis];
1237   pos = MIN (pos, new_axis->n_dimensions);
1238
1239   if (old_axis == new_axis && pos == dim->level)
1240     {
1241       /* No change. */
1242       return;
1243     }
1244
1245
1246   /* Update the current layer, if necessary.  If we're moving within the layer
1247      axis, preserve the current layer. */
1248   if (dim->axis_type == PIVOT_AXIS_LAYER)
1249     {
1250       if (axis == PIVOT_AXIS_LAYER)
1251         {
1252           /* Rearranging the layer axis. */
1253           move_element (table->current_layer, old_axis->n_dimensions,
1254                         sizeof *table->current_layer,
1255                         dim->level, pos);
1256         }
1257       else
1258         {
1259           /* A layer is becoming a row or column. */
1260           remove_element (table->current_layer, old_axis->n_dimensions,
1261                           sizeof *table->current_layer, dim->level);
1262         }
1263     }
1264   else if (axis == PIVOT_AXIS_LAYER)
1265     {
1266       /* A row or column is becoming a layer. */
1267       table->current_layer = xrealloc (
1268         table->current_layer,
1269         (new_axis->n_dimensions + 1) * sizeof *table->current_layer);
1270       insert_element (table->current_layer, new_axis->n_dimensions,
1271                       sizeof *table->current_layer, pos);
1272       table->current_layer[pos] = 0;
1273     }
1274
1275   /* Remove DIM from its current axis. */
1276   remove_element (old_axis->dimensions, old_axis->n_dimensions,
1277                   sizeof *old_axis->dimensions, dim->level);
1278   old_axis->n_dimensions--;
1279
1280   /* Insert DIM into its new axis. */
1281   new_axis->dimensions = xrealloc (
1282     new_axis->dimensions,
1283     (new_axis->n_dimensions + 1) * sizeof *new_axis->dimensions);
1284   insert_element (new_axis->dimensions, new_axis->n_dimensions,
1285                   sizeof *new_axis->dimensions, pos);
1286   new_axis->dimensions[pos] = dim;
1287   new_axis->n_dimensions++;
1288
1289   pivot_table_update_axes (table);
1290 }
1291
1292
1293 const struct pivot_table_look *
1294 pivot_table_get_look (const struct pivot_table *table)
1295 {
1296   return table->look;
1297 }
1298
1299 void
1300 pivot_table_set_look (struct pivot_table *table,
1301                       const struct pivot_table_look *look)
1302 {
1303   pivot_table_look_unref (table->look);
1304   table->look = pivot_table_look_ref (look);
1305 }
1306
1307 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
1308    WV, which should be the weight variable for the dictionary whose data or
1309    statistics are being put into TABLE.
1310
1311    This has no effect if WV is NULL. */
1312 void
1313 pivot_table_set_weight_var (struct pivot_table *table,
1314                             const struct variable *wv)
1315 {
1316   if (wv)
1317     pivot_table_set_weight_format (table, var_get_print_format (wv));
1318 }
1319
1320 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
1321    format for the dictionary whose data or statistics are being put into TABLE.
1322
1323    This has no effect if WFMT is NULL. */
1324 void
1325 pivot_table_set_weight_format (struct pivot_table *table,
1326                                const struct fmt_spec *wfmt)
1327 {
1328   if (wfmt)
1329     table->weight_format = *wfmt;
1330 }
1331
1332 /* Returns true if TABLE has no cells, false otherwise. */
1333 bool
1334 pivot_table_is_empty (const struct pivot_table *table)
1335 {
1336   return hmap_is_empty (&table->cells);
1337 }
1338
1339 static unsigned int
1340 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
1341 {
1342   return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
1343 }
1344
1345 static bool
1346 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
1347 {
1348   for (size_t i = 0; i < n; i++)
1349     if (a[i] != b[i])
1350       return false;
1351
1352   return true;
1353 }
1354
1355 static struct pivot_cell *
1356 pivot_table_lookup_cell__ (const struct pivot_table *table,
1357                             const size_t *dindexes, unsigned int hash)
1358 {
1359   struct pivot_cell *cell;
1360   HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
1361                            &table->cells)
1362     if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
1363       return cell;
1364   return false;
1365 }
1366
1367 static struct pivot_cell *
1368 pivot_cell_allocate (size_t n_idx)
1369 {
1370   struct pivot_cell *cell UNUSED;
1371   return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
1372 }
1373
1374 static struct pivot_cell *
1375 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
1376 {
1377   unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1378   struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
1379   if (!cell)
1380     {
1381       cell = pivot_cell_allocate (table->n_dimensions);
1382       for (size_t i = 0; i < table->n_dimensions; i++)
1383         cell->idx[i] = dindexes[i];
1384       cell->value = NULL;
1385       hmap_insert (&table->cells, &cell->hmap_node, hash);
1386     }
1387   return cell;
1388 }
1389
1390 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
1391    DINDEXES.  N must be the number of dimensions in TABLE.  Takes ownership of
1392    VALUE.
1393
1394    If VALUE is a numeric value without a specified format, this function checks
1395    each of the categories designated by DINDEXES[] and takes the format from
1396    the first category with a result class.  If none has a result class, uses
1397    the overall default numeric format. */
1398 void
1399 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
1400                  struct pivot_value *value)
1401 {
1402   assert (n == table->n_dimensions);
1403   for (size_t i = 0; i < n; i++)
1404     assert (dindexes[i] < table->dimensions[i]->n_leaves);
1405
1406   if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
1407     {
1408       for (size_t i = 0; i < table->n_dimensions; i++)
1409         {
1410           const struct pivot_dimension *d = table->dimensions[i];
1411           if (dindexes[i] < d->n_leaves)
1412             {
1413               const struct pivot_category *c = d->data_leaves[dindexes[i]];
1414               if (c->format.w)
1415                 {
1416                   value->numeric.format = c->format;
1417                   goto done;
1418                 }
1419             }
1420         }
1421       value->numeric.format = *settings_get_format ();
1422
1423     done:;
1424     }
1425
1426   struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1427   pivot_value_destroy (cell->value);
1428   cell->value = value;
1429 }
1430
1431 /* Puts VALUE in the cell in TABLE with index IDX1.  TABLE must have 1
1432    dimension.  Takes ownership of VALUE.  */
1433 void
1434 pivot_table_put1 (struct pivot_table *table, size_t idx1,
1435                   struct pivot_value *value)
1436 {
1437   size_t dindexes[] = { idx1 };
1438   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1439 }
1440
1441 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2).  TABLE must have 2
1442    dimensions.  Takes ownership of VALUE.  */
1443 void
1444 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
1445                   struct pivot_value *value)
1446 {
1447   size_t dindexes[] = { idx1, idx2 };
1448   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1449 }
1450
1451 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3).  TABLE must
1452    have 3 dimensions.  Takes ownership of VALUE.  */
1453 void
1454 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
1455                   size_t idx3, struct pivot_value *value)
1456 {
1457   size_t dindexes[] = { idx1, idx2, idx3 };
1458   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1459 }
1460
1461 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4).  TABLE
1462    must have 4 dimensions.  Takes ownership of VALUE.  */
1463 void
1464 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1465                   size_t idx3, size_t idx4, struct pivot_value *value)
1466 {
1467   size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1468   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1469 }
1470
1471 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1472    automatically assigned marker.
1473
1474    The footnote will only appear in output if it is referenced.  Use
1475    pivot_value_add_footnote() to add a reference to the footnote. */
1476 struct pivot_footnote *
1477 pivot_table_create_footnote (struct pivot_table *table,
1478                              struct pivot_value *content)
1479 {
1480   return pivot_table_create_footnote__ (table, table->n_footnotes,
1481                                         NULL, content);
1482 }
1483
1484 static struct pivot_value *
1485 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1486 {
1487   char text[INT_BUFSIZE_BOUND (size_t)];
1488   if (show_numeric_markers)
1489     snprintf (text, sizeof text, "%d", idx + 1);
1490   else
1491     str_format_26adic (idx + 1, false, text, sizeof text);
1492   return pivot_value_new_user_text (text, -1);
1493 }
1494
1495 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1496    all lower indexes as a side effect).  If MARKER is nonnull, sets the
1497    footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1498 struct pivot_footnote *
1499 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1500                                struct pivot_value *marker,
1501                                struct pivot_value *content)
1502 {
1503   if (idx >= table->n_footnotes)
1504     {
1505       while (idx >= table->allocated_footnotes)
1506         table->footnotes = x2nrealloc (table->footnotes,
1507                                        &table->allocated_footnotes,
1508                                        sizeof *table->footnotes);
1509       while (idx >= table->n_footnotes)
1510         {
1511           struct pivot_footnote *f = xmalloc (sizeof *f);
1512           f->idx = table->n_footnotes;
1513           f->marker = pivot_make_default_footnote_marker (
1514             f->idx, table->look->show_numeric_markers);
1515           f->content = NULL;
1516           f->show = true;
1517
1518           table->footnotes[table->n_footnotes++] = f;
1519         }
1520     }
1521
1522   struct pivot_footnote *f = table->footnotes[idx];
1523   if (marker)
1524     {
1525       pivot_value_destroy (f->marker);
1526       f->marker = marker;
1527     }
1528   if (content)
1529     {
1530       pivot_value_destroy (f->content);
1531       f->content = content;
1532     }
1533   return f;
1534 }
1535
1536 /* Frees the data owned by F. */
1537 void
1538 pivot_footnote_destroy (struct pivot_footnote *f)
1539 {
1540   if (f)
1541     {
1542       pivot_value_destroy (f->content);
1543       pivot_value_destroy (f->marker);
1544       free (f);
1545     }
1546 }
1547
1548 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1549    indexes for each dimension in TABLE in DINDEXES[]. */
1550 void
1551 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1552                                   const size_t *pindexes[PIVOT_N_AXES],
1553                                   size_t dindexes[/* table->n_dimensions */])
1554 {
1555   for (size_t i = 0; i < PIVOT_N_AXES; i++)
1556     {
1557       const struct pivot_axis *axis = &table->axes[i];
1558
1559       for (size_t j = 0; j < axis->n_dimensions; j++)
1560         {
1561           const struct pivot_dimension *d = axis->dimensions[j];
1562           dindexes[d->top_index]
1563             = d->presentation_leaves[pindexes[i][j]]->data_index;
1564         }
1565     }
1566 }
1567
1568 size_t *
1569 pivot_table_enumerate_axis (const struct pivot_table *table,
1570                             enum pivot_axis_type axis_type,
1571                             const size_t *layer_indexes, bool omit_empty,
1572                             size_t *n)
1573 {
1574   const struct pivot_axis *axis = &table->axes[axis_type];
1575   if (!axis->n_dimensions)
1576     {
1577       size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1578       enumeration[0] = 0;
1579       enumeration[1] = SIZE_MAX;
1580       if (n)
1581         *n = 1;
1582       return enumeration;
1583     }
1584   else if (!axis->extent)
1585     {
1586       size_t *enumeration = xmalloc (sizeof *enumeration);
1587       *enumeration = SIZE_MAX;
1588       if (n)
1589         *n = 0;
1590       return enumeration;
1591     }
1592
1593   size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1594                                                 axis->n_dimensions), 1),
1595                                   sizeof *enumeration);
1596   size_t *p = enumeration;
1597   size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1598
1599   size_t *axis_indexes;
1600   PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1601     {
1602       if (omit_empty)
1603         {
1604           enum pivot_axis_type axis2_type
1605             = pivot_axis_type_transpose (axis_type);
1606
1607           size_t *axis2_indexes;
1608           PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1609             {
1610               const size_t *pindexes[PIVOT_N_AXES];
1611               pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1612               pindexes[axis_type] = axis_indexes;
1613               pindexes[axis2_type] = axis2_indexes;
1614               pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1615               if (pivot_table_get (table, dindexes))
1616                 goto found;
1617             }
1618           continue;
1619
1620         found:
1621           free (axis2_indexes);
1622         }
1623
1624       memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1625       p += axis->n_dimensions;
1626     }
1627   if (omit_empty && p == enumeration)
1628     {
1629       PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1630         {
1631           memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1632           p += axis->n_dimensions;
1633         }
1634     }
1635   *p = SIZE_MAX;
1636   if (n)
1637     *n = (p - enumeration) / axis->n_dimensions;
1638
1639   free (dindexes);
1640   return enumeration;
1641 }
1642
1643 static struct pivot_cell *
1644 pivot_table_lookup_cell (const struct pivot_table *table,
1645                          const size_t *dindexes)
1646 {
1647   unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1648   return pivot_table_lookup_cell__ (table, dindexes, hash);
1649 }
1650
1651 const struct pivot_value *
1652 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1653 {
1654   const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1655   return cell ? cell->value : NULL;
1656 }
1657
1658 struct pivot_value *
1659 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1660 {
1661   struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1662   if (!cell->value)
1663     cell->value = pivot_value_new_user_text ("", -1);
1664   return cell->value;
1665 }
1666
1667 static void
1668 pivot_table_delete_cell (struct pivot_table *table, struct pivot_cell *cell)
1669 {
1670   hmap_delete (&table->cells, &cell->hmap_node);
1671   pivot_value_destroy (cell->value);
1672   free (cell);
1673 }
1674
1675 bool
1676 pivot_table_delete (struct pivot_table *table, const size_t *dindexes)
1677 {
1678   struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1679   if (cell)
1680     {
1681       pivot_table_delete_cell (table, cell);
1682       return true;
1683     }
1684   else
1685     return false;
1686 }
1687
1688 static void
1689 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1690 {
1691   if (pivot_category_is_group (category) && category->n_subs)
1692     for (size_t i = 0; i < category->n_subs; i++)
1693       distribute_extra_depth (category->subs[i], extra_depth);
1694   else
1695     category->extra_depth += extra_depth;
1696 }
1697
1698 static void
1699 pivot_category_assign_label_depth (struct pivot_category *category,
1700                                    bool dimension_labels_in_corner)
1701 {
1702   category->extra_depth = 0;
1703
1704   if (pivot_category_is_group (category))
1705     {
1706       size_t depth = 0;
1707       for (size_t i = 0; i < category->n_subs; i++)
1708         {
1709           pivot_category_assign_label_depth (category->subs[i], false);
1710           depth = MAX (depth, category->subs[i]->label_depth);
1711         }
1712
1713       for (size_t i = 0; i < category->n_subs; i++)
1714         {
1715           struct pivot_category *sub = category->subs[i];
1716
1717           size_t extra_depth = depth - sub->label_depth;
1718           if (extra_depth)
1719             distribute_extra_depth (sub, extra_depth);
1720
1721           sub->label_depth = depth;
1722         }
1723
1724       category->show_label_in_corner = (category->show_label
1725                                         && dimension_labels_in_corner);
1726       category->label_depth
1727         = (category->show_label && !category->show_label_in_corner
1728            ? depth + 1 : depth);
1729     }
1730   else
1731     category->label_depth = 1;
1732 }
1733
1734 static bool
1735 pivot_axis_assign_label_depth (struct pivot_table *table,
1736                              enum pivot_axis_type axis_type,
1737                              bool dimension_labels_in_corner)
1738 {
1739   struct pivot_axis *axis = &table->axes[axis_type];
1740   bool any_label_shown_in_corner = false;
1741   axis->label_depth = 0;
1742   axis->extent = 1;
1743   for (size_t i = 0; i < axis->n_dimensions; i++)
1744     {
1745       struct pivot_dimension *d = axis->dimensions[i];
1746       pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1747       d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1748       axis->label_depth += d->label_depth;
1749       axis->extent *= d->n_leaves;
1750
1751       if (d->root->show_label_in_corner)
1752         any_label_shown_in_corner = true;
1753     }
1754   return any_label_shown_in_corner;
1755 }
1756
1757 void
1758 pivot_table_assign_label_depth (struct pivot_table *table)
1759 {
1760   pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1761   if (pivot_axis_assign_label_depth (
1762         table, PIVOT_AXIS_ROW, (table->look->row_labels_in_corner
1763                                 && !table->corner_text))
1764       && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1765     table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1766   pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1767 }
1768 \f
1769 static void
1770 indent (int indentation)
1771 {
1772   for (int i = 0; i < indentation * 2; i++)
1773     putchar (' ');
1774 }
1775
1776 static void
1777 pivot_value_dump (const struct pivot_value *value,
1778                   const struct pivot_table *pt)
1779 {
1780   char *s = pivot_value_to_string (value, pt);
1781   fputs (s, stdout);
1782   free (s);
1783 }
1784
1785 static void
1786 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1787                         const struct pivot_table *pt, int indentation)
1788 {
1789   if (value)
1790     {
1791       indent (indentation);
1792       printf ("%s: ", name);
1793       pivot_value_dump (value, pt);
1794       putchar ('\n');
1795     }
1796 }
1797
1798 static void
1799 pivot_table_dump_string (const char *string, const char *name, int indentation)
1800 {
1801   if (string)
1802     {
1803       indent (indentation);
1804       printf ("%s: %s\n", name, string);
1805     }
1806 }
1807
1808 static void
1809 pivot_category_dump (const struct pivot_category *c,
1810                      const struct pivot_table *pt, int indentation)
1811 {
1812   indent (indentation);
1813   printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1814   pivot_value_dump (c->name, pt);
1815   printf ("\" ");
1816
1817   if (pivot_category_is_leaf (c))
1818     printf ("data_index=%zu\n", c->data_index);
1819   else
1820     {
1821       printf (" (label %s)", c->show_label ? "shown" : "hidden");
1822       printf ("\n");
1823
1824       for (size_t i = 0; i < c->n_subs; i++)
1825         pivot_category_dump (c->subs[i], pt, indentation + 1);
1826     }
1827 }
1828
1829 void
1830 pivot_dimension_dump (const struct pivot_dimension *d,
1831                       const struct pivot_table *pt, int indentation)
1832 {
1833   indent (indentation);
1834   printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1835           pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1836
1837   pivot_category_dump (d->root, pt, indentation + 1);
1838 }
1839
1840 static void
1841 table_area_style_dump (enum pivot_area area, const struct table_area_style *a,
1842                        int indentation)
1843 {
1844   indent (indentation);
1845   printf ("%s: ", pivot_area_to_string (area));
1846   font_style_dump (&a->font_style);
1847   putchar (' ');
1848   cell_style_dump (&a->cell_style);
1849   putchar ('\n');
1850 }
1851
1852 static void
1853 table_border_style_dump (enum pivot_border border,
1854                          const struct table_border_style *b, int indentation)
1855 {
1856   indent (indentation);
1857   printf ("%s: %s ", pivot_border_to_string (border),
1858           table_stroke_to_string (b->stroke));
1859   cell_color_dump (&b->color);
1860   putchar ('\n');
1861 }
1862
1863 static char ***
1864 compose_headings (const struct pivot_table *pt,
1865                   const struct pivot_axis *axis,
1866                   const size_t *column_enumeration)
1867 {
1868   if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1869     return NULL;
1870
1871   char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1872   for (size_t i = 0; i < axis->label_depth; i++)
1873     headings[i] = xcalloc (axis->extent, sizeof **headings);
1874
1875   const size_t *indexes;
1876   size_t column = 0;
1877   PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1878     {
1879       int row = axis->label_depth - 1;
1880       for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1881         {
1882           const struct pivot_dimension *d = axis->dimensions[dim_index];
1883           if (d->hide_all_labels)
1884             continue;
1885           for (const struct pivot_category *c
1886                  = d->presentation_leaves[indexes[dim_index]];
1887                c;
1888                c = c->parent)
1889             {
1890               if (pivot_category_is_leaf (c) || (c->show_label
1891                                                  && !c->show_label_in_corner))
1892                 {
1893                   headings[row][column] = pivot_value_to_string (c->name, pt);
1894                   if (!*headings[row][column])
1895                     headings[row][column] = xstrdup ("<blank>");
1896                   row--;
1897                 }
1898             }
1899         }
1900       column++;
1901     }
1902
1903   return headings;
1904 }
1905
1906 static void
1907 free_headings (const struct pivot_axis *axis, char ***headings)
1908 {
1909   for (size_t i = 0; i < axis->label_depth; i++)
1910     {
1911       for (size_t j = 0; j < axis->extent; j++)
1912         free (headings[i][j]);
1913       free (headings[i]);
1914     }
1915   free (headings);
1916 }
1917
1918 static void
1919 pivot_table_sizing_dump (const char *name,
1920                          const int width_ranges[2],
1921                          const struct pivot_table_sizing *s,
1922                          int indentation)
1923 {
1924   indent (indentation);
1925   printf ("%ss: min=%d, max=%d\n", name, width_ranges[0], width_ranges[1]);
1926   if (s->n_widths)
1927     {
1928       indent (indentation + 1);
1929       printf ("%s widths:", name);
1930       for (size_t i = 0; i < s->n_widths; i++)
1931         printf (" %d", s->widths[i]);
1932       printf ("\n");
1933     }
1934   if (s->n_breaks)
1935     {
1936       indent (indentation + 1);
1937       printf ("break after %ss:", name);
1938       for (size_t i = 0; i < s->n_breaks; i++)
1939         printf (" %zu", s->breaks[i]);
1940       printf ("\n");
1941     }
1942   if (s->n_keeps)
1943     {
1944       indent (indentation + 1);
1945       printf ("keep %ss together:", name);
1946       for (size_t i = 0; i < s->n_keeps; i++)
1947         printf (" [%zu,%zu]",
1948                 s->keeps[i].ofs,
1949                 s->keeps[i].ofs + s->keeps[i].n - 1);
1950       printf ("\n");
1951     }
1952 }
1953
1954 void
1955 pivot_table_dump (const struct pivot_table *table, int indentation)
1956 {
1957   if (!table)
1958     return;
1959
1960   pivot_table_assign_label_depth (CONST_CAST (struct pivot_table *, table));
1961
1962   pivot_table_dump_value (table->title, "title", table, indentation);
1963   pivot_table_dump_value (table->subtype, "subtype", table, indentation);
1964   pivot_table_dump_string (table->command_c, "command", indentation);
1965   pivot_table_dump_string (table->dataset, "dataset", indentation);
1966   pivot_table_dump_string (table->datafile, "datafile", indentation);
1967   pivot_table_dump_string (table->notes, "notes", indentation);
1968   pivot_table_dump_string (table->look->name, "table-look", indentation);
1969   if (table->date)
1970     {
1971       indent (indentation);
1972
1973       struct tm *tm = localtime (&table->date);
1974       printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
1975               tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
1976               tm->tm_sec);
1977     }
1978
1979   indent (indentation);
1980   printf ("sizing:\n");
1981   pivot_table_sizing_dump ("column", table->look->width_ranges[TABLE_HORZ],
1982                            &table->sizing[TABLE_HORZ], indentation + 1);
1983   pivot_table_sizing_dump ("row", table->look->width_ranges[TABLE_VERT],
1984                            &table->sizing[TABLE_VERT], indentation + 1);
1985
1986   indent (indentation);
1987   printf ("areas:\n");
1988   for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1989     table_area_style_dump (area, &table->look->areas[area], indentation + 1);
1990
1991   indent (indentation);
1992   printf ("borders:\n");
1993   for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1994     table_border_style_dump (border, &table->look->borders[border],
1995                              indentation + 1);
1996
1997   for (size_t i = 0; i < table->n_dimensions; i++)
1998     pivot_dimension_dump (table->dimensions[i], table, indentation);
1999
2000   /* Presentation and data indexes. */
2001   size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
2002
2003   const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
2004   if (layer_axis->n_dimensions)
2005     {
2006       indent (indentation);
2007       printf ("current layer:");
2008
2009       for (size_t i = 0; i < layer_axis->n_dimensions; i++)
2010         {
2011           const struct pivot_dimension *d = layer_axis->dimensions[i];
2012           char *name = pivot_value_to_string (d->root->name, table);
2013           char *value = pivot_value_to_string (
2014             d->data_leaves[table->current_layer[i]]->name, table);
2015           printf (" %s=%s", name, value);
2016           free (value);
2017           free (name);
2018         }
2019
2020       putchar ('\n');
2021     }
2022
2023   size_t *layer_indexes;
2024   size_t layer_iteration = 0;
2025   PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
2026     {
2027       indent (indentation);
2028       printf ("layer %zu:", layer_iteration++);
2029
2030       const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
2031       for (size_t i = 0; i < layer_axis->n_dimensions; i++)
2032         {
2033           const struct pivot_dimension *d = layer_axis->dimensions[i];
2034
2035           fputs (i == 0 ? " " : ", ", stdout);
2036           pivot_value_dump (d->root->name, table);
2037           fputs (" =", stdout);
2038
2039           struct pivot_value **names = xnmalloc (d->n_leaves, sizeof *names);
2040           size_t n_names = 0;
2041           for (const struct pivot_category *c
2042                  = d->presentation_leaves[layer_indexes[i]];
2043                c;
2044                c = c->parent)
2045             {
2046               if (pivot_category_is_leaf (c) || c->show_label)
2047                 names[n_names++] = c->name;
2048             }
2049
2050           for (size_t i = n_names; i-- > 0;)
2051             {
2052               putchar (' ');
2053               pivot_value_dump (names[i], table);
2054             }
2055           free (names);
2056         }
2057       putchar ('\n');
2058
2059       size_t *column_enumeration = pivot_table_enumerate_axis (
2060         table, PIVOT_AXIS_COLUMN, layer_indexes, table->look->omit_empty, NULL);
2061       size_t *row_enumeration = pivot_table_enumerate_axis (
2062         table, PIVOT_AXIS_ROW, layer_indexes, table->look->omit_empty, NULL);
2063
2064       char ***column_headings = compose_headings (
2065         table, &table->axes[PIVOT_AXIS_COLUMN], column_enumeration);
2066       for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
2067         {
2068           indent (indentation + 1);
2069           for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
2070             {
2071               if (x)
2072                 fputs ("; ", stdout);
2073               if (column_headings[y][x])
2074                 fputs (column_headings[y][x], stdout);
2075             }
2076           putchar ('\n');
2077         }
2078       free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
2079
2080       indent (indentation + 1);
2081       printf ("-----------------------------------------------\n");
2082
2083       char ***row_headings = compose_headings (
2084         table, &table->axes[PIVOT_AXIS_ROW], row_enumeration);
2085
2086       size_t x = 0;
2087       const size_t *pindexes[PIVOT_N_AXES]
2088         = { [PIVOT_AXIS_LAYER] = layer_indexes };
2089       PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
2090                                   &table->axes[PIVOT_AXIS_ROW])
2091         {
2092           indent (indentation + 1);
2093
2094           size_t i = 0;
2095           for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
2096             {
2097               if (i++)
2098                 fputs ("; ", stdout);
2099               if (row_headings[y][x])
2100                 fputs (row_headings[y][x], stdout);
2101             }
2102
2103           printf (" | ");
2104
2105           i = 0;
2106           PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
2107                                       column_enumeration,
2108                                       &table->axes[PIVOT_AXIS_COLUMN])
2109             {
2110               if (i++)
2111                 printf ("; ");
2112
2113               pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
2114               const struct pivot_value *value = pivot_table_get (
2115                 table, dindexes);
2116               if (value)
2117                 pivot_value_dump (value, table);
2118             }
2119           printf ("\n");
2120
2121           x++;
2122         }
2123
2124       free (column_enumeration);
2125       free (row_enumeration);
2126       free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
2127     }
2128
2129   pivot_table_dump_value (table->caption, "caption", table, indentation);
2130
2131   for (size_t i = 0; i < table->n_footnotes; i++)
2132     {
2133       const struct pivot_footnote *f = table->footnotes[i];
2134       indent (indentation);
2135       putchar ('[');
2136       if (f->marker)
2137         pivot_value_dump (f->marker, table);
2138       else
2139         printf ("%zu", f->idx);
2140       putchar (']');
2141       pivot_value_dump (f->content, table);
2142       putchar ('\n');
2143     }
2144
2145   free (dindexes);
2146 }
2147 \f
2148 static const char *
2149 consume_int (const char *p, size_t *n)
2150 {
2151   *n = 0;
2152   while (c_isdigit (*p))
2153     *n = *n * 10 + (*p++ - '0');
2154   return p;
2155 }
2156
2157 static size_t
2158 pivot_format_inner_template (struct string *out, const char *template,
2159                              char escape,
2160                              struct pivot_value **values, size_t n_values,
2161                              const struct pivot_table *pt)
2162 {
2163   size_t args_consumed = 0;
2164   while (*template && *template != ':')
2165     {
2166       if (*template == '\\' && template[1])
2167         {
2168           ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
2169           template += 2;
2170         }
2171       else if (*template == escape)
2172         {
2173           size_t index;
2174           template = consume_int (template + 1, &index);
2175           if (index >= 1 && index <= n_values)
2176             {
2177               pivot_value_format (values[index - 1], pt, out);
2178               args_consumed = MAX (args_consumed, index);
2179             }
2180         }
2181       else
2182         ds_put_byte (out, *template++);
2183     }
2184   return args_consumed;
2185 }
2186
2187 static const char *
2188 pivot_extract_inner_template (const char *template, const char **p)
2189 {
2190   *p = template;
2191
2192   for (;;)
2193     {
2194       if (*template == '\\' && template[1] != '\0')
2195         template += 2;
2196       else if (*template == ':')
2197         return template + 1;
2198       else if (*template == '\0')
2199         return template;
2200       else
2201         template++;
2202     }
2203 }
2204
2205 static void
2206 pivot_format_template (struct string *out, const char *template,
2207                        const struct pivot_argument *args, size_t n_args,
2208                        const struct pivot_table *pt)
2209 {
2210   while (*template)
2211     {
2212       if (*template == '\\' && template[1] != '\0')
2213         {
2214           ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
2215           template += 2;
2216         }
2217       else if (*template == '^')
2218         {
2219           size_t index;
2220           template = consume_int (template + 1, &index);
2221           if (index >= 1 && index <= n_args && args[index - 1].n > 0)
2222             pivot_value_format (args[index - 1].values[0], pt, out);
2223         }
2224       else if (*template == '[')
2225         {
2226           const char *tmpl[2];
2227           template = pivot_extract_inner_template (template + 1, &tmpl[0]);
2228           template = pivot_extract_inner_template (template, &tmpl[1]);
2229           template += *template == ']';
2230
2231           size_t index;
2232           template = consume_int (template, &index);
2233           if (index < 1 || index > n_args)
2234             continue;
2235
2236           const struct pivot_argument *arg = &args[index - 1];
2237           size_t left = arg->n;
2238           while (left)
2239             {
2240               struct pivot_value **values = arg->values + (arg->n - left);
2241               int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
2242               char escape = "%^"[tmpl_idx];
2243               size_t used = pivot_format_inner_template (
2244                 out, tmpl[tmpl_idx], escape, values, left, pt);
2245               if (!used || used > left)
2246                 break;
2247               left -= used;
2248             }
2249         }
2250       else
2251         ds_put_byte (out, *template++);
2252     }
2253 }
2254
2255 static enum settings_value_show
2256 interpret_show (enum settings_value_show global_show,
2257                 enum settings_value_show table_show,
2258                 enum settings_value_show value_show,
2259                 bool has_label)
2260 {
2261   return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
2262           : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
2263           : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
2264           : global_show);
2265 }
2266
2267 /* Appends a text representation of the body of VALUE to OUT.  Settings on
2268    PT control whether variable and value labels are included.
2269
2270    The "body" omits subscripts and superscripts and footnotes.
2271
2272    Returns true if OUT is a number (or a number plus a value label), false
2273    otherwise.  */
2274 bool
2275 pivot_value_format_body (const struct pivot_value *value,
2276                          const struct pivot_table *pt,
2277                          struct string *out)
2278 {
2279   enum settings_value_show show;
2280   bool numeric = false;
2281
2282   switch (value->type)
2283     {
2284     case PIVOT_VALUE_NUMERIC:
2285       show = interpret_show (settings_get_show_values (),
2286                              pt->show_values,
2287                              value->numeric.show,
2288                              value->numeric.value_label != NULL);
2289       if (show & SETTINGS_VALUE_SHOW_VALUE)
2290         {
2291           char *s = data_out (&(union value) { .f = value->numeric.x },
2292                               "UTF-8", &value->numeric.format, &pt->settings);
2293           ds_put_cstr (out, s + strspn (s, " "));
2294           free (s);
2295         }
2296       if (show & SETTINGS_VALUE_SHOW_LABEL)
2297         {
2298           if (show & SETTINGS_VALUE_SHOW_VALUE)
2299             ds_put_byte (out, ' ');
2300           ds_put_cstr (out, value->numeric.value_label);
2301         }
2302       numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
2303       break;
2304
2305     case PIVOT_VALUE_STRING:
2306       show = interpret_show (settings_get_show_values (),
2307                              pt->show_values,
2308                              value->string.show,
2309                              value->string.value_label != NULL);
2310       if (show & SETTINGS_VALUE_SHOW_VALUE)
2311         {
2312           if (value->string.hex)
2313             {
2314               for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
2315                    *p; p++)
2316                 ds_put_format (out, "%02X", *p);
2317             }
2318           else
2319             ds_put_cstr (out, value->string.s);
2320         }
2321       if (show & SETTINGS_VALUE_SHOW_LABEL)
2322         {
2323           if (show & SETTINGS_VALUE_SHOW_VALUE)
2324             ds_put_byte (out, ' ');
2325           ds_put_cstr (out, value->string.value_label);
2326         }
2327       break;
2328
2329     case PIVOT_VALUE_VARIABLE:
2330       show = interpret_show (settings_get_show_variables (),
2331                              pt->show_variables,
2332                              value->variable.show,
2333                              value->variable.var_label != NULL);
2334       if (show & SETTINGS_VALUE_SHOW_VALUE)
2335         ds_put_cstr (out, value->variable.var_name);
2336       if (show & SETTINGS_VALUE_SHOW_LABEL)
2337         {
2338           if (show & SETTINGS_VALUE_SHOW_VALUE)
2339             ds_put_byte (out, ' ');
2340           ds_put_cstr (out, value->variable.var_label);
2341         }
2342       break;
2343
2344     case PIVOT_VALUE_TEXT:
2345       ds_put_cstr (out, value->text.local);
2346       break;
2347
2348     case PIVOT_VALUE_TEMPLATE:
2349       pivot_format_template (out, value->template.local, value->template.args,
2350                              value->template.n_args, pt);
2351       break;
2352     }
2353
2354   return numeric;
2355 }
2356
2357 /* Appends a text representation of VALUE to OUT.  Settings on
2358    PT control whether variable and value labels are included.
2359
2360    Subscripts and footnotes are included. */
2361 void
2362 pivot_value_format (const struct pivot_value *value,
2363                     const struct pivot_table *pt,
2364                     struct string *out)
2365 {
2366   pivot_value_format_body (value, pt, out);
2367
2368   if (value->n_subscripts)
2369     {
2370       for (size_t i = 0; i < value->n_subscripts; i++)
2371         ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
2372     }
2373
2374   for (size_t i = 0; i < value->n_footnotes; i++)
2375     {
2376       ds_put_byte (out, '[');
2377
2378       size_t idx = value->footnote_indexes[i];
2379       const struct pivot_footnote *f = pt->footnotes[idx];
2380       pivot_value_format (f->marker, pt, out);
2381
2382       ds_put_byte (out, ']');
2383     }
2384 }
2385
2386 /* Returns a text representation of VALUE.  The caller must free the string,
2387    with free(). */
2388 char *
2389 pivot_value_to_string (const struct pivot_value *value,
2390                        const struct pivot_table *pt)
2391 {
2392   struct string s = DS_EMPTY_INITIALIZER;
2393   pivot_value_format (value, pt, &s);
2394   return ds_steal_cstr (&s);
2395 }
2396
2397 char *
2398 pivot_value_to_string_defaults (const struct pivot_value *value)
2399 {
2400   static const struct pivot_table pt = {
2401     .show_values = SETTINGS_VALUE_SHOW_DEFAULT,
2402     .show_variables = SETTINGS_VALUE_SHOW_DEFAULT,
2403   };
2404   return pivot_value_to_string (value, &pt);
2405 }
2406
2407 struct pivot_value *
2408 pivot_value_clone (const struct pivot_value *old)
2409 {
2410   if (!old)
2411     return NULL;
2412
2413   struct pivot_value *new = xmemdup (old, sizeof *new);
2414   if (old->font_style)
2415     {
2416       new->font_style = xmalloc (sizeof *new->font_style);
2417       font_style_copy (NULL, new->font_style, old->font_style);
2418     }
2419   if (old->cell_style)
2420     new->font_style = xmemdup (old->font_style, sizeof *new->font_style);
2421   if (old->n_subscripts)
2422     {
2423       new->subscripts = xnmalloc (old->n_subscripts, sizeof *new->subscripts);
2424       for (size_t i = 0; i < old->n_subscripts; i++)
2425         new->subscripts[i] = xstrdup (old->subscripts[i]);
2426     }
2427   if (old->n_footnotes)
2428     new->footnote_indexes = xmemdup (
2429       old->footnote_indexes, old->n_footnotes * sizeof *new->footnote_indexes);
2430
2431   switch (new->type)
2432     {
2433     case PIVOT_VALUE_NUMERIC:
2434       new->numeric.var_name = xstrdup_if_nonnull (new->numeric.var_name);
2435       new->numeric.value_label = xstrdup_if_nonnull (new->numeric.value_label);
2436       break;
2437
2438     case PIVOT_VALUE_STRING:
2439       new->string.s = xstrdup (new->string.s);
2440       new->string.var_name = xstrdup_if_nonnull (new->string.var_name);
2441       new->string.value_label = xstrdup_if_nonnull (new->string.value_label);
2442       break;
2443
2444     case PIVOT_VALUE_VARIABLE:
2445       new->variable.var_name = xstrdup_if_nonnull (new->variable.var_name);
2446       new->variable.var_label = xstrdup_if_nonnull (new->variable.var_label);
2447       break;
2448
2449     case PIVOT_VALUE_TEXT:
2450       new->text.local = xstrdup (old->text.local);
2451       new->text.c = (old->text.c == old->text.local ? new->text.local
2452                      : xstrdup (old->text.c));
2453       new->text.id = (old->text.id == old->text.local ? new->text.local
2454                       : old->text.id == old->text.c ? new->text.c
2455                       : xstrdup (old->text.id));
2456       break;
2457
2458     case PIVOT_VALUE_TEMPLATE:
2459       new->template.local = xstrdup (old->template.local);
2460       new->template.id = (old->template.id == old->template.local
2461                           ? new->template.local
2462                           : xstrdup (old->template.id));
2463       new->template.args = xmalloc (new->template.n_args
2464                                     * sizeof *new->template.args);
2465       for (size_t i = 0; i < old->template.n_args; i++)
2466         pivot_argument_copy (&new->template.args[i],
2467                              &old->template.args[i]);
2468       break;
2469
2470     default:
2471       NOT_REACHED ();
2472     }
2473   return new;
2474 }
2475
2476 /* Frees the data owned by V. */
2477 void
2478 pivot_value_destroy (struct pivot_value *value)
2479 {
2480   if (value)
2481     {
2482       font_style_uninit (value->font_style);
2483       free (value->font_style);
2484       free (value->cell_style);
2485       free (value->footnote_indexes);
2486
2487       for (size_t i = 0; i < value->n_subscripts; i++)
2488         free (value->subscripts[i]);
2489       free (value->subscripts);
2490
2491       switch (value->type)
2492         {
2493         case PIVOT_VALUE_NUMERIC:
2494           free (value->numeric.var_name);
2495           free (value->numeric.value_label);
2496           break;
2497
2498         case PIVOT_VALUE_STRING:
2499           free (value->string.s);
2500           free (value->string.var_name);
2501           free (value->string.value_label);
2502           break;
2503
2504         case PIVOT_VALUE_VARIABLE:
2505           free (value->variable.var_name);
2506           free (value->variable.var_label);
2507           break;
2508
2509         case PIVOT_VALUE_TEXT:
2510           free (value->text.local);
2511           if (value->text.c != value->text.local)
2512             free (value->text.c);
2513           if (value->text.id != value->text.local
2514               && value->text.id != value->text.c)
2515             free (value->text.id);
2516           break;
2517
2518         case PIVOT_VALUE_TEMPLATE:
2519           free (value->template.local);
2520           if (value->template.id != value->template.local)
2521             free (value->template.id);
2522           for (size_t i = 0; i < value->template.n_args; i++)
2523             pivot_argument_uninit (&value->template.args[i]);
2524           free (value->template.args);
2525           break;
2526
2527         default:
2528           NOT_REACHED ();
2529         }
2530       free (value);
2531     }
2532 }
2533
2534 /* Sets AREA to the style to use for VALUE, with defaults coming from
2535    DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
2536 void
2537 pivot_value_get_style (struct pivot_value *value,
2538                        const struct font_style *base_font_style,
2539                        const struct cell_style *base_cell_style,
2540                        struct table_area_style *area)
2541 {
2542   font_style_copy (NULL, &area->font_style, (value->font_style
2543                                              ? value->font_style
2544                                              : base_font_style));
2545   area->cell_style = *(value->cell_style
2546                        ? value->cell_style
2547                        : base_cell_style);
2548 }
2549
2550 /* Copies AREA into VALUE's style. */
2551 void
2552 pivot_value_set_style (struct pivot_value *value,
2553                        const struct table_area_style *area)
2554 {
2555   pivot_value_set_font_style (value, &area->font_style);
2556   pivot_value_set_cell_style (value, &area->cell_style);
2557 }
2558
2559 void
2560 pivot_value_set_font_style (struct pivot_value *value,
2561                             const struct font_style *font_style)
2562 {
2563   if (value->font_style)
2564     font_style_uninit (value->font_style);
2565   else
2566     value->font_style = xmalloc (sizeof *value->font_style);
2567   font_style_copy (NULL, value->font_style, font_style);
2568 }
2569
2570 void
2571 pivot_value_set_cell_style (struct pivot_value *value,
2572                             const struct cell_style *cell_style)
2573 {
2574   if (!value->cell_style)
2575     value->cell_style = xmalloc (sizeof *value->cell_style);
2576   *value->cell_style = *cell_style;
2577 }
2578
2579 void
2580 pivot_argument_copy (struct pivot_argument *dst,
2581                      const struct pivot_argument *src)
2582 {
2583   *dst = (struct pivot_argument) {
2584     .n = src->n,
2585     .values = xmalloc (src->n * sizeof *dst->values),
2586   };
2587
2588   for (size_t i = 0; i < src->n; i++)
2589     dst->values[i] = pivot_value_clone (src->values[i]);
2590 }
2591
2592 /* Frees the data owned by ARG (but not ARG itself). */
2593 void
2594 pivot_argument_uninit (struct pivot_argument *arg)
2595 {
2596   if (arg)
2597     {
2598       for (size_t i = 0; i < arg->n; i++)
2599         pivot_value_destroy (arg->values[i]);
2600       free (arg->values);
2601     }
2602 }
2603
2604 /* Creates and returns a new pivot_value whose contents is the null-terminated
2605    string TEXT.  Takes ownership of TEXT.
2606
2607    This function is for text strings provided by the user (with the exception
2608    that pivot_value_new_variable() should be used for variable names).  For
2609    strings that are part of the PSPP user interface, such as names of
2610    procedures, statistics, annotations, error messages, etc., use
2611    pivot_value_new_text(). */
2612 struct pivot_value *
2613 pivot_value_new_user_text_nocopy (char *text)
2614 {
2615   struct pivot_value *value = xmalloc (sizeof *value);
2616   *value = (struct pivot_value) {
2617     .type = PIVOT_VALUE_TEXT,
2618     .text = {
2619       .local = text,
2620       .c = text,
2621       .id = text,
2622       .user_provided = true,
2623     }
2624   };
2625   return value;
2626 }
2627
2628 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2629    TEXT.  Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2630    in advance.
2631
2632    This function is for text strings provided by the user (with the exception
2633    that pivot_value_new_variable() should be used for variable names).  For
2634    strings that are part of the PSPP user interface, such as names of
2635    procedures, statistics, annotations, error messages, etc., use
2636    pivot_value_new_text().j
2637
2638    The caller retains ownership of TEXT.*/
2639 struct pivot_value *
2640 pivot_value_new_user_text (const char *text, size_t length)
2641 {
2642   return pivot_value_new_user_text_nocopy (
2643     xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2644 }
2645
2646 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2647    a translatable string, but not actually translated yet, e.g. enclosed in
2648    N_().  This function is for text strings that are part of the PSPP user
2649    interface, such as names of procedures, statistics, annotations, error
2650    messages, etc.  For strings that come from the user, use
2651    pivot_value_new_user_text(). */
2652 struct pivot_value *
2653 pivot_value_new_text (const char *text)
2654 {
2655   char *c = xstrdup (text);
2656   char *local = xstrdup (gettext (c));
2657
2658   struct pivot_value *value = xmalloc (sizeof *value);
2659   *value = (struct pivot_value) {
2660     .type = PIVOT_VALUE_TEXT,
2661     .text = {
2662       .local = local,
2663       .c = c,
2664       .id = c,
2665       .user_provided = false,
2666     }
2667   };
2668   return value;
2669 }
2670
2671 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2672    string. */
2673 struct pivot_value * PRINTF_FORMAT (1, 2)
2674 pivot_value_new_text_format (const char *format, ...)
2675 {
2676   va_list args;
2677   va_start (args, format);
2678   char *c = xvasprintf (format, args);
2679   va_end (args);
2680
2681   va_start (args, format);
2682   char *local = xvasprintf (gettext (format), args);
2683   va_end (args);
2684
2685   struct pivot_value *value = xmalloc (sizeof *value);
2686   *value = (struct pivot_value) {
2687     .type = PIVOT_VALUE_TEXT,
2688     .text = {
2689       .local = local,
2690       .c = c,
2691       .id = xstrdup (c),
2692       .user_provided = false,
2693     }
2694   };
2695   return value;
2696 }
2697
2698 /* Returns a new pivot_value that represents X.
2699
2700    The format to use for X is unspecified.  Usually the easiest way to specify
2701    a format is through assigning a result class to one of the categories that
2702    the pivot_value will end up in.  If that is not suitable, then the caller
2703    can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2704 struct pivot_value *
2705 pivot_value_new_number (double x)
2706 {
2707   struct pivot_value *value = xmalloc (sizeof *value);
2708   *value = (struct pivot_value) {
2709     .type = PIVOT_VALUE_NUMERIC,
2710     .numeric = { .x = x, },
2711   };
2712   return value;
2713 }
2714
2715 /* Returns a new pivot_value that represents X, formatted as an integer. */
2716 struct pivot_value *
2717 pivot_value_new_integer (double x)
2718 {
2719   struct pivot_value *value = pivot_value_new_number (x);
2720   value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2721   return value;
2722 }
2723
2724 /* Returns a new pivot_value that represents VALUE, formatted as for
2725    VARIABLE. */
2726 struct pivot_value *
2727 pivot_value_new_var_value (const struct variable *variable,
2728                            const union value *value)
2729 {
2730   struct pivot_value *pv = pivot_value_new_value (
2731     value, var_get_width (variable), var_get_print_format (variable),
2732     var_get_encoding (variable));
2733
2734   char *var_name = xstrdup (var_get_name (variable));
2735   if (var_is_alpha (variable))
2736     pv->string.var_name = var_name;
2737   else
2738     pv->numeric.var_name = var_name;
2739
2740   const char *label = var_lookup_value_label (variable, value);
2741   if (label)
2742     {
2743       if (var_is_alpha (variable))
2744         pv->string.value_label = xstrdup (label);
2745       else
2746         pv->numeric.value_label = xstrdup (label);
2747     }
2748
2749   return pv;
2750 }
2751
2752 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2753    formatted with FORMAT.  For a string value, ENCODING must be its character
2754    encoding. */
2755 struct pivot_value *
2756 pivot_value_new_value (const union value *value, int width,
2757                        const struct fmt_spec *format, const char *encoding)
2758 {
2759   struct pivot_value *pv = xzalloc (sizeof *pv);
2760   if (width > 0)
2761     {
2762       char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2763                                width);
2764       size_t n = strlen (s);
2765       while (n > 0 && s[n - 1] == ' ')
2766         s[--n] = '\0';
2767
2768       pv->type = PIVOT_VALUE_STRING;
2769       pv->string.s = s;
2770       pv->string.hex = format->type == FMT_AHEX;
2771     }
2772   else
2773     {
2774       pv->type = PIVOT_VALUE_NUMERIC;
2775       pv->numeric.x = value->f;
2776       pv->numeric.format = *format;
2777     }
2778
2779   return pv;
2780 }
2781
2782 /* Returns a new pivot_value for VARIABLE. */
2783 struct pivot_value *
2784 pivot_value_new_variable (const struct variable *variable)
2785 {
2786   struct pivot_value *value = xmalloc (sizeof *value);
2787   *value = (struct pivot_value) {
2788     .type = PIVOT_VALUE_VARIABLE,
2789     .variable = {
2790       .var_name = xstrdup (var_get_name (variable)),
2791       .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2792     },
2793   };
2794   return value;
2795 }
2796
2797 /* Attaches a reference to FOOTNOTE to V. */
2798 void
2799 pivot_value_add_footnote (struct pivot_value *v,
2800                           const struct pivot_footnote *footnote)
2801 {
2802   /* Some legacy tables include numerous duplicate footnotes.  Suppress
2803      them. */
2804   for (size_t i = 0; i < v->n_footnotes; i++)
2805     if (v->footnote_indexes[i] == footnote->idx)
2806       return;
2807
2808   v->footnote_indexes = xrealloc (
2809     v->footnote_indexes, (v->n_footnotes + 1) * sizeof *v->footnote_indexes);
2810   v->footnote_indexes[v->n_footnotes++] = footnote->idx;
2811 }
2812
2813 /* If VALUE is a numeric value, and RC is a result class such as
2814    PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2815 void
2816 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2817                     const char *rc)
2818 {
2819   if (value->type == PIVOT_VALUE_NUMERIC)
2820     {
2821       const struct fmt_spec *f = pivot_table_get_format (table, rc);
2822       if (f)
2823         value->numeric.format = *f;
2824     }
2825 }
2826