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