X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Foutput%2Fspv%2Fspv-light-decoder.c;h=e58d423d6768f8f98d29ac42ab3fa2a1348eeb23;hb=5ce9c6ba1502e623ec6723a8273da77e5858b8d4;hp=be58d416eb8c7a89ba5fe01b58bf62bdefdf737d;hpb=50f6ea7d66d03895020891215fb4f55bbf061003;p=pspp diff --git a/src/output/spv/spv-light-decoder.c b/src/output/spv/spv-light-decoder.c index be58d416eb..e58d423d67 100644 --- a/src/output/spv/spv-light-decoder.c +++ b/src/output/spv/spv-light-decoder.c @@ -22,9 +22,11 @@ #include #include #include +#include #include "libpspp/i18n.h" #include "libpspp/message.h" +#include "libpspp/string-array.h" #include "output/pivot-table.h" #include "output/spv/light-binary-parser.h" #include "output/spv/spv.h" @@ -32,10 +34,15 @@ #include "gl/xalloc.h" #include "gl/xsize.h" +/* Returns a copy of S converted to UTF-8. S might be in UTF-8 already or it + might be in ENCODING (yes, this makes no sense). */ static char * to_utf8 (const char *s, const char *encoding) { - return recode_string ("UTF-8", encoding, s, strlen (s)); + size_t length = strlen (s); + return (u8_check (CHAR_CAST (const uint8_t *, s), length) + ? recode_string ("UTF-8", encoding, s, length) + : xstrdup (s)); } static char * @@ -89,7 +96,7 @@ static char * WARN_UNUSED_RESULT decode_spvlb_color_string (const char *s, uint8_t def, struct cell_color *colorp) { - int r, g, b; + unsigned int r, g, b; if (!*s) r = g = b = def; else if (sscanf (s, "#%2x%2x%2x", &r, &g, &b) != 3) @@ -185,6 +192,7 @@ decode_spvlb_valign (uint32_t in, enum table_valign *valignp) return NULL; default: + *valignp = 0; return xasprintf ("bad cell style valign %"PRIu32, in); } } @@ -294,6 +302,7 @@ decode_spvlb_value (const struct pivot_table *table, out->type = PIVOT_VALUE_NUMERIC; out->numeric.x = in->type_01.x; error = spv_decode_fmt_spec (in->type_01.format, &out->numeric.format); + out->numeric.honor_small = (in->type_01.format >> 16) == 40; if (error) return error; break; @@ -329,6 +338,7 @@ decode_spvlb_value (const struct pivot_table *table, if (error) return NULL; out->string.s = to_utf8 (in->type_04.s, encoding); + out->string.hex = (in->type_04.format >> 16) == fmt_to_io (FMT_AHEX); out->string.var_name = to_utf8 (in->type_04.var_name, encoding); out->string.value_label = to_utf8_if_nonempty (in->type_04.value_label, encoding); @@ -376,23 +386,26 @@ decode_spvlb_value (const struct pivot_table *table, break; default: - assert (0); + abort (); } if (vm) { if (vm->n_subscripts) { - out->n_subscripts = vm->n_subscripts; - out->subscripts = xnmalloc (vm->n_subscripts, - sizeof *out->subscripts); + struct pivot_value_ex *ex = pivot_value_ex_rw (out); + ex->n_subscripts = vm->n_subscripts; + ex->subscripts = xnmalloc (vm->n_subscripts, sizeof *ex->subscripts); for (size_t i = 0; i < vm->n_subscripts; i++) - out->subscripts[i] = to_utf8 (vm->subscripts[i], encoding); + ex->subscripts[i] = to_utf8 (vm->subscripts[i], encoding); } if (vm->n_refs) { - out->footnotes = xnmalloc (vm->n_refs, sizeof *out->footnotes); + struct pivot_value_ex *ex = pivot_value_ex_rw (out); + ex->footnote_indexes = xnmalloc (vm->n_refs, + sizeof *ex->footnote_indexes); + for (size_t i = 0; i < vm->n_refs; i++) { uint16_t idx = vm->refs[i]; @@ -403,17 +416,19 @@ decode_spvlb_value (const struct pivot_table *table, idx, table->n_footnotes); } - out->footnotes[out->n_footnotes++] = table->footnotes[idx]; + ex->footnote_indexes[ex->n_footnotes++] = idx; } + pivot_value_sort_footnotes (out); } if (vm->style_pair) { + struct pivot_value_ex *ex = pivot_value_ex_rw (out); error = decode_spvlb_font_style (vm->style_pair->font_style, - encoding, &out->font_style); + encoding, &ex->font_style); if (!error) error = decode_spvlb_cell_style (vm->style_pair->cell_style, - &out->cell_style); + &ex->cell_style); if (error) { pivot_value_destroy (out); @@ -433,7 +448,7 @@ decode_spvlb_value (const struct pivot_table *table, } static char * WARN_UNUSED_RESULT -decode_spvlb_area (const struct spvlb_area *in, struct area_style *out, +decode_spvlb_area (const struct spvlb_area *in, struct table_area_style *out, const char *encoding) { char *error; @@ -466,7 +481,8 @@ decode_spvlb_area (const struct spvlb_area *in, struct area_style *out, if (error) return error; - *out = (struct area_style) { + table_area_style_uninit (out); + *out = (struct table_area_style) { .font_style = { .bold = (in->style & 1) != 0, .italic = (in->style & 2) != 0, @@ -565,7 +581,7 @@ decode_spvlb_group (const struct pivot_table *table, struct pivot_dimension *dimension, const char *encoding) { - category->subs = xcalloc (n_categories, sizeof *category->subs); + category->subs = XCALLOC (n_categories, struct pivot_category *); category->n_subs = 0; category->allocated_subs = 0; category->show_label = show_label; @@ -633,9 +649,8 @@ decode_spvlb_dimension (const struct pivot_table *table, /* Allocate and fill the array of leaves now that we know how many there are. */ - out->data_leaves = xcalloc (out->n_leaves, sizeof *out->data_leaves); - out->presentation_leaves = xcalloc (out->n_leaves, - sizeof *out->presentation_leaves); + out->data_leaves = XCALLOC (out->n_leaves, struct pivot_category *); + out->presentation_leaves = XCALLOC (out->n_leaves, struct pivot_category *); out->allocated_leaves = out->n_leaves; error = fill_leaves (out->root, out); if (error) @@ -679,7 +694,7 @@ decode_spvlb_border (const struct spvlb_border *in, struct pivot_table *table) if (in->border_type >= PIVOT_N_BORDERS) return xasprintf ("bad border type %"PRIu32, in->border_type); - struct table_border_style *out = &table->borders[in->border_type]; + struct table_border_style *out = &table->look->borders[in->border_type]; out->color = decode_spvlb_color_u32 (in->color); return decode_spvlb_stroke (in->stroke_type, &out->stroke); } @@ -689,7 +704,7 @@ decode_spvlb_axis (const uint32_t *dimension_indexes, size_t n_dimensions, enum pivot_axis_type axis_type, struct pivot_table *table) { struct pivot_axis *axis = &table->axes[axis_type]; - axis->dimensions = xcalloc (n_dimensions, sizeof *axis->dimensions); + axis->dimensions = XCALLOC (n_dimensions, struct pivot_dimension *); axis->n_dimensions = n_dimensions; axis->extent = 1; for (size_t i = 0; i < n_dimensions; i++) @@ -718,7 +733,7 @@ decode_data_index (uint64_t in, const struct pivot_table *table, size_t *out) { uint64_t remainder = in; - for (size_t i = table->n_dimensions - 1; i > 0; i--) + for (size_t i = table->n_dimensions - 1; i < table->n_dimensions; i--) { const struct pivot_dimension *d = table->dimensions[i]; if (d->n_leaves) @@ -729,10 +744,9 @@ decode_data_index (uint64_t in, const struct pivot_table *table, else out[i] = 0; } - if (remainder >= table->dimensions[0]->n_leaves) + if (remainder) return xasprintf ("out of range cell data index %"PRIu64, in); - out[0] = remainder; return NULL; } @@ -797,19 +811,21 @@ decode_current_layer (uint64_t current_layer, struct pivot_table *table) table->current_layer = xnmalloc (axis->n_dimensions, sizeof *table->current_layer); + uint64_t remainder = current_layer; for (size_t i = 0; i < axis->n_dimensions; i++) { const struct pivot_dimension *d = axis->dimensions[i]; if (d->n_leaves) { - table->current_layer[i] = current_layer % d->n_leaves; - current_layer /= d->n_leaves; + table->current_layer[i] = remainder % d->n_leaves; + remainder /= d->n_leaves; } else table->current_layer[i] = 0; } - if (current_layer > 0) + if (remainder > 0) return xasprintf ("out of range layer data index %"PRIu64, current_layer); + return NULL; } @@ -825,28 +841,24 @@ decode_spvlb_table (const struct spvlb_table *in, struct pivot_table **outp) struct pivot_table *out = xzalloc (sizeof *out); out->ref_cnt = 1; hmap_init (&out->cells); + out->look = pivot_table_look_new_builtin_default (); + out->settings = (struct fmt_settings) FMT_SETTINGS_INIT; const struct spvlb_y1 *y1 = (in->formats->x0 ? in->formats->x0->y1 : in->formats->x3 ? in->formats->x3->y1 : NULL); - const char *encoding; - if (y1) - encoding = y1->charset; - else - { - const char *dot = strchr (in->formats->locale, '.'); - encoding = dot ? dot + 1 : "windows-1252"; - } + const char *encoding = spvlb_table_get_encoding (in); /* Display settings. */ - out->show_numeric_markers = !in->ts->show_alphabetic_markers; + out->look->show_numeric_markers = !in->ts->show_alphabetic_markers; out->rotate_inner_column_labels = in->header->rotate_inner_column_labels; out->rotate_outer_row_labels = in->header->rotate_outer_row_labels; - out->row_labels_in_corner = in->ts->show_row_labels_in_corner; + out->look->row_labels_in_corner = in->ts->show_row_labels_in_corner; out->show_grid_lines = in->borders->show_grid_lines; + out->show_title = true; out->show_caption = true; - out->footnote_marker_superscripts = in->ts->footnote_marker_superscripts; - out->omit_empty = in->ts->omit_empty; + out->look->footnote_marker_superscripts = in->ts->footnote_marker_superscripts; + out->look->omit_empty = in->ts->omit_empty; const struct spvlb_x1 *x1 = in->formats->x1; if (x1) @@ -859,13 +871,14 @@ decode_spvlb_table (const struct spvlb_table *in, struct pivot_table **outp) goto error; out->show_caption = x1->show_caption; + out->show_title = x1->show_title != 10; } /* Column and row display settings. */ - out->sizing[TABLE_VERT].range[0] = in->header->min_row_height; - out->sizing[TABLE_VERT].range[1] = in->header->max_row_height; - out->sizing[TABLE_HORZ].range[0] = in->header->min_col_width; - out->sizing[TABLE_HORZ].range[1] = in->header->max_col_width; + out->look->width_ranges[TABLE_VERT][0] = in->header->min_row_height; + out->look->width_ranges[TABLE_VERT][1] = in->header->max_row_height; + out->look->width_ranges[TABLE_HORZ][0] = in->header->min_col_width; + out->look->width_ranges[TABLE_HORZ][1] = in->header->max_col_width; convert_widths (in->formats->widths, in->formats->n_widths, &out->sizing[TABLE_HORZ].widths, @@ -892,26 +905,39 @@ decode_spvlb_table (const struct spvlb_table *in, struct pivot_table **outp) &out->sizing[TABLE_HORZ].n_keeps); out->notes = to_utf8_if_nonempty (in->ts->notes, encoding); - out->table_look = to_utf8_if_nonempty (in->ts->table_look, encoding); + out->look->name = to_utf8_if_nonempty (in->ts->table_look, encoding); /* Print settings. */ - out->print_all_layers = in->ps->all_layers; - out->paginate_layers = in->ps->paginate_layers; - out->shrink_to_fit[TABLE_HORZ] = in->ps->fit_width; - out->shrink_to_fit[TABLE_VERT] = in->ps->fit_length; - out->top_continuation = in->ps->top_continuation; - out->bottom_continuation = in->ps->bottom_continuation; - out->continuation = xstrdup (in->ps->continuation_string); - out->n_orphan_lines = in->ps->n_orphan_lines; + out->look->print_all_layers = in->ps->all_layers; + out->look->paginate_layers = in->ps->paginate_layers; + out->look->shrink_to_fit[TABLE_HORZ] = in->ps->fit_width; + out->look->shrink_to_fit[TABLE_VERT] = in->ps->fit_length; + out->look->top_continuation = in->ps->top_continuation; + out->look->bottom_continuation = in->ps->bottom_continuation; + out->look->continuation = to_utf8 (in->ps->continuation_string, encoding); + out->look->n_orphan_lines = in->ps->n_orphan_lines; /* Format settings. */ - out->epoch = in->formats->y0->epoch; - out->decimal = in->formats->y0->decimal; + int epoch = in->formats->y0->epoch; + if (epoch >= 1000 && epoch <= 9999) + out->settings.epoch = epoch; + char decimal = in->formats->y0->decimal; + if (decimal == '.' || decimal == ',') + out->settings.decimal = decimal; + else + { + /* XXX warn about bad decimal point */ + } out->grouping = in->formats->y0->grouping; const struct spvlb_custom_currency *cc = in->formats->custom_currency; for (int i = 0; i < 5; i++) - if (cc && i < cc->n_ccs) - out->ccs[i] = xstrdup (cc->ccs[i]); + { + if (cc && i < cc->n_ccs) + { + out->settings.ccs[i] = fmt_number_style_from_string (cc->ccs[i]); + /* XXX warn if parsing fails */ + } + } out->small = in->formats->x3 ? in->formats->x3->small : 0; /* Command information. */ @@ -919,9 +945,9 @@ decode_spvlb_table (const struct spvlb_table *in, struct pivot_table **outp) { out->command_local = to_utf8 (y1->command_local, encoding); out->command_c = to_utf8 (y1->command, encoding); - out->language = xstrdup (y1->language); + out->language = to_utf8 (y1->language, encoding); /* charset? */ - out->locale = xstrdup (y1->locale); + out->locale = to_utf8 (y1->locale, encoding); } /* Source information. */ @@ -990,7 +1016,7 @@ decode_spvlb_table (const struct spvlb_table *in, struct pivot_table **outp) /* Styles. */ for (size_t i = 0; i < PIVOT_N_AREAS; i++) { - error = decode_spvlb_area (in->areas->areas[i], &out->areas[i], + error = decode_spvlb_area (in->areas->areas[i], &out->look->areas[i], encoding); if (error) goto error; @@ -1004,7 +1030,7 @@ decode_spvlb_table (const struct spvlb_table *in, struct pivot_table **outp) /* Dimensions. */ out->n_dimensions = in->dimensions->n_dims; - out->dimensions = xcalloc (out->n_dimensions, sizeof *out->dimensions); + out->dimensions = XCALLOC (out->n_dimensions, struct pivot_dimension *); for (size_t i = 0; i < out->n_dimensions; i++) { error = decode_spvlb_dimension (out, in->dimensions->dims[i], @@ -1054,3 +1080,171 @@ error: pivot_table_unref (out); return error; } + +/* collect_spvlb_strings */ + +static void +add_if_nonempty (struct string_array *strings, const char *s) +{ + if (s && s[0]) + string_array_append (strings, s); +} + +static void +collect_value_mod_strings (struct string_array *strings, + const struct spvlb_value_mod *vm) +{ + if (vm->template_string) + add_if_nonempty (strings, vm->template_string->id); + + if (vm->style_pair && vm->style_pair->font_style) + add_if_nonempty (strings, vm->style_pair->font_style->typeface); +} + +static void +collect_value_strings (struct string_array *strings, + const struct spvlb_value *value) +{ + if (!value) + return; + + switch (value->type) + { + case 1: + collect_value_mod_strings (strings, value->type_01.value_mod); + break; + + case 2: + collect_value_mod_strings (strings, value->type_02.value_mod); + add_if_nonempty (strings, value->type_02.var_name); + add_if_nonempty (strings, value->type_02.value_label); + break; + + case 3: + collect_value_mod_strings (strings, value->type_03.value_mod); + add_if_nonempty (strings, value->type_03.local); + add_if_nonempty (strings, value->type_03.id); + add_if_nonempty (strings, value->type_03.c); + break; + + case 4: + collect_value_mod_strings (strings, value->type_04.value_mod); + add_if_nonempty (strings, value->type_04.value_label); + add_if_nonempty (strings, value->type_04.var_name); + add_if_nonempty (strings, value->type_04.s); + break; + + case 5: + collect_value_mod_strings (strings, value->type_05.value_mod); + add_if_nonempty (strings, value->type_05.var_name); + add_if_nonempty (strings, value->type_05.var_label); + break; + + case 6: + collect_value_mod_strings (strings, value->type_06.value_mod); + add_if_nonempty (strings, value->type_06.local); + add_if_nonempty (strings, value->type_06.id); + add_if_nonempty (strings, value->type_06.c); + break; + + case -1: + collect_value_mod_strings (strings, value->type_else.value_mod); + add_if_nonempty (strings, value->type_else.template); + for (size_t i = 0; i < value->type_else.n_args; i++) + { + const struct spvlb_argument *a = value->type_else.args[i]; + collect_value_strings (strings, a->value); + for (size_t j = 0; j < a->n_values; j++) + collect_value_strings (strings, a->values[j]); + } + break; + } +} + +static void +collect_category_strings (struct string_array *strings, + const struct spvlb_category *cat) +{ + collect_value_strings (strings, cat->name); + if (cat->group) + for (size_t i = 0; i < cat->group->n_subcategories; i++) + collect_category_strings (strings, cat->group->subcategories[i]); +} + +/* Adds all of the characters strings in TABLE to STRINGS. */ +void +collect_spvlb_strings (const struct spvlb_table *table, + struct string_array *strings) +{ + add_if_nonempty (strings, table->ts->notes); + add_if_nonempty (strings, table->ts->table_look); + add_if_nonempty (strings, table->ps->continuation_string); + + const struct spvlb_custom_currency *cc = table->formats->custom_currency; + if (cc) + for (int i = 0; i < cc->n_ccs; i++) + add_if_nonempty (strings, cc->ccs[i]); + + const struct spvlb_y1 *y1 = (table->formats->x0 ? table->formats->x0->y1 + : table->formats->x3 ? table->formats->x3->y1 + : NULL); + if (y1) + { + add_if_nonempty (strings, y1->command_local); + add_if_nonempty (strings, y1->command); + add_if_nonempty (strings, y1->language); + add_if_nonempty (strings, y1->charset); + add_if_nonempty (strings, y1->locale); + } + + const struct spvlb_x3 *x3 = table->formats->x3; + if (x3) + { + if (x3->dataset && x3->dataset[0] && x3->dataset[0] != 4) + add_if_nonempty (strings, x3->dataset); + add_if_nonempty (strings, x3->datafile); + } + + for (size_t i = 0; i < table->footnotes->n_footnotes; i++) + { + const struct spvlb_footnote *f = table->footnotes->footnotes[i]; + collect_value_strings (strings, f->text); + collect_value_strings (strings, f->marker); + } + + collect_value_strings (strings, table->titles->user_title); + collect_value_strings (strings, table->titles->subtype); + collect_value_strings (strings, table->titles->corner_text); + collect_value_strings (strings, table->titles->caption); + + for (size_t i = 0; i < PIVOT_N_AREAS; i++) + add_if_nonempty (strings, table->areas->areas[i]->typeface); + + for (size_t i = 0; i < table->dimensions->n_dims; i++) + { + const struct spvlb_dimension *d = table->dimensions->dims[i]; + collect_value_strings (strings, d->name); + for (size_t j = 0; j < d->n_categories; j++) + collect_category_strings (strings, d->categories[j]); + } + + for (size_t i = 0; i < table->cells->n_cells; i++) + collect_value_strings (strings, table->cells->cells[i]->value); +} + +/* Returns the encoding that TABLE declares to be in use for its strings. + (Watch out, it's not always correct.) */ +const char * +spvlb_table_get_encoding (const struct spvlb_table *table) +{ + const struct spvlb_y1 *y1 = (table->formats->x0 ? table->formats->x0->y1 + : table->formats->x3 ? table->formats->x3->y1 + : NULL); + if (y1) + return y1->charset; + else + { + const char *dot = strchr (table->formats->locale, '.'); + return dot ? dot + 1 : "windows-1252"; + } +}