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"
27 #include "libpspp/i18n.h"
28 #include "libpspp/message.h"
29 #include "libpspp/string-array.h"
30 #include "output/pivot-table.h"
31 #include "output/spv/light-binary-parser.h"
32 #include "output/spv/spv.h"
34 #include "gl/xalloc.h"
37 /* Returns a copy of S converted to UTF-8. S might be in UTF-8 already or it
38 might be in ENCODING (yes, this makes no sense). */
40 to_utf8 (const char *s, const char *encoding)
42 size_t length = strlen (s);
43 return (u8_check (CHAR_CAST (const uint8_t *, s), length)
44 ? recode_string ("UTF-8", encoding, s, length)
49 to_utf8_if_nonempty (const char *s, const char *encoding)
51 return s && s[0] ? to_utf8 (s, encoding) : NULL;
55 convert_widths (const uint32_t *in, uint32_t n, int **out, size_t *n_out)
60 *out = xnmalloc (n, sizeof **out);
61 for (size_t i = 0; i < n; i++)
67 convert_breakpoints (const struct spvlb_breakpoints *in,
68 size_t **out, size_t *n_out)
70 if (in && in->n_breaks)
72 *n_out = in->n_breaks;
73 *out = xnmalloc (in->n_breaks, sizeof *out);
74 for (size_t i = 0; i < in->n_breaks; i++)
75 (*out)[i] = in->breaks[i];
80 convert_keeps (const struct spvlb_keeps *in,
81 struct pivot_keep **out, size_t *n_out)
83 if (in && in->n_keeps)
86 *out = xnmalloc (*n_out, sizeof **out);
87 for (size_t i = 0; i < *n_out; i++)
89 (*out)[i].ofs = in->keeps[i]->offset;
90 (*out)[i].n = in->keeps[i]->n;
95 static char * WARN_UNUSED_RESULT
96 decode_spvlb_color_string (const char *s, uint8_t def,
97 struct cell_color *colorp)
102 else if (sscanf (s, "#%2x%2x%2x", &r, &g, &b) != 3)
103 return xasprintf ("bad color %s", s);
105 *colorp = (struct cell_color) CELL_COLOR (r, g, b);
109 static struct cell_color
110 decode_spvlb_color_u32 (uint32_t x)
112 return (struct cell_color) { x >> 24, x >> 16, x >> 8, x };
115 static char * WARN_UNUSED_RESULT
116 decode_spvlb_font_style (const struct spvlb_font_style *in,
117 const char *encoding, struct font_style **outp)
125 struct cell_color fg, bg;
126 char *error = decode_spvlb_color_string (in->fg_color, 0x00, &fg);
128 error = decode_spvlb_color_string (in->bg_color, 0xff, &bg);
132 *outp = xmalloc (sizeof **outp);
133 **outp = (struct font_style) {
135 .italic = in->italic,
136 .underline = in->underline,
139 .typeface = to_utf8 (in->typeface, encoding),
140 .size = in->size / 1.33,
145 static char * WARN_UNUSED_RESULT
146 decode_spvlb_halign (uint32_t in, enum table_halign *halignp)
151 *halignp = TABLE_HALIGN_CENTER;
155 *halignp = TABLE_HALIGN_LEFT;
159 *halignp = TABLE_HALIGN_RIGHT;
164 *halignp = TABLE_HALIGN_DECIMAL;
169 *halignp = TABLE_HALIGN_MIXED;
174 return xasprintf ("bad cell style halign %"PRIu32, in);
178 static char * WARN_UNUSED_RESULT
179 decode_spvlb_valign (uint32_t in, enum table_valign *valignp)
184 *valignp = TABLE_VALIGN_CENTER;
188 *valignp = TABLE_VALIGN_TOP;
192 *valignp = TABLE_VALIGN_BOTTOM;
197 return xasprintf ("bad cell style valign %"PRIu32, in);
201 static char * WARN_UNUSED_RESULT
202 decode_spvlb_cell_style (const struct spvlb_cell_style *in,
203 struct cell_style **outp)
211 enum table_halign halign;
212 char *error = decode_spvlb_halign (in->halign, &halign);
216 enum table_valign valign;
217 error = decode_spvlb_valign (in->valign, &valign);
221 *outp = xzalloc (sizeof **outp);
222 **outp = (struct cell_style) {
225 .decimal_offset = in->decimal_offset,
227 [TABLE_HORZ] = { in->left_margin, in->right_margin },
228 [TABLE_VERT] = { in->top_margin, in->bottom_margin },
234 static char *decode_spvlb_value (
235 const struct pivot_table *, const struct spvlb_value *,
236 const char *encoding, struct pivot_value **) WARN_UNUSED_RESULT;
238 static char * WARN_UNUSED_RESULT
239 decode_spvlb_argument (const struct pivot_table *table,
240 const struct spvlb_argument *in,
241 const char *encoding, struct pivot_argument *out)
245 struct pivot_value *value;
246 char *error = decode_spvlb_value (table, in->value, encoding, &value);
251 out->values = xmalloc (sizeof *out->values);
252 out->values[0] = value;
257 out->values = xnmalloc (in->n_values, sizeof *out->values);
258 for (size_t i = 0; i < in->n_values; i++)
260 char *error = decode_spvlb_value (table, in->values[i], encoding,
264 pivot_argument_uninit (out);
274 static char * WARN_UNUSED_RESULT
275 decode_spvlb_value_show (uint8_t in, enum settings_value_show *out)
279 case 0: *out = SETTINGS_VALUE_SHOW_DEFAULT; return NULL;
280 case 1: *out = SETTINGS_VALUE_SHOW_VALUE; return NULL;
281 case 2: *out = SETTINGS_VALUE_SHOW_LABEL; return NULL;
282 case 3: *out = SETTINGS_VALUE_SHOW_BOTH; return NULL;
284 return xasprintf ("bad value show %"PRIu8, in);
288 static char * WARN_UNUSED_RESULT
289 decode_spvlb_value (const struct pivot_table *table,
290 const struct spvlb_value *in,
291 const char *encoding, struct pivot_value **outp)
295 struct pivot_value *out = XZALLOC (struct pivot_value);
296 const struct spvlb_value_mod *vm;
302 vm = in->type_01.value_mod;
303 out->type = PIVOT_VALUE_NUMERIC;
304 out->numeric.x = in->type_01.x;
305 error = spv_decode_fmt_spec (in->type_01.format, &out->numeric.format);
306 out->numeric.honor_small = (in->type_01.format >> 16) == 40;
312 vm = in->type_02.value_mod;
313 out->type = PIVOT_VALUE_NUMERIC;
314 out->numeric.x = in->type_02.x;
315 error = spv_decode_fmt_spec (in->type_02.format, &out->numeric.format);
317 error = decode_spvlb_value_show (in->type_02.show, &out->numeric.show);
320 out->numeric.var_name = to_utf8_if_nonempty (in->type_02.var_name,
322 out->numeric.value_label = to_utf8_if_nonempty (in->type_02.value_label,
327 vm = in->type_03.value_mod;
328 out->type = PIVOT_VALUE_TEXT;
329 out->text.local = to_utf8 (in->type_03.local, encoding);
330 out->text.c = to_utf8 (in->type_03.c, encoding);
331 out->text.id = to_utf8 (in->type_03.id, encoding);
332 out->text.user_provided = !in->type_03.fixed;
336 vm = in->type_04.value_mod;
337 out->type = PIVOT_VALUE_STRING;
338 error = decode_spvlb_value_show (in->type_04.show, &out->string.show);
341 out->string.s = to_utf8 (in->type_04.s, encoding);
342 out->string.hex = (in->type_04.format >> 16) == fmt_to_io (FMT_AHEX);
343 out->string.var_name = to_utf8 (in->type_04.var_name, encoding);
344 out->string.value_label = to_utf8_if_nonempty (in->type_04.value_label,
349 vm = in->type_05.value_mod;
350 out->type = PIVOT_VALUE_VARIABLE;
351 error = decode_spvlb_value_show (in->type_05.show, &out->variable.show);
354 out->variable.var_name = to_utf8 (in->type_05.var_name, encoding);
355 out->variable.var_label = to_utf8_if_nonempty (in->type_05.var_label,
360 vm = in->type_06.value_mod;
361 out->type = PIVOT_VALUE_TEXT;
362 out->text.local = to_utf8 (in->type_06.local, encoding);
363 out->text.c = to_utf8 (in->type_06.c, encoding);
364 out->text.id = to_utf8 (in->type_06.id, encoding);
365 out->text.user_provided = false;
369 vm = in->type_else.value_mod;
370 out->type = PIVOT_VALUE_TEMPLATE;
371 out->template.local = to_utf8 (in->type_else.template, encoding);
372 out->template.id = out->template.local;
373 out->template.n_args = 0;
374 out->template.args = xnmalloc (in->type_else.n_args,
375 sizeof *out->template.args);
376 for (size_t i = 0; i < in->type_else.n_args; i++)
378 error = decode_spvlb_argument (table, in->type_else.args[i],
379 encoding, &out->template.args[i]);
382 pivot_value_destroy (out);
385 out->template.n_args++;
395 if (vm->n_subscripts)
397 struct pivot_value_ex *ex = pivot_value_ex_rw (out);
398 ex->n_subscripts = vm->n_subscripts;
399 ex->subscripts = xnmalloc (vm->n_subscripts, sizeof *ex->subscripts);
400 for (size_t i = 0; i < vm->n_subscripts; i++)
401 ex->subscripts[i] = to_utf8 (vm->subscripts[i], encoding);
406 struct pivot_value_ex *ex = pivot_value_ex_rw (out);
407 ex->footnote_indexes = xnmalloc (vm->n_refs,
408 sizeof *ex->footnote_indexes);
410 for (size_t i = 0; i < vm->n_refs; i++)
412 uint16_t idx = vm->refs[i];
413 if (idx >= table->n_footnotes)
415 pivot_value_destroy (out);
416 return xasprintf ("bad footnote index: %"PRIu16" >= %zu",
417 idx, table->n_footnotes);
420 ex->footnote_indexes[ex->n_footnotes++] = idx;
422 pivot_value_sort_footnotes (out);
427 struct pivot_value_ex *ex = pivot_value_ex_rw (out);
428 error = decode_spvlb_font_style (vm->style_pair->font_style,
429 encoding, &ex->font_style);
431 error = decode_spvlb_cell_style (vm->style_pair->cell_style,
435 pivot_value_destroy (out);
440 if (vm->template_string
441 && vm->template_string->id
442 && vm->template_string->id[0]
443 && out->type == PIVOT_VALUE_TEMPLATE)
444 out->template.id = to_utf8 (vm->template_string->id, encoding);
451 static char * WARN_UNUSED_RESULT
452 decode_spvlb_area (const struct spvlb_area *in, struct table_area_style *out,
453 const char *encoding)
457 struct cell_color fg0, fg1, bg0, bg1;
458 error = decode_spvlb_color_string (in->fg_color, 0x00, &fg0);
460 error = decode_spvlb_color_string (in->bg_color, 0xff, &bg0);
461 if (!error && in->alternate)
462 error = decode_spvlb_color_string (in->alt_fg_color, 0x00, &fg1);
463 if (!error && in->alternate)
464 error = decode_spvlb_color_string (in->alt_bg_color, 0xff, &bg1);
466 enum table_halign halign;
469 error = decode_spvlb_halign (in->halign, &halign);
471 /* TABLE_HALIGN_DECIMAL doesn't seem to be a real halign for areas, which
472 is good because there's no way to indicate the decimal offset. Just
474 if (!error && halign == TABLE_HALIGN_DECIMAL)
475 halign = TABLE_HALIGN_MIXED;
478 enum table_valign valign;
480 error = decode_spvlb_valign (in->valign, &valign);
485 table_area_style_uninit (out);
486 *out = (struct table_area_style) {
488 .bold = (in->style & 1) != 0,
489 .italic = (in->style & 2) != 0,
490 .underline = in->underline,
491 .fg = { fg0, in->alternate ? fg1 : fg0 },
492 .bg = { bg0, in->alternate ? bg1 : bg0 },
493 .typeface = to_utf8 (in->typeface, encoding),
494 .size = in->size / 1.33,
500 [TABLE_HORZ] = { in->left_margin, in->right_margin },
501 [TABLE_VERT] = { in->top_margin, in->bottom_margin },
508 static char * WARN_UNUSED_RESULT
509 decode_spvlb_group (const struct pivot_table *,
510 struct spvlb_category **,
513 struct pivot_category *parent,
514 struct pivot_dimension *,
515 const char *encoding);
517 static char * WARN_UNUSED_RESULT
518 decode_spvlb_categories (const struct pivot_table *table,
519 struct spvlb_category **categories,
521 struct pivot_category *parent,
522 struct pivot_dimension *dimension,
523 const char *encoding)
525 for (size_t i = 0; i < n_categories; i++)
527 const struct spvlb_category *in = categories[i];
528 if (in->group && in->group->merge)
530 char *error = decode_spvlb_categories (
531 table, in->group->subcategories, in->group->n_subcategories,
532 parent, dimension, encoding);
539 struct pivot_value *name;
540 char *error = decode_spvlb_value (table, in->name, encoding, &name);
544 struct pivot_category *out = XZALLOC (struct pivot_category);
546 out->parent = parent;
547 out->dimension = dimension;
550 char *error = decode_spvlb_group (table, in->group->subcategories,
551 in->group->n_subcategories,
552 true, out, dimension, encoding);
555 pivot_category_destroy (out);
559 out->data_index = SIZE_MAX;
560 out->presentation_index = SIZE_MAX;
564 out->data_index = in->leaf->leaf_index;
565 out->presentation_index = dimension->n_leaves;
566 dimension->n_leaves++;
569 if (parent->n_subs >= parent->allocated_subs)
570 parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
571 sizeof *parent->subs);
572 parent->subs[parent->n_subs++] = out;
577 static char * WARN_UNUSED_RESULT
578 decode_spvlb_group (const struct pivot_table *table,
579 struct spvlb_category **categories,
580 size_t n_categories, bool show_label,
581 struct pivot_category *category,
582 struct pivot_dimension *dimension,
583 const char *encoding)
585 category->subs = XCALLOC (n_categories, struct pivot_category *);
586 category->n_subs = 0;
587 category->allocated_subs = 0;
588 category->show_label = show_label;
590 return decode_spvlb_categories (table, categories, n_categories, category,
591 dimension, encoding);
594 static char * WARN_UNUSED_RESULT
595 fill_leaves (struct pivot_category *category,
596 struct pivot_dimension *dimension)
598 if (pivot_category_is_group (category))
600 for (size_t i = 0; i < category->n_subs; i++)
602 char *error = fill_leaves (category->subs[i], dimension);
609 if (category->data_index >= dimension->n_leaves)
610 return xasprintf ("leaf_index %zu >= n_leaves %zu",
611 category->data_index, dimension->n_leaves);
612 if (dimension->data_leaves[category->data_index])
613 return xasprintf ("two leaves with data_index %zu",
614 category->data_index);
615 dimension->data_leaves[category->data_index] = category;
616 dimension->presentation_leaves[category->presentation_index] = category;
621 static char * WARN_UNUSED_RESULT
622 decode_spvlb_dimension (const struct pivot_table *table,
623 const struct spvlb_dimension *in,
624 size_t idx, const char *encoding,
625 struct pivot_dimension **outp)
627 /* Convert most of the dimension. */
628 struct pivot_value *name;
629 char *error = decode_spvlb_value (table, in->name, encoding, &name);
633 struct pivot_dimension *out = XZALLOC (struct pivot_dimension);
634 out->level = UINT_MAX;
635 out->top_index = idx;
636 out->hide_all_labels = in->props->hide_all_labels;
638 out->root = xzalloc (sizeof *out->root);
639 *out->root = (struct pivot_category) {
642 .data_index = SIZE_MAX,
643 .presentation_index = SIZE_MAX,
645 error = decode_spvlb_group (table, in->categories, in->n_categories,
646 !in->props->hide_dim_label, out->root,
651 /* Allocate and fill the array of leaves now that we know how many there
653 out->data_leaves = XCALLOC (out->n_leaves, struct pivot_category *);
654 out->presentation_leaves = XCALLOC (out->n_leaves, struct pivot_category *);
655 out->allocated_leaves = out->n_leaves;
656 error = fill_leaves (out->root, out);
659 for (size_t i = 0; i < out->n_leaves; i++)
661 assert (out->data_leaves[i] != NULL);
662 assert (out->presentation_leaves[i] != NULL);
668 pivot_dimension_destroy (out);
672 static char * WARN_UNUSED_RESULT
673 decode_spvlb_stroke (uint32_t stroke_type, enum table_stroke *strokep)
675 enum table_stroke strokes[] = {
684 if (stroke_type >= sizeof strokes / sizeof *strokes)
685 return xasprintf ("bad stroke %"PRIu32, stroke_type);
687 *strokep = strokes[stroke_type];
691 static char * WARN_UNUSED_RESULT
692 decode_spvlb_border (const struct spvlb_border *in, struct pivot_table *table)
695 if (in->border_type >= PIVOT_N_BORDERS)
696 return xasprintf ("bad border type %"PRIu32, in->border_type);
698 struct table_border_style *out = &table->look->borders[in->border_type];
699 out->color = decode_spvlb_color_u32 (in->color);
700 return decode_spvlb_stroke (in->stroke_type, &out->stroke);
703 static char * WARN_UNUSED_RESULT
704 decode_spvlb_axis (const uint32_t *dimension_indexes, size_t n_dimensions,
705 enum pivot_axis_type axis_type, struct pivot_table *table)
707 struct pivot_axis *axis = &table->axes[axis_type];
708 axis->dimensions = XCALLOC (n_dimensions, struct pivot_dimension *);
709 axis->n_dimensions = n_dimensions;
711 for (size_t i = 0; i < n_dimensions; i++)
713 uint32_t idx = dimension_indexes[i];
714 if (idx >= table->n_dimensions)
715 return xasprintf ("bad dimension index %"PRIu32" >= %zu",
716 idx, table->n_dimensions);
718 struct pivot_dimension *d = table->dimensions[idx];
719 if (d->level != UINT_MAX)
720 return xasprintf ("duplicate dimension %"PRIu32, idx);
722 axis->dimensions[i] = d;
723 d->axis_type = axis_type;
726 axis->extent *= d->n_leaves;
733 decode_data_index (uint64_t in, const struct pivot_table *table,
736 uint64_t remainder = in;
737 for (size_t i = table->n_dimensions - 1; i < table->n_dimensions; i--)
739 const struct pivot_dimension *d = table->dimensions[i];
742 out[i] = remainder % d->n_leaves;
743 remainder /= d->n_leaves;
749 return xasprintf ("out of range cell data index %"PRIu64, in);
754 static char * WARN_UNUSED_RESULT
755 decode_spvlb_cells (struct spvlb_cell **in, size_t n_in,
756 struct pivot_table *table, const char *encoding)
758 if (!table->n_dimensions)
761 size_t *dindexes = xnmalloc (table->n_dimensions, sizeof *dindexes);
762 for (size_t i = 0; i < n_in; i++)
764 struct pivot_value *value;
765 char *error = decode_data_index (in[i]->index, table, dindexes);
767 error = decode_spvlb_value (table, in[i]->value, encoding, &value);
773 pivot_table_put (table, dindexes, table->n_dimensions, value);
780 static char * WARN_UNUSED_RESULT
781 decode_spvlb_footnote (const struct spvlb_footnote *in, const char *encoding,
782 size_t idx, struct pivot_table *table)
784 struct pivot_value *content;
785 char *error = decode_spvlb_value (table, in->text, encoding, &content);
789 struct pivot_value *marker = NULL;
792 error = decode_spvlb_value (table, in->marker, encoding, &marker);
795 pivot_value_destroy (content);
798 if (marker->type == PIVOT_VALUE_TEXT)
799 marker->text.user_provided = false;
802 struct pivot_footnote *f = pivot_table_create_footnote__ (
803 table, idx, marker, content);
804 f->show = (int32_t) in->show > 0;
808 static char * WARN_UNUSED_RESULT
809 decode_current_layer (uint64_t current_layer, struct pivot_table *table)
811 const struct pivot_axis *axis = &table->axes[PIVOT_AXIS_LAYER];
812 table->current_layer = xnmalloc (axis->n_dimensions,
813 sizeof *table->current_layer);
815 uint64_t remainder = current_layer;
816 for (size_t i = 0; i < axis->n_dimensions; i++)
818 const struct pivot_dimension *d = axis->dimensions[i];
821 table->current_layer[i] = remainder % d->n_leaves;
822 remainder /= d->n_leaves;
825 table->current_layer[i] = 0;
828 return xasprintf ("out of range layer data index %"PRIu64, current_layer);
833 char * WARN_UNUSED_RESULT
834 decode_spvlb_table (const struct spvlb_table *in, struct pivot_table **outp)
837 if (in->header->version != 1 && in->header->version != 3)
838 return xasprintf ("unknown version %"PRIu32" (expected 1 or 3)",
839 in->header->version);
842 struct pivot_table *out = XZALLOC (struct pivot_table);
844 hmap_init (&out->cells);
845 out->look = pivot_table_look_new_builtin_default ();
846 out->settings = (struct fmt_settings) FMT_SETTINGS_INIT;
848 const struct spvlb_y1 *y1 = (in->formats->x0 ? in->formats->x0->y1
849 : in->formats->x3 ? in->formats->x3->y1
851 const char *encoding = spvlb_table_get_encoding (in);
853 /* Display settings. */
854 out->look->show_numeric_markers = !in->ts->show_alphabetic_markers;
855 out->rotate_inner_column_labels = in->header->rotate_inner_column_labels;
856 out->rotate_outer_row_labels = in->header->rotate_outer_row_labels;
857 out->look->row_labels_in_corner = in->ts->show_row_labels_in_corner;
858 out->show_grid_lines = in->borders->show_grid_lines;
859 out->show_title = true;
860 out->show_caption = true;
861 out->look->footnote_marker_superscripts = in->ts->footnote_marker_superscripts;
862 out->look->omit_empty = in->ts->omit_empty;
864 const struct spvlb_x1 *x1 = in->formats->x1;
867 error = decode_spvlb_value_show (x1->show_values, &out->show_values);
869 error = decode_spvlb_value_show (x1->show_variables,
870 &out->show_variables);
874 out->show_caption = x1->show_caption;
875 out->show_title = x1->show_title != 10;
878 /* Column and row display settings. */
879 out->look->width_ranges[TABLE_VERT][0] = in->header->min_row_height;
880 out->look->width_ranges[TABLE_VERT][1] = in->header->max_row_height;
881 out->look->width_ranges[TABLE_HORZ][0] = in->header->min_col_width;
882 out->look->width_ranges[TABLE_HORZ][1] = in->header->max_col_width;
884 convert_widths (in->formats->widths, in->formats->n_widths,
885 &out->sizing[TABLE_HORZ].widths,
886 &out->sizing[TABLE_HORZ].n_widths);
888 const struct spvlb_x2 *x2 = in->formats->x2;
890 convert_widths (x2->row_heights, x2->n_row_heights,
891 &out->sizing[TABLE_VERT].widths,
892 &out->sizing[TABLE_VERT].n_widths);
894 convert_breakpoints (in->ts->row_breaks,
895 &out->sizing[TABLE_VERT].breaks,
896 &out->sizing[TABLE_VERT].n_breaks);
897 convert_breakpoints (in->ts->col_breaks,
898 &out->sizing[TABLE_HORZ].breaks,
899 &out->sizing[TABLE_HORZ].n_breaks);
901 convert_keeps (in->ts->row_keeps,
902 &out->sizing[TABLE_VERT].keeps,
903 &out->sizing[TABLE_VERT].n_keeps);
904 convert_keeps (in->ts->col_keeps,
905 &out->sizing[TABLE_HORZ].keeps,
906 &out->sizing[TABLE_HORZ].n_keeps);
908 out->notes = to_utf8_if_nonempty (in->ts->notes, encoding);
909 out->look->name = to_utf8_if_nonempty (in->ts->table_look, encoding);
911 /* Print settings. */
912 out->look->print_all_layers = in->ps->all_layers;
913 out->look->paginate_layers = in->ps->paginate_layers;
914 out->look->shrink_to_fit[TABLE_HORZ] = in->ps->fit_width;
915 out->look->shrink_to_fit[TABLE_VERT] = in->ps->fit_length;
916 out->look->top_continuation = in->ps->top_continuation;
917 out->look->bottom_continuation = in->ps->bottom_continuation;
918 out->look->continuation = to_utf8 (in->ps->continuation_string, encoding);
919 out->look->n_orphan_lines = in->ps->n_orphan_lines;
921 /* Format settings. */
922 int epoch = in->formats->y0->epoch;
923 if (epoch >= 1000 && epoch <= 9999)
924 out->settings.epoch = epoch;
925 char decimal = in->formats->y0->decimal;
926 if (decimal == '.' || decimal == ',')
927 out->settings.decimal = decimal;
930 /* XXX warn about bad decimal point */
932 out->grouping = in->formats->y0->grouping;
933 const struct spvlb_custom_currency *cc = in->formats->custom_currency;
934 for (int i = 0; i < 5; i++)
936 if (cc && i < cc->n_ccs)
938 out->settings.ccs[i] = fmt_number_style_from_string (cc->ccs[i]);
939 /* XXX warn if parsing fails */
943 out->settings.include_leading_zero = y1->include_leading_zero;
944 out->small = in->formats->x3 ? in->formats->x3->small : 0;
946 /* Command information. */
949 out->command_local = to_utf8 (y1->command_local, encoding);
950 out->command_c = to_utf8 (y1->command, encoding);
951 out->language = to_utf8 (y1->language, encoding);
953 out->locale = to_utf8 (y1->locale, encoding);
956 /* Source information. */
957 const struct spvlb_x3 *x3 = in->formats->x3;
960 if (x3->dataset && x3->dataset[0] && x3->dataset[0] != 4)
961 out->dataset = to_utf8 (x3->dataset, encoding);
962 out->datafile = to_utf8_if_nonempty (x3->datafile, encoding);
963 out->date = x3->date;
968 Any pivot_value might refer to footnotes, so it's important to process the
969 footnotes early to ensure that those references can be resolved. There is
970 a possible problem that a footnote might itself reference an
971 as-yet-unprocessed footnote, but that's OK because footnote references
972 don't actually look at the footnote contents but only resolve a pointer to
973 where the footnote will go later.
975 Before we really start, create all the footnotes we'll fill in. This is
976 because sometimes footnotes refer to themselves or to each other and we
977 don't want to reject those references. */
978 const struct spvlb_footnotes *fn = in->footnotes;
979 if (fn->n_footnotes > 0)
981 pivot_table_create_footnote__ (out, fn->n_footnotes - 1, NULL, NULL);
982 for (size_t i = 0; i < fn->n_footnotes; i++)
984 error = decode_spvlb_footnote (in->footnotes->footnotes[i],
991 /* Title and caption. */
992 error = decode_spvlb_value (out, in->titles->user_title, encoding,
997 error = decode_spvlb_value (out, in->titles->subtype, encoding,
1002 if (in->titles->corner_text)
1004 error = decode_spvlb_value (out, in->titles->corner_text,
1005 encoding, &out->corner_text);
1010 if (in->titles->caption)
1012 error = decode_spvlb_value (out, in->titles->caption, encoding,
1020 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
1022 error = decode_spvlb_area (in->areas->areas[i], &out->look->areas[i],
1027 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
1029 error = decode_spvlb_border (in->borders->borders[i], out);
1035 out->n_dimensions = in->dimensions->n_dims;
1036 out->dimensions = XCALLOC (out->n_dimensions, struct pivot_dimension *);
1037 for (size_t i = 0; i < out->n_dimensions; i++)
1039 error = decode_spvlb_dimension (out, in->dimensions->dims[i],
1040 i, encoding, &out->dimensions[i]);
1046 size_t a = in->axes->n_layers;
1047 size_t b = in->axes->n_rows;
1048 size_t c = in->axes->n_columns;
1049 if (size_overflow_p (xsum3 (a, b, c)) || a + b + c != out->n_dimensions)
1051 error = xasprintf ("dimensions do not sum correctly "
1052 "(%zu + %zu + %zu != %zu)",
1053 a, b, c, out->n_dimensions);
1056 error = decode_spvlb_axis (in->axes->layers, in->axes->n_layers,
1057 PIVOT_AXIS_LAYER, out);
1060 error = decode_spvlb_axis (in->axes->rows, in->axes->n_rows,
1061 PIVOT_AXIS_ROW, out);
1064 error = decode_spvlb_axis (in->axes->columns, in->axes->n_columns,
1065 PIVOT_AXIS_COLUMN, out);
1069 pivot_table_assign_label_depth (out);
1071 error = decode_current_layer (in->ts->current_layer, out);
1076 error = decode_spvlb_cells (in->cells->cells, in->cells->n_cells, out,
1083 pivot_table_unref (out);
1087 /* collect_spvlb_strings */
1090 add_if_nonempty (struct string_array *strings, const char *s)
1093 string_array_append (strings, s);
1097 collect_value_mod_strings (struct string_array *strings,
1098 const struct spvlb_value_mod *vm)
1100 if (vm->template_string)
1101 add_if_nonempty (strings, vm->template_string->id);
1103 if (vm->style_pair && vm->style_pair->font_style)
1104 add_if_nonempty (strings, vm->style_pair->font_style->typeface);
1108 collect_value_strings (struct string_array *strings,
1109 const struct spvlb_value *value)
1114 switch (value->type)
1117 collect_value_mod_strings (strings, value->type_01.value_mod);
1121 collect_value_mod_strings (strings, value->type_02.value_mod);
1122 add_if_nonempty (strings, value->type_02.var_name);
1123 add_if_nonempty (strings, value->type_02.value_label);
1127 collect_value_mod_strings (strings, value->type_03.value_mod);
1128 add_if_nonempty (strings, value->type_03.local);
1129 add_if_nonempty (strings, value->type_03.id);
1130 add_if_nonempty (strings, value->type_03.c);
1134 collect_value_mod_strings (strings, value->type_04.value_mod);
1135 add_if_nonempty (strings, value->type_04.value_label);
1136 add_if_nonempty (strings, value->type_04.var_name);
1137 add_if_nonempty (strings, value->type_04.s);
1141 collect_value_mod_strings (strings, value->type_05.value_mod);
1142 add_if_nonempty (strings, value->type_05.var_name);
1143 add_if_nonempty (strings, value->type_05.var_label);
1147 collect_value_mod_strings (strings, value->type_06.value_mod);
1148 add_if_nonempty (strings, value->type_06.local);
1149 add_if_nonempty (strings, value->type_06.id);
1150 add_if_nonempty (strings, value->type_06.c);
1154 collect_value_mod_strings (strings, value->type_else.value_mod);
1155 add_if_nonempty (strings, value->type_else.template);
1156 for (size_t i = 0; i < value->type_else.n_args; i++)
1158 const struct spvlb_argument *a = value->type_else.args[i];
1159 collect_value_strings (strings, a->value);
1160 for (size_t j = 0; j < a->n_values; j++)
1161 collect_value_strings (strings, a->values[j]);
1168 collect_category_strings (struct string_array *strings,
1169 const struct spvlb_category *cat)
1171 collect_value_strings (strings, cat->name);
1173 for (size_t i = 0; i < cat->group->n_subcategories; i++)
1174 collect_category_strings (strings, cat->group->subcategories[i]);
1177 /* Adds all of the characters strings in TABLE to STRINGS. */
1179 collect_spvlb_strings (const struct spvlb_table *table,
1180 struct string_array *strings)
1182 add_if_nonempty (strings, table->ts->notes);
1183 add_if_nonempty (strings, table->ts->table_look);
1184 add_if_nonempty (strings, table->ps->continuation_string);
1186 const struct spvlb_custom_currency *cc = table->formats->custom_currency;
1188 for (int i = 0; i < cc->n_ccs; i++)
1189 add_if_nonempty (strings, cc->ccs[i]);
1191 const struct spvlb_y1 *y1 = (table->formats->x0 ? table->formats->x0->y1
1192 : table->formats->x3 ? table->formats->x3->y1
1196 add_if_nonempty (strings, y1->command_local);
1197 add_if_nonempty (strings, y1->command);
1198 add_if_nonempty (strings, y1->language);
1199 add_if_nonempty (strings, y1->charset);
1200 add_if_nonempty (strings, y1->locale);
1203 const struct spvlb_x3 *x3 = table->formats->x3;
1206 if (x3->dataset && x3->dataset[0] && x3->dataset[0] != 4)
1207 add_if_nonempty (strings, x3->dataset);
1208 add_if_nonempty (strings, x3->datafile);
1211 for (size_t i = 0; i < table->footnotes->n_footnotes; i++)
1213 const struct spvlb_footnote *f = table->footnotes->footnotes[i];
1214 collect_value_strings (strings, f->text);
1215 collect_value_strings (strings, f->marker);
1218 collect_value_strings (strings, table->titles->user_title);
1219 collect_value_strings (strings, table->titles->subtype);
1220 collect_value_strings (strings, table->titles->corner_text);
1221 collect_value_strings (strings, table->titles->caption);
1223 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
1224 add_if_nonempty (strings, table->areas->areas[i]->typeface);
1226 for (size_t i = 0; i < table->dimensions->n_dims; i++)
1228 const struct spvlb_dimension *d = table->dimensions->dims[i];
1229 collect_value_strings (strings, d->name);
1230 for (size_t j = 0; j < d->n_categories; j++)
1231 collect_category_strings (strings, d->categories[j]);
1234 for (size_t i = 0; i < table->cells->n_cells; i++)
1235 collect_value_strings (strings, table->cells->cells[i]->value);
1238 /* Returns the encoding that TABLE declares to be in use for its strings.
1239 (Watch out, it's not always correct.) */
1241 spvlb_table_get_encoding (const struct spvlb_table *table)
1243 const struct spvlb_y1 *y1 = (table->formats->x0 ? table->formats->x0->y1
1244 : table->formats->x3 ? table->formats->x3->y1
1250 const char *dot = strchr (table->formats->locale, '.');
1251 return dot ? dot + 1 : "windows-1252";