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