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