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