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