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