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