pivot-table: Incorporate format settings.
authorBen Pfaff <blp@cs.stanford.edu>
Thu, 7 Jan 2021 01:03:43 +0000 (17:03 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Thu, 7 Jan 2021 04:29:38 +0000 (20:29 -0800)
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
src/data/format.h
src/data/settings.c
src/language/utilities/set.q
src/output/pivot-table.c
src/output/pivot-table.h
src/output/spv/spv-light-decoder.c
src/output/spv/spv-writer.c

index 12939c5dce5cbfcc64edb6155e230afdfb2723f6..a25e08f62b4d381e7b9490bc74ffe1dc27ebec85 100644 (file)
@@ -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)
 {
index 223ce1533d11f2185568d8f18f9e1c444277cde3..21b75a14f534d7196f9df4ddacb12a8cc58b67c9 100644 (file)
@@ -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 *);
 \f
@@ -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);
index 2479431b554687aff821f219cb6ae9cbf994683b..6a336af6a02896ed2d0f8b18ca76ac15ae0e5977 100644 (file)
@@ -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. */
index 4bdd910390d55d91b1beb9b2be737e16b13c84b6..159c9bef6b1bebdc5ccc6c25f11dcfdf10fecd49 100644 (file)
@@ -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 *
index 1fd136a57717f8d8ba56e4d0855cd7166523d627..22cd20de1339b1103f545d0873b05a8b3243325f 100644 (file)
@@ -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);
 }
 \f
 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);
         }
index e2bb886c30dc891d65c266d2aac7cdd3e6160fcf..343d7a3c09042011f9727a37cd0721840a9eb5ec 100644 (file)
@@ -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);
 \f
 /* 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. */
index 351f7caf80e3e5292322f092248a28ce14686547..9c4bf80bc1eb3f322075ab074bf2972d8fa351e6 100644 (file)
@@ -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. */
index fe8b8bacbe87fdaeb9729bd228f155d1776ec316..b8a4768fc00e300818b772e183cc7e2fab963960 100644 (file)
@@ -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