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