text-item: Simplify text_item further to just hold a pivot_value.
[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,      { FMT_F,   40, 0 } },
752     { PIVOT_RC_PERCENT,      { FMT_PCT, 40, 1 } },
753     { PIVOT_RC_CORRELATION,  { FMT_F,   40, 3 } },
754     { PIVOT_RC_SIGNIFICANCE, { FMT_F,   40, 3 } },
755     { PIVOT_RC_RESIDUAL,     { FMT_F,   40, 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 (sizeof *table);
869   table->ref_cnt = 1;
870   table->show_title = true;
871   table->show_caption = true;
872   table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
873   table->title = title;
874   table->subtype = subtype ? pivot_value_new_text (subtype) : NULL;
875   table->command_c = 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 char *
917 xstrdup_if_nonnull (const char *s)
918 {
919   return s ? xstrdup (s) : NULL;
920 }
921
922 static struct pivot_table_sizing
923 clone_sizing (const struct pivot_table_sizing *s)
924 {
925   return (struct pivot_table_sizing) {
926     .widths = (s->n_widths
927                ? xmemdup (s->widths, s->n_widths * sizeof *s->widths)
928                : NULL),
929     .n_widths = s->n_widths,
930
931     .breaks = (s->n_breaks
932                ? xmemdup (s->breaks, s->n_breaks * sizeof *s->breaks)
933                : NULL),
934     .n_breaks = s->n_breaks,
935
936     .keeps = (s->n_keeps
937               ? xmemdup (s->keeps, s->n_keeps * sizeof *s->keeps)
938               : NULL),
939     .n_keeps = s->n_keeps,
940   };
941 }
942
943 static struct pivot_footnote **
944 clone_footnotes (struct pivot_footnote **old, size_t n)
945 {
946   if (!n)
947     return NULL;
948
949   struct pivot_footnote **new = xmalloc (n * sizeof *new);
950   for (size_t i = 0; i < n; i++)
951     {
952       new[i] = xmalloc (sizeof *new[i]);
953       *new[i] = (struct pivot_footnote) {
954         .idx = old[i]->idx,
955         .content = pivot_value_clone (old[i]->content),
956         .marker = pivot_value_clone (old[i]->marker),
957         .show = old[i]->show,
958       };
959     }
960   return new;
961 }
962
963 static struct pivot_category *
964 clone_category (struct pivot_category *old,
965                 struct pivot_dimension *new_dimension,
966                 struct pivot_category *new_parent)
967 {
968   struct pivot_category *new = xmalloc (sizeof *new);
969   *new = (struct pivot_category) {
970     .name = pivot_value_clone (old->name),
971     .parent = new_parent,
972     .dimension = new_dimension,
973     .label_depth = old->label_depth,
974     .extra_depth = old->extra_depth,
975
976     .subs = (old->n_subs
977              ? xzalloc (old->n_subs * sizeof *new->subs)
978              : NULL),
979     .n_subs = old->n_subs,
980     .allocated_subs = old->n_subs,
981
982     .show_label = old->show_label,
983     .show_label_in_corner = old->show_label_in_corner,
984
985     .format = old->format,
986     .group_index = old->group_index,
987     .data_index = old->data_index,
988     .presentation_index = old->presentation_index,
989   };
990
991   if (pivot_category_is_leaf (old))
992     {
993       assert (new->data_index < new_dimension->n_leaves);
994       new->dimension->data_leaves[new->data_index] = new;
995
996       assert (new->presentation_index < new_dimension->n_leaves);
997       new->dimension->presentation_leaves[new->presentation_index] = new;
998     }
999
1000   for (size_t i = 0; i < new->n_subs; i++)
1001     new->subs[i] = clone_category (old->subs[i], new_dimension, new);
1002
1003   return new;
1004 }
1005
1006 static struct pivot_dimension *
1007 clone_dimension (struct pivot_dimension *old, struct pivot_table *new_pt)
1008 {
1009   struct pivot_dimension *new = xmalloc (sizeof *new);
1010   *new = (struct pivot_dimension) {
1011     .table = new_pt,
1012     .axis_type = old->axis_type,
1013     .level = old->level,
1014     .top_index = old->top_index,
1015     .data_leaves = xzalloc (old->n_leaves * sizeof *new->data_leaves),
1016     .presentation_leaves = xzalloc (old->n_leaves
1017                                     * sizeof *new->presentation_leaves),
1018     .n_leaves = old->n_leaves,
1019     .allocated_leaves = old->n_leaves,
1020     .hide_all_labels = old->hide_all_labels,
1021     .label_depth = old->label_depth,
1022   };
1023
1024   new->root = clone_category (old->root, new, NULL);
1025
1026   return new;
1027 }
1028
1029 static struct pivot_dimension **
1030 clone_dimensions (struct pivot_dimension **old, size_t n,
1031                   struct pivot_table *new_pt)
1032 {
1033   if (!n)
1034     return NULL;
1035
1036   struct pivot_dimension **new = xmalloc (n * sizeof *new);
1037   for (size_t i = 0; i < n; i++)
1038     new[i] = clone_dimension (old[i], new_pt);
1039   return new;
1040 }
1041
1042 struct pivot_table *
1043 pivot_table_unshare (struct pivot_table *old)
1044 {
1045   assert (old->ref_cnt > 0);
1046   if (old->ref_cnt == 1)
1047     return old;
1048
1049   pivot_table_unref (old);
1050
1051   struct pivot_table *new = xmalloc (sizeof *new);
1052   *new = (struct pivot_table) {
1053     .ref_cnt = 1,
1054
1055     .look = pivot_table_look_ref (old->look),
1056
1057     .rotate_inner_column_labels = old->rotate_inner_column_labels,
1058     .rotate_outer_row_labels = old->rotate_outer_row_labels,
1059     .show_grid_lines = old->show_grid_lines,
1060     .show_title = old->show_title,
1061     .show_caption = old->show_caption,
1062     .current_layer = (old->current_layer
1063                       ? xmemdup (old->current_layer,
1064                                  old->axes[PIVOT_AXIS_LAYER].n_dimensions
1065                                  * sizeof *new->current_layer)
1066                       : NULL),
1067     .show_values = old->show_values,
1068     .show_variables = old->show_variables,
1069     .weight_format = old->weight_format,
1070
1071     .sizing = {
1072       [TABLE_HORZ] = clone_sizing (&old->sizing[TABLE_HORZ]),
1073       [TABLE_VERT] = clone_sizing (&old->sizing[TABLE_VERT]),
1074     },
1075
1076     .settings = fmt_settings_copy (&old->settings),
1077     .grouping = old->grouping,
1078     .small = old->small,
1079
1080     .command_local = xstrdup_if_nonnull (old->command_local),
1081     .command_c = xstrdup_if_nonnull (old->command_c),
1082     .language = xstrdup_if_nonnull (old->language),
1083     .locale = xstrdup_if_nonnull (old->locale),
1084
1085     .dataset = xstrdup_if_nonnull (old->dataset),
1086     .datafile = xstrdup_if_nonnull (old->datafile),
1087     .date = old->date,
1088
1089     .footnotes = clone_footnotes (old->footnotes, old->n_footnotes),
1090     .n_footnotes = old->n_footnotes,
1091     .allocated_footnotes = old->n_footnotes,
1092
1093     .title = pivot_value_clone (old->title),
1094     .subtype = pivot_value_clone (old->subtype),
1095     .corner_text = pivot_value_clone (old->corner_text),
1096     .caption = pivot_value_clone (old->caption),
1097     .notes = xstrdup_if_nonnull (old->notes),
1098
1099     .dimensions = clone_dimensions (old->dimensions, old->n_dimensions, new),
1100     .n_dimensions = old->n_dimensions,
1101
1102     .cells = HMAP_INITIALIZER (new->cells),
1103   };
1104
1105   for (size_t i = 0; i < PIVOT_N_AXES; i++)
1106     {
1107       struct pivot_axis *new_axis = &new->axes[i];
1108       const struct pivot_axis *old_axis = &old->axes[i];
1109
1110       *new_axis = (struct pivot_axis) {
1111         .dimensions = xmalloc (old_axis->n_dimensions
1112                                * sizeof *new_axis->dimensions),
1113         .n_dimensions = old_axis->n_dimensions,
1114         .extent = old_axis->extent,
1115         .label_depth = old_axis->label_depth,
1116       };
1117
1118       for (size_t i = 0; i < new_axis->n_dimensions; i++)
1119         new_axis->dimensions[i] = new->dimensions[
1120           old_axis->dimensions[i]->top_index];
1121     }
1122
1123   const struct pivot_cell *old_cell;
1124   size_t *dindexes = xmalloc (old->n_dimensions * sizeof *dindexes);
1125   HMAP_FOR_EACH (old_cell, struct pivot_cell, hmap_node, &old->cells)
1126     {
1127       for (size_t i = 0; i < old->n_dimensions; i++)
1128         dindexes[i] = old_cell->idx[i];
1129       struct pivot_cell *new_cell
1130         = pivot_table_insert_cell (new, dindexes);
1131       new_cell->value = pivot_value_clone (old_cell->value);
1132     }
1133   free (dindexes);
1134
1135   return new;
1136 }
1137
1138 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
1139    If TABLE no longer has any owners, it is freed. */
1140 void
1141 pivot_table_unref (struct pivot_table *table)
1142 {
1143   if (!table)
1144     return;
1145   assert (table->ref_cnt > 0);
1146   if (--table->ref_cnt)
1147     return;
1148
1149   free (table->current_layer);
1150   pivot_table_look_unref (table->look);
1151
1152   for (int i = 0; i < TABLE_N_AXES; i++)
1153     pivot_table_sizing_uninit (&table->sizing[i]);
1154
1155   fmt_settings_uninit (&table->settings);
1156
1157   free (table->command_local);
1158   free (table->command_c);
1159   free (table->language);
1160   free (table->locale);
1161
1162   free (table->dataset);
1163   free (table->datafile);
1164
1165   for (size_t i = 0; i < table->n_footnotes; i++)
1166     pivot_footnote_destroy (table->footnotes[i]);
1167   free (table->footnotes);
1168
1169   pivot_value_destroy (table->title);
1170   pivot_value_destroy (table->subtype);
1171   pivot_value_destroy (table->corner_text);
1172   pivot_value_destroy (table->caption);
1173   free (table->notes);
1174
1175   for (size_t i = 0; i < table->n_dimensions; i++)
1176     pivot_dimension_destroy (table->dimensions[i]);
1177   free (table->dimensions);
1178
1179   for (size_t i = 0; i < PIVOT_N_AXES; i++)
1180     free (table->axes[i].dimensions);
1181
1182   struct pivot_cell *cell, *next_cell;
1183   HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
1184                       &table->cells)
1185     pivot_table_delete_cell (table, cell);
1186
1187   hmap_destroy (&table->cells);
1188
1189   free (table);
1190 }
1191
1192 /* Returns true if TABLE has more than one owner.  A pivot table that is shared
1193    among multiple owners must not be modified. */
1194 bool
1195 pivot_table_is_shared (const struct pivot_table *table)
1196 {
1197   return table->ref_cnt > 1;
1198 }
1199
1200 /* Swaps axes A and B in TABLE. */
1201 void
1202 pivot_table_swap_axes (struct pivot_table *table,
1203                        enum pivot_axis_type a, enum pivot_axis_type b)
1204 {
1205   if (a == b)
1206     return;
1207
1208   struct pivot_axis tmp = table->axes[a];
1209   table->axes[a] = table->axes[b];
1210   table->axes[b] = tmp;
1211
1212   for (int a = 0; a < PIVOT_N_AXES; a++)
1213     {
1214       struct pivot_axis *axis = &table->axes[a];
1215       for (size_t d = 0; d < axis->n_dimensions; d++)
1216         axis->dimensions[d]->axis_type = a;
1217     }
1218
1219   if (a == PIVOT_AXIS_LAYER || b == PIVOT_AXIS_LAYER)
1220     {
1221       free (table->current_layer);
1222       table->current_layer = xzalloc (
1223         table->axes[PIVOT_AXIS_LAYER].n_dimensions
1224         * sizeof *table->current_layer);
1225     }
1226 }
1227
1228 /* Swaps the row and column axes in TABLE. */
1229 void
1230 pivot_table_transpose (struct pivot_table *table)
1231 {
1232   pivot_table_swap_axes (table, PIVOT_AXIS_ROW, PIVOT_AXIS_COLUMN);
1233 }
1234
1235 static void
1236 pivot_table_update_axes (struct pivot_table *table)
1237 {
1238   for (int a = 0; a < PIVOT_N_AXES; a++)
1239     {
1240       struct pivot_axis *axis = &table->axes[a];
1241
1242       for (size_t d = 0; d < axis->n_dimensions; d++)
1243         {
1244           struct pivot_dimension *dim = axis->dimensions[d];
1245           dim->axis_type = a;
1246           dim->level = d;
1247         }
1248     }
1249 }
1250
1251 /* Moves DIM from its current location in TABLE to POS within AXIS.  POS of 0
1252    is the innermost dimension, 1 is the next one out, and so on. */
1253 void
1254 pivot_table_move_dimension (struct pivot_table *table,
1255                             struct pivot_dimension *dim,
1256                             enum pivot_axis_type axis, size_t pos)
1257 {
1258   assert (dim->table == table);
1259
1260   struct pivot_axis *old_axis = &table->axes[dim->axis_type];
1261   struct pivot_axis *new_axis = &table->axes[axis];
1262   pos = MIN (pos, new_axis->n_dimensions);
1263
1264   if (old_axis == new_axis && pos == dim->level)
1265     {
1266       /* No change. */
1267       return;
1268     }
1269
1270   /* Update the current layer, if necessary.  If we're moving within the layer
1271      axis, preserve the current layer. */
1272   if (dim->axis_type == PIVOT_AXIS_LAYER)
1273     {
1274       if (axis == PIVOT_AXIS_LAYER)
1275         {
1276           /* Rearranging the layer axis. */
1277           move_element (table->current_layer, old_axis->n_dimensions,
1278                         sizeof *table->current_layer,
1279                         dim->level, pos);
1280         }
1281       else
1282         {
1283           /* A layer is becoming a row or column. */
1284           remove_element (table->current_layer, old_axis->n_dimensions,
1285                           sizeof *table->current_layer, dim->level);
1286         }
1287     }
1288   else if (axis == PIVOT_AXIS_LAYER)
1289     {
1290       /* A row or column is becoming a layer. */
1291       table->current_layer = xrealloc (
1292         table->current_layer,
1293         (new_axis->n_dimensions + 1) * sizeof *table->current_layer);
1294       insert_element (table->current_layer, new_axis->n_dimensions,
1295                       sizeof *table->current_layer, pos);
1296       table->current_layer[pos] = 0;
1297     }
1298
1299   /* Remove DIM from its current axis. */
1300   remove_element (old_axis->dimensions, old_axis->n_dimensions,
1301                   sizeof *old_axis->dimensions, dim->level);
1302   old_axis->n_dimensions--;
1303
1304   /* Insert DIM into its new axis. */
1305   new_axis->dimensions = xrealloc (
1306     new_axis->dimensions,
1307     (new_axis->n_dimensions + 1) * sizeof *new_axis->dimensions);
1308   insert_element (new_axis->dimensions, new_axis->n_dimensions,
1309                   sizeof *new_axis->dimensions, pos);
1310   new_axis->dimensions[pos] = dim;
1311   new_axis->n_dimensions++;
1312
1313   pivot_table_update_axes (table);
1314 }
1315
1316
1317 const struct pivot_table_look *
1318 pivot_table_get_look (const struct pivot_table *table)
1319 {
1320   return table->look;
1321 }
1322
1323 void
1324 pivot_table_set_look (struct pivot_table *table,
1325                       const struct pivot_table_look *look)
1326 {
1327   pivot_table_look_unref (table->look);
1328   table->look = pivot_table_look_ref (look);
1329 }
1330
1331 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
1332    WV, which should be the weight variable for the dictionary whose data or
1333    statistics are being put into TABLE.
1334
1335    This has no effect if WV is NULL. */
1336 void
1337 pivot_table_set_weight_var (struct pivot_table *table,
1338                             const struct variable *wv)
1339 {
1340   if (wv)
1341     pivot_table_set_weight_format (table, var_get_print_format (wv));
1342 }
1343
1344 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
1345    format for the dictionary whose data or statistics are being put into TABLE.
1346
1347    This has no effect if WFMT is NULL. */
1348 void
1349 pivot_table_set_weight_format (struct pivot_table *table,
1350                                const struct fmt_spec *wfmt)
1351 {
1352   if (wfmt)
1353     table->weight_format = *wfmt;
1354 }
1355
1356 /* Returns true if TABLE has no cells, false otherwise. */
1357 bool
1358 pivot_table_is_empty (const struct pivot_table *table)
1359 {
1360   return hmap_is_empty (&table->cells);
1361 }
1362
1363 static unsigned int
1364 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
1365 {
1366   return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
1367 }
1368
1369 static bool
1370 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
1371 {
1372   for (size_t i = 0; i < n; i++)
1373     if (a[i] != b[i])
1374       return false;
1375
1376   return true;
1377 }
1378
1379 static struct pivot_cell *
1380 pivot_table_lookup_cell__ (const struct pivot_table *table,
1381                             const size_t *dindexes, unsigned int hash)
1382 {
1383   struct pivot_cell *cell;
1384   HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
1385                            &table->cells)
1386     if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
1387       return cell;
1388   return false;
1389 }
1390
1391 static struct pivot_cell *
1392 pivot_cell_allocate (size_t n_idx)
1393 {
1394   struct pivot_cell *cell UNUSED;
1395   return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
1396 }
1397
1398 static struct pivot_cell *
1399 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
1400 {
1401   unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1402   struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
1403   if (!cell)
1404     {
1405       cell = pivot_cell_allocate (table->n_dimensions);
1406       for (size_t i = 0; i < table->n_dimensions; i++)
1407         cell->idx[i] = dindexes[i];
1408       cell->value = NULL;
1409       hmap_insert (&table->cells, &cell->hmap_node, hash);
1410     }
1411   return cell;
1412 }
1413
1414 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
1415    DINDEXES.  N must be the number of dimensions in TABLE.  Takes ownership of
1416    VALUE.
1417
1418    If VALUE is a numeric value without a specified format, this function checks
1419    each of the categories designated by DINDEXES[] and takes the format from
1420    the first category with a result class.  If none has a result class, uses
1421    the overall default numeric format. */
1422 void
1423 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
1424                  struct pivot_value *value)
1425 {
1426   assert (n == table->n_dimensions);
1427   for (size_t i = 0; i < n; i++)
1428     assert (dindexes[i] < table->dimensions[i]->n_leaves);
1429
1430   if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
1431     {
1432       for (size_t i = 0; i < table->n_dimensions; i++)
1433         {
1434           const struct pivot_dimension *d = table->dimensions[i];
1435           if (dindexes[i] < d->n_leaves)
1436             {
1437               const struct pivot_category *c = d->data_leaves[dindexes[i]];
1438               if (c->format.w)
1439                 {
1440                   value->numeric.format = c->format;
1441                   value->numeric.honor_small = c->honor_small;
1442                   goto done;
1443                 }
1444             }
1445         }
1446       value->numeric.format = *settings_get_format ();
1447       value->numeric.honor_small = true;
1448
1449     done:;
1450     }
1451
1452   struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1453   pivot_value_destroy (cell->value);
1454   cell->value = value;
1455 }
1456
1457 /* Puts VALUE in the cell in TABLE with index IDX1.  TABLE must have 1
1458    dimension.  Takes ownership of VALUE.  */
1459 void
1460 pivot_table_put1 (struct pivot_table *table, size_t idx1,
1461                   struct pivot_value *value)
1462 {
1463   size_t dindexes[] = { idx1 };
1464   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1465 }
1466
1467 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2).  TABLE must have 2
1468    dimensions.  Takes ownership of VALUE.  */
1469 void
1470 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
1471                   struct pivot_value *value)
1472 {
1473   size_t dindexes[] = { idx1, idx2 };
1474   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1475 }
1476
1477 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3).  TABLE must
1478    have 3 dimensions.  Takes ownership of VALUE.  */
1479 void
1480 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
1481                   size_t idx3, struct pivot_value *value)
1482 {
1483   size_t dindexes[] = { idx1, idx2, idx3 };
1484   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1485 }
1486
1487 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4).  TABLE
1488    must have 4 dimensions.  Takes ownership of VALUE.  */
1489 void
1490 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1491                   size_t idx3, size_t idx4, struct pivot_value *value)
1492 {
1493   size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1494   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1495 }
1496
1497 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1498    automatically assigned marker.
1499
1500    The footnote will only appear in output if it is referenced.  Use
1501    pivot_value_add_footnote() to add a reference to the footnote. */
1502 struct pivot_footnote *
1503 pivot_table_create_footnote (struct pivot_table *table,
1504                              struct pivot_value *content)
1505 {
1506   return pivot_table_create_footnote__ (table, table->n_footnotes,
1507                                         NULL, content);
1508 }
1509
1510 void
1511 pivot_footnote_format_marker (const struct pivot_footnote *f,
1512                               const struct pivot_table *pt,
1513                               struct string *s)
1514 {
1515   if (f->marker)
1516     pivot_value_format_body (f->marker, pt, s);
1517   else if (pt->look->show_numeric_markers)
1518     ds_put_format (s, "%zu", f->idx + 1);
1519   else
1520     {
1521       char text[INT_BUFSIZE_BOUND (size_t)];
1522       str_format_26adic (f->idx + 1, false, text, sizeof text);
1523       ds_put_cstr (s, text);
1524     }
1525 }
1526
1527 char *
1528 pivot_footnote_marker_string (const struct pivot_footnote *f,
1529                               const struct pivot_table *pt)
1530 {
1531   struct string s = DS_EMPTY_INITIALIZER;
1532   pivot_footnote_format_marker (f, pt, &s);
1533   return ds_steal_cstr (&s);
1534 }
1535
1536 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1537    all lower indexes as a side effect).  If MARKER is nonnull, sets the
1538    footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1539 struct pivot_footnote *
1540 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1541                                struct pivot_value *marker,
1542                                struct pivot_value *content)
1543 {
1544   if (idx >= table->n_footnotes)
1545     {
1546       while (idx >= table->allocated_footnotes)
1547         table->footnotes = x2nrealloc (table->footnotes,
1548                                        &table->allocated_footnotes,
1549                                        sizeof *table->footnotes);
1550       while (idx >= table->n_footnotes)
1551         {
1552           struct pivot_footnote *f = xmalloc (sizeof *f);
1553           *f = (struct pivot_footnote) {
1554             .idx = table->n_footnotes,
1555             .show = true,
1556           };
1557           table->footnotes[table->n_footnotes++] = f;
1558         }
1559     }
1560
1561   struct pivot_footnote *f = table->footnotes[idx];
1562   if (marker)
1563     {
1564       pivot_value_destroy (f->marker);
1565       f->marker = marker;
1566     }
1567   if (content)
1568     {
1569       pivot_value_destroy (f->content);
1570       f->content = content;
1571     }
1572   return f;
1573 }
1574
1575 /* Frees the data owned by F. */
1576 void
1577 pivot_footnote_destroy (struct pivot_footnote *f)
1578 {
1579   if (f)
1580     {
1581       pivot_value_destroy (f->content);
1582       pivot_value_destroy (f->marker);
1583       free (f);
1584     }
1585 }
1586
1587 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1588    indexes for each dimension in TABLE in DINDEXES[]. */
1589 void
1590 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1591                                   const size_t *pindexes[PIVOT_N_AXES],
1592                                   size_t dindexes[/* table->n_dimensions */])
1593 {
1594   for (size_t i = 0; i < PIVOT_N_AXES; i++)
1595     {
1596       const struct pivot_axis *axis = &table->axes[i];
1597
1598       for (size_t j = 0; j < axis->n_dimensions; j++)
1599         {
1600           const struct pivot_dimension *d = axis->dimensions[j];
1601           size_t pindex = pindexes[i][j];
1602           dindexes[d->top_index] = d->presentation_leaves[pindex]->data_index;
1603         }
1604     }
1605 }
1606
1607 size_t *
1608 pivot_table_enumerate_axis (const struct pivot_table *table,
1609                             enum pivot_axis_type axis_type,
1610                             const size_t *layer_indexes, bool omit_empty,
1611                             size_t *n)
1612 {
1613   const struct pivot_axis *axis = &table->axes[axis_type];
1614   if (!axis->n_dimensions)
1615     {
1616       size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1617       enumeration[0] = 0;
1618       enumeration[1] = SIZE_MAX;
1619       if (n)
1620         *n = 1;
1621       return enumeration;
1622     }
1623   else if (!axis->extent)
1624     {
1625       size_t *enumeration = xmalloc (sizeof *enumeration);
1626       *enumeration = SIZE_MAX;
1627       if (n)
1628         *n = 0;
1629       return enumeration;
1630     }
1631
1632   size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1633                                                 axis->n_dimensions), 1),
1634                                   sizeof *enumeration);
1635   size_t *p = enumeration;
1636   size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1637
1638   size_t *axis_indexes;
1639   PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1640     {
1641       if (omit_empty)
1642         {
1643           enum pivot_axis_type axis2_type
1644             = pivot_axis_type_transpose (axis_type);
1645
1646           size_t *axis2_indexes;
1647           PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1648             {
1649               const size_t *pindexes[PIVOT_N_AXES];
1650               pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1651               pindexes[axis_type] = axis_indexes;
1652               pindexes[axis2_type] = axis2_indexes;
1653               pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1654               if (pivot_table_get (table, dindexes))
1655                 goto found;
1656             }
1657           continue;
1658
1659         found:
1660           free (axis2_indexes);
1661         }
1662
1663       memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1664       p += axis->n_dimensions;
1665     }
1666   if (omit_empty && p == enumeration)
1667     {
1668       PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1669         {
1670           memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1671           p += axis->n_dimensions;
1672         }
1673     }
1674   *p = SIZE_MAX;
1675   if (n)
1676     *n = (p - enumeration) / axis->n_dimensions;
1677
1678   free (dindexes);
1679   return enumeration;
1680 }
1681
1682 static struct pivot_cell *
1683 pivot_table_lookup_cell (const struct pivot_table *table,
1684                          const size_t *dindexes)
1685 {
1686   unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1687   return pivot_table_lookup_cell__ (table, dindexes, hash);
1688 }
1689
1690 const struct pivot_value *
1691 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1692 {
1693   const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1694   return cell ? cell->value : NULL;
1695 }
1696
1697 struct pivot_value *
1698 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1699 {
1700   struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1701   if (!cell->value)
1702     cell->value = pivot_value_new_user_text ("", -1);
1703   return cell->value;
1704 }
1705
1706 static void
1707 pivot_table_delete_cell (struct pivot_table *table, struct pivot_cell *cell)
1708 {
1709   hmap_delete (&table->cells, &cell->hmap_node);
1710   pivot_value_destroy (cell->value);
1711   free (cell);
1712 }
1713
1714 bool
1715 pivot_table_delete (struct pivot_table *table, const size_t *dindexes)
1716 {
1717   struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1718   if (cell)
1719     {
1720       pivot_table_delete_cell (table, cell);
1721       return true;
1722     }
1723   else
1724     return false;
1725 }
1726
1727 static void
1728 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1729 {
1730   if (pivot_category_is_group (category) && category->n_subs)
1731     for (size_t i = 0; i < category->n_subs; i++)
1732       distribute_extra_depth (category->subs[i], extra_depth);
1733   else
1734     category->extra_depth += extra_depth;
1735 }
1736
1737 static void
1738 pivot_category_assign_label_depth (struct pivot_category *category,
1739                                    bool dimension_labels_in_corner)
1740 {
1741   category->extra_depth = 0;
1742
1743   if (pivot_category_is_group (category))
1744     {
1745       size_t depth = 0;
1746       for (size_t i = 0; i < category->n_subs; i++)
1747         {
1748           pivot_category_assign_label_depth (category->subs[i], false);
1749           depth = MAX (depth, category->subs[i]->label_depth);
1750         }
1751
1752       for (size_t i = 0; i < category->n_subs; i++)
1753         {
1754           struct pivot_category *sub = category->subs[i];
1755
1756           size_t extra_depth = depth - sub->label_depth;
1757           if (extra_depth)
1758             distribute_extra_depth (sub, extra_depth);
1759
1760           sub->label_depth = depth;
1761         }
1762
1763       category->show_label_in_corner = (category->show_label
1764                                         && dimension_labels_in_corner);
1765       category->label_depth
1766         = (category->show_label && !category->show_label_in_corner
1767            ? depth + 1 : depth);
1768     }
1769   else
1770     category->label_depth = 1;
1771 }
1772
1773 static bool
1774 pivot_axis_assign_label_depth (struct pivot_table *table,
1775                              enum pivot_axis_type axis_type,
1776                              bool dimension_labels_in_corner)
1777 {
1778   struct pivot_axis *axis = &table->axes[axis_type];
1779   bool any_label_shown_in_corner = false;
1780   axis->label_depth = 0;
1781   axis->extent = 1;
1782   for (size_t i = 0; i < axis->n_dimensions; i++)
1783     {
1784       struct pivot_dimension *d = axis->dimensions[i];
1785       pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1786       d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1787       axis->label_depth += d->label_depth;
1788       axis->extent *= d->n_leaves;
1789
1790       if (d->root->show_label_in_corner)
1791         any_label_shown_in_corner = true;
1792     }
1793   return any_label_shown_in_corner;
1794 }
1795
1796 void
1797 pivot_table_assign_label_depth (struct pivot_table *table)
1798 {
1799   pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1800   if (pivot_axis_assign_label_depth (
1801         table, PIVOT_AXIS_ROW, (table->look->row_labels_in_corner
1802                                 && !table->corner_text))
1803       && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1804     table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1805   pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1806 }
1807 \f
1808 static void
1809 indent (int indentation)
1810 {
1811   for (int i = 0; i < indentation * 2; i++)
1812     putchar (' ');
1813 }
1814
1815 static void
1816 pivot_value_dump (const struct pivot_value *value,
1817                   const struct pivot_table *pt)
1818 {
1819   char *s = pivot_value_to_string (value, pt);
1820   fputs (s, stdout);
1821   free (s);
1822 }
1823
1824 static void
1825 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1826                         const struct pivot_table *pt, int indentation)
1827 {
1828   if (value)
1829     {
1830       indent (indentation);
1831       printf ("%s: ", name);
1832       pivot_value_dump (value, pt);
1833       putchar ('\n');
1834     }
1835 }
1836
1837 static void
1838 pivot_table_dump_string (const char *string, const char *name, int indentation)
1839 {
1840   if (string)
1841     {
1842       indent (indentation);
1843       printf ("%s: %s\n", name, string);
1844     }
1845 }
1846
1847 static void
1848 pivot_category_dump (const struct pivot_category *c,
1849                      const struct pivot_table *pt, int indentation)
1850 {
1851   indent (indentation);
1852   printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1853   pivot_value_dump (c->name, pt);
1854   printf ("\" ");
1855
1856   if (pivot_category_is_leaf (c))
1857     printf ("data_index=%zu\n", c->data_index);
1858   else
1859     {
1860       printf (" (label %s)", c->show_label ? "shown" : "hidden");
1861       printf ("\n");
1862
1863       for (size_t i = 0; i < c->n_subs; i++)
1864         pivot_category_dump (c->subs[i], pt, indentation + 1);
1865     }
1866 }
1867
1868 void
1869 pivot_dimension_dump (const struct pivot_dimension *d,
1870                       const struct pivot_table *pt, int indentation)
1871 {
1872   indent (indentation);
1873   printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1874           pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1875
1876   pivot_category_dump (d->root, pt, indentation + 1);
1877 }
1878
1879 static void
1880 table_area_style_dump (enum pivot_area area, const struct table_area_style *a,
1881                        int indentation)
1882 {
1883   indent (indentation);
1884   printf ("%s: ", pivot_area_to_string (area));
1885   font_style_dump (&a->font_style);
1886   putchar (' ');
1887   cell_style_dump (&a->cell_style);
1888   putchar ('\n');
1889 }
1890
1891 static void
1892 table_border_style_dump (enum pivot_border border,
1893                          const struct table_border_style *b, int indentation)
1894 {
1895   indent (indentation);
1896   printf ("%s: %s ", pivot_border_to_string (border),
1897           table_stroke_to_string (b->stroke));
1898   cell_color_dump (&b->color);
1899   putchar ('\n');
1900 }
1901
1902 static char ***
1903 compose_headings (const struct pivot_table *pt,
1904                   const struct pivot_axis *axis,
1905                   const size_t *column_enumeration)
1906 {
1907   if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1908     return NULL;
1909
1910   char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1911   for (size_t i = 0; i < axis->label_depth; i++)
1912     headings[i] = xcalloc (axis->extent, sizeof **headings);
1913
1914   const size_t *indexes;
1915   size_t column = 0;
1916   PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1917     {
1918       int row = axis->label_depth - 1;
1919       for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1920         {
1921           const struct pivot_dimension *d = axis->dimensions[dim_index];
1922           if (d->hide_all_labels)
1923             continue;
1924           for (const struct pivot_category *c
1925                  = d->presentation_leaves[indexes[dim_index]];
1926                c;
1927                c = c->parent)
1928             {
1929               if (pivot_category_is_leaf (c) || (c->show_label
1930                                                  && !c->show_label_in_corner))
1931                 {
1932                   headings[row][column] = pivot_value_to_string (c->name, pt);
1933                   if (!*headings[row][column])
1934                     headings[row][column] = xstrdup ("<blank>");
1935                   row--;
1936                 }
1937             }
1938         }
1939       column++;
1940     }
1941
1942   return headings;
1943 }
1944
1945 static void
1946 free_headings (const struct pivot_axis *axis, char ***headings)
1947 {
1948   for (size_t i = 0; i < axis->label_depth; i++)
1949     {
1950       for (size_t j = 0; j < axis->extent; j++)
1951         free (headings[i][j]);
1952       free (headings[i]);
1953     }
1954   free (headings);
1955 }
1956
1957 static void
1958 pivot_table_sizing_dump (const char *name,
1959                          const int width_ranges[2],
1960                          const struct pivot_table_sizing *s,
1961                          int indentation)
1962 {
1963   indent (indentation);
1964   printf ("%ss: min=%d, max=%d\n", name, width_ranges[0], width_ranges[1]);
1965   if (s->n_widths)
1966     {
1967       indent (indentation + 1);
1968       printf ("%s widths:", name);
1969       for (size_t i = 0; i < s->n_widths; i++)
1970         printf (" %d", s->widths[i]);
1971       printf ("\n");
1972     }
1973   if (s->n_breaks)
1974     {
1975       indent (indentation + 1);
1976       printf ("break after %ss:", name);
1977       for (size_t i = 0; i < s->n_breaks; i++)
1978         printf (" %zu", s->breaks[i]);
1979       printf ("\n");
1980     }
1981   if (s->n_keeps)
1982     {
1983       indent (indentation + 1);
1984       printf ("keep %ss together:", name);
1985       for (size_t i = 0; i < s->n_keeps; i++)
1986         printf (" [%zu,%zu]",
1987                 s->keeps[i].ofs,
1988                 s->keeps[i].ofs + s->keeps[i].n - 1);
1989       printf ("\n");
1990     }
1991 }
1992
1993 void
1994 pivot_table_dump (const struct pivot_table *table, int indentation)
1995 {
1996   if (!table)
1997     return;
1998
1999   pivot_table_assign_label_depth (CONST_CAST (struct pivot_table *, table));
2000
2001   pivot_table_dump_value (table->title, "title", table, indentation);
2002   pivot_table_dump_value (table->subtype, "subtype", table, indentation);
2003   pivot_table_dump_string (table->command_c, "command", indentation);
2004   pivot_table_dump_string (table->dataset, "dataset", indentation);
2005   pivot_table_dump_string (table->datafile, "datafile", indentation);
2006   pivot_table_dump_string (table->notes, "notes", indentation);
2007   pivot_table_dump_string (table->look->name, "table-look", indentation);
2008   if (table->date)
2009     {
2010       indent (indentation);
2011
2012       struct tm *tm = localtime (&table->date);
2013       printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
2014               tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
2015               tm->tm_sec);
2016     }
2017
2018   indent (indentation);
2019   printf ("sizing:\n");
2020   pivot_table_sizing_dump ("column", table->look->width_ranges[TABLE_HORZ],
2021                            &table->sizing[TABLE_HORZ], indentation + 1);
2022   pivot_table_sizing_dump ("row", table->look->width_ranges[TABLE_VERT],
2023                            &table->sizing[TABLE_VERT], indentation + 1);
2024
2025   indent (indentation);
2026   printf ("areas:\n");
2027   for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
2028     table_area_style_dump (area, &table->look->areas[area], indentation + 1);
2029
2030   indent (indentation);
2031   printf ("borders:\n");
2032   for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
2033     table_border_style_dump (border, &table->look->borders[border],
2034                              indentation + 1);
2035
2036   for (size_t i = 0; i < table->n_dimensions; i++)
2037     pivot_dimension_dump (table->dimensions[i], table, indentation);
2038
2039   /* Presentation and data indexes. */
2040   size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
2041
2042   const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
2043   if (layer_axis->n_dimensions)
2044     {
2045       indent (indentation);
2046       printf ("current layer:");
2047
2048       for (size_t i = 0; i < layer_axis->n_dimensions; i++)
2049         {
2050           const struct pivot_dimension *d = layer_axis->dimensions[i];
2051           char *name = pivot_value_to_string (d->root->name, table);
2052           char *value = pivot_value_to_string (
2053             d->data_leaves[table->current_layer[i]]->name, table);
2054           printf (" %s=%s", name, value);
2055           free (value);
2056           free (name);
2057         }
2058
2059       putchar ('\n');
2060     }
2061
2062   size_t *layer_indexes;
2063   size_t layer_iteration = 0;
2064   PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
2065     {
2066       indent (indentation);
2067       printf ("layer %zu:", layer_iteration++);
2068
2069       const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
2070       for (size_t i = 0; i < layer_axis->n_dimensions; i++)
2071         {
2072           const struct pivot_dimension *d = layer_axis->dimensions[i];
2073
2074           fputs (i == 0 ? " " : ", ", stdout);
2075           pivot_value_dump (d->root->name, table);
2076           fputs (" =", stdout);
2077
2078           struct pivot_value **names = xnmalloc (d->n_leaves, sizeof *names);
2079           size_t n_names = 0;
2080           for (const struct pivot_category *c
2081                  = d->presentation_leaves[layer_indexes[i]];
2082                c;
2083                c = c->parent)
2084             {
2085               if (pivot_category_is_leaf (c) || c->show_label)
2086                 names[n_names++] = c->name;
2087             }
2088
2089           for (size_t i = n_names; i-- > 0;)
2090             {
2091               putchar (' ');
2092               pivot_value_dump (names[i], table);
2093             }
2094           free (names);
2095         }
2096       putchar ('\n');
2097
2098       size_t *column_enumeration = pivot_table_enumerate_axis (
2099         table, PIVOT_AXIS_COLUMN, layer_indexes, table->look->omit_empty, NULL);
2100       size_t *row_enumeration = pivot_table_enumerate_axis (
2101         table, PIVOT_AXIS_ROW, layer_indexes, table->look->omit_empty, NULL);
2102
2103       char ***column_headings = compose_headings (
2104         table, &table->axes[PIVOT_AXIS_COLUMN], column_enumeration);
2105       for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
2106         {
2107           indent (indentation + 1);
2108           for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
2109             {
2110               if (x)
2111                 fputs ("; ", stdout);
2112               if (column_headings[y][x])
2113                 fputs (column_headings[y][x], stdout);
2114             }
2115           putchar ('\n');
2116         }
2117       free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
2118
2119       indent (indentation + 1);
2120       printf ("-----------------------------------------------\n");
2121
2122       char ***row_headings = compose_headings (
2123         table, &table->axes[PIVOT_AXIS_ROW], row_enumeration);
2124
2125       size_t x = 0;
2126       const size_t *pindexes[PIVOT_N_AXES]
2127         = { [PIVOT_AXIS_LAYER] = layer_indexes };
2128       PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
2129                                   &table->axes[PIVOT_AXIS_ROW])
2130         {
2131           indent (indentation + 1);
2132
2133           size_t i = 0;
2134           for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
2135             {
2136               if (i++)
2137                 fputs ("; ", stdout);
2138               if (row_headings[y][x])
2139                 fputs (row_headings[y][x], stdout);
2140             }
2141
2142           printf (" | ");
2143
2144           i = 0;
2145           PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
2146                                       column_enumeration,
2147                                       &table->axes[PIVOT_AXIS_COLUMN])
2148             {
2149               if (i++)
2150                 printf ("; ");
2151
2152               pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
2153               const struct pivot_value *value = pivot_table_get (
2154                 table, dindexes);
2155               if (value)
2156                 pivot_value_dump (value, table);
2157             }
2158           printf ("\n");
2159
2160           x++;
2161         }
2162
2163       free (column_enumeration);
2164       free (row_enumeration);
2165       free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
2166     }
2167
2168   pivot_table_dump_value (table->caption, "caption", table, indentation);
2169
2170   for (size_t i = 0; i < table->n_footnotes; i++)
2171     {
2172       const struct pivot_footnote *f = table->footnotes[i];
2173       indent (indentation);
2174       putchar ('[');
2175       if (f->marker)
2176         pivot_value_dump (f->marker, table);
2177       else
2178         printf ("%zu", f->idx);
2179       putchar (']');
2180       pivot_value_dump (f->content, table);
2181       putchar ('\n');
2182     }
2183
2184   free (dindexes);
2185 }
2186 \f
2187 static const char *
2188 consume_int (const char *p, size_t *n)
2189 {
2190   *n = 0;
2191   while (c_isdigit (*p))
2192     *n = *n * 10 + (*p++ - '0');
2193   return p;
2194 }
2195
2196 static size_t
2197 pivot_format_inner_template (struct string *out, const char *template,
2198                              char escape,
2199                              struct pivot_value **values, size_t n_values,
2200                              const struct pivot_table *pt)
2201 {
2202   size_t args_consumed = 0;
2203   while (*template && *template != ':')
2204     {
2205       if (*template == '\\' && template[1])
2206         {
2207           ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
2208           template += 2;
2209         }
2210       else if (*template == escape)
2211         {
2212           size_t index;
2213           template = consume_int (template + 1, &index);
2214           if (index >= 1 && index <= n_values)
2215             {
2216               pivot_value_format (values[index - 1], pt, out);
2217               args_consumed = MAX (args_consumed, index);
2218             }
2219         }
2220       else
2221         ds_put_byte (out, *template++);
2222     }
2223   return args_consumed;
2224 }
2225
2226 static const char *
2227 pivot_extract_inner_template (const char *template, const char **p)
2228 {
2229   *p = template;
2230
2231   for (;;)
2232     {
2233       if (*template == '\\' && template[1] != '\0')
2234         template += 2;
2235       else if (*template == ':')
2236         return template + 1;
2237       else if (*template == '\0')
2238         return template;
2239       else
2240         template++;
2241     }
2242 }
2243
2244 static void
2245 pivot_format_template (struct string *out, const char *template,
2246                        const struct pivot_argument *args, size_t n_args,
2247                        const struct pivot_table *pt)
2248 {
2249   while (*template)
2250     {
2251       if (*template == '\\' && template[1] != '\0')
2252         {
2253           ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
2254           template += 2;
2255         }
2256       else if (*template == '^')
2257         {
2258           size_t index;
2259           template = consume_int (template + 1, &index);
2260           if (index >= 1 && index <= n_args && args[index - 1].n > 0)
2261             pivot_value_format (args[index - 1].values[0], pt, out);
2262         }
2263       else if (*template == '[')
2264         {
2265           const char *tmpl[2];
2266           template = pivot_extract_inner_template (template + 1, &tmpl[0]);
2267           template = pivot_extract_inner_template (template, &tmpl[1]);
2268           template += *template == ']';
2269
2270           size_t index;
2271           template = consume_int (template, &index);
2272           if (index < 1 || index > n_args)
2273             continue;
2274
2275           const struct pivot_argument *arg = &args[index - 1];
2276           size_t left = arg->n;
2277           while (left)
2278             {
2279               struct pivot_value **values = arg->values + (arg->n - left);
2280               int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
2281               char escape = "%^"[tmpl_idx];
2282               size_t used = pivot_format_inner_template (
2283                 out, tmpl[tmpl_idx], escape, values, left, pt);
2284               if (!used || used > left)
2285                 break;
2286               left -= used;
2287             }
2288         }
2289       else
2290         ds_put_byte (out, *template++);
2291     }
2292 }
2293
2294 static enum settings_value_show
2295 interpret_show (enum settings_value_show global_show,
2296                 enum settings_value_show table_show,
2297                 enum settings_value_show value_show,
2298                 bool has_label)
2299 {
2300   return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
2301           : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
2302           : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
2303           : global_show);
2304 }
2305
2306 /* Appends to OUT the actual text content from the given Pango MARKUP. */
2307 static void
2308 get_text_from_markup (const char *markup, struct string *out)
2309 {
2310   xmlParserCtxt *parser = xmlCreatePushParserCtxt (NULL, NULL, NULL, 0, NULL);
2311   if (!parser)
2312     {
2313       ds_put_cstr (out, markup);
2314       return;
2315     }
2316
2317   xmlParseChunk (parser, "<xml>", strlen ("<xml>"), false);
2318   xmlParseChunk (parser, markup, strlen (markup), false);
2319   xmlParseChunk (parser, "</xml>", strlen ("</xml>"), true);
2320
2321   if (parser->wellFormed)
2322     {
2323       xmlChar *s = xmlNodeGetContent (xmlDocGetRootElement (parser->myDoc));
2324       ds_put_cstr (out, CHAR_CAST (char *, s));
2325       xmlFree (s);
2326     }
2327   else
2328     ds_put_cstr (out, markup);
2329   xmlFreeDoc (parser->myDoc);
2330   xmlFreeParserCtxt (parser);
2331 }
2332
2333 /* Appends a text representation of the body of VALUE to OUT.  Settings on
2334    PT control whether variable and value labels are included.
2335
2336    The "body" omits subscripts and superscripts and footnotes.
2337
2338    Returns true if OUT is a number (or a number plus a value label), false
2339    otherwise.  */
2340 bool
2341 pivot_value_format_body (const struct pivot_value *value,
2342                          const struct pivot_table *pt,
2343                          struct string *out)
2344 {
2345   enum settings_value_show show;
2346   bool numeric = false;
2347
2348   switch (value->type)
2349     {
2350     case PIVOT_VALUE_NUMERIC:
2351       show = interpret_show (settings_get_show_values (),
2352                              pt->show_values,
2353                              value->numeric.show,
2354                              value->numeric.value_label != NULL);
2355       if (show & SETTINGS_VALUE_SHOW_VALUE)
2356         {
2357           const struct fmt_spec *f = &value->numeric.format;
2358           const struct fmt_spec *format
2359             = (f->type == FMT_F
2360                && value->numeric.honor_small
2361                && value->numeric.x != 0
2362                && fabs (value->numeric.x) < pt->small
2363                ? &(struct fmt_spec) { .type = FMT_E, .w = 40, .d = f->d }
2364                : f);
2365
2366           char *s = data_out (&(union value) { .f = value->numeric.x },
2367                               "UTF-8", format, &pt->settings);
2368           ds_put_cstr (out, s + strspn (s, " "));
2369           free (s);
2370         }
2371       if (show & SETTINGS_VALUE_SHOW_LABEL)
2372         {
2373           if (show & SETTINGS_VALUE_SHOW_VALUE)
2374             ds_put_byte (out, ' ');
2375           ds_put_cstr (out, value->numeric.value_label);
2376         }
2377       numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
2378       break;
2379
2380     case PIVOT_VALUE_STRING:
2381       show = interpret_show (settings_get_show_values (),
2382                              pt->show_values,
2383                              value->string.show,
2384                              value->string.value_label != NULL);
2385       if (show & SETTINGS_VALUE_SHOW_VALUE)
2386         {
2387           if (value->string.hex)
2388             {
2389               for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
2390                    *p; p++)
2391                 ds_put_format (out, "%02X", *p);
2392             }
2393           else
2394             ds_put_cstr (out, value->string.s);
2395         }
2396       if (show & SETTINGS_VALUE_SHOW_LABEL)
2397         {
2398           if (show & SETTINGS_VALUE_SHOW_VALUE)
2399             ds_put_byte (out, ' ');
2400           ds_put_cstr (out, value->string.value_label);
2401         }
2402       break;
2403
2404     case PIVOT_VALUE_VARIABLE:
2405       show = interpret_show (settings_get_show_variables (),
2406                              pt->show_variables,
2407                              value->variable.show,
2408                              value->variable.var_label != NULL);
2409       if (show & SETTINGS_VALUE_SHOW_VALUE)
2410         ds_put_cstr (out, value->variable.var_name);
2411       if (show & SETTINGS_VALUE_SHOW_LABEL)
2412         {
2413           if (show & SETTINGS_VALUE_SHOW_VALUE)
2414             ds_put_byte (out, ' ');
2415           ds_put_cstr (out, value->variable.var_label);
2416         }
2417       break;
2418
2419     case PIVOT_VALUE_TEXT:
2420       if (value->font_style && value->font_style->markup)
2421         get_text_from_markup (value->text.local, out);
2422       else
2423         ds_put_cstr (out, value->text.local);
2424       break;
2425
2426     case PIVOT_VALUE_TEMPLATE:
2427       pivot_format_template (out, value->template.local, value->template.args,
2428                              value->template.n_args, pt);
2429       break;
2430     }
2431
2432   return numeric;
2433 }
2434
2435 /* Appends a text representation of VALUE to OUT.  Settings on
2436    PT control whether variable and value labels are included.
2437
2438    Subscripts and footnotes are included.
2439
2440    Returns true if OUT is a number (or a number plus a value label), false
2441    otherwise.  */
2442 bool
2443 pivot_value_format (const struct pivot_value *value,
2444                     const struct pivot_table *pt,
2445                     struct string *out)
2446 {
2447   bool numeric = pivot_value_format_body (value, pt, out);
2448
2449   if (value->n_subscripts)
2450     {
2451       for (size_t i = 0; i < value->n_subscripts; i++)
2452         ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
2453     }
2454
2455   for (size_t i = 0; i < value->n_footnotes; i++)
2456     {
2457       ds_put_byte (out, '[');
2458
2459       size_t idx = value->footnote_indexes[i];
2460       const struct pivot_footnote *f = pt->footnotes[idx];
2461       pivot_footnote_format_marker (f, pt, out);
2462
2463       ds_put_byte (out, ']');
2464     }
2465
2466   return numeric;
2467 }
2468
2469 /* Returns a text representation of VALUE.  The caller must free the string,
2470    with free(). */
2471 char *
2472 pivot_value_to_string (const struct pivot_value *value,
2473                        const struct pivot_table *pt)
2474 {
2475   struct string s = DS_EMPTY_INITIALIZER;
2476   pivot_value_format (value, pt, &s);
2477   return ds_steal_cstr (&s);
2478 }
2479
2480 char *
2481 pivot_value_to_string_defaults (const struct pivot_value *value)
2482 {
2483   static const struct pivot_table pt = {
2484     .show_values = SETTINGS_VALUE_SHOW_DEFAULT,
2485     .show_variables = SETTINGS_VALUE_SHOW_DEFAULT,
2486     .settings = FMT_SETTINGS_INIT,
2487   };
2488   return pivot_value_to_string (value, &pt);
2489 }
2490
2491 struct pivot_value *
2492 pivot_value_clone (const struct pivot_value *old)
2493 {
2494   if (!old)
2495     return NULL;
2496
2497   struct pivot_value *new = xmemdup (old, sizeof *new);
2498   if (old->font_style)
2499     {
2500       new->font_style = xmalloc (sizeof *new->font_style);
2501       font_style_copy (NULL, new->font_style, old->font_style);
2502     }
2503   if (old->cell_style)
2504     new->cell_style = xmemdup (old->cell_style, sizeof *new->cell_style);
2505   if (old->n_subscripts)
2506     {
2507       new->subscripts = xnmalloc (old->n_subscripts, sizeof *new->subscripts);
2508       for (size_t i = 0; i < old->n_subscripts; i++)
2509         new->subscripts[i] = xstrdup (old->subscripts[i]);
2510     }
2511   if (old->n_footnotes)
2512     new->footnote_indexes = xmemdup (
2513       old->footnote_indexes, old->n_footnotes * sizeof *new->footnote_indexes);
2514
2515   switch (new->type)
2516     {
2517     case PIVOT_VALUE_NUMERIC:
2518       new->numeric.var_name = xstrdup_if_nonnull (new->numeric.var_name);
2519       new->numeric.value_label = xstrdup_if_nonnull (new->numeric.value_label);
2520       break;
2521
2522     case PIVOT_VALUE_STRING:
2523       new->string.s = xstrdup (new->string.s);
2524       new->string.var_name = xstrdup_if_nonnull (new->string.var_name);
2525       new->string.value_label = xstrdup_if_nonnull (new->string.value_label);
2526       break;
2527
2528     case PIVOT_VALUE_VARIABLE:
2529       new->variable.var_name = xstrdup_if_nonnull (new->variable.var_name);
2530       new->variable.var_label = xstrdup_if_nonnull (new->variable.var_label);
2531       break;
2532
2533     case PIVOT_VALUE_TEXT:
2534       new->text.local = xstrdup (old->text.local);
2535       new->text.c = (old->text.c == old->text.local ? new->text.local
2536                      : xstrdup_if_nonnull (old->text.c));
2537       new->text.id = (old->text.id == old->text.local ? new->text.local
2538                       : old->text.id == old->text.c ? new->text.c
2539                       : xstrdup_if_nonnull (old->text.id));
2540       break;
2541
2542     case PIVOT_VALUE_TEMPLATE:
2543       new->template.local = xstrdup (old->template.local);
2544       new->template.id = (old->template.id == old->template.local
2545                           ? new->template.local
2546                           : xstrdup (old->template.id));
2547       new->template.args = xmalloc (new->template.n_args
2548                                     * sizeof *new->template.args);
2549       for (size_t i = 0; i < old->template.n_args; i++)
2550         pivot_argument_copy (&new->template.args[i],
2551                              &old->template.args[i]);
2552       break;
2553
2554     default:
2555       NOT_REACHED ();
2556     }
2557   return new;
2558 }
2559
2560 /* Frees the data owned by V. */
2561 void
2562 pivot_value_destroy (struct pivot_value *value)
2563 {
2564   if (value)
2565     {
2566       font_style_uninit (value->font_style);
2567       free (value->font_style);
2568       free (value->cell_style);
2569       free (value->footnote_indexes);
2570
2571       for (size_t i = 0; i < value->n_subscripts; i++)
2572         free (value->subscripts[i]);
2573       free (value->subscripts);
2574
2575       switch (value->type)
2576         {
2577         case PIVOT_VALUE_NUMERIC:
2578           free (value->numeric.var_name);
2579           free (value->numeric.value_label);
2580           break;
2581
2582         case PIVOT_VALUE_STRING:
2583           free (value->string.s);
2584           free (value->string.var_name);
2585           free (value->string.value_label);
2586           break;
2587
2588         case PIVOT_VALUE_VARIABLE:
2589           free (value->variable.var_name);
2590           free (value->variable.var_label);
2591           break;
2592
2593         case PIVOT_VALUE_TEXT:
2594           free (value->text.local);
2595           if (value->text.c != value->text.local)
2596             free (value->text.c);
2597           if (value->text.id != value->text.local
2598               && value->text.id != value->text.c)
2599             free (value->text.id);
2600           break;
2601
2602         case PIVOT_VALUE_TEMPLATE:
2603           free (value->template.local);
2604           if (value->template.id != value->template.local)
2605             free (value->template.id);
2606           for (size_t i = 0; i < value->template.n_args; i++)
2607             pivot_argument_uninit (&value->template.args[i]);
2608           free (value->template.args);
2609           break;
2610
2611         default:
2612           NOT_REACHED ();
2613         }
2614       free (value);
2615     }
2616 }
2617
2618 /* Sets AREA to the style to use for VALUE, with defaults coming from
2619    DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
2620 void
2621 pivot_value_get_style (struct pivot_value *value,
2622                        const struct font_style *base_font_style,
2623                        const struct cell_style *base_cell_style,
2624                        struct table_area_style *area)
2625 {
2626   font_style_copy (NULL, &area->font_style, (value->font_style
2627                                              ? value->font_style
2628                                              : base_font_style));
2629   area->cell_style = *(value->cell_style
2630                        ? value->cell_style
2631                        : base_cell_style);
2632 }
2633
2634 /* Copies AREA into VALUE's style. */
2635 void
2636 pivot_value_set_style (struct pivot_value *value,
2637                        const struct table_area_style *area)
2638 {
2639   pivot_value_set_font_style (value, &area->font_style);
2640   pivot_value_set_cell_style (value, &area->cell_style);
2641 }
2642
2643 void
2644 pivot_value_set_font_style (struct pivot_value *value,
2645                             const struct font_style *font_style)
2646 {
2647   if (value->font_style)
2648     font_style_uninit (value->font_style);
2649   else
2650     value->font_style = xmalloc (sizeof *value->font_style);
2651   font_style_copy (NULL, value->font_style, font_style);
2652 }
2653
2654 void
2655 pivot_value_set_cell_style (struct pivot_value *value,
2656                             const struct cell_style *cell_style)
2657 {
2658   if (!value->cell_style)
2659     value->cell_style = xmalloc (sizeof *value->cell_style);
2660   *value->cell_style = *cell_style;
2661 }
2662
2663 void
2664 pivot_argument_copy (struct pivot_argument *dst,
2665                      const struct pivot_argument *src)
2666 {
2667   *dst = (struct pivot_argument) {
2668     .n = src->n,
2669     .values = xmalloc (src->n * sizeof *dst->values),
2670   };
2671
2672   for (size_t i = 0; i < src->n; i++)
2673     dst->values[i] = pivot_value_clone (src->values[i]);
2674 }
2675
2676 /* Frees the data owned by ARG (but not ARG itself). */
2677 void
2678 pivot_argument_uninit (struct pivot_argument *arg)
2679 {
2680   if (arg)
2681     {
2682       for (size_t i = 0; i < arg->n; i++)
2683         pivot_value_destroy (arg->values[i]);
2684       free (arg->values);
2685     }
2686 }
2687
2688 /* Creates and returns a new pivot_value whose contents is the null-terminated
2689    string TEXT.  Takes ownership of TEXT.
2690
2691    This function is for text strings provided by the user (with the exception
2692    that pivot_value_new_variable() should be used for variable names).  For
2693    strings that are part of the PSPP user interface, such as names of
2694    procedures, statistics, annotations, error messages, etc., use
2695    pivot_value_new_text(). */
2696 struct pivot_value *
2697 pivot_value_new_user_text_nocopy (char *text)
2698 {
2699   struct pivot_value *value = xmalloc (sizeof *value);
2700   *value = (struct pivot_value) {
2701     .type = PIVOT_VALUE_TEXT,
2702     .text = {
2703       .local = text,
2704       .c = text,
2705       .id = text,
2706       .user_provided = true,
2707     }
2708   };
2709   return value;
2710 }
2711
2712 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2713    TEXT.  Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2714    in advance.
2715
2716    This function is for text strings provided by the user (with the exception
2717    that pivot_value_new_variable() should be used for variable names).  For
2718    strings that are part of the PSPP user interface, such as names of
2719    procedures, statistics, annotations, error messages, etc., use
2720    pivot_value_new_text().j
2721
2722    The caller retains ownership of TEXT.*/
2723 struct pivot_value *
2724 pivot_value_new_user_text (const char *text, size_t length)
2725 {
2726   return pivot_value_new_user_text_nocopy (
2727     xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2728 }
2729
2730 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2731    a translatable string, but not actually translated yet, e.g. enclosed in
2732    N_().  This function is for text strings that are part of the PSPP user
2733    interface, such as names of procedures, statistics, annotations, error
2734    messages, etc.  For strings that come from the user, use
2735    pivot_value_new_user_text(). */
2736 struct pivot_value *
2737 pivot_value_new_text (const char *text)
2738 {
2739   char *c = xstrdup (text);
2740   char *local = xstrdup (gettext (c));
2741
2742   struct pivot_value *value = xmalloc (sizeof *value);
2743   *value = (struct pivot_value) {
2744     .type = PIVOT_VALUE_TEXT,
2745     .text = {
2746       .local = local,
2747       .c = c,
2748       .id = c,
2749       .user_provided = false,
2750     }
2751   };
2752   return value;
2753 }
2754
2755 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2756    string. */
2757 struct pivot_value * PRINTF_FORMAT (1, 2)
2758 pivot_value_new_text_format (const char *format, ...)
2759 {
2760   va_list args;
2761   va_start (args, format);
2762   char *c = xvasprintf (format, args);
2763   va_end (args);
2764
2765   va_start (args, format);
2766   char *local = xvasprintf (gettext (format), args);
2767   va_end (args);
2768
2769   struct pivot_value *value = xmalloc (sizeof *value);
2770   *value = (struct pivot_value) {
2771     .type = PIVOT_VALUE_TEXT,
2772     .text = {
2773       .local = local,
2774       .c = c,
2775       .id = xstrdup (c),
2776       .user_provided = false,
2777     }
2778   };
2779   return value;
2780 }
2781
2782 /* Returns a new pivot_value that represents X.
2783
2784    The format to use for X is unspecified.  Usually the easiest way to specify
2785    a format is through assigning a result class to one of the categories that
2786    the pivot_value will end up in.  If that is not suitable, then the caller
2787    can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2788 struct pivot_value *
2789 pivot_value_new_number (double x)
2790 {
2791   struct pivot_value *value = xmalloc (sizeof *value);
2792   *value = (struct pivot_value) {
2793     .type = PIVOT_VALUE_NUMERIC,
2794     .numeric = { .x = x, },
2795   };
2796   return value;
2797 }
2798
2799 /* Returns a new pivot_value that represents X, formatted as an integer. */
2800 struct pivot_value *
2801 pivot_value_new_integer (double x)
2802 {
2803   struct pivot_value *value = pivot_value_new_number (x);
2804   value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2805   return value;
2806 }
2807
2808 /* Returns a new pivot_value that represents VALUE, formatted as for
2809    VARIABLE. */
2810 struct pivot_value *
2811 pivot_value_new_var_value (const struct variable *variable,
2812                            const union value *value)
2813 {
2814   struct pivot_value *pv = pivot_value_new_value (
2815     value, var_get_width (variable), var_get_print_format (variable),
2816     var_get_encoding (variable));
2817
2818   char *var_name = xstrdup (var_get_name (variable));
2819   if (var_is_alpha (variable))
2820     pv->string.var_name = var_name;
2821   else
2822     pv->numeric.var_name = var_name;
2823
2824   const char *label = var_lookup_value_label (variable, value);
2825   if (label)
2826     {
2827       if (var_is_alpha (variable))
2828         pv->string.value_label = xstrdup (label);
2829       else
2830         pv->numeric.value_label = xstrdup (label);
2831     }
2832
2833   return pv;
2834 }
2835
2836 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2837    formatted with FORMAT.  For a string value, ENCODING must be its character
2838    encoding. */
2839 struct pivot_value *
2840 pivot_value_new_value (const union value *value, int width,
2841                        const struct fmt_spec *format, const char *encoding)
2842 {
2843   struct pivot_value *pv = xzalloc (sizeof *pv);
2844   if (width > 0)
2845     {
2846       char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2847                                width);
2848       size_t n = strlen (s);
2849       while (n > 0 && s[n - 1] == ' ')
2850         s[--n] = '\0';
2851
2852       pv->type = PIVOT_VALUE_STRING;
2853       pv->string.s = s;
2854       pv->string.hex = format->type == FMT_AHEX;
2855     }
2856   else
2857     {
2858       pv->type = PIVOT_VALUE_NUMERIC;
2859       pv->numeric.x = value->f;
2860       pv->numeric.format = *format;
2861     }
2862
2863   return pv;
2864 }
2865
2866 /* Returns a new pivot_value for VARIABLE. */
2867 struct pivot_value *
2868 pivot_value_new_variable (const struct variable *variable)
2869 {
2870   struct pivot_value *value = xmalloc (sizeof *value);
2871   *value = (struct pivot_value) {
2872     .type = PIVOT_VALUE_VARIABLE,
2873     .variable = {
2874       .var_name = xstrdup (var_get_name (variable)),
2875       .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2876     },
2877   };
2878   return value;
2879 }
2880
2881 /* Attaches a reference to FOOTNOTE to V. */
2882 void
2883 pivot_value_add_footnote (struct pivot_value *v,
2884                           const struct pivot_footnote *footnote)
2885 {
2886   /* Some legacy tables include numerous duplicate footnotes.  Suppress
2887      them. */
2888   for (size_t i = 0; i < v->n_footnotes; i++)
2889     if (v->footnote_indexes[i] == footnote->idx)
2890       return;
2891
2892   v->footnote_indexes = xrealloc (
2893     v->footnote_indexes, (v->n_footnotes + 1) * sizeof *v->footnote_indexes);
2894   v->footnote_indexes[v->n_footnotes++] = footnote->idx;
2895   pivot_value_sort_footnotes (v);
2896 }
2897
2898 static int
2899 compare_footnote_indexes (const void *a_, const void *b_)
2900 {
2901   const size_t *ap = a_;
2902   const size_t *bp = b_;
2903   size_t a = *ap;
2904   size_t b = *bp;
2905   return a < b ? -1 : a > b;
2906 }
2907
2908 /* Sorts the footnote references in V in the standard ascending order.
2909
2910    This is only necessary if code adds (plural) footnotes to a pivot_value by
2911    itself, because pivot_value_add_footnote() does it automatically. */
2912 void
2913 pivot_value_sort_footnotes (struct pivot_value *v)
2914 {
2915   if (v->n_footnotes > 1)
2916     qsort (v->footnote_indexes, v->n_footnotes, sizeof *v->footnote_indexes,
2917            compare_footnote_indexes);
2918 }
2919
2920 /* If VALUE is a numeric value, and RC is a result class such as
2921    PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2922 void
2923 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2924                     const char *rc)
2925 {
2926   if (value->type == PIVOT_VALUE_NUMERIC)
2927     pivot_table_use_rc (table, rc,
2928                         &value->numeric.format, &value->numeric.honor_small);
2929 }
2930