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