)LABEL[N]. untested, probably doesn't work.
authorBen Pfaff <blp@cs.stanford.edu>
Sun, 3 Jul 2022 18:23:36 +0000 (11:23 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Sun, 3 Jul 2022 18:23:36 +0000 (11:23 -0700)
src/language/stats/ctables.c
tests/language/stats/ctables.at

index 072b9f83a8d4f688d65c2a095f4498e454597f5a..ee35fd6bd3e790ba6a17446ed30139769819e97b 100644 (file)
@@ -3363,17 +3363,75 @@ merge_item_compare_3way (const struct merge_item *a, const struct merge_item *b)
 }
 
 static struct pivot_value *
-ctables_category_create_label (const struct ctables_category *cat,
-                               const struct variable *var,
-                               const union value *value)
+ctables_category_create_label__ (const struct ctables_category *cat,
+                                 const struct variable *var,
+                                 const union value *value)
 {
   return (cat->type == CCT_TOTAL || cat->type == CCT_SUBTOTAL
           ? pivot_value_new_user_text (cat->total_label, SIZE_MAX)
-          : cat->type == CCT_POSTCOMPUTE && cat->pc->label
-          ? pivot_value_new_user_text (cat->pc->label, SIZE_MAX)
           : pivot_value_new_var_value (var, value));
 }
 
+static struct pivot_value *
+ctables_postcompute_label (const struct ctables_categories *cats,
+                           const struct ctables_category *cat,
+                           const struct variable *var,
+                           const union value *value)
+{
+  struct substring in = ss_cstr (cat->pc->label);
+  struct substring target = ss_cstr (")LABEL[");
+
+  struct string out = DS_EMPTY_INITIALIZER;
+  for (;;)
+    {
+      size_t chunk = ss_find_substring (in, target);
+      if (chunk == SIZE_MAX)
+        {
+          if (ds_is_empty (&out))
+            return pivot_value_new_user_text (in.string, in.length);
+          else
+            {
+              ds_put_substring (&out, in);
+              return pivot_value_new_user_text_nocopy (ds_steal_cstr (&out));
+            }
+        }
+
+      ds_put_substring (&out, ss_head (in, chunk));
+      ss_advance (&in, chunk + target.length);
+
+      struct substring idx_s;
+      if (!ss_get_until (&in, ']', &idx_s))
+        goto error;
+      char *tail;
+      long int idx = strtol (idx_s.string, &tail, 10);
+      if (idx < 1 || idx > cats->n_cats || tail != ss_end (idx_s))
+        goto error;
+
+      struct ctables_category *cat2 = &cats->cats[idx - 1];
+      struct pivot_value *label2
+        = ctables_category_create_label__ (cat2, var, value);
+      char *label2_s = pivot_value_to_string_defaults (label2);
+      ds_put_cstr (&out, label2_s);
+      free (label2_s);
+      pivot_value_destroy (label2);
+    }
+
+error:
+  ds_destroy (&out);
+  return pivot_value_new_user_text (cat->pc->label, SIZE_MAX);
+}
+
+static struct pivot_value *
+ctables_category_create_label (const struct ctables_categories *cats,
+                               const struct ctables_category *cat,
+                               const struct variable *var,
+                               const union value *value)
+{
+  return (cat->type == CCT_POSTCOMPUTE && cat->pc->label
+          ? ctables_postcompute_label (cats, cat, var, value)
+          : ctables_category_create_label__ (cat, var, value));
+}
+
 static struct ctables_value *
 ctables_value_find__ (struct ctables_table *t, const union value *value,
                       int width, unsigned int hash)
@@ -3720,7 +3778,8 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
           const struct ctables_category *cat = ctables_categories_match (c, &value->value, var);
           assert (cat != NULL);
           pivot_category_create_leaf (d->root, ctables_category_create_label (
-                                        cat, t->clabels_example, &value->value));
+                                        c, cat, t->clabels_example,
+                                        &value->value));
         }
     }
 
@@ -3912,8 +3971,9 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
                       else if (level->type == CTL_CATEGORY)
                         {
                           const struct ctables_cell_value *cv = &cell->axes[a].cvs[level->var_idx];
-                          label = ctables_category_create_label (cv->category,
-                                                                 var, &cv->value);
+                          label = ctables_category_create_label (
+                            t->categories[var_get_dict_index (var)],
+                            cv->category, var, &cv->value);
                         }
                       else
                         NOT_REACHED ();
index a5ae1eebf0f00d03b6816bd63e77287bd5f8efff..1d787428d3fd96cd8a8585e7228595f349f5a3f2 100644 (file)
@@ -18,7 +18,6 @@ dnl   * multi-dimensional
 dnl   * MISSING, OTHERNM
 dnl   * strings
 dnl - PPROPERTIES:
-dnl   * )LABEL[N].
 dnl   * summary statistics and formats?
 dnl
 dnl Features not yet tested:
@@ -46,6 +45,8 @@ dnl - HIDESMALLCOUNTS.
 dnl - Date/time variables and values
 dnl - Special formats for summary functions: NEGPAREN, NEQUAL, PAREN, PCTPAREN.
 dnl - TITLES: )DATE, )TIME, )TABLE.
+dnl - PPROPERTIES:
+dnl   * )LABEL[N].
 dnl
 dnl Not for v1:
 dnl - Multiple response sets