table: Add pool parameter to area_style_copy(), font_style_copy().
[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 void
66 pivot_area_get_default_style (enum pivot_area area, struct area_style *style)
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     },                                                          \
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   *style = default_area_styles[area];
95   style->font_style.typeface = xstrdup ("SansSerif");
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->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
705   table->title = title;
706   table->subtype = pivot_value_new_text (subtype);
707
708   const char *command_id = output_get_command_name ();
709   table->command_c = command_id ? xstrdup (command_id) : NULL;
710
711   table->sizing[TABLE_HORZ].range[0] = 50;
712   table->sizing[TABLE_HORZ].range[1] = 72;
713   table->sizing[TABLE_VERT].range[0] = 36;
714   table->sizing[TABLE_VERT].range[1] = 120;
715
716   for (size_t i = 0; i < PIVOT_N_AREAS; i++)
717     pivot_area_get_default_style (i, &table->areas[i]);
718
719   /* Set default border styles. */
720   static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
721     [PIVOT_BORDER_TITLE]        = TABLE_STROKE_NONE,
722     [PIVOT_BORDER_OUTER_LEFT]   = TABLE_STROKE_NONE,
723     [PIVOT_BORDER_OUTER_TOP]    = TABLE_STROKE_NONE,
724     [PIVOT_BORDER_OUTER_RIGHT]  = TABLE_STROKE_NONE,
725     [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
726     [PIVOT_BORDER_INNER_LEFT]   = TABLE_STROKE_THICK,
727     [PIVOT_BORDER_INNER_TOP]    = TABLE_STROKE_THICK,
728     [PIVOT_BORDER_INNER_RIGHT]  = TABLE_STROKE_THICK,
729     [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
730     [PIVOT_BORDER_DATA_LEFT]    = TABLE_STROKE_THICK,
731     [PIVOT_BORDER_DATA_TOP]     = TABLE_STROKE_THICK,
732     [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
733     [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
734     [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
735     [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
736     [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
737     [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
738     [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
739     [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
740   };
741   for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
742     table->borders[i] = (struct table_border_style) {
743       .stroke = default_strokes[i],
744       .color = CELL_COLOR_BLACK,
745     };
746
747   table->row_labels_in_corner = true;
748   hmap_init (&table->cells);
749
750   return table;
751 }
752
753 /* Creates and returns a new pivot table with the given TITLE and a single cell
754    with the given CONTENT.
755
756    This is really just for error handling. */
757 struct pivot_table *
758 pivot_table_create_for_text (struct pivot_value *title,
759                              struct pivot_value *content)
760 {
761   struct pivot_table *table = pivot_table_create__ (title, "Error");
762
763   struct pivot_dimension *d = pivot_dimension_create (
764     table, PIVOT_AXIS_ROW, N_("Error"));
765   d->hide_all_labels = true;
766   pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
767
768   pivot_table_put1 (table, 0, content);
769
770   return table;
771 }
772
773 /* Increases TABLE's reference count, indicating that it has an additional
774    owner.  A pivot table that is shared among multiple owners must not be
775    modified. */
776 struct pivot_table *
777 pivot_table_ref (const struct pivot_table *table_)
778 {
779   struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
780   table->ref_cnt++;
781   return table;
782 }
783
784 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
785    If TABLE no longer has any owners, it is freed. */
786 void
787 pivot_table_unref (struct pivot_table *table)
788 {
789   if (!table)
790     return;
791   assert (table->ref_cnt > 0);
792   if (--table->ref_cnt)
793     return;
794
795   free (table->current_layer);
796   free (table->table_look);
797
798   for (int i = 0; i < TABLE_N_AXES; i++)
799     pivot_table_sizing_uninit (&table->sizing[i]);
800
801   free (table->continuation);
802
803   for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
804     free (table->ccs[i]);
805
806   free (table->command_local);
807   free (table->command_c);
808   free (table->language);
809   free (table->locale);
810
811   free (table->dataset);
812   free (table->datafile);
813
814   for (size_t i = 0; i < table->n_footnotes; i++)
815     pivot_footnote_destroy (table->footnotes[i]);
816   free (table->footnotes);
817
818   pivot_value_destroy (table->title);
819   pivot_value_destroy (table->subtype);
820   pivot_value_destroy (table->corner_text);
821   pivot_value_destroy (table->caption);
822
823   for (size_t i = 0; i < PIVOT_N_AREAS; i++)
824     area_style_uninit (&table->areas[i]);
825
826   for (size_t i = 0; i < table->n_dimensions; i++)
827     pivot_dimension_destroy (table->dimensions[i]);
828   free (table->dimensions);
829
830   for (size_t i = 0; i < PIVOT_N_AXES; i++)
831     free (table->axes[i].dimensions);
832
833   struct pivot_cell *cell, *next_cell;
834   HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
835                       &table->cells)
836     {
837       hmap_delete (&table->cells, &cell->hmap_node);
838       pivot_value_destroy (cell->value);
839       free (cell);
840     }
841   hmap_destroy (&table->cells);
842
843   free (table);
844 }
845
846 /* Returns true if TABLE has more than one owner.  A pivot table that is shared
847    among multiple owners must not be modified. */
848 bool
849 pivot_table_is_shared (const struct pivot_table *table)
850 {
851   return table->ref_cnt > 1;
852 }
853
854 /* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
855    WV, which should be the weight variable for the dictionary whose data or
856    statistics are being put into TABLE.
857
858    This has no effect if WV is NULL. */
859 void
860 pivot_table_set_weight_var (struct pivot_table *table,
861                             const struct variable *wv)
862 {
863   if (wv)
864     pivot_table_set_weight_format (table, var_get_print_format (wv));
865 }
866
867 /* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
868    format for the dictionary whose data or statistics are being put into TABLE.
869
870    This has no effect if WFMT is NULL. */
871 void
872 pivot_table_set_weight_format (struct pivot_table *table,
873                                const struct fmt_spec *wfmt)
874 {
875   if (wfmt)
876     table->weight_format = *wfmt;
877 }
878
879 /* Returns true if TABLE has no cells, false otherwise. */
880 bool
881 pivot_table_is_empty (const struct pivot_table *table)
882 {
883   return hmap_is_empty (&table->cells);
884 }
885
886 static unsigned int
887 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
888 {
889   return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
890 }
891
892 static bool
893 equal_indexes (const size_t *a, const unsigned int *b, size_t n)
894 {
895   for (size_t i = 0; i < n; i++)
896     if (a[i] != b[i])
897       return false;
898
899   return true;
900 }
901
902 static struct pivot_cell *
903 pivot_table_lookup_cell__ (const struct pivot_table *table,
904                             const size_t *dindexes, unsigned int hash)
905 {
906   struct pivot_cell *cell;
907   HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
908                            &table->cells)
909     if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
910       return cell;
911   return false;
912 }
913
914 static struct pivot_cell *
915 pivot_cell_allocate (size_t n_idx)
916 {
917   struct pivot_cell *cell UNUSED;
918   return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
919 }
920
921 static struct pivot_cell *
922 pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
923 {
924   unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
925   struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
926   if (!cell)
927     {
928       cell = pivot_cell_allocate (table->n_dimensions);
929       for (size_t i = 0; i < table->n_dimensions; i++)
930         cell->idx[i] = dindexes[i];
931       cell->value = NULL;
932       hmap_insert (&table->cells, &cell->hmap_node, hash);
933     }
934   return cell;
935 }
936
937 /* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
938    DINDEXES.  N must be the number of dimensions in TABLE.  Takes ownership of
939    VALUE.
940
941    If VALUE is a numeric value without a specified format, this function checks
942    each of the categories designated by DINDEXES[] and takes the format from
943    the first category with a result class.  If none has a result class, uses
944    the overall default numeric format. */
945 void
946 pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
947                  struct pivot_value *value)
948 {
949   assert (n == table->n_dimensions);
950
951   if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
952     {
953       for (size_t i = 0; i < table->n_dimensions; i++)
954         {
955           const struct pivot_dimension *d = table->dimensions[i];
956           if (dindexes[i] < d->n_leaves)
957             {
958               const struct pivot_category *c = d->data_leaves[dindexes[i]];
959               if (c->format.w)
960                 {
961                   value->numeric.format = c->format;
962                   goto done;
963                 }
964             }
965         }
966       value->numeric.format = *settings_get_format ();
967
968     done:;
969     }
970
971   struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
972   pivot_value_destroy (cell->value);
973   cell->value = value;
974 }
975
976 /* Puts VALUE in the cell in TABLE with index IDX1.  TABLE must have 1
977    dimension.  Takes ownership of VALUE.  */
978 void
979 pivot_table_put1 (struct pivot_table *table, size_t idx1,
980                   struct pivot_value *value)
981 {
982   size_t dindexes[] = { idx1 };
983   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
984 }
985
986 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2).  TABLE must have 2
987    dimensions.  Takes ownership of VALUE.  */
988 void
989 pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
990                   struct pivot_value *value)
991 {
992   size_t dindexes[] = { idx1, idx2 };
993   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
994 }
995
996 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3).  TABLE must
997    have 3 dimensions.  Takes ownership of VALUE.  */
998 void
999 pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
1000                   size_t idx3, struct pivot_value *value)
1001 {
1002   size_t dindexes[] = { idx1, idx2, idx3 };
1003   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1004 }
1005
1006 /* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4).  TABLE
1007    must have 4 dimensions.  Takes ownership of VALUE.  */
1008 void
1009 pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
1010                   size_t idx3, size_t idx4, struct pivot_value *value)
1011 {
1012   size_t dindexes[] = { idx1, idx2, idx3, idx4 };
1013   pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
1014 }
1015
1016 /* Creates and returns a new footnote in TABLE with the given CONTENT and an
1017    automatically assigned marker.
1018
1019    The footnote will only appear in output if it is referenced.  Use
1020    pivot_value_add_footnote() to add a reference to the footnote. */
1021 struct pivot_footnote *
1022 pivot_table_create_footnote (struct pivot_table *table,
1023                              struct pivot_value *content)
1024 {
1025   return pivot_table_create_footnote__ (table, table->n_footnotes,
1026                                         NULL, content);
1027 }
1028
1029 static struct pivot_value *
1030 pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
1031 {
1032   char text[INT_BUFSIZE_BOUND (size_t)];
1033   if (show_numeric_markers)
1034     snprintf (text, sizeof text, "%d", idx + 1);
1035   else
1036     str_format_26adic (idx + 1, false, text, sizeof text);
1037   return pivot_value_new_user_text (text, -1);
1038 }
1039
1040 /* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
1041    all lower indexes as a side effect).  If MARKER is nonnull, sets the
1042    footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
1043 struct pivot_footnote *
1044 pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
1045                                struct pivot_value *marker,
1046                                struct pivot_value *content)
1047 {
1048   if (idx >= table->n_footnotes)
1049     {
1050       while (idx >= table->allocated_footnotes)
1051         table->footnotes = x2nrealloc (table->footnotes,
1052                                        &table->allocated_footnotes,
1053                                        sizeof *table->footnotes);
1054       while (idx >= table->n_footnotes)
1055         {
1056           struct pivot_footnote *f = xmalloc (sizeof *f);
1057           f->idx = table->n_footnotes;
1058           f->marker = pivot_make_default_footnote_marker (
1059             f->idx, table->show_numeric_markers);
1060           f->content = NULL;
1061
1062           table->footnotes[table->n_footnotes++] = f;
1063         }
1064     }
1065
1066   struct pivot_footnote *f = table->footnotes[idx];
1067   if (marker)
1068     {
1069       pivot_value_destroy (f->marker);
1070       f->marker = marker;
1071     }
1072   if (content)
1073     {
1074       pivot_value_destroy (f->content);
1075       f->content = content;
1076     }
1077   return f;
1078 }
1079
1080 /* Frees the data owned by F. */
1081 void
1082 pivot_footnote_destroy (struct pivot_footnote *f)
1083 {
1084   if (f)
1085     {
1086       pivot_value_destroy (f->content);
1087       pivot_value_destroy (f->marker);
1088       free (f);
1089     }
1090 }
1091
1092 /* Converts per-axis presentation-order indexes, given in PINDEXES, into data
1093    indexes for each dimension in TABLE in DINDEXES[]. */
1094 void
1095 pivot_table_convert_indexes_ptod (const struct pivot_table *table,
1096                                   const size_t *pindexes[PIVOT_N_AXES],
1097                                   size_t dindexes[/* table->n_dimensions */])
1098 {
1099   for (size_t i = 0; i < PIVOT_N_AXES; i++)
1100     {
1101       const struct pivot_axis *axis = &table->axes[i];
1102
1103       for (size_t j = 0; j < axis->n_dimensions; j++)
1104         {
1105           const struct pivot_dimension *d = axis->dimensions[j];
1106           dindexes[d->top_index]
1107             = d->presentation_leaves[pindexes[i][j]]->data_index;
1108         }
1109     }
1110 }
1111
1112 size_t *
1113 pivot_table_enumerate_axis (const struct pivot_table *table,
1114                             enum pivot_axis_type axis_type,
1115                             const size_t *layer_indexes, bool omit_empty,
1116                             size_t *n)
1117 {
1118   const struct pivot_axis *axis = &table->axes[axis_type];
1119   if (!axis->n_dimensions)
1120     {
1121       size_t *enumeration = xnmalloc (2, sizeof *enumeration);
1122       enumeration[0] = 0;
1123       enumeration[1] = SIZE_MAX;
1124       if (n)
1125         *n = 1;
1126       return enumeration;
1127     }
1128   else if (!axis->extent)
1129     {
1130       size_t *enumeration = xmalloc (sizeof *enumeration);
1131       *enumeration = SIZE_MAX;
1132       if (n)
1133         *n = 0;
1134       return enumeration;
1135     }
1136
1137   size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
1138                                                 axis->n_dimensions), 1),
1139                                   sizeof *enumeration);
1140   size_t *p = enumeration;
1141   size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1142
1143   size_t *axis_indexes;
1144   PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
1145     {
1146       if (omit_empty)
1147         {
1148           enum pivot_axis_type axis2_type
1149             = pivot_axis_type_transpose (axis_type);
1150
1151           size_t *axis2_indexes;
1152           PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
1153             {
1154               const size_t *pindexes[PIVOT_N_AXES];
1155               pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
1156               pindexes[axis_type] = axis_indexes;
1157               pindexes[axis2_type] = axis2_indexes;
1158               pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1159               if (pivot_table_get (table, dindexes))
1160                 goto found;
1161             }
1162           continue;
1163
1164         found:
1165           free (axis2_indexes);
1166         }
1167
1168       memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
1169       p += axis->n_dimensions;
1170     }
1171   *p = SIZE_MAX;
1172   if (n)
1173     *n = (p - enumeration) / axis->n_dimensions;
1174
1175   free (dindexes);
1176   return enumeration;
1177 }
1178
1179 static const struct pivot_cell *
1180 pivot_table_lookup_cell (const struct pivot_table *table,
1181                           const size_t *dindexes)
1182 {
1183   unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
1184   return pivot_table_lookup_cell__ (table, dindexes, hash);
1185 }
1186
1187 const struct pivot_value *
1188 pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
1189 {
1190   const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
1191   return cell ? cell->value : NULL;
1192 }
1193
1194 struct pivot_value *
1195 pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
1196 {
1197   struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
1198   if (!cell->value)
1199     cell->value = pivot_value_new_user_text ("", -1);
1200   return cell->value;
1201 }
1202
1203 static void
1204 distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
1205 {
1206   if (pivot_category_is_group (category) && category->n_subs)
1207     for (size_t i = 0; i < category->n_subs; i++)
1208       distribute_extra_depth (category->subs[i], extra_depth);
1209   else
1210     category->extra_depth += extra_depth;
1211 }
1212
1213 static void
1214 pivot_category_assign_label_depth (struct pivot_category *category,
1215                                    bool dimension_labels_in_corner)
1216 {
1217   category->extra_depth = 0;
1218
1219   if (pivot_category_is_group (category))
1220     {
1221       size_t depth = 0;
1222       for (size_t i = 0; i < category->n_subs; i++)
1223         {
1224           pivot_category_assign_label_depth (category->subs[i], false);
1225           depth = MAX (depth, category->subs[i]->label_depth);
1226         }
1227
1228       for (size_t i = 0; i < category->n_subs; i++)
1229         {
1230           struct pivot_category *sub = category->subs[i];
1231
1232           size_t extra_depth = depth - sub->label_depth;
1233           if (extra_depth)
1234             distribute_extra_depth (sub, extra_depth);
1235
1236           sub->label_depth = depth;
1237         }
1238
1239       category->show_label_in_corner = (category->show_label
1240                                         && dimension_labels_in_corner);
1241       category->label_depth
1242         = (category->show_label && !category->show_label_in_corner
1243            ? depth + 1 : depth);
1244     }
1245   else
1246     category->label_depth = 1;
1247 }
1248
1249 static bool
1250 pivot_axis_assign_label_depth (struct pivot_table *table,
1251                              enum pivot_axis_type axis_type,
1252                              bool dimension_labels_in_corner)
1253 {
1254   struct pivot_axis *axis = &table->axes[axis_type];
1255   bool any_label_shown_in_corner = false;
1256   axis->label_depth = 0;
1257   axis->extent = 1;
1258   for (size_t i = 0; i < axis->n_dimensions; i++)
1259     {
1260       struct pivot_dimension *d = axis->dimensions[i];
1261       pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
1262       d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
1263       axis->label_depth += d->label_depth;
1264       axis->extent *= d->n_leaves;
1265
1266       if (d->root->show_label_in_corner)
1267         any_label_shown_in_corner = true;
1268     }
1269   return any_label_shown_in_corner;
1270 }
1271
1272 void
1273 pivot_table_assign_label_depth (struct pivot_table *table)
1274 {
1275   pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
1276   if (pivot_axis_assign_label_depth (
1277         table, PIVOT_AXIS_ROW, (table->row_labels_in_corner
1278                                 && !table->corner_text))
1279       && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
1280     table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
1281   pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
1282 }
1283 \f
1284 /* Footnotes. */
1285
1286 \f
1287 \f
1288 static void
1289 indent (int indentation)
1290 {
1291   for (int i = 0; i < indentation * 2; i++)
1292     putchar (' ');
1293 }
1294
1295 static void
1296 pivot_value_dump (const struct pivot_value *value)
1297 {
1298   char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
1299                                    SETTINGS_VALUE_SHOW_DEFAULT);
1300   fputs (s, stdout);
1301   free (s);
1302 }
1303
1304 static void
1305 pivot_table_dump_value (const struct pivot_value *value, const char *name,
1306                       int indentation)
1307 {
1308   if (value)
1309     {
1310       indent (indentation);
1311       printf ("%s: ", name);
1312       pivot_value_dump (value);
1313       putchar ('\n');
1314     }
1315 }
1316
1317 static void
1318 pivot_table_dump_string (const char *string, const char *name, int indentation)
1319 {
1320   if (string)
1321     {
1322       indent (indentation);
1323       printf ("%s: %s\n", name, string);
1324     }
1325 }
1326
1327 static void
1328 pivot_category_dump (const struct pivot_category *c, int indentation)
1329 {
1330   indent (indentation);
1331   printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
1332   pivot_value_dump (c->name);
1333   printf ("\" ");
1334
1335   if (pivot_category_is_leaf (c))
1336     printf ("data_index=%zu\n", c->data_index);
1337   else
1338     {
1339       printf (" (label %s)", c->show_label ? "shown" : "hidden");
1340       printf ("\n");
1341
1342       for (size_t i = 0; i < c->n_subs; i++)
1343         pivot_category_dump (c->subs[i], indentation + 1);
1344     }
1345 }
1346
1347 void
1348 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
1349 {
1350   indent (indentation);
1351   printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
1352           pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
1353
1354   pivot_category_dump (d->root, indentation + 1);
1355 }
1356
1357 static void
1358 area_style_dump (enum pivot_area area, const struct area_style *a,
1359                  int indentation)
1360 {
1361   indent (indentation);
1362   printf ("%s: ", pivot_area_to_string (area));
1363   font_style_dump (&a->font_style);
1364   putchar (' ');
1365   cell_style_dump (&a->cell_style);
1366   putchar ('\n');
1367 }
1368
1369 static void
1370 table_border_style_dump (enum pivot_border border,
1371                          const struct table_border_style *b, int indentation)
1372 {
1373   indent (indentation);
1374   printf ("%s: %s ", pivot_border_to_string (border),
1375           table_stroke_to_string (b->stroke));
1376   cell_color_dump (&b->color);
1377   putchar ('\n');
1378 }
1379
1380 static char ***
1381 compose_headings (const struct pivot_axis *axis,
1382                   const size_t *column_enumeration,
1383                   enum settings_value_show show_values,
1384                   enum settings_value_show show_variables)
1385 {
1386   if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
1387     return NULL;
1388
1389   char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
1390   for (size_t i = 0; i < axis->label_depth; i++)
1391     headings[i] = xcalloc (axis->extent, sizeof **headings);
1392
1393   const size_t *indexes;
1394   size_t column = 0;
1395   PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
1396     {
1397       int row = axis->label_depth - 1;
1398       for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
1399         {
1400           const struct pivot_dimension *d = axis->dimensions[dim_index];
1401           if (d->hide_all_labels)
1402             continue;
1403           for (const struct pivot_category *c
1404                  = d->presentation_leaves[indexes[dim_index]];
1405                c;
1406                c = c->parent)
1407             {
1408               if (pivot_category_is_leaf (c) || (c->show_label
1409                                                  && !c->show_label_in_corner))
1410                 {
1411                   headings[row][column] = pivot_value_to_string (
1412                     c->name, show_values, show_variables);
1413                   if (!*headings[row][column])
1414                     headings[row][column] = xstrdup ("<blank>");
1415                   row--;
1416                 }
1417             }
1418         }
1419       column++;
1420     }
1421
1422   return headings;
1423 }
1424
1425 static void
1426 free_headings (const struct pivot_axis *axis, char ***headings)
1427 {
1428   for (size_t i = 0; i < axis->label_depth; i++)
1429     {
1430       for (size_t j = 0; j < axis->extent; j++)
1431         free (headings[i][j]);
1432       free (headings[i]);
1433     }
1434   free (headings);
1435 }
1436
1437 static void
1438 pivot_table_sizing_dump (const char *name, const struct pivot_table_sizing *s,
1439                          int indentation)
1440 {
1441   indent (indentation);
1442   printf ("%ss: min=%d, max=%d\n", name, s->range[0], s->range[1]);
1443   if (s->n_widths)
1444     {
1445       indent (indentation + 1);
1446       printf ("%s widths:", name);
1447       for (size_t i = 0; i < s->n_widths; i++)
1448         printf (" %d", s->widths[i]);
1449       printf ("\n");
1450     }
1451   if (s->n_breaks)
1452     {
1453       indent (indentation + 1);
1454       printf ("break after %ss:", name);
1455       for (size_t i = 0; i < s->n_breaks; i++)
1456         printf (" %zu", s->breaks[i]);
1457       printf ("\n");
1458     }
1459   if (s->n_keeps)
1460     {
1461       indent (indentation + 1);
1462       printf ("keep %ss together:", name);
1463       for (size_t i = 0; i < s->n_keeps; i++)
1464         printf (" [%zu,%zu]",
1465                 s->keeps[i].ofs,
1466                 s->keeps[i].ofs + s->keeps[i].n - 1);
1467       printf ("\n");
1468     }
1469 }
1470
1471 void
1472 pivot_table_dump (const struct pivot_table *table, int indentation)
1473 {
1474   if (!table)
1475     return;
1476
1477   int old_decimal = settings_get_decimal_char (FMT_COMMA);
1478   if (table->decimal == '.' || table->decimal == ',')
1479     settings_set_decimal_char (table->decimal);
1480
1481   pivot_table_dump_value (table->title, "title", indentation);
1482   pivot_table_dump_string (table->command_c, "command", indentation);
1483   pivot_table_dump_string (table->dataset, "dataset", indentation);
1484   pivot_table_dump_string (table->datafile, "datafile", indentation);
1485   pivot_table_dump_string (table->notes, "notes", indentation);
1486   pivot_table_dump_string (table->table_look, "table-look", indentation);
1487   if (table->date)
1488     {
1489       indent (indentation);
1490       char buf[26];
1491       printf ("date: %s", ctime_r (&table->date, buf));
1492     }
1493
1494   indent (indentation);
1495   printf ("sizing:\n");
1496   pivot_table_sizing_dump ("column", &table->sizing[TABLE_HORZ],
1497                            indentation + 1);
1498   pivot_table_sizing_dump ("row", &table->sizing[TABLE_VERT],
1499                            indentation + 1);
1500
1501   indent (indentation);
1502   printf ("areas:\n");
1503   for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
1504     area_style_dump (area, &table->areas[area], indentation + 1);
1505
1506   indent (indentation);
1507   printf ("borders:\n");
1508   for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
1509     table_border_style_dump (border, &table->borders[border], indentation + 1);
1510
1511   for (size_t i = 0; i < table->n_dimensions; i++)
1512     pivot_dimension_dump (table->dimensions[i], indentation);
1513
1514   /* Presentation and data indexes. */
1515   size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
1516
1517   const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1518   if (layer_axis->n_dimensions)
1519     {
1520       indent (indentation);
1521       printf ("current layer:");
1522
1523       for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1524         {
1525           const struct pivot_dimension *d = layer_axis->dimensions[i];
1526           char *name = pivot_value_to_string (d->root->name,
1527                                               table->show_values,
1528                                               table->show_variables);
1529           char *value = pivot_value_to_string (
1530             d->data_leaves[table->current_layer[i]]->name,
1531             table->show_values, table->show_variables);
1532           printf (" %s=%s", name, value);
1533           free (value);
1534           free (name);
1535         }
1536
1537       putchar ('\n');
1538     }
1539
1540   size_t *layer_indexes;
1541   size_t layer_iteration = 0;
1542   PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
1543     {
1544       indent (indentation);
1545       printf ("layer %zu:", layer_iteration++);
1546
1547       const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1548       for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1549         {
1550           const struct pivot_dimension *d = layer_axis->dimensions[i];
1551
1552           fputs (i == 0 ? " " : ", ", stdout);
1553           pivot_value_dump (d->root->name);
1554           fputs (" =", stdout);
1555
1556           struct pivot_value **names = xnmalloc (layer_axis->label_depth,
1557                                                  sizeof *names);
1558           size_t n_names = 0;
1559           for (const struct pivot_category *c
1560                  = d->presentation_leaves[layer_indexes[i]];
1561                c;
1562                c = c->parent)
1563             {
1564               if (pivot_category_is_leaf (c) || c->show_label)
1565                 names[n_names++] = c->name;
1566             }
1567
1568           for (size_t i = n_names; i-- > 0; )
1569             {
1570               putchar (' ');
1571               pivot_value_dump (names[i]);
1572             }
1573           free (names);
1574         }
1575       putchar ('\n');
1576
1577       size_t *column_enumeration = pivot_table_enumerate_axis (
1578         table, PIVOT_AXIS_COLUMN, layer_indexes, table->omit_empty, NULL);
1579       size_t *row_enumeration = pivot_table_enumerate_axis (
1580         table, PIVOT_AXIS_ROW, layer_indexes, table->omit_empty, NULL);
1581
1582       char ***column_headings = compose_headings (
1583         &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
1584         table->show_values, table->show_variables);
1585       for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
1586         {
1587           indent (indentation + 1);
1588           for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
1589             {
1590               if (x)
1591                 fputs ("; ", stdout);
1592               if (column_headings[y][x])
1593                 fputs (column_headings[y][x], stdout);
1594             }
1595           putchar ('\n');
1596         }
1597       free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
1598
1599       indent (indentation + 1);
1600       printf ("-----------------------------------------------\n");
1601
1602       char ***row_headings = compose_headings (
1603         &table->axes[PIVOT_AXIS_ROW], row_enumeration,
1604         table->show_values, table->show_variables);
1605
1606       size_t x = 0;
1607       const size_t *pindexes[PIVOT_N_AXES]
1608         = { [PIVOT_AXIS_LAYER] = layer_indexes };
1609       PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
1610                                   &table->axes[PIVOT_AXIS_ROW])
1611         {
1612           indent (indentation + 1);
1613
1614           size_t i = 0;
1615           for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
1616             {
1617               if (i++)
1618                 fputs ("; ", stdout);
1619               if (row_headings[y][x])
1620                 fputs (row_headings[y][x], stdout);
1621             }
1622
1623           printf (" | ");
1624
1625           i = 0;
1626           PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
1627                                       column_enumeration,
1628                                       &table->axes[PIVOT_AXIS_COLUMN])
1629             {
1630               if (i++)
1631                 printf ("; ");
1632
1633               pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
1634               const struct pivot_value *value = pivot_table_get (
1635                 table, dindexes);
1636               if (value)
1637                 pivot_value_dump (value);
1638             }
1639           printf ("\n");
1640
1641           x++;
1642         }
1643
1644       free (column_enumeration);
1645       free (row_enumeration);
1646       free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
1647     }
1648
1649   pivot_table_dump_value (table->caption, "caption", indentation);
1650
1651   for (size_t i = 0; i < table->n_footnotes; i++)
1652     {
1653       const struct pivot_footnote *f = table->footnotes[i];
1654       indent (indentation);
1655       putchar ('[');
1656       if (f->marker)
1657         pivot_value_dump (f->marker);
1658       else
1659         printf ("%zu", f->idx);
1660       putchar (']');
1661       pivot_value_dump (f->content);
1662       putchar ('\n');
1663     }
1664
1665   free (dindexes);
1666   settings_set_decimal_char (old_decimal);
1667 }
1668 \f
1669 static const char *
1670 consume_int (const char *p, size_t *n)
1671 {
1672   *n = 0;
1673   while (c_isdigit (*p))
1674     *n = *n * 10 + (*p++ - '0');
1675   return p;
1676 }
1677
1678 static size_t
1679 pivot_format_inner_template (struct string *out, const char *template,
1680                              char escape,
1681                              struct pivot_value **values, size_t n_values,
1682                              enum settings_value_show show_values,
1683                              enum settings_value_show show_variables)
1684 {
1685   size_t args_consumed = 0;
1686   while (*template && *template != ':')
1687     {
1688       if (*template == '\\' && template[1])
1689         {
1690           ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1691           template += 2;
1692         }
1693       else if (*template == escape)
1694         {
1695           size_t index;
1696           template = consume_int (template + 1, &index);
1697           if (index >= 1 && index <= n_values)
1698             {
1699               pivot_value_format (values[index - 1], show_values,
1700                                   show_variables, out);
1701               args_consumed = MAX (args_consumed, index);
1702             }
1703         }
1704       else
1705         ds_put_byte (out, *template++);
1706     }
1707   return args_consumed;
1708 }
1709
1710 static const char *
1711 pivot_extract_inner_template (const char *template, const char **p)
1712 {
1713   *p = template;
1714
1715   for (;;)
1716     {
1717       if (*template == '\\' && template[1] != '\0')
1718         template += 2;
1719       else if (*template == ':')
1720         return template + 1;
1721       else if (*template == '\0')
1722         return template;
1723       else
1724         template++;
1725     }
1726 }
1727
1728 static void
1729 pivot_format_template (struct string *out, const char *template,
1730                        const struct pivot_argument *args, size_t n_args,
1731                        enum settings_value_show show_values,
1732                        enum settings_value_show show_variables)
1733 {
1734   while (*template)
1735     {
1736       if (*template == '\\' && template[1] != '\0')
1737         {
1738           ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
1739           template += 2;
1740         }
1741       else if (*template == '^')
1742         {
1743           size_t index;
1744           template = consume_int (template + 1, &index);
1745           if (index >= 1 && index <= n_args && args[index - 1].n > 0)
1746             pivot_value_format (args[index - 1].values[0],
1747                                 show_values, show_variables, out);
1748         }
1749       else if (*template == '[')
1750         {
1751           const char *tmpl[2];
1752           template = pivot_extract_inner_template (template + 1, &tmpl[0]);
1753           template = pivot_extract_inner_template (template, &tmpl[1]);
1754           template += *template == ']';
1755
1756           size_t index;
1757           template = consume_int (template, &index);
1758           if (index < 1 || index > n_args)
1759             continue;
1760
1761           const struct pivot_argument *arg = &args[index - 1];
1762           size_t left = arg->n;
1763           while (left)
1764             {
1765               struct pivot_value **values = arg->values + (arg->n - left);
1766               int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
1767               char escape = "%^"[tmpl_idx];
1768               size_t used = pivot_format_inner_template (
1769                 out, tmpl[tmpl_idx], escape, values, left,
1770                 show_values, show_variables);
1771               if (!used || used > left)
1772                 break;
1773               left -= used;
1774             }
1775         }
1776       else
1777         ds_put_byte (out, *template++);
1778     }
1779 }
1780
1781 static enum settings_value_show
1782 interpret_show (enum settings_value_show global_show,
1783                 enum settings_value_show table_show,
1784                 enum settings_value_show value_show,
1785                 bool has_label)
1786 {
1787   return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
1788           : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
1789           : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
1790           : global_show);
1791 }
1792
1793 /* Appends a text representation of the body of VALUE to OUT.  SHOW_VALUES and
1794    SHOW_VARIABLES control whether variable and value labels are included.
1795
1796    The "body" omits subscripts and superscripts and footnotes. */
1797 bool
1798 pivot_value_format_body (const struct pivot_value *value,
1799                          enum settings_value_show show_values,
1800                          enum settings_value_show show_variables,
1801                          struct string *out)
1802 {
1803   enum settings_value_show show;
1804   bool numeric = false;
1805
1806   switch (value->type)
1807     {
1808     case PIVOT_VALUE_NUMERIC:
1809       show = interpret_show (settings_get_show_values (),
1810                              show_values,
1811                              value->numeric.show,
1812                              value->numeric.value_label != NULL);
1813       if (show & SETTINGS_VALUE_SHOW_VALUE)
1814         {
1815           char *s = data_out (&(union value) { .f = value->numeric.x },
1816                               "UTF-8", &value->numeric.format);
1817           ds_put_cstr (out, s + strspn (s, " "));
1818           free (s);
1819         }
1820       if (show & SETTINGS_VALUE_SHOW_LABEL)
1821         {
1822           if (show & SETTINGS_VALUE_SHOW_VALUE)
1823             ds_put_byte (out, ' ');
1824           ds_put_cstr (out, value->numeric.value_label);
1825         }
1826       numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
1827       break;
1828
1829     case PIVOT_VALUE_STRING:
1830       show = interpret_show (settings_get_show_values (),
1831                              show_values,
1832                              value->string.show,
1833                              value->string.value_label != NULL);
1834       if (show & SETTINGS_VALUE_SHOW_VALUE)
1835         {
1836           if (value->string.hex)
1837             {
1838               for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
1839                    *p; p++)
1840                 ds_put_format (out, "%02X", *p);
1841             }
1842           else
1843             ds_put_cstr (out, value->string.s);
1844         }
1845       if (show & SETTINGS_VALUE_SHOW_LABEL)
1846         {
1847           if (show & SETTINGS_VALUE_SHOW_VALUE)
1848             ds_put_byte (out, ' ');
1849           ds_put_cstr (out, value->string.value_label);
1850         }
1851       break;
1852
1853     case PIVOT_VALUE_VARIABLE:
1854       show = interpret_show (settings_get_show_variables (),
1855                              show_variables,
1856                              value->variable.show,
1857                              value->variable.var_label != NULL);
1858       if (show & SETTINGS_VALUE_SHOW_VALUE)
1859         ds_put_cstr (out, value->variable.var_name);
1860       if (show & SETTINGS_VALUE_SHOW_LABEL)
1861         {
1862           if (show & SETTINGS_VALUE_SHOW_VALUE)
1863             ds_put_byte (out, ' ');
1864           ds_put_cstr (out, value->variable.var_label);
1865         }
1866       break;
1867
1868     case PIVOT_VALUE_TEXT:
1869       ds_put_cstr (out, value->text.local);
1870       break;
1871
1872     case PIVOT_VALUE_TEMPLATE:
1873       pivot_format_template (out, value->template.local, value->template.args,
1874                              value->template.n_args, show_values,
1875                              show_variables);
1876       break;
1877     }
1878
1879   return numeric;
1880 }
1881
1882 /* Appends a text representation of VALUE to OUT.  SHOW_VALUES and
1883    SHOW_VARIABLES control whether variable and value labels are included.
1884
1885    Subscripts and superscripts and footnotes are included. */
1886 void
1887 pivot_value_format (const struct pivot_value *value,
1888                     enum settings_value_show show_values,
1889                     enum settings_value_show show_variables,
1890                     struct string *out)
1891 {
1892   pivot_value_format_body ( value, show_values, show_variables, out);
1893
1894   if (value->subscript)
1895     ds_put_format (out, "_%s", value->subscript);
1896
1897   if (value->superscript)
1898     ds_put_format (out, "^%s", value->superscript);
1899
1900   for (size_t i = 0; i < value->n_footnotes; i++)
1901     {
1902       ds_put_byte (out, '^');
1903       pivot_value_format (value->footnotes[i]->marker,
1904                           show_values, show_variables, out);
1905     }
1906 }
1907
1908 /* Returns a text representation of VALUE.  The caller must free the string,
1909    with free(). */
1910 char *
1911 pivot_value_to_string (const struct pivot_value *value,
1912                        enum settings_value_show show_values,
1913                        enum settings_value_show show_variables)
1914 {
1915   struct string s = DS_EMPTY_INITIALIZER;
1916   pivot_value_format (value, show_values, show_variables, &s);
1917   return ds_steal_cstr (&s);
1918 }
1919
1920 /* Frees the data owned by V. */
1921 void
1922 pivot_value_destroy (struct pivot_value *value)
1923 {
1924   if (value)
1925     {
1926       font_style_uninit (value->font_style);
1927       free (value->font_style);
1928       free (value->cell_style);
1929       /* Do not free the elements of footnotes because VALUE does not own
1930          them. */
1931       free (value->footnotes);
1932       free (value->subscript);
1933
1934       switch (value->type)
1935         {
1936         case PIVOT_VALUE_NUMERIC:
1937           free (value->numeric.var_name);
1938           free (value->numeric.value_label);
1939           break;
1940
1941         case PIVOT_VALUE_STRING:
1942           free (value->string.s);
1943           free (value->string.var_name);
1944           free (value->string.value_label);
1945           break;
1946
1947         case PIVOT_VALUE_VARIABLE:
1948           free (value->variable.var_name);
1949           free (value->variable.var_label);
1950           break;
1951
1952         case PIVOT_VALUE_TEXT:
1953           free (value->text.local);
1954           if (value->text.c != value->text.local)
1955             free (value->text.c);
1956           if (value->text.id != value->text.local
1957               && value->text.id != value->text.c)
1958             free (value->text.id);
1959           break;
1960
1961         case PIVOT_VALUE_TEMPLATE:
1962           free (value->template.local);
1963           if (value->template.id != value->template.local)
1964             free (value->template.id);
1965           for (size_t i = 0; i < value->template.n_args; i++)
1966             pivot_argument_uninit (&value->template.args[i]);
1967           free (value->template.args);
1968           break;
1969         }
1970       free (value);
1971     }
1972 }
1973
1974 /* Sets AREA to the style to use for VALUE, with defaults coming from
1975    DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
1976 void
1977 pivot_value_get_style (struct pivot_value *value,
1978                        const struct area_style *default_style,
1979                        struct area_style *area)
1980 {
1981   font_style_copy (NULL, &area->font_style, (value->font_style
1982                                              ? value->font_style
1983                                              : &default_style->font_style));
1984   area->cell_style = (value->cell_style
1985                       ? *value->cell_style
1986                       : default_style->cell_style);
1987 }
1988
1989 /* Copies AREA into VALUE's style. */
1990 void
1991 pivot_value_set_style (struct pivot_value *value,
1992                        const struct area_style *area)
1993 {
1994   if (value->font_style)
1995     font_style_uninit (value->font_style);
1996   else
1997     value->font_style = xmalloc (sizeof *value->font_style);
1998   font_style_copy (NULL, value->font_style, &area->font_style);
1999
2000   if (!value->cell_style)
2001     value->cell_style = xmalloc (sizeof *value->cell_style);
2002   *value->cell_style = area->cell_style;
2003 }
2004
2005 /* Frees the data owned by ARG (but not ARG itself). */
2006 void
2007 pivot_argument_uninit (struct pivot_argument *arg)
2008 {
2009   if (arg)
2010     {
2011       for (size_t i = 0; i < arg->n; i++)
2012         pivot_value_destroy (arg->values[i]);
2013       free (arg->values);
2014     }
2015 }
2016
2017 /* Creates and returns a new pivot_value whose contents is the null-terminated
2018    string TEXT.  Takes ownership of TEXT.
2019
2020    This function is for text strings provided by the user (with the exception
2021    that pivot_value_new_variable() should be used for variable names).  For
2022    strings that are part of the PSPP user interface, such as names of
2023    procedures, statistics, annotations, error messages, etc., use
2024    pivot_value_new_text(). */
2025 struct pivot_value *
2026 pivot_value_new_user_text_nocopy (char *text)
2027 {
2028   struct pivot_value *value = xmalloc (sizeof *value);
2029   *value = (struct pivot_value) {
2030     .type = PIVOT_VALUE_TEXT,
2031     .text = {
2032       .local = text,
2033       .c = text,
2034       .id = text,
2035       .user_provided = true,
2036     }
2037   };
2038   return value;
2039 }
2040
2041 /* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
2042    TEXT.  Use SIZE_MAX if TEXT is null-teriminated and its length is not known
2043    in advance.
2044
2045    This function is for text strings provided by the user (with the exception
2046    that pivot_value_new_variable() should be used for variable names).  For
2047    strings that are part of the PSPP user interface, such as names of
2048    procedures, statistics, annotations, error messages, etc., use
2049    pivot_value_new_text().j
2050
2051    The caller retains ownership of TEXT.*/
2052 struct pivot_value *
2053 pivot_value_new_user_text (const char *text, size_t length)
2054 {
2055   return pivot_value_new_user_text_nocopy (
2056     xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
2057 }
2058
2059 /* Creates and returns new pivot_value whose contents is TEXT, which should be
2060    a translatable string, but not actually translated yet, e.g. enclosed in
2061    N_().  This function is for text strings that are part of the PSPP user
2062    interface, such as names of procedures, statistics, annotations, error
2063    messages, etc.  For strings that come from the user, use
2064    pivot_value_new_user_text(). */
2065 struct pivot_value *
2066 pivot_value_new_text (const char *text)
2067 {
2068   char *c = xstrdup (text);
2069   char *local = xstrdup (gettext (c));
2070
2071   struct pivot_value *value = xmalloc (sizeof *value);
2072   *value = (struct pivot_value) {
2073     .type = PIVOT_VALUE_TEXT,
2074     .text = {
2075       .local = local,
2076       .c = c,
2077       .id = c,
2078       .user_provided = false,
2079     }
2080   };
2081   return value;
2082 }
2083
2084 /* Same as pivot_value_new_text() but its argument is a printf()-like format
2085    string. */
2086 struct pivot_value * PRINTF_FORMAT (1, 2)
2087 pivot_value_new_text_format (const char *format, ...)
2088 {
2089   va_list args;
2090   va_start (args, format);
2091   char *c = xvasprintf (format, args);
2092   va_end (args);
2093
2094   va_start (args, format);
2095   char *local = xvasprintf (gettext (format), args);
2096   va_end (args);
2097
2098   struct pivot_value *value = xmalloc (sizeof *value);
2099   *value = (struct pivot_value) {
2100     .type = PIVOT_VALUE_TEXT,
2101     .text = {
2102       .local = local,
2103       .c = c,
2104       .id = xstrdup (c),
2105       .user_provided = false,
2106     }
2107   };
2108   return value;
2109 }
2110
2111 static char *
2112 xstrdup_if_nonempty (const char *s)
2113 {
2114   return s && s[0] ? xstrdup (s) : NULL;
2115 }
2116
2117 /* Returns a new pivot_value that represents X.
2118
2119    The format to use for X is unspecified.  Usually the easiest way to specify
2120    a format is through assigning a result class to one of the categories that
2121    the pivot_value will end up in.  If that is not suitable, then the caller
2122    can use pivot_value_set_rc() or assign directly to value->numeric.format. */
2123 struct pivot_value *
2124 pivot_value_new_number (double x)
2125 {
2126   struct pivot_value *value = xmalloc (sizeof *value);
2127   *value = (struct pivot_value) {
2128     .type = PIVOT_VALUE_NUMERIC,
2129     .numeric = { .x = x, },
2130   };
2131   return value;
2132 }
2133
2134 /* Returns a new pivot_value that represents X, formatted as an integer. */
2135 struct pivot_value *
2136 pivot_value_new_integer (double x)
2137 {
2138   struct pivot_value *value = pivot_value_new_number (x);
2139   value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
2140   return value;
2141 }
2142
2143 /* Returns a new pivot_value that represents VALUE, formatted as for
2144    VARIABLE. */
2145 struct pivot_value *
2146 pivot_value_new_var_value (const struct variable *variable,
2147                            const union value *value)
2148 {
2149   struct pivot_value *pv = pivot_value_new_value (
2150     value, var_get_width (variable), var_get_print_format (variable),
2151     var_get_encoding (variable));
2152
2153   char *var_name = xstrdup (var_get_name (variable));
2154   if (var_is_alpha (variable))
2155     pv->string.var_name = var_name;
2156   else
2157     pv->numeric.var_name = var_name;
2158
2159   const char *label = var_lookup_value_label (variable, value);
2160   if (label)
2161     {
2162       if (var_is_alpha (variable))
2163         pv->string.value_label = xstrdup (label);
2164       else
2165         pv->numeric.value_label = xstrdup (label);
2166     }
2167
2168   return pv;
2169 }
2170
2171 /* Returns a new pivot_value that represents VALUE, with the given WIDTH,
2172    formatted with FORMAT.  For a string value, ENCODING must be its character
2173    encoding. */
2174 struct pivot_value *
2175 pivot_value_new_value (const union value *value, int width,
2176                        const struct fmt_spec *format, const char *encoding)
2177 {
2178   struct pivot_value *pv = xzalloc (sizeof *pv);
2179   if (width > 0)
2180     {
2181       char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
2182                                width);
2183       size_t n = strlen (s);
2184       while (n > 0 && s[n - 1] == ' ')
2185         s[--n] = '\0';
2186
2187       pv->type = PIVOT_VALUE_STRING;
2188       pv->string.s = s;
2189       pv->string.hex = format->type == FMT_AHEX;
2190     }
2191   else
2192     {
2193       pv->type = PIVOT_VALUE_NUMERIC;
2194       pv->numeric.x = value->f;
2195       pv->numeric.format = *format;
2196     }
2197
2198   return pv;
2199 }
2200
2201 /* Returns a new pivot_value for VARIABLE. */
2202 struct pivot_value *
2203 pivot_value_new_variable (const struct variable *variable)
2204 {
2205   struct pivot_value *value = xmalloc (sizeof *value);
2206   *value = (struct pivot_value) {
2207     .type = PIVOT_VALUE_VARIABLE,
2208     .variable = {
2209       .var_name = xstrdup (var_get_name (variable)),
2210       .var_label = xstrdup_if_nonempty (var_get_label (variable)),
2211     },
2212   };
2213   return value;
2214 }
2215
2216 /* Attaches a reference to FOOTNOTE to V. */
2217 void
2218 pivot_value_add_footnote (struct pivot_value *v,
2219                           const struct pivot_footnote *footnote)
2220 {
2221   v->footnotes = xrealloc (v->footnotes,
2222                            (v->n_footnotes + 1) * sizeof *v->footnotes);
2223   v->footnotes[v->n_footnotes++] = footnote;
2224 }
2225
2226 /* If VALUE is a numeric value, and RC is a result class such as
2227    PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
2228 void
2229 pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
2230                     const char *rc)
2231 {
2232   if (value->type == PIVOT_VALUE_NUMERIC)
2233     {
2234       const struct fmt_spec *f = pivot_table_get_format (table, rc);
2235       if (f)
2236         value->numeric.format = *f;
2237     }
2238 }
2239