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