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