dates
[pspp] / src / language / stats / ctables.c
index 7b7a81946ca29bbec057550e06772e5c99f15c9d..2611bfebb3a53cbc21fb18e9ce9f546790b2c0e7 100644 (file)
@@ -1395,6 +1395,7 @@ ctables_destroy (struct ctables *ct)
       hmap_delete (&ct->postcomputes, &pc->hmap_node);
       free (pc);
     }
+  hmap_destroy (&ct->postcomputes);
 
   fmt_settings_uninit (&ct->ctables_formats);
   pivot_table_look_unref (ct->look);
@@ -2680,12 +2681,16 @@ ctables_summary_add (union ctables_summary *s,
       break;
 
     case CTSF_MISSING:
-      if (is_missing)
+      if (is_scale
+          ? is_scale_missing
+          : is_missing)
         s->count += d_weight;
       break;
 
     case CTSF_UMISSING:
-      if (is_missing)
+      if (is_scale
+          ? is_scale_missing
+          : is_missing)
         s->count += 1.0;
       break;
 
@@ -3889,21 +3894,88 @@ merge_item_compare_3way (const struct merge_item *a, const struct merge_item *b)
   return strcmp (as_label, bs_label);
 }
 
-static struct pivot_value *
-ctables_category_create_label__ (const struct ctables_category *cat,
-                                 const struct variable *var,
-                                 const union value *value)
+static void
+ctables_category_format_number (double number, const struct variable *var,
+                                struct string *s)
 {
-  return (cat->type == CCT_TOTAL || cat->type == CCT_SUBTOTAL
-          ? pivot_value_new_user_text (cat->total_label, SIZE_MAX)
-          : pivot_value_new_var_value (var, value));
+  struct pivot_value *pv = pivot_value_new_var_value (
+    var, &(union value) { .f = number });
+  pivot_value_format (pv, NULL, s);
+  pivot_value_destroy (pv);
+}
+
+static void
+ctables_category_format_string (struct substring string,
+                                const struct variable *var, struct string *out)
+{
+  int width = var_get_width (var);
+  char *s = xmalloc (width);
+  buf_copy_rpad (s, width, string.string, string.length, ' ');
+  struct pivot_value *pv = pivot_value_new_var_value (
+    var, &(union value) { .s = CHAR_CAST (uint8_t *, s) });
+  pivot_value_format (pv, NULL, out);
+  pivot_value_destroy (pv);
+  free (s);
+}
+
+static bool
+ctables_category_format_label (const struct ctables_category *cat,
+                               const struct variable *var,
+                               struct string *s)
+{
+  switch (cat->type)
+    {
+    case CCT_NUMBER:
+      ctables_category_format_number (cat->number, var, s);
+      return true;
+
+    case CCT_STRING:
+      ctables_category_format_string (cat->string, var, s);
+      return true;
+
+    case CCT_NRANGE:
+      ctables_category_format_number (cat->nrange[0], var, s);
+      ds_put_format (s, " THRU ");
+      ctables_category_format_number (cat->nrange[1], var, s);
+      return true;
+
+    case CCT_SRANGE:
+      ctables_category_format_string (cat->srange[0], var, s);
+      ds_put_format (s, " THRU ");
+      ctables_category_format_string (cat->srange[1], var, s);
+      return true;
+
+    case CCT_MISSING:
+      ds_put_cstr (s, "MISSING");
+      return true;
+
+    case CCT_OTHERNM:
+      ds_put_cstr (s, "OTHERNM");
+      return true;
+
+    case CCT_POSTCOMPUTE:
+      ds_put_format (s, "&%s", cat->pc->name);
+      return true;
+
+    case CCT_TOTAL:
+    case CCT_SUBTOTAL:
+      ds_put_cstr (s, cat->total_label);
+      return true;
+
+    case CCT_VALUE:
+    case CCT_LABEL:
+    case CCT_FUNCTION:
+    case CCT_EXCLUDED_MISSING:
+      return false;
+    }
+
+  return false;
 }
 
 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)
+                           const struct variable *var)
 {
   struct substring in = ss_cstr (cat->pc->label);
   struct substring target = ss_cstr (")LABEL[");
@@ -3935,12 +4007,8 @@ ctables_postcompute_label (const struct ctables_categories *cats,
         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);
+      if (!ctables_category_format_label (cat2, var, &out))
+        goto error;
     }
 
 error:
@@ -3949,14 +4017,16 @@ error:
 }
 
 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)
+ctables_category_create_value_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));
+          ? ctables_postcompute_label (cats, cat, var)
+          : cat->type == CCT_TOTAL || cat->type == CCT_SUBTOTAL
+          ? pivot_value_new_user_text (cat->total_label, SIZE_MAX)
+          : pivot_value_new_var_value (var, value));
 }
 
 static struct ctables_value *
@@ -4170,6 +4240,8 @@ ctables_pcexpr_evaluate (const struct ctables_pcexpr_evaluate_ctx *ctx,
 
     case CTPO_CAT_NRANGE:
     case CTPO_CAT_SRANGE:
+    case CTPO_CAT_MISSING:
+    case CTPO_CAT_OTHERNM:
       {
         struct ctables_cell_value cv = {
           .category = ctables_find_category_for_postcompute (ctx->section->table->ctables->dict, ctx->cats, ctx->parse_format, e)
@@ -4191,8 +4263,6 @@ ctables_pcexpr_evaluate (const struct ctables_pcexpr_evaluate_ctx *ctx,
       }
 
     case CTPO_CAT_NUMBER:
-    case CTPO_CAT_MISSING:
-    case CTPO_CAT_OTHERNM:
     case CTPO_CAT_SUBTOTAL:
     case CTPO_CAT_TOTAL:
       {
@@ -4213,11 +4283,21 @@ ctables_pcexpr_evaluate (const struct ctables_pcexpr_evaluate_ctx *ctx,
             s = xmalloc (width);
             buf_copy_rpad (s, width, e->string.string, e->string.length, ' ');
           }
-        struct ctables_cell_value cv = {
-          .category = ctables_find_category_for_postcompute (ctx->section->table->ctables->dict, ctx->cats, ctx->parse_format, e),
-          .value = { .s = CHAR_CAST (uint8_t *, s ? s : e->string.string) },
-        };
-        assert (cv.category != NULL);
+
+        const struct ctables_category *category
+          = ctables_find_category_for_postcompute (
+            ctx->section->table->ctables->dict,
+            ctx->cats, ctx->parse_format, e);
+        assert (category != NULL);
+
+        struct ctables_cell_value cv = { .category = category };
+        if (category->type == CCT_NUMBER)
+          cv.value.f = category->number;
+        else if (category->type == CCT_STRING)
+          cv.value.s = CHAR_CAST (uint8_t *, s ? s : e->string.string);
+        else
+          NOT_REACHED ();
+
         double retval = ctables_pcexpr_evaluate_category (ctx, &cv);
         free (s);
         return retval;
@@ -4355,6 +4435,23 @@ ctables_format (double d, const struct fmt_spec *format,
   return s;
 }
 
+static bool
+all_hidden_vlabels (const struct ctables_table *t, enum pivot_axis_type a)
+{
+  for (size_t i = 0; i < t->stacks[a].n; i++)
+    {
+      struct ctables_nest *nest = &t->stacks[a].nests[i];
+      if (nest->n != 1 || nest->scale_idx != 0)
+        return false;
+
+      enum ctables_vlabel vlabel
+        = t->ctables->vlabels[var_get_dict_index (nest->vars[0])];
+      if (vlabel != CTVL_NONE)
+        return false;
+    }
+  return true;
+}
+
 static void
 ctables_table_output (struct ctables *ct, struct ctables_table *t)
 {
@@ -4400,9 +4497,10 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
           const struct ctables_value *value = t->clabels_values[i];
           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 (
-                                        c, cat, t->clabels_example,
-                                        &value->value));
+          pivot_category_create_leaf (
+            d->root, ctables_category_create_value_label (c, cat,
+                                                          t->clabels_example,
+                                                          &value->value));
         }
     }
 
@@ -4505,6 +4603,8 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
           for (size_t k = 0; k < nest->n; k++)
             {
               enum ctables_vlabel vlabel = ct->vlabels[var_get_dict_index (nest->vars[k])];
+              if (vlabel == CTVL_NONE && nest->scale_idx == k)
+                vlabel = CTVL_NAME;
               if (vlabel != CTVL_NONE)
                 {
                   levels[n_levels++] = (struct ctables_level) {
@@ -4613,7 +4713,7 @@ 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 (
+                          label = ctables_category_create_value_label (
                             t->categories[var_get_dict_index (var)],
                             cv->category, var, &cv->value);
                         }
@@ -4633,7 +4733,10 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
           free (groups);
           free (levels);
           free (sections);
+
         }
+
+      d[a]->hide_all_labels = all_hidden_vlabels (t, a);
     }
 
   {