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