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