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