pivot-table: Tolerate nulls in pivot_value_clone().
[pspp] / src / output / pivot-table.c
index 22cd20de1339b1103f545d0873b05a8b3243325f..aa3b9b51c25b28185c2132ecd875cf403e4497d6 100644 (file)
@@ -18,6 +18,7 @@
 
 #include "output/pivot-table.h"
 
+#include <math.h>
 #include <stdlib.h>
 
 #include "data/data-out.h"
@@ -45,8 +46,8 @@
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
-static const struct fmt_spec *pivot_table_get_format (
-  const struct pivot_table *, const char *s);
+static void pivot_table_use_rc (const struct pivot_table *, const char *s,
+                                struct fmt_spec *, bool *honor_small);
 \f
 /* Pivot table display styling. */
 
@@ -394,17 +395,19 @@ pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis)
 static void
 pivot_category_set_rc (struct pivot_category *category, const char *s)
 {
-  const struct fmt_spec *format = pivot_table_get_format (
-    category->dimension->table, s);
-  if (format)
-    category->format = *format;
+  if (!s)
+    return;
+
+  pivot_table_use_rc (category->dimension->table, s,
+                      &category->format, &category->honor_small);
 
   /* Ensure that the category itself, in addition to the cells within it, takes
      the format.  (It's kind of rare for a category to have a numeric format
      though.) */
   struct pivot_value *name = category->name;
   if (name->type == PIVOT_VALUE_NUMERIC && !name->numeric.format.w)
-    name->numeric.format = format ? *format : *settings_get_format ();
+    pivot_table_use_rc (category->dimension->table, s,
+                        &name->numeric.format, &name->numeric.honor_small);
 }
 
 static void
@@ -764,19 +767,35 @@ pivot_result_class_find (const char *s)
   return NULL;
 }
 
-static const struct fmt_spec *
-pivot_table_get_format (const struct pivot_table *table, const char *s)
+static void
+pivot_table_use_rc (const struct pivot_table *table, const char *s,
+                    struct fmt_spec *format, bool *honor_small)
 {
-  if (!s)
-    return NULL;
-  else if (!strcmp (s, PIVOT_RC_OTHER))
-    return settings_get_format ();
-  else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
-    return &table->weight_format;
-  else
+  if (s)
     {
-      const struct result_class *rc = pivot_result_class_find (s);
-      return rc ? &rc->format : NULL;
+      if (!strcmp (s, PIVOT_RC_OTHER))
+        {
+          *format = *settings_get_format ();
+          *honor_small = true;
+        }
+      else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
+        {
+          *format = table->weight_format;
+          *honor_small = false;
+        }
+      else
+        {
+          const struct result_class *rc = pivot_result_class_find (s);
+          if (rc)
+            {
+              *format = rc->format;
+              *honor_small = false;
+            }
+          else
+            {
+              printf ("unknown class %s\n", s);
+            }
+        }
     }
 }
 
@@ -854,6 +873,7 @@ pivot_table_create__ (struct pivot_value *title, const char *subtype)
   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 ());
+  table->small = settings_get_small ();
 
   hmap_init (&table->cells);
 
@@ -968,7 +988,10 @@ clone_category (struct pivot_category *old,
 
   if (pivot_category_is_leaf (old))
     {
+      assert (new->data_index < new_dimension->n_leaves);
       new->dimension->data_leaves[new->data_index] = new;
+
+      assert (new->presentation_index < new_dimension->n_leaves);
       new->dimension->presentation_leaves[new->presentation_index] = new;
     }
 
@@ -1414,11 +1437,13 @@ pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
               if (c->format.w)
                 {
                   value->numeric.format = c->format;
+                  value->numeric.honor_small = c->honor_small;
                   goto done;
                 }
             }
         }
       value->numeric.format = *settings_get_format ();
+      value->numeric.honor_small = true;
 
     done:;
     }
@@ -2288,8 +2313,17 @@ pivot_value_format_body (const struct pivot_value *value,
                              value->numeric.value_label != NULL);
       if (show & SETTINGS_VALUE_SHOW_VALUE)
         {
+          const struct fmt_spec *f = &value->numeric.format;
+          const struct fmt_spec *format
+            = (f->type == FMT_F
+               && value->numeric.honor_small
+               && value->numeric.x != 0
+               && fabs (value->numeric.x) < pt->small
+               ? &(struct fmt_spec) { .type = FMT_E, .w = 40, .d = f->d }
+               : f);
+
           char *s = data_out (&(union value) { .f = value->numeric.x },
-                              "UTF-8", &value->numeric.format, &pt->settings);
+                              "UTF-8", format, &pt->settings);
           ds_put_cstr (out, s + strspn (s, " "));
           free (s);
         }
@@ -2417,7 +2451,7 @@ pivot_value_clone (const struct pivot_value *old)
       font_style_copy (NULL, new->font_style, old->font_style);
     }
   if (old->cell_style)
-    new->font_style = xmemdup (old->font_style, sizeof *new->font_style);
+    new->cell_style = xmemdup (old->cell_style, sizeof *new->cell_style);
   if (old->n_subscripts)
     {
       new->subscripts = xnmalloc (old->n_subscripts, sizeof *new->subscripts);
@@ -2449,10 +2483,10 @@ pivot_value_clone (const struct pivot_value *old)
     case PIVOT_VALUE_TEXT:
       new->text.local = xstrdup (old->text.local);
       new->text.c = (old->text.c == old->text.local ? new->text.local
-                     : xstrdup (old->text.c));
+                     : xstrdup_if_nonnull (old->text.c));
       new->text.id = (old->text.id == old->text.local ? new->text.local
                       : old->text.id == old->text.c ? new->text.c
-                      : xstrdup (old->text.id));
+                      : xstrdup_if_nonnull (old->text.id));
       break;
 
     case PIVOT_VALUE_TEMPLATE:
@@ -2817,10 +2851,7 @@ pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
                     const char *rc)
 {
   if (value->type == PIVOT_VALUE_NUMERIC)
-    {
-      const struct fmt_spec *f = pivot_table_get_format (table, rc);
-      if (f)
-        value->numeric.format = *f;
-    }
+    pivot_table_use_rc (table, rc,
+                        &value->numeric.format, &value->numeric.honor_small);
 }