c6197beb04dde747307cc757169b00836f69a8cc
[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
1376    TABLE. */
1377 void
1378 pivot_table_set_weight_format (struct pivot_table *table,
1379                                const struct fmt_spec wfmt)
1380 {
1381   table->weight_format = wfmt;
1382 }
1383
1384 /* Returns true if TABLE has no cells, false otherwise. */
1385 bool
1386 pivot_table_is_empty (const struct pivot_table *table)
1387 {
1388   return hmap_is_empty (&table->cells);
1389 }
1390
1391 static unsigned int
1392 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
1393 {
1394   return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
1395 }
1396
1397 static bool
1398 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
1399 {
1400   for (size_t i = 0; i < n; i++)
1401     if (a[i] != b[i])
1402       return false;
1403
1404   return true;
1405 }
1406
1407 static struct pivot_cell *
1408 pivot_table_lookup_cell__ (const struct pivot_table *table,
1409                             const size_t *dindexes, unsigned int hash)
1410 {
1411   struct pivot_cell *cell;
1412   HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
1413                            &table->cells)
1414     if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
1415       return cell;
1416   return false;
1417 }
1418
1419 static struct pivot_cell *
1420 pivot_cell_allocate (size_t n_idx)
1421 {
1422   struct pivot_cell *cell UNUSED;
1423   return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
1424 }
1425
1426 static struct pivot_cell *
1427 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
1428 {
1429   unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1430   struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
1431   if (!cell)
1432     {
1433       cell = pivot_cell_allocate (table->n_dimensions);
1434       for (size_t i = 0; i < table->n_dimensions; i++)
1435         cell->idx[i] = dindexes[i];
1436       cell->value = NULL;
1437       hmap_insert (&table->cells, &cell->hmap_node, hash);
1438     }
1439   return cell;
1440 }
1441
1442 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
1443    DINDEXES.  The order of the indexes is the same as the order in which the
1444    dimensions were created.  N must be the number of dimensions in TABLE.
1445    Takes ownership of VALUE.
1446
1447    If VALUE is a numeric value without a specified format, this function checks
1448    each of the categories designated by DINDEXES[] and takes the format from
1449    the first category with a result class.  If none has a result class, uses
1450    the overall default numeric format. */
1451 void
1452 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
1453                  struct pivot_value *value)
1454 {
1455   assert (n == table->n_dimensions);
1456   for (size_t i = 0; i < n; i++)
1457     assert (dindexes[i] < table->dimensions[i]->n_leaves);
1458
1459   if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
1460     {
1461       for (size_t i = 0; i < table->n_dimensions; i++)
1462         {
1463           const struct pivot_dimension *d = table->dimensions[i];
1464           if (dindexes[i] < d->n_leaves)
1465             {
1466               const struct pivot_category *c = d->data_leaves[dindexes[i]];
1467               if (c->format.w)
1468                 {
1469                   value->numeric.format = c->format;
1470                   value->numeric.honor_small = c->honor_small;
1471                   goto done;
1472                 }
1473             }
1474         }
1475       value->numeric.format = *settings_get_format ();
1476       value->numeric.honor_small = true;
1477
1478     done:;
1479     }
1480
1481   struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1482   pivot_value_destroy (cell->value);
1483   cell->value = value;
1484 }
1485
1486 /* Puts VALUE in the cell in TABLE with index IDX1.  TABLE must have 1
1487    dimension.  Takes ownership of VALUE.  */
1488 void
1489 pivot_table_put1 (struct pivot_table *table, size_t idx1,
1490                   struct pivot_value *value)
1491 {
1492   size_t dindexes[] = { idx1 };
1493   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1494 }
1495
1496 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2).  TABLE must have 2
1497    dimensions.  Takes ownership of VALUE.  */
1498 void
1499 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
1500                   struct pivot_value *value)
1501 {
1502   size_t dindexes[] = { idx1, idx2 };
1503   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1504 }
1505
1506 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3).  TABLE must
1507    have 3 dimensions.  Takes ownership of VALUE.  */
1508 void
1509 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
1510                   size_t idx3, struct pivot_value *value)
1511 {
1512   size_t dindexes[] = { idx1, idx2, idx3 };
1513   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1514 }
1515
1516 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4).  TABLE
1517    must have 4 dimensions.  Takes ownership of VALUE.  */
1518 void
1519 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1520                   size_t idx3, size_t idx4, struct pivot_value *value)
1521 {
1522   size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1523   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1524 }
1525
1526 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1527    automatically assigned marker.
1528
1529    The footnote will only appear in output if it is referenced.  Use
1530    pivot_value_add_footnote() to add a reference to the footnote. */
1531 struct pivot_footnote *
1532 pivot_table_create_footnote (struct pivot_table *table,
1533                              struct pivot_value *content)
1534 {
1535   return pivot_table_create_footnote__ (table, table->n_footnotes,
1536                                         NULL, content);
1537 }
1538
1539 void
1540 pivot_footnote_format_marker (const struct pivot_footnote *f,
1541                               const struct pivot_table *pt,
1542                               struct string *s)
1543 {
1544   if (f->marker)
1545     pivot_value_format_body (f->marker, pt, s);
1546   else if (pt->look->show_numeric_markers)
1547     ds_put_format (s, "%zu", f->idx + 1);
1548   else
1549     {
1550       char text[INT_BUFSIZE_BOUND (size_t)];
1551       str_format_26adic (f->idx + 1, false, text, sizeof text);
1552       ds_put_cstr (s, text);
1553     }
1554 }
1555
1556 char *
1557 pivot_footnote_marker_string (const struct pivot_footnote *f,
1558                               const struct pivot_table *pt)
1559 {
1560   struct string s = DS_EMPTY_INITIALIZER;
1561   pivot_footnote_format_marker (f, pt, &s);
1562   return ds_steal_cstr (&s);
1563 }
1564
1565 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1566    all lower indexes as a side effect).  If MARKER is nonnull, sets the
1567    footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1568 struct pivot_footnote *
1569 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1570                                struct pivot_value *marker,
1571                                struct pivot_value *content)
1572 {
1573   if (idx >= table->n_footnotes)
1574     {
1575       while (idx >= table->allocated_footnotes)
1576         table->footnotes = x2nrealloc (table->footnotes,
1577                                        &table->allocated_footnotes,
1578                                        sizeof *table->footnotes);
1579       while (idx >= table->n_footnotes)
1580         {
1581           struct pivot_footnote *f = xmalloc (sizeof *f);
1582           *f = (struct pivot_footnote) {
1583             .idx = table->n_footnotes,
1584             .show = true,
1585           };
1586           table->footnotes[table->n_footnotes++] = f;
1587         }
1588     }
1589
1590   struct pivot_footnote *f = table->footnotes[idx];
1591   if (marker)
1592     {
1593       pivot_value_destroy (f->marker);
1594       f->marker = marker;
1595     }
1596   if (content)
1597     {
1598       pivot_value_destroy (f->content);
1599       f->content = content;
1600     }
1601   return f;
1602 }
1603
1604 /* Frees the data owned by F. */
1605 void
1606 pivot_footnote_destroy (struct pivot_footnote *f)
1607 {
1608   if (f)
1609     {
1610       pivot_value_destroy (f->content);
1611       pivot_value_destroy (f->marker);
1612       free (f);
1613     }
1614 }
1615
1616 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1617    indexes for each dimension in TABLE in DINDEXES[]. */
1618 void
1619 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1620                                   const size_t *pindexes[PIVOT_N_AXES],
1621                                   size_t dindexes[/* table->n_dimensions */])
1622 {
1623   for (size_t i = 0; i < PIVOT_N_AXES; i++)
1624     {
1625       const struct pivot_axis *axis = &table->axes[i];
1626
1627       for (size_t j = 0; j < axis->n_dimensions; j++)
1628         {
1629           const struct pivot_dimension *d = axis->dimensions[j];
1630           size_t pindex = pindexes[i][j];
1631           dindexes[d->top_index] = d->presentation_leaves[pindex]->data_index;
1632         }
1633     }
1634 }
1635
1636 size_t *
1637 pivot_table_enumerate_axis (const struct pivot_table *table,
1638                             enum pivot_axis_type axis_type,
1639                             const size_t *layer_indexes, bool omit_empty,
1640                             size_t *n)
1641 {
1642   const struct pivot_axis *axis = &table->axes[axis_type];
1643   if (!axis->n_dimensions)
1644     {
1645       size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1646       enumeration[0] = 0;
1647       enumeration[1] = SIZE_MAX;
1648       if (n)
1649         *n = 1;
1650       return enumeration;
1651     }
1652   else if (!axis->extent)
1653     {
1654       size_t *enumeration = xmalloc (sizeof *enumeration);
1655       *enumeration = SIZE_MAX;
1656       if (n)
1657         *n = 0;
1658       return enumeration;
1659     }
1660
1661   size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1662                                                 axis->n_dimensions), 1),
1663                                   sizeof *enumeration);
1664   size_t *p = enumeration;
1665   size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1666
1667   size_t *axis_indexes;
1668   PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1669     {
1670       if (omit_empty)
1671         {
1672           enum pivot_axis_type axis2_type
1673             = pivot_axis_type_transpose (axis_type);
1674
1675           size_t *axis2_indexes;
1676           PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1677             {
1678               const size_t *pindexes[PIVOT_N_AXES];
1679               pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1680               pindexes[axis_type] = axis_indexes;
1681               pindexes[axis2_type] = axis2_indexes;
1682               pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1683               if (pivot_table_get (table, dindexes))
1684                 goto found;
1685             }
1686           continue;
1687
1688         found:
1689           free (axis2_indexes);
1690         }
1691
1692       memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1693       p += axis->n_dimensions;
1694     }
1695   if (omit_empty && p == enumeration)
1696     {
1697       PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1698         {
1699           memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1700           p += axis->n_dimensions;
1701         }
1702     }
1703   *p = SIZE_MAX;
1704   if (n)
1705     *n = (p - enumeration) / axis->n_dimensions;
1706
1707   free (dindexes);
1708   return enumeration;
1709 }
1710
1711 static struct pivot_cell *
1712 pivot_table_lookup_cell (const struct pivot_table *table,
1713                          const size_t *dindexes)
1714 {
1715   unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1716   return pivot_table_lookup_cell__ (table, dindexes, hash);
1717 }
1718
1719 const struct pivot_value *
1720 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1721 {
1722   const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1723   return cell ? cell->value : NULL;
1724 }
1725
1726 struct pivot_value *
1727 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1728 {
1729   struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1730   if (!cell->value)
1731     cell->value = pivot_value_new_user_text ("", -1);
1732   return cell->value;
1733 }
1734
1735 static void
1736 pivot_table_delete_cell (struct pivot_table *table, struct pivot_cell *cell)
1737 {
1738   hmap_delete (&table->cells, &cell->hmap_node);
1739   pivot_value_destroy (cell->value);
1740   free (cell);
1741 }
1742
1743 bool
1744 pivot_table_delete (struct pivot_table *table, const size_t *dindexes)
1745 {
1746   struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1747   if (cell)
1748     {
1749       pivot_table_delete_cell (table, cell);
1750       return true;
1751     }
1752   else
1753     return false;
1754 }
1755
1756 static void
1757 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1758 {
1759   if (pivot_category_is_group (category) && category->n_subs)
1760     for (size_t i = 0; i < category->n_subs; i++)
1761       distribute_extra_depth (category->subs[i], extra_depth);
1762   else
1763     category->extra_depth += extra_depth;
1764 }
1765
1766 static void
1767 pivot_category_assign_label_depth (struct pivot_category *category,
1768                                    bool dimension_labels_in_corner)
1769 {
1770   category->extra_depth = 0;
1771
1772   if (pivot_category_is_group (category))
1773     {
1774       size_t depth = 0;
1775       for (size_t i = 0; i < category->n_subs; i++)
1776         {
1777           pivot_category_assign_label_depth (category->subs[i], false);
1778           depth = MAX (depth, category->subs[i]->label_depth);
1779         }
1780
1781       for (size_t i = 0; i < category->n_subs; i++)
1782         {
1783           struct pivot_category *sub = category->subs[i];
1784
1785           size_t extra_depth = depth - sub->label_depth;
1786           if (extra_depth)
1787             distribute_extra_depth (sub, extra_depth);
1788
1789           sub->label_depth = depth;
1790         }
1791
1792       category->show_label_in_corner = (category->show_label
1793                                         && dimension_labels_in_corner);
1794       category->label_depth
1795         = (category->show_label && !category->show_label_in_corner
1796            ? depth + 1 : depth);
1797     }
1798   else
1799     category->label_depth = 1;
1800 }
1801
1802 static bool
1803 pivot_axis_assign_label_depth (struct pivot_table *table,
1804                              enum pivot_axis_type axis_type,
1805                              bool dimension_labels_in_corner)
1806 {
1807   struct pivot_axis *axis = &table->axes[axis_type];
1808   bool any_label_shown_in_corner = false;
1809   axis->label_depth = 0;
1810   axis->extent = 1;
1811   for (size_t i = 0; i < axis->n_dimensions; i++)
1812     {
1813       struct pivot_dimension *d = axis->dimensions[i];
1814       pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1815       d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1816       axis->label_depth += d->label_depth;
1817       axis->extent *= d->n_leaves;
1818
1819       if (d->root->show_label_in_corner)
1820         any_label_shown_in_corner = true;
1821     }
1822   return any_label_shown_in_corner;
1823 }
1824
1825 void
1826 pivot_table_assign_label_depth (struct pivot_table *table)
1827 {
1828   pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1829   if (pivot_axis_assign_label_depth (
1830         table, PIVOT_AXIS_ROW, (table->look->row_labels_in_corner
1831                                 && !table->corner_text))
1832       && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1833     table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1834   pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1835 }
1836 \f
1837 static void
1838 indent (int indentation)
1839 {
1840   for (int i = 0; i < indentation * 2; i++)
1841     putchar (' ');
1842 }
1843
1844 static void
1845 pivot_value_dump (const struct pivot_value *value,
1846                   const struct pivot_table *pt)
1847 {
1848   char *s = pivot_value_to_string (value, pt);
1849   fputs (s, stdout);
1850   free (s);
1851 }
1852
1853 static void
1854 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1855                         const struct pivot_table *pt, int indentation)
1856 {
1857   if (value)
1858     {
1859       indent (indentation);
1860       printf ("%s: ", name);
1861       pivot_value_dump (value, pt);
1862       putchar ('\n');
1863     }
1864 }
1865
1866 static void
1867 pivot_table_dump_string (const char *string, const char *name, int indentation)
1868 {
1869   if (string)
1870     {
1871       indent (indentation);
1872       printf ("%s: %s\n", name, string);
1873     }
1874 }
1875
1876 static void
1877 pivot_category_dump (const struct pivot_category *c,
1878                      const struct pivot_table *pt, int indentation)
1879 {
1880   indent (indentation);
1881   printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1882   pivot_value_dump (c->name, pt);
1883   printf ("\" ");
1884
1885   if (pivot_category_is_leaf (c))
1886     printf ("data_index=%zu\n", c->data_index);
1887   else
1888     {
1889       printf (" (label %s)", c->show_label ? "shown" : "hidden");
1890       printf ("\n");
1891
1892       for (size_t i = 0; i < c->n_subs; i++)
1893         pivot_category_dump (c->subs[i], pt, indentation + 1);
1894     }
1895 }
1896
1897 void
1898 pivot_dimension_dump (const struct pivot_dimension *d,
1899                       const struct pivot_table *pt, int indentation)
1900 {
1901   indent (indentation);
1902   printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1903           pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1904
1905   pivot_category_dump (d->root, pt, indentation + 1);
1906 }
1907
1908 static void
1909 table_area_style_dump (enum pivot_area area, const struct table_area_style *a,
1910                        int indentation)
1911 {
1912   indent (indentation);
1913   printf ("%s: ", pivot_area_to_string (area));
1914   font_style_dump (&a->font_style);
1915   putchar (' ');
1916   cell_style_dump (&a->cell_style);
1917   putchar ('\n');
1918 }
1919
1920 static void
1921 table_border_style_dump (enum pivot_border border,
1922                          const struct table_border_style *b, int indentation)
1923 {
1924   indent (indentation);
1925   printf ("%s: %s ", pivot_border_to_string (border),
1926           table_stroke_to_string (b->stroke));
1927   cell_color_dump (&b->color);
1928   putchar ('\n');
1929 }
1930
1931 static char ***
1932 compose_headings (const struct pivot_table *pt,
1933                   const struct pivot_axis *axis,
1934                   const size_t *column_enumeration)
1935 {
1936   if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1937     return NULL;
1938
1939   char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1940   for (size_t i = 0; i < axis->label_depth; i++)
1941     headings[i] = xcalloc (axis->extent, sizeof **headings);
1942
1943   const size_t *indexes;
1944   size_t column = 0;
1945   PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1946     {
1947       int row = axis->label_depth - 1;
1948       for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1949         {
1950           const struct pivot_dimension *d = axis->dimensions[dim_index];
1951           if (d->hide_all_labels)
1952             continue;
1953           for (const struct pivot_category *c
1954                  = d->presentation_leaves[indexes[dim_index]];
1955                c;
1956                c = c->parent)
1957             {
1958               if (pivot_category_is_leaf (c) || (c->show_label
1959                                                  && !c->show_label_in_corner))
1960                 {
1961                   headings[row][column] = pivot_value_to_string (c->name, pt);
1962                   if (!*headings[row][column])
1963                     {
1964                       free (headings[row][column]);
1965                       headings[row][column] = xstrdup ("<blank>");
1966                     }
1967                   row--;
1968                 }
1969             }
1970         }
1971       column++;
1972     }
1973
1974   return headings;
1975 }
1976
1977 static void
1978 free_headings (const struct pivot_axis *axis, char ***headings)
1979 {
1980   if (!headings)
1981     return;
1982   for (size_t i = 0; i < axis->label_depth; i++)
1983     {
1984       for (size_t j = 0; j < axis->extent; j++)
1985         free (headings[i][j]);
1986       free (headings[i]);
1987     }
1988   free (headings);
1989 }
1990
1991 static void
1992 pivot_table_sizing_dump (const char *name,
1993                          const int width_ranges[2],
1994                          const struct pivot_table_sizing *s,
1995                          int indentation)
1996 {
1997   indent (indentation);
1998   printf ("%ss: min=%d, max=%d\n", name, width_ranges[0], width_ranges[1]);
1999   if (s->n_widths)
2000     {
2001       indent (indentation + 1);
2002       printf ("%s widths:", name);
2003       for (size_t i = 0; i < s->n_widths; i++)
2004         printf (" %d", s->widths[i]);
2005       printf ("\n");
2006     }
2007   if (s->n_breaks)
2008     {
2009       indent (indentation + 1);
2010       printf ("break after %ss:", name);
2011       for (size_t i = 0; i < s->n_breaks; i++)
2012         printf (" %zu", s->breaks[i]);
2013       printf ("\n");
2014     }
2015   if (s->n_keeps)
2016     {
2017       indent (indentation + 1);
2018       printf ("keep %ss together:", name);
2019       for (size_t i = 0; i < s->n_keeps; i++)
2020         printf (" [%zu,%zu]",
2021                 s->keeps[i].ofs,
2022                 s->keeps[i].ofs + s->keeps[i].n - 1);
2023       printf ("\n");
2024     }
2025 }
2026
2027 static void
2028 dump_leaf (const struct pivot_table *table, const struct pivot_category *c)
2029 {
2030   if (c)
2031     {
2032       dump_leaf (table, c->parent);
2033       if (pivot_category_is_leaf (c) || c->show_label)
2034         {
2035           putchar (' ');
2036           pivot_value_dump (c->name, table);
2037         }
2038     }
2039 }
2040
2041 void
2042 pivot_table_dump (const struct pivot_table *table, int indentation)
2043 {
2044   if (!table)
2045     return;
2046
2047   pivot_table_assign_label_depth (CONST_CAST (struct pivot_table *, table));
2048
2049   pivot_table_dump_value (table->title, "title", table, indentation);
2050   pivot_table_dump_value (table->subtype, "subtype", table, indentation);
2051   pivot_table_dump_string (table->command_c, "command", indentation);
2052   pivot_table_dump_string (table->dataset, "dataset", indentation);
2053   pivot_table_dump_string (table->datafile, "datafile", indentation);
2054   pivot_table_dump_string (table->notes, "notes", indentation);
2055   pivot_table_dump_string (table->look->name, "table-look", indentation);
2056   if (table->date)
2057     {
2058       indent (indentation);
2059
2060       struct tm *tm = localtime (&table->date);
2061       printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
2062               tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
2063               tm->tm_sec);
2064     }
2065
2066   indent (indentation);
2067   printf ("sizing:\n");
2068   pivot_table_sizing_dump ("column", table->look->col_heading_width_range,
2069                            &table->sizing[TABLE_HORZ], indentation + 1);
2070   pivot_table_sizing_dump ("row", table->look->row_heading_width_range,
2071                            &table->sizing[TABLE_VERT], indentation + 1);
2072
2073   indent (indentation);
2074   printf ("areas:\n");
2075   for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
2076     table_area_style_dump (area, &table->look->areas[area], indentation + 1);
2077
2078   indent (indentation);
2079   printf ("borders:\n");
2080   for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
2081     table_border_style_dump (border, &table->look->borders[border],
2082                              indentation + 1);
2083
2084   for (size_t i = 0; i < table->n_dimensions; i++)
2085     pivot_dimension_dump (table->dimensions[i], table, indentation);
2086
2087   /* Presentation and data indexes. */
2088   size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
2089
2090   const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
2091   if (layer_axis->n_dimensions)
2092     {
2093       indent (indentation);
2094       printf ("current layer:");
2095
2096       for (size_t i = 0; i < layer_axis->n_dimensions; i++)
2097         {
2098           const struct pivot_dimension *d = layer_axis->dimensions[i];
2099           char *name = pivot_value_to_string (d->root->name, table);
2100           printf (" %s", name);
2101           free (name);
2102
2103           size_t ofs = table->current_layer[i];
2104           if (ofs < d->n_leaves)
2105             {
2106               char *value = pivot_value_to_string (d->data_leaves[ofs]->name,
2107                                                    table);
2108               printf ("=%s", value);
2109               free (value);
2110             }
2111         }
2112
2113       putchar ('\n');
2114     }
2115
2116   size_t *layer_indexes;
2117   size_t layer_iteration = 0;
2118   PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
2119     {
2120       indent (indentation);
2121       printf ("layer %zu:", layer_iteration++);
2122
2123       const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
2124       for (size_t i = 0; i < layer_axis->n_dimensions; i++)
2125         {
2126           const struct pivot_dimension *d = layer_axis->dimensions[i];
2127
2128           fputs (i == 0 ? " " : ", ", stdout);
2129           pivot_value_dump (d->root->name, table);
2130           fputs (" =", stdout);
2131
2132           dump_leaf (table, d->presentation_leaves[layer_indexes[i]]);
2133         }
2134       putchar ('\n');
2135
2136       size_t *column_enumeration = pivot_table_enumerate_axis (
2137         table, PIVOT_AXIS_COLUMN, layer_indexes, table->look->omit_empty, NULL);
2138       size_t *row_enumeration = pivot_table_enumerate_axis (
2139         table, PIVOT_AXIS_ROW, layer_indexes, table->look->omit_empty, NULL);
2140
2141       /* Print column headings.
2142
2143          Ordinarily the test for nonnull 'column_headings' would be
2144          unnecessary, because 'column_headings' is null only if the axis's
2145          label_depth is 0, but there is a special case for the column axis only
2146          in pivot_table_assign_label_depth(). */
2147       char ***column_headings = compose_headings (
2148         table, &table->axes[PIVOT_AXIS_COLUMN], column_enumeration);
2149       if (column_headings)
2150         {
2151           for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
2152             {
2153               indent (indentation + 1);
2154               for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
2155                 {
2156                   if (x)
2157                     fputs ("; ", stdout);
2158                   if (column_headings && column_headings[y] && column_headings[y][x])
2159                     fputs (column_headings[y][x], stdout);
2160                 }
2161               putchar ('\n');
2162             }
2163           free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
2164         }
2165
2166       indent (indentation + 1);
2167       printf ("-----------------------------------------------\n");
2168
2169       char ***row_headings = compose_headings (
2170         table, &table->axes[PIVOT_AXIS_ROW], row_enumeration);
2171
2172       size_t x = 0;
2173       const size_t *pindexes[PIVOT_N_AXES]
2174         = { [PIVOT_AXIS_LAYER] = layer_indexes };
2175       PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
2176                                   &table->axes[PIVOT_AXIS_ROW])
2177         {
2178           indent (indentation + 1);
2179
2180           size_t i = 0;
2181           for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
2182             {
2183               if (i++)
2184                 fputs ("; ", stdout);
2185               if (row_headings[y][x])
2186                 fputs (row_headings[y][x], stdout);
2187             }
2188
2189           printf (" | ");
2190
2191           i = 0;
2192           PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
2193                                       column_enumeration,
2194                                       &table->axes[PIVOT_AXIS_COLUMN])
2195             {
2196               if (i++)
2197                 printf ("; ");
2198
2199               pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
2200               const struct pivot_value *value = pivot_table_get (
2201                 table, dindexes);
2202               if (value)
2203                 pivot_value_dump (value, table);
2204             }
2205           printf ("\n");
2206
2207           x++;
2208         }
2209
2210       free (column_enumeration);
2211       free (row_enumeration);
2212       free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
2213     }
2214
2215   pivot_table_dump_value (table->caption, "caption", table, indentation);
2216
2217   for (size_t i = 0; i < table->n_footnotes; i++)
2218     {
2219       const struct pivot_footnote *f = table->footnotes[i];
2220       indent (indentation);
2221       putchar ('[');
2222       if (f->marker)
2223         pivot_value_dump (f->marker, table);
2224       else
2225         printf ("%zu", f->idx);
2226       putchar (']');
2227       pivot_value_dump (f->content, table);
2228       putchar ('\n');
2229     }
2230
2231   free (dindexes);
2232 }
2233 \f
2234 static const char *
2235 consume_int (const char *p, size_t *n)
2236 {
2237   *n = 0;
2238   while (c_isdigit (*p))
2239     *n = *n * 10 + (*p++ - '0');
2240   return p;
2241 }
2242
2243 static size_t
2244 pivot_format_inner_template (struct string *out, const char *template,
2245                              char escape,
2246                              struct pivot_value **values, size_t n_values,
2247                              const struct pivot_table *pt)
2248 {
2249   size_t args_consumed = 0;
2250   while (*template && *template != ':')
2251     {
2252       if (*template == '\\' && template[1])
2253         {
2254           ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
2255           template += 2;
2256         }
2257       else if (*template == escape)
2258         {
2259           size_t index;
2260           template = consume_int (template + 1, &index);
2261           if (index >= 1 && index <= n_values)
2262             {
2263               pivot_value_format (values[index - 1], pt, out);
2264               args_consumed = MAX (args_consumed, index);
2265             }
2266         }
2267       else
2268         ds_put_byte (out, *template++);
2269     }
2270   return args_consumed;
2271 }
2272
2273 static const char *
2274 pivot_extract_inner_template (const char *template, const char **p)
2275 {
2276   *p = template;
2277
2278   for (;;)
2279     {
2280       if (*template == '\\' && template[1] != '\0')
2281         template += 2;
2282       else if (*template == ':')
2283         return template + 1;
2284       else if (*template == '\0')
2285         return template;
2286       else
2287         template++;
2288     }
2289 }
2290
2291 static void
2292 pivot_format_template (struct string *out, const char *template,
2293                        const struct pivot_argument *args, size_t n_args,
2294                        const struct pivot_table *pt)
2295 {
2296   while (*template)
2297     {
2298       if (*template == '\\' && template[1] != '\0')
2299         {
2300           ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
2301           template += 2;
2302         }
2303       else if (*template == '^')
2304         {
2305           size_t index;
2306           template = consume_int (template + 1, &index);
2307           if (index >= 1 && index <= n_args && args[index - 1].n > 0)
2308             pivot_value_format (args[index - 1].values[0], pt, out);
2309         }
2310       else if (*template == '[')
2311         {
2312           const char *tmpl[2];
2313           template = pivot_extract_inner_template (template + 1, &tmpl[0]);
2314           template = pivot_extract_inner_template (template, &tmpl[1]);
2315           template += *template == ']';
2316
2317           size_t index;
2318           template = consume_int (template, &index);
2319           if (index < 1 || index > n_args)
2320             continue;
2321
2322           const struct pivot_argument *arg = &args[index - 1];
2323           size_t left = arg->n;
2324           while (left)
2325             {
2326               struct pivot_value **values = arg->values + (arg->n - left);
2327               int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
2328               char escape = "%^"[tmpl_idx];
2329               size_t used = pivot_format_inner_template (
2330                 out, tmpl[tmpl_idx], escape, values, left, pt);
2331               if (!used || used > left)
2332                 break;
2333               left -= used;
2334             }
2335         }
2336       else
2337         ds_put_byte (out, *template++);
2338     }
2339 }
2340
2341 static enum settings_value_show
2342 interpret_show (enum settings_value_show global_show,
2343                 enum settings_value_show table_show,
2344                 enum settings_value_show value_show,
2345                 bool has_label)
2346 {
2347   return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
2348           : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
2349           : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
2350           : global_show);
2351 }
2352
2353 /* Appends to OUT the actual text content from the given Pango MARKUP. */
2354 static void
2355 get_text_from_markup (const char *markup, struct string *out)
2356 {
2357   xmlParserCtxt *parser = xmlCreatePushParserCtxt (NULL, NULL, NULL, 0, NULL);
2358   if (!parser)
2359     {
2360       ds_put_cstr (out, markup);
2361       return;
2362     }
2363
2364   xmlParseChunk (parser, "<xml>", strlen ("<xml>"), false);
2365   xmlParseChunk (parser, markup, strlen (markup), false);
2366   xmlParseChunk (parser, "</xml>", strlen ("</xml>"), true);
2367
2368   if (parser->wellFormed)
2369     {
2370       xmlChar *s = xmlNodeGetContent (xmlDocGetRootElement (parser->myDoc));
2371       ds_put_cstr (out, CHAR_CAST (char *, s));
2372       xmlFree (s);
2373     }
2374   else
2375     ds_put_cstr (out, markup);
2376   xmlFreeDoc (parser->myDoc);
2377   xmlFreeParserCtxt (parser);
2378 }
2379
2380 static const struct pivot_table pivot_value_format_defaults = {
2381   .show_values = SETTINGS_VALUE_SHOW_DEFAULT,
2382   .show_variables = SETTINGS_VALUE_SHOW_DEFAULT,
2383   .settings = FMT_SETTINGS_INIT,
2384 };
2385
2386 /* Appends a text representation of the body of VALUE to OUT.  Settings on PT
2387    control whether variable and value labels are included (pass NULL for PT to
2388    get default formatting in the absence of a pivot table).
2389
2390    The "body" omits subscripts and superscripts and footnotes.
2391
2392    Returns true if OUT is a number (or a number plus a value label), false
2393    otherwise.  */
2394 bool
2395 pivot_value_format_body (const struct pivot_value *value,
2396                          const struct pivot_table *pt_,
2397                          struct string *out)
2398 {
2399   const struct pivot_table *pt = pt_ ? pt_ : &pivot_value_format_defaults;
2400   enum settings_value_show show;
2401   bool numeric = false;
2402
2403   switch (value->type)
2404     {
2405     case PIVOT_VALUE_NUMERIC:
2406       show = interpret_show (settings_get_show_values (),
2407                              pt->show_values,
2408                              value->numeric.show,
2409                              value->numeric.value_label != NULL);
2410       if (show & SETTINGS_VALUE_SHOW_VALUE)
2411         {
2412           const struct fmt_spec *f = &value->numeric.format;
2413           const struct fmt_spec *format
2414             = (f->type == FMT_F
2415                && value->numeric.honor_small
2416                && value->numeric.x != 0
2417                && fabs (value->numeric.x) < pt->small
2418                ? &(struct fmt_spec) { .type = FMT_E, .w = 40, .d = f->d }
2419                : f);
2420
2421           char *s = data_out (&(union value) { .f = value->numeric.x },
2422                               "UTF-8", format, &pt->settings);
2423           ds_put_cstr (out, s + strspn (s, " "));
2424           free (s);
2425         }
2426       if (show & SETTINGS_VALUE_SHOW_LABEL)
2427         {
2428           if (show & SETTINGS_VALUE_SHOW_VALUE)
2429             ds_put_byte (out, ' ');
2430           ds_put_cstr (out, value->numeric.value_label);
2431         }
2432       numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
2433       break;
2434
2435     case PIVOT_VALUE_STRING:
2436       show = interpret_show (settings_get_show_values (),
2437                              pt->show_values,
2438                              value->string.show,
2439                              value->string.value_label != NULL);
2440       if (show & SETTINGS_VALUE_SHOW_VALUE)
2441         {
2442           if (value->string.hex)
2443             {
2444               for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
2445                    *p; p++)
2446                 ds_put_format (out, "%02X", *p);
2447             }
2448           else
2449             ds_put_cstr (out, value->string.s);
2450         }
2451       if (show & SETTINGS_VALUE_SHOW_LABEL)
2452         {
2453           if (show & SETTINGS_VALUE_SHOW_VALUE)
2454             ds_put_byte (out, ' ');
2455           ds_put_cstr (out, value->string.value_label);
2456         }
2457       break;
2458
2459     case PIVOT_VALUE_VARIABLE:
2460       show = interpret_show (settings_get_show_variables (),
2461                              pt->show_variables,
2462                              value->variable.show,
2463                              value->variable.var_label != NULL);
2464       if (show & SETTINGS_VALUE_SHOW_VALUE)
2465         ds_put_cstr (out, value->variable.var_name);
2466       if (show & SETTINGS_VALUE_SHOW_LABEL)
2467         {
2468           if (show & SETTINGS_VALUE_SHOW_VALUE)
2469             ds_put_byte (out, ' ');
2470           ds_put_cstr (out, value->variable.var_label);
2471         }
2472       break;
2473
2474     case PIVOT_VALUE_TEXT:
2475       if (value->ex && value->ex->font_style && value->ex->font_style->markup)
2476         get_text_from_markup (value->text.local, out);
2477       else
2478         ds_put_cstr (out, value->text.local);
2479       break;
2480
2481     case PIVOT_VALUE_TEMPLATE:
2482       pivot_format_template (out, value->template.local, value->template.args,
2483                              value->template.n_args, pt);
2484       break;
2485     }
2486
2487   return numeric;
2488 }
2489
2490 /* Appends a text representation of VALUE to OUT.  Settings on PT control
2491    whether variable and value labels are included (pass NULL for PT to get
2492    default formatting in the absence of a pivot table).
2493
2494    Subscripts and footnotes are included.
2495
2496    Returns true if OUT is a number (or a number plus a value label), false
2497    otherwise.  */
2498 bool
2499 pivot_value_format (const struct pivot_value *value,
2500                     const struct pivot_table *pt_,
2501                     struct string *out)
2502 {
2503   const struct pivot_table *pt = pt_ ? pt_ : &pivot_value_format_defaults;
2504   bool numeric = pivot_value_format_body (value, pt, out);
2505
2506   const struct pivot_value_ex *ex = value->ex;
2507   if (ex)
2508     {
2509       if (ex->n_subscripts)
2510         {
2511           for (size_t i = 0; i < ex->n_subscripts; i++)
2512             ds_put_format (out, "%c%s", i ? ',' : '_', ex->subscripts[i]);
2513         }
2514
2515       for (size_t i = 0; i < ex->n_footnotes; i++)
2516         {
2517           ds_put_byte (out, '[');
2518
2519           size_t idx = ex->footnote_indexes[i];
2520           const struct pivot_footnote *f = pt->footnotes[idx];
2521           pivot_footnote_format_marker (f, pt, out);
2522
2523           ds_put_byte (out, ']');
2524         }
2525     }
2526
2527   return numeric;
2528 }
2529
2530 /* Returns a text representation of VALUE.  The caller must free the string,
2531    with free().  Settings on PT control whether variable and value labels are
2532    included (pass NULL for PT to get default formatting in the absence of a
2533    pivot table). */
2534 char *
2535 pivot_value_to_string (const struct pivot_value *value,
2536                        const struct pivot_table *pt)
2537 {
2538   struct string s = DS_EMPTY_INITIALIZER;
2539   pivot_value_format (value, pt, &s);
2540   return ds_steal_cstr (&s);
2541 }
2542
2543 struct pivot_value *
2544 pivot_value_clone (const struct pivot_value *old)
2545 {
2546   if (!old)
2547     return NULL;
2548
2549   struct pivot_value *new = xmemdup (old, sizeof *new);
2550   if (old->ex)
2551     new->ex = pivot_value_ex_clone (old->ex);
2552
2553   switch (new->type)
2554     {
2555     case PIVOT_VALUE_NUMERIC:
2556       new->numeric.var_name = xstrdup_if_nonnull (new->numeric.var_name);
2557       new->numeric.value_label = xstrdup_if_nonnull (new->numeric.value_label);
2558       break;
2559
2560     case PIVOT_VALUE_STRING:
2561       new->string.s = xstrdup (new->string.s);
2562       new->string.var_name = xstrdup_if_nonnull (new->string.var_name);
2563       new->string.value_label = xstrdup_if_nonnull (new->string.value_label);
2564       break;
2565
2566     case PIVOT_VALUE_VARIABLE:
2567       new->variable.var_name = xstrdup_if_nonnull (new->variable.var_name);
2568       new->variable.var_label = xstrdup_if_nonnull (new->variable.var_label);
2569       break;
2570
2571     case PIVOT_VALUE_TEXT:
2572       new->text.local = xstrdup (old->text.local);
2573       new->text.c = (old->text.c == old->text.local ? new->text.local
2574                      : xstrdup_if_nonnull (old->text.c));
2575       new->text.id = (old->text.id == old->text.local ? new->text.local
2576                       : old->text.id == old->text.c ? new->text.c
2577                       : xstrdup_if_nonnull (old->text.id));
2578       break;
2579
2580     case PIVOT_VALUE_TEMPLATE:
2581       new->template.local = xstrdup (old->template.local);
2582       new->template.id = (old->template.id == old->template.local
2583                           ? new->template.local
2584                           : xstrdup (old->template.id));
2585       new->template.args = xmalloc (new->template.n_args
2586                                     * sizeof *new->template.args);
2587       for (size_t i = 0; i < old->template.n_args; i++)
2588         pivot_argument_copy (&new->template.args[i],
2589                              &old->template.args[i]);
2590       break;
2591
2592     default:
2593       NOT_REACHED ();
2594     }
2595   return new;
2596 }
2597
2598 /* Frees the data owned by V. */
2599 void
2600 pivot_value_destroy (struct pivot_value *value)
2601 {
2602   if (value)
2603     {
2604       pivot_value_ex_destroy (value->ex);
2605       switch (value->type)
2606         {
2607         case PIVOT_VALUE_NUMERIC:
2608           free (value->numeric.var_name);
2609           free (value->numeric.value_label);
2610           break;
2611
2612         case PIVOT_VALUE_STRING:
2613           free (value->string.s);
2614           free (value->string.var_name);
2615           free (value->string.value_label);
2616           break;
2617
2618         case PIVOT_VALUE_VARIABLE:
2619           free (value->variable.var_name);
2620           free (value->variable.var_label);
2621           break;
2622
2623         case PIVOT_VALUE_TEXT:
2624           free (value->text.local);
2625           if (value->text.c != value->text.local)
2626             free (value->text.c);
2627           if (value->text.id != value->text.local
2628               && value->text.id != value->text.c)
2629             free (value->text.id);
2630           break;
2631
2632         case PIVOT_VALUE_TEMPLATE:
2633           free (value->template.local);
2634           if (value->template.id != value->template.local)
2635             free (value->template.id);
2636           for (size_t i = 0; i < value->template.n_args; i++)
2637             pivot_argument_uninit (&value->template.args[i]);
2638           free (value->template.args);
2639           break;
2640
2641         default:
2642           NOT_REACHED ();
2643         }
2644       free (value);
2645     }
2646 }
2647
2648 /* Sets AREA to the style to use for VALUE, with defaults coming from
2649    DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
2650 void
2651 pivot_value_get_style (struct pivot_value *value,
2652                        const struct font_style *base_font_style,
2653                        const struct cell_style *base_cell_style,
2654                        struct table_area_style *area)
2655 {
2656   const struct pivot_value_ex *ex = pivot_value_ex (value);
2657   font_style_copy (NULL, &area->font_style,
2658                    ex->font_style ? ex->font_style : base_font_style);
2659   area->cell_style = *(ex->cell_style ? ex->cell_style : base_cell_style);
2660 }
2661
2662 /* Copies AREA into VALUE's style. */
2663 void
2664 pivot_value_set_style (struct pivot_value *value,
2665                        const struct table_area_style *area)
2666 {
2667   pivot_value_set_font_style (value, &area->font_style);
2668   pivot_value_set_cell_style (value, &area->cell_style);
2669 }
2670
2671 void
2672 pivot_value_set_font_style (struct pivot_value *value,
2673                             const struct font_style *font_style)
2674 {
2675   struct pivot_value_ex *ex = pivot_value_ex_rw (value);
2676   if (ex->font_style)
2677     font_style_uninit (ex->font_style);
2678   else
2679     ex->font_style = xmalloc (sizeof *ex->font_style);
2680   font_style_copy (NULL, ex->font_style, font_style);
2681 }
2682
2683 void
2684 pivot_value_set_cell_style (struct pivot_value *value,
2685                             const struct cell_style *cell_style)
2686 {
2687   struct pivot_value_ex *ex = pivot_value_ex_rw (value);
2688   if (!ex->cell_style)
2689     ex->cell_style = xmalloc (sizeof *ex->cell_style);
2690   *ex->cell_style = *cell_style;
2691 }
2692
2693 void
2694 pivot_argument_copy (struct pivot_argument *dst,
2695                      const struct pivot_argument *src)
2696 {
2697   *dst = (struct pivot_argument) {
2698     .n = src->n,
2699     .values = xmalloc (src->n * sizeof *dst->values),
2700   };
2701
2702   for (size_t i = 0; i < src->n; i++)
2703     dst->values[i] = pivot_value_clone (src->values[i]);
2704 }
2705
2706 /* Frees the data owned by ARG (but not ARG itself). */
2707 void
2708 pivot_argument_uninit (struct pivot_argument *arg)
2709 {
2710   if (arg)
2711     {
2712       for (size_t i = 0; i < arg->n; i++)
2713         pivot_value_destroy (arg->values[i]);
2714       free (arg->values);
2715     }
2716 }
2717
2718 /* Creates and returns a new pivot_value whose contents is the null-terminated
2719    string TEXT.  Takes ownership of TEXT.
2720
2721    This function is for text strings provided by the user (with the exception
2722    that pivot_value_new_variable() should be used for variable names).  For
2723    strings that are part of the PSPP user interface, such as names of
2724    procedures, statistics, annotations, error messages, etc., use
2725    pivot_value_new_text(). */
2726 struct pivot_value *
2727 pivot_value_new_user_text_nocopy (char *text)
2728 {
2729   struct pivot_value *value = xmalloc (sizeof *value);
2730   *value = (struct pivot_value) {
2731     .text = {
2732       .type = PIVOT_VALUE_TEXT,
2733       .local = text,
2734       .c = text,
2735       .id = text,
2736       .user_provided = true,
2737     }
2738   };
2739   return value;
2740 }
2741
2742 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2743    TEXT.  Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2744    in advance.
2745
2746    This function is for text strings provided by the user (with the exception
2747    that pivot_value_new_variable() should be used for variable names).  For
2748    strings that are part of the PSPP user interface, such as names of
2749    procedures, statistics, annotations, error messages, etc., use
2750    pivot_value_new_text().
2751
2752    The caller retains ownership of TEXT. */
2753 struct pivot_value *
2754 pivot_value_new_user_text (const char *text, size_t length)
2755 {
2756   return pivot_value_new_user_text_nocopy (
2757     xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2758 }
2759
2760 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2761    a translatable string, but not actually translated yet, e.g. enclosed in
2762    N_().  This function is for text strings that are part of the PSPP user
2763    interface, such as names of procedures, statistics, annotations, error
2764    messages, etc.  For strings that come from the user, use
2765    pivot_value_new_user_text(). */
2766 struct pivot_value *
2767 pivot_value_new_text (const char *text)
2768 {
2769   char *c = xstrdup (text);
2770   char *local = xstrdup (gettext (c));
2771
2772   struct pivot_value *value = xmalloc (sizeof *value);
2773   *value = (struct pivot_value) {
2774     .text = {
2775       .type = PIVOT_VALUE_TEXT,
2776       .local = local,
2777       .c = c,
2778       .id = c,
2779       .user_provided = false,
2780     }
2781   };
2782   return value;
2783 }
2784
2785 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2786    string.  The format string should generally be enclosed in N_(). */
2787 struct pivot_value * PRINTF_FORMAT (1, 2)
2788 pivot_value_new_text_format (const char *format, ...)
2789 {
2790   va_list args;
2791   va_start (args, format);
2792   char *c = xvasprintf (format, args);
2793   va_end (args);
2794
2795   va_start (args, format);
2796   char *local = xvasprintf (gettext (format), args);
2797   va_end (args);
2798
2799   struct pivot_value *value = xmalloc (sizeof *value);
2800   *value = (struct pivot_value) {
2801     .text = {
2802       .type = PIVOT_VALUE_TEXT,
2803       .local = local,
2804       .c = c,
2805       .id = xstrdup (c),
2806       .user_provided = false,
2807     }
2808   };
2809   return value;
2810 }
2811
2812 /* Returns a new pivot_value that represents X.
2813
2814    The format to use for X is unspecified.  Usually the easiest way to specify
2815    a format is through assigning a result class to one of the categories that
2816    the pivot_value will end up in.  If that is not suitable, then the caller
2817    can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2818 struct pivot_value *
2819 pivot_value_new_number (double x)
2820 {
2821   struct pivot_value *value = xmalloc (sizeof *value);
2822   *value = (struct pivot_value) {
2823     .numeric = {
2824       .type = PIVOT_VALUE_NUMERIC,
2825       .x = x
2826     },
2827   };
2828   return value;
2829 }
2830
2831 /* Returns a new pivot_value that represents X, formatted as an integer. */
2832 struct pivot_value *
2833 pivot_value_new_integer (double x)
2834 {
2835   struct pivot_value *value = pivot_value_new_number (x);
2836   value->numeric.format = (struct fmt_spec) { .type = FMT_F, .w = 40 };
2837   return value;
2838 }
2839
2840 /* Returns a new pivot_value that represents VALUE, formatted as for
2841    VARIABLE. */
2842 struct pivot_value *
2843 pivot_value_new_var_value (const struct variable *variable,
2844                            const union value *value)
2845 {
2846   struct pivot_value *pv = pivot_value_new_value (
2847     value, var_get_width (variable), var_get_print_format (variable),
2848     var_get_encoding (variable));
2849
2850   char *var_name = xstrdup (var_get_name (variable));
2851   if (var_is_alpha (variable))
2852     pv->string.var_name = var_name;
2853   else
2854     pv->numeric.var_name = var_name;
2855
2856   const char *label = var_lookup_value_label (variable, value);
2857   if (label)
2858     {
2859       if (var_is_alpha (variable))
2860         pv->string.value_label = xstrdup (label);
2861       else
2862         pv->numeric.value_label = xstrdup (label);
2863     }
2864
2865   return pv;
2866 }
2867
2868 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2869    formatted with FORMAT.  For a string value, ENCODING must be its character
2870    encoding. */
2871 struct pivot_value *
2872 pivot_value_new_value (const union value *value, int width,
2873                        const struct fmt_spec *format, const char *encoding)
2874 {
2875   struct pivot_value *pv = XZALLOC (struct pivot_value);
2876   if (width > 0)
2877     {
2878       char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2879                                width);
2880       size_t n = strlen (s);
2881       while (n > 0 && s[n - 1] == ' ')
2882         s[--n] = '\0';
2883
2884       pv->type = PIVOT_VALUE_STRING;
2885       pv->string.s = s;
2886       pv->string.hex = format->type == FMT_AHEX;
2887     }
2888   else
2889     {
2890       pv->type = PIVOT_VALUE_NUMERIC;
2891       pv->numeric.x = value->f;
2892       pv->numeric.format = *format;
2893     }
2894
2895   return pv;
2896 }
2897
2898 /* Returns a new pivot_value for VARIABLE. */
2899 struct pivot_value *
2900 pivot_value_new_variable (const struct variable *variable)
2901 {
2902   return pivot_value_new_variable__ (var_get_name (variable),
2903                                      var_get_label (variable));
2904 }
2905
2906 /* Returns a new pivot_value for a variable with the given NAME and optional
2907    LABEL. */
2908 struct pivot_value *
2909 pivot_value_new_variable__ (const char *name, const char *label)
2910 {
2911   struct pivot_value *value = xmalloc (sizeof *value);
2912   *value = (struct pivot_value) {
2913     .variable = {
2914       .type = PIVOT_VALUE_VARIABLE,
2915       .var_name = xstrdup (name),
2916       .var_label = xstrdup_if_nonnull (label),
2917     },
2918   };
2919   return value;
2920 }
2921
2922 /* Attaches a reference to FOOTNOTE to V. */
2923 void
2924 pivot_value_add_footnote (struct pivot_value *v,
2925                           const struct pivot_footnote *footnote)
2926 {
2927   struct pivot_value_ex *ex = pivot_value_ex_rw (v);
2928
2929   /* Some legacy tables include numerous duplicate footnotes.  Suppress
2930      them. */
2931   for (size_t i = 0; i < ex->n_footnotes; i++)
2932     if (ex->footnote_indexes[i] == footnote->idx)
2933       return;
2934
2935   ex->footnote_indexes = xrealloc (
2936     ex->footnote_indexes,
2937     (ex->n_footnotes + 1) * sizeof *ex->footnote_indexes);
2938   ex->footnote_indexes[ex->n_footnotes++] = footnote->idx;
2939   pivot_value_sort_footnotes (v);
2940 }
2941
2942 static int
2943 compare_footnote_indexes (const void *a_, const void *b_)
2944 {
2945   const size_t *ap = a_;
2946   const size_t *bp = b_;
2947   size_t a = *ap;
2948   size_t b = *bp;
2949   return a < b ? -1 : a > b;
2950 }
2951
2952 /* Sorts the footnote references in V in the standard ascending order.
2953
2954    This is only necessary if code adds (plural) footnotes to a pivot_value by
2955    itself, because pivot_value_add_footnote() does it automatically. */
2956 void
2957 pivot_value_sort_footnotes (struct pivot_value *v)
2958 {
2959   if (v->ex && v->ex->n_footnotes > 1)
2960     qsort (v->ex->footnote_indexes, v->ex->n_footnotes,
2961            sizeof *v->ex->footnote_indexes, compare_footnote_indexes);
2962 }
2963
2964 /* If VALUE is a numeric value, and RC is a result class such as
2965    PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2966 void
2967 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2968                     const char *rc)
2969 {
2970   if (value->type == PIVOT_VALUE_NUMERIC)
2971     pivot_table_use_rc (table, rc,
2972                         &value->numeric.format, &value->numeric.honor_small);
2973 }
2974 \f
2975 /* pivot_value_ex. */
2976
2977 struct pivot_value_ex *
2978 pivot_value_ex_rw (struct pivot_value *value)
2979 {
2980   if (!value->ex)
2981     value->ex = xzalloc (sizeof *value->ex);
2982   return value->ex;
2983 }
2984
2985 struct pivot_value_ex *
2986 pivot_value_ex_clone (const struct pivot_value_ex *old)
2987 {
2988   struct font_style *font_style = NULL;
2989   if (old->font_style)
2990     {
2991       font_style = xmalloc (sizeof *font_style);
2992       font_style_copy (NULL, font_style, old->font_style);
2993     }
2994
2995   char **subscripts = NULL;
2996   if (old->n_subscripts)
2997     {
2998       subscripts = xnmalloc (old->n_subscripts, sizeof *subscripts);
2999       for (size_t i = 0; i < old->n_subscripts; i++)
3000         subscripts[i] = xstrdup (old->subscripts[i]);
3001     }
3002
3003   struct pivot_value_ex *new = xmalloc (sizeof *new);
3004   *new = (struct pivot_value_ex) {
3005     .font_style = font_style,
3006     .cell_style = (old->cell_style
3007                    ? xmemdup (old->cell_style, sizeof *new->cell_style)
3008                    : NULL),
3009     .subscripts = subscripts,
3010     .n_subscripts = old->n_subscripts,
3011     .footnote_indexes = (
3012       old->n_footnotes
3013       ? xmemdup (old->footnote_indexes,
3014                  old->n_footnotes * sizeof *new->footnote_indexes)
3015       : NULL),
3016     .n_footnotes = old->n_footnotes
3017   };
3018   return new;
3019 }
3020
3021 void
3022 pivot_value_ex_destroy (struct pivot_value_ex *ex)
3023 {
3024   if (ex)
3025     {
3026       font_style_uninit (ex->font_style);
3027       free (ex->font_style);
3028       free (ex->cell_style);
3029       free (ex->footnote_indexes);
3030
3031       for (size_t i = 0; i < ex->n_subscripts; i++)
3032         free (ex->subscripts[i]);
3033       free (ex->subscripts);
3034       free (ex);
3035     }
3036 }
3037 \f
3038 /* pivot_splits */
3039
3040 struct pivot_splits_value
3041   {
3042     struct hmap_node hmap_node;
3043     union value value;
3044     int leaf;
3045   };
3046
3047 struct pivot_splits_var
3048   {
3049     struct pivot_dimension *dimension;
3050     const struct variable *var;
3051     int width;
3052     struct hmap values;
3053   };
3054
3055 struct pivot_splits_dup
3056   {
3057     struct hmap_node hmap_node;
3058     union value *values;
3059   };
3060
3061 struct pivot_splits
3062   {
3063     struct pivot_splits_var *vars;
3064     size_t n;
3065     char *encoding;
3066
3067     struct hmap dups;
3068
3069     size_t dindexes[MAX_SPLITS];
3070
3071     int warnings_left;
3072   };
3073
3074 /* Adds a dimension for each layered split file variable in DICT to PT on AXIS.
3075    These dimensions should be the last dimensions added to PT (the
3076    pivot_splits_put*() functions rely on this).  Returns a new pivot_splits
3077    structure if any dimensions were added, otherwise a null pointer.
3078
3079    See the large comment on split file handling in pivot-table.h for more
3080    information. */
3081 struct pivot_splits *
3082 pivot_splits_create (struct pivot_table *pt,
3083                      enum pivot_axis_type axis,
3084                      const struct dictionary *dict)
3085 {
3086   if (dict_get_split_type (dict) != SPLIT_LAYERED)
3087     return NULL;
3088
3089   size_t n = dict_get_n_splits (dict);
3090   assert (n <= MAX_SPLITS);
3091
3092   const struct variable *const *vars = dict_get_split_vars (dict);
3093   struct pivot_splits_var *psvars = xnmalloc (n, sizeof *psvars);
3094   for (size_t i = n - 1; i < n; i--)
3095     {
3096       const struct variable *var = vars[i];
3097       struct pivot_splits_var *psvar = &psvars[i];
3098
3099       struct pivot_dimension *d = pivot_dimension_create__ (
3100         pt, axis, pivot_value_new_variable (var));
3101       d->root->show_label = true;
3102
3103       *psvar = (struct pivot_splits_var) {
3104         .width = var_get_width (var),
3105         .values = HMAP_INITIALIZER (psvar->values),
3106         .dimension = d,
3107         .var = var,
3108       };
3109     }
3110
3111   struct pivot_splits *ps = xmalloc (sizeof *ps);
3112   *ps = (struct pivot_splits) {
3113     .vars = psvars,
3114     .n = n,
3115     .encoding = xstrdup (dict_get_encoding (dict)),
3116     .dups = HMAP_INITIALIZER (ps->dups),
3117     .dindexes = { [0] = SIZE_MAX },
3118     .warnings_left = 5,
3119   };
3120   return ps;
3121 }
3122
3123 /* Destroys PS. */
3124 void
3125 pivot_splits_destroy (struct pivot_splits *ps)
3126 {
3127   if (!ps)
3128     return;
3129
3130   if (ps->warnings_left < 0)
3131     msg (SW, ngettext ("Suppressed %d additional warning about duplicate "
3132                        "split values.",
3133                        "Suppressed %d additional warnings about duplicate "
3134                        "split values.", -ps->warnings_left),
3135          -ps->warnings_left);
3136
3137   struct pivot_splits_dup *dup, *next_dup;
3138   HMAP_FOR_EACH_SAFE (dup, next_dup, struct pivot_splits_dup, hmap_node,
3139                       &ps->dups)
3140     {
3141       for (size_t i = 0; i < ps->n; i++)
3142         value_destroy (&dup->values[i], ps->vars[i].width);
3143       free (dup->values);
3144       free (dup);
3145     }
3146   hmap_destroy (&ps->dups);
3147
3148   for (size_t i = 0; i < ps->n; i++)
3149     {
3150       struct pivot_splits_var *psvar = &ps->vars[i];
3151       struct pivot_splits_value *psval, *next;
3152       HMAP_FOR_EACH_SAFE (psval, next, struct pivot_splits_value, hmap_node,
3153                           &psvar->values)
3154         {
3155           value_destroy (&psval->value, psvar->width);
3156           hmap_delete (&psvar->values, &psval->hmap_node);
3157           free (psval);
3158         }
3159       hmap_destroy (&psvar->values);
3160     }
3161   free (ps->vars);
3162
3163   free (ps->encoding);
3164   free (ps);
3165 }
3166
3167 static struct pivot_splits_value *
3168 pivot_splits_value_find (struct pivot_splits_var *psvar,
3169                          const union value *value)
3170 {
3171   struct pivot_splits_value *psval;
3172   HMAP_FOR_EACH_WITH_HASH (psval, struct pivot_splits_value, hmap_node,
3173                            value_hash (value, psvar->width, 0), &psvar->values)
3174     if (value_equal (&psval->value, value, psvar->width))
3175       return psval;
3176   return NULL;
3177 }
3178
3179 static bool
3180 pivot_splits_find_dup (struct pivot_splits *ps, const struct ccase *example)
3181 {
3182   unsigned int hash = 0;
3183   for (size_t i = 0; i < ps->n; i++)
3184     {
3185       struct pivot_splits_var *psvar = &ps->vars[i];
3186       const union value *value = case_data (example, psvar->var);
3187       hash = value_hash (value, psvar->width, hash);
3188     }
3189   struct pivot_splits_dup *dup;
3190   HMAP_FOR_EACH_WITH_HASH (dup, struct pivot_splits_dup, hmap_node, hash,
3191                            &ps->dups)
3192     {
3193       bool equal = true;
3194       for (size_t i = 0; i < ps->n && equal; i++)
3195         {
3196           struct pivot_splits_var *psvar = &ps->vars[i];
3197           const union value *value = case_data (example, psvar->var);
3198           equal = value_equal (value, &dup->values[i], psvar->width);
3199         }
3200       if (equal)
3201         return true;
3202     }
3203
3204   union value *values = xmalloc (ps->n * sizeof *values);
3205   for (size_t i = 0; i < ps->n; i++)
3206     {
3207       struct pivot_splits_var *psvar = &ps->vars[i];
3208       const union value *value = case_data (example, psvar->var);
3209       value_clone (&values[i], value, psvar->width);
3210     }
3211
3212   dup = xmalloc (sizeof *dup);
3213   dup->values = values;
3214   hmap_insert (&ps->dups, &dup->hmap_node, hash);
3215   return false;
3216 }
3217
3218 /* Begins adding data for a new split file group to the pivot table associated
3219    with PS.  EXAMPLE should be a case from the new split file group.
3220
3221    This is a no-op if PS is NULL.
3222
3223    See the large comment on split file handling in pivot-table.h for more
3224    information. */
3225 void
3226 pivot_splits_new_split (struct pivot_splits *ps, const struct ccase *example)
3227 {
3228   if (!ps)
3229     return;
3230
3231   for (size_t i = 0; i < ps->n; i++)
3232     {
3233       struct pivot_splits_var *psvar = &ps->vars[i];
3234       const union value *value = case_data (example, psvar->var);
3235       struct pivot_splits_value *psval = pivot_splits_value_find (psvar, value);
3236       if (!psval)
3237         {
3238           psval = xmalloc (sizeof *psval);
3239           hmap_insert (&psvar->values, &psval->hmap_node,
3240                        value_hash (value, psvar->width, 0));
3241           value_clone (&psval->value, value, psvar->width);
3242           psval->leaf = pivot_category_create_leaf (
3243             psvar->dimension->root,
3244             pivot_value_new_var_value (psvar->var, value));
3245         }
3246
3247       ps->dindexes[i] = psval->leaf;
3248     }
3249
3250   if (pivot_splits_find_dup (ps, example))
3251     {
3252       if (ps->warnings_left-- > 0)
3253         {
3254           struct string s = DS_EMPTY_INITIALIZER;
3255           for (size_t i = 0; i < ps->n; i++)
3256             {
3257               if (i > 0)
3258                 ds_put_cstr (&s, ", ");
3259
3260               struct pivot_splits_var *psvar = &ps->vars[i];
3261               const union value *value = case_data (example, psvar->var);
3262               ds_put_format (&s, "%s = ", var_get_name (psvar->var));
3263
3264               char *s2 = data_out (value, ps->encoding,
3265                                    var_get_print_format (psvar->var),
3266                                    settings_get_fmt_settings ());
3267               ds_put_cstr (&s, s2 + strspn (s2, " "));
3268               free (s2);
3269             }
3270           msg (SW, _("When SPLIT FILE is in effect, the input data must be "
3271                      "sorted by the split variables (for example, using SORT "
3272                      "CASES), but multiple runs of cases with the same split "
3273                      "values were found separated by cases with different "
3274                      "values.  Each run will be analyzed separately.  The "
3275                      "duplicate split values are: %s"), ds_cstr (&s));
3276           ds_destroy (&s);
3277         }
3278
3279       struct pivot_splits_var *psvar = &ps->vars[0];
3280       const union value *value = case_data (example, psvar->var);
3281       ps->dindexes[0] = pivot_category_create_leaf (
3282         psvar->dimension->root,
3283         pivot_value_new_var_value (psvar->var, value));
3284     }
3285 }
3286
3287 static size_t
3288 pivot_splits_get_dindexes (const struct pivot_splits *ps, size_t *dindexes)
3289 {
3290   if (!ps)
3291     return 0;
3292
3293   assert (ps->dindexes[0] != SIZE_MAX);
3294   for (size_t i = 0; i < ps->n; i++)
3295     dindexes[ps->n - i - 1] = ps->dindexes[i];
3296   return ps->n;
3297 }
3298
3299 /* Puts VALUE in the cell in TABLE with index IDX1.  TABLE must have 1
3300    dimension plus the split file dimensions from PS (if nonnull).  Takes
3301    ownership of VALUE.
3302
3303    See the large comment on split file handling in pivot-table.h for more
3304    information. */
3305 void
3306 pivot_splits_put1 (struct pivot_splits *ps, struct pivot_table *table,
3307                    size_t idx1, struct pivot_value *value)
3308 {
3309   size_t dindexes[1 + MAX_SPLITS];
3310   size_t *p = dindexes;
3311   *p++ = idx1;
3312   p += pivot_splits_get_dindexes (ps, p);
3313   pivot_table_put (table, dindexes, p - dindexes, value);
3314 }
3315
3316 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2).  TABLE must have 2
3317    dimensions plus the split file dimensions from PS (if nonnull).  Takes
3318    ownership of VALUE.
3319
3320    See the large comment on split file handling in pivot-table.h for more
3321    information. */
3322 void
3323 pivot_splits_put2 (struct pivot_splits *ps, struct pivot_table *table,
3324                    size_t idx1, size_t idx2, struct pivot_value *value)
3325 {
3326   size_t dindexes[2 + MAX_SPLITS];
3327   size_t *p = dindexes;
3328   *p++ = idx1;
3329   *p++ = idx2;
3330   p += pivot_splits_get_dindexes (ps, p);
3331   pivot_table_put (table, dindexes, p - dindexes, value);
3332 }
3333
3334 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3).  TABLE must
3335    have 3 dimensions plus the split file dimensions from PS (if nonnull).
3336    Takes ownership of VALUE.
3337
3338    See the large comment on split file handling in pivot-table.h for more
3339    information. */
3340 void
3341 pivot_splits_put3 (struct pivot_splits *ps, struct pivot_table *table,
3342                    size_t idx1, size_t idx2, size_t idx3,
3343                    struct pivot_value *value)
3344 {
3345   size_t dindexes[3 + MAX_SPLITS];
3346   size_t *p = dindexes;
3347   *p++ = idx1;
3348   *p++ = idx2;
3349   *p++ = idx3;
3350   p += pivot_splits_get_dindexes (ps, p);
3351   pivot_table_put (table, dindexes, p - dindexes, value);
3352 }
3353
3354 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4).  TABLE
3355    must have 4 dimensions plus the split file dimensions from PS (if nonnull).
3356    Takes ownership of VALUE.
3357
3358    See the large comment on split file handling in pivot-table.h for more
3359    information. */
3360 void
3361 pivot_splits_put4 (struct pivot_splits *ps, struct pivot_table *table,
3362                    size_t idx1, size_t idx2, size_t idx3, size_t idx4,
3363                    struct pivot_value *value)
3364 {
3365   size_t dindexes[4 + MAX_SPLITS];
3366   size_t *p = dindexes;
3367   *p++ = idx1;
3368   *p++ = idx2;
3369   *p++ = idx3;
3370   *p++ = idx4;
3371   p += pivot_splits_get_dindexes (ps, p);
3372   pivot_table_put (table, dindexes, p - dindexes, value);
3373 }