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