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