From b0486442675e454c1e542a7098e5f127b2757787 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Wed, 6 Jan 2021 17:03:43 -0800 Subject: [PATCH] pivot-table: Incorporate format settings. This allows pivot tables to save the decimal point and custom currency settings that were in effect when they were created, and to honor the ones read from an .spv file. --- src/data/format.c | 38 ++++++++++++++++--- src/data/format.h | 4 +- src/data/settings.c | 2 +- src/language/utilities/set.q | 30 +-------------- src/output/pivot-table.c | 61 ++++++++++++------------------ src/output/pivot-table.h | 7 ++-- src/output/spv/spv-light-decoder.c | 22 +++++++++-- src/output/spv/spv-writer.c | 12 ++++-- 8 files changed, 94 insertions(+), 82 deletions(-) diff --git a/src/data/format.c b/src/data/format.c index 12939c5dce..a25e08f62b 100644 --- a/src/data/format.c +++ b/src/data/format.c @@ -63,13 +63,13 @@ fmt_settings_uninit (struct fmt_settings *settings) fmt_number_style_destroy (settings->ccs[i]); } -void -fmt_settings_copy (struct fmt_settings *new, const struct fmt_settings *old) +struct fmt_settings +fmt_settings_copy (const struct fmt_settings *old) { - new->epoch = old->epoch; - new->decimal = old->decimal; + struct fmt_settings new = *old; for (int i = 0; i < FMT_N_CCS; i++) - new->ccs[i] = fmt_number_style_clone (old->ccs[i]); + new.ccs[i] = fmt_number_style_clone (old->ccs[i]); + return new; } static size_t @@ -1240,6 +1240,34 @@ fmt_number_style_from_string (const char *s) return style; } +static void +format_cc (struct string *out, const char *in, char grouping) +{ + while (*in != '\0') + { + char c = *in++; + if (c == grouping || c == '\'') + ds_put_byte (out, '\''); + else if (c == '"') + ds_put_byte (out, '"'); + ds_put_byte (out, c); + } +} + +char * +fmt_number_style_to_string (const struct fmt_number_style *cc) +{ + struct string out = DS_EMPTY_INITIALIZER; + format_cc (&out, cc->neg_prefix.s, cc->grouping); + ds_put_byte (&out, cc->grouping); + format_cc (&out, cc->prefix.s, cc->grouping); + ds_put_byte (&out, cc->grouping); + format_cc (&out, cc->suffix.s, cc->grouping); + ds_put_byte (&out, cc->grouping); + format_cc (&out, cc->neg_suffix.s, cc->grouping); + return ds_steal_cstr (&out); +} + struct fmt_number_style * fmt_number_style_clone (const struct fmt_number_style *old) { diff --git a/src/data/format.h b/src/data/format.h index 223ce1533d..21b75a14f5 100644 --- a/src/data/format.h +++ b/src/data/format.h @@ -175,6 +175,8 @@ struct fmt_number_style *fmt_number_style_clone ( const struct fmt_number_style *); void fmt_number_style_destroy (struct fmt_number_style *); +char *fmt_number_style_to_string (const struct fmt_number_style *); + int fmt_affix_width (const struct fmt_number_style *); int fmt_neg_affix_width (const struct fmt_number_style *); @@ -191,7 +193,7 @@ struct fmt_settings void fmt_settings_init (struct fmt_settings *); void fmt_settings_uninit (struct fmt_settings *); -void fmt_settings_copy (struct fmt_settings *, const struct fmt_settings *); +struct fmt_settings fmt_settings_copy (const struct fmt_settings *); const struct fmt_number_style *fmt_settings_get_style ( const struct fmt_settings *, enum fmt_type); diff --git a/src/data/settings.c b/src/data/settings.c index 2479431b55..6a336af6a0 100644 --- a/src/data/settings.c +++ b/src/data/settings.c @@ -140,7 +140,7 @@ static void settings_copy (struct settings *dst, const struct settings *src) { *dst = *src; - fmt_settings_copy (&dst->styles, &src->styles); + dst->styles = fmt_settings_copy (&src->styles); } /* Returns a copy of the current settings. */ diff --git a/src/language/utilities/set.q b/src/language/utilities/set.q index 4bdd910390..159c9bef6b 100644 --- a/src/language/utilities/set.q +++ b/src/language/utilities/set.q @@ -655,37 +655,11 @@ show_blanks (const struct dataset *ds UNUSED) : xasprintf ("%.*g", DBL_DIG + 1, settings_get_blanks ())); } -static void -format_cc (struct string *out, const char *in, char grouping) -{ - while (*in != '\0') - { - char c = *in++; - if (c == grouping || c == '\'') - ds_put_byte (out, '\''); - else if (c == '"') - ds_put_byte (out, '"'); - ds_put_byte (out, c); - } -} - static char * show_cc (enum fmt_type type) { - const struct fmt_number_style *cc = fmt_settings_get_style ( - settings_get_fmt_settings (), type); - struct string out; - - ds_init_empty (&out); - format_cc (&out, cc->neg_prefix.s, cc->grouping); - ds_put_byte (&out, cc->grouping); - format_cc (&out, cc->prefix.s, cc->grouping); - ds_put_byte (&out, cc->grouping); - format_cc (&out, cc->suffix.s, cc->grouping); - ds_put_byte (&out, cc->grouping); - format_cc (&out, cc->neg_suffix.s, cc->grouping); - - return ds_cstr (&out); + return fmt_number_style_to_string (fmt_settings_get_style ( + settings_get_fmt_settings (), type)); } static char * diff --git a/src/output/pivot-table.c b/src/output/pivot-table.c index 1fd136a577..22cd20de13 100644 --- a/src/output/pivot-table.c +++ b/src/output/pivot-table.c @@ -853,6 +853,7 @@ pivot_table_create__ (struct pivot_value *title, const char *subtype) table->subtype = subtype ? pivot_value_new_text (subtype) : NULL; table->command_c = output_get_command_name (); table->look = pivot_table_look_ref (pivot_table_look_get_default ()); + table->settings = fmt_settings_copy (settings_get_fmt_settings ()); hmap_init (&table->cells); @@ -1047,16 +1048,8 @@ pivot_table_unshare (struct pivot_table *old) [TABLE_VERT] = clone_sizing (&old->sizing[TABLE_VERT]), }, - .epoch = old->epoch, - .decimal = old->decimal, + .settings = fmt_settings_copy (&old->settings), .grouping = old->grouping, - .ccs = { - [0] = xstrdup_if_nonnull (old->ccs[0]), - [1] = xstrdup_if_nonnull (old->ccs[1]), - [2] = xstrdup_if_nonnull (old->ccs[2]), - [3] = xstrdup_if_nonnull (old->ccs[3]), - [4] = xstrdup_if_nonnull (old->ccs[4]), - }, .small = old->small, .command_local = xstrdup_if_nonnull (old->command_local), @@ -1134,8 +1127,7 @@ pivot_table_unref (struct pivot_table *table) for (int i = 0; i < TABLE_N_AXES; i++) pivot_table_sizing_uninit (&table->sizing[i]); - for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++) - free (table->ccs[i]); + fmt_settings_uninit (&table->settings); free (table->command_local); free (table->command_c); @@ -1782,22 +1774,23 @@ indent (int indentation) } static void -pivot_value_dump (const struct pivot_value *value) +pivot_value_dump (const struct pivot_value *value, + const struct pivot_table *pt) { - char *s = pivot_value_to_string_defaults (value); + char *s = pivot_value_to_string (value, pt); fputs (s, stdout); free (s); } static void pivot_table_dump_value (const struct pivot_value *value, const char *name, - int indentation) + const struct pivot_table *pt, int indentation) { if (value) { indent (indentation); printf ("%s: ", name); - pivot_value_dump (value); + pivot_value_dump (value, pt); putchar ('\n'); } } @@ -1813,11 +1806,12 @@ pivot_table_dump_string (const char *string, const char *name, int indentation) } static void -pivot_category_dump (const struct pivot_category *c, int indentation) +pivot_category_dump (const struct pivot_category *c, + const struct pivot_table *pt, int indentation) { indent (indentation); printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group"); - pivot_value_dump (c->name); + pivot_value_dump (c->name, pt); printf ("\" "); if (pivot_category_is_leaf (c)) @@ -1828,18 +1822,19 @@ pivot_category_dump (const struct pivot_category *c, int indentation) printf ("\n"); for (size_t i = 0; i < c->n_subs; i++) - pivot_category_dump (c->subs[i], indentation + 1); + pivot_category_dump (c->subs[i], pt, indentation + 1); } } void -pivot_dimension_dump (const struct pivot_dimension *d, int indentation) +pivot_dimension_dump (const struct pivot_dimension *d, + const struct pivot_table *pt, int indentation) { indent (indentation); printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n", pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth); - pivot_category_dump (d->root, indentation + 1); + pivot_category_dump (d->root, pt, indentation + 1); } static void @@ -1964,12 +1959,8 @@ pivot_table_dump (const struct pivot_table *table, int indentation) pivot_table_assign_label_depth (CONST_CAST (struct pivot_table *, table)); - int old_decimal = settings_get_fmt_settings ()->decimal; - if (table->decimal == '.' || table->decimal == ',') - settings_set_decimal_char (table->decimal); - - pivot_table_dump_value (table->title, "title", indentation); - pivot_table_dump_value (table->subtype, "subtype", indentation); + pivot_table_dump_value (table->title, "title", table, indentation); + pivot_table_dump_value (table->subtype, "subtype", table, indentation); pivot_table_dump_string (table->command_c, "command", indentation); pivot_table_dump_string (table->dataset, "dataset", indentation); pivot_table_dump_string (table->datafile, "datafile", indentation); @@ -2004,7 +1995,7 @@ pivot_table_dump (const struct pivot_table *table, int indentation) indentation + 1); for (size_t i = 0; i < table->n_dimensions; i++) - pivot_dimension_dump (table->dimensions[i], indentation); + pivot_dimension_dump (table->dimensions[i], table, indentation); /* Presentation and data indexes. */ size_t *dindexes = XCALLOC (table->n_dimensions, size_t); @@ -2042,7 +2033,7 @@ pivot_table_dump (const struct pivot_table *table, int indentation) const struct pivot_dimension *d = layer_axis->dimensions[i]; fputs (i == 0 ? " " : ", ", stdout); - pivot_value_dump (d->root->name); + pivot_value_dump (d->root->name, table); fputs (" =", stdout); struct pivot_value **names = xnmalloc (d->n_leaves, sizeof *names); @@ -2059,7 +2050,7 @@ pivot_table_dump (const struct pivot_table *table, int indentation) for (size_t i = n_names; i-- > 0;) { putchar (' '); - pivot_value_dump (names[i]); + pivot_value_dump (names[i], table); } free (names); } @@ -2123,7 +2114,7 @@ pivot_table_dump (const struct pivot_table *table, int indentation) const struct pivot_value *value = pivot_table_get ( table, dindexes); if (value) - pivot_value_dump (value); + pivot_value_dump (value, table); } printf ("\n"); @@ -2135,7 +2126,7 @@ pivot_table_dump (const struct pivot_table *table, int indentation) free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings); } - pivot_table_dump_value (table->caption, "caption", indentation); + pivot_table_dump_value (table->caption, "caption", table, indentation); for (size_t i = 0; i < table->n_footnotes; i++) { @@ -2143,16 +2134,15 @@ pivot_table_dump (const struct pivot_table *table, int indentation) indent (indentation); putchar ('['); if (f->marker) - pivot_value_dump (f->marker); + pivot_value_dump (f->marker, table); else printf ("%zu", f->idx); putchar (']'); - pivot_value_dump (f->content); + pivot_value_dump (f->content, table); putchar ('\n'); } free (dindexes); - settings_set_decimal_char (old_decimal); } static const char * @@ -2299,8 +2289,7 @@ pivot_value_format_body (const struct pivot_value *value, if (show & SETTINGS_VALUE_SHOW_VALUE) { char *s = data_out (&(union value) { .f = value->numeric.x }, - "UTF-8", &value->numeric.format, - settings_get_fmt_settings ()); + "UTF-8", &value->numeric.format, &pt->settings); ds_put_cstr (out, s + strspn (s, " ")); free (s); } diff --git a/src/output/pivot-table.h b/src/output/pivot-table.h index e2bb886c30..343d7a3c09 100644 --- a/src/output/pivot-table.h +++ b/src/output/pivot-table.h @@ -278,7 +278,8 @@ struct pivot_dimension *pivot_dimension_create__ (struct pivot_table *, void pivot_dimension_destroy (struct pivot_dimension *); -void pivot_dimension_dump (const struct pivot_dimension *, int indentation); +void pivot_dimension_dump (const struct pivot_dimension *, + const struct pivot_table *, int indentation); /* A pivot_category is a leaf (a category) or a group: @@ -439,10 +440,8 @@ struct pivot_table struct pivot_table_sizing sizing[TABLE_N_AXES]; /* Format settings. */ - int epoch; - char decimal; /* Usually ',' or '.'. */ + struct fmt_settings settings; char grouping; /* Usually '.' or ','. */ - char *ccs[5]; /* Custom currency. */ double small; /* Command information. */ diff --git a/src/output/spv/spv-light-decoder.c b/src/output/spv/spv-light-decoder.c index 351f7caf80..9c4bf80bc1 100644 --- a/src/output/spv/spv-light-decoder.c +++ b/src/output/spv/spv-light-decoder.c @@ -828,6 +828,7 @@ decode_spvlb_table (const struct spvlb_table *in, struct pivot_table **outp) 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 @@ -910,13 +911,26 @@ decode_spvlb_table (const struct spvlb_table *in, struct pivot_table **outp) 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. */ diff --git a/src/output/spv/spv-writer.c b/src/output/spv/spv-writer.c index fe8b8bacbe..b8a4768fc0 100644 --- a/src/output/spv/spv-writer.c +++ b/src/output/spv/spv-writer.c @@ -698,8 +698,8 @@ put_category (struct buf *buf, const struct pivot_category *c) static void put_y0 (struct buf *buf, const struct pivot_table *table) { - put_u32 (buf, table->epoch); - put_byte (buf, table->decimal); + put_u32 (buf, table->settings.epoch); + put_byte (buf, table->settings.decimal); put_byte (buf, table->grouping); } @@ -708,7 +708,13 @@ put_custom_currency (struct buf *buf, const struct pivot_table *table) { put_u32 (buf, 5); for (int i = 0; i < 5; i++) - put_string (buf, table->ccs[i]); + { + enum fmt_type types[5] = { FMT_CCA, FMT_CCB, FMT_CCC, FMT_CCD, FMT_CCE }; + char *cc = fmt_number_style_to_string (fmt_settings_get_style ( + &table->settings, types[i])); + put_string (buf, cc); + free (cc); + } } static void -- 2.30.2