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