pivot-table: Make pivot_table_look a refcounted object.
[pspp] / src / output / spv / spv-legacy-decoder.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/spv/spv-legacy-decoder.h"
20
21 #include <errno.h>
22 #include <inttypes.h>
23 #include <math.h>
24 #include <limits.h>
25 #include <stdlib.h>
26
27 #include "data/data-out.h"
28 #include "data/calendar.h"
29 #include "data/format.h"
30 #include "data/value.h"
31 #include "libpspp/assertion.h"
32 #include "libpspp/hash-functions.h"
33 #include "libpspp/hmap.h"
34 #include "libpspp/message.h"
35 #include "output/pivot-table.h"
36 #include "output/spv/detail-xml-parser.h"
37 #include "output/spv/spv-legacy-data.h"
38 #include "output/spv/spv-table-look.h"
39 #include "output/spv/spv.h"
40 #include "output/spv/structure-xml-parser.h"
41
42 #include "gl/c-strtod.h"
43 #include "gl/xalloc.h"
44 #include "gl/xmemdup0.h"
45
46 #include <libxml/tree.h>
47
48 #include "gettext.h"
49 #define N_(msgid) msgid
50 #define _(msgid) gettext (msgid)
51
52 struct spv_series
53   {
54     struct hmap_node hmap_node; /* By name. */
55     char *name;
56     char *label;
57     struct fmt_spec format;
58
59     struct spv_series *label_series;
60     bool is_label_series;
61
62     const struct spvxml_node *xml;
63
64     struct spv_data_value *values;
65     size_t n_values;
66     struct hmap map;            /* Contains "struct spv_mapping". */
67     bool remapped;
68
69     struct pivot_dimension *dimension;
70
71     struct pivot_category **index_to_category;
72     size_t n_index;
73
74     struct spvdx_affix **affixes;
75     size_t n_affixes;
76   };
77
78 static void spv_map_destroy (struct hmap *);
79
80 static struct spv_series *
81 spv_series_first (struct hmap *series_map)
82 {
83   struct spv_series *series;
84   HMAP_FOR_EACH (series, struct spv_series, hmap_node, series_map)
85     return series;
86   return NULL;
87 }
88
89 static struct spv_series *
90 spv_series_find (const struct hmap *series_map, const char *name)
91 {
92   struct spv_series *series;
93   HMAP_FOR_EACH_WITH_HASH (series, struct spv_series, hmap_node,
94                            hash_string (name, 0), series_map)
95     if (!strcmp (name, series->name))
96       return series;
97   return NULL;
98 }
99
100 static struct spv_series *
101 spv_series_from_ref (const struct hmap *series_map,
102                      const struct spvxml_node *ref)
103 {
104   const struct spvxml_node *node
105     = (spvdx_is_source_variable (ref)
106        ? &spvdx_cast_source_variable (ref)->node_
107        : &spvdx_cast_derived_variable (ref)->node_);
108   return spv_series_find (series_map, node->id);
109 }
110
111 static void UNUSED
112 spv_series_dump (const struct spv_series *series)
113 {
114   printf ("series \"%s\"", series->name);
115   if (series->label)
116     printf (" (label \"%s\")", series->label);
117   printf (", %zu values:", series->n_values);
118   for (size_t i = 0; i < series->n_values; i++)
119     {
120       putchar (' ');
121       spv_data_value_dump (&series->values[i], stdout);
122     }
123   putchar ('\n');
124 }
125
126 static void
127 spv_series_destroy (struct hmap *series_map)
128 {
129   struct spv_series *series, *next_series;
130   HMAP_FOR_EACH_SAFE (series, next_series, struct spv_series, hmap_node,
131                       series_map)
132     {
133       free (series->name);
134       free (series->label);
135
136       for (size_t i = 0; i < series->n_values; i++)
137         spv_data_value_uninit (&series->values[i]);
138       free (series->values);
139
140       spv_map_destroy (&series->map);
141
142       free (series->index_to_category);
143
144       hmap_delete (series_map, &series->hmap_node);
145       free (series);
146     }
147   hmap_destroy (series_map);
148 }
149
150 struct spv_mapping
151   {
152     struct hmap_node hmap_node;
153     double from;
154     struct spv_data_value to;
155   };
156
157 static struct spv_mapping *
158 spv_map_search (const struct hmap *map, double from)
159 {
160   struct spv_mapping *mapping;
161   HMAP_FOR_EACH_WITH_HASH (mapping, struct spv_mapping, hmap_node,
162                            hash_double (from, 0), map)
163     if (mapping->from == from)
164       return mapping;
165   return NULL;
166 }
167
168 static const struct spv_data_value *
169 spv_map_lookup (const struct hmap *map, const struct spv_data_value *in)
170 {
171   if (in->width >= 0)
172     return in;
173
174   const struct spv_mapping *m = spv_map_search (map, in->d);
175   return m ? &m->to : in;
176 }
177
178 static bool
179 parse_real (const char *s, double *real)
180 {
181   int save_errno = errno;
182   errno = 0;
183   char *end;
184   *real = c_strtod (s, &end);
185   bool ok = !errno && end > s && !*end;
186   errno = save_errno;
187
188   return ok;
189 }
190
191 static char * WARN_UNUSED_RESULT
192 spv_map_insert (struct hmap *map, double from, const char *to,
193                 bool try_strings_as_numbers, const struct fmt_spec *format)
194 {
195   struct spv_mapping *mapping = xmalloc (sizeof *mapping);
196   mapping->from = from;
197
198   if ((try_strings_as_numbers || (format && fmt_is_numeric (format->type)))
199       && parse_real (to, &mapping->to.d))
200     {
201       if (try_strings_as_numbers)
202         mapping->to.width = -1;
203       else
204         {
205           union value v = { .f = mapping->to.d };
206           mapping->to.s = data_out_stretchy (&v, NULL, format, NULL);
207           mapping->to.width = strlen (mapping->to.s);
208         }
209     }
210   else
211     {
212       mapping->to.width = strlen (to);
213       mapping->to.s = xstrdup (to);
214     }
215
216   struct spv_mapping *old_mapping = spv_map_search (map, from);
217   if (old_mapping)
218     {
219       bool same = spv_data_value_equal (&old_mapping->to, &mapping->to);
220       spv_data_value_uninit (&mapping->to);
221       free (mapping);
222       return (same ? NULL
223               : xasprintf ("Duplicate relabeling differs for from=\"%.*g\"",
224                            DBL_DIG + 1, from));
225     }
226
227   hmap_insert (map, &mapping->hmap_node, hash_double (from, 0));
228   return NULL;
229 }
230
231 static void
232 spv_map_destroy (struct hmap *map)
233 {
234   struct spv_mapping *mapping, *next;
235   HMAP_FOR_EACH_SAFE (mapping, next, struct spv_mapping, hmap_node, map)
236     {
237       spv_data_value_uninit (&mapping->to);
238       hmap_delete (map, &mapping->hmap_node);
239       free (mapping);
240     }
241   hmap_destroy (map);
242 }
243
244 static char * WARN_UNUSED_RESULT
245 spv_series_parse_relabels (struct hmap *map,
246                            struct spvdx_relabel **relabels, size_t n_relabels,
247                            bool try_strings_as_numbers,
248                            const struct fmt_spec *format)
249 {
250   for (size_t i = 0; i < n_relabels; i++)
251     {
252       const struct spvdx_relabel *relabel = relabels[i];
253       char *error = spv_map_insert (map, relabel->from, relabel->to,
254                                     try_strings_as_numbers, format);
255       if (error)
256         return error;
257     }
258   return NULL;
259 }
260
261 static char * WARN_UNUSED_RESULT
262 spv_series_parse_value_map_entry (struct hmap *map,
263                                   const struct spvdx_value_map_entry *vme)
264 {
265   for (const char *p = vme->from; ; p++)
266     {
267       int save_errno = errno;
268       errno = 0;
269       char *end;
270       double from = c_strtod (p, &end);
271       bool ok = !errno && end > p && strchr (";", *end);
272       errno = save_errno;
273       if (!ok)
274         return xasprintf ("Syntax error in valueMapEntry from=\"%s\".",
275                           vme->from);
276
277       char *error = spv_map_insert (map, from, vme->to, true,
278                                     &(struct fmt_spec) { FMT_A, 40, 0 });
279       if (error)
280         return error;
281
282       p = end;
283       if (*p == '\0')
284         return NULL;
285       assert (*p == ';');
286     }
287 }
288
289 static struct fmt_spec
290 decode_date_time_format (const struct spvdx_date_time_format *dtf)
291 {
292   if (dtf->dt_base_format == SPVDX_DT_BASE_FORMAT_DATE)
293     {
294       enum fmt_type type
295         = (dtf->show_quarter > 0 ? FMT_QYR
296            : dtf->show_week > 0 ? FMT_WKYR
297            : dtf->mdy_order == SPVDX_MDY_ORDER_DAY_MONTH_YEAR
298            ? (dtf->month_format == SPVDX_MONTH_FORMAT_NUMBER
299               || dtf->month_format == SPVDX_MONTH_FORMAT_PADDED_NUMBER
300               ? FMT_EDATE : FMT_DATE)
301            : dtf->mdy_order == SPVDX_MDY_ORDER_YEAR_MONTH_DAY ? FMT_SDATE
302            : FMT_ADATE);
303
304       int w = fmt_min_output_width (type);
305       if (dtf->year_abbreviation <= 0)
306         w += 2;
307       return (struct fmt_spec) { .type = type, .w = w };
308     }
309   else
310     {
311       enum fmt_type type
312         = (dtf->dt_base_format == SPVDX_DT_BASE_FORMAT_DATE_TIME
313            ? (dtf->mdy_order == SPVDX_MDY_ORDER_YEAR_MONTH_DAY
314               ? FMT_YMDHMS
315               : FMT_DATETIME)
316            : (dtf->show_day > 0 ? FMT_DTIME
317               : dtf->show_hour > 0 ? FMT_TIME
318               : FMT_MTIME));
319       int w = fmt_min_output_width (type);
320       int d = 0;
321       if (dtf->show_second > 0)
322         {
323           w += 3;
324           if (dtf->show_millis > 0)
325             {
326               d = 3;
327               w += d + 1;
328             }
329         }
330       return (struct fmt_spec) { .type = type, .w = w, .d = d };
331     }
332 }
333
334 static struct fmt_spec
335 decode_elapsed_time_format (const struct spvdx_elapsed_time_format *etf)
336 {
337   enum fmt_type type
338     = (etf->dt_base_format != SPVDX_DT_BASE_FORMAT_TIME ? FMT_DTIME
339        : etf->show_hour > 0 ? FMT_TIME
340        : FMT_MTIME);
341   int w = fmt_min_output_width (type);
342   int d = 0;
343   if (etf->show_second > 0)
344     {
345       w += 3;
346       if (etf->show_millis > 0)
347         {
348           d = 3;
349           w += d + 1;
350         }
351     }
352   return (struct fmt_spec) { .type = type, .w = w, .d = d };
353 }
354
355 static struct fmt_spec
356 decode_number_format (const struct spvdx_number_format *nf)
357 {
358   enum fmt_type type = (nf->scientific == SPVDX_SCIENTIFIC_TRUE ? FMT_E
359                         : nf->prefix && !strcmp (nf->prefix, "$") ? FMT_DOLLAR
360                         : nf->suffix && !strcmp (nf->suffix, "%") ? FMT_PCT
361                         : nf->use_grouping ? FMT_COMMA
362                         : FMT_F);
363
364   int d = nf->maximum_fraction_digits;
365   if (d < 0 || d > 15)
366     d = 2;
367
368   struct fmt_spec f = (struct fmt_spec) { type, 40, d };
369   fmt_fix_output (&f);
370   return f;
371 }
372
373 /* Returns an *approximation* of IN as a fmt_spec.
374
375    Not for use with string formats, which don't have any options anyway. */
376 static struct fmt_spec
377 decode_format (const struct spvdx_format *in)
378 {
379   if (in->f_base_format == SPVDX_F_BASE_FORMAT_DATE ||
380       in->f_base_format == SPVDX_F_BASE_FORMAT_TIME ||
381       in->f_base_format == SPVDX_F_BASE_FORMAT_DATE_TIME)
382     {
383       struct spvdx_date_time_format dtf = {
384         .dt_base_format = (in->f_base_format == SPVDX_F_BASE_FORMAT_DATE
385                            ? SPVDX_DT_BASE_FORMAT_DATE
386                            : in->f_base_format == SPVDX_F_BASE_FORMAT_TIME
387                            ? SPVDX_DT_BASE_FORMAT_TIME
388                            : SPVDX_DT_BASE_FORMAT_DATE_TIME),
389         .separator_chars = in->separator_chars,
390         .mdy_order = in->mdy_order,
391         .show_year = in->show_year,
392         .year_abbreviation = in->year_abbreviation,
393         .show_quarter = in->show_quarter,
394         .quarter_prefix = in->quarter_prefix,
395         .quarter_suffix = in->quarter_suffix,
396         .show_month = in->show_month,
397         .month_format = in->month_format,
398         .show_week = in->show_week,
399         .week_padding = in->week_padding,
400         .week_suffix = in->week_suffix,
401         .show_day_of_week = in->show_day_of_week,
402         .day_of_week_abbreviation = in->day_of_week_abbreviation,
403         .day_padding = in->day_padding,
404         .day_of_month_padding = in->day_of_month_padding,
405         .hour_padding = in->hour_padding,
406         .minute_padding = in->minute_padding,
407         .second_padding = in->second_padding,
408         .show_day = in->show_day,
409         .show_hour = in->show_hour,
410         .show_minute = in->show_minute,
411         .show_second = in->show_second,
412         .show_millis = in->show_millis,
413         .day_type = in->day_type,
414         .hour_format = in->hour_format,
415       };
416       return decode_date_time_format (&dtf);
417     }
418   else if (in->f_base_format == SPVDX_F_BASE_FORMAT_ELAPSED_TIME)
419     {
420       struct spvdx_elapsed_time_format etf = {
421         .dt_base_format = (in->f_base_format == SPVDX_F_BASE_FORMAT_DATE
422                            ? SPVDX_DT_BASE_FORMAT_DATE
423                            : in->f_base_format == SPVDX_F_BASE_FORMAT_TIME
424                            ? SPVDX_DT_BASE_FORMAT_TIME
425                            : SPVDX_DT_BASE_FORMAT_DATE_TIME),
426         .day_padding = in->day_padding,
427         .minute_padding = in->minute_padding,
428         .second_padding = in->second_padding,
429         .show_year = in->show_year,
430         .show_day = in->show_day,
431         .show_hour = in->show_hour,
432         .show_minute = in->show_minute,
433         .show_second = in->show_second,
434         .show_millis = in->show_millis,
435       };
436       return decode_elapsed_time_format (&etf);
437     }
438   else
439     {
440       assert (!in->f_base_format);
441       struct spvdx_number_format nf = {
442         .minimum_integer_digits = in->minimum_integer_digits,
443         .maximum_fraction_digits = in->maximum_fraction_digits,
444         .minimum_fraction_digits = in->minimum_fraction_digits,
445         .use_grouping = in->use_grouping,
446         .scientific = in->scientific,
447         .small = in->small,
448         .prefix = in->prefix,
449         .suffix = in->suffix,
450       };
451       return decode_number_format (&nf);
452     }
453 }
454
455 static void
456 spv_series_execute_mapping (struct spv_series *series)
457 {
458   if (!hmap_is_empty (&series->map))
459     {
460       series->remapped = true;
461       for (size_t i = 0; i < series->n_values; i++)
462         {
463           struct spv_data_value *value = &series->values[i];
464           if (value->width >= 0)
465             continue;
466
467           const struct spv_mapping *mapping = spv_map_search (&series->map,
468                                                               value->d);
469           if (mapping)
470             {
471               value->index = value->d;
472               assert (value->index == floor (value->index));
473               value->width = mapping->to.width;
474               if (value->width >= 0)
475                 value->s = xmemdup0 (mapping->to.s, mapping->to.width);
476               else
477                 value->d = mapping->to.d;
478             }
479         }
480     }
481 }
482
483 static char * WARN_UNUSED_RESULT
484 spv_series_remap_formats (struct spv_series *series,
485                           struct spvxml_node **seq, size_t n_seq)
486 {
487   spv_map_destroy (&series->map);
488   hmap_init (&series->map);
489   for (size_t i = 0; i < n_seq; i++)
490     {
491       struct spvxml_node *node = seq[i];
492       if (spvdx_is_format (node))
493         {
494           struct spvdx_format *f = spvdx_cast_format (node);
495           series->format = decode_format (f);
496           char *error = spv_series_parse_relabels (
497             &series->map, f->relabel, f->n_relabel,
498             f->try_strings_as_numbers > 0, &series->format);
499           if (error)
500             return error;
501
502           series->affixes = f->affix;
503           series->n_affixes = f->n_affix;
504         }
505       else if (spvdx_is_string_format (node))
506         {
507           struct spvdx_string_format *sf = spvdx_cast_string_format (node);
508           char *error = spv_series_parse_relabels (&series->map,
509                                                    sf->relabel, sf->n_relabel,
510                                                    false, NULL);
511           if (error)
512             return error;
513
514           series->affixes = sf->affix;
515           series->n_affixes = sf->n_affix;
516         }
517       else
518         NOT_REACHED ();
519     }
520   spv_series_execute_mapping (series);
521   return NULL;
522 }
523
524 static char * WARN_UNUSED_RESULT
525 spv_series_remap_vmes (struct spv_series *series,
526                        struct spvdx_value_map_entry **vmes,
527                        size_t n_vmes)
528 {
529   spv_map_destroy (&series->map);
530   hmap_init (&series->map);
531   for (size_t i = 0; i < n_vmes; i++)
532     {
533       char *error = spv_series_parse_value_map_entry (&series->map, vmes[i]);
534       if (error)
535         return error;
536     }
537   spv_series_execute_mapping (series);
538   return NULL;
539 }
540
541 static void
542 decode_footnotes (struct pivot_table *table, const struct spvdx_footnotes *f)
543 {
544   if (f->n_footnote_mapping > 0)
545     pivot_table_create_footnote__ (table, f->n_footnote_mapping - 1,
546                                    NULL, NULL);
547   for (size_t i = 0; i < f->n_footnote_mapping; i++)
548     {
549       const struct spvdx_footnote_mapping *fm = f->footnote_mapping[i];
550       pivot_table_create_footnote__ (table, fm->defines_reference - 1,
551                                      pivot_value_new_user_text (fm->to, -1),
552                                      NULL);
553     }
554 }
555
556 static struct cell_color
557 optional_color (int color, struct cell_color default_color)
558 {
559   return (color >= 0
560           ? (struct cell_color) CELL_COLOR (color >> 16, color >> 8, color)
561           : default_color);
562 }
563
564 static int
565 optional_length (const char *s, int default_length)
566 {
567   /* There is usually a "pt" suffix.  We ignore it. */
568   int length;
569   return s && sscanf (s, "%d", &length) == 1 ? length : default_length;
570 }
571
572 static int
573 optional_px (double inches, int default_px)
574 {
575   return inches != DBL_MAX ? inches * 96.0 : default_px;
576 }
577
578 static void
579 decode_spvdx_style_incremental (const struct spvdx_style *in,
580                                 const struct spvdx_style *bg,
581                                 struct table_area_style *out)
582 {
583   if (in && in->font_weight)
584     out->font_style.bold = in->font_weight == SPVDX_FONT_WEIGHT_BOLD;
585   if (in && in->font_style)
586     out->font_style.italic = in->font_style == SPVDX_FONT_STYLE_ITALIC;
587   if (in && in->font_underline)
588     out->font_style.underline = in->font_underline == SPVDX_FONT_UNDERLINE_UNDERLINE;
589   if (in && in->color >= 0)
590     {
591       out->font_style.fg[0] = optional_color (
592         in->color, (struct cell_color) CELL_COLOR_BLACK);
593       out->font_style.fg[1] = out->font_style.fg[0];
594     }
595   if (bg && bg->color >= 0)
596     {
597       out->font_style.bg[0] = optional_color (
598         bg->color, (struct cell_color) CELL_COLOR_WHITE);
599       out->font_style.bg[1] = out->font_style.bg[0];
600     }
601   if (in && in->font_family)
602     {
603       free (out->font_style.typeface);
604       out->font_style.typeface = xstrdup (in->font_family);
605     }
606   if (in && in->font_size)
607     {
608       int size = optional_length (in->font_size, 0);
609       if (size)
610         out->font_style.size = size;
611     }
612   if (in && in->text_alignment)
613     out->cell_style.halign
614       = (in->text_alignment == SPVDX_TEXT_ALIGNMENT_LEFT
615          ? TABLE_HALIGN_LEFT
616          : in->text_alignment == SPVDX_TEXT_ALIGNMENT_RIGHT
617          ? TABLE_HALIGN_RIGHT
618          : in->text_alignment == SPVDX_TEXT_ALIGNMENT_CENTER
619          ? TABLE_HALIGN_CENTER
620          : in->text_alignment == SPVDX_TEXT_ALIGNMENT_DECIMAL
621          ? TABLE_HALIGN_DECIMAL
622          : TABLE_HALIGN_MIXED);
623   if (in && in->label_location_vertical)
624     out->cell_style.valign =
625       (in->label_location_vertical == SPVDX_LABEL_LOCATION_VERTICAL_NEGATIVE
626        ? TABLE_VALIGN_BOTTOM
627        : in->label_location_vertical == SPVDX_LABEL_LOCATION_VERTICAL_POSITIVE
628        ? TABLE_VALIGN_TOP
629        : TABLE_VALIGN_CENTER);
630   if (in && in->decimal_offset != DBL_MAX)
631     out->cell_style.decimal_offset = optional_px (in->decimal_offset, 0);
632 #if 0
633   if (in && in->margin_left != DBL_MAX)
634     out->cell_style.margin[TABLE_HORZ][0] = optional_pt (in->margin_left, 8);
635   if (in && in->margin_right != DBL_MAX)
636     out->cell_style.margin[TABLE_HORZ][1] = optional_pt (in->margin_right, 11);
637   if (in && in->margin_top != DBL_MAX)
638     out->cell_style.margin[TABLE_VERT][0] = optional_pt (in->margin_top, 1);
639   if (in && in->margin_bottom != DBL_MAX)
640     out->cell_style.margin[TABLE_VERT][1] = optional_pt (in->margin_bottom, 1);
641 #endif
642 }
643
644 static void
645 decode_spvdx_style (const struct spvdx_style *in,
646                     const struct spvdx_style *bg,
647                     struct table_area_style *out)
648 {
649   *out = (struct table_area_style) TABLE_AREA_STYLE_INITIALIZER;
650   decode_spvdx_style_incremental (in, bg, out);
651 }
652
653 static void
654 add_footnote (struct pivot_value *v, int idx, struct pivot_table *table)
655 {
656   if (idx < 1 || idx > table->n_footnotes)
657     return;
658
659   pivot_value_add_footnote (v, table->footnotes[idx - 1]);
660 }
661
662 static char * WARN_UNUSED_RESULT
663 decode_label_frame (struct pivot_table *table,
664                     const struct spvdx_label_frame *lf)
665 {
666   if (!lf->label)
667     return NULL;
668
669   struct pivot_value **target;
670   struct table_area_style *area;
671   if (lf->label->purpose == SPVDX_PURPOSE_TITLE)
672     {
673       target = &table->title;
674       area = &table->look->areas[PIVOT_AREA_TITLE];
675     }
676   else if (lf->label->purpose == SPVDX_PURPOSE_SUB_TITLE)
677     {
678       target = &table->caption;
679       area = &table->look->areas[PIVOT_AREA_CAPTION];
680     }
681   else if (lf->label->purpose == SPVDX_PURPOSE_FOOTNOTE)
682     {
683       if (lf->label->n_text > 0
684           && lf->label->text[0]->uses_reference != INT_MIN)
685         {
686           target = NULL;
687           area = &table->look->areas[PIVOT_AREA_FOOTER];
688         }
689       else
690         return NULL;
691     }
692   else if (lf->label->purpose == SPVDX_PURPOSE_LAYER)
693     {
694       target = NULL;
695       area = &table->look->areas[PIVOT_AREA_LAYERS];
696     }
697   else
698     return NULL;
699
700   table_area_style_uninit (area);
701   decode_spvdx_style (lf->label->style, lf->label->text_frame_style, area);
702
703   if (target)
704     {
705       struct pivot_value *value = xzalloc (sizeof *value);
706       value->type = PIVOT_VALUE_TEXT;
707       for (size_t i = 0; i < lf->label->n_text; i++)
708         {
709           const struct spvdx_text *in = lf->label->text[i];
710           if (in->defines_reference != INT_MIN)
711             add_footnote (value, in->defines_reference, table);
712           else if (!value->text.local)
713             value->text.local = xstrdup (in->text);
714           else
715             {
716               char *new = xasprintf ("%s%s", value->text.local, in->text);
717               free (value->text.local);
718               value->text.local = new;
719             }
720         }
721       pivot_value_destroy (*target);
722       *target = value;
723     }
724   else
725     for (size_t i = 0; i < lf->label->n_text; i++)
726       {
727         const struct spvdx_text *in = lf->label->text[i];
728         if (in->uses_reference == INT_MIN)
729           continue;
730         if (i % 2)
731           {
732             size_t length = strlen (in->text);
733             if (length && in->text[length - 1] == '\n')
734               length--;
735
736             pivot_table_create_footnote__ (
737               table, in->uses_reference - 1, NULL,
738               pivot_value_new_user_text (in->text, length));
739           }
740         else
741           {
742             size_t length = strlen (in->text);
743             if (length && in->text[length - 1] == '.')
744               length--;
745
746             pivot_table_create_footnote__ (
747               table, in->uses_reference - 1,
748               pivot_value_new_user_text (in->text, length), NULL);
749           }
750       }
751   return NULL;
752 }
753
754 /* Special return value for decode_spvdx_variable(). */
755 static char BAD_REFERENCE;
756
757 static char * WARN_UNUSED_RESULT
758 decode_spvdx_source_variable (const struct spvxml_node *node,
759                               struct spv_data *data,
760                               struct hmap *series_map)
761 {
762   const struct spvdx_source_variable *sv = spvdx_cast_source_variable (node);
763
764   struct spv_series *label_series = NULL;
765   if (sv->label_variable)
766     {
767       label_series = spv_series_find (series_map,
768                                       sv->label_variable->node_.id);
769       if (!label_series)
770         return &BAD_REFERENCE;
771
772       label_series->is_label_series = true;
773     }
774
775   const struct spv_data_variable *var = spv_data_find_variable (
776     data, sv->source, sv->source_name);
777   if (!var)
778     return xasprintf ("sourceVariable %s references nonexistent "
779                       "source %s variable %s.",
780                       sv->node_.id, sv->source, sv->source_name);
781
782   struct spv_series *s = xzalloc (sizeof *s);
783   s->name = xstrdup (node->id);
784   s->xml = node;
785   s->label = sv->label ? xstrdup (sv->label) : NULL;
786   s->label_series = label_series;
787   s->values = spv_data_values_clone (var->values, var->n_values);
788   s->n_values = var->n_values;
789   s->format = F_8_0;
790   hmap_init (&s->map);
791   hmap_insert (series_map, &s->hmap_node, hash_string (s->name, 0));
792
793   char *error = spv_series_remap_formats (s, sv->seq, sv->n_seq);
794   if (error)
795     return error;
796
797   if (label_series && !s->remapped)
798     {
799       for (size_t i = 0; i < s->n_values; i++)
800         if (s->values[i].width < 0)
801           {
802             char *dest;
803             if (label_series->values[i].width < 0)
804               {
805                 union value v = { .f = label_series->values[i].d };
806                 dest = data_out_stretchy (&v, "UTF-8", &s->format, NULL);
807               }
808             else
809               dest = label_series->values[i].s;
810             char *error = spv_map_insert (&s->map, s->values[i].d,
811                                           dest, false, NULL);
812             free (error);   /* Duplicates are OK. */
813             if (label_series->values[i].width < 0)
814               free (dest);
815           }
816     }
817
818   return NULL;
819 }
820
821 static char * WARN_UNUSED_RESULT
822 decode_spvdx_derived_variable (const struct spvxml_node *node,
823                                struct hmap *series_map)
824 {
825   const struct spvdx_derived_variable *dv = spvdx_cast_derived_variable (node);
826
827   struct spv_data_value *values;
828   size_t n_values;
829
830   struct substring value = ss_cstr (dv->value);
831   if (ss_equals (value, ss_cstr ("constant(0)")))
832     {
833       struct spv_series *existing_series = spv_series_first (series_map);
834       if (!existing_series)
835         return &BAD_REFERENCE;
836
837       n_values = existing_series->n_values;
838       values = XCALLOC (n_values, struct spv_data_value);
839       for (size_t i = 0; i < n_values; i++)
840         values[i].width = -1;
841     }
842   else if (ss_starts_with (value, ss_cstr ("constant(")))
843     {
844       values = NULL;
845       n_values = 0;
846     }
847   else if (ss_starts_with (value, ss_cstr ("map("))
848            && ss_ends_with (value, ss_cstr (")")))
849     {
850       char *dependency_name = ss_xstrdup (ss_substr (value, 4,
851                                                      value.length - 5));
852       struct spv_series *dependency
853         = spv_series_find (series_map, dependency_name);
854       free (dependency_name);
855       if (!dependency)
856         return &BAD_REFERENCE;
857
858       values = spv_data_values_clone (dependency->values,
859                                       dependency->n_values);
860       n_values = dependency->n_values;
861     }
862   else
863     return xasprintf ("Derived variable %s has unknown value \"%s\"",
864                       node->id, dv->value);
865
866   struct spv_series *s = xzalloc (sizeof *s);
867   s->format = F_8_0;
868   s->name = xstrdup (node->id);
869   s->values = values;
870   s->n_values = n_values;
871   hmap_init (&s->map);
872   hmap_insert (series_map, &s->hmap_node, hash_string (s->name, 0));
873
874   char *error = spv_series_remap_vmes (s, dv->value_map_entry,
875                                        dv->n_value_map_entry);
876   if (error)
877     return error;
878
879   error = spv_series_remap_formats (s, dv->seq, dv->n_seq);
880   if (error)
881     return error;
882
883   if (n_values > 0)
884     {
885       for (size_t i = 0; i < n_values; i++)
886         if (values[i].width != 0)
887           goto nonempty;
888       for (size_t i = 0; i < n_values; i++)
889         spv_data_value_uninit (&s->values[i]);
890       free (s->values);
891
892       s->values = NULL;
893       s->n_values = 0;
894
895     nonempty:;
896     }
897   return NULL;
898 }
899
900 struct format_mapping
901   {
902     struct hmap_node hmap_node;
903     uint32_t from;
904     struct fmt_spec to;
905   };
906
907 static const struct format_mapping *
908 format_map_find (const struct hmap *format_map, uint32_t u32_format)
909 {
910   if (format_map)
911     {
912       const struct format_mapping *fm;
913       HMAP_FOR_EACH_IN_BUCKET (fm, struct format_mapping, hmap_node,
914                                hash_int (u32_format, 0), format_map)
915         if (fm->from == u32_format)
916           return fm;
917     }
918
919   return NULL;
920 }
921
922 static char * WARN_UNUSED_RESULT
923 spv_format_from_data_value (const struct spv_data_value *data,
924                             const struct hmap *format_map,
925                             struct fmt_spec *out)
926 {
927   if (!data)
928     {
929       *out = fmt_for_output (FMT_F, 40, 2);
930       return NULL;
931     }
932
933   uint32_t u32_format = data->width < 0 ? data->d : atoi (data->s);
934   const struct format_mapping *fm = format_map_find (format_map, u32_format);
935   if (fm)
936     {
937       *out = fm->to;
938       return NULL;
939     }
940   return spv_decode_fmt_spec (u32_format, out);
941 }
942
943 static char * WARN_UNUSED_RESULT
944 pivot_value_from_data_value (const struct spv_data_value *data,
945                              const struct spv_data_value *format,
946                              const struct hmap *format_map,
947                              struct pivot_value **vp)
948 {
949   *vp = NULL;
950
951   struct fmt_spec f;
952   char *error = spv_format_from_data_value (format, format_map, &f);
953   if (error)
954     return error;
955
956   struct pivot_value *v = xzalloc (sizeof *v);
957   if (data->width >= 0)
958     {
959       if (format && fmt_get_category (f.type) == FMT_CAT_DATE)
960         {
961           int year, month, day, hour, minute, second, msec, len = -1;
962           if (sscanf (data->s, "%4d-%2d-%2dT%2d:%2d:%2d.%3d%n",
963                       &year, &month, &day, &hour, &minute, &second,
964                       &msec, &len) == 7
965               && len == 23
966               && data->s[len] == '\0')
967             {
968               double date = calendar_gregorian_to_offset (year, month, day,
969                                                           NULL);
970               if (date != SYSMIS)
971                 {
972                   v->type = PIVOT_VALUE_NUMERIC;
973                   v->numeric.x = (date * 60. * 60. * 24.
974                                   + hour * 60. * 60.
975                                   + minute * 60.
976                                   + second
977                                   + msec / 1000.0);
978                   v->numeric.format = f;
979                   *vp = v;
980                   return NULL;
981                 }
982             }
983         }
984       else if (format && fmt_get_category (f.type) == FMT_CAT_TIME)
985         {
986           int hour, minute, second, msec, len = -1;
987           if (sscanf (data->s, "%d:%2d:%2d.%3d%n",
988                       &hour, &minute, &second, &msec, &len) == 4
989               && len > 0
990               && data->s[len] == '\0')
991             {
992               v->type = PIVOT_VALUE_NUMERIC;
993               v->numeric.x = (hour * 60. * 60.
994                               + minute * 60.
995                               + second
996                               + msec / 1000.0);
997               v->numeric.format = f;
998               *vp = v;
999               return NULL;
1000             }
1001         }
1002       v->type = PIVOT_VALUE_STRING;
1003       v->string.s = xstrdup (data->s);
1004     }
1005   else
1006     {
1007       v->type = PIVOT_VALUE_NUMERIC;
1008       v->numeric.x = data->d;
1009       v->numeric.format = f;
1010     }
1011   *vp = v;
1012   return NULL;
1013 }
1014
1015 static void
1016 add_parents (struct pivot_category *cat, struct pivot_category *parent,
1017              size_t group_index)
1018 {
1019   cat->parent = parent;
1020   cat->group_index = group_index;
1021   if (pivot_category_is_group (cat))
1022     for (size_t i = 0; i < cat->n_subs; i++)
1023       add_parents (cat->subs[i], cat, i);
1024 }
1025
1026 static const struct spvdx_facet_level *
1027 find_facet_level (const struct spvdx_visualization *v, int facet_level)
1028 {
1029   const struct spvdx_facet_layout *layout = v->graph->facet_layout;
1030   for (size_t i = 0; i < layout->n_facet_level; i++)
1031     {
1032       const struct spvdx_facet_level *fl = layout->facet_level[i];
1033       if (facet_level == fl->level)
1034         return fl;
1035     }
1036   return NULL;
1037 }
1038
1039 static bool
1040 should_show_label (const struct spvdx_facet_level *fl)
1041 {
1042   return fl && fl->axis->label && fl->axis->label->style->visible != 0;
1043 }
1044
1045 static size_t
1046 max_category (const struct spv_series *s)
1047 {
1048   double max_cat = -DBL_MAX;
1049   for (size_t i = 0; i < s->n_values; i++)
1050     {
1051       const struct spv_data_value *dv = &s->values[i];
1052       double d = dv->width < 0 ? dv->d : dv->index;
1053       if (d > max_cat)
1054         max_cat = d;
1055     }
1056   assert (max_cat >= 0 && max_cat < SIZE_MAX - 1);
1057
1058   return max_cat;
1059 }
1060
1061 static void
1062 add_affixes (struct pivot_table *table, struct pivot_value *value,
1063              struct spvdx_affix **affixes, size_t n_affixes)
1064 {
1065   for (size_t i = 0; i < n_affixes; i++)
1066     add_footnote (value, affixes[i]->defines_reference, table);
1067 }
1068
1069 static char * WARN_UNUSED_RESULT
1070 add_dimension (struct spv_series **series, size_t n,
1071                enum pivot_axis_type axis_type,
1072                const struct spvdx_visualization *v, struct pivot_table *table,
1073                struct spv_series **dim_seriesp, size_t *n_dim_seriesp,
1074                int base_facet_level, struct pivot_dimension **dp)
1075 {
1076   char *error = NULL;
1077
1078   const struct spvdx_facet_level *fl
1079     = find_facet_level (v, base_facet_level + n);
1080   if (fl)
1081     {
1082       struct table_area_style *area
1083         = (axis_type == PIVOT_AXIS_COLUMN
1084            ? &table->look->areas[PIVOT_AREA_COLUMN_LABELS]
1085            : axis_type == PIVOT_AXIS_ROW
1086            ? &table->look->areas[PIVOT_AREA_ROW_LABELS]
1087            : NULL);
1088       if (area && fl->axis->label)
1089         {
1090           table_area_style_uninit (area);
1091           decode_spvdx_style (fl->axis->label->style,
1092                               fl->axis->label->text_frame_style, area);
1093         }
1094     }
1095
1096   if (axis_type == PIVOT_AXIS_ROW)
1097     {
1098       const struct spvdx_facet_level *fl2
1099         = find_facet_level (v, base_facet_level + (n - 1));
1100       if (fl2)
1101         decode_spvdx_style_incremental (
1102           fl2->axis->major_ticks->style,
1103           fl2->axis->major_ticks->tick_frame_style,
1104           &table->look->areas[PIVOT_AREA_ROW_LABELS]);
1105     }
1106
1107   const struct spvdx_facet_level *fl3 = find_facet_level (v, base_facet_level);
1108   if (fl3 && fl3->axis->major_ticks->label_angle == -90)
1109     {
1110       if (axis_type == PIVOT_AXIS_COLUMN)
1111         table->rotate_inner_column_labels = true;
1112       else
1113         table->rotate_outer_row_labels = true;
1114     }
1115
1116   /* Find the first row for each category. */
1117   size_t max_cat = max_category (series[0]);
1118   size_t *cat_rows = xnmalloc (max_cat + 1, sizeof *cat_rows);
1119   for (size_t k = 0; k <= max_cat; k++)
1120     cat_rows[k] = SIZE_MAX;
1121   for (size_t k = 0; k < series[0]->n_values; k++)
1122     {
1123       const struct spv_data_value *dv = &series[0]->values[k];
1124       double d = dv->width < 0 ? dv->d : dv->index;
1125       if (d >= 0 && d < SIZE_MAX - 1)
1126         {
1127           size_t row = d;
1128           if (cat_rows[row] == SIZE_MAX)
1129             cat_rows[row] = k;
1130         }
1131     }
1132
1133   /* Drop missing categories and count what's left. */
1134   size_t n_cats = 0;
1135   for (size_t k = 0; k <= max_cat; k++)
1136     if (cat_rows[k] != SIZE_MAX)
1137       cat_rows[n_cats++] = cat_rows[k];
1138   assert (n_cats > 0);
1139
1140   /* Make the categories. */
1141   struct pivot_dimension *d = xzalloc (sizeof *d);
1142   table->dimensions[table->n_dimensions++] = d;
1143
1144   series[0]->n_index = max_cat + 1;
1145   series[0]->index_to_category = xcalloc (
1146     max_cat + 1, sizeof *series[0]->index_to_category);
1147   struct pivot_category **cats = xnmalloc (n_cats, sizeof **cats);
1148   for (size_t k = 0; k < n_cats; k++)
1149     {
1150       struct spv_data_value *dv = &series[0]->values[cat_rows[k]];
1151       int dv_num = dv ? dv->d : dv->index;
1152       struct pivot_category *cat = xzalloc (sizeof *cat);
1153       char *retval = pivot_value_from_data_value (
1154         spv_map_lookup (&series[0]->map, dv), NULL, NULL, &cat->name);
1155       if (retval)
1156         {
1157           if (error)
1158             free (retval);
1159           else
1160             error = retval;
1161         }
1162       cat->parent = NULL;
1163       cat->dimension = d;
1164       cat->data_index = k;
1165       cat->presentation_index = cat_rows[k];
1166       cats[k] = cat;
1167       series[0]->index_to_category[dv_num] = cat;
1168
1169       if (cat->name)
1170         add_affixes (table, cat->name,
1171                      series[0]->affixes, series[0]->n_affixes);
1172     }
1173   free (cat_rows);
1174
1175   struct pivot_axis *axis = &table->axes[axis_type];
1176   d->axis_type = axis_type;
1177   d->level = axis->n_dimensions;
1178   d->top_index = table->n_dimensions - 1;
1179   d->root = xzalloc (sizeof *d->root);
1180   *d->root = (struct pivot_category) {
1181     .name = pivot_value_new_user_text (
1182       series[0]->label ? series[0]->label : "", -1),
1183     .dimension = d,
1184     .show_label = should_show_label (fl),
1185     .data_index = SIZE_MAX,
1186     .presentation_index = SIZE_MAX,
1187   };
1188   d->data_leaves = xmemdup (cats, n_cats * sizeof *cats);
1189   d->presentation_leaves = xmemdup (cats, n_cats * sizeof *cats);
1190   d->n_leaves = d->allocated_leaves = n_cats;
1191
1192   /* Now group them, in one pass per grouping variable, innermost first. */
1193   for (size_t j = 1; j < n; j++)
1194     {
1195       struct pivot_category **new_cats = xnmalloc (n_cats, sizeof **cats);
1196       size_t n_new_cats = 0;
1197
1198       /* Allocate a category index. */
1199       size_t max_cat = max_category (series[j]);
1200       series[j]->n_index = max_cat + 1;
1201       series[j]->index_to_category = xcalloc (
1202         max_cat + 1, sizeof *series[j]->index_to_category);
1203       for (size_t cat1 = 0; cat1 < n_cats;)
1204         {
1205           /* Find a sequence of categories cat1...cat2 (exclusive), that all
1206              have the same value in series 'j'.  (This might be only a single
1207              category; we will drop unnamed 1-category groups later.) */
1208           size_t row1 = cats[cat1]->presentation_index;
1209           const struct spv_data_value *dv1 = &series[j]->values[row1];
1210           size_t cat2;
1211           for (cat2 = cat1 + 1; cat2 < n_cats; cat2++)
1212             {
1213               size_t row2 = cats[cat2]->presentation_index;
1214               const struct spv_data_value *dv2 = &series[j]->values[row2];
1215               if (!spv_data_value_equal (dv1, dv2))
1216                 break;
1217             }
1218           size_t n_subs = cat2 - cat1;
1219
1220           struct pivot_category *new_cat;
1221           const struct spv_data_value *name
1222             = spv_map_lookup (&series[j]->map, dv1);
1223           if (n_subs == 1 && name->width == 0)
1224             {
1225               /* The existing category stands on its own. */
1226               new_cat = cats[cat1++];
1227             }
1228           else
1229             {
1230               /* Create a new group with cat...cat2 as subcategories. */
1231               new_cat = xzalloc (sizeof *new_cat);
1232               *new_cat = (struct pivot_category) {
1233                 .dimension = d,
1234                 .subs = xnmalloc (n_subs, sizeof *new_cat->subs),
1235                 .n_subs = n_subs,
1236                 .show_label = true,
1237                 .data_index = SIZE_MAX,
1238                 .presentation_index = row1,
1239               };
1240               char *retval = pivot_value_from_data_value (name, NULL, NULL,
1241                                                           &new_cat->name);
1242               if (retval)
1243                 {
1244                   if (error)
1245                     free (retval);
1246                   else
1247                     error = retval;
1248                 }
1249               for (size_t k = 0; k < n_subs; k++)
1250                 new_cat->subs[k] = cats[cat1++];
1251
1252               int dv1_num = dv1->width < 0 ? dv1->d : dv1->index;
1253               series[j]->index_to_category[dv1_num] = new_cat;
1254             }
1255
1256           if (new_cat->name)
1257             add_affixes (table, new_cat->name,
1258                          series[j]->affixes, series[j]->n_affixes);
1259
1260           /* Append the new group to the list of new groups. */
1261           new_cats[n_new_cats++] = new_cat;
1262         }
1263
1264       free (cats);
1265       cats = new_cats;
1266       n_cats = n_new_cats;
1267     }
1268
1269   /* Now drop unnamed 1-category groups and add parent pointers. */
1270   for (size_t j = 0; j < n_cats; j++)
1271     add_parents (cats[j], d->root, j);
1272
1273   d->root->subs = cats;
1274   d->root->n_subs = n_cats;
1275
1276   if (error)
1277     {
1278       pivot_dimension_destroy (d);
1279       return error;
1280     }
1281
1282   dim_seriesp[(*n_dim_seriesp)++] = series[0];
1283   series[0]->dimension = d;
1284
1285   axis->dimensions = xnrealloc (axis->dimensions, axis->n_dimensions + 1,
1286                                sizeof *axis->dimensions);
1287   axis->dimensions[axis->n_dimensions++] = d;
1288   axis->extent *= d->n_leaves;
1289
1290   *dp = d;
1291   return NULL;
1292 }
1293
1294 static char * WARN_UNUSED_RESULT
1295 add_dimensions (struct hmap *series_map, const struct spvdx_nest *nest,
1296                 enum pivot_axis_type axis_type,
1297                 const struct spvdx_visualization *v, struct pivot_table *table,
1298                 struct spv_series **dim_seriesp, size_t *n_dim_seriesp,
1299                 int level_ofs)
1300 {
1301   struct pivot_axis *axis = &table->axes[axis_type];
1302   if (!axis->extent)
1303     axis->extent = 1;
1304
1305   if (!nest)
1306     return NULL;
1307
1308   struct spv_series **series = xnmalloc (nest->n_vars, sizeof *series);
1309   for (size_t i = 0; i < nest->n_vars;)
1310     {
1311       size_t n;
1312       for (n = 0; i + n < nest->n_vars; n++)
1313         {
1314           series[n] = spv_series_from_ref (series_map, nest->vars[i + n]->ref);
1315           if (!series[n] || !series[n]->n_values)
1316             break;
1317         }
1318
1319       if (n > 0)
1320         {
1321           struct pivot_dimension *d;
1322           char *error = add_dimension (series, n, axis_type, v, table,
1323                                        dim_seriesp, n_dim_seriesp,
1324                                        level_ofs + i, &d);
1325           if (error)
1326             {
1327               free (series);
1328               return error;
1329             }
1330         }
1331
1332       i += n + 1;
1333     }
1334   free (series);
1335
1336   return NULL;
1337 }
1338
1339 static char * WARN_UNUSED_RESULT
1340 add_layers (struct hmap *series_map,
1341             struct spvdx_layer **layers, size_t n_layers,
1342             const struct spvdx_visualization *v, struct pivot_table *table,
1343             struct spv_series **dim_seriesp, size_t *n_dim_seriesp,
1344             int level_ofs)
1345 {
1346   struct pivot_axis *axis = &table->axes[PIVOT_AXIS_LAYER];
1347   if (!axis->extent)
1348     axis->extent = 1;
1349
1350   if (!n_layers)
1351     return NULL;
1352
1353   struct spv_series **series = xnmalloc (n_layers, sizeof *series);
1354   for (size_t i = 0; i < n_layers;)
1355     {
1356       size_t n;
1357       for (n = 0; i + n < n_layers; n++)
1358         {
1359           series[n] = spv_series_from_ref (series_map,
1360                                            layers[i + n]->variable);
1361           if (!series[n] || !series[n]->n_values)
1362             break;
1363         }
1364
1365       if (n > 0)
1366         {
1367           struct pivot_dimension *d;
1368           char *error = add_dimension (
1369             series, n, PIVOT_AXIS_LAYER, v, table,
1370             dim_seriesp, n_dim_seriesp, level_ofs + i, &d);
1371           if (error)
1372             {
1373               free (series);
1374               return error;
1375             }
1376
1377           int index = atoi (layers[i]->value);
1378           assert (index < d->n_leaves);
1379           table->current_layer = xrealloc (
1380             table->current_layer,
1381             axis->n_dimensions * sizeof *table->current_layer);
1382           table->current_layer[axis->n_dimensions - 1] = index;
1383         }
1384       i += n + 1;
1385     }
1386   free (series);
1387
1388   return NULL;
1389 }
1390
1391 static struct pivot_category *
1392 find_category (struct spv_series *series, int index)
1393 {
1394   return (index >= 0 && index < series->n_index
1395           ? series->index_to_category[index]
1396           : NULL);
1397 }
1398
1399 static bool
1400 int_in_array (int value, const int *array, size_t n)
1401 {
1402   for (size_t i = 0; i < n; i++)
1403     if (array[i] == value)
1404       return true;
1405
1406   return false;
1407 }
1408
1409 static void
1410 apply_styles_to_value (struct pivot_table *table,
1411                        struct pivot_value *value,
1412                        const struct spvdx_set_format *sf,
1413                        const struct table_area_style *base_area_style,
1414                        const struct spvdx_style *fg,
1415                        const struct spvdx_style *bg)
1416 {
1417   if (sf)
1418     {
1419       if (sf->reset > 0)
1420         {
1421           free (value->footnotes);
1422           value->footnotes = NULL;
1423           value->n_footnotes = 0;
1424         }
1425
1426       struct fmt_spec format = { .w = 0 };
1427       if (sf->format)
1428         {
1429           format = decode_format (sf->format);
1430           add_affixes (table, value, sf->format->affix, sf->format->n_affix);
1431         }
1432       else if (sf->number_format)
1433         {
1434           format = decode_number_format (sf->number_format);
1435           add_affixes (table, value, sf->number_format->affix,
1436                        sf->number_format->n_affix);
1437         }
1438       else if (sf->n_string_format)
1439         {
1440           for (size_t i = 0; i < sf->n_string_format; i++)
1441             add_affixes (table, value, sf->string_format[i]->affix,
1442                          sf->string_format[i]->n_affix);
1443         }
1444       else if (sf->date_time_format)
1445         {
1446           format = decode_date_time_format (sf->date_time_format);
1447           add_affixes (table, value, sf->date_time_format->affix,
1448                        sf->date_time_format->n_affix);
1449         }
1450       else if (sf->elapsed_time_format)
1451         {
1452           format = decode_elapsed_time_format (sf->elapsed_time_format);
1453           add_affixes (table, value, sf->elapsed_time_format->affix,
1454                        sf->elapsed_time_format->n_affix);
1455         }
1456
1457       if (format.w)
1458         {
1459           if (value->type == PIVOT_VALUE_NUMERIC)
1460             value->numeric.format = format;
1461
1462           /* Possibly we should try to apply date and time formats too,
1463              but none seem to occur in practice so far. */
1464         }
1465     }
1466   if (fg || bg)
1467     {
1468       struct table_area_style area;
1469       pivot_value_get_style (
1470         value,
1471         value->font_style ? value->font_style : &base_area_style->font_style,
1472         value->cell_style ? value->cell_style : &base_area_style->cell_style,
1473         &area);
1474       decode_spvdx_style_incremental (fg, bg, &area);
1475       pivot_value_set_style (value, &area);
1476       table_area_style_uninit (&area);
1477     }
1478 }
1479
1480 static void
1481 decode_set_cell_properties__ (struct pivot_table *table,
1482                               struct hmap *series_map,
1483                               const struct spvdx_intersect *intersect,
1484                               const struct spvdx_style *interval,
1485                               const struct spvdx_style *graph,
1486                               const struct spvdx_style *labeling,
1487                               const struct spvdx_style *frame,
1488                               const struct spvdx_style *major_ticks,
1489                               const struct spvdx_set_format *set_format)
1490 {
1491   if (graph && labeling && intersect->alternating
1492       && !interval && !major_ticks && !frame && !set_format)
1493     {
1494       /* Sets alt_fg_color and alt_bg_color. */
1495       struct table_area_style area;
1496       decode_spvdx_style (labeling, graph, &area);
1497       table->look->areas[PIVOT_AREA_DATA].font_style.fg[1]
1498         = area.font_style.fg[0];
1499       table->look->areas[PIVOT_AREA_DATA].font_style.bg[1]
1500         = area.font_style.bg[0];
1501       table_area_style_uninit (&area);
1502     }
1503   else if (graph
1504            && !labeling && !interval && !major_ticks && !frame && !set_format)
1505     {
1506       /* 'graph->width' likely just sets the width of the table as a
1507          whole.  */
1508     }
1509   else if (!graph && !labeling && !interval && !frame && !set_format
1510            && !major_ticks)
1511     {
1512       /* No-op.  (Presumably there's a setMetaData we don't care about.) */
1513     }
1514   else if (((set_format && spvdx_is_major_ticks (set_format->target))
1515             || major_ticks || frame)
1516            && intersect->n_where == 1)
1517     {
1518       /* Formatting for individual row or column labels. */
1519       const struct spvdx_where *w = intersect->where[0];
1520       struct spv_series *s = spv_series_find (series_map, w->variable->id);
1521       assert (s);
1522
1523       const char *p = w->include;
1524
1525       while (*p)
1526         {
1527           char *tail;
1528           int include = strtol (p, &tail, 10);
1529
1530           struct pivot_category *c = find_category (s, include);
1531           if (c)
1532             {
1533               const struct table_area_style *base_area_style
1534                 = (c->dimension->axis_type == PIVOT_AXIS_ROW
1535                    ? &table->look->areas[PIVOT_AREA_ROW_LABELS]
1536                    : &table->look->areas[PIVOT_AREA_COLUMN_LABELS]);
1537               apply_styles_to_value (table, c->name, set_format,
1538                                      base_area_style, major_ticks, frame);
1539             }
1540
1541           if (tail == p)
1542             break;
1543           p = tail;
1544           if (*p == ';')
1545             p++;
1546         }
1547     }
1548   else if ((set_format && spvdx_is_labeling (set_format->target))
1549            || labeling || interval)
1550     {
1551       /* Formatting for individual cells or groups of them with some dimensions
1552          in common. */
1553       int **indexes = XCALLOC (table->n_dimensions, int *);
1554       size_t *n = XCALLOC (table->n_dimensions, size_t);
1555       size_t *allocated = XCALLOC (table->n_dimensions, size_t);
1556
1557       for (size_t i = 0; i < intersect->n_where; i++)
1558         {
1559           const struct spvdx_where *w = intersect->where[i];
1560           struct spv_series *s = spv_series_find (series_map, w->variable->id);
1561           assert (s);
1562           if (!s->dimension)
1563             {
1564               /* Group indexes may be included even though they are redundant.
1565                  Ignore them. */
1566               continue;
1567             }
1568
1569           size_t j = s->dimension->top_index;
1570
1571           const char *p = w->include;
1572           while (*p)
1573             {
1574               char *tail;
1575               int include = strtol (p, &tail, 10);
1576
1577               struct pivot_category *c = find_category (s, include);
1578               if (c)
1579                 {
1580                   if (n[j] >= allocated[j])
1581                     indexes[j] = x2nrealloc (indexes[j], &allocated[j],
1582                                              sizeof *indexes[j]);
1583                   indexes[j][n[j]++] = c->data_index;
1584                 }
1585
1586               if (tail == p)
1587                 break;
1588               p = tail;
1589               if (*p == ';')
1590                 p++;
1591             }
1592         }
1593
1594 #if 0
1595       printf ("match:");
1596       for (size_t i = 0; i < table->n_dimensions; i++)
1597         {
1598           if (n[i])
1599             {
1600               printf (" %d=(", i);
1601               for (size_t j = 0; j < n[i]; j++)
1602                 {
1603                   if (j)
1604                     putchar (',');
1605                   printf ("%d", indexes[i][j]);
1606                 }
1607               putchar (')');
1608             }
1609         }
1610       printf ("\n");
1611 #endif
1612
1613       /* XXX This is inefficient in the common case where all of the dimensions
1614          are matched.  We should use a heuristic where if all of the dimensions
1615          are matched and the product of n[*] is less than
1616          hmap_count(&table->cells) then iterate through all the possibilities
1617          rather than all the cells.  Or even only do it if there is just one
1618          possibility. */
1619
1620       struct pivot_cell *cell;
1621       HMAP_FOR_EACH (cell, struct pivot_cell, hmap_node, &table->cells)
1622         {
1623           for (size_t i = 0; i < table->n_dimensions; i++)
1624             {
1625               if (n[i] && !int_in_array (cell->idx[i], indexes[i], n[i]))
1626                 goto skip;
1627             }
1628           apply_styles_to_value (table, cell->value, set_format,
1629                                  &table->look->areas[PIVOT_AREA_DATA],
1630                                  labeling, interval);
1631
1632         skip: ;
1633         }
1634
1635       for (size_t i = 0; i < table->n_dimensions; i++)
1636         free (indexes[i]);
1637       free (indexes);
1638       free (n);
1639       free (allocated);
1640     }
1641   else
1642     NOT_REACHED ();
1643 }
1644
1645 static void
1646 decode_set_cell_properties (struct pivot_table *table, struct hmap *series_map,
1647                             struct spvdx_set_cell_properties **scps,
1648                             size_t n_scps)
1649 {
1650   for (size_t i = 0; i < n_scps; i++)
1651     {
1652       const struct spvdx_set_cell_properties *scp = scps[i];
1653       const struct spvdx_style *interval = NULL;
1654       const struct spvdx_style *graph = NULL;
1655       const struct spvdx_style *labeling = NULL;
1656       const struct spvdx_style *frame = NULL;
1657       const struct spvdx_style *major_ticks = NULL;
1658       const struct spvdx_set_format *set_format = NULL;
1659       for (size_t j = 0; j < scp->n_seq; j++)
1660         {
1661           const struct spvxml_node *node = scp->seq[j];
1662           if (spvdx_is_set_style (node))
1663             {
1664               const struct spvdx_set_style *set_style
1665                 = spvdx_cast_set_style (node);
1666               if (spvdx_is_graph (set_style->target))
1667                 graph = set_style->style;
1668               else if (spvdx_is_labeling (set_style->target))
1669                 labeling = set_style->style;
1670               else if (spvdx_is_interval (set_style->target))
1671                 interval = set_style->style;
1672               else if (spvdx_is_major_ticks (set_style->target))
1673                 major_ticks = set_style->style;
1674               else
1675                 NOT_REACHED ();
1676             }
1677           else if (spvdx_is_set_frame_style (node))
1678             frame = spvdx_cast_set_frame_style (node)->style;
1679           else if (spvdx_is_set_format (node))
1680             set_format = spvdx_cast_set_format (node);
1681           else
1682             assert (spvdx_is_set_meta_data (node));
1683         }
1684
1685       if (scp->union_ && scp->apply_to_converse <= 0)
1686         {
1687           for (size_t j = 0; j < scp->union_->n_intersect; j++)
1688             decode_set_cell_properties__ (
1689               table, series_map, scp->union_->intersect[j],
1690               interval, graph, labeling, frame, major_ticks, set_format);
1691         }
1692       else if (!scp->union_ && scp->apply_to_converse > 0)
1693         {
1694           if ((set_format && spvdx_is_labeling (set_format->target))
1695               || labeling || interval)
1696             {
1697               struct pivot_cell *cell;
1698               HMAP_FOR_EACH (cell, struct pivot_cell, hmap_node, &table->cells)
1699                 apply_styles_to_value (table, cell->value, set_format,
1700                                        &table->look->areas[PIVOT_AREA_DATA],
1701                                        NULL, NULL);
1702             }
1703         }
1704       else if (!scp->union_ && scp->apply_to_converse <= 0)
1705         {
1706           /* Appears to be used to set the font for something--but what? */
1707         }
1708       else
1709         NOT_REACHED ();
1710     }
1711 }
1712
1713 static struct spv_series *
1714 parse_formatting (const struct spvdx_visualization *v,
1715                   const struct hmap *series_map, struct hmap *format_map)
1716 {
1717   const struct spvdx_labeling *labeling = v->graph->interval->labeling;
1718   struct spv_series *cell_format = NULL;
1719   for (size_t i = 0; i < labeling->n_seq; i++)
1720     {
1721       const struct spvdx_formatting *f
1722         = spvdx_cast_formatting (labeling->seq[i]);
1723       if (!f)
1724         continue;
1725
1726       cell_format = spv_series_from_ref (series_map, f->variable);
1727       for (size_t j = 0; j < f->n_format_mapping; j++)
1728         {
1729           const struct spvdx_format_mapping *fm = f->format_mapping[j];
1730
1731           if (fm->format)
1732             {
1733               struct format_mapping *out = xmalloc (sizeof *out);
1734               out->from = fm->from;
1735               out->to = decode_format (fm->format);
1736               hmap_insert (format_map, &out->hmap_node,
1737                            hash_int (out->from, 0));
1738             }
1739         }
1740     }
1741
1742   return cell_format;
1743 }
1744
1745 static void
1746 format_map_destroy (struct hmap *format_map)
1747 {
1748   struct format_mapping *fm, *next;
1749   HMAP_FOR_EACH_SAFE (fm, next, struct format_mapping, hmap_node, format_map)
1750     {
1751       hmap_delete (format_map, &fm->hmap_node);
1752       free (fm);
1753     }
1754   hmap_destroy (format_map);
1755 }
1756
1757 char * WARN_UNUSED_RESULT
1758 decode_spvdx_table (const struct spvdx_visualization *v, const char *subtype,
1759                     const struct pivot_table_look *look,
1760                     struct spv_data *data, struct pivot_table **outp)
1761 {
1762   struct pivot_table *table = pivot_table_create__ (NULL, subtype);
1763
1764   pivot_table_set_look (table, look);
1765   table->look = pivot_table_look_unshare (table->look);
1766
1767   struct hmap series_map = HMAP_INITIALIZER (series_map);
1768   struct hmap format_map = HMAP_INITIALIZER (format_map);
1769   struct spv_series **dim_series = NULL;
1770   char *error;
1771
1772   struct spvdx_visualization_extension *ve = v->visualization_extension;
1773   table->show_grid_lines = ve && ve->show_gridline;
1774
1775   /* Sizing from the legacy properties can get overridden. */
1776   if (v->graph->cell_style->width)
1777     {
1778       int min_width, max_width, n = 0;
1779       if (sscanf (v->graph->cell_style->width, "%*d%%;%dpt;%dpt%n",
1780                   &min_width, &max_width, &n)
1781           && v->graph->cell_style->width[n] == '\0')
1782         {
1783           table->look->width_ranges[TABLE_HORZ][0] = min_width;
1784           table->look->width_ranges[TABLE_HORZ][1] = max_width;
1785         }
1786     }
1787
1788   /* Footnotes.
1789
1790      Any pivot_value might refer to footnotes, so it's important to process the
1791      footnotes early to ensure that those references can be resolved.  There is
1792      a possible problem that a footnote might itself reference an
1793      as-yet-unprocessed footnote, but that's OK because footnote references
1794      don't actually look at the footnote contents but only resolve a pointer to
1795      where the footnote will go later.
1796
1797      Before we really start, create all the footnotes we'll fill in.  This is
1798      because sometimes footnotes refer to themselves or to each other and we
1799      don't want to reject those references. */
1800   if (v->container)
1801     for (size_t i = 0; i < v->container->n_label_frame; i++)
1802       {
1803         const struct spvdx_label_frame *lf = v->container->label_frame[i];
1804         if (lf->label
1805             && lf->label->purpose == SPVDX_PURPOSE_FOOTNOTE
1806             && lf->label->n_text > 0
1807             && lf->label->text[0]->uses_reference > 0)
1808           {
1809             pivot_table_create_footnote__ (
1810               table, lf->label->text[0]->uses_reference - 1,
1811               NULL, NULL);
1812           }
1813       }
1814
1815   if (v->graph->interval->footnotes)
1816     decode_footnotes (table, v->graph->interval->footnotes);
1817
1818   struct spv_series *footnotes = NULL;
1819   for (size_t i = 0; i < v->graph->interval->labeling->n_seq; i++)
1820     {
1821       const struct spvxml_node *node = v->graph->interval->labeling->seq[i];
1822       if (spvdx_is_footnotes (node))
1823         {
1824           const struct spvdx_footnotes *f = spvdx_cast_footnotes (node);
1825           footnotes = spv_series_from_ref (&series_map, f->variable);
1826           decode_footnotes (table, f);
1827         }
1828     }
1829   for (size_t i = 0; i < v->n_lf1; i++)
1830     {
1831       error = decode_label_frame (table, v->lf1[i]);
1832       if (error)
1833         goto exit;
1834     }
1835   for (size_t i = 0; i < v->n_lf2; i++)
1836     {
1837       error = decode_label_frame (table, v->lf2[i]);
1838       if (error)
1839         goto exit;
1840     }
1841   if (v->container)
1842     for (size_t i = 0; i < v->container->n_label_frame; i++)
1843       {
1844         error = decode_label_frame (table, v->container->label_frame[i]);
1845         if (error)
1846           goto exit;
1847       }
1848   if (v->graph->interval->labeling->style)
1849     {
1850       table_area_style_uninit (&table->look->areas[PIVOT_AREA_DATA]);
1851       decode_spvdx_style (v->graph->interval->labeling->style,
1852                           v->graph->cell_style,
1853                           &table->look->areas[PIVOT_AREA_DATA]);
1854     }
1855
1856   /* Decode all of the sourceVariable and derivedVariable  */
1857   struct spvxml_node **nodes = xmemdup (v->seq, v->n_seq * sizeof *v->seq);
1858   size_t n_nodes = v->n_seq;
1859   while (n_nodes > 0)
1860     {
1861       bool progress = false;
1862       for (size_t i = 0; i < n_nodes;)
1863         {
1864           error = (spvdx_is_source_variable (nodes[i])
1865                    ? decode_spvdx_source_variable (nodes[i], data, &series_map)
1866                    : decode_spvdx_derived_variable (nodes[i], &series_map));
1867           if (!error)
1868             {
1869               nodes[i] = nodes[--n_nodes];
1870               progress = true;
1871             }
1872           else if (error == &BAD_REFERENCE)
1873             i++;
1874           else
1875             {
1876               free (nodes);
1877               goto exit;
1878             }
1879         }
1880
1881       if (!progress)
1882         {
1883           free (nodes);
1884           error = xasprintf ("Table has %zu variables with circular or "
1885                              "unresolved references, including variable %s.",
1886                              n_nodes, nodes[0]->id);
1887           goto exit;
1888         }
1889     }
1890   free (nodes);
1891
1892   const struct spvdx_cross *cross = v->graph->faceting->cross;
1893
1894   assert (cross->n_seq == 1);
1895   const struct spvdx_nest *columns = spvdx_cast_nest (cross->seq[0]);
1896   size_t max_columns = columns ? columns->n_vars : 0;
1897
1898   assert (cross->n_seq2 == 1);
1899   const struct spvdx_nest *rows = spvdx_cast_nest (cross->seq2[0]);
1900   size_t max_rows = rows ? rows->n_vars : 0;
1901
1902   size_t max_layers = (v->graph->faceting->n_layers1
1903                        + v->graph->faceting->n_layers2);
1904
1905   size_t max_dims = max_columns + max_rows + max_layers;
1906   table->dimensions = xnmalloc (max_dims, sizeof *table->dimensions);
1907   dim_series = xnmalloc (max_dims, sizeof *dim_series);
1908   size_t n_dim_series = 0;
1909
1910   error = add_dimensions (&series_map, columns, PIVOT_AXIS_COLUMN, v, table,
1911                           dim_series, &n_dim_series, 1);
1912   if (error)
1913     goto exit;
1914
1915   error = add_dimensions (&series_map, rows, PIVOT_AXIS_ROW, v, table,
1916                           dim_series, &n_dim_series, max_columns + 1);
1917   if (error)
1918     goto exit;
1919
1920   error = add_layers (&series_map, v->graph->faceting->layers1,
1921                       v->graph->faceting->n_layers1,
1922                       v, table, dim_series, &n_dim_series,
1923                       max_rows + max_columns + 1);
1924   if (error)
1925     goto exit;
1926
1927   error = add_layers (&series_map, v->graph->faceting->layers2,
1928                       v->graph->faceting->n_layers2,
1929                       v, table, dim_series, &n_dim_series,
1930                       (max_rows + max_columns + v->graph->faceting->n_layers1
1931                        + 1));
1932   if (error)
1933     goto exit;
1934
1935   struct spv_series *cell = spv_series_find (&series_map, "cell");
1936   if (!cell)
1937     {
1938       error = xstrdup (_("Table lacks cell data."));
1939       goto exit;
1940     }
1941
1942   struct spv_series *cell_format = parse_formatting (v, &series_map,
1943                                                      &format_map);
1944
1945   assert (table->n_dimensions == n_dim_series);
1946   size_t *dim_indexes = xnmalloc (table->n_dimensions, sizeof *dim_indexes);
1947   for (size_t i = 0; i < cell->n_values; i++)
1948     {
1949       for (size_t j = 0; j < table->n_dimensions; j++)
1950         {
1951           const struct spv_data_value *value = &dim_series[j]->values[i];
1952           const struct pivot_category *cat = find_category (
1953             dim_series[j], value->width < 0 ? value->d : value->index);
1954           if (!cat)
1955             goto skip;
1956           dim_indexes[j] = cat->data_index;
1957         }
1958
1959       struct pivot_value *value;
1960       error = pivot_value_from_data_value (
1961         &cell->values[i], cell_format ? &cell_format->values[i] : NULL,
1962         &format_map, &value);
1963       if (error)
1964         goto exit;
1965
1966       if (footnotes)
1967         {
1968           const struct spv_data_value *d = &footnotes->values[i];
1969           if (d->width >= 0)
1970             {
1971               const char *p = d->s;
1972               while (*p)
1973                 {
1974                   char *tail;
1975                   int idx = strtol (p, &tail, 10);
1976                   add_footnote (value, idx, table);
1977                   if (tail == p)
1978                     break;
1979                   p = tail;
1980                   if (*p == ',')
1981                     p++;
1982                 }
1983             }
1984         }
1985
1986       if (value->type == PIVOT_VALUE_NUMERIC
1987           && value->numeric.x == SYSMIS
1988           && !value->n_footnotes)
1989         {
1990           /* Apparently, system-missing values are just empty cells? */
1991           pivot_value_destroy (value);
1992         }
1993       else
1994         pivot_table_put (table, dim_indexes, table->n_dimensions, value);
1995     skip:;
1996     }
1997   free (dim_indexes);
1998
1999   decode_set_cell_properties (table, &series_map, v->graph->facet_layout->scp1,
2000                               v->graph->facet_layout->n_scp1);
2001   decode_set_cell_properties (table, &series_map, v->graph->facet_layout->scp2,
2002                               v->graph->facet_layout->n_scp2);
2003
2004   pivot_table_assign_label_depth (table);
2005
2006   format_map_destroy (&format_map);
2007
2008 exit:
2009   free (dim_series);
2010   spv_series_destroy (&series_map);
2011   if (error)
2012     {
2013       pivot_table_unref (table);
2014       *outp = NULL;
2015     }
2016   else
2017     *outp = table;
2018   return error;
2019 }