0b224405b7913a297f5236144d4ad804ae4e1edd
[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       if (!value->text.local)
724         value->text.local = xstrdup ("");
725       value->text.c = value->text.id = value->text.local;
726       pivot_value_destroy (*target);
727       *target = value;
728     }
729   else
730     for (size_t i = 0; i < lf->label->n_text; i++)
731       {
732         const struct spvdx_text *in = lf->label->text[i];
733         if (in->uses_reference == INT_MIN)
734           continue;
735         if (i % 2)
736           {
737             size_t length = strlen (in->text);
738             if (length && in->text[length - 1] == '\n')
739               length--;
740
741             pivot_table_create_footnote__ (
742               table, in->uses_reference - 1, NULL,
743               pivot_value_new_user_text (in->text, length));
744           }
745         else
746           {
747             size_t length = strlen (in->text);
748             if (length && in->text[length - 1] == '.')
749               length--;
750
751             pivot_table_create_footnote__ (
752               table, in->uses_reference - 1,
753               pivot_value_new_user_text (in->text, length), NULL);
754           }
755       }
756   return NULL;
757 }
758
759 /* Special return value for decode_spvdx_variable(). */
760 static char BAD_REFERENCE;
761
762 static char * WARN_UNUSED_RESULT
763 decode_spvdx_source_variable (const struct spvxml_node *node,
764                               struct spv_data *data,
765                               struct hmap *series_map)
766 {
767   const struct spvdx_source_variable *sv = spvdx_cast_source_variable (node);
768
769   struct spv_series *label_series = NULL;
770   if (sv->label_variable)
771     {
772       label_series = spv_series_find (series_map,
773                                       sv->label_variable->node_.id);
774       if (!label_series)
775         return &BAD_REFERENCE;
776
777       label_series->is_label_series = true;
778     }
779
780   const struct spv_data_variable *var = spv_data_find_variable (
781     data, sv->source, sv->source_name);
782   if (!var)
783     return xasprintf ("sourceVariable %s references nonexistent "
784                       "source %s variable %s.",
785                       sv->node_.id, sv->source, sv->source_name);
786
787   struct spv_series *s = xzalloc (sizeof *s);
788   s->name = xstrdup (node->id);
789   s->xml = node;
790   s->label = sv->label ? xstrdup (sv->label) : NULL;
791   s->label_series = label_series;
792   s->values = spv_data_values_clone (var->values, var->n_values);
793   s->n_values = var->n_values;
794   s->format = F_8_0;
795   hmap_init (&s->map);
796   hmap_insert (series_map, &s->hmap_node, hash_string (s->name, 0));
797
798   char *error = spv_series_remap_formats (s, sv->seq, sv->n_seq);
799   if (error)
800     return error;
801
802   if (label_series && !s->remapped)
803     {
804       for (size_t i = 0; i < s->n_values; i++)
805         if (s->values[i].width < 0)
806           {
807             char *dest;
808             if (label_series->values[i].width < 0)
809               {
810                 union value v = { .f = label_series->values[i].d };
811                 dest = data_out_stretchy (&v, "UTF-8", &s->format,
812                                           settings_get_fmt_settings (), NULL);
813               }
814             else
815               dest = label_series->values[i].s;
816             char *error = spv_map_insert (&s->map, s->values[i].d,
817                                           dest, false, NULL);
818             free (error);   /* Duplicates are OK. */
819             if (label_series->values[i].width < 0)
820               free (dest);
821           }
822     }
823
824   return NULL;
825 }
826
827 static char * WARN_UNUSED_RESULT
828 decode_spvdx_derived_variable (const struct spvxml_node *node,
829                                struct hmap *series_map)
830 {
831   const struct spvdx_derived_variable *dv = spvdx_cast_derived_variable (node);
832
833   struct spv_data_value *values;
834   size_t n_values;
835
836   struct substring value = ss_cstr (dv->value);
837   if (ss_equals (value, ss_cstr ("constant(0)")))
838     {
839       struct spv_series *existing_series = spv_series_first (series_map);
840       if (!existing_series)
841         return &BAD_REFERENCE;
842
843       n_values = existing_series->n_values;
844       values = XCALLOC (n_values, struct spv_data_value);
845       for (size_t i = 0; i < n_values; i++)
846         values[i].width = -1;
847     }
848   else if (ss_starts_with (value, ss_cstr ("constant(")))
849     {
850       values = NULL;
851       n_values = 0;
852     }
853   else if (ss_starts_with (value, ss_cstr ("map("))
854            && ss_ends_with (value, ss_cstr (")")))
855     {
856       char *dependency_name = ss_xstrdup (ss_substr (value, 4,
857                                                      value.length - 5));
858       struct spv_series *dependency
859         = spv_series_find (series_map, dependency_name);
860       free (dependency_name);
861       if (!dependency)
862         return &BAD_REFERENCE;
863
864       values = spv_data_values_clone (dependency->values,
865                                       dependency->n_values);
866       n_values = dependency->n_values;
867     }
868   else
869     return xasprintf ("Derived variable %s has unknown value \"%s\"",
870                       node->id, dv->value);
871
872   struct spv_series *s = xzalloc (sizeof *s);
873   s->format = F_8_0;
874   s->name = xstrdup (node->id);
875   s->values = values;
876   s->n_values = n_values;
877   hmap_init (&s->map);
878   hmap_insert (series_map, &s->hmap_node, hash_string (s->name, 0));
879
880   char *error = spv_series_remap_vmes (s, dv->value_map_entry,
881                                        dv->n_value_map_entry);
882   if (error)
883     return error;
884
885   error = spv_series_remap_formats (s, dv->seq, dv->n_seq);
886   if (error)
887     return error;
888
889   if (n_values > 0)
890     {
891       for (size_t i = 0; i < n_values; i++)
892         if (values[i].width != 0)
893           goto nonempty;
894       for (size_t i = 0; i < n_values; i++)
895         spv_data_value_uninit (&s->values[i]);
896       free (s->values);
897
898       s->values = NULL;
899       s->n_values = 0;
900
901     nonempty:;
902     }
903   return NULL;
904 }
905
906 struct format_mapping
907   {
908     struct hmap_node hmap_node;
909     uint32_t from;
910     struct fmt_spec to;
911   };
912
913 static const struct format_mapping *
914 format_map_find (const struct hmap *format_map, uint32_t u32_format)
915 {
916   if (format_map)
917     {
918       const struct format_mapping *fm;
919       HMAP_FOR_EACH_IN_BUCKET (fm, struct format_mapping, hmap_node,
920                                hash_int (u32_format, 0), format_map)
921         if (fm->from == u32_format)
922           return fm;
923     }
924
925   return NULL;
926 }
927
928 static char * WARN_UNUSED_RESULT
929 spv_format_from_data_value (const struct spv_data_value *data,
930                             const struct hmap *format_map,
931                             struct fmt_spec *out)
932 {
933   if (!data)
934     {
935       *out = fmt_for_output (FMT_F, 40, 2);
936       return NULL;
937     }
938
939   uint32_t u32_format = data->width < 0 ? data->d : atoi (data->s);
940   const struct format_mapping *fm = format_map_find (format_map, u32_format);
941   if (fm)
942     {
943       *out = fm->to;
944       return NULL;
945     }
946   return spv_decode_fmt_spec (u32_format, out);
947 }
948
949 static char * WARN_UNUSED_RESULT
950 pivot_value_from_data_value (const struct spv_data_value *data,
951                              const struct spv_data_value *format,
952                              const struct hmap *format_map,
953                              struct pivot_value **vp)
954 {
955   *vp = NULL;
956
957   struct fmt_spec f;
958   char *error = spv_format_from_data_value (format, format_map, &f);
959   if (error)
960     return error;
961
962   struct pivot_value *v = xzalloc (sizeof *v);
963   if (data->width >= 0)
964     {
965       if (format && fmt_get_category (f.type) == FMT_CAT_DATE)
966         {
967           int year, month, day, hour, minute, second, msec, len = -1;
968           if (sscanf (data->s, "%4d-%2d-%2dT%2d:%2d:%2d.%3d%n",
969                       &year, &month, &day, &hour, &minute, &second,
970                       &msec, &len) == 7
971               && len == 23
972               && data->s[len] == '\0')
973             {
974               double date = calendar_gregorian_to_offset (
975                 year, month, day, settings_get_fmt_settings (), NULL);
976               if (date != SYSMIS)
977                 {
978                   v->type = PIVOT_VALUE_NUMERIC;
979                   v->numeric.x = (date * 60. * 60. * 24.
980                                   + hour * 60. * 60.
981                                   + minute * 60.
982                                   + second
983                                   + msec / 1000.0);
984                   v->numeric.format = f;
985                   *vp = v;
986                   return NULL;
987                 }
988             }
989         }
990       else if (format && fmt_get_category (f.type) == FMT_CAT_TIME)
991         {
992           int hour, minute, second, msec, len = -1;
993           if (sscanf (data->s, "%d:%2d:%2d.%3d%n",
994                       &hour, &minute, &second, &msec, &len) == 4
995               && len > 0
996               && data->s[len] == '\0')
997             {
998               v->type = PIVOT_VALUE_NUMERIC;
999               v->numeric.x = (hour * 60. * 60.
1000                               + minute * 60.
1001                               + second
1002                               + msec / 1000.0);
1003               v->numeric.format = f;
1004               *vp = v;
1005               return NULL;
1006             }
1007         }
1008       v->type = PIVOT_VALUE_STRING;
1009       v->string.s = xstrdup (data->s);
1010     }
1011   else
1012     {
1013       v->type = PIVOT_VALUE_NUMERIC;
1014       v->numeric.x = data->d;
1015       v->numeric.format = f;
1016     }
1017   *vp = v;
1018   return NULL;
1019 }
1020
1021 static void
1022 add_parents (struct pivot_category *cat, struct pivot_category *parent,
1023              size_t group_index)
1024 {
1025   cat->parent = parent;
1026   cat->group_index = group_index;
1027   if (pivot_category_is_group (cat))
1028     for (size_t i = 0; i < cat->n_subs; i++)
1029       add_parents (cat->subs[i], cat, i);
1030 }
1031
1032 static const struct spvdx_facet_level *
1033 find_facet_level (const struct spvdx_visualization *v, int facet_level)
1034 {
1035   const struct spvdx_facet_layout *layout = v->graph->facet_layout;
1036   for (size_t i = 0; i < layout->n_facet_level; i++)
1037     {
1038       const struct spvdx_facet_level *fl = layout->facet_level[i];
1039       if (facet_level == fl->level)
1040         return fl;
1041     }
1042   return NULL;
1043 }
1044
1045 static bool
1046 should_show_label (const struct spvdx_facet_level *fl)
1047 {
1048   return fl && fl->axis->label && fl->axis->label->style->visible != 0;
1049 }
1050
1051 static size_t
1052 max_category (const struct spv_series *s)
1053 {
1054   double max_cat = -DBL_MAX;
1055   for (size_t i = 0; i < s->n_values; i++)
1056     {
1057       const struct spv_data_value *dv = &s->values[i];
1058       double d = dv->width < 0 ? dv->d : dv->index;
1059       if (d > max_cat)
1060         max_cat = d;
1061     }
1062   assert (max_cat >= 0 && max_cat < SIZE_MAX - 1);
1063
1064   return max_cat;
1065 }
1066
1067 static void
1068 add_affixes (struct pivot_table *table, struct pivot_value *value,
1069              struct spvdx_affix **affixes, size_t n_affixes)
1070 {
1071   for (size_t i = 0; i < n_affixes; i++)
1072     add_footnote (value, affixes[i]->defines_reference, table);
1073 }
1074
1075 static char * WARN_UNUSED_RESULT
1076 add_dimension (struct spv_series **series, size_t n,
1077                enum pivot_axis_type axis_type,
1078                const struct spvdx_visualization *v, struct pivot_table *table,
1079                struct spv_series **dim_seriesp, size_t *n_dim_seriesp,
1080                int base_facet_level, struct pivot_dimension **dp)
1081 {
1082   char *error = NULL;
1083
1084   const struct spvdx_facet_level *fl
1085     = find_facet_level (v, base_facet_level + n);
1086   if (fl)
1087     {
1088       struct table_area_style *area
1089         = (axis_type == PIVOT_AXIS_COLUMN
1090            ? &table->look->areas[PIVOT_AREA_COLUMN_LABELS]
1091            : axis_type == PIVOT_AXIS_ROW
1092            ? &table->look->areas[PIVOT_AREA_ROW_LABELS]
1093            : NULL);
1094       if (area && fl->axis->label)
1095         {
1096           table_area_style_uninit (area);
1097           decode_spvdx_style (fl->axis->label->style,
1098                               fl->axis->label->text_frame_style, area);
1099         }
1100     }
1101
1102   if (axis_type == PIVOT_AXIS_ROW)
1103     {
1104       const struct spvdx_facet_level *fl2
1105         = find_facet_level (v, base_facet_level + (n - 1));
1106       if (fl2)
1107         decode_spvdx_style_incremental (
1108           fl2->axis->major_ticks->style,
1109           fl2->axis->major_ticks->tick_frame_style,
1110           &table->look->areas[PIVOT_AREA_ROW_LABELS]);
1111     }
1112
1113   const struct spvdx_facet_level *fl3 = find_facet_level (v, base_facet_level);
1114   if (fl3 && fl3->axis->major_ticks->label_angle == -90)
1115     {
1116       if (axis_type == PIVOT_AXIS_COLUMN)
1117         table->rotate_inner_column_labels = true;
1118       else
1119         table->rotate_outer_row_labels = true;
1120     }
1121
1122   /* Find the first row for each category. */
1123   size_t max_cat = max_category (series[0]);
1124   size_t *cat_rows = xnmalloc (max_cat + 1, sizeof *cat_rows);
1125   for (size_t k = 0; k <= max_cat; k++)
1126     cat_rows[k] = SIZE_MAX;
1127   for (size_t k = 0; k < series[0]->n_values; k++)
1128     {
1129       const struct spv_data_value *dv = &series[0]->values[k];
1130       double d = dv->width < 0 ? dv->d : dv->index;
1131       if (d >= 0 && d < SIZE_MAX - 1)
1132         {
1133           size_t row = d;
1134           if (cat_rows[row] == SIZE_MAX)
1135             cat_rows[row] = k;
1136         }
1137     }
1138
1139   /* Drop missing categories and count what's left. */
1140   size_t n_cats = 0;
1141   for (size_t k = 0; k <= max_cat; k++)
1142     if (cat_rows[k] != SIZE_MAX)
1143       cat_rows[n_cats++] = cat_rows[k];
1144   assert (n_cats > 0);
1145
1146   /* Make the categories. */
1147   struct pivot_dimension *d = xzalloc (sizeof *d);
1148   table->dimensions[table->n_dimensions++] = d;
1149
1150   series[0]->n_index = max_cat + 1;
1151   series[0]->index_to_category = xcalloc (
1152     max_cat + 1, sizeof *series[0]->index_to_category);
1153   struct pivot_category **cats = xnmalloc (n_cats, sizeof **cats);
1154   for (size_t k = 0; k < n_cats; k++)
1155     {
1156       struct spv_data_value *dv = &series[0]->values[cat_rows[k]];
1157       int dv_num = dv ? dv->d : dv->index;
1158       struct pivot_category *cat = xzalloc (sizeof *cat);
1159       char *retval = pivot_value_from_data_value (
1160         spv_map_lookup (&series[0]->map, dv), NULL, NULL, &cat->name);
1161       if (retval)
1162         {
1163           if (error)
1164             free (retval);
1165           else
1166             error = retval;
1167         }
1168       cat->parent = NULL;
1169       cat->dimension = d;
1170       cat->data_index = k;
1171       cat->presentation_index = cat_rows[k];
1172       cats[k] = cat;
1173       series[0]->index_to_category[dv_num] = cat;
1174
1175       if (cat->name)
1176         add_affixes (table, cat->name,
1177                      series[0]->affixes, series[0]->n_affixes);
1178     }
1179   free (cat_rows);
1180
1181   struct pivot_axis *axis = &table->axes[axis_type];
1182   d->axis_type = axis_type;
1183   d->level = axis->n_dimensions;
1184   d->top_index = table->n_dimensions - 1;
1185   d->root = xzalloc (sizeof *d->root);
1186   *d->root = (struct pivot_category) {
1187     .name = pivot_value_new_user_text (
1188       series[0]->label ? series[0]->label : "", -1),
1189     .dimension = d,
1190     .show_label = should_show_label (fl),
1191     .data_index = SIZE_MAX,
1192     .presentation_index = SIZE_MAX,
1193   };
1194   d->data_leaves = xmemdup (cats, n_cats * sizeof *cats);
1195   d->presentation_leaves = xmemdup (cats, n_cats * sizeof *cats);
1196   d->n_leaves = d->allocated_leaves = n_cats;
1197
1198   /* Now group them, in one pass per grouping variable, innermost first. */
1199   for (size_t j = 1; j < n; j++)
1200     {
1201       struct pivot_category **new_cats = xnmalloc (n_cats, sizeof **cats);
1202       size_t n_new_cats = 0;
1203
1204       /* Allocate a category index. */
1205       size_t max_cat = max_category (series[j]);
1206       series[j]->n_index = max_cat + 1;
1207       series[j]->index_to_category = xcalloc (
1208         max_cat + 1, sizeof *series[j]->index_to_category);
1209       for (size_t cat1 = 0; cat1 < n_cats;)
1210         {
1211           /* Find a sequence of categories cat1...cat2 (exclusive), that all
1212              have the same value in series 'j'.  (This might be only a single
1213              category; we will drop unnamed 1-category groups later.) */
1214           size_t row1 = cats[cat1]->presentation_index;
1215           const struct spv_data_value *dv1 = &series[j]->values[row1];
1216           size_t cat2;
1217           for (cat2 = cat1 + 1; cat2 < n_cats; cat2++)
1218             {
1219               size_t row2 = cats[cat2]->presentation_index;
1220               const struct spv_data_value *dv2 = &series[j]->values[row2];
1221               if (!spv_data_value_equal (dv1, dv2))
1222                 break;
1223             }
1224           size_t n_subs = cat2 - cat1;
1225
1226           struct pivot_category *new_cat;
1227           const struct spv_data_value *name
1228             = spv_map_lookup (&series[j]->map, dv1);
1229           if (n_subs == 1 && name->width == 0)
1230             {
1231               /* The existing category stands on its own. */
1232               new_cat = cats[cat1++];
1233             }
1234           else
1235             {
1236               /* Create a new group with cat...cat2 as subcategories. */
1237               new_cat = xzalloc (sizeof *new_cat);
1238               *new_cat = (struct pivot_category) {
1239                 .dimension = d,
1240                 .subs = xnmalloc (n_subs, sizeof *new_cat->subs),
1241                 .n_subs = n_subs,
1242                 .show_label = true,
1243                 .data_index = SIZE_MAX,
1244                 .presentation_index = row1,
1245               };
1246               char *retval = pivot_value_from_data_value (name, NULL, NULL,
1247                                                           &new_cat->name);
1248               if (retval)
1249                 {
1250                   if (error)
1251                     free (retval);
1252                   else
1253                     error = retval;
1254                 }
1255               for (size_t k = 0; k < n_subs; k++)
1256                 new_cat->subs[k] = cats[cat1++];
1257
1258               int dv1_num = dv1->width < 0 ? dv1->d : dv1->index;
1259               series[j]->index_to_category[dv1_num] = new_cat;
1260             }
1261
1262           if (new_cat->name)
1263             add_affixes (table, new_cat->name,
1264                          series[j]->affixes, series[j]->n_affixes);
1265
1266           /* Append the new group to the list of new groups. */
1267           new_cats[n_new_cats++] = new_cat;
1268         }
1269
1270       free (cats);
1271       cats = new_cats;
1272       n_cats = n_new_cats;
1273     }
1274
1275   /* Now drop unnamed 1-category groups and add parent pointers. */
1276   for (size_t j = 0; j < n_cats; j++)
1277     add_parents (cats[j], d->root, j);
1278   for (size_t j = 0; j < d->n_leaves; j++)
1279     {
1280       d->data_leaves[j]->data_index = j;
1281       d->presentation_leaves[j]->presentation_index = j;
1282     }
1283
1284   d->root->subs = cats;
1285   d->root->n_subs = n_cats;
1286
1287   if (error)
1288     {
1289       pivot_dimension_destroy (d);
1290       return error;
1291     }
1292
1293   dim_seriesp[(*n_dim_seriesp)++] = series[0];
1294   series[0]->dimension = d;
1295
1296   axis->dimensions = xnrealloc (axis->dimensions, axis->n_dimensions + 1,
1297                                sizeof *axis->dimensions);
1298   axis->dimensions[axis->n_dimensions++] = d;
1299   axis->extent *= d->n_leaves;
1300
1301   *dp = d;
1302   return NULL;
1303 }
1304
1305 static char * WARN_UNUSED_RESULT
1306 add_dimensions (struct hmap *series_map, const struct spvdx_nest *nest,
1307                 enum pivot_axis_type axis_type,
1308                 const struct spvdx_visualization *v, struct pivot_table *table,
1309                 struct spv_series **dim_seriesp, size_t *n_dim_seriesp,
1310                 int level_ofs)
1311 {
1312   struct pivot_axis *axis = &table->axes[axis_type];
1313   if (!axis->extent)
1314     axis->extent = 1;
1315
1316   if (!nest)
1317     return NULL;
1318
1319   struct spv_series **series = xnmalloc (nest->n_vars, sizeof *series);
1320   for (size_t i = 0; i < nest->n_vars;)
1321     {
1322       size_t n;
1323       for (n = 0; i + n < nest->n_vars; n++)
1324         {
1325           series[n] = spv_series_from_ref (series_map, nest->vars[i + n]->ref);
1326           if (!series[n] || !series[n]->n_values)
1327             break;
1328         }
1329
1330       if (n > 0)
1331         {
1332           struct pivot_dimension *d;
1333           char *error = add_dimension (series, n, axis_type, v, table,
1334                                        dim_seriesp, n_dim_seriesp,
1335                                        level_ofs + i, &d);
1336           if (error)
1337             {
1338               free (series);
1339               return error;
1340             }
1341         }
1342
1343       i += n + 1;
1344     }
1345   free (series);
1346
1347   return NULL;
1348 }
1349
1350 static char * WARN_UNUSED_RESULT
1351 add_layers (struct hmap *series_map,
1352             struct spvdx_layer **layers, size_t n_layers,
1353             const struct spvdx_visualization *v, struct pivot_table *table,
1354             struct spv_series **dim_seriesp, size_t *n_dim_seriesp,
1355             int level_ofs)
1356 {
1357   struct pivot_axis *axis = &table->axes[PIVOT_AXIS_LAYER];
1358   if (!axis->extent)
1359     axis->extent = 1;
1360
1361   if (!n_layers)
1362     return NULL;
1363
1364   struct spv_series **series = xnmalloc (n_layers, sizeof *series);
1365   for (size_t i = 0; i < n_layers;)
1366     {
1367       size_t n;
1368       for (n = 0; i + n < n_layers; n++)
1369         {
1370           series[n] = spv_series_from_ref (series_map,
1371                                            layers[i + n]->variable);
1372           if (!series[n] || !series[n]->n_values)
1373             break;
1374         }
1375
1376       if (n > 0)
1377         {
1378           struct pivot_dimension *d;
1379           char *error = add_dimension (
1380             series, n, PIVOT_AXIS_LAYER, v, table,
1381             dim_seriesp, n_dim_seriesp, level_ofs + i, &d);
1382           if (error)
1383             {
1384               free (series);
1385               return error;
1386             }
1387
1388           int index = atoi (layers[i]->value);
1389           assert (index < d->n_leaves);
1390           table->current_layer = xrealloc (
1391             table->current_layer,
1392             axis->n_dimensions * sizeof *table->current_layer);
1393           table->current_layer[axis->n_dimensions - 1] = index;
1394         }
1395       i += n + 1;
1396     }
1397   free (series);
1398
1399   return NULL;
1400 }
1401
1402 static struct pivot_category *
1403 find_category (struct spv_series *series, int index)
1404 {
1405   return (index >= 0 && index < series->n_index
1406           ? series->index_to_category[index]
1407           : NULL);
1408 }
1409
1410 static bool
1411 int_in_array (int value, const int *array, size_t n)
1412 {
1413   for (size_t i = 0; i < n; i++)
1414     if (array[i] == value)
1415       return true;
1416
1417   return false;
1418 }
1419
1420 static void
1421 apply_styles_to_value (struct pivot_table *table,
1422                        struct pivot_value *value,
1423                        const struct spvdx_set_format *sf,
1424                        const struct table_area_style *base_area_style,
1425                        const struct spvdx_style *fg,
1426                        const struct spvdx_style *bg)
1427 {
1428   if (sf)
1429     {
1430       if (sf->reset > 0)
1431         {
1432           free (value->footnote_indexes);
1433           value->footnote_indexes = NULL;
1434           value->n_footnotes = 0;
1435         }
1436
1437       struct fmt_spec format = { .w = 0 };
1438       if (sf->format)
1439         {
1440           format = decode_format (sf->format);
1441           add_affixes (table, value, sf->format->affix, sf->format->n_affix);
1442         }
1443       else if (sf->number_format)
1444         {
1445           format = decode_number_format (sf->number_format);
1446           add_affixes (table, value, sf->number_format->affix,
1447                        sf->number_format->n_affix);
1448         }
1449       else if (sf->n_string_format)
1450         {
1451           for (size_t i = 0; i < sf->n_string_format; i++)
1452             add_affixes (table, value, sf->string_format[i]->affix,
1453                          sf->string_format[i]->n_affix);
1454         }
1455       else if (sf->date_time_format)
1456         {
1457           format = decode_date_time_format (sf->date_time_format);
1458           add_affixes (table, value, sf->date_time_format->affix,
1459                        sf->date_time_format->n_affix);
1460         }
1461       else if (sf->elapsed_time_format)
1462         {
1463           format = decode_elapsed_time_format (sf->elapsed_time_format);
1464           add_affixes (table, value, sf->elapsed_time_format->affix,
1465                        sf->elapsed_time_format->n_affix);
1466         }
1467
1468       if (format.w)
1469         {
1470           if (value->type == PIVOT_VALUE_NUMERIC)
1471             value->numeric.format = format;
1472
1473           /* Possibly we should try to apply date and time formats too,
1474              but none seem to occur in practice so far. */
1475         }
1476     }
1477   if (fg || bg)
1478     {
1479       struct table_area_style area;
1480       pivot_value_get_style (
1481         value,
1482         value->font_style ? value->font_style : &base_area_style->font_style,
1483         value->cell_style ? value->cell_style : &base_area_style->cell_style,
1484         &area);
1485       decode_spvdx_style_incremental (fg, bg, &area);
1486       pivot_value_set_style (value, &area);
1487       table_area_style_uninit (&area);
1488     }
1489 }
1490
1491 static void
1492 decode_set_cell_properties__ (struct pivot_table *table,
1493                               struct hmap *series_map,
1494                               const struct spvdx_intersect *intersect,
1495                               const struct spvdx_style *interval,
1496                               const struct spvdx_style *graph,
1497                               const struct spvdx_style *labeling,
1498                               const struct spvdx_style *frame,
1499                               const struct spvdx_style *major_ticks,
1500                               const struct spvdx_set_format *set_format)
1501 {
1502   if (graph && labeling && intersect->alternating
1503       && !interval && !major_ticks && !frame && !set_format)
1504     {
1505       /* Sets alt_fg_color and alt_bg_color. */
1506       struct table_area_style area;
1507       decode_spvdx_style (labeling, graph, &area);
1508       table->look->areas[PIVOT_AREA_DATA].font_style.fg[1]
1509         = area.font_style.fg[0];
1510       table->look->areas[PIVOT_AREA_DATA].font_style.bg[1]
1511         = area.font_style.bg[0];
1512       table_area_style_uninit (&area);
1513     }
1514   else if (graph
1515            && !labeling && !interval && !major_ticks && !frame && !set_format)
1516     {
1517       /* 'graph->width' likely just sets the width of the table as a
1518          whole.  */
1519     }
1520   else if (!graph && !labeling && !interval && !frame && !set_format
1521            && !major_ticks)
1522     {
1523       /* No-op.  (Presumably there's a setMetaData we don't care about.) */
1524     }
1525   else if (((set_format && spvdx_is_major_ticks (set_format->target))
1526             || major_ticks || frame)
1527            && intersect->n_where == 1)
1528     {
1529       /* Formatting for individual row or column labels. */
1530       const struct spvdx_where *w = intersect->where[0];
1531       struct spv_series *s = spv_series_find (series_map, w->variable->id);
1532       assert (s);
1533
1534       const char *p = w->include;
1535
1536       while (*p)
1537         {
1538           char *tail;
1539           int include = strtol (p, &tail, 10);
1540
1541           struct pivot_category *c = find_category (s, include);
1542           if (c)
1543             {
1544               const struct table_area_style *base_area_style
1545                 = (c->dimension->axis_type == PIVOT_AXIS_ROW
1546                    ? &table->look->areas[PIVOT_AREA_ROW_LABELS]
1547                    : &table->look->areas[PIVOT_AREA_COLUMN_LABELS]);
1548               apply_styles_to_value (table, c->name, set_format,
1549                                      base_area_style, major_ticks, frame);
1550             }
1551
1552           if (tail == p)
1553             break;
1554           p = tail;
1555           if (*p == ';')
1556             p++;
1557         }
1558     }
1559   else if ((set_format && spvdx_is_labeling (set_format->target))
1560            || labeling || interval)
1561     {
1562       /* Formatting for individual cells or groups of them with some dimensions
1563          in common. */
1564       int **indexes = XCALLOC (table->n_dimensions, int *);
1565       size_t *n = XCALLOC (table->n_dimensions, size_t);
1566       size_t *allocated = XCALLOC (table->n_dimensions, size_t);
1567
1568       for (size_t i = 0; i < intersect->n_where; i++)
1569         {
1570           const struct spvdx_where *w = intersect->where[i];
1571           struct spv_series *s = spv_series_find (series_map, w->variable->id);
1572           assert (s);
1573           if (!s->dimension)
1574             {
1575               /* Group indexes may be included even though they are redundant.
1576                  Ignore them. */
1577               continue;
1578             }
1579
1580           size_t j = s->dimension->top_index;
1581
1582           const char *p = w->include;
1583           while (*p)
1584             {
1585               char *tail;
1586               int include = strtol (p, &tail, 10);
1587
1588               struct pivot_category *c = find_category (s, include);
1589               if (c)
1590                 {
1591                   if (n[j] >= allocated[j])
1592                     indexes[j] = x2nrealloc (indexes[j], &allocated[j],
1593                                              sizeof *indexes[j]);
1594                   indexes[j][n[j]++] = c->data_index;
1595                 }
1596
1597               if (tail == p)
1598                 break;
1599               p = tail;
1600               if (*p == ';')
1601                 p++;
1602             }
1603         }
1604
1605 #if 0
1606       printf ("match:");
1607       for (size_t i = 0; i < table->n_dimensions; i++)
1608         {
1609           if (n[i])
1610             {
1611               printf (" %d=(", i);
1612               for (size_t j = 0; j < n[i]; j++)
1613                 {
1614                   if (j)
1615                     putchar (',');
1616                   printf ("%d", indexes[i][j]);
1617                 }
1618               putchar (')');
1619             }
1620         }
1621       printf ("\n");
1622 #endif
1623
1624       /* XXX This is inefficient in the common case where all of the dimensions
1625          are matched.  We should use a heuristic where if all of the dimensions
1626          are matched and the product of n[*] is less than
1627          hmap_count(&table->cells) then iterate through all the possibilities
1628          rather than all the cells.  Or even only do it if there is just one
1629          possibility. */
1630
1631       struct pivot_cell *cell;
1632       HMAP_FOR_EACH (cell, struct pivot_cell, hmap_node, &table->cells)
1633         {
1634           for (size_t i = 0; i < table->n_dimensions; i++)
1635             {
1636               if (n[i] && !int_in_array (cell->idx[i], indexes[i], n[i]))
1637                 goto skip;
1638             }
1639           apply_styles_to_value (table, cell->value, set_format,
1640                                  &table->look->areas[PIVOT_AREA_DATA],
1641                                  labeling, interval);
1642
1643         skip: ;
1644         }
1645
1646       for (size_t i = 0; i < table->n_dimensions; i++)
1647         free (indexes[i]);
1648       free (indexes);
1649       free (n);
1650       free (allocated);
1651     }
1652   else
1653     NOT_REACHED ();
1654 }
1655
1656 static void
1657 decode_set_cell_properties (struct pivot_table *table, struct hmap *series_map,
1658                             struct spvdx_set_cell_properties **scps,
1659                             size_t n_scps)
1660 {
1661   for (size_t i = 0; i < n_scps; i++)
1662     {
1663       const struct spvdx_set_cell_properties *scp = scps[i];
1664       const struct spvdx_style *interval = NULL;
1665       const struct spvdx_style *graph = NULL;
1666       const struct spvdx_style *labeling = NULL;
1667       const struct spvdx_style *frame = NULL;
1668       const struct spvdx_style *major_ticks = NULL;
1669       const struct spvdx_set_format *set_format = NULL;
1670       for (size_t j = 0; j < scp->n_seq; j++)
1671         {
1672           const struct spvxml_node *node = scp->seq[j];
1673           if (spvdx_is_set_style (node))
1674             {
1675               const struct spvdx_set_style *set_style
1676                 = spvdx_cast_set_style (node);
1677               if (spvdx_is_graph (set_style->target))
1678                 graph = set_style->style;
1679               else if (spvdx_is_labeling (set_style->target))
1680                 labeling = set_style->style;
1681               else if (spvdx_is_interval (set_style->target))
1682                 interval = set_style->style;
1683               else if (spvdx_is_major_ticks (set_style->target))
1684                 major_ticks = set_style->style;
1685               else
1686                 NOT_REACHED ();
1687             }
1688           else if (spvdx_is_set_frame_style (node))
1689             frame = spvdx_cast_set_frame_style (node)->style;
1690           else if (spvdx_is_set_format (node))
1691             set_format = spvdx_cast_set_format (node);
1692           else
1693             assert (spvdx_is_set_meta_data (node));
1694         }
1695
1696       if (scp->union_ && scp->apply_to_converse <= 0)
1697         {
1698           for (size_t j = 0; j < scp->union_->n_intersect; j++)
1699             decode_set_cell_properties__ (
1700               table, series_map, scp->union_->intersect[j],
1701               interval, graph, labeling, frame, major_ticks, set_format);
1702         }
1703       else if (!scp->union_ && scp->apply_to_converse > 0)
1704         {
1705           if ((set_format && spvdx_is_labeling (set_format->target))
1706               || labeling || interval)
1707             {
1708               struct pivot_cell *cell;
1709               HMAP_FOR_EACH (cell, struct pivot_cell, hmap_node, &table->cells)
1710                 apply_styles_to_value (table, cell->value, set_format,
1711                                        &table->look->areas[PIVOT_AREA_DATA],
1712                                        NULL, NULL);
1713             }
1714         }
1715       else if (!scp->union_ && scp->apply_to_converse <= 0)
1716         {
1717           /* Appears to be used to set the font for something--but what? */
1718         }
1719       else
1720         NOT_REACHED ();
1721     }
1722 }
1723
1724 static struct spv_series *
1725 parse_formatting (const struct spvdx_visualization *v,
1726                   const struct hmap *series_map, struct hmap *format_map)
1727 {
1728   const struct spvdx_labeling *labeling = v->graph->interval->labeling;
1729   struct spv_series *cell_format = NULL;
1730   for (size_t i = 0; i < labeling->n_seq; i++)
1731     {
1732       const struct spvdx_formatting *f
1733         = spvdx_cast_formatting (labeling->seq[i]);
1734       if (!f)
1735         continue;
1736
1737       cell_format = spv_series_from_ref (series_map, f->variable);
1738       for (size_t j = 0; j < f->n_format_mapping; j++)
1739         {
1740           const struct spvdx_format_mapping *fm = f->format_mapping[j];
1741
1742           if (fm->format)
1743             {
1744               struct format_mapping *out = xmalloc (sizeof *out);
1745               out->from = fm->from;
1746               out->to = decode_format (fm->format);
1747               hmap_insert (format_map, &out->hmap_node,
1748                            hash_int (out->from, 0));
1749             }
1750         }
1751     }
1752
1753   return cell_format;
1754 }
1755
1756 static void
1757 format_map_destroy (struct hmap *format_map)
1758 {
1759   struct format_mapping *fm, *next;
1760   HMAP_FOR_EACH_SAFE (fm, next, struct format_mapping, hmap_node, format_map)
1761     {
1762       hmap_delete (format_map, &fm->hmap_node);
1763       free (fm);
1764     }
1765   hmap_destroy (format_map);
1766 }
1767
1768 char * WARN_UNUSED_RESULT
1769 decode_spvdx_table (const struct spvdx_visualization *v, const char *subtype,
1770                     const struct pivot_table_look *look,
1771                     struct spv_data *data, struct pivot_table **outp)
1772 {
1773   struct pivot_table *table = pivot_table_create__ (NULL, subtype);
1774
1775   pivot_table_set_look (table, look);
1776   table->look = pivot_table_look_unshare (table->look);
1777
1778   struct hmap series_map = HMAP_INITIALIZER (series_map);
1779   struct hmap format_map = HMAP_INITIALIZER (format_map);
1780   struct spv_series **dim_series = NULL;
1781   char *error;
1782
1783   struct spvdx_visualization_extension *ve = v->visualization_extension;
1784   table->show_grid_lines = ve && ve->show_gridline;
1785
1786   /* Sizing from the legacy properties can get overridden. */
1787   if (v->graph->cell_style->width)
1788     {
1789       int min_width, max_width, n = 0;
1790       if (sscanf (v->graph->cell_style->width, "%*d%%;%dpt;%dpt%n",
1791                   &min_width, &max_width, &n)
1792           && v->graph->cell_style->width[n] == '\0')
1793         {
1794           table->look->width_ranges[TABLE_HORZ][0] = min_width;
1795           table->look->width_ranges[TABLE_HORZ][1] = max_width;
1796         }
1797     }
1798
1799   /* Footnotes.
1800
1801      Any pivot_value might refer to footnotes, so it's important to process the
1802      footnotes early to ensure that those references can be resolved.  There is
1803      a possible problem that a footnote might itself reference an
1804      as-yet-unprocessed footnote, but that's OK because footnote references
1805      don't actually look at the footnote contents but only resolve a pointer to
1806      where the footnote will go later.
1807
1808      Before we really start, create all the footnotes we'll fill in.  This is
1809      because sometimes footnotes refer to themselves or to each other and we
1810      don't want to reject those references. */
1811   if (v->container)
1812     for (size_t i = 0; i < v->container->n_label_frame; i++)
1813       {
1814         const struct spvdx_label_frame *lf = v->container->label_frame[i];
1815         if (lf->label
1816             && lf->label->purpose == SPVDX_PURPOSE_FOOTNOTE
1817             && lf->label->n_text > 0
1818             && lf->label->text[0]->uses_reference > 0)
1819           {
1820             pivot_table_create_footnote__ (
1821               table, lf->label->text[0]->uses_reference - 1,
1822               NULL, NULL);
1823           }
1824       }
1825
1826   if (v->graph->interval->footnotes)
1827     decode_footnotes (table, v->graph->interval->footnotes);
1828
1829   struct spv_series *footnotes = NULL;
1830   for (size_t i = 0; i < v->graph->interval->labeling->n_seq; i++)
1831     {
1832       const struct spvxml_node *node = v->graph->interval->labeling->seq[i];
1833       if (spvdx_is_footnotes (node))
1834         {
1835           const struct spvdx_footnotes *f = spvdx_cast_footnotes (node);
1836           footnotes = spv_series_from_ref (&series_map, f->variable);
1837           decode_footnotes (table, f);
1838         }
1839     }
1840   for (size_t i = 0; i < v->n_lf1; i++)
1841     {
1842       error = decode_label_frame (table, v->lf1[i]);
1843       if (error)
1844         goto exit;
1845     }
1846   for (size_t i = 0; i < v->n_lf2; i++)
1847     {
1848       error = decode_label_frame (table, v->lf2[i]);
1849       if (error)
1850         goto exit;
1851     }
1852   if (v->container)
1853     for (size_t i = 0; i < v->container->n_label_frame; i++)
1854       {
1855         error = decode_label_frame (table, v->container->label_frame[i]);
1856         if (error)
1857           goto exit;
1858       }
1859   if (v->graph->interval->labeling->style)
1860     {
1861       table_area_style_uninit (&table->look->areas[PIVOT_AREA_DATA]);
1862       decode_spvdx_style (v->graph->interval->labeling->style,
1863                           v->graph->cell_style,
1864                           &table->look->areas[PIVOT_AREA_DATA]);
1865     }
1866
1867   /* Decode all of the sourceVariable and derivedVariable  */
1868   struct spvxml_node **nodes = xmemdup (v->seq, v->n_seq * sizeof *v->seq);
1869   size_t n_nodes = v->n_seq;
1870   while (n_nodes > 0)
1871     {
1872       bool progress = false;
1873       for (size_t i = 0; i < n_nodes;)
1874         {
1875           error = (spvdx_is_source_variable (nodes[i])
1876                    ? decode_spvdx_source_variable (nodes[i], data, &series_map)
1877                    : decode_spvdx_derived_variable (nodes[i], &series_map));
1878           if (!error)
1879             {
1880               nodes[i] = nodes[--n_nodes];
1881               progress = true;
1882             }
1883           else if (error == &BAD_REFERENCE)
1884             i++;
1885           else
1886             {
1887               free (nodes);
1888               goto exit;
1889             }
1890         }
1891
1892       if (!progress)
1893         {
1894           free (nodes);
1895           error = xasprintf ("Table has %zu variables with circular or "
1896                              "unresolved references, including variable %s.",
1897                              n_nodes, nodes[0]->id);
1898           goto exit;
1899         }
1900     }
1901   free (nodes);
1902
1903   const struct spvdx_cross *cross = v->graph->faceting->cross;
1904
1905   assert (cross->n_seq == 1);
1906   const struct spvdx_nest *columns = spvdx_cast_nest (cross->seq[0]);
1907   size_t max_columns = columns ? columns->n_vars : 0;
1908
1909   assert (cross->n_seq2 == 1);
1910   const struct spvdx_nest *rows = spvdx_cast_nest (cross->seq2[0]);
1911   size_t max_rows = rows ? rows->n_vars : 0;
1912
1913   size_t max_layers = (v->graph->faceting->n_layers1
1914                        + v->graph->faceting->n_layers2);
1915
1916   size_t max_dims = max_columns + max_rows + max_layers;
1917   table->dimensions = xnmalloc (max_dims, sizeof *table->dimensions);
1918   dim_series = xnmalloc (max_dims, sizeof *dim_series);
1919   size_t n_dim_series = 0;
1920
1921   error = add_dimensions (&series_map, columns, PIVOT_AXIS_COLUMN, v, table,
1922                           dim_series, &n_dim_series, 1);
1923   if (error)
1924     goto exit;
1925
1926   error = add_dimensions (&series_map, rows, PIVOT_AXIS_ROW, v, table,
1927                           dim_series, &n_dim_series, max_columns + 1);
1928   if (error)
1929     goto exit;
1930
1931   error = add_layers (&series_map, v->graph->faceting->layers1,
1932                       v->graph->faceting->n_layers1,
1933                       v, table, dim_series, &n_dim_series,
1934                       max_rows + max_columns + 1);
1935   if (error)
1936     goto exit;
1937
1938   error = add_layers (&series_map, v->graph->faceting->layers2,
1939                       v->graph->faceting->n_layers2,
1940                       v, table, dim_series, &n_dim_series,
1941                       (max_rows + max_columns + v->graph->faceting->n_layers1
1942                        + 1));
1943   if (error)
1944     goto exit;
1945
1946   struct spv_series *cell = spv_series_find (&series_map, "cell");
1947   if (!cell)
1948     {
1949       error = xstrdup (_("Table lacks cell data."));
1950       goto exit;
1951     }
1952
1953   struct spv_series *cell_format = parse_formatting (v, &series_map,
1954                                                      &format_map);
1955
1956   assert (table->n_dimensions == n_dim_series);
1957   size_t *dim_indexes = xnmalloc (table->n_dimensions, sizeof *dim_indexes);
1958   for (size_t i = 0; i < cell->n_values; i++)
1959     {
1960       for (size_t j = 0; j < table->n_dimensions; j++)
1961         {
1962           const struct spv_data_value *value = &dim_series[j]->values[i];
1963           const struct pivot_category *cat = find_category (
1964             dim_series[j], value->width < 0 ? value->d : value->index);
1965           if (!cat)
1966             goto skip;
1967           dim_indexes[j] = cat->data_index;
1968         }
1969
1970       struct pivot_value *value;
1971       error = pivot_value_from_data_value (
1972         &cell->values[i], cell_format ? &cell_format->values[i] : NULL,
1973         &format_map, &value);
1974       if (error)
1975         goto exit;
1976
1977       if (footnotes)
1978         {
1979           const struct spv_data_value *d = &footnotes->values[i];
1980           if (d->width >= 0)
1981             {
1982               const char *p = d->s;
1983               while (*p)
1984                 {
1985                   char *tail;
1986                   int idx = strtol (p, &tail, 10);
1987                   add_footnote (value, idx, table);
1988                   if (tail == p)
1989                     break;
1990                   p = tail;
1991                   if (*p == ',')
1992                     p++;
1993                 }
1994             }
1995         }
1996
1997       if (value->type == PIVOT_VALUE_NUMERIC
1998           && value->numeric.x == SYSMIS
1999           && !value->n_footnotes)
2000         {
2001           /* Apparently, system-missing values are just empty cells? */
2002           pivot_value_destroy (value);
2003         }
2004       else
2005         pivot_table_put (table, dim_indexes, table->n_dimensions, value);
2006     skip:;
2007     }
2008   free (dim_indexes);
2009
2010   decode_set_cell_properties (table, &series_map, v->graph->facet_layout->scp1,
2011                               v->graph->facet_layout->n_scp1);
2012   decode_set_cell_properties (table, &series_map, v->graph->facet_layout->scp2,
2013                               v->graph->facet_layout->n_scp2);
2014
2015   pivot_table_assign_label_depth (table);
2016
2017   format_map_destroy (&format_map);
2018
2019 exit:
2020   free (dim_series);
2021   spv_series_destroy (&series_map);
2022   if (error)
2023     {
2024       pivot_table_unref (table);
2025       *outp = NULL;
2026     }
2027   else
2028     *outp = table;
2029   return error;
2030 }