1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2017, 2018 Free Software Foundation, Inc.
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.
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.
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/>. */
19 #include "output/spv/spv-light-decoder.h"
26 #include "libpspp/i18n.h"
27 #include "libpspp/message.h"
28 #include "libpspp/string-array.h"
29 #include "output/pivot-table.h"
30 #include "output/spv/light-binary-parser.h"
31 #include "output/spv/spv.h"
33 #include "gl/xalloc.h"
37 xstrdup_if_nonempty (const char *s)
39 return s && s[0] ? xstrdup (s) : NULL;
43 convert_widths (const uint32_t *in, uint32_t n, int **out, size_t *n_out)
48 *out = xnmalloc (n, sizeof **out);
49 for (size_t i = 0; i < n; i++)
55 convert_breakpoints (const struct spvlb_breakpoints *in,
56 size_t **out, size_t *n_out)
58 if (in && in->n_breaks)
60 *n_out = in->n_breaks;
61 *out = xnmalloc (in->n_breaks, sizeof *out);
62 for (size_t i = 0; i < in->n_breaks; i++)
63 (*out)[i] = in->breaks[i];
68 convert_keeps (const struct spvlb_keeps *in,
69 struct pivot_keep **out, size_t *n_out)
71 if (in && in->n_keeps)
74 *out = xnmalloc (*n_out, sizeof **out);
75 for (size_t i = 0; i < *n_out; i++)
77 (*out)[i].ofs = in->keeps[i]->offset;
78 (*out)[i].n = in->keeps[i]->n;
83 static char * WARN_UNUSED_RESULT
84 decode_spvlb_color_string (const char *s, uint8_t def,
85 struct cell_color *colorp)
90 else if (sscanf (s, "#%2x%2x%2x", &r, &g, &b) != 3)
91 return xasprintf ("bad color %s", s);
93 *colorp = (struct cell_color) CELL_COLOR (r, g, b);
97 static struct cell_color
98 decode_spvlb_color_u32 (uint32_t x)
100 return (struct cell_color) { x >> 24, x >> 16, x >> 8, x };
103 static char * WARN_UNUSED_RESULT
104 decode_spvlb_font_style (const struct spvlb_font_style *in,
105 struct font_style **outp)
113 struct cell_color fg, bg;
114 char *error = decode_spvlb_color_string (in->fg_color, 0x00, &fg);
116 error = decode_spvlb_color_string (in->bg_color, 0xff, &bg);
120 *outp = xmalloc (sizeof **outp);
121 **outp = (struct font_style) {
123 .italic = in->italic,
124 .underline = in->underline,
127 .typeface = xstrdup (in->typeface),
128 .size = in->size / 1.33,
133 static char * WARN_UNUSED_RESULT
134 decode_spvlb_halign (uint32_t in, enum table_halign *halignp)
139 *halignp = TABLE_HALIGN_CENTER;
143 *halignp = TABLE_HALIGN_LEFT;
147 *halignp = TABLE_HALIGN_RIGHT;
152 *halignp = TABLE_HALIGN_DECIMAL;
157 *halignp = TABLE_HALIGN_MIXED;
161 return xasprintf ("bad cell style halign %"PRIu32, in);
165 static char * WARN_UNUSED_RESULT
166 decode_spvlb_valign (uint32_t in, enum table_valign *valignp)
171 *valignp = TABLE_VALIGN_CENTER;
175 *valignp = TABLE_VALIGN_TOP;
179 *valignp = TABLE_VALIGN_BOTTOM;
184 return xasprintf ("bad cell style valign %"PRIu32, in);
188 static char * WARN_UNUSED_RESULT
189 decode_spvlb_cell_style (const struct spvlb_cell_style *in,
190 struct cell_style **outp)
198 enum table_halign halign;
199 char *error = decode_spvlb_halign (in->halign, &halign);
203 enum table_valign valign;
204 error = decode_spvlb_valign (in->valign, &valign);
208 *outp = xzalloc (sizeof **outp);
209 **outp = (struct cell_style) {
212 .decimal_offset = in->decimal_offset,
214 [TABLE_HORZ] = { in->left_margin, in->right_margin },
215 [TABLE_VERT] = { in->top_margin, in->bottom_margin },
221 static char *decode_spvlb_value (
222 const struct pivot_table *, const struct spvlb_value *,
223 struct pivot_value **) WARN_UNUSED_RESULT;
225 static char * WARN_UNUSED_RESULT
226 decode_spvlb_argument (const struct pivot_table *table,
227 const struct spvlb_argument *in,
228 struct pivot_argument *out)
232 struct pivot_value *value;
233 char *error = decode_spvlb_value (table, in->value, &value);
238 out->values = xmalloc (sizeof *out->values);
239 out->values[0] = value;
244 out->values = xnmalloc (in->n_values, sizeof *out->values);
245 for (size_t i = 0; i < in->n_values; i++)
247 char *error = decode_spvlb_value (table, in->values[i],
251 pivot_argument_uninit (out);
261 static char * WARN_UNUSED_RESULT
262 decode_spvlb_value_show (uint8_t in, enum settings_value_show *out)
266 case 0: *out = SETTINGS_VALUE_SHOW_DEFAULT; return NULL;
267 case 1: *out = SETTINGS_VALUE_SHOW_VALUE; return NULL;
268 case 2: *out = SETTINGS_VALUE_SHOW_LABEL; return NULL;
269 case 3: *out = SETTINGS_VALUE_SHOW_BOTH; return NULL;
271 return xasprintf ("bad value show %"PRIu8, in);
275 static char * WARN_UNUSED_RESULT
276 decode_spvlb_value (const struct pivot_table *table,
277 const struct spvlb_value *in, struct pivot_value **outp)
281 struct pivot_value *out = xzalloc (sizeof *out);
282 const struct spvlb_value_mod *vm;
288 vm = in->type_01.value_mod;
289 out->type = PIVOT_VALUE_NUMERIC;
290 out->numeric.x = in->type_01.x;
291 error = spv_decode_fmt_spec (in->type_01.format, &out->numeric.format);
297 vm = in->type_02.value_mod;
298 out->type = PIVOT_VALUE_NUMERIC;
299 out->numeric.x = in->type_02.x;
300 error = spv_decode_fmt_spec (in->type_02.format, &out->numeric.format);
302 error = decode_spvlb_value_show (in->type_02.show, &out->numeric.show);
305 out->numeric.var_name = xstrdup_if_nonempty (in->type_02.var_name);
306 out->numeric.value_label = xstrdup_if_nonempty (in->type_02.value_label);
310 vm = in->type_03.value_mod;
311 out->type = PIVOT_VALUE_TEXT;
312 out->text.local = xstrdup (in->type_03.local);
313 out->text.c = xstrdup (in->type_03.c);
314 out->text.id = xstrdup (in->type_03.id);
315 out->text.user_provided = !in->type_03.fixed;
319 vm = in->type_04.value_mod;
320 out->type = PIVOT_VALUE_STRING;
321 error = decode_spvlb_value_show (in->type_04.show, &out->string.show);
324 out->string.s = xstrdup (in->type_04.s);
325 out->string.hex = (in->type_04.format >> 16) == fmt_to_io (FMT_AHEX);
326 out->string.var_name = xstrdup (in->type_04.var_name);
327 out->string.value_label = xstrdup_if_nonempty (in->type_04.value_label);
331 vm = in->type_05.value_mod;
332 out->type = PIVOT_VALUE_VARIABLE;
333 error = decode_spvlb_value_show (in->type_05.show, &out->variable.show);
336 out->variable.var_name = xstrdup (in->type_05.var_name);
337 out->variable.var_label = xstrdup_if_nonempty (in->type_05.var_label);
341 vm = in->type_06.value_mod;
342 out->type = PIVOT_VALUE_TEXT;
343 out->text.local = xstrdup (in->type_06.local);
344 out->text.c = xstrdup (in->type_06.c);
345 out->text.id = xstrdup (in->type_06.id);
346 out->text.user_provided = false;
350 vm = in->type_else.value_mod;
351 out->type = PIVOT_VALUE_TEMPLATE;
352 out->template.local = xstrdup (in->type_else.template);
353 out->template.id = out->template.local;
354 out->template.n_args = 0;
355 out->template.args = xnmalloc (in->type_else.n_args,
356 sizeof *out->template.args);
357 for (size_t i = 0; i < in->type_else.n_args; i++)
359 error = decode_spvlb_argument (table, in->type_else.args[i],
360 &out->template.args[i]);
363 pivot_value_destroy (out);
366 out->template.n_args++;
376 if (vm->n_subscripts)
378 out->n_subscripts = vm->n_subscripts;
379 out->subscripts = xnmalloc (vm->n_subscripts,
380 sizeof *out->subscripts);
381 for (size_t i = 0; i < vm->n_subscripts; i++)
382 out->subscripts[i] = xstrdup (vm->subscripts[i]);
387 out->footnote_indexes = xnmalloc (vm->n_refs,
388 sizeof *out->footnote_indexes);
389 for (size_t i = 0; i < vm->n_refs; i++)
391 uint16_t idx = vm->refs[i];
392 if (idx >= table->n_footnotes)
394 pivot_value_destroy (out);
395 return xasprintf ("bad footnote index: %"PRIu16" >= %zu",
396 idx, table->n_footnotes);
399 out->footnote_indexes[out->n_footnotes++] = idx;
405 error = decode_spvlb_font_style (vm->style_pair->font_style,
408 error = decode_spvlb_cell_style (vm->style_pair->cell_style,
412 pivot_value_destroy (out);
417 if (vm->template_string
418 && vm->template_string->id
419 && vm->template_string->id[0]
420 && out->type == PIVOT_VALUE_TEMPLATE)
421 out->template.id = xstrdup (vm->template_string->id);
428 static char * WARN_UNUSED_RESULT
429 decode_spvlb_area (const struct spvlb_area *in, struct table_area_style *out)
433 struct cell_color fg0, fg1, bg0, bg1;
434 error = decode_spvlb_color_string (in->fg_color, 0x00, &fg0);
436 error = decode_spvlb_color_string (in->bg_color, 0xff, &bg0);
437 if (!error && in->alternate)
438 error = decode_spvlb_color_string (in->alt_fg_color, 0x00, &fg1);
439 if (!error && in->alternate)
440 error = decode_spvlb_color_string (in->alt_bg_color, 0xff, &bg1);
442 enum table_halign halign;
445 error = decode_spvlb_halign (in->halign, &halign);
447 /* TABLE_HALIGN_DECIMAL doesn't seem to be a real halign for areas, which
448 is good because there's no way to indicate the decimal offset. Just
450 if (!error && halign == TABLE_HALIGN_DECIMAL)
451 halign = TABLE_HALIGN_MIXED;
454 enum table_valign valign;
456 error = decode_spvlb_valign (in->valign, &valign);
461 table_area_style_uninit (out);
462 *out = (struct table_area_style) {
464 .bold = (in->style & 1) != 0,
465 .italic = (in->style & 2) != 0,
466 .underline = in->underline,
467 .fg = { fg0, in->alternate ? fg1 : fg0 },
468 .bg = { bg0, in->alternate ? bg1 : bg0 },
469 .typeface = xstrdup (in->typeface),
470 .size = in->size / 1.33,
476 [TABLE_HORZ] = { in->left_margin, in->right_margin },
477 [TABLE_VERT] = { in->top_margin, in->bottom_margin },
484 static char * WARN_UNUSED_RESULT
485 decode_spvlb_group (const struct pivot_table *,
486 struct spvlb_category **,
489 struct pivot_category *parent,
490 struct pivot_dimension *);
492 static char * WARN_UNUSED_RESULT
493 decode_spvlb_categories (const struct pivot_table *table,
494 struct spvlb_category **categories,
496 struct pivot_category *parent,
497 struct pivot_dimension *dimension)
499 for (size_t i = 0; i < n_categories; i++)
501 const struct spvlb_category *in = categories[i];
502 if (in->group && in->group->merge)
504 char *error = decode_spvlb_categories (
505 table, in->group->subcategories, in->group->n_subcategories,
513 struct pivot_value *name;
514 char *error = decode_spvlb_value (table, in->name, &name);
518 struct pivot_category *out = xzalloc (sizeof *out);
520 out->parent = parent;
521 out->dimension = dimension;
524 char *error = decode_spvlb_group (table, in->group->subcategories,
525 in->group->n_subcategories,
526 true, out, dimension);
529 pivot_category_destroy (out);
533 out->data_index = SIZE_MAX;
534 out->presentation_index = SIZE_MAX;
538 out->data_index = in->leaf->leaf_index;
539 out->presentation_index = dimension->n_leaves;
540 dimension->n_leaves++;
543 if (parent->n_subs >= parent->allocated_subs)
544 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
545 sizeof *parent->subs);
546 parent->subs[parent->n_subs++] = out;
551 static char * WARN_UNUSED_RESULT
552 decode_spvlb_group (const struct pivot_table *table,
553 struct spvlb_category **categories,
554 size_t n_categories, bool show_label,
555 struct pivot_category *category,
556 struct pivot_dimension *dimension)
558 category->subs = XCALLOC (n_categories, struct pivot_category *);
559 category->n_subs = 0;
560 category->allocated_subs = 0;
561 category->show_label = show_label;
563 return decode_spvlb_categories (table, categories, n_categories, category,
567 static char * WARN_UNUSED_RESULT
568 fill_leaves (struct pivot_category *category,
569 struct pivot_dimension *dimension)
571 if (pivot_category_is_group (category))
573 for (size_t i = 0; i < category->n_subs; i++)
575 char *error = fill_leaves (category->subs[i], dimension);
582 if (category->data_index >= dimension->n_leaves)
583 return xasprintf ("leaf_index %zu >= n_leaves %zu",
584 category->data_index, dimension->n_leaves);
585 if (dimension->data_leaves[category->data_index])
586 return xasprintf ("two leaves with data_index %zu",
587 category->data_index);
588 dimension->data_leaves[category->data_index] = category;
589 dimension->presentation_leaves[category->presentation_index] = category;
594 static char * WARN_UNUSED_RESULT
595 decode_spvlb_dimension (const struct pivot_table *table,
596 const struct spvlb_dimension *in,
597 size_t idx, struct pivot_dimension **outp)
599 /* Convert most of the dimension. */
600 struct pivot_value *name;
601 char *error = decode_spvlb_value (table, in->name, &name);
605 struct pivot_dimension *out = xzalloc (sizeof *out);
606 out->level = UINT_MAX;
607 out->top_index = idx;
608 out->hide_all_labels = in->props->hide_all_labels;
610 out->root = xzalloc (sizeof *out->root);
611 *out->root = (struct pivot_category) {
614 .data_index = SIZE_MAX,
615 .presentation_index = SIZE_MAX,
617 error = decode_spvlb_group (table, in->categories, in->n_categories,
618 !in->props->hide_dim_label, out->root,
623 /* Allocate and fill the array of leaves now that we know how many there
625 out->data_leaves = XCALLOC (out->n_leaves, struct pivot_category *);
626 out->presentation_leaves = XCALLOC (out->n_leaves, struct pivot_category *);
627 out->allocated_leaves = out->n_leaves;
628 error = fill_leaves (out->root, out);
631 for (size_t i = 0; i < out->n_leaves; i++)
633 assert (out->data_leaves[i] != NULL);
634 assert (out->presentation_leaves[i] != NULL);
640 pivot_dimension_destroy (out);
644 static char * WARN_UNUSED_RESULT
645 decode_spvlb_stroke (uint32_t stroke_type, enum table_stroke *strokep)
647 enum table_stroke strokes[] = {
656 if (stroke_type >= sizeof strokes / sizeof *strokes)
657 return xasprintf ("bad stroke %"PRIu32, stroke_type);
659 *strokep = strokes[stroke_type];
663 static char * WARN_UNUSED_RESULT
664 decode_spvlb_border (const struct spvlb_border *in, struct pivot_table *table)
667 if (in->border_type >= PIVOT_N_BORDERS)
668 return xasprintf ("bad border type %"PRIu32, in->border_type);
670 struct table_border_style *out = &table->look->borders[in->border_type];
671 out->color = decode_spvlb_color_u32 (in->color);
672 return decode_spvlb_stroke (in->stroke_type, &out->stroke);
675 static char * WARN_UNUSED_RESULT
676 decode_spvlb_axis (const uint32_t *dimension_indexes, size_t n_dimensions,
677 enum pivot_axis_type axis_type, struct pivot_table *table)
679 struct pivot_axis *axis = &table->axes[axis_type];
680 axis->dimensions = XCALLOC (n_dimensions, struct pivot_dimension *);
681 axis->n_dimensions = n_dimensions;
683 for (size_t i = 0; i < n_dimensions; i++)
685 uint32_t idx = dimension_indexes[i];
686 if (idx >= table->n_dimensions)
687 return xasprintf ("bad dimension index %"PRIu32" >= %zu",
688 idx, table->n_dimensions);
690 struct pivot_dimension *d = table->dimensions[idx];
691 if (d->level != UINT_MAX)
692 return xasprintf ("duplicate dimension %"PRIu32, idx);
694 axis->dimensions[i] = d;
695 d->axis_type = axis_type;
698 axis->extent *= d->n_leaves;
705 decode_data_index (uint64_t in, const struct pivot_table *table,
708 uint64_t remainder = in;
709 for (size_t i = table->n_dimensions - 1; i > 0; i--)
711 const struct pivot_dimension *d = table->dimensions[i];
714 out[i] = remainder % d->n_leaves;
715 remainder /= d->n_leaves;
720 if (remainder >= table->dimensions[0]->n_leaves)
721 return xasprintf ("out of range cell data index %"PRIu64, in);
727 static char * WARN_UNUSED_RESULT
728 decode_spvlb_cells (struct spvlb_cell **in, size_t n_in,
729 struct pivot_table *table)
731 if (!table->n_dimensions)
734 size_t *dindexes = xnmalloc (table->n_dimensions, sizeof *dindexes);
735 for (size_t i = 0; i < n_in; i++)
737 struct pivot_value *value;
738 char *error = decode_data_index (in[i]->index, table, dindexes);
740 error = decode_spvlb_value (table, in[i]->value, &value);
746 pivot_table_put (table, dindexes, table->n_dimensions, value);
753 static char * WARN_UNUSED_RESULT
754 decode_spvlb_footnote (const struct spvlb_footnote *in,
755 size_t idx, struct pivot_table *table)
757 struct pivot_value *content;
758 char *error = decode_spvlb_value (table, in->text, &content);
762 struct pivot_value *marker = NULL;
765 error = decode_spvlb_value (table, in->marker, &marker);
768 pivot_value_destroy (content);
771 if (marker->type == PIVOT_VALUE_TEXT)
772 marker->text.user_provided = false;
775 struct pivot_footnote *f = pivot_table_create_footnote__ (
776 table, idx, marker, content);
777 f->show = (int32_t) in->show > 0;
781 static char * WARN_UNUSED_RESULT
782 decode_current_layer (uint64_t current_layer, struct pivot_table *table)
784 const struct pivot_axis *axis = &table->axes[PIVOT_AXIS_LAYER];
785 table->current_layer = xnmalloc (axis->n_dimensions,
786 sizeof *table->current_layer);
788 for (size_t i = 0; i < axis->n_dimensions; i++)
790 const struct pivot_dimension *d = axis->dimensions[i];
793 table->current_layer[i] = current_layer % d->n_leaves;
794 current_layer /= d->n_leaves;
797 table->current_layer[i] = 0;
799 if (current_layer > 0)
800 return xasprintf ("out of range layer data index %"PRIu64, current_layer);
804 char * WARN_UNUSED_RESULT
805 decode_spvlb_table (const struct spvlb_table *in, struct pivot_table **outp)
808 if (in->header->version != 1 && in->header->version != 3)
809 return xasprintf ("unknown version %"PRIu32" (expected 1 or 3)",
810 in->header->version);
813 struct pivot_table *out = xzalloc (sizeof *out);
815 hmap_init (&out->cells);
816 out->look = pivot_table_look_new_builtin_default ();
817 out->settings = (struct fmt_settings) FMT_SETTINGS_INIT;
819 /* Display settings. */
820 out->look->show_numeric_markers = !in->ts->show_alphabetic_markers;
821 out->rotate_inner_column_labels = in->header->rotate_inner_column_labels;
822 out->rotate_outer_row_labels = in->header->rotate_outer_row_labels;
823 out->look->row_labels_in_corner = in->ts->show_row_labels_in_corner;
824 out->show_grid_lines = in->borders->show_grid_lines;
825 out->show_title = true;
826 out->show_caption = true;
827 out->look->footnote_marker_superscripts = in->ts->footnote_marker_superscripts;
828 out->look->omit_empty = in->ts->omit_empty;
830 const struct spvlb_x1 *x1 = in->formats->x1;
833 error = decode_spvlb_value_show (x1->show_values, &out->show_values);
835 error = decode_spvlb_value_show (x1->show_variables,
836 &out->show_variables);
840 out->show_caption = x1->show_caption;
841 out->show_title = x1->show_title != 10;
844 /* Column and row display settings. */
845 out->look->width_ranges[TABLE_VERT][0] = in->header->min_row_height;
846 out->look->width_ranges[TABLE_VERT][1] = in->header->max_row_height;
847 out->look->width_ranges[TABLE_HORZ][0] = in->header->min_col_width;
848 out->look->width_ranges[TABLE_HORZ][1] = in->header->max_col_width;
850 convert_widths (in->formats->widths, in->formats->n_widths,
851 &out->sizing[TABLE_HORZ].widths,
852 &out->sizing[TABLE_HORZ].n_widths);
854 const struct spvlb_x2 *x2 = in->formats->x2;
856 convert_widths (x2->row_heights, x2->n_row_heights,
857 &out->sizing[TABLE_VERT].widths,
858 &out->sizing[TABLE_VERT].n_widths);
860 convert_breakpoints (in->ts->row_breaks,
861 &out->sizing[TABLE_VERT].breaks,
862 &out->sizing[TABLE_VERT].n_breaks);
863 convert_breakpoints (in->ts->col_breaks,
864 &out->sizing[TABLE_HORZ].breaks,
865 &out->sizing[TABLE_HORZ].n_breaks);
867 convert_keeps (in->ts->row_keeps,
868 &out->sizing[TABLE_VERT].keeps,
869 &out->sizing[TABLE_VERT].n_keeps);
870 convert_keeps (in->ts->col_keeps,
871 &out->sizing[TABLE_HORZ].keeps,
872 &out->sizing[TABLE_HORZ].n_keeps);
874 out->notes = xstrdup_if_nonempty (in->ts->notes);
875 out->look->name = xstrdup_if_nonempty (in->ts->table_look);
877 /* Print settings. */
878 out->look->print_all_layers = in->ps->all_layers;
879 out->look->paginate_layers = in->ps->paginate_layers;
880 out->look->shrink_to_fit[TABLE_HORZ] = in->ps->fit_width;
881 out->look->shrink_to_fit[TABLE_VERT] = in->ps->fit_length;
882 out->look->top_continuation = in->ps->top_continuation;
883 out->look->bottom_continuation = in->ps->bottom_continuation;
884 out->look->continuation = xstrdup (in->ps->continuation_string);
885 out->look->n_orphan_lines = in->ps->n_orphan_lines;
887 /* Format settings. */
888 int epoch = in->formats->y0->epoch;
889 if (epoch >= 1000 && epoch <= 9999)
890 out->settings.epoch = epoch;
891 char decimal = in->formats->y0->decimal;
892 if (decimal == '.' || decimal == '.')
893 out->settings.decimal = decimal;
896 /* XXX warn about bad decimal point */
898 out->grouping = in->formats->y0->grouping;
899 const struct spvlb_custom_currency *cc = in->formats->custom_currency;
900 for (int i = 0; i < 5; i++)
902 if (cc && i < cc->n_ccs)
904 out->settings.ccs[i] = fmt_number_style_from_string (cc->ccs[i]);
905 /* XXX warn if parsing fails */
908 out->small = in->formats->x3 ? in->formats->x3->small : 0;
910 /* Command information. */
911 const struct spvlb_y1 *y1 = (in->formats->x0 ? in->formats->x0->y1
912 : in->formats->x3 ? in->formats->x3->y1
916 out->command_local = xstrdup (y1->command_local);
917 out->command_c = xstrdup (y1->command);
918 out->language = xstrdup (y1->language);
920 out->locale = xstrdup (y1->locale);
923 /* Source information. */
924 const struct spvlb_x3 *x3 = in->formats->x3;
927 if (x3->dataset && x3->dataset[0] && x3->dataset[0] != 4)
928 out->dataset = xstrdup (x3->dataset);
929 out->datafile = xstrdup_if_nonempty (x3->datafile);
930 out->date = x3->date;
935 Any pivot_value might refer to footnotes, so it's important to process the
936 footnotes early to ensure that those references can be resolved. There is
937 a possible problem that a footnote might itself reference an
938 as-yet-unprocessed footnote, but that's OK because footnote references
939 don't actually look at the footnote contents but only resolve a pointer to
940 where the footnote will go later.
942 Before we really start, create all the footnotes we'll fill in. This is
943 because sometimes footnotes refer to themselves or to each other and we
944 don't want to reject those references. */
945 const struct spvlb_footnotes *fn = in->footnotes;
946 if (fn->n_footnotes > 0)
948 pivot_table_create_footnote__ (out, fn->n_footnotes - 1, NULL, NULL);
949 for (size_t i = 0; i < fn->n_footnotes; i++)
951 error = decode_spvlb_footnote (in->footnotes->footnotes[i], i, out);
957 /* Title and caption. */
958 error = decode_spvlb_value (out, in->titles->user_title, &out->title);
962 error = decode_spvlb_value (out, in->titles->subtype, &out->subtype);
966 if (in->titles->corner_text)
968 error = decode_spvlb_value (out, in->titles->corner_text,
974 if (in->titles->caption)
976 error = decode_spvlb_value (out, in->titles->caption, &out->caption);
983 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
985 error = decode_spvlb_area (in->areas->areas[i], &out->look->areas[i]);
989 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
991 error = decode_spvlb_border (in->borders->borders[i], out);
997 out->n_dimensions = in->dimensions->n_dims;
998 out->dimensions = XCALLOC (out->n_dimensions, struct pivot_dimension *);
999 for (size_t i = 0; i < out->n_dimensions; i++)
1001 error = decode_spvlb_dimension (out, in->dimensions->dims[i],
1002 i, &out->dimensions[i]);
1008 size_t a = in->axes->n_layers;
1009 size_t b = in->axes->n_rows;
1010 size_t c = in->axes->n_columns;
1011 if (size_overflow_p (xsum3 (a, b, c)) || a + b + c != out->n_dimensions)
1013 error = xasprintf ("dimensions do not sum correctly "
1014 "(%zu + %zu + %zu != %zu)",
1015 a, b, c, out->n_dimensions);
1018 error = decode_spvlb_axis (in->axes->layers, in->axes->n_layers,
1019 PIVOT_AXIS_LAYER, out);
1022 error = decode_spvlb_axis (in->axes->rows, in->axes->n_rows,
1023 PIVOT_AXIS_ROW, out);
1026 error = decode_spvlb_axis (in->axes->columns, in->axes->n_columns,
1027 PIVOT_AXIS_COLUMN, out);
1031 pivot_table_assign_label_depth (out);
1033 error = decode_current_layer (in->ts->current_layer, out);
1038 error = decode_spvlb_cells (in->cells->cells, in->cells->n_cells, out);
1044 pivot_table_unref (out);
1048 /* collect_spvlb_strings */
1051 add_if_nonempty (struct string_array *strings, const char *s)
1054 string_array_append (strings, s);
1058 collect_value_mod_strings (struct string_array *strings,
1059 const struct spvlb_value_mod *vm)
1061 if (vm->template_string)
1062 add_if_nonempty (strings, vm->template_string->id);
1064 if (vm->style_pair && vm->style_pair->font_style)
1065 add_if_nonempty (strings, vm->style_pair->font_style->typeface);
1069 collect_value_strings (struct string_array *strings,
1070 const struct spvlb_value *value)
1075 switch (value->type)
1078 collect_value_mod_strings (strings, value->type_01.value_mod);
1082 collect_value_mod_strings (strings, value->type_02.value_mod);
1083 add_if_nonempty (strings, value->type_02.var_name);
1084 add_if_nonempty (strings, value->type_02.value_label);
1088 collect_value_mod_strings (strings, value->type_03.value_mod);
1089 add_if_nonempty (strings, value->type_03.local);
1090 add_if_nonempty (strings, value->type_03.id);
1091 add_if_nonempty (strings, value->type_03.c);
1095 collect_value_mod_strings (strings, value->type_04.value_mod);
1096 add_if_nonempty (strings, value->type_04.value_label);
1097 add_if_nonempty (strings, value->type_04.var_name);
1098 add_if_nonempty (strings, value->type_04.s);
1102 collect_value_mod_strings (strings, value->type_05.value_mod);
1103 add_if_nonempty (strings, value->type_05.var_name);
1104 add_if_nonempty (strings, value->type_05.var_label);
1108 collect_value_mod_strings (strings, value->type_06.value_mod);
1109 add_if_nonempty (strings, value->type_06.local);
1110 add_if_nonempty (strings, value->type_06.id);
1111 add_if_nonempty (strings, value->type_06.c);
1115 collect_value_mod_strings (strings, value->type_else.value_mod);
1116 add_if_nonempty (strings, value->type_else.template);
1117 for (size_t i = 0; i < value->type_else.n_args; i++)
1119 const struct spvlb_argument *a = value->type_else.args[i];
1120 collect_value_strings (strings, a->value);
1121 for (size_t j = 0; j < a->n_values; j++)
1122 collect_value_strings (strings, a->values[j]);
1129 collect_category_strings (struct string_array *strings,
1130 const struct spvlb_category *cat)
1132 collect_value_strings (strings, cat->name);
1134 for (size_t i = 0; i < cat->group->n_subcategories; i++)
1135 collect_category_strings (strings, cat->group->subcategories[i]);
1138 /* Adds all of the characters strings in TABLE to STRINGS. */
1140 collect_spvlb_strings (const struct spvlb_table *table,
1141 struct string_array *strings)
1143 add_if_nonempty (strings, table->ts->notes);
1144 add_if_nonempty (strings, table->ts->table_look);
1145 add_if_nonempty (strings, table->ps->continuation_string);
1147 const struct spvlb_custom_currency *cc = table->formats->custom_currency;
1149 for (int i = 0; i < cc->n_ccs; i++)
1150 add_if_nonempty (strings, cc->ccs[i]);
1152 const struct spvlb_y1 *y1 = (table->formats->x0 ? table->formats->x0->y1
1153 : table->formats->x3 ? table->formats->x3->y1
1157 add_if_nonempty (strings, y1->command_local);
1158 add_if_nonempty (strings, y1->command);
1159 add_if_nonempty (strings, y1->language);
1160 add_if_nonempty (strings, y1->charset);
1161 add_if_nonempty (strings, y1->locale);
1164 const struct spvlb_x3 *x3 = table->formats->x3;
1167 if (x3->dataset && x3->dataset[0] && x3->dataset[0] != 4)
1168 add_if_nonempty (strings, x3->dataset);
1169 add_if_nonempty (strings, x3->datafile);
1172 for (size_t i = 0; i < table->footnotes->n_footnotes; i++)
1174 const struct spvlb_footnote *f = table->footnotes->footnotes[i];
1175 collect_value_strings (strings, f->text);
1176 collect_value_strings (strings, f->marker);
1179 collect_value_strings (strings, table->titles->user_title);
1180 collect_value_strings (strings, table->titles->subtype);
1181 collect_value_strings (strings, table->titles->corner_text);
1182 collect_value_strings (strings, table->titles->caption);
1184 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
1185 add_if_nonempty (strings, table->areas->areas[i]->typeface);
1187 for (size_t i = 0; i < table->dimensions->n_dims; i++)
1189 const struct spvlb_dimension *d = table->dimensions->dims[i];
1190 collect_value_strings (strings, d->name);
1191 for (size_t j = 0; j < d->n_categories; j++)
1192 collect_category_strings (strings, d->categories[j]);
1195 for (size_t i = 0; i < table->cells->n_cells; i++)
1196 collect_value_strings (strings, table->cells->cells[i]->value);
1199 /* Returns the encoding that TABLE declares to be in use for its strings.
1200 (Watch out, it's not always correct.) */
1202 spvlb_table_get_encoding (const struct spvlb_table *table)
1204 const struct spvlb_y1 *y1 = (table->formats->x0 ? table->formats->x0->y1
1205 : table->formats->x3 ? table->formats->x3->y1
1211 const char *dot = strchr (table->formats->locale, '.');
1212 return dot ? dot + 1 : "windows-1252";