)CILEVEL
authorBen Pfaff <blp@cs.stanford.edu>
Tue, 5 Jul 2022 01:32:57 +0000 (18:32 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Tue, 5 Jul 2022 01:32:57 +0000 (18:32 -0700)
src/language/stats/ctables.c
src/output/pivot-table.c
tests/language/stats/ctables.at

index f611af5100014c93fe13a61a94a3dbd915a7ae5b..470179127b50fe66b75427db605a62e805da0b72 100644 (file)
@@ -1073,19 +1073,40 @@ ctables_summary_default_format (enum ctables_summary_function function,
     }
 }
 
-static char *
-ctables_summary_default_label (enum ctables_summary_function function,
-                               double percentile)
+static struct pivot_value *
+ctables_summary_label (const struct ctables_summary_spec *spec, double cilevel)
 {
-  static const char *default_labels[] = {
+  if (!spec->label)
+    {
+      static const char *default_labels[] = {
 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = LABEL,
-    SUMMARIES
+        SUMMARIES
 #undef S
-  };
+      };
 
-  return (function == CTSF_PTILE
-          ? xasprintf (_("Percentile %.2f"), percentile)
-          : xstrdup (gettext (default_labels[function])));
+      return (spec->function == CTSF_PTILE
+              ? pivot_value_new_text_format (N_("Percentile %.2f"),
+                                             spec->percentile)
+              : pivot_value_new_text (default_labels[spec->function]));
+    }
+  else
+    {
+      struct substring in = ss_cstr (spec->label);
+      struct substring target = ss_cstr (")CILEVEL");
+
+      struct string out = DS_EMPTY_INITIALIZER;
+      for (;;)
+        {
+          size_t chunk = ss_find_substring (in, target);
+          ds_put_substring (&out, ss_head (in, chunk));
+          ss_advance (&in, chunk);
+          if (!in.length)
+            return pivot_value_new_user_text_nocopy (ds_steal_cstr (&out));
+          
+          ss_advance (&in, target.length);
+          ds_put_format (&out, "%g", cilevel);
+        }
+    }
 }
 
 static const char *
@@ -1146,7 +1167,7 @@ add_summary_spec (struct ctables_axis *axis,
       *dst = (struct ctables_summary_spec) {
         .function = function,
         .percentile = percentile,
-        .label = xstrdup (label),
+        .label = xstrdup_if_nonnull (label),
         .format = (format ? *format
                    : ctables_summary_default_format (function, axis->var)),
         .is_ctables_format = is_ctables_format,
@@ -1286,14 +1307,12 @@ ctables_axis_parse_postfix (struct ctables_axis_parse_ctx *ctx)
         }
 
       /* Parse label. */
-      char *label;
+      char *label = NULL;
       if (lex_is_string (ctx->lexer))
         {
           label = ss_xstrdup (lex_tokss (ctx->lexer));
           lex_get (ctx->lexer);
         }
-      else
-        label = ctables_summary_default_label (function, percentile);
 
       /* Parse format. */
       struct fmt_spec format;
@@ -3698,7 +3717,10 @@ merge_item_compare_3way (const struct merge_item *a, const struct merge_item *b)
     return as->function > bs->function ? 1 : -1;
   else if (as->percentile != bs->percentile)
     return as->percentile < bs->percentile ? 1 : -1;
-  return strcmp (as->label, bs->label);
+
+  const char *as_label = as->label ? as->label : "";
+  const char *bs_label = bs->label ? bs->label : "";
+  return strcmp (as_label, bs_label);
 }
 
 static struct pivot_value *
@@ -4135,7 +4157,7 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
         d->hide_all_labels = true;
       for (size_t i = 0; i < specs->n; i++)
         pivot_category_create_leaf (
-          d->root, pivot_value_new_text (specs->specs[i].label));
+          d->root, ctables_summary_label (&specs->specs[i], t->cilevel));
     }
 
   bool categories_dimension = t->clabels_example != NULL;
@@ -4330,7 +4352,8 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
                       for (size_t m = 0; m < specs->n; m++)
                         {
                           int leaf = pivot_category_create_leaf (
-                            parent, pivot_value_new_text (specs->specs[m].label));
+                            parent, ctables_summary_label (&specs->specs[m],
+                                                           t->cilevel));
                           if (!m)
                             prev_leaf = leaf;
                         }
@@ -4621,7 +4644,6 @@ ctables_prepare_table (struct ctables_table *t)
           *specs->specs = (struct ctables_summary_spec) {
             .function = function,
             .format = ctables_summary_default_format (function, specs->var),
-            .label = ctables_summary_default_label (function, 0),
           };
           if (!specs->var)
             specs->var = nest->vars[0];
index 009e8296139c6bb48d7e51985590009e1eaa7f29..f8f917d9dd1d965b3d5b2830b725c7c12004eee1 100644 (file)
@@ -2777,7 +2777,7 @@ pivot_value_new_text (const char *text)
 }
 
 /* Same as pivot_value_new_text() but its argument is a printf()-like format
-   string. */
+   string.  The format string should generally be enclosed in N_(). */
 struct pivot_value * PRINTF_FORMAT (1, 2)
 pivot_value_new_text_format (const char *format, ...)
 {
index 9f0eed8b9b2500198d593989ad0deeaaf168d45b..3bcae6541c11109a49e4571db2cafae9f769111a 100644 (file)
@@ -5,7 +5,6 @@ dnl
 dnl - SPLIT FILE with SEPARATE splits
 dnl - Definition of columns/rows when labels are rotated from one axis to another.
 dnl - Preprocessing to distinguish categorical from scale.
-dnl - )CILEVEL in summary specifications
 dnl - Summary functions:
 dnl   * Unimplemented ones.
 dnl   * .LCL and .UCL suffixes.
@@ -26,6 +25,7 @@ dnl - Test WEIGHT and adjustment weights.
 dnl - EMPTY=INCLUDE For string ranges.
 dnl - Summary functions:
 dnl   * Separate summary functions for totals and subtotals.
+dnl   * )CILEVEL in summary label specification
 dnl Category sorting:
 dnl   * VALUE
 dnl   * LABEL