f8f917d9dd1d965b3d5b2830b725c7c12004eee1
[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   if (!headings)
1980     return;
1981   for (size_t i = 0; i < axis->label_depth; i++)
1982     {
1983       for (size_t j = 0; j < axis->extent; j++)
1984         free (headings[i][j]);
1985       free (headings[i]);
1986     }
1987   free (headings);
1988 }
1989
1990 static void
1991 pivot_table_sizing_dump (const char *name,
1992                          const int width_ranges[2],
1993                          const struct pivot_table_sizing *s,
1994                          int indentation)
1995 {
1996   indent (indentation);
1997   printf ("%ss: min=%d, max=%d\n", name, width_ranges[0], width_ranges[1]);
1998   if (s->n_widths)
1999     {
2000       indent (indentation + 1);
2001       printf ("%s widths:", name);
2002       for (size_t i = 0; i < s->n_widths; i++)
2003         printf (" %d", s->widths[i]);
2004       printf ("\n");
2005     }
2006   if (s->n_breaks)
2007     {
2008       indent (indentation + 1);
2009       printf ("break after %ss:", name);
2010       for (size_t i = 0; i < s->n_breaks; i++)
2011         printf (" %zu", s->breaks[i]);
2012       printf ("\n");
2013     }
2014   if (s->n_keeps)
2015     {
2016       indent (indentation + 1);
2017       printf ("keep %ss together:", name);
2018       for (size_t i = 0; i < s->n_keeps; i++)
2019         printf (" [%zu,%zu]",
2020                 s->keeps[i].ofs,
2021                 s->keeps[i].ofs + s->keeps[i].n - 1);
2022       printf ("\n");
2023     }
2024 }
2025
2026 void
2027 pivot_table_dump (const struct pivot_table *table, int indentation)
2028 {
2029   if (!table)
2030     return;
2031
2032   pivot_table_assign_label_depth (CONST_CAST (struct pivot_table *, table));
2033
2034   pivot_table_dump_value (table->title, "title", table, indentation);
2035   pivot_table_dump_value (table->subtype, "subtype", table, indentation);
2036   pivot_table_dump_string (table->command_c, "command", indentation);
2037   pivot_table_dump_string (table->dataset, "dataset", indentation);
2038   pivot_table_dump_string (table->datafile, "datafile", indentation);
2039   pivot_table_dump_string (table->notes, "notes", indentation);
2040   pivot_table_dump_string (table->look->name, "table-look", indentation);
2041   if (table->date)
2042     {
2043       indent (indentation);
2044
2045       struct tm *tm = localtime (&table->date);
2046       printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
2047               tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
2048               tm->tm_sec);
2049     }
2050
2051   indent (indentation);
2052   printf ("sizing:\n");
2053   pivot_table_sizing_dump ("column", table->look->width_ranges[TABLE_HORZ],
2054                            &table->sizing[TABLE_HORZ], indentation + 1);
2055   pivot_table_sizing_dump ("row", table->look->width_ranges[TABLE_VERT],
2056                            &table->sizing[TABLE_VERT], indentation + 1);
2057
2058   indent (indentation);
2059   printf ("areas:\n");
2060   for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
2061     table_area_style_dump (area, &table->look->areas[area], indentation + 1);
2062
2063   indent (indentation);
2064   printf ("borders:\n");
2065   for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
2066     table_border_style_dump (border, &table->look->borders[border],
2067                              indentation + 1);
2068
2069   for (size_t i = 0; i < table->n_dimensions; i++)
2070     pivot_dimension_dump (table->dimensions[i], table, indentation);
2071
2072   /* Presentation and data indexes. */
2073   size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
2074
2075   const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
2076   if (layer_axis->n_dimensions)
2077     {
2078       indent (indentation);
2079       printf ("current layer:");
2080
2081       for (size_t i = 0; i < layer_axis->n_dimensions; i++)
2082         {
2083           const struct pivot_dimension *d = layer_axis->dimensions[i];
2084           char *name = pivot_value_to_string (d->root->name, table);
2085           char *value = pivot_value_to_string (
2086             d->data_leaves[table->current_layer[i]]->name, table);
2087           printf (" %s=%s", name, value);
2088           free (value);
2089           free (name);
2090         }
2091
2092       putchar ('\n');
2093     }
2094
2095   size_t *layer_indexes;
2096   size_t layer_iteration = 0;
2097   PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
2098     {
2099       indent (indentation);
2100       printf ("layer %zu:", layer_iteration++);
2101
2102       const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
2103       for (size_t i = 0; i < layer_axis->n_dimensions; i++)
2104         {
2105           const struct pivot_dimension *d = layer_axis->dimensions[i];
2106
2107           fputs (i == 0 ? " " : ", ", stdout);
2108           pivot_value_dump (d->root->name, table);
2109           fputs (" =", stdout);
2110
2111           struct pivot_value **names = xnmalloc (d->n_leaves, sizeof *names);
2112           size_t n_names = 0;
2113           for (const struct pivot_category *c
2114                  = d->presentation_leaves[layer_indexes[i]];
2115                c;
2116                c = c->parent)
2117             {
2118               if (pivot_category_is_leaf (c) || c->show_label)
2119                 names[n_names++] = c->name;
2120             }
2121
2122           for (size_t i = n_names; i-- > 0;)
2123             {
2124               putchar (' ');
2125               pivot_value_dump (names[i], table);
2126             }
2127           free (names);
2128         }
2129       putchar ('\n');
2130
2131       size_t *column_enumeration = pivot_table_enumerate_axis (
2132         table, PIVOT_AXIS_COLUMN, layer_indexes, table->look->omit_empty, NULL);
2133       size_t *row_enumeration = pivot_table_enumerate_axis (
2134         table, PIVOT_AXIS_ROW, layer_indexes, table->look->omit_empty, NULL);
2135
2136       /* Print column headings.
2137
2138          Ordinarily the test for nonnull 'column_headings' would be
2139          unnecessary, because 'column_headings' is null only if the axis's
2140          label_depth is 0, but there is a special case for the column axis only
2141          in pivot_table_assign_label_depth(). */
2142       char ***column_headings = compose_headings (
2143         table, &table->axes[PIVOT_AXIS_COLUMN], column_enumeration);
2144       if (column_headings)
2145         {
2146           for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
2147             {
2148               indent (indentation + 1);
2149               for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
2150                 {
2151                   if (x)
2152                     fputs ("; ", stdout);
2153                   if (column_headings && column_headings[y] && column_headings[y][x])
2154                     fputs (column_headings[y][x], stdout);
2155                 }
2156               putchar ('\n');
2157             }
2158           free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
2159         }
2160
2161       indent (indentation + 1);
2162       printf ("-----------------------------------------------\n");
2163
2164       char ***row_headings = compose_headings (
2165         table, &table->axes[PIVOT_AXIS_ROW], row_enumeration);
2166
2167       size_t x = 0;
2168       const size_t *pindexes[PIVOT_N_AXES]
2169         = { [PIVOT_AXIS_LAYER] = layer_indexes };
2170       PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
2171                                   &table->axes[PIVOT_AXIS_ROW])
2172         {
2173           indent (indentation + 1);
2174
2175           size_t i = 0;
2176           for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
2177             {
2178               if (i++)
2179                 fputs ("; ", stdout);
2180               if (row_headings[y][x])
2181                 fputs (row_headings[y][x], stdout);
2182             }
2183
2184           printf (" | ");
2185
2186           i = 0;
2187           PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
2188                                       column_enumeration,
2189                                       &table->axes[PIVOT_AXIS_COLUMN])
2190             {
2191               if (i++)
2192                 printf ("; ");
2193
2194               pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
2195               const struct pivot_value *value = pivot_table_get (
2196                 table, dindexes);
2197               if (value)
2198                 pivot_value_dump (value, table);
2199             }
2200           printf ("\n");
2201
2202           x++;
2203         }
2204
2205       free (column_enumeration);
2206       free (row_enumeration);
2207       free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
2208     }
2209
2210   pivot_table_dump_value (table->caption, "caption", table, indentation);
2211
2212   for (size_t i = 0; i < table->n_footnotes; i++)
2213     {
2214       const struct pivot_footnote *f = table->footnotes[i];
2215       indent (indentation);
2216       putchar ('[');
2217       if (f->marker)
2218         pivot_value_dump (f->marker, table);
2219       else
2220         printf ("%zu", f->idx);
2221       putchar (']');
2222       pivot_value_dump (f->content, table);
2223       putchar ('\n');
2224     }
2225
2226   free (dindexes);
2227 }
2228 \f
2229 static const char *
2230 consume_int (const char *p, size_t *n)
2231 {
2232   *n = 0;
2233   while (c_isdigit (*p))
2234     *n = *n * 10 + (*p++ - '0');
2235   return p;
2236 }
2237
2238 static size_t
2239 pivot_format_inner_template (struct string *out, const char *template,
2240                              char escape,
2241                              struct pivot_value **values, size_t n_values,
2242                              const struct pivot_table *pt)
2243 {
2244   size_t args_consumed = 0;
2245   while (*template && *template != ':')
2246     {
2247       if (*template == '\\' && template[1])
2248         {
2249           ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
2250           template += 2;
2251         }
2252       else if (*template == escape)
2253         {
2254           size_t index;
2255           template = consume_int (template + 1, &index);
2256           if (index >= 1 && index <= n_values)
2257             {
2258               pivot_value_format (values[index - 1], pt, out);
2259               args_consumed = MAX (args_consumed, index);
2260             }
2261         }
2262       else
2263         ds_put_byte (out, *template++);
2264     }
2265   return args_consumed;
2266 }
2267
2268 static const char *
2269 pivot_extract_inner_template (const char *template, const char **p)
2270 {
2271   *p = template;
2272
2273   for (;;)
2274     {
2275       if (*template == '\\' && template[1] != '\0')
2276         template += 2;
2277       else if (*template == ':')
2278         return template + 1;
2279       else if (*template == '\0')
2280         return template;
2281       else
2282         template++;
2283     }
2284 }
2285
2286 static void
2287 pivot_format_template (struct string *out, const char *template,
2288                        const struct pivot_argument *args, size_t n_args,
2289                        const struct pivot_table *pt)
2290 {
2291   while (*template)
2292     {
2293       if (*template == '\\' && template[1] != '\0')
2294         {
2295           ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
2296           template += 2;
2297         }
2298       else if (*template == '^')
2299         {
2300           size_t index;
2301           template = consume_int (template + 1, &index);
2302           if (index >= 1 && index <= n_args && args[index - 1].n > 0)
2303             pivot_value_format (args[index - 1].values[0], pt, out);
2304         }
2305       else if (*template == '[')
2306         {
2307           const char *tmpl[2];
2308           template = pivot_extract_inner_template (template + 1, &tmpl[0]);
2309           template = pivot_extract_inner_template (template, &tmpl[1]);
2310           template += *template == ']';
2311
2312           size_t index;
2313           template = consume_int (template, &index);
2314           if (index < 1 || index > n_args)
2315             continue;
2316
2317           const struct pivot_argument *arg = &args[index - 1];
2318           size_t left = arg->n;
2319           while (left)
2320             {
2321               struct pivot_value **values = arg->values + (arg->n - left);
2322               int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
2323               char escape = "%^"[tmpl_idx];
2324               size_t used = pivot_format_inner_template (
2325                 out, tmpl[tmpl_idx], escape, values, left, pt);
2326               if (!used || used > left)
2327                 break;
2328               left -= used;
2329             }
2330         }
2331       else
2332         ds_put_byte (out, *template++);
2333     }
2334 }
2335
2336 static enum settings_value_show
2337 interpret_show (enum settings_value_show global_show,
2338                 enum settings_value_show table_show,
2339                 enum settings_value_show value_show,
2340                 bool has_label)
2341 {
2342   return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
2343           : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
2344           : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
2345           : global_show);
2346 }
2347
2348 /* Appends to OUT the actual text content from the given Pango MARKUP. */
2349 static void
2350 get_text_from_markup (const char *markup, struct string *out)
2351 {
2352   xmlParserCtxt *parser = xmlCreatePushParserCtxt (NULL, NULL, NULL, 0, NULL);
2353   if (!parser)
2354     {
2355       ds_put_cstr (out, markup);
2356       return;
2357     }
2358
2359   xmlParseChunk (parser, "<xml>", strlen ("<xml>"), false);
2360   xmlParseChunk (parser, markup, strlen (markup), false);
2361   xmlParseChunk (parser, "</xml>", strlen ("</xml>"), true);
2362
2363   if (parser->wellFormed)
2364     {
2365       xmlChar *s = xmlNodeGetContent (xmlDocGetRootElement (parser->myDoc));
2366       ds_put_cstr (out, CHAR_CAST (char *, s));
2367       xmlFree (s);
2368     }
2369   else
2370     ds_put_cstr (out, markup);
2371   xmlFreeDoc (parser->myDoc);
2372   xmlFreeParserCtxt (parser);
2373 }
2374
2375 /* Appends a text representation of the body of VALUE to OUT.  Settings on
2376    PT control whether variable and value labels are included.
2377
2378    The "body" omits subscripts and superscripts and footnotes.
2379
2380    Returns true if OUT is a number (or a number plus a value label), false
2381    otherwise.  */
2382 bool
2383 pivot_value_format_body (const struct pivot_value *value,
2384                          const struct pivot_table *pt,
2385                          struct string *out)
2386 {
2387   enum settings_value_show show;
2388   bool numeric = false;
2389
2390   switch (value->type)
2391     {
2392     case PIVOT_VALUE_NUMERIC:
2393       show = interpret_show (settings_get_show_values (),
2394                              pt->show_values,
2395                              value->numeric.show,
2396                              value->numeric.value_label != NULL);
2397       if (show & SETTINGS_VALUE_SHOW_VALUE)
2398         {
2399           const struct fmt_spec *f = &value->numeric.format;
2400           const struct fmt_spec *format
2401             = (f->type == FMT_F
2402                && value->numeric.honor_small
2403                && value->numeric.x != 0
2404                && fabs (value->numeric.x) < pt->small
2405                ? &(struct fmt_spec) { .type = FMT_E, .w = 40, .d = f->d }
2406                : f);
2407
2408           char *s = data_out (&(union value) { .f = value->numeric.x },
2409                               "UTF-8", format, &pt->settings);
2410           ds_put_cstr (out, s + strspn (s, " "));
2411           free (s);
2412         }
2413       if (show & SETTINGS_VALUE_SHOW_LABEL)
2414         {
2415           if (show & SETTINGS_VALUE_SHOW_VALUE)
2416             ds_put_byte (out, ' ');
2417           ds_put_cstr (out, value->numeric.value_label);
2418         }
2419       numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
2420       break;
2421
2422     case PIVOT_VALUE_STRING:
2423       show = interpret_show (settings_get_show_values (),
2424                              pt->show_values,
2425                              value->string.show,
2426                              value->string.value_label != NULL);
2427       if (show & SETTINGS_VALUE_SHOW_VALUE)
2428         {
2429           if (value->string.hex)
2430             {
2431               for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
2432                    *p; p++)
2433                 ds_put_format (out, "%02X", *p);
2434             }
2435           else
2436             ds_put_cstr (out, value->string.s);
2437         }
2438       if (show & SETTINGS_VALUE_SHOW_LABEL)
2439         {
2440           if (show & SETTINGS_VALUE_SHOW_VALUE)
2441             ds_put_byte (out, ' ');
2442           ds_put_cstr (out, value->string.value_label);
2443         }
2444       break;
2445
2446     case PIVOT_VALUE_VARIABLE:
2447       show = interpret_show (settings_get_show_variables (),
2448                              pt->show_variables,
2449                              value->variable.show,
2450                              value->variable.var_label != NULL);
2451       if (show & SETTINGS_VALUE_SHOW_VALUE)
2452         ds_put_cstr (out, value->variable.var_name);
2453       if (show & SETTINGS_VALUE_SHOW_LABEL)
2454         {
2455           if (show & SETTINGS_VALUE_SHOW_VALUE)
2456             ds_put_byte (out, ' ');
2457           ds_put_cstr (out, value->variable.var_label);
2458         }
2459       break;
2460
2461     case PIVOT_VALUE_TEXT:
2462       if (value->ex && value->ex->font_style && value->ex->font_style->markup)
2463         get_text_from_markup (value->text.local, out);
2464       else
2465         ds_put_cstr (out, value->text.local);
2466       break;
2467
2468     case PIVOT_VALUE_TEMPLATE:
2469       pivot_format_template (out, value->template.local, value->template.args,
2470                              value->template.n_args, pt);
2471       break;
2472     }
2473
2474   return numeric;
2475 }
2476
2477 /* Appends a text representation of VALUE to OUT.  Settings on
2478    PT control whether variable and value labels are included.
2479
2480    Subscripts and footnotes are included.
2481
2482    Returns true if OUT is a number (or a number plus a value label), false
2483    otherwise.  */
2484 bool
2485 pivot_value_format (const struct pivot_value *value,
2486                     const struct pivot_table *pt,
2487                     struct string *out)
2488 {
2489   bool numeric = pivot_value_format_body (value, pt, out);
2490
2491   const struct pivot_value_ex *ex = value->ex;
2492   if (ex)
2493     {
2494       if (ex->n_subscripts)
2495         {
2496           for (size_t i = 0; i < ex->n_subscripts; i++)
2497             ds_put_format (out, "%c%s", i ? ',' : '_', ex->subscripts[i]);
2498         }
2499
2500       for (size_t i = 0; i < ex->n_footnotes; i++)
2501         {
2502           ds_put_byte (out, '[');
2503
2504           size_t idx = ex->footnote_indexes[i];
2505           const struct pivot_footnote *f = pt->footnotes[idx];
2506           pivot_footnote_format_marker (f, pt, out);
2507
2508           ds_put_byte (out, ']');
2509         }
2510     }
2511
2512   return numeric;
2513 }
2514
2515 /* Returns a text representation of VALUE.  The caller must free the string,
2516    with free(). */
2517 char *
2518 pivot_value_to_string (const struct pivot_value *value,
2519                        const struct pivot_table *pt)
2520 {
2521   struct string s = DS_EMPTY_INITIALIZER;
2522   pivot_value_format (value, pt, &s);
2523   return ds_steal_cstr (&s);
2524 }
2525
2526 char *
2527 pivot_value_to_string_defaults (const struct pivot_value *value)
2528 {
2529   static const struct pivot_table pt = {
2530     .show_values = SETTINGS_VALUE_SHOW_DEFAULT,
2531     .show_variables = SETTINGS_VALUE_SHOW_DEFAULT,
2532     .settings = FMT_SETTINGS_INIT,
2533   };
2534   return pivot_value_to_string (value, &pt);
2535 }
2536
2537 struct pivot_value *
2538 pivot_value_clone (const struct pivot_value *old)
2539 {
2540   if (!old)
2541     return NULL;
2542
2543   struct pivot_value *new = xmemdup (old, sizeof *new);
2544   if (old->ex)
2545     new->ex = pivot_value_ex_clone (old->ex);
2546
2547   switch (new->type)
2548     {
2549     case PIVOT_VALUE_NUMERIC:
2550       new->numeric.var_name = xstrdup_if_nonnull (new->numeric.var_name);
2551       new->numeric.value_label = xstrdup_if_nonnull (new->numeric.value_label);
2552       break;
2553
2554     case PIVOT_VALUE_STRING:
2555       new->string.s = xstrdup (new->string.s);
2556       new->string.var_name = xstrdup_if_nonnull (new->string.var_name);
2557       new->string.value_label = xstrdup_if_nonnull (new->string.value_label);
2558       break;
2559
2560     case PIVOT_VALUE_VARIABLE:
2561       new->variable.var_name = xstrdup_if_nonnull (new->variable.var_name);
2562       new->variable.var_label = xstrdup_if_nonnull (new->variable.var_label);
2563       break;
2564
2565     case PIVOT_VALUE_TEXT:
2566       new->text.local = xstrdup (old->text.local);
2567       new->text.c = (old->text.c == old->text.local ? new->text.local
2568                      : xstrdup_if_nonnull (old->text.c));
2569       new->text.id = (old->text.id == old->text.local ? new->text.local
2570                       : old->text.id == old->text.c ? new->text.c
2571                       : xstrdup_if_nonnull (old->text.id));
2572       break;
2573
2574     case PIVOT_VALUE_TEMPLATE:
2575       new->template.local = xstrdup (old->template.local);
2576       new->template.id = (old->template.id == old->template.local
2577                           ? new->template.local
2578                           : xstrdup (old->template.id));
2579       new->template.args = xmalloc (new->template.n_args
2580                                     * sizeof *new->template.args);
2581       for (size_t i = 0; i < old->template.n_args; i++)
2582         pivot_argument_copy (&new->template.args[i],
2583                              &old->template.args[i]);
2584       break;
2585
2586     default:
2587       NOT_REACHED ();
2588     }
2589   return new;
2590 }
2591
2592 /* Frees the data owned by V. */
2593 void
2594 pivot_value_destroy (struct pivot_value *value)
2595 {
2596   if (value)
2597     {
2598       pivot_value_ex_destroy (value->ex);
2599       switch (value->type)
2600         {
2601         case PIVOT_VALUE_NUMERIC:
2602           free (value->numeric.var_name);
2603           free (value->numeric.value_label);
2604           break;
2605
2606         case PIVOT_VALUE_STRING:
2607           free (value->string.s);
2608           free (value->string.var_name);
2609           free (value->string.value_label);
2610           break;
2611
2612         case PIVOT_VALUE_VARIABLE:
2613           free (value->variable.var_name);
2614           free (value->variable.var_label);
2615           break;
2616
2617         case PIVOT_VALUE_TEXT:
2618           free (value->text.local);
2619           if (value->text.c != value->text.local)
2620             free (value->text.c);
2621           if (value->text.id != value->text.local
2622               && value->text.id != value->text.c)
2623             free (value->text.id);
2624           break;
2625
2626         case PIVOT_VALUE_TEMPLATE:
2627           free (value->template.local);
2628           if (value->template.id != value->template.local)
2629             free (value->template.id);
2630           for (size_t i = 0; i < value->template.n_args; i++)
2631             pivot_argument_uninit (&value->template.args[i]);
2632           free (value->template.args);
2633           break;
2634
2635         default:
2636           NOT_REACHED ();
2637         }
2638       free (value);
2639     }
2640 }
2641
2642 /* Sets AREA to the style to use for VALUE, with defaults coming from
2643    DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
2644 void
2645 pivot_value_get_style (struct pivot_value *value,
2646                        const struct font_style *base_font_style,
2647                        const struct cell_style *base_cell_style,
2648                        struct table_area_style *area)
2649 {
2650   const struct pivot_value_ex *ex = pivot_value_ex (value);
2651   font_style_copy (NULL, &area->font_style,
2652                    ex->font_style ? ex->font_style : base_font_style);
2653   area->cell_style = *(ex->cell_style ? ex->cell_style : base_cell_style);
2654 }
2655
2656 /* Copies AREA into VALUE's style. */
2657 void
2658 pivot_value_set_style (struct pivot_value *value,
2659                        const struct table_area_style *area)
2660 {
2661   pivot_value_set_font_style (value, &area->font_style);
2662   pivot_value_set_cell_style (value, &area->cell_style);
2663 }
2664
2665 void
2666 pivot_value_set_font_style (struct pivot_value *value,
2667                             const struct font_style *font_style)
2668 {
2669   struct pivot_value_ex *ex = pivot_value_ex_rw (value);
2670   if (ex->font_style)
2671     font_style_uninit (ex->font_style);
2672   else
2673     ex->font_style = xmalloc (sizeof *ex->font_style);
2674   font_style_copy (NULL, ex->font_style, font_style);
2675 }
2676
2677 void
2678 pivot_value_set_cell_style (struct pivot_value *value,
2679                             const struct cell_style *cell_style)
2680 {
2681   struct pivot_value_ex *ex = pivot_value_ex_rw (value);
2682   if (!ex->cell_style)
2683     ex->cell_style = xmalloc (sizeof *ex->cell_style);
2684   *ex->cell_style = *cell_style;
2685 }
2686
2687 void
2688 pivot_argument_copy (struct pivot_argument *dst,
2689                      const struct pivot_argument *src)
2690 {
2691   *dst = (struct pivot_argument) {
2692     .n = src->n,
2693     .values = xmalloc (src->n * sizeof *dst->values),
2694   };
2695
2696   for (size_t i = 0; i < src->n; i++)
2697     dst->values[i] = pivot_value_clone (src->values[i]);
2698 }
2699
2700 /* Frees the data owned by ARG (but not ARG itself). */
2701 void
2702 pivot_argument_uninit (struct pivot_argument *arg)
2703 {
2704   if (arg)
2705     {
2706       for (size_t i = 0; i < arg->n; i++)
2707         pivot_value_destroy (arg->values[i]);
2708       free (arg->values);
2709     }
2710 }
2711
2712 /* Creates and returns a new pivot_value whose contents is the null-terminated
2713    string TEXT.  Takes ownership of TEXT.
2714
2715    This function is for text strings provided by the user (with the exception
2716    that pivot_value_new_variable() should be used for variable names).  For
2717    strings that are part of the PSPP user interface, such as names of
2718    procedures, statistics, annotations, error messages, etc., use
2719    pivot_value_new_text(). */
2720 struct pivot_value *
2721 pivot_value_new_user_text_nocopy (char *text)
2722 {
2723   struct pivot_value *value = xmalloc (sizeof *value);
2724   *value = (struct pivot_value) {
2725     .text = {
2726       .type = PIVOT_VALUE_TEXT,
2727       .local = text,
2728       .c = text,
2729       .id = text,
2730       .user_provided = true,
2731     }
2732   };
2733   return value;
2734 }
2735
2736 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2737    TEXT.  Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2738    in advance.
2739
2740    This function is for text strings provided by the user (with the exception
2741    that pivot_value_new_variable() should be used for variable names).  For
2742    strings that are part of the PSPP user interface, such as names of
2743    procedures, statistics, annotations, error messages, etc., use
2744    pivot_value_new_text().
2745
2746    The caller retains ownership of TEXT. */
2747 struct pivot_value *
2748 pivot_value_new_user_text (const char *text, size_t length)
2749 {
2750   return pivot_value_new_user_text_nocopy (
2751     xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2752 }
2753
2754 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2755    a translatable string, but not actually translated yet, e.g. enclosed in
2756    N_().  This function is for text strings that are part of the PSPP user
2757    interface, such as names of procedures, statistics, annotations, error
2758    messages, etc.  For strings that come from the user, use
2759    pivot_value_new_user_text(). */
2760 struct pivot_value *
2761 pivot_value_new_text (const char *text)
2762 {
2763   char *c = xstrdup (text);
2764   char *local = xstrdup (gettext (c));
2765
2766   struct pivot_value *value = xmalloc (sizeof *value);
2767   *value = (struct pivot_value) {
2768     .text = {
2769       .type = PIVOT_VALUE_TEXT,
2770       .local = local,
2771       .c = c,
2772       .id = c,
2773       .user_provided = false,
2774     }
2775   };
2776   return value;
2777 }
2778
2779 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2780    string.  The format string should generally be enclosed in N_(). */
2781 struct pivot_value * PRINTF_FORMAT (1, 2)
2782 pivot_value_new_text_format (const char *format, ...)
2783 {
2784   va_list args;
2785   va_start (args, format);
2786   char *c = xvasprintf (format, args);
2787   va_end (args);
2788
2789   va_start (args, format);
2790   char *local = xvasprintf (gettext (format), args);
2791   va_end (args);
2792
2793   struct pivot_value *value = xmalloc (sizeof *value);
2794   *value = (struct pivot_value) {
2795     .text = {
2796       .type = PIVOT_VALUE_TEXT,
2797       .local = local,
2798       .c = c,
2799       .id = xstrdup (c),
2800       .user_provided = false,
2801     }
2802   };
2803   return value;
2804 }
2805
2806 /* Returns a new pivot_value that represents X.
2807
2808    The format to use for X is unspecified.  Usually the easiest way to specify
2809    a format is through assigning a result class to one of the categories that
2810    the pivot_value will end up in.  If that is not suitable, then the caller
2811    can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2812 struct pivot_value *
2813 pivot_value_new_number (double x)
2814 {
2815   struct pivot_value *value = xmalloc (sizeof *value);
2816   *value = (struct pivot_value) {
2817     .numeric = {
2818       .type = PIVOT_VALUE_NUMERIC,
2819       .x = x
2820     },
2821   };
2822   return value;
2823 }
2824
2825 /* Returns a new pivot_value that represents X, formatted as an integer. */
2826 struct pivot_value *
2827 pivot_value_new_integer (double x)
2828 {
2829   struct pivot_value *value = pivot_value_new_number (x);
2830   value->numeric.format = (struct fmt_spec) { .type = FMT_F, .w = 40 };
2831   return value;
2832 }
2833
2834 /* Returns a new pivot_value that represents VALUE, formatted as for
2835    VARIABLE. */
2836 struct pivot_value *
2837 pivot_value_new_var_value (const struct variable *variable,
2838                            const union value *value)
2839 {
2840   struct pivot_value *pv = pivot_value_new_value (
2841     value, var_get_width (variable), var_get_print_format (variable),
2842     var_get_encoding (variable));
2843
2844   char *var_name = xstrdup (var_get_name (variable));
2845   if (var_is_alpha (variable))
2846     pv->string.var_name = var_name;
2847   else
2848     pv->numeric.var_name = var_name;
2849
2850   const char *label = var_lookup_value_label (variable, value);
2851   if (label)
2852     {
2853       if (var_is_alpha (variable))
2854         pv->string.value_label = xstrdup (label);
2855       else
2856         pv->numeric.value_label = xstrdup (label);
2857     }
2858
2859   return pv;
2860 }
2861
2862 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2863    formatted with FORMAT.  For a string value, ENCODING must be its character
2864    encoding. */
2865 struct pivot_value *
2866 pivot_value_new_value (const union value *value, int width,
2867                        const struct fmt_spec *format, const char *encoding)
2868 {
2869   struct pivot_value *pv = XZALLOC (struct pivot_value);
2870   if (width > 0)
2871     {
2872       char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2873                                width);
2874       size_t n = strlen (s);
2875       while (n > 0 && s[n - 1] == ' ')
2876         s[--n] = '\0';
2877
2878       pv->type = PIVOT_VALUE_STRING;
2879       pv->string.s = s;
2880       pv->string.hex = format->type == FMT_AHEX;
2881     }
2882   else
2883     {
2884       pv->type = PIVOT_VALUE_NUMERIC;
2885       pv->numeric.x = value->f;
2886       pv->numeric.format = *format;
2887     }
2888
2889   return pv;
2890 }
2891
2892 /* Returns a new pivot_value for VARIABLE. */
2893 struct pivot_value *
2894 pivot_value_new_variable (const struct variable *variable)
2895 {
2896   return pivot_value_new_variable__ (var_get_name (variable),
2897                                      var_get_label (variable));
2898 }
2899
2900 /* Returns a new pivot_value for a variable with the given NAME and optional
2901    LABEL. */
2902 struct pivot_value *
2903 pivot_value_new_variable__ (const char *name, const char *label)
2904 {
2905   struct pivot_value *value = xmalloc (sizeof *value);
2906   *value = (struct pivot_value) {
2907     .variable = {
2908       .type = PIVOT_VALUE_VARIABLE,
2909       .var_name = xstrdup (name),
2910       .var_label = xstrdup_if_nonempty (label),
2911     },
2912   };
2913   return value;
2914 }
2915
2916 /* Attaches a reference to FOOTNOTE to V. */
2917 void
2918 pivot_value_add_footnote (struct pivot_value *v,
2919                           const struct pivot_footnote *footnote)
2920 {
2921   struct pivot_value_ex *ex = pivot_value_ex_rw (v);
2922
2923   /* Some legacy tables include numerous duplicate footnotes.  Suppress
2924      them. */
2925   for (size_t i = 0; i < ex->n_footnotes; i++)
2926     if (ex->footnote_indexes[i] == footnote->idx)
2927       return;
2928
2929   ex->footnote_indexes = xrealloc (
2930     ex->footnote_indexes,
2931     (ex->n_footnotes + 1) * sizeof *ex->footnote_indexes);
2932   ex->footnote_indexes[ex->n_footnotes++] = footnote->idx;
2933   pivot_value_sort_footnotes (v);
2934 }
2935
2936 static int
2937 compare_footnote_indexes (const void *a_, const void *b_)
2938 {
2939   const size_t *ap = a_;
2940   const size_t *bp = b_;
2941   size_t a = *ap;
2942   size_t b = *bp;
2943   return a < b ? -1 : a > b;
2944 }
2945
2946 /* Sorts the footnote references in V in the standard ascending order.
2947
2948    This is only necessary if code adds (plural) footnotes to a pivot_value by
2949    itself, because pivot_value_add_footnote() does it automatically. */
2950 void
2951 pivot_value_sort_footnotes (struct pivot_value *v)
2952 {
2953   if (v->ex && v->ex->n_footnotes > 1)
2954     qsort (v->ex->footnote_indexes, v->ex->n_footnotes,
2955            sizeof *v->ex->footnote_indexes, compare_footnote_indexes);
2956 }
2957
2958 /* If VALUE is a numeric value, and RC is a result class such as
2959    PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2960 void
2961 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2962                     const char *rc)
2963 {
2964   if (value->type == PIVOT_VALUE_NUMERIC)
2965     pivot_table_use_rc (table, rc,
2966                         &value->numeric.format, &value->numeric.honor_small);
2967 }
2968 \f
2969 /* pivot_value_ex. */
2970
2971 struct pivot_value_ex *
2972 pivot_value_ex_rw (struct pivot_value *value)
2973 {
2974   if (!value->ex)
2975     value->ex = xzalloc (sizeof *value->ex);
2976   return value->ex;
2977 }
2978
2979 struct pivot_value_ex *
2980 pivot_value_ex_clone (const struct pivot_value_ex *old)
2981 {
2982   struct font_style *font_style = NULL;
2983   if (old->font_style)
2984     {
2985       font_style = xmalloc (sizeof *font_style);
2986       font_style_copy (NULL, font_style, old->font_style);
2987     }
2988
2989   char **subscripts = NULL;
2990   if (old->n_subscripts)
2991     {
2992       subscripts = xnmalloc (old->n_subscripts, sizeof *subscripts);
2993       for (size_t i = 0; i < old->n_subscripts; i++)
2994         subscripts[i] = xstrdup (old->subscripts[i]);
2995     }
2996
2997   struct pivot_value_ex *new = xmalloc (sizeof *new);
2998   *new = (struct pivot_value_ex) {
2999     .font_style = font_style,
3000     .cell_style = (old->cell_style
3001                    ? xmemdup (old->cell_style, sizeof *new->cell_style)
3002                    : NULL),
3003     .subscripts = subscripts,
3004     .n_subscripts = old->n_subscripts,
3005     .footnote_indexes = (
3006       old->n_footnotes
3007       ? xmemdup (old->footnote_indexes,
3008                  old->n_footnotes * sizeof *new->footnote_indexes)
3009       : NULL),
3010     .n_footnotes = old->n_footnotes
3011   };
3012   return new;
3013 }
3014
3015 void
3016 pivot_value_ex_destroy (struct pivot_value_ex *ex)
3017 {
3018   if (ex)
3019     {
3020       font_style_uninit (ex->font_style);
3021       free (ex->font_style);
3022       free (ex->cell_style);
3023       free (ex->footnote_indexes);
3024
3025       for (size_t i = 0; i < ex->n_subscripts; i++)
3026         free (ex->subscripts[i]);
3027       free (ex->subscripts);
3028       free (ex);
3029     }
3030 }