totals can go first as well as last
[pspp] / src / language / stats / ctables.c
index ce635b15b8eaf67864c54c2befc24a357eafa66f..18fd30b683b3a438dd41036f2a596773a18b53cc 100644 (file)
@@ -2127,8 +2127,11 @@ ctables_categories_match (const struct ctables_categories *c,
 static const struct ctables_category *
 ctables_categories_total (const struct ctables_categories *c)
 {
-  const struct ctables_category *total = &c->cats[c->n_cats - 1];
-  return total->type == CCT_TOTAL ? total : NULL;
+  const struct ctables_category *first = &c->cats[0];
+  const struct ctables_category *last = &c->cats[c->n_cats - 1];
+  return (first->type == CCT_TOTAL ? first
+          : last->type == CCT_TOTAL ? last
+          : NULL);
 }
 
 static void
@@ -2207,6 +2210,38 @@ summarize:
     f->domains[dt]->valid += weight;
 }
 
+static void
+recurse_totals (struct ctables_table *t, const struct ccase *c,
+                size_t ix[PIVOT_N_AXES],
+                const struct ctables_category *cats[PIVOT_N_AXES][10],
+                double weight,
+                enum pivot_axis_type start_a, size_t start_va)
+{
+  for (enum pivot_axis_type a = start_a; a < PIVOT_N_AXES; a++)
+    {
+      const struct var_array *va = &t->vaas[a].vas[ix[a]];
+      for (size_t i = start_va; i < va->n; i++)
+        {
+          if (i == va->scale_idx)
+            continue;
+
+          const struct variable *var = va->vars[i];
+
+          const struct ctables_category *total = ctables_categories_total (
+            t->categories[var_get_dict_index (var)]);
+          if (total)
+            {
+              const struct ctables_category *save = cats[a][i];
+              cats[a][i] = total;
+              ctables_cell_insert__ (t, c, ix, cats, weight);
+              recurse_totals (t, c, ix, cats, weight, a, i + 1);
+              cats[a][i] = save;
+            }
+        }
+      start_va = 0;
+    }
+}
+
 static void
 ctables_cell_insert (struct ctables_table *t,
                      const struct ccase *c,
@@ -2243,27 +2278,7 @@ ctables_cell_insert (struct ctables_table *t,
 
   ctables_cell_insert__ (t, c, ix, cats, weight);
 
-  for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
-    {
-      const struct var_array *va = &t->vaas[a].vas[ix[a]];
-      for (size_t i = 0; i < va->n; i++)
-        {
-          if (i == va->scale_idx)
-            continue;
-
-          const struct variable *var = va->vars[i];
-
-          const struct ctables_category *total = ctables_categories_total (
-            t->categories[var_get_dict_index (var)]);
-          if (total)
-            {
-              const struct ctables_category *save = cats[a][i];
-              cats[a][i] = total;
-              ctables_cell_insert__ (t, c, ix, cats, weight);
-              cats[a][i] = save;
-            }
-        }
-    }
+  recurse_totals (t, c, ix, cats, weight, 0, 0);
 }
 
 static bool
@@ -2392,7 +2407,7 @@ ctables_execute (struct dataset *ds, struct ctables *ct)
         (t->title
          ? pivot_value_new_user_text (t->title, SIZE_MAX)
          : pivot_value_new_text (N_("Custom Tables"))),
-        NULL);
+        "Custom Tables");
       if (t->caption)
         pivot_table_set_caption (
           pt, pivot_value_new_user_text (t->caption, SIZE_MAX));