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