pivot-table: Make pivot_table_look a refcounted object.
[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 <stdlib.h>
22
23 #include "data/data-out.h"
24 #include "data/settings.h"
25 #include "data/value.h"
26 #include "data/variable.h"
27 #include "libpspp/hash-functions.h"
28 #include "libpspp/i18n.h"
29 #include "output/driver.h"
30
31 #include "gl/c-ctype.h"
32 #include "gl/intprops.h"
33 #include "gl/minmax.h"
34 #include "gl/xalloc.h"
35 #include "gl/xmemdup0.h"
36 #include "gl/xsize.h"
37
38 #include "gettext.h"
39 #define _(msgid) gettext (msgid)
40 #define N_(msgid) msgid
41
42 static const struct fmt_spec *pivot_table_get_format (
43   const struct pivot_table *, const char *s);
44 \f
45 /* Pivot table display styling. */
46
47 /* Returns the name of AREA. */
48 const char *
49 pivot_area_to_string (enum pivot_area area)
50 {
51   switch (area)
52     {
53     case PIVOT_AREA_TITLE: return "title";
54     case PIVOT_AREA_CAPTION: return "caption";
55     case PIVOT_AREA_FOOTER: return "footer";
56     case PIVOT_AREA_CORNER: return "corner";
57     case PIVOT_AREA_COLUMN_LABELS: return "column labels";
58     case PIVOT_AREA_ROW_LABELS: return "row labels";
59     case PIVOT_AREA_DATA: return "data";
60     case PIVOT_AREA_LAYERS: return "layers";
61     case PIVOT_N_AREAS: default: return "**error**";
62     }
63 }
64
65 /* Returns the name of BORDER. */
66 const char *
67 pivot_border_to_string (enum pivot_border border)
68 {
69   switch (border)
70     {
71     case PIVOT_BORDER_TITLE:
72       return "title";
73
74     case PIVOT_BORDER_OUTER_LEFT:
75       return "left outer frame";
76     case PIVOT_BORDER_OUTER_TOP:
77       return "top outer frame";
78     case PIVOT_BORDER_OUTER_RIGHT:
79       return "right outer frame";
80     case PIVOT_BORDER_OUTER_BOTTOM:
81       return "bottom outer frame";
82
83     case PIVOT_BORDER_INNER_LEFT:
84       return "left inner frame";
85     case PIVOT_BORDER_INNER_TOP:
86       return "top inner frame";
87     case PIVOT_BORDER_INNER_RIGHT:
88       return "right inner frame";
89     case PIVOT_BORDER_INNER_BOTTOM:
90       return "bottom inner frame";
91
92     case PIVOT_BORDER_DATA_LEFT:
93       return "data area left";
94     case PIVOT_BORDER_DATA_TOP:
95       return "data area top";
96
97     case PIVOT_BORDER_DIM_ROW_HORZ:
98       return "row label horizontal dimension border";
99     case PIVOT_BORDER_DIM_ROW_VERT:
100       return "row label vertical dimension border";
101     case PIVOT_BORDER_DIM_COL_HORZ:
102       return "column label horizontal dimension border";
103     case PIVOT_BORDER_DIM_COL_VERT:
104       return "column label vertical dimension border";
105
106     case PIVOT_BORDER_CAT_ROW_HORZ:
107       return "row label horizontal category border";
108     case PIVOT_BORDER_CAT_ROW_VERT:
109       return "row label vertical category border";
110     case PIVOT_BORDER_CAT_COL_HORZ:
111       return "column label horizontal category border";
112     case PIVOT_BORDER_CAT_COL_VERT:
113       return "column label vertical category border";
114
115     case PIVOT_N_BORDERS:
116     default:
117       return "**error**";
118     }
119 }
120
121 void
122 pivot_table_sizing_uninit (struct pivot_table_sizing *sizing)
123 {
124   if (sizing)
125     {
126       free (sizing->widths);
127       free (sizing->breaks);
128       free (sizing->keeps);
129     }
130 }
131 \f
132 /* Pivot table looks. */
133
134 const struct pivot_table_look *
135 pivot_table_look_builtin_default (void)
136 {
137   static struct pivot_table_look look = {
138     .ref_cnt = 1,
139
140     .omit_empty = true,
141     .row_labels_in_corner = true,
142     .width_ranges = {
143       [TABLE_HORZ] = { 36, 72 },
144       [TABLE_VERT] = { 36, 120 },
145     },
146
147     .areas = {
148 #define AREA(BOLD, H, V, L, R, T, B) {                         \
149     .cell_style = {                                             \
150       .halign = TABLE_HALIGN_##H,                               \
151       .valign = TABLE_VALIGN_##V,                               \
152       .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R,     \
153                   [TABLE_VERT][0] = T, [TABLE_VERT][1] = B },   \
154     },                                                          \
155     .font_style = {                                             \
156       .bold = BOLD,                                             \
157       .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK},  \
158       .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE},  \
159       .size = 9,                                                \
160       .typeface = (char *) "Sans Serif",                        \
161     },                                                          \
162   }
163       [PIVOT_AREA_TITLE]         = AREA(true,  CENTER, CENTER,  8,11,1,8),
164       [PIVOT_AREA_CAPTION]       = AREA(false, LEFT,   TOP,     8,11,1,1),
165       [PIVOT_AREA_FOOTER]        = AREA(false, LEFT,   TOP,    11, 8,2,3),
166       [PIVOT_AREA_CORNER]        = AREA(false, LEFT,   BOTTOM,  8,11,1,1),
167       [PIVOT_AREA_COLUMN_LABELS] = AREA(false, CENTER, BOTTOM,  8,11,1,3),
168       [PIVOT_AREA_ROW_LABELS]    = AREA(false, LEFT,   TOP,     8,11,1,3),
169       [PIVOT_AREA_DATA]          = AREA(false, MIXED,  TOP,     8,11,1,1),
170       [PIVOT_AREA_LAYERS]        = AREA(false, LEFT,   BOTTOM,  8,11,1,3),
171 #undef AREA
172     },
173
174     .borders = {
175 #define BORDER(STROKE) { .stroke = STROKE, .color = CELL_COLOR_BLACK }
176       [PIVOT_BORDER_TITLE]        = BORDER(TABLE_STROKE_NONE),
177       [PIVOT_BORDER_OUTER_LEFT]   = BORDER(TABLE_STROKE_NONE),
178       [PIVOT_BORDER_OUTER_TOP]    = BORDER(TABLE_STROKE_NONE),
179       [PIVOT_BORDER_OUTER_RIGHT]  = BORDER(TABLE_STROKE_NONE),
180       [PIVOT_BORDER_OUTER_BOTTOM] = BORDER(TABLE_STROKE_NONE),
181       [PIVOT_BORDER_INNER_LEFT]   = BORDER(TABLE_STROKE_THICK),
182       [PIVOT_BORDER_INNER_TOP]    = BORDER(TABLE_STROKE_THICK),
183       [PIVOT_BORDER_INNER_RIGHT]  = BORDER(TABLE_STROKE_THICK),
184       [PIVOT_BORDER_INNER_BOTTOM] = BORDER(TABLE_STROKE_THICK),
185       [PIVOT_BORDER_DATA_LEFT]    = BORDER(TABLE_STROKE_THICK),
186       [PIVOT_BORDER_DATA_TOP]     = BORDER(TABLE_STROKE_THICK),
187       [PIVOT_BORDER_DIM_ROW_HORZ] = BORDER(TABLE_STROKE_SOLID),
188       [PIVOT_BORDER_DIM_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
189       [PIVOT_BORDER_DIM_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
190       [PIVOT_BORDER_DIM_COL_VERT] = BORDER(TABLE_STROKE_SOLID),
191       [PIVOT_BORDER_CAT_ROW_HORZ] = BORDER(TABLE_STROKE_NONE),
192       [PIVOT_BORDER_CAT_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
193       [PIVOT_BORDER_CAT_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
194       [PIVOT_BORDER_CAT_COL_VERT] = BORDER(TABLE_STROKE_SOLID),
195     },
196   };
197
198   return &look;
199 }
200
201 struct pivot_table_look *
202 pivot_table_look_new_builtin_default (void)
203 {
204   return pivot_table_look_unshare (
205     pivot_table_look_ref (pivot_table_look_builtin_default ()));
206 }
207
208 struct pivot_table_look *
209 pivot_table_look_ref (const struct pivot_table_look *look_)
210 {
211   assert (look_->ref_cnt > 0);
212
213   struct pivot_table_look *look = CONST_CAST (struct pivot_table_look *, look_);
214   look->ref_cnt++;
215   return look;
216 }
217
218 static char *
219 xstrdup_if_nonempty (const char *s)
220 {
221   return s && s[0] ? xstrdup (s) : NULL;
222 }
223
224 struct pivot_table_look *
225 pivot_table_look_unshare (struct pivot_table_look *old)
226 {
227   assert (old->ref_cnt > 0);
228   if (old->ref_cnt == 1)
229     return old;
230
231   pivot_table_look_unref (old);
232
233   struct pivot_table_look *new = xmemdup (old, sizeof *old);
234   new->ref_cnt = 1;
235   new->name = xstrdup_if_nonempty (old->name);
236   for (size_t i = 0; i < PIVOT_N_AREAS; i++)
237     table_area_style_copy (NULL, &new->areas[i], &old->areas[i]);
238   new->continuation = xstrdup_if_nonempty (old->continuation);
239
240   return new;
241 }
242
243 void
244 pivot_table_look_unref (struct pivot_table_look *look)
245 {
246   if (look)
247     {
248       assert (look->ref_cnt > 0);
249       if (!--look->ref_cnt)
250         {
251           free (look->name);
252           for (size_t i = 0; i < PIVOT_N_AREAS; i++)
253             table_area_style_uninit (&look->areas[i]);
254           free (look->continuation);
255           free (look);
256         }
257     }
258 }
259 \f
260 /* Axes. */
261
262 /* Returns the name of AXIS_TYPE. */
263 const char *
264 pivot_axis_type_to_string (enum pivot_axis_type axis_type)
265 {
266   switch (axis_type)
267     {
268     case PIVOT_AXIS_LAYER:
269       return "layer";
270
271     case PIVOT_AXIS_ROW:
272       return "row";
273
274     case PIVOT_AXIS_COLUMN:
275       return "column";
276
277     default:
278       return "<error>";
279     }
280 }
281
282 static enum pivot_axis_type
283 pivot_axis_type_transpose (enum pivot_axis_type axis_type)
284 {
285   assert (axis_type == PIVOT_AXIS_ROW || axis_type == PIVOT_AXIS_COLUMN);
286   return (axis_type == PIVOT_AXIS_ROW ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW);
287 }
288
289 /* Implementation of PIVOT_AXIS_FOR_EACH. */
290 size_t *
291 pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis)
292 {
293   if (!indexes)
294     {
295       if (axis->n_dimensions)
296         for (size_t i = 0; i < axis->n_dimensions; i++)
297           if (axis->dimensions[i]->n_leaves == 0)
298             return NULL;
299
300       return xcalloc (axis->n_dimensions, sizeof *indexes);
301     }
302
303   for (size_t i = 0; i < axis->n_dimensions; i++)
304     {
305       const struct pivot_dimension *d = axis->dimensions[i];
306       if (++indexes[i] < d->n_leaves)
307         return indexes;
308
309       indexes[i] = 0;
310     }
311
312   free (indexes);
313   return NULL;
314 }
315 \f
316 /* Dimensions. */
317
318 static void
319 pivot_category_set_rc (struct pivot_category *category, const char *s)
320 {
321   const struct fmt_spec *format = pivot_table_get_format (
322     category->dimension->table, s);
323   if (format)
324     category->format = *format;
325 }
326
327 static void
328 pivot_category_create_leaves_valist (struct pivot_category *parent,
329                                      va_list args)
330 {
331   const char *s;
332   while ((s = va_arg (args, const char *)))
333     {
334       if (!strncmp (s, "RC_", 3))
335         {
336           assert (parent->n_subs);
337           pivot_category_set_rc (parent->subs[parent->n_subs - 1], s);
338         }
339       else
340         pivot_category_create_leaf (parent, pivot_value_new_text (s));
341     }
342 }
343
344 /* Creates a new dimension with the given NAME in TABLE and returns it.  The
345    dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
346    that axis.
347
348    NAME should be a translatable name, but not actually translated yet,
349    e.g. enclosed in N_().  To use a different kind of value for a name, use
350    pivot_dimension_create__() instead.
351
352    The optional varargs parameters may be used to add an initial set of
353    categories to the dimension.  Each string should be a translatable category
354    name, but not actually translated yet, e.g. enclosed in N_().  Each string
355    may optionally be followod by a PIVOT_RC_* string that specifies the default
356    numeric format for cells in this category. */
357 struct pivot_dimension * SENTINEL (0)
358 (pivot_dimension_create) (struct pivot_table *table,
359                           enum pivot_axis_type axis_type,
360                           const char *name, ...)
361 {
362   struct pivot_dimension *d = pivot_dimension_create__ (
363     table, axis_type, pivot_value_new_text (name));
364
365   va_list args;
366   va_start (args, name);
367   pivot_category_create_leaves_valist (d->root, args);
368   va_end (args);
369
370   return d;
371 }
372
373 /* Creates a new dimension with the given NAME in TABLE and returns it.  The
374    dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
375    that axis. */
376 struct pivot_dimension *
377 pivot_dimension_create__ (struct pivot_table *table,
378                           enum pivot_axis_type axis_type,
379                           struct pivot_value *name)
380 {
381   assert (pivot_table_is_empty (table));
382
383   struct pivot_dimension *d = xmalloc (sizeof *d);
384   *d = (struct pivot_dimension) {
385     .table = table,
386     .axis_type = axis_type,
387     .level = table->axes[axis_type].n_dimensions,
388     .top_index = table->n_dimensions,
389     .root = xmalloc (sizeof *d->root),
390   };
391
392   struct pivot_category *root = d->root;
393   *root = (struct pivot_category) {
394     .name = name,
395     .parent = NULL,
396     .dimension = d,
397     .show_label = false,
398     .data_index = SIZE_MAX,
399     .presentation_index = SIZE_MAX,
400   };
401
402   table->dimensions = xrealloc (
403     table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions);
404   table->dimensions[table->n_dimensions++] = d;
405
406   struct pivot_axis *axis = &table->axes[axis_type];
407   axis->dimensions = xrealloc (
408     axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
409   axis->dimensions[axis->n_dimensions++] = d;
410
411   if (axis_type == PIVOT_AXIS_LAYER)
412     {
413       free (table->current_layer);
414       table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
415                                       sizeof *table->current_layer);
416     }
417
418   /* axis->extent and axis->label_depth will be calculated later. */
419
420   return d;
421 }
422
423 void
424 pivot_dimension_destroy (struct pivot_dimension *d)
425 {
426   if (!d)
427     return;
428
429   pivot_category_destroy (d->root);
430   free (d->data_leaves);
431   free (d->presentation_leaves);
432   free (d);
433 }
434
435 /* Returns the first leaf node in an in-order traversal that is a child of
436    CAT. */
437 static const struct pivot_category * UNUSED
438 pivot_category_first_leaf (const struct pivot_category *cat)
439 {
440   if (pivot_category_is_leaf (cat))
441     return cat;
442
443   for (size_t i = 0; i < cat->n_subs; i++)
444     {
445       const struct pivot_category *first
446         = pivot_category_first_leaf (cat->subs[i]);
447       if (first)
448         return first;
449     }
450
451   return NULL;
452 }
453
454 /* Returns the next leaf node in an in-order traversal starting at CAT, which
455    must be a leaf. */
456 static const struct pivot_category * UNUSED
457 pivot_category_next_leaf (const struct pivot_category *cat)
458 {
459   assert (pivot_category_is_leaf (cat));
460
461   for (;;)
462     {
463       const struct pivot_category *parent = cat->parent;
464       if (!parent)
465         return NULL;
466       for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
467         {
468           const struct pivot_category *next
469             = pivot_category_first_leaf (parent->subs[i]);
470           if (next)
471             return next;
472         }
473
474       cat = cat->parent;
475     }
476 }
477
478 static void
479 pivot_category_add_child (struct pivot_category *child)
480 {
481   struct pivot_category *parent = child->parent;
482
483   assert (pivot_category_is_group (parent));
484   if (parent->n_subs >= parent->allocated_subs)
485     parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
486                                sizeof *parent->subs);
487   parent->subs[parent->n_subs++] = child;
488 }
489
490 /* Adds leaf categories as a child of PARENT.  To create top-level categories
491    within dimension 'd', pass 'd->root' for PARENT.
492
493    Each of the varargs parameters should be a string, each of which should be a
494    translatable category name, but not actually translated yet, e.g. enclosed
495    in N_().  Each string may optionally be followod by a PIVOT_RC_* string that
496    specifies the default numeric format for cells in this category.
497
498    Returns the category index, which is just a 0-based array index, for the
499    first new category.
500
501    Leaves have to be created in in-order, that is, don't create a group and add
502    some leaves, then add leaves outside the group and try to add more leaves
503    inside it. */
504 int SENTINEL (0)
505 (pivot_category_create_leaves) (struct pivot_category *parent, ...)
506 {
507   int retval = parent->dimension->n_leaves;
508
509   va_list args;
510   va_start (args, parent);
511   pivot_category_create_leaves_valist (parent, args);
512   va_end (args);
513
514   return retval;
515 }
516
517 /* Creates a new leaf category with the given NAME as a child of PARENT.  To
518    create a top-level category within dimension 'd', pass 'd->root' for PARENT.
519    Returns the category index, which is just a 0-based array index, for the new
520    category.
521
522    Leaves have to be created in in-order, that is, don't create a group and add
523    some leaves, then add leaves outside the group and try to add more leaves
524    inside it. */
525 int
526 pivot_category_create_leaf (struct pivot_category *parent,
527                             struct pivot_value *name)
528 {
529   return pivot_category_create_leaf_rc (parent, name, NULL);
530 }
531
532 /* Creates a new leaf category with the given NAME as a child of PARENT.  To
533    create a top-level category within dimension 'd', pass 'd->root' for PARENT.
534    Returns the category index, which is just a 0-based array index, for the new
535    category.
536
537    If RC is nonnull and the name of a result category, the category is assigned
538    that result category.
539
540    Leaves have to be created in in-order, that is, don't create a group and add
541    some leaves, then add leaves outside the group and try to add more leaves
542    inside it. */
543 int
544 pivot_category_create_leaf_rc (struct pivot_category *parent,
545                                struct pivot_value *name, const char *rc)
546 {
547   struct pivot_dimension *d = parent->dimension;
548
549   struct pivot_category *leaf = xmalloc (sizeof *leaf);
550   *leaf = (struct pivot_category) {
551     .name = name,
552     .parent = parent,
553     .dimension = d,
554     .group_index = parent->n_subs,
555     .data_index = d->n_leaves,
556     .presentation_index = d->n_leaves,
557   };
558
559   if (d->n_leaves >= d->allocated_leaves)
560     {
561       d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
562                                    sizeof *d->data_leaves);
563       d->presentation_leaves = xrealloc (
564         d->presentation_leaves,
565         d->allocated_leaves * sizeof *d->presentation_leaves);
566     }
567
568   d->data_leaves[d->n_leaves] = leaf;
569   d->presentation_leaves[d->n_leaves] = leaf;
570   d->n_leaves++;
571
572   pivot_category_add_child (leaf);
573
574   /* Make sure that the new child is the last in in-order. */
575   assert (!pivot_category_next_leaf (leaf));
576
577   pivot_category_set_rc (leaf, rc);
578
579   return leaf->data_index;
580 }
581
582 /* Adds a new category group named NAME as a child of PARENT.  To create a
583    top-level group within dimension 'd', pass 'd->root' for PARENT.
584
585    NAME should be a translatable name, but not actually translated yet,
586    e.g. enclosed in N_().  To use a different kind of value for a name, use
587    pivot_category_create_group__() instead.
588
589    The optional varargs parameters may be used to add an initial set of
590    categories to the group.  Each string should be a translatable category
591    name, but not actually translated yet, e.g. enclosed in N_().  Each string
592    may optionally be followod by a PIVOT_RC_* string that specifies the default
593    numeric format for cells in this category.
594
595    Returns the new group. */
596 struct pivot_category * SENTINEL (0)
597 (pivot_category_create_group) (struct pivot_category *parent,
598                                const char *name, ...)
599 {
600   struct pivot_category *group = pivot_category_create_group__ (
601     parent, pivot_value_new_text (name));
602
603   va_list args;
604   va_start (args, name);
605   pivot_category_create_leaves_valist (group, args);
606   va_end (args);
607
608   return group;
609 }
610
611 /* Adds a new category group named NAME as a child of PARENT.  To create a
612    top-level group within dimension 'd', pass 'd->root' for PARENT.  Returns
613    the new group. */
614 struct pivot_category *
615 pivot_category_create_group__ (struct pivot_category *parent,
616                                struct pivot_value *name)
617 {
618   struct pivot_dimension *d = parent->dimension;
619
620   struct pivot_category *group = xmalloc (sizeof *group);
621   *group = (struct pivot_category) {
622     .name = name,
623     .parent = parent,
624     .dimension = d,
625     .show_label = true,
626     .group_index = parent->n_subs,
627     .data_index = SIZE_MAX,
628     .presentation_index = SIZE_MAX,
629   };
630
631   pivot_category_add_child (group);
632
633   return group;
634 }
635
636 void
637 pivot_category_destroy (struct pivot_category *c)
638 {
639   if (!c)
640     return;
641
642   pivot_value_destroy (c->name);
643   for (size_t i = 0; i < c->n_subs; i++)
644     pivot_category_destroy (c->subs[i]);
645   free (c->subs);
646   free (c);
647 }
648 \f
649 /* Result classes.
650
651    These are usually the easiest way to control the formatting of numeric data
652    in a pivot table.  See pivot_dimension_create() for an explanation of their
653    use.  */
654 struct result_class
655   {
656     const char *name;           /* "RC_*". */
657     struct fmt_spec format;
658   };
659
660 /* Formats for most of the result classes. */
661 static struct result_class result_classes[] =
662   {
663     { PIVOT_RC_INTEGER,      { FMT_F,   40, 0 } },
664     { PIVOT_RC_PERCENT,      { FMT_PCT, 40, 1 } },
665     { PIVOT_RC_CORRELATION,  { FMT_F,   40, 3 } },
666     { PIVOT_RC_SIGNIFICANCE, { FMT_F,   40, 3 } },
667     { PIVOT_RC_RESIDUAL,     { FMT_F,   40, 2 } },
668     { PIVOT_RC_COUNT,        { 0, 0, 0 } },
669     { PIVOT_RC_OTHER,        { 0, 0, 0 } },
670   };
671
672 /* Has PIVOT_RC_COUNT been overridden by the user? */
673 static bool overridden_count_format;
674
675 static struct result_class *
676 pivot_result_class_find (const char *s)
677 {
678   for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
679     if (!strcmp (s, result_classes[i].name))
680       return &result_classes[i];
681   return NULL;
682 }
683
684 static const struct fmt_spec *
685 pivot_table_get_format (const struct pivot_table *table, const char *s)
686 {
687   if (!s)
688     return NULL;
689   else if (!strcmp (s, PIVOT_RC_OTHER))
690     return settings_get_format ();
691   else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
692     return &table->weight_format;
693   else
694     {
695       const struct result_class *rc = pivot_result_class_find (s);
696       return rc ? &rc->format : NULL;
697     }
698 }
699
700 /* Sets the format specification for the result class named S (which should not
701    include the RC_ prefix) to *FORMAT.  Returns true if successful, false if S
702    does not name a known result class. */
703 bool
704 pivot_result_class_change (const char *s_, const struct fmt_spec *format)
705 {
706   char *s = xasprintf ("RC_%s", s_);
707   struct result_class *rc = pivot_result_class_find (s);
708   if (rc)
709     {
710       rc->format = *format;
711       if (!strcmp (s, PIVOT_RC_COUNT))
712         overridden_count_format = true;
713     }
714   free (s);
715
716   return rc != NULL;
717 }
718 \f
719 /* Pivot tables. */
720
721 /* Creates and returns a new pivot table with the given TITLE.  TITLE should be
722    a text string marked for translation but not actually translated yet,
723    e.g. N_("Descriptive Statistics").  The un-translated text string is used as
724    the pivot table's subtype.
725
726    Operations commonly performed on the new pivot_table:
727
728    - If empty rows or columns should not be displayed, set ->omit_empty to
729      true.
730
731    - Set the format to use for "count" values with pivot_table_set_weight_var()
732      or pivot_table_set_weight_format().
733
734    This function is a shortcut for pivot_table_create__() for the most common
735    case.  Use pivot_table_create__() directly if the title should be some kind
736    of value other than an ordinary text string, or if the subtype should be
737 different from the title.
738
739    See the large comment at the top of pivot-table.h for general advice on
740    creating pivot tables. */
741 struct pivot_table *
742 pivot_table_create (const char *title)
743 {
744   return pivot_table_create__ (pivot_value_new_text (title), title);
745 }
746
747 /* Creates and returns a new pivot table with the given TITLE, and takes
748    ownership of TITLE.  The new pivot table's subtype is SUBTYPE, which
749    should be an untranslated English string that describes the contents of
750    the table at a high level without being specific about the variables or
751    other context involved.
752
753    Operations commonly performed on the new pivot_table:
754
755    - If empty rows or columns should not be displayed, set ->omit_empty to
756      true.
757
758    - Set the format to use for "count" values with pivot_table_set_weight_var()
759      or pivot_table_set_weight_format().
760
761    See the large comment at the top of pivot-table.h for general advice on
762    creating pivot tables. */
763 struct pivot_table *
764 pivot_table_create__ (struct pivot_value *title, const char *subtype)
765 {
766   struct pivot_table *table = xzalloc (sizeof *table);
767   table->ref_cnt = 1;
768   table->show_caption = true;
769   table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
770   table->title = title;
771   table->subtype = subtype ? pivot_value_new_text (subtype) : NULL;
772   table->command_c = output_get_command_name ();
773   table->look = pivot_table_look_ref (pivot_table_look_builtin_default ());
774
775   hmap_init (&table->cells);
776
777   return table;
778 }
779
780 /* Creates and returns a new pivot table with the given TITLE and a single cell
781    with the given CONTENT.
782
783    This is really just for error handling. */
784 struct pivot_table *
785 pivot_table_create_for_text (struct pivot_value *title,
786                              struct pivot_value *content)
787 {
788   struct pivot_table *table = pivot_table_create__ (title, "Error");
789
790   struct pivot_dimension *d = pivot_dimension_create (
791     table, PIVOT_AXIS_ROW, N_("Error"));
792   d->hide_all_labels = true;
793   pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
794
795   pivot_table_put1 (table, 0, content);
796
797   return table;
798 }
799
800 /* Increases TABLE's reference count, indicating that it has an additional
801    owner.  A pivot table that is shared among multiple owners must not be
802    modified. */
803 struct pivot_table *
804 pivot_table_ref (const struct pivot_table *table_)
805 {
806   struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
807   table->ref_cnt++;
808   return table;
809 }
810
811 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
812    If TABLE no longer has any owners, it is freed. */
813 void
814 pivot_table_unref (struct pivot_table *table)
815 {
816   if (!table)
817     return;
818   assert (table->ref_cnt > 0);
819   if (--table->ref_cnt)
820     return;
821
822   free (table->current_layer);
823   pivot_table_look_unref (table->look);
824
825   for (int i = 0; i < TABLE_N_AXES; i++)
826     pivot_table_sizing_uninit (&table->sizing[i]);
827
828   for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
829     free (table->ccs[i]);
830
831   free (table->command_local);
832   free (table->command_c);
833   free (table->language);
834   free (table->locale);
835
836   free (table->dataset);
837   free (table->datafile);
838
839   for (size_t i = 0; i < table->n_footnotes; i++)
840     pivot_footnote_destroy (table->footnotes[i]);
841   free (table->footnotes);
842
843   pivot_value_destroy (table->title);
844   pivot_value_destroy (table->subtype);
845   pivot_value_destroy (table->corner_text);
846   pivot_value_destroy (table->caption);
847
848   for (size_t i = 0; i < table->n_dimensions; i++)
849     pivot_dimension_destroy (table->dimensions[i]);
850   free (table->dimensions);
851
852   for (size_t i = 0; i < PIVOT_N_AXES; i++)
853     free (table->axes[i].dimensions);
854
855   struct pivot_cell *cell, *next_cell;
856   HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
857                       &table->cells)
858     {
859       hmap_delete (&table->cells, &cell->hmap_node);
860       pivot_value_destroy (cell->value);
861       free (cell);
862     }
863   hmap_destroy (&table->cells);
864
865   free (table);
866 }
867
868 /* Returns true if TABLE has more than one owner.  A pivot table that is shared
869    among multiple owners must not be modified. */
870 bool
871 pivot_table_is_shared (const struct pivot_table *table)
872 {
873   return table->ref_cnt > 1;
874 }
875
876 const struct pivot_table_look *
877 pivot_table_get_look (const struct pivot_table *table)
878 {
879   return table->look;
880 }
881
882 void
883 pivot_table_set_look (struct pivot_table *table,
884                       const struct pivot_table_look *look)
885 {
886   pivot_table_look_unref (table->look);
887   table->look = pivot_table_look_ref (look);
888 }
889
890 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
891    WV, which should be the weight variable for the dictionary whose data or
892    statistics are being put into TABLE.
893
894    This has no effect if WV is NULL. */
895 void
896 pivot_table_set_weight_var (struct pivot_table *table,
897                             const struct variable *wv)
898 {
899   if (wv)
900     pivot_table_set_weight_format (table, var_get_print_format (wv));
901 }
902
903 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
904    format for the dictionary whose data or statistics are being put into TABLE.
905
906    This has no effect if WFMT is NULL. */
907 void
908 pivot_table_set_weight_format (struct pivot_table *table,
909                                const struct fmt_spec *wfmt)
910 {
911   if (wfmt)
912     table->weight_format = *wfmt;
913 }
914
915 /* Returns true if TABLE has no cells, false otherwise. */
916 bool
917 pivot_table_is_empty (const struct pivot_table *table)
918 {
919   return hmap_is_empty (&table->cells);
920 }
921
922 static unsigned int
923 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
924 {
925   return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
926 }
927
928 static bool
929 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
930 {
931   for (size_t i = 0; i < n; i++)
932     if (a[i] != b[i])
933       return false;
934
935   return true;
936 }
937
938 static struct pivot_cell *
939 pivot_table_lookup_cell__ (const struct pivot_table *table,
940                             const size_t *dindexes, unsigned int hash)
941 {
942   struct pivot_cell *cell;
943   HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
944                            &table->cells)
945     if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
946       return cell;
947   return false;
948 }
949
950 static struct pivot_cell *
951 pivot_cell_allocate (size_t n_idx)
952 {
953   struct pivot_cell *cell UNUSED;
954   return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
955 }
956
957 static struct pivot_cell *
958 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
959 {
960   unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
961   struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
962   if (!cell)
963     {
964       cell = pivot_cell_allocate (table->n_dimensions);
965       for (size_t i = 0; i < table->n_dimensions; i++)
966         cell->idx[i] = dindexes[i];
967       cell->value = NULL;
968       hmap_insert (&table->cells, &cell->hmap_node, hash);
969     }
970   return cell;
971 }
972
973 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
974    DINDEXES.  N must be the number of dimensions in TABLE.  Takes ownership of
975    VALUE.
976
977    If VALUE is a numeric value without a specified format, this function checks
978    each of the categories designated by DINDEXES[] and takes the format from
979    the first category with a result class.  If none has a result class, uses
980    the overall default numeric format. */
981 void
982 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
983                  struct pivot_value *value)
984 {
985   assert (n == table->n_dimensions);
986
987   if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
988     {
989       for (size_t i = 0; i < table->n_dimensions; i++)
990         {
991           const struct pivot_dimension *d = table->dimensions[i];
992           if (dindexes[i] < d->n_leaves)
993             {
994               const struct pivot_category *c = d->data_leaves[dindexes[i]];
995               if (c->format.w)
996                 {
997                   value->numeric.format = c->format;
998                   goto done;
999                 }
1000             }
1001         }
1002       value->numeric.format = *settings_get_format ();
1003
1004     done:;
1005     }
1006
1007   struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1008   pivot_value_destroy (cell->value);
1009   cell->value = value;
1010 }
1011
1012 /* Puts VALUE in the cell in TABLE with index IDX1.  TABLE must have 1
1013    dimension.  Takes ownership of VALUE.  */
1014 void
1015 pivot_table_put1 (struct pivot_table *table, size_t idx1,
1016                   struct pivot_value *value)
1017 {
1018   size_t dindexes[] = { idx1 };
1019   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1020 }
1021
1022 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2).  TABLE must have 2
1023    dimensions.  Takes ownership of VALUE.  */
1024 void
1025 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
1026                   struct pivot_value *value)
1027 {
1028   size_t dindexes[] = { idx1, idx2 };
1029   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1030 }
1031
1032 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3).  TABLE must
1033    have 3 dimensions.  Takes ownership of VALUE.  */
1034 void
1035 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
1036                   size_t idx3, struct pivot_value *value)
1037 {
1038   size_t dindexes[] = { idx1, idx2, idx3 };
1039   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1040 }
1041
1042 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4).  TABLE
1043    must have 4 dimensions.  Takes ownership of VALUE.  */
1044 void
1045 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1046                   size_t idx3, size_t idx4, struct pivot_value *value)
1047 {
1048   size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1049   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1050 }
1051
1052 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1053    automatically assigned marker.
1054
1055    The footnote will only appear in output if it is referenced.  Use
1056    pivot_value_add_footnote() to add a reference to the footnote. */
1057 struct pivot_footnote *
1058 pivot_table_create_footnote (struct pivot_table *table,
1059                              struct pivot_value *content)
1060 {
1061   return pivot_table_create_footnote__ (table, table->n_footnotes,
1062                                         NULL, content);
1063 }
1064
1065 static struct pivot_value *
1066 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1067 {
1068   char text[INT_BUFSIZE_BOUND (size_t)];
1069   if (show_numeric_markers)
1070     snprintf (text, sizeof text, "%d", idx + 1);
1071   else
1072     str_format_26adic (idx + 1, false, text, sizeof text);
1073   return pivot_value_new_user_text (text, -1);
1074 }
1075
1076 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1077    all lower indexes as a side effect).  If MARKER is nonnull, sets the
1078    footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1079 struct pivot_footnote *
1080 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1081                                struct pivot_value *marker,
1082                                struct pivot_value *content)
1083 {
1084   if (idx >= table->n_footnotes)
1085     {
1086       while (idx >= table->allocated_footnotes)
1087         table->footnotes = x2nrealloc (table->footnotes,
1088                                        &table->allocated_footnotes,
1089                                        sizeof *table->footnotes);
1090       while (idx >= table->n_footnotes)
1091         {
1092           struct pivot_footnote *f = xmalloc (sizeof *f);
1093           f->idx = table->n_footnotes;
1094           f->marker = pivot_make_default_footnote_marker (
1095             f->idx, table->look->show_numeric_markers);
1096           f->content = NULL;
1097           f->show = true;
1098
1099           table->footnotes[table->n_footnotes++] = f;
1100         }
1101     }
1102
1103   struct pivot_footnote *f = table->footnotes[idx];
1104   if (marker)
1105     {
1106       pivot_value_destroy (f->marker);
1107       f->marker = marker;
1108     }
1109   if (content)
1110     {
1111       pivot_value_destroy (f->content);
1112       f->content = content;
1113     }
1114   return f;
1115 }
1116
1117 /* Frees the data owned by F. */
1118 void
1119 pivot_footnote_destroy (struct pivot_footnote *f)
1120 {
1121   if (f)
1122     {
1123       pivot_value_destroy (f->content);
1124       pivot_value_destroy (f->marker);
1125       free (f);
1126     }
1127 }
1128
1129 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1130    indexes for each dimension in TABLE in DINDEXES[]. */
1131 void
1132 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1133                                   const size_t *pindexes[PIVOT_N_AXES],
1134                                   size_t dindexes[/* table->n_dimensions */])
1135 {
1136   for (size_t i = 0; i < PIVOT_N_AXES; i++)
1137     {
1138       const struct pivot_axis *axis = &table->axes[i];
1139
1140       for (size_t j = 0; j < axis->n_dimensions; j++)
1141         {
1142           const struct pivot_dimension *d = axis->dimensions[j];
1143           dindexes[d->top_index]
1144             = d->presentation_leaves[pindexes[i][j]]->data_index;
1145         }
1146     }
1147 }
1148
1149 size_t *
1150 pivot_table_enumerate_axis (const struct pivot_table *table,
1151                             enum pivot_axis_type axis_type,
1152                             const size_t *layer_indexes, bool omit_empty,
1153                             size_t *n)
1154 {
1155   const struct pivot_axis *axis = &table->axes[axis_type];
1156   if (!axis->n_dimensions)
1157     {
1158       size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1159       enumeration[0] = 0;
1160       enumeration[1] = SIZE_MAX;
1161       if (n)
1162         *n = 1;
1163       return enumeration;
1164     }
1165   else if (!axis->extent)
1166     {
1167       size_t *enumeration = xmalloc (sizeof *enumeration);
1168       *enumeration = SIZE_MAX;
1169       if (n)
1170         *n = 0;
1171       return enumeration;
1172     }
1173
1174   size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1175                                                 axis->n_dimensions), 1),
1176                                   sizeof *enumeration);
1177   size_t *p = enumeration;
1178   size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1179
1180   size_t *axis_indexes;
1181   PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1182     {
1183       if (omit_empty)
1184         {
1185           enum pivot_axis_type axis2_type
1186             = pivot_axis_type_transpose (axis_type);
1187
1188           size_t *axis2_indexes;
1189           PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1190             {
1191               const size_t *pindexes[PIVOT_N_AXES];
1192               pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1193               pindexes[axis_type] = axis_indexes;
1194               pindexes[axis2_type] = axis2_indexes;
1195               pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1196               if (pivot_table_get (table, dindexes))
1197                 goto found;
1198             }
1199           continue;
1200
1201         found:
1202           free (axis2_indexes);
1203         }
1204
1205       memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1206       p += axis->n_dimensions;
1207     }
1208   if (omit_empty && p == enumeration)
1209     {
1210       PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1211         {
1212           memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1213           p += axis->n_dimensions;
1214         }
1215     }
1216   *p = SIZE_MAX;
1217   if (n)
1218     *n = (p - enumeration) / axis->n_dimensions;
1219
1220   free (dindexes);
1221   return enumeration;
1222 }
1223
1224 static const struct pivot_cell *
1225 pivot_table_lookup_cell (const struct pivot_table *table,
1226                           const size_t *dindexes)
1227 {
1228   unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1229   return pivot_table_lookup_cell__ (table, dindexes, hash);
1230 }
1231
1232 const struct pivot_value *
1233 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1234 {
1235   const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1236   return cell ? cell->value : NULL;
1237 }
1238
1239 struct pivot_value *
1240 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1241 {
1242   struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1243   if (!cell->value)
1244     cell->value = pivot_value_new_user_text ("", -1);
1245   return cell->value;
1246 }
1247
1248 static void
1249 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1250 {
1251   if (pivot_category_is_group (category) && category->n_subs)
1252     for (size_t i = 0; i < category->n_subs; i++)
1253       distribute_extra_depth (category->subs[i], extra_depth);
1254   else
1255     category->extra_depth += extra_depth;
1256 }
1257
1258 static void
1259 pivot_category_assign_label_depth (struct pivot_category *category,
1260                                    bool dimension_labels_in_corner)
1261 {
1262   category->extra_depth = 0;
1263
1264   if (pivot_category_is_group (category))
1265     {
1266       size_t depth = 0;
1267       for (size_t i = 0; i < category->n_subs; i++)
1268         {
1269           pivot_category_assign_label_depth (category->subs[i], false);
1270           depth = MAX (depth, category->subs[i]->label_depth);
1271         }
1272
1273       for (size_t i = 0; i < category->n_subs; i++)
1274         {
1275           struct pivot_category *sub = category->subs[i];
1276
1277           size_t extra_depth = depth - sub->label_depth;
1278           if (extra_depth)
1279             distribute_extra_depth (sub, extra_depth);
1280
1281           sub->label_depth = depth;
1282         }
1283
1284       category->show_label_in_corner = (category->show_label
1285                                         && dimension_labels_in_corner);
1286       category->label_depth
1287         = (category->show_label && !category->show_label_in_corner
1288            ? depth + 1 : depth);
1289     }
1290   else
1291     category->label_depth = 1;
1292 }
1293
1294 static bool
1295 pivot_axis_assign_label_depth (struct pivot_table *table,
1296                              enum pivot_axis_type axis_type,
1297                              bool dimension_labels_in_corner)
1298 {
1299   struct pivot_axis *axis = &table->axes[axis_type];
1300   bool any_label_shown_in_corner = false;
1301   axis->label_depth = 0;
1302   axis->extent = 1;
1303   for (size_t i = 0; i < axis->n_dimensions; i++)
1304     {
1305       struct pivot_dimension *d = axis->dimensions[i];
1306       pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1307       d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1308       axis->label_depth += d->label_depth;
1309       axis->extent *= d->n_leaves;
1310
1311       if (d->root->show_label_in_corner)
1312         any_label_shown_in_corner = true;
1313     }
1314   return any_label_shown_in_corner;
1315 }
1316
1317 void
1318 pivot_table_assign_label_depth (struct pivot_table *table)
1319 {
1320   pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1321   if (pivot_axis_assign_label_depth (
1322         table, PIVOT_AXIS_ROW, (table->look->row_labels_in_corner
1323                                 && !table->corner_text))
1324       && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1325     table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1326   pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1327 }
1328 \f
1329 /* Footnotes. */
1330
1331 \f
1332 \f
1333 static void
1334 indent (int indentation)
1335 {
1336   for (int i = 0; i < indentation * 2; i++)
1337     putchar (' ');
1338 }
1339
1340 static void
1341 pivot_value_dump (const struct pivot_value *value)
1342 {
1343   char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1344                                    SETTINGS_VALUE_SHOW_DEFAULT);
1345   fputs (s, stdout);
1346   free (s);
1347 }
1348
1349 static void
1350 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1351                       int indentation)
1352 {
1353   if (value)
1354     {
1355       indent (indentation);
1356       printf ("%s: ", name);
1357       pivot_value_dump (value);
1358       putchar ('\n');
1359     }
1360 }
1361
1362 static void
1363 pivot_table_dump_string (const char *string, const char *name, int indentation)
1364 {
1365   if (string)
1366     {
1367       indent (indentation);
1368       printf ("%s: %s\n", name, string);
1369     }
1370 }
1371
1372 static void
1373 pivot_category_dump (const struct pivot_category *c, int indentation)
1374 {
1375   indent (indentation);
1376   printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1377   pivot_value_dump (c->name);
1378   printf ("\" ");
1379
1380   if (pivot_category_is_leaf (c))
1381     printf ("data_index=%zu\n", c->data_index);
1382   else
1383     {
1384       printf (" (label %s)", c->show_label ? "shown" : "hidden");
1385       printf ("\n");
1386
1387       for (size_t i = 0; i < c->n_subs; i++)
1388         pivot_category_dump (c->subs[i], indentation + 1);
1389     }
1390 }
1391
1392 void
1393 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1394 {
1395   indent (indentation);
1396   printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1397           pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1398
1399   pivot_category_dump (d->root, indentation + 1);
1400 }
1401
1402 static void
1403 table_area_style_dump (enum pivot_area area, const struct table_area_style *a,
1404                        int indentation)
1405 {
1406   indent (indentation);
1407   printf ("%s: ", pivot_area_to_string (area));
1408   font_style_dump (&a->font_style);
1409   putchar (' ');
1410   cell_style_dump (&a->cell_style);
1411   putchar ('\n');
1412 }
1413
1414 static void
1415 table_border_style_dump (enum pivot_border border,
1416                          const struct table_border_style *b, int indentation)
1417 {
1418   indent (indentation);
1419   printf ("%s: %s ", pivot_border_to_string (border),
1420           table_stroke_to_string (b->stroke));
1421   cell_color_dump (&b->color);
1422   putchar ('\n');
1423 }
1424
1425 static char ***
1426 compose_headings (const struct pivot_axis *axis,
1427                   const size_t *column_enumeration,
1428                   enum settings_value_show show_values,
1429                   enum settings_value_show show_variables)
1430 {
1431   if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1432     return NULL;
1433
1434   char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1435   for (size_t i = 0; i < axis->label_depth; i++)
1436     headings[i] = xcalloc (axis->extent, sizeof **headings);
1437
1438   const size_t *indexes;
1439   size_t column = 0;
1440   PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1441     {
1442       int row = axis->label_depth - 1;
1443       for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1444         {
1445           const struct pivot_dimension *d = axis->dimensions[dim_index];
1446           if (d->hide_all_labels)
1447             continue;
1448           for (const struct pivot_category *c
1449                  = d->presentation_leaves[indexes[dim_index]];
1450                c;
1451                c = c->parent)
1452             {
1453               if (pivot_category_is_leaf (c) || (c->show_label
1454                                                  && !c->show_label_in_corner))
1455                 {
1456                   headings[row][column] = pivot_value_to_string (
1457                     c->name, show_values, show_variables);
1458                   if (!*headings[row][column])
1459                     headings[row][column] = xstrdup ("<blank>");
1460                   row--;
1461                 }
1462             }
1463         }
1464       column++;
1465     }
1466
1467   return headings;
1468 }
1469
1470 static void
1471 free_headings (const struct pivot_axis *axis, char ***headings)
1472 {
1473   for (size_t i = 0; i < axis->label_depth; i++)
1474     {
1475       for (size_t j = 0; j < axis->extent; j++)
1476         free (headings[i][j]);
1477       free (headings[i]);
1478     }
1479   free (headings);
1480 }
1481
1482 static void
1483 pivot_table_sizing_dump (const char *name,
1484                          const int width_ranges[2],
1485                          const struct pivot_table_sizing *s,
1486                          int indentation)
1487 {
1488   indent (indentation);
1489   printf ("%ss: min=%d, max=%d\n", name, width_ranges[0], width_ranges[1]);
1490   if (s->n_widths)
1491     {
1492       indent (indentation + 1);
1493       printf ("%s widths:", name);
1494       for (size_t i = 0; i < s->n_widths; i++)
1495         printf (" %d", s->widths[i]);
1496       printf ("\n");
1497     }
1498   if (s->n_breaks)
1499     {
1500       indent (indentation + 1);
1501       printf ("break after %ss:", name);
1502       for (size_t i = 0; i < s->n_breaks; i++)
1503         printf (" %zu", s->breaks[i]);
1504       printf ("\n");
1505     }
1506   if (s->n_keeps)
1507     {
1508       indent (indentation + 1);
1509       printf ("keep %ss together:", name);
1510       for (size_t i = 0; i < s->n_keeps; i++)
1511         printf (" [%zu,%zu]",
1512                 s->keeps[i].ofs,
1513                 s->keeps[i].ofs + s->keeps[i].n - 1);
1514       printf ("\n");
1515     }
1516 }
1517
1518 void
1519 pivot_table_dump (const struct pivot_table *table, int indentation)
1520 {
1521   if (!table)
1522     return;
1523
1524   int old_decimal = settings_get_decimal_char (FMT_COMMA);
1525   if (table->decimal == '.' || table->decimal == ',')
1526     settings_set_decimal_char (table->decimal);
1527
1528   pivot_table_dump_value (table->title, "title", indentation);
1529   pivot_table_dump_string (table->command_c, "command", indentation);
1530   pivot_table_dump_string (table->dataset, "dataset", indentation);
1531   pivot_table_dump_string (table->datafile, "datafile", indentation);
1532   pivot_table_dump_string (table->notes, "notes", indentation);
1533   pivot_table_dump_string (table->look->name, "table-look", indentation);
1534   if (table->date)
1535     {
1536       indent (indentation);
1537
1538       struct tm *tm = localtime (&table->date);
1539       printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
1540               tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
1541               tm->tm_sec);
1542     }
1543
1544   indent (indentation);
1545   printf ("sizing:\n");
1546   pivot_table_sizing_dump ("column", table->look->width_ranges[TABLE_HORZ],
1547                            &table->sizing[TABLE_HORZ], indentation + 1);
1548   pivot_table_sizing_dump ("row", table->look->width_ranges[TABLE_VERT],
1549                            &table->sizing[TABLE_VERT], indentation + 1);
1550
1551   indent (indentation);
1552   printf ("areas:\n");
1553   for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1554     table_area_style_dump (area, &table->look->areas[area], indentation + 1);
1555
1556   indent (indentation);
1557   printf ("borders:\n");
1558   for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1559     table_border_style_dump (border, &table->look->borders[border],
1560                              indentation + 1);
1561
1562   for (size_t i = 0; i < table->n_dimensions; i++)
1563     pivot_dimension_dump (table->dimensions[i], indentation);
1564
1565   /* Presentation and data indexes. */
1566   size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
1567
1568   const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1569   if (layer_axis->n_dimensions)
1570     {
1571       indent (indentation);
1572       printf ("current layer:");
1573
1574       for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1575         {
1576           const struct pivot_dimension *d = layer_axis->dimensions[i];
1577           char *name = pivot_value_to_string (d->root->name,
1578                                               table->show_values,
1579                                               table->show_variables);
1580           char *value = pivot_value_to_string (
1581             d->data_leaves[table->current_layer[i]]->name,
1582             table->show_values, table->show_variables);
1583           printf (" %s=%s", name, value);
1584           free (value);
1585           free (name);
1586         }
1587
1588       putchar ('\n');
1589     }
1590
1591   size_t *layer_indexes;
1592   size_t layer_iteration = 0;
1593   PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1594     {
1595       indent (indentation);
1596       printf ("layer %zu:", layer_iteration++);
1597
1598       const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1599       for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1600         {
1601           const struct pivot_dimension *d = layer_axis->dimensions[i];
1602
1603           fputs (i == 0 ? " " : ", ", stdout);
1604           pivot_value_dump (d->root->name);
1605           fputs (" =", stdout);
1606
1607           struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1608                                                  sizeof *names);
1609           size_t n_names = 0;
1610           for (const struct pivot_category *c
1611                  = d->presentation_leaves[layer_indexes[i]];
1612                c;
1613                c = c->parent)
1614             {
1615               if (pivot_category_is_leaf (c) || c->show_label)
1616                 names[n_names++] = c->name;
1617             }
1618
1619           for (size_t i = n_names; i-- > 0;)
1620             {
1621               putchar (' ');
1622               pivot_value_dump (names[i]);
1623             }
1624           free (names);
1625         }
1626       putchar ('\n');
1627
1628       size_t *column_enumeration = pivot_table_enumerate_axis (
1629         table, PIVOT_AXIS_COLUMN, layer_indexes, table->look->omit_empty, NULL);
1630       size_t *row_enumeration = pivot_table_enumerate_axis (
1631         table, PIVOT_AXIS_ROW, layer_indexes, table->look->omit_empty, NULL);
1632
1633       char ***column_headings = compose_headings (
1634         &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1635         table->show_values, table->show_variables);
1636       for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1637         {
1638           indent (indentation + 1);
1639           for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1640             {
1641               if (x)
1642                 fputs ("; ", stdout);
1643               if (column_headings[y][x])
1644                 fputs (column_headings[y][x], stdout);
1645             }
1646           putchar ('\n');
1647         }
1648       free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1649
1650       indent (indentation + 1);
1651       printf ("-----------------------------------------------\n");
1652
1653       char ***row_headings = compose_headings (
1654         &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1655         table->show_values, table->show_variables);
1656
1657       size_t x = 0;
1658       const size_t *pindexes[PIVOT_N_AXES]
1659         = { [PIVOT_AXIS_LAYER] = layer_indexes };
1660       PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1661                                   &table->axes[PIVOT_AXIS_ROW])
1662         {
1663           indent (indentation + 1);
1664
1665           size_t i = 0;
1666           for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1667             {
1668               if (i++)
1669                 fputs ("; ", stdout);
1670               if (row_headings[y][x])
1671                 fputs (row_headings[y][x], stdout);
1672             }
1673
1674           printf (" | ");
1675
1676           i = 0;
1677           PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1678                                       column_enumeration,
1679                                       &table->axes[PIVOT_AXIS_COLUMN])
1680             {
1681               if (i++)
1682                 printf ("; ");
1683
1684               pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1685               const struct pivot_value *value = pivot_table_get (
1686                 table, dindexes);
1687               if (value)
1688                 pivot_value_dump (value);
1689             }
1690           printf ("\n");
1691
1692           x++;
1693         }
1694
1695       free (column_enumeration);
1696       free (row_enumeration);
1697       free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1698     }
1699
1700   pivot_table_dump_value (table->caption, "caption", indentation);
1701
1702   for (size_t i = 0; i < table->n_footnotes; i++)
1703     {
1704       const struct pivot_footnote *f = table->footnotes[i];
1705       indent (indentation);
1706       putchar ('[');
1707       if (f->marker)
1708         pivot_value_dump (f->marker);
1709       else
1710         printf ("%zu", f->idx);
1711       putchar (']');
1712       pivot_value_dump (f->content);
1713       putchar ('\n');
1714     }
1715
1716   free (dindexes);
1717   settings_set_decimal_char (old_decimal);
1718 }
1719 \f
1720 static const char *
1721 consume_int (const char *p, size_t *n)
1722 {
1723   *n = 0;
1724   while (c_isdigit (*p))
1725     *n = *n * 10 + (*p++ - '0');
1726   return p;
1727 }
1728
1729 static size_t
1730 pivot_format_inner_template (struct string *out, const char *template,
1731                              char escape,
1732                              struct pivot_value **values, size_t n_values,
1733                              enum settings_value_show show_values,
1734                              enum settings_value_show show_variables)
1735 {
1736   size_t args_consumed = 0;
1737   while (*template && *template != ':')
1738     {
1739       if (*template == '\\' && template[1])
1740         {
1741           ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1742           template += 2;
1743         }
1744       else if (*template == escape)
1745         {
1746           size_t index;
1747           template = consume_int (template + 1, &index);
1748           if (index >= 1 && index <= n_values)
1749             {
1750               pivot_value_format (values[index - 1], show_values,
1751                                   show_variables, out);
1752               args_consumed = MAX (args_consumed, index);
1753             }
1754         }
1755       else
1756         ds_put_byte (out, *template++);
1757     }
1758   return args_consumed;
1759 }
1760
1761 static const char *
1762 pivot_extract_inner_template (const char *template, const char **p)
1763 {
1764   *p = template;
1765
1766   for (;;)
1767     {
1768       if (*template == '\\' && template[1] != '\0')
1769         template += 2;
1770       else if (*template == ':')
1771         return template + 1;
1772       else if (*template == '\0')
1773         return template;
1774       else
1775         template++;
1776     }
1777 }
1778
1779 static void
1780 pivot_format_template (struct string *out, const char *template,
1781                        const struct pivot_argument *args, size_t n_args,
1782                        enum settings_value_show show_values,
1783                        enum settings_value_show show_variables)
1784 {
1785   while (*template)
1786     {
1787       if (*template == '\\' && template[1] != '\0')
1788         {
1789           ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1790           template += 2;
1791         }
1792       else if (*template == '^')
1793         {
1794           size_t index;
1795           template = consume_int (template + 1, &index);
1796           if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1797             pivot_value_format (args[index - 1].values[0],
1798                                 show_values, show_variables, out);
1799         }
1800       else if (*template == '[')
1801         {
1802           const char *tmpl[2];
1803           template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1804           template = pivot_extract_inner_template (template, &tmpl[1]);
1805           template += *template == ']';
1806
1807           size_t index;
1808           template = consume_int (template, &index);
1809           if (index < 1 || index > n_args)
1810             continue;
1811
1812           const struct pivot_argument *arg = &args[index - 1];
1813           size_t left = arg->n;
1814           while (left)
1815             {
1816               struct pivot_value **values = arg->values + (arg->n - left);
1817               int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1818               char escape = "%^"[tmpl_idx];
1819               size_t used = pivot_format_inner_template (
1820                 out, tmpl[tmpl_idx], escape, values, left,
1821                 show_values, show_variables);
1822               if (!used || used > left)
1823                 break;
1824               left -= used;
1825             }
1826         }
1827       else
1828         ds_put_byte (out, *template++);
1829     }
1830 }
1831
1832 static enum settings_value_show
1833 interpret_show (enum settings_value_show global_show,
1834                 enum settings_value_show table_show,
1835                 enum settings_value_show value_show,
1836                 bool has_label)
1837 {
1838   return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1839           : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1840           : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1841           : global_show);
1842 }
1843
1844 /* Appends a text representation of the body of VALUE to OUT.  SHOW_VALUES and
1845    SHOW_VARIABLES control whether variable and value labels are included.
1846
1847    The "body" omits subscripts and superscripts and footnotes. */
1848 bool
1849 pivot_value_format_body (const struct pivot_value *value,
1850                          enum settings_value_show show_values,
1851                          enum settings_value_show show_variables,
1852                          struct string *out)
1853 {
1854   enum settings_value_show show;
1855   bool numeric = false;
1856
1857   switch (value->type)
1858     {
1859     case PIVOT_VALUE_NUMERIC:
1860       show = interpret_show (settings_get_show_values (),
1861                              show_values,
1862                              value->numeric.show,
1863                              value->numeric.value_label != NULL);
1864       if (show & SETTINGS_VALUE_SHOW_VALUE)
1865         {
1866           char *s = data_out (&(union value) { .f = value->numeric.x },
1867                               "UTF-8", &value->numeric.format);
1868           ds_put_cstr (out, s + strspn (s, " "));
1869           free (s);
1870         }
1871       if (show & SETTINGS_VALUE_SHOW_LABEL)
1872         {
1873           if (show & SETTINGS_VALUE_SHOW_VALUE)
1874             ds_put_byte (out, ' ');
1875           ds_put_cstr (out, value->numeric.value_label);
1876         }
1877       numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1878       break;
1879
1880     case PIVOT_VALUE_STRING:
1881       show = interpret_show (settings_get_show_values (),
1882                              show_values,
1883                              value->string.show,
1884                              value->string.value_label != NULL);
1885       if (show & SETTINGS_VALUE_SHOW_VALUE)
1886         {
1887           if (value->string.hex)
1888             {
1889               for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1890                    *p; p++)
1891                 ds_put_format (out, "%02X", *p);
1892             }
1893           else
1894             ds_put_cstr (out, value->string.s);
1895         }
1896       if (show & SETTINGS_VALUE_SHOW_LABEL)
1897         {
1898           if (show & SETTINGS_VALUE_SHOW_VALUE)
1899             ds_put_byte (out, ' ');
1900           ds_put_cstr (out, value->string.value_label);
1901         }
1902       break;
1903
1904     case PIVOT_VALUE_VARIABLE:
1905       show = interpret_show (settings_get_show_variables (),
1906                              show_variables,
1907                              value->variable.show,
1908                              value->variable.var_label != NULL);
1909       if (show & SETTINGS_VALUE_SHOW_VALUE)
1910         ds_put_cstr (out, value->variable.var_name);
1911       if (show & SETTINGS_VALUE_SHOW_LABEL)
1912         {
1913           if (show & SETTINGS_VALUE_SHOW_VALUE)
1914             ds_put_byte (out, ' ');
1915           ds_put_cstr (out, value->variable.var_label);
1916         }
1917       break;
1918
1919     case PIVOT_VALUE_TEXT:
1920       ds_put_cstr (out, value->text.local);
1921       break;
1922
1923     case PIVOT_VALUE_TEMPLATE:
1924       pivot_format_template (out, value->template.local, value->template.args,
1925                              value->template.n_args, show_values,
1926                              show_variables);
1927       break;
1928     }
1929
1930   return numeric;
1931 }
1932
1933 /* Appends a text representation of VALUE to OUT.  SHOW_VALUES and
1934    SHOW_VARIABLES control whether variable and value labels are included.
1935
1936    Subscripts and superscripts and footnotes are included. */
1937 void
1938 pivot_value_format (const struct pivot_value *value,
1939                     enum settings_value_show show_values,
1940                     enum settings_value_show show_variables,
1941                     struct string *out)
1942 {
1943   pivot_value_format_body (value, show_values, show_variables, out);
1944
1945   if (value->n_subscripts)
1946     {
1947       for (size_t i = 0; i < value->n_subscripts; i++)
1948         ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
1949     }
1950
1951   if (value->superscript)
1952     ds_put_format (out, "^%s", value->superscript);
1953
1954   for (size_t i = 0; i < value->n_footnotes; i++)
1955     {
1956       ds_put_byte (out, '^');
1957       pivot_value_format (value->footnotes[i]->marker,
1958                           show_values, show_variables, out);
1959     }
1960 }
1961
1962 /* Returns a text representation of VALUE.  The caller must free the string,
1963    with free(). */
1964 char *
1965 pivot_value_to_string (const struct pivot_value *value,
1966                        enum settings_value_show show_values,
1967                        enum settings_value_show show_variables)
1968 {
1969   struct string s = DS_EMPTY_INITIALIZER;
1970   pivot_value_format (value, show_values, show_variables, &s);
1971   return ds_steal_cstr (&s);
1972 }
1973
1974 /* Frees the data owned by V. */
1975 void
1976 pivot_value_destroy (struct pivot_value *value)
1977 {
1978   if (value)
1979     {
1980       font_style_uninit (value->font_style);
1981       free (value->font_style);
1982       free (value->cell_style);
1983       /* Do not free the elements of footnotes because VALUE does not own
1984          them. */
1985       free (value->footnotes);
1986
1987       for (size_t i = 0; i < value->n_subscripts; i++)
1988         free (value->subscripts[i]);
1989       free (value->subscripts);
1990
1991       free (value->superscript);
1992
1993       switch (value->type)
1994         {
1995         case PIVOT_VALUE_NUMERIC:
1996           free (value->numeric.var_name);
1997           free (value->numeric.value_label);
1998           break;
1999
2000         case PIVOT_VALUE_STRING:
2001           free (value->string.s);
2002           free (value->string.var_name);
2003           free (value->string.value_label);
2004           break;
2005
2006         case PIVOT_VALUE_VARIABLE:
2007           free (value->variable.var_name);
2008           free (value->variable.var_label);
2009           break;
2010
2011         case PIVOT_VALUE_TEXT:
2012           free (value->text.local);
2013           if (value->text.c != value->text.local)
2014             free (value->text.c);
2015           if (value->text.id != value->text.local
2016               && value->text.id != value->text.c)
2017             free (value->text.id);
2018           break;
2019
2020         case PIVOT_VALUE_TEMPLATE:
2021           free (value->template.local);
2022           if (value->template.id != value->template.local)
2023             free (value->template.id);
2024           for (size_t i = 0; i < value->template.n_args; i++)
2025             pivot_argument_uninit (&value->template.args[i]);
2026           free (value->template.args);
2027           break;
2028         }
2029       free (value);
2030     }
2031 }
2032
2033 /* Sets AREA to the style to use for VALUE, with defaults coming from
2034    DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
2035 void
2036 pivot_value_get_style (struct pivot_value *value,
2037                        const struct font_style *base_font_style,
2038                        const struct cell_style *base_cell_style,
2039                        struct table_area_style *area)
2040 {
2041   font_style_copy (NULL, &area->font_style, (value->font_style
2042                                              ? value->font_style
2043                                              : base_font_style));
2044   area->cell_style = *(value->cell_style
2045                        ? value->cell_style
2046                        : base_cell_style);
2047 }
2048
2049 /* Copies AREA into VALUE's style. */
2050 void
2051 pivot_value_set_style (struct pivot_value *value,
2052                        const struct table_area_style *area)
2053 {
2054   if (value->font_style)
2055     font_style_uninit (value->font_style);
2056   else
2057     value->font_style = xmalloc (sizeof *value->font_style);
2058   font_style_copy (NULL, value->font_style, &area->font_style);
2059
2060   if (!value->cell_style)
2061     value->cell_style = xmalloc (sizeof *value->cell_style);
2062   *value->cell_style = area->cell_style;
2063 }
2064
2065 /* Frees the data owned by ARG (but not ARG itself). */
2066 void
2067 pivot_argument_uninit (struct pivot_argument *arg)
2068 {
2069   if (arg)
2070     {
2071       for (size_t i = 0; i < arg->n; i++)
2072         pivot_value_destroy (arg->values[i]);
2073       free (arg->values);
2074     }
2075 }
2076
2077 /* Creates and returns a new pivot_value whose contents is the null-terminated
2078    string TEXT.  Takes ownership of TEXT.
2079
2080    This function is for text strings provided by the user (with the exception
2081    that pivot_value_new_variable() should be used for variable names).  For
2082    strings that are part of the PSPP user interface, such as names of
2083    procedures, statistics, annotations, error messages, etc., use
2084    pivot_value_new_text(). */
2085 struct pivot_value *
2086 pivot_value_new_user_text_nocopy (char *text)
2087 {
2088   struct pivot_value *value = xmalloc (sizeof *value);
2089   *value = (struct pivot_value) {
2090     .type = PIVOT_VALUE_TEXT,
2091     .text = {
2092       .local = text,
2093       .c = text,
2094       .id = text,
2095       .user_provided = true,
2096     }
2097   };
2098   return value;
2099 }
2100
2101 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2102    TEXT.  Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2103    in advance.
2104
2105    This function is for text strings provided by the user (with the exception
2106    that pivot_value_new_variable() should be used for variable names).  For
2107    strings that are part of the PSPP user interface, such as names of
2108    procedures, statistics, annotations, error messages, etc., use
2109    pivot_value_new_text().j
2110
2111    The caller retains ownership of TEXT.*/
2112 struct pivot_value *
2113 pivot_value_new_user_text (const char *text, size_t length)
2114 {
2115   return pivot_value_new_user_text_nocopy (
2116     xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2117 }
2118
2119 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2120    a translatable string, but not actually translated yet, e.g. enclosed in
2121    N_().  This function is for text strings that are part of the PSPP user
2122    interface, such as names of procedures, statistics, annotations, error
2123    messages, etc.  For strings that come from the user, use
2124    pivot_value_new_user_text(). */
2125 struct pivot_value *
2126 pivot_value_new_text (const char *text)
2127 {
2128   char *c = xstrdup (text);
2129   char *local = xstrdup (gettext (c));
2130
2131   struct pivot_value *value = xmalloc (sizeof *value);
2132   *value = (struct pivot_value) {
2133     .type = PIVOT_VALUE_TEXT,
2134     .text = {
2135       .local = local,
2136       .c = c,
2137       .id = c,
2138       .user_provided = false,
2139     }
2140   };
2141   return value;
2142 }
2143
2144 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2145    string. */
2146 struct pivot_value * PRINTF_FORMAT (1, 2)
2147 pivot_value_new_text_format (const char *format, ...)
2148 {
2149   va_list args;
2150   va_start (args, format);
2151   char *c = xvasprintf (format, args);
2152   va_end (args);
2153
2154   va_start (args, format);
2155   char *local = xvasprintf (gettext (format), args);
2156   va_end (args);
2157
2158   struct pivot_value *value = xmalloc (sizeof *value);
2159   *value = (struct pivot_value) {
2160     .type = PIVOT_VALUE_TEXT,
2161     .text = {
2162       .local = local,
2163       .c = c,
2164       .id = xstrdup (c),
2165       .user_provided = false,
2166     }
2167   };
2168   return value;
2169 }
2170
2171 /* Returns a new pivot_value that represents X.
2172
2173    The format to use for X is unspecified.  Usually the easiest way to specify
2174    a format is through assigning a result class to one of the categories that
2175    the pivot_value will end up in.  If that is not suitable, then the caller
2176    can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2177 struct pivot_value *
2178 pivot_value_new_number (double x)
2179 {
2180   struct pivot_value *value = xmalloc (sizeof *value);
2181   *value = (struct pivot_value) {
2182     .type = PIVOT_VALUE_NUMERIC,
2183     .numeric = { .x = x, },
2184   };
2185   return value;
2186 }
2187
2188 /* Returns a new pivot_value that represents X, formatted as an integer. */
2189 struct pivot_value *
2190 pivot_value_new_integer (double x)
2191 {
2192   struct pivot_value *value = pivot_value_new_number (x);
2193   value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2194   return value;
2195 }
2196
2197 /* Returns a new pivot_value that represents VALUE, formatted as for
2198    VARIABLE. */
2199 struct pivot_value *
2200 pivot_value_new_var_value (const struct variable *variable,
2201                            const union value *value)
2202 {
2203   struct pivot_value *pv = pivot_value_new_value (
2204     value, var_get_width (variable), var_get_print_format (variable),
2205     var_get_encoding (variable));
2206
2207   char *var_name = xstrdup (var_get_name (variable));
2208   if (var_is_alpha (variable))
2209     pv->string.var_name = var_name;
2210   else
2211     pv->numeric.var_name = var_name;
2212
2213   const char *label = var_lookup_value_label (variable, value);
2214   if (label)
2215     {
2216       if (var_is_alpha (variable))
2217         pv->string.value_label = xstrdup (label);
2218       else
2219         pv->numeric.value_label = xstrdup (label);
2220     }
2221
2222   return pv;
2223 }
2224
2225 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2226    formatted with FORMAT.  For a string value, ENCODING must be its character
2227    encoding. */
2228 struct pivot_value *
2229 pivot_value_new_value (const union value *value, int width,
2230                        const struct fmt_spec *format, const char *encoding)
2231 {
2232   struct pivot_value *pv = xzalloc (sizeof *pv);
2233   if (width > 0)
2234     {
2235       char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2236                                width);
2237       size_t n = strlen (s);
2238       while (n > 0 && s[n - 1] == ' ')
2239         s[--n] = '\0';
2240
2241       pv->type = PIVOT_VALUE_STRING;
2242       pv->string.s = s;
2243       pv->string.hex = format->type == FMT_AHEX;
2244     }
2245   else
2246     {
2247       pv->type = PIVOT_VALUE_NUMERIC;
2248       pv->numeric.x = value->f;
2249       pv->numeric.format = *format;
2250     }
2251
2252   return pv;
2253 }
2254
2255 /* Returns a new pivot_value for VARIABLE. */
2256 struct pivot_value *
2257 pivot_value_new_variable (const struct variable *variable)
2258 {
2259   struct pivot_value *value = xmalloc (sizeof *value);
2260   *value = (struct pivot_value) {
2261     .type = PIVOT_VALUE_VARIABLE,
2262     .variable = {
2263       .var_name = xstrdup (var_get_name (variable)),
2264       .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2265     },
2266   };
2267   return value;
2268 }
2269
2270 /* Attaches a reference to FOOTNOTE to V. */
2271 void
2272 pivot_value_add_footnote (struct pivot_value *v,
2273                           const struct pivot_footnote *footnote)
2274 {
2275   /* Some legacy tables include numerous duplicate footnotes.  Suppress
2276      them. */
2277   for (size_t i = 0; i < v->n_footnotes; i++)
2278     if (v->footnotes[i] == footnote)
2279       return;
2280
2281   v->footnotes = xrealloc (v->footnotes,
2282                            (v->n_footnotes + 1) * sizeof *v->footnotes);
2283   v->footnotes[v->n_footnotes++] = footnote;
2284 }
2285
2286 /* If VALUE is a numeric value, and RC is a result class such as
2287    PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2288 void
2289 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2290                     const char *rc)
2291 {
2292   if (value->type == PIVOT_VALUE_NUMERIC)
2293     {
2294       const struct fmt_spec *f = pivot_table_get_format (table, rc);
2295       if (f)
2296         value->numeric.format = *f;
2297     }
2298 }
2299