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