Revert "work on adding empty categories"
[pspp] / src / language / stats / ctables.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2021 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include <math.h>
20
21 #include "data/casereader.h"
22 #include "data/casewriter.h"
23 #include "data/dataset.h"
24 #include "data/dictionary.h"
25 #include "data/mrset.h"
26 #include "data/subcase.h"
27 #include "data/value-labels.h"
28 #include "language/command.h"
29 #include "language/lexer/format-parser.h"
30 #include "language/lexer/lexer.h"
31 #include "language/lexer/variable-parser.h"
32 #include "libpspp/array.h"
33 #include "libpspp/assertion.h"
34 #include "libpspp/hash-functions.h"
35 #include "libpspp/hmap.h"
36 #include "libpspp/message.h"
37 #include "libpspp/string-array.h"
38 #include "math/mode.h"
39 #include "math/moments.h"
40 #include "math/percentiles.h"
41 #include "math/sort.h"
42 #include "output/pivot-table.h"
43
44 #include "gl/minmax.h"
45 #include "gl/xalloc.h"
46
47 #include "gettext.h"
48 #define _(msgid) gettext (msgid)
49 #define N_(msgid) (msgid)
50
51 enum ctables_vlabel
52   {
53     CTVL_NONE = SETTINGS_VALUE_SHOW_DEFAULT,
54     CTVL_NAME = SETTINGS_VALUE_SHOW_VALUE,
55     CTVL_LABEL = SETTINGS_VALUE_SHOW_LABEL,
56     CTVL_BOTH = SETTINGS_VALUE_SHOW_BOTH,
57   };
58
59 /* XXX:
60    - unweighted summaries (U*)
61    - lower confidence limits (*.LCL)
62    - upper confidence limits (*.UCL)
63    - standard error (*.SE)
64  */
65 #define SUMMARIES                                                       \
66     /* All variables. */                                                \
67     S(CTSF_COUNT, "COUNT", N_("Count"), CTF_COUNT, CTFA_ALL)            \
68     S(CTSF_ECOUNT, "ECOUNT", N_("Adjusted Count"), CTF_COUNT, CTFA_ALL) \
69     S(CTSF_ROWPCT_COUNT, "ROWPCT.COUNT", N_("Row %"), CTF_PERCENT, CTFA_ALL) \
70     S(CTSF_COLPCT_COUNT, "COLPCT.COUNT", N_("Column %"), CTF_PERCENT, CTFA_ALL) \
71     S(CTSF_TABLEPCT_COUNT, "TABLEPCT.COUNT", N_("Table %"), CTF_PERCENT, CTFA_ALL) \
72     S(CTSF_SUBTABLEPCT_COUNT, "SUBTABLEPCT.COUNT", N_("Subtable %"), CTF_PERCENT, CTFA_ALL) \
73     S(CTSF_LAYERPCT_COUNT, "LAYERPCT.COUNT", N_("Layer %"), CTF_PERCENT, CTFA_ALL) \
74     S(CTSF_LAYERROWPCT_COUNT, "LAYERROWPCT.COUNT", N_("Layer Row %"), CTF_PERCENT, CTFA_ALL) \
75     S(CTSF_LAYERCOLPCT_COUNT, "LAYERCOLPCT.COUNT", N_("Layer Column %"), CTF_PERCENT, CTFA_ALL) \
76     S(CTSF_ROWPCT_VALIDN, "ROWPCT.VALIDN", N_("Row Valid N %"), CTF_PERCENT, CTFA_ALL) \
77     S(CTSF_COLPCT_VALIDN, "COLPCT.VALIDN", N_("Column Valid N %"), CTF_PERCENT, CTFA_ALL) \
78     S(CTSF_TABLEPCT_VALIDN, "TABLEPCT.VALIDN", N_("Table Valid N %"), CTF_PERCENT, CTFA_ALL) \
79     S(CTSF_SUBTABLEPCT_VALIDN, "SUBTABLEPCT.VALIDN", N_("Subtable Valid N %"), CTF_PERCENT, CTFA_ALL) \
80     S(CTSF_LAYERPCT_VALIDN, "LAYERPCT.VALIDN", N_("Layer Valid N %"), CTF_PERCENT, CTFA_ALL) \
81     S(CTSF_LAYERROWPCT_VALIDN, "LAYERROWPCT.VALIDN", N_("Layer Row Valid N %"), CTF_PERCENT, CTFA_ALL) \
82     S(CTSF_LAYERCOLPCT_VALIDN, "LAYERCOLPCT.VALIDN", N_("Layer Column Valid N %"), CTF_PERCENT, CTFA_ALL) \
83     S(CTSF_ROWPCT_TOTALN, "ROWPCT.TOTALN", N_("Row Total N %"), CTF_PERCENT, CTFA_ALL) \
84     S(CTSF_COLPCT_TOTALN, "COLPCT.TOTALN", N_("Column Total N %"), CTF_PERCENT, CTFA_ALL) \
85     S(CTSF_TABLEPCT_TOTALN, "TABLEPCT.TOTALN", N_("Table Total N %"), CTF_PERCENT, CTFA_ALL) \
86     S(CTSF_SUBTABLEPCT_TOTALN, "SUBTABLEPCT.TOTALN", N_("Subtable Total N %"), CTF_PERCENT, CTFA_ALL) \
87     S(CTSF_LAYERPCT_TOTALN, "LAYERPCT.TOTALN", N_("Layer Total N %"), CTF_PERCENT, CTFA_ALL) \
88     S(CTSF_LAYERROWPCT_TOTALN, "LAYERROWPCT.TOTALN", N_("Layer Row Total N %"), CTF_PERCENT, CTFA_ALL) \
89     S(CTSF_LAYERCOLPCT_TOTALN, "LAYERCOLPCT.TOTALN", N_("Layer Column Total N %"), CTF_PERCENT, CTFA_ALL) \
90                                                                         \
91     /* Scale variables, totals, and subtotals. */                       \
92     S(CTSF_MAXIMUM, "MAXIMUM", N_("Maximum"), CTF_GENERAL, CTFA_SCALE)  \
93     S(CTSF_MEAN, "MEAN", N_("Mean"), CTF_GENERAL, CTFA_SCALE)           \
94     S(CTSF_MEDIAN, "MEDIAN", N_("Median"), CTF_GENERAL, CTFA_SCALE)     \
95     S(CTSF_MINIMUM, "MINIMUM", N_("Minimum"), CTF_GENERAL, CTFA_SCALE)  \
96     S(CTSF_MISSING, "MISSING", N_("Missing"), CTF_GENERAL, CTFA_SCALE)  \
97     S(CTSF_MODE, "MODE", N_("Mode"), CTF_GENERAL, CTFA_SCALE)           \
98     S(CTSF_PTILE, "PTILE", N_("Percentile"), CTF_GENERAL, CTFA_SCALE)   \
99     S(CTSF_RANGE, "RANGE", N_("Range"), CTF_GENERAL, CTFA_SCALE)        \
100     S(CTSF_SEMEAN, "SEMEAN", N_("Std Error of Mean"), CTF_GENERAL, CTFA_SCALE) \
101     S(CTSF_STDDEV, "STDDEV", N_("Std Deviation"), CTF_GENERAL, CTFA_SCALE) \
102     S(CTSF_SUM, "SUM", N_("Sum"), CTF_GENERAL, CTFA_SCALE)              \
103     S(CSTF_TOTALN, "TOTALN", N_("Total N"), CTF_COUNT, CTFA_SCALE)      \
104     S(CTSF_ETOTALN, "ETOTALN", N_("Adjusted Total N"), CTF_COUNT, CTFA_SCALE) \
105     S(CTSF_VALIDN, "VALIDN", N_("Valid N"), CTF_COUNT, CTFA_SCALE)      \
106     S(CTSF_EVALIDN, "EVALIDN", N_("Adjusted Valid N"), CTF_COUNT, CTFA_SCALE) \
107     S(CTSF_VARIANCE, "VARIANCE", N_("Variance"), CTF_GENERAL, CTFA_SCALE) \
108     S(CTSF_ROWPCT_SUM, "ROWPCT.SUM", N_("Row Sum %"), CTF_PERCENT, CTFA_SCALE) \
109     S(CTSF_COLPCT_SUM, "COLPCT.SUM", N_("Column Sum %"), CTF_PERCENT, CTFA_SCALE) \
110     S(CTSF_TABLEPCT_SUM, "TABLEPCT.SUM", N_("Table Sum %"), CTF_PERCENT, CTFA_SCALE) \
111     S(CTSF_SUBTABLEPCT_SUM, "SUBTABLEPCT.SUM", N_("Subtable Sum %"), CTF_PERCENT, CTFA_SCALE) \
112     S(CTSF_LAYERPCT_SUM, "LAYERPCT.SUM", N_("Layer Sum %"), CTF_PERCENT, CTFA_SCALE) \
113     S(CTSF_LAYERROWPCT_SUM, "LAYERROWPCT.SUM", N_("Layer Row Sum %"), CTF_PERCENT, CTFA_SCALE) \
114     S(CTSF_LAYERCOLPCT_SUM, "LAYERCOLPCT.SUM", N_("Layer Column Sum %"), CTF_PERCENT, CTFA_SCALE) \
115                                                                         \
116     /* Multiple response sets. */                                       \
117   S(CTSF_RESPONSES, "RESPONSES", N_("Responses"), CTF_COUNT, CTFA_MRSETS) \
118     S(CTSF_ROWPCT_RESPONSES, "ROWPCT.RESPONSES", N_("Row Responses %"), CTF_PERCENT, CTFA_MRSETS) \
119     S(CTSF_COLPCT_RESPONSES, "COLPCT.RESPONSES", N_("Column Responses %"), CTF_PERCENT, CTFA_MRSETS) \
120     S(CTSF_TABLEPCT_RESPONSES, "TABLEPCT.RESPONSES", N_("Table Responses %"), CTF_PERCENT, CTFA_MRSETS) \
121     S(CTSF_SUBTABLEPCT_RESPONSES, "SUBTABLEPCT.RESPONSES", N_("Subtable Responses %"), CTF_PERCENT, CTFA_MRSETS) \
122     S(CTSF_LAYERPCT_RESPONSES, "LAYERPCT.RESPONSES", N_("Layer Responses %"), CTF_PERCENT, CTFA_MRSETS) \
123     S(CTSF_LAYERROWPCT_RESPONSES, "LAYERROWPCT.RESPONSES", N_("Layer Row Responses %"), CTF_PERCENT, CTFA_MRSETS) \
124     S(CTSF_LAYERCOLPCT_RESPONSES, "LAYERCOLPCT.RESPONSES", N_("Layer Column Responses %"), CTF_PERCENT, CTFA_MRSETS) \
125     S(CTSF_ROWPCT_RESPONSES_COUNT, "ROWPCT.RESPONSES.COUNT", N_("Row Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
126     S(CTSF_COLPCT_RESPONSES_COUNT, "COLPCT.RESPONSES.COUNT", N_("Column Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
127     S(CTSF_TABLEPCT_RESPONSES_COUNT, "TABLEPCT.RESPONSES.COUNT", N_("Table Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
128     S(CTSF_SUBTABLEPCT_RESPONSES_COUNT, "SUBTABLEPCT.RESPONSES.COUNT", N_("Subtable Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
129     S(CTSF_LAYERPCT_RESPONSES_COUNT, "LAYERPCT.RESPONSES.COUNT", N_("Layer Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
130     S(CTSF_LAYERROWPCT_RESPONSES_COUNT, "LAYERROWPCT.RESPONSES.COUNT", N_("Layer Row Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
131     S(CTSF_LAYERCOLPCT_RESPONSES_COUNT, "LAYERCOLPCT.RESPONSES.COUNT", N_("Layer Column Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
132     S(CTSF_ROWPCT_COUNT_RESPONSES, "ROWPCT.COUNT.RESPONSES", N_("Row Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
133     S(CTSF_COLPCT_COUNT_RESPONSES, "COLPCT.COUNT.RESPONSES", N_("Column Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
134     S(CTSF_TABLEPCT_COUNT_RESPONSES, "TABLEPCT.COUNT.RESPONSES", N_("Table Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
135     S(CTSF_SUBTABLEPCT_COUNT_RESPONSES, "SUBTABLEPCT.COUNT.RESPONSES", N_("Subtable Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
136     S(CTSF_LAYERPCT_COUNT_RESPONSES, "LAYERPCT.COUNT.RESPONSES", N_("Layer Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
137     S(CTSF_LAYERROWPCT_COUNT_RESPONSES, "LAYERROWPCT.COUNT.RESPONSES", N_("Layer Row Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
138     S(CTSF_LAYERCOLPCT_COUNT_RESPONSES, "LAYERCOLPCT.RESPONSES.COUNT", N_("Layer Column Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS)
139
140 enum ctables_summary_function
141   {
142 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) ENUM,
143     SUMMARIES
144 #undef S
145   };
146
147 enum {
148 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) +1
149   N_CTSF_FUNCTIONS = SUMMARIES
150 #undef S
151 };
152
153 enum ctables_domain_type
154   {
155     /* Within a section, where stacked variables divide one section from
156        another. */
157     CTDT_TABLE,                  /* All layers of a whole section. */
158     CTDT_LAYER,                  /* One layer within a section. */
159     CTDT_LAYERROW,               /* Row in one layer within a section. */
160     CTDT_LAYERCOL,               /* Column in one layer within a section. */
161
162     /* Within a subtable, where a subtable pairs an innermost row variable with
163        an innermost column variable within a single layer.  */
164     CTDT_SUBTABLE,               /* Whole subtable. */
165     CTDT_ROW,                    /* Row within a subtable. */
166     CTDT_COL,                    /* Column within a subtable. */
167 #define N_CTDTS 7
168   };
169
170 struct ctables_domain
171   {
172     struct hmap_node node;
173
174     const struct ctables_cell *example;
175
176     double d_valid;             /* Dictionary weight. */
177     double d_missing;
178     double e_valid;             /* Effective weight */
179     double e_missing;
180   };
181
182 enum ctables_summary_variant
183   {
184     CSV_CELL,
185     CSV_TOTAL
186 #define N_CSVS 2
187   };
188
189 struct ctables_cell
190   {
191     /* In struct ctables's 'cells' hmap.  Indexed by all the values in all the
192        axes (except the scalar variable, if any). */
193     struct hmap_node node;
194
195     /* The domains that contain this cell. */
196     bool contributes_to_domains;
197     struct ctables_domain *domains[N_CTDTS];
198
199     bool hide;
200     enum ctables_summary_variant sv;
201
202     struct
203       {
204         size_t nest_idx;
205         struct ctables_cell_value
206           {
207             const struct ctables_category *category;
208             union value value;
209           }
210         *cvs;
211         int leaf;
212       }
213     axes[PIVOT_N_AXES];
214
215     union ctables_summary *summaries;
216   };
217
218 struct ctables
219   {
220     struct pivot_table_look *look;
221
222     /* If this is NULL, zeros are displayed using the normal print format.
223        Otherwise, this string is displayed. */
224     char *zero;
225
226     /* If this is NULL, missing values are displayed using the normal print
227        format.  Otherwise, this string is displayed. */
228     char *missing;
229
230     /* Indexed by variable dictionary index. */
231     enum ctables_vlabel *vlabels;
232
233     bool mrsets_count_duplicates; /* MRSETS. */
234     bool smissing_listwise;       /* SMISSING. */
235     struct variable *e_weight;    /* WEIGHT. */
236     int hide_threshold;           /* HIDESMALLCOUNTS. */
237
238     struct ctables_table **tables;
239     size_t n_tables;
240   };
241
242 struct ctables_postcompute
243   {
244     struct hmap_node hmap_node; /* In struct ctables's 'pcompute' hmap. */
245     const char *name;           /* Name, without leading &. */
246
247     struct ctables_postcompute_expr *expr;
248     char *label;
249     /* XXX FORMAT */
250     bool hide_source_cats;
251   };
252
253 struct ctables_postcompute_expr
254   {
255     enum ctables_postcompute_op
256       {
257         /* Terminals. */
258         CTPO_CAT_NUMBER,
259         CTPO_CAT_STRING,
260         CTPO_CAT_RANGE,
261         CTPO_CAT_MISSING,
262         /* XXX OTHERNM */
263         /* XXX SUBTOTAL and HSUBTOTAL */
264
265         /* Nonterminals. */
266         CTPO_ADD,
267         CTPO_SUB,
268         CTPO_MUL,
269         CTPO_DIV,
270         CTPO_POW,
271       }
272     op;
273
274     union
275       {
276         /* CTPO_CAT_NUMBER, CTPO_NUMBER. */
277         double number;
278
279         /* CTPO_CAT_RANGE.
280
281            XXX what about string ranges? */
282         double range[2];
283
284         /* CTPO_ADD, CTPO_SUB, CTPO_MUL, CTPO_DIV, CTPO_POW. */
285         struct ctables_postcompute_expr *subs[2];
286       };
287   };
288
289 struct ctables_summary_spec_set
290   {
291     struct ctables_summary_spec *specs;
292     size_t n;
293     size_t allocated;
294
295     struct variable *var;
296   };
297
298 static void ctables_summary_spec_set_clone (struct ctables_summary_spec_set *,
299                                             const struct ctables_summary_spec_set *);
300 static void ctables_summary_spec_set_uninit (struct ctables_summary_spec_set *);
301
302 /* A nested sequence of variables, e.g. a > b > c. */
303 struct ctables_nest
304   {
305     struct variable **vars;
306     size_t n;
307     size_t scale_idx;
308     size_t *domains[N_CTDTS];
309     size_t n_domains[N_CTDTS];
310
311     struct ctables_summary_spec_set specs[N_CSVS];
312   };
313
314 /* A stack of nestings, e.g. nest1 + nest2 + ... + nestN. */
315 struct ctables_stack
316   {
317     struct ctables_nest *nests;
318     size_t n;
319   };
320
321 struct ctables_value
322   {
323     struct hmap_node node;
324     union value value;
325     int leaf;
326   };
327
328 struct ctables_table
329   {
330     struct ctables_axis *axes[PIVOT_N_AXES];
331     struct ctables_stack stacks[PIVOT_N_AXES];
332     enum pivot_axis_type summary_axis;
333     struct ctables_summary_spec_set summary_specs;
334     struct hmap cells;
335     struct hmap domains[N_CTDTS];
336
337     const struct variable *clabels_example;
338     struct hmap clabels_values_map;
339     struct ctables_value **clabels_values;
340     size_t n_clabels_values;
341
342     enum pivot_axis_type slabels_axis;
343     bool slabels_visible;
344
345     /* The innermost category labels for axis 'a' appear on axis label_axis[a].
346
347        Most commonly, label_axis[a] == a, and in particular we always have
348        label_axis{PIVOT_AXIS_LAYER] == PIVOT_AXIS_LAYER.
349
350        If ROWLABELS or COLLABELS is specified, then one of
351        label_axis[PIVOT_AXIS_ROW] or label_axis[PIVOT_AXIS_COLUMN] can be the
352        opposite axis or PIVOT_AXIS_LAYER.  Only one of them will differ.
353     */
354     enum pivot_axis_type label_axis[PIVOT_N_AXES];
355     enum pivot_axis_type clabels_from_axis;
356
357     /* Indexed by variable dictionary index. */
358     struct ctables_categories **categories;
359     size_t n_categories;
360
361     double cilevel;
362
363     char *caption;
364     char *corner;
365     char *title;
366
367     struct ctables_chisq *chisq;
368     struct ctables_pairwise *pairwise;
369   };
370
371 struct ctables_var
372   {
373     bool is_mrset;
374     union
375       {
376         struct variable *var;
377         const struct mrset *mrset;
378       };
379   };
380
381 static const struct fmt_spec *
382 ctables_var_get_print_format (const struct ctables_var *var)
383 {
384   return (var->is_mrset
385           ? var_get_print_format (var->mrset->vars[0])
386           : var_get_print_format (var->var));
387 }
388
389 static const char *
390 ctables_var_name (const struct ctables_var *var)
391 {
392   return var->is_mrset ? var->mrset->name : var_get_name (var->var);
393 }
394
395 struct ctables_categories
396   {
397     size_t n_refs;
398     struct ctables_category *cats;
399     size_t n_cats;
400     bool show_empty;
401   };
402
403 struct ctables_category
404   {
405     enum ctables_category_type
406       {
407         CCT_NUMBER,
408         CCT_STRING,
409         CCT_RANGE,
410         CCT_MISSING,
411         CCT_OTHERNM,
412
413         CCT_SUBTOTAL,
414         CCT_HSUBTOTAL,
415         CCT_TOTAL,
416
417         CCT_VALUE,
418         CCT_LABEL,
419         CCT_FUNCTION,
420       }
421     type;
422
423     struct ctables_category *subtotal;
424
425     union
426       {
427         double number;          /* CCT_NUMBER. */
428         char *string;           /* CCT_STRING. */
429         double range[2];        /* CCT_RANGE. */
430         char *total_label;   /* CCT_SUBTOTAL, CCT_HSUBTOTAL, CCT_TOTAL. */
431
432         /* CCT_VALUE, CCT_LABEL, CCT_FUNCTION. */
433         struct
434           {
435             bool include_missing;
436             bool sort_ascending;
437
438             /* CCT_FUNCTION. */
439             enum ctables_summary_function sort_function;
440             struct variable *sort_var;
441             double percentile;
442           };
443       };
444   };
445
446 static void
447 ctables_category_uninit (struct ctables_category *cat)
448 {
449   if (!cat)
450     return;
451
452   switch (cat->type)
453     {
454     case CCT_NUMBER:
455     case CCT_RANGE:
456     case CCT_MISSING:
457     case CCT_OTHERNM:
458       break;
459
460     case CCT_STRING:
461       free (cat->string);
462       break;
463
464     case CCT_SUBTOTAL:
465     case CCT_HSUBTOTAL:
466     case CCT_TOTAL:
467       free (cat->total_label);
468       break;
469
470     case CCT_VALUE:
471     case CCT_LABEL:
472     case CCT_FUNCTION:
473       break;
474     }
475 }
476
477 static bool
478 ctables_category_equal (const struct ctables_category *a,
479                         const struct ctables_category *b)
480 {
481   if (a->type != b->type)
482     return false;
483
484   switch (a->type)
485     {
486     case CCT_NUMBER:
487       return a->number == b->number;
488
489     case CCT_STRING:
490       return strcmp (a->string, b->string);
491
492     case CCT_RANGE:
493       return a->range[0] == b->range[0] && a->range[1] == b->range[1];
494
495     case CCT_MISSING:
496     case CCT_OTHERNM:
497       return true;
498
499     case CCT_SUBTOTAL:
500     case CCT_HSUBTOTAL:
501     case CCT_TOTAL:
502       return !strcmp (a->total_label, b->total_label);
503
504     case CCT_VALUE:
505     case CCT_LABEL:
506     case CCT_FUNCTION:
507       return (a->include_missing == b->include_missing
508               && a->sort_ascending == b->sort_ascending
509               && a->sort_function == b->sort_function
510               && a->sort_var == b->sort_var
511               && a->percentile == b->percentile);
512     }
513
514   NOT_REACHED ();
515 }
516
517 static void
518 ctables_categories_unref (struct ctables_categories *c)
519 {
520   if (!c)
521     return;
522
523   assert (c->n_refs > 0);
524   if (--c->n_refs)
525     return;
526
527   for (size_t i = 0; i < c->n_cats; i++)
528     ctables_category_uninit (&c->cats[i]);
529   free (c->cats);
530   free (c);
531 }
532
533 static bool
534 ctables_categories_equal (const struct ctables_categories *a,
535                           const struct ctables_categories *b)
536 {
537   if (a->n_cats != b->n_cats || a->show_empty != b->show_empty)
538     return false;
539
540   for (size_t i = 0; i < a->n_cats; i++)
541     if (!ctables_category_equal (&a->cats[i], &b->cats[i]))
542       return false;
543
544   return true;
545 }
546
547 /* Chi-square test (SIGTEST). */
548 struct ctables_chisq
549   {
550     double alpha;
551     bool include_mrsets;
552     bool all_visible;
553   };
554
555 /* Pairwise comparison test (COMPARETEST). */
556 struct ctables_pairwise
557   {
558     enum { PROP, MEAN } type;
559     double alpha[2];
560     bool include_mrsets;
561     bool meansvariance_allcats;
562     bool all_visible;
563     enum { BONFERRONI = 1, BH } adjust;
564     bool merge;
565     bool apa_style;
566     bool show_sig;
567   };
568
569 struct ctables_axis
570   {
571     enum ctables_axis_op
572       {
573         /* Terminals. */
574         CTAO_VAR,
575
576         /* Nonterminals. */
577         CTAO_STACK,             /* + */
578         CTAO_NEST,              /* > */
579       }
580     op;
581
582     union
583       {
584         /* Terminals. */
585         struct
586           {
587             struct ctables_var var;
588             bool scale;
589             struct ctables_summary_spec_set specs[N_CSVS];
590           };
591
592         /* Nonterminals. */
593         struct ctables_axis *subs[2];
594       };
595
596     struct msg_location *loc;
597   };
598
599 static void ctables_axis_destroy (struct ctables_axis *);
600
601 enum ctables_format
602   {
603     CTF_COUNT,
604     CTF_PERCENT,
605     CTF_GENERAL
606   };
607
608 enum ctables_function_availability
609   {
610     CTFA_ALL,                /* Any variables. */
611     CTFA_SCALE,              /* Only scale variables, totals, and subtotals. */
612     CTFA_MRSETS,             /* Only multiple-response sets */
613   };
614
615 struct ctables_summary_spec
616   {
617     enum ctables_summary_function function;
618     double percentile;          /* CTSF_PTILE only. */
619     char *label;
620     struct fmt_spec format;     /* XXX extra CTABLES formats */
621     size_t axis_idx;
622   };
623
624 static void
625 ctables_summary_spec_clone (struct ctables_summary_spec *dst,
626                             const struct ctables_summary_spec *src)
627 {
628   *dst = *src;
629   dst->label = xstrdup (src->label);
630 }
631
632 static void
633 ctables_summary_spec_uninit (struct ctables_summary_spec *s)
634 {
635   if (s)
636     free (s->label);
637 }
638
639 static void
640 ctables_summary_spec_set_clone (struct ctables_summary_spec_set *dst,
641                                 const struct ctables_summary_spec_set *src)
642 {
643   struct ctables_summary_spec *specs = xnmalloc (src->n, sizeof *specs);
644   for (size_t i = 0; i < src->n; i++)
645     ctables_summary_spec_clone (&specs[i], &src->specs[i]);
646
647   *dst = (struct ctables_summary_spec_set) {
648     .specs = specs,
649     .n = src->n,
650     .allocated = src->n,
651     .var = src->var
652   };
653 }
654
655 static void
656 ctables_summary_spec_set_uninit (struct ctables_summary_spec_set *set)
657 {
658   for (size_t i = 0; i < set->n; i++)
659     ctables_summary_spec_uninit (&set->specs[i]);
660   free (set->specs);
661 }
662
663 static bool
664 parse_col_width (struct lexer *lexer, const char *name, double *width)
665 {
666   lex_match (lexer, T_EQUALS);
667   if (lex_match_id (lexer, "DEFAULT"))
668     *width = SYSMIS;
669   else if (lex_force_num_range_closed (lexer, name, 0, DBL_MAX))
670     {
671       *width = lex_number (lexer);
672       lex_get (lexer);
673     }
674   else
675     return false;
676
677   return true;
678 }
679
680 static bool
681 parse_bool (struct lexer *lexer, bool *b)
682 {
683   if (lex_match_id (lexer, "NO"))
684     *b = false;
685   else if (lex_match_id (lexer, "YES"))
686     *b = true;
687   else
688     {
689       lex_error_expecting (lexer, "YES", "NO");
690       return false;
691     }
692   return true;
693 }
694
695 static enum ctables_function_availability
696 ctables_function_availability (enum ctables_summary_function f)
697 {
698   static enum ctables_function_availability availability[] = {
699 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = AVAILABILITY,
700     SUMMARIES
701 #undef S
702   };
703
704   return availability[f];
705 }
706
707 static bool
708 parse_ctables_summary_function (struct lexer *lexer,
709                                 enum ctables_summary_function *f)
710 {
711   struct pair
712     {
713       enum ctables_summary_function function;
714       struct substring name;
715     };
716   static struct pair names[] = {
717 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) \
718     { ENUM, SS_LITERAL_INITIALIZER (NAME) },
719     SUMMARIES
720
721     /* The .COUNT suffix may be omitted. */
722     S(CTSF_ROWPCT_COUNT, "ROWPCT", _, _, _)
723     S(CTSF_COLPCT_COUNT, "COLPCT", _, _, _)
724     S(CTSF_TABLEPCT_COUNT, "TABLEPCT", _, _, _)
725     S(CTSF_SUBTABLEPCT_COUNT, "SUBTABLEPCT", _, _, _)
726     S(CTSF_LAYERPCT_COUNT, "LAYERPCT", _, _, _)
727     S(CTSF_LAYERROWPCT_COUNT, "LAYERROWPCT", _, _, _)
728     S(CTSF_LAYERCOLPCT_COUNT, "LAYERCOLPCT", _, _, _)
729 #undef S
730   };
731
732   if (!lex_force_id (lexer))
733     return false;
734
735   for (size_t i = 0; i < sizeof names / sizeof *names; i++)
736     if (ss_equals_case (names[i].name, lex_tokss (lexer)))
737       {
738         *f = names[i].function;
739         lex_get (lexer);
740         return true;
741       }
742
743   lex_error (lexer, _("Expecting summary function name."));
744   return false;
745 }
746
747 static void
748 ctables_axis_destroy (struct ctables_axis *axis)
749 {
750   if (!axis)
751     return;
752
753   switch (axis->op)
754     {
755     case CTAO_VAR:
756       for (size_t i = 0; i < N_CSVS; i++)
757         ctables_summary_spec_set_uninit (&axis->specs[i]);
758       break;
759
760     case CTAO_STACK:
761     case CTAO_NEST:
762       ctables_axis_destroy (axis->subs[0]);
763       ctables_axis_destroy (axis->subs[1]);
764       break;
765     }
766   msg_location_destroy (axis->loc);
767   free (axis);
768 }
769
770 static struct ctables_axis *
771 ctables_axis_new_nonterminal (enum ctables_axis_op op,
772                               struct ctables_axis *sub0,
773                               struct ctables_axis *sub1,
774                               struct lexer *lexer, int start_ofs)
775 {
776   struct ctables_axis *axis = xmalloc (sizeof *axis);
777   *axis = (struct ctables_axis) {
778     .op = op,
779     .subs = { sub0, sub1 },
780     .loc = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer) - 1),
781   };
782   return axis;
783 }
784
785 struct ctables_axis_parse_ctx
786   {
787     struct lexer *lexer;
788     struct dictionary *dict;
789     struct ctables *ct;
790     struct ctables_table *t;
791   };
792
793 static struct fmt_spec
794 ctables_summary_default_format (enum ctables_summary_function function,
795                                 const struct ctables_var *var)
796 {
797   static const enum ctables_format default_formats[] = {
798 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = FORMAT,
799     SUMMARIES
800 #undef S
801   };
802   switch (default_formats[function])
803     {
804     case CTF_COUNT:
805       return (struct fmt_spec) { .type = FMT_F, .w = 40 };
806
807     case CTF_PERCENT:
808       return (struct fmt_spec) { .type = FMT_PCT, .w = 40, .d = 1 };
809
810     case CTF_GENERAL:
811       return *ctables_var_get_print_format (var);
812
813     default:
814       NOT_REACHED ();
815     }
816 }
817
818 static char *
819 ctables_summary_default_label (enum ctables_summary_function function,
820                                double percentile)
821 {
822   static const char *default_labels[] = {
823 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = LABEL,
824     SUMMARIES
825 #undef S
826   };
827
828   return (function == CTSF_PTILE
829           ? xasprintf (_("Percentile %.2f"), percentile)
830           : xstrdup (gettext (default_labels[function])));
831 }
832
833 static const char *
834 ctables_summary_function_name (enum ctables_summary_function function)
835 {
836   static const char *names[] = {
837 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = NAME,
838     SUMMARIES
839 #undef S
840   };
841   return names[function];
842 }
843
844 static bool
845 add_summary_spec (struct ctables_axis *axis,
846                   enum ctables_summary_function function, double percentile,
847                   const char *label, const struct fmt_spec *format,
848                   const struct msg_location *loc, enum ctables_summary_variant sv)
849 {
850   if (axis->op == CTAO_VAR)
851     {
852       const char *function_name = ctables_summary_function_name (function);
853       const char *var_name = ctables_var_name (&axis->var);
854       switch (ctables_function_availability (function))
855         {
856         case CTFA_MRSETS:
857           if (!axis->var.is_mrset)
858             {
859               msg_at (SE, loc, _("Summary function %s applies only to multiple "
860                                  "response sets."), function_name);
861               msg_at (SN, axis->loc, _("'%s' is not a multiple response set."),
862                       var_name);
863               return false;
864             }
865           break;
866
867         case CTFA_SCALE:
868           if (!axis->scale)
869             {
870               msg_at (SE, loc,
871                       _("Summary function %s applies only to scale variables."),
872                       function_name);
873               msg_at (SN, axis->loc, _("'%s' is not a scale variable."),
874                       var_name);
875               return false;
876             }
877           break;
878
879         case CTFA_ALL:
880           break;
881         }
882
883       struct ctables_summary_spec_set *set = &axis->specs[sv];
884       if (set->n >= set->allocated)
885         set->specs = x2nrealloc (set->specs, &set->allocated,
886                                  sizeof *set->specs);
887
888       struct ctables_summary_spec *dst = &set->specs[set->n++];
889       *dst = (struct ctables_summary_spec) {
890         .function = function,
891         .percentile = percentile,
892         .label = xstrdup (label),
893         .format = (format ? *format
894                    : ctables_summary_default_format (function, &axis->var)),
895       };
896       return true;
897     }
898   else
899     {
900       for (size_t i = 0; i < 2; i++)
901         if (!add_summary_spec (axis->subs[i], function, percentile, label,
902                                format, loc, sv))
903           return false;
904       return true;
905     }
906 }
907
908 static struct ctables_axis *ctables_axis_parse_stack (
909   struct ctables_axis_parse_ctx *);
910
911 static bool
912 ctables_var_parse (struct lexer *lexer, struct dictionary *dict,
913                    struct ctables_var *var)
914 {
915   if (ss_starts_with (lex_tokss (lexer), ss_cstr ("$")))
916     {
917       *var = (struct ctables_var) {
918         .is_mrset = true,
919         .mrset = dict_lookup_mrset (dict, lex_tokcstr (lexer))
920       };
921       if (!var->mrset)
922         {
923           lex_error (lexer, _("'%s' does not name a multiple-response set "
924                               "in the active file dictionary."),
925                      lex_tokcstr (lexer));
926           return false;
927         }
928       lex_get (lexer);
929       return true;
930     }
931   else
932     {
933       *var = (struct ctables_var) {
934         .is_mrset = false,
935         .var = parse_variable (lexer, dict),
936       };
937       return var->var != NULL;
938     }
939 }
940
941 static struct ctables_axis *
942 ctables_axis_parse_primary (struct ctables_axis_parse_ctx *ctx)
943 {
944   if (lex_match (ctx->lexer, T_LPAREN))
945     {
946       struct ctables_axis *sub = ctables_axis_parse_stack (ctx);
947       if (!sub || !lex_force_match (ctx->lexer, T_RPAREN))
948         {
949           ctables_axis_destroy (sub);
950           return NULL;
951         }
952       return sub;
953     }
954
955   if (!lex_force_id (ctx->lexer))
956     return NULL;
957
958   int start_ofs = lex_ofs (ctx->lexer);
959   struct ctables_var var;
960   if (!ctables_var_parse (ctx->lexer, ctx->dict, &var))
961     return NULL;
962
963   struct ctables_axis *axis = xmalloc (sizeof *axis);
964   *axis = (struct ctables_axis) { .op = CTAO_VAR, .var = var };
965
966   /* XXX should figure out default measures by reading data */
967   axis->scale = (var.is_mrset ? false
968                  : lex_match_phrase (ctx->lexer, "[S]") ? true
969                  : lex_match_phrase (ctx->lexer, "[C]") ? false
970                  : var_get_measure (var.var) == MEASURE_SCALE);
971   axis->loc = lex_ofs_location (ctx->lexer, start_ofs,
972                                 lex_ofs (ctx->lexer) - 1);
973   return axis;
974 }
975
976 static bool
977 has_digit (const char *s)
978 {
979   return s[strcspn (s, "0123456789")] != '\0';
980 }
981
982 static struct ctables_axis *
983 ctables_axis_parse_postfix (struct ctables_axis_parse_ctx *ctx)
984 {
985   struct ctables_axis *sub = ctables_axis_parse_primary (ctx);
986   if (!sub || !lex_match (ctx->lexer, T_LBRACK))
987     return sub;
988
989   enum ctables_summary_variant sv = CSV_CELL;
990   for (;;)
991     {
992       int start_ofs = lex_ofs (ctx->lexer);
993
994       /* Parse function. */
995       enum ctables_summary_function function;
996       if (!parse_ctables_summary_function (ctx->lexer, &function))
997         goto error;
998
999       /* Parse percentile. */
1000       double percentile = 0;
1001       if (function == CTSF_PTILE)
1002         {
1003           if (!lex_force_num_range_closed (ctx->lexer, "PTILE", 0, 100))
1004             goto error;
1005           percentile = lex_number (ctx->lexer);
1006           lex_get (ctx->lexer);
1007         }
1008
1009       /* Parse label. */
1010       char *label;
1011       if (lex_is_string (ctx->lexer))
1012         {
1013           label = ss_xstrdup (lex_tokss (ctx->lexer));
1014           lex_get (ctx->lexer);
1015         }
1016       else
1017         label = ctables_summary_default_label (function, percentile);
1018
1019       /* Parse format. */
1020       struct fmt_spec format;
1021       const struct fmt_spec *formatp;
1022       if (lex_token (ctx->lexer) == T_ID
1023           && has_digit (lex_tokcstr (ctx->lexer)))
1024         {
1025           if (!parse_format_specifier (ctx->lexer, &format)
1026               || !fmt_check_output (&format)
1027               || !fmt_check_type_compat (&format, VAL_NUMERIC))
1028             {
1029               free (label);
1030               goto error;
1031             }
1032           formatp = &format;
1033         }
1034       else
1035         formatp = NULL;
1036
1037       struct msg_location *loc = lex_ofs_location (ctx->lexer, start_ofs,
1038                                                    lex_ofs (ctx->lexer) - 1);
1039       add_summary_spec (sub, function, percentile, label, formatp, loc, sv);
1040       free (label);
1041       msg_location_destroy (loc);
1042
1043       lex_match (ctx->lexer, T_COMMA);
1044       if (sv == CSV_CELL && lex_match_id (ctx->lexer, "TOTALS"))
1045         {
1046           if (!lex_force_match (ctx->lexer, T_LBRACK))
1047             goto error;
1048           sv = CSV_TOTAL;
1049         }
1050       else if (lex_match (ctx->lexer, T_RBRACK))
1051         {
1052           if (sv == CSV_TOTAL && !lex_force_match (ctx->lexer, T_RBRACK))
1053             goto error;
1054           return sub;
1055         }
1056     }
1057
1058 error:
1059   ctables_axis_destroy (sub);
1060   return NULL;
1061 }
1062
1063 static const struct ctables_axis *
1064 find_scale (const struct ctables_axis *axis)
1065 {
1066   if (!axis)
1067     return NULL;
1068   else if (axis->op == CTAO_VAR)
1069     {
1070       if (axis->scale)
1071         {
1072           assert (!axis->var.is_mrset);
1073           return axis;
1074         }
1075       else
1076         return NULL;
1077     }
1078   else
1079     {
1080       for (size_t i = 0; i < 2; i++)
1081         {
1082           const struct ctables_axis *scale = find_scale (axis->subs[i]);
1083           if (scale)
1084             return scale;
1085         }
1086       return NULL;
1087     }
1088 }
1089
1090 static const struct ctables_axis *
1091 find_categorical_summary_spec (const struct ctables_axis *axis)
1092 {
1093   if (!axis)
1094     return NULL;
1095   else if (axis->op == CTAO_VAR)
1096     return !axis->scale && axis->specs[CSV_CELL].n ? axis : NULL;
1097   else
1098     {
1099       for (size_t i = 0; i < 2; i++)
1100         {
1101           const struct ctables_axis *sum
1102             = find_categorical_summary_spec (axis->subs[i]);
1103           if (sum)
1104             return sum;
1105         }
1106       return NULL;
1107     }
1108 }
1109
1110 static struct ctables_axis *
1111 ctables_axis_parse_nest (struct ctables_axis_parse_ctx *ctx)
1112 {
1113   int start_ofs = lex_ofs (ctx->lexer);
1114   struct ctables_axis *lhs = ctables_axis_parse_postfix (ctx);
1115   if (!lhs)
1116     return NULL;
1117
1118   while (lex_match (ctx->lexer, T_GT))
1119     {
1120       struct ctables_axis *rhs = ctables_axis_parse_postfix (ctx);
1121       if (!rhs)
1122         return NULL;
1123
1124       struct ctables_axis *nest = ctables_axis_new_nonterminal (
1125         CTAO_NEST, lhs, rhs, ctx->lexer, start_ofs);
1126
1127       const struct ctables_axis *outer_scale = find_scale (lhs);
1128       const struct ctables_axis *inner_scale = find_scale (rhs);
1129       if (outer_scale && inner_scale)
1130         {
1131           msg_at (SE, nest->loc, _("Cannot nest scale variables."));
1132           msg_at (SN, outer_scale->loc, _("This is an outer scale variable."));
1133           msg_at (SN, inner_scale->loc, _("This is an inner scale variable."));
1134           ctables_axis_destroy (nest);
1135           return NULL;
1136         }
1137
1138       const struct ctables_axis *outer_sum = find_categorical_summary_spec (lhs);
1139       if (outer_sum)
1140         {
1141           msg_at (SE, nest->loc,
1142                   _("Summaries may only be requested for categorical variables "
1143                     "at the innermost nesting level."));
1144           msg_at (SN, outer_sum->loc,
1145                   _("This outer categorical variable has a summary."));
1146           ctables_axis_destroy (nest);
1147           return NULL;
1148         }
1149
1150       lhs = nest;
1151     }
1152
1153   return lhs;
1154 }
1155
1156 static struct ctables_axis *
1157 ctables_axis_parse_stack (struct ctables_axis_parse_ctx *ctx)
1158 {
1159   int start_ofs = lex_ofs (ctx->lexer);
1160   struct ctables_axis *lhs = ctables_axis_parse_nest (ctx);
1161   if (!lhs)
1162     return NULL;
1163
1164   while (lex_match (ctx->lexer, T_PLUS))
1165     {
1166       struct ctables_axis *rhs = ctables_axis_parse_nest (ctx);
1167       if (!rhs)
1168         return NULL;
1169
1170       lhs = ctables_axis_new_nonterminal (CTAO_STACK, lhs, rhs,
1171                                           ctx->lexer, start_ofs);
1172     }
1173
1174   return lhs;
1175 }
1176
1177 static bool
1178 ctables_axis_parse (struct lexer *lexer, struct dictionary *dict,
1179                     struct ctables *ct, struct ctables_table *t,
1180                     enum pivot_axis_type a)
1181 {
1182   if (lex_token (lexer) == T_BY
1183       || lex_token (lexer) == T_SLASH
1184       || lex_token (lexer) == T_ENDCMD)
1185     return true;
1186
1187   struct ctables_axis_parse_ctx ctx = {
1188     .lexer = lexer,
1189     .dict = dict,
1190     .ct = ct,
1191     .t = t
1192   };
1193   t->axes[a] = ctables_axis_parse_stack (&ctx);
1194   return t->axes[a] != NULL;
1195 }
1196
1197 static void
1198 ctables_chisq_destroy (struct ctables_chisq *chisq)
1199 {
1200   free (chisq);
1201 }
1202
1203 static void
1204 ctables_pairwise_destroy (struct ctables_pairwise *pairwise)
1205 {
1206   free (pairwise);
1207 }
1208
1209 static void
1210 ctables_table_destroy (struct ctables_table *t)
1211 {
1212   if (!t)
1213     return;
1214
1215   for (size_t i = 0; i < t->n_categories; i++)
1216     ctables_categories_unref (t->categories[i]);
1217   free (t->categories);
1218
1219   ctables_axis_destroy (t->axes[PIVOT_AXIS_COLUMN]);
1220   ctables_axis_destroy (t->axes[PIVOT_AXIS_ROW]);
1221   ctables_axis_destroy (t->axes[PIVOT_AXIS_LAYER]);
1222   free (t->caption);
1223   free (t->corner);
1224   free (t->title);
1225   ctables_chisq_destroy (t->chisq);
1226   ctables_pairwise_destroy (t->pairwise);
1227   free (t);
1228 }
1229
1230 static void
1231 ctables_destroy (struct ctables *ct)
1232 {
1233   if (!ct)
1234     return;
1235
1236   pivot_table_look_unref (ct->look);
1237   free (ct->zero);
1238   free (ct->missing);
1239   free (ct->vlabels);
1240   for (size_t i = 0; i < ct->n_tables; i++)
1241     ctables_table_destroy (ct->tables[i]);
1242   free (ct->tables);
1243   free (ct);
1244 }
1245
1246 static struct ctables_category
1247 cct_range (double low, double high)
1248 {
1249   return (struct ctables_category) {
1250     .type = CCT_RANGE,
1251     .range = { low, high }
1252   };
1253 }
1254
1255 static bool
1256 ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
1257                                 struct ctables_table *t)
1258 {
1259   if (!lex_match_id (lexer, "VARIABLES"))
1260     return false;
1261   lex_match (lexer, T_EQUALS);
1262
1263   struct variable **vars;
1264   size_t n_vars;
1265   if (!parse_variables (lexer, dict, &vars, &n_vars, PV_NO_SCRATCH))
1266     return false;
1267
1268   struct ctables_categories *c = xmalloc (sizeof *c);
1269   *c = (struct ctables_categories) { .n_refs = n_vars };
1270   for (size_t i = 0; i < n_vars; i++)
1271     {
1272       struct ctables_categories **cp
1273         = &t->categories[var_get_dict_index (vars[i])];
1274       ctables_categories_unref (*cp);
1275       *cp = c;
1276     }
1277   free (vars);
1278
1279   size_t allocated_cats = 0;
1280   if (lex_match (lexer, T_LBRACK))
1281     {
1282       do
1283         {
1284           if (c->n_cats >= allocated_cats)
1285             c->cats = x2nrealloc (c->cats, &allocated_cats, sizeof *c->cats);
1286
1287           struct ctables_category *cat = &c->cats[c->n_cats];
1288           if (lex_match_id (lexer, "OTHERNM"))
1289             cat->type = CCT_OTHERNM;
1290           else if (lex_match_id (lexer, "MISSING"))
1291             cat->type = CCT_MISSING;
1292           else if (lex_match_id (lexer, "SUBTOTAL"))
1293             *cat = (struct ctables_category)
1294               { .type = CCT_SUBTOTAL, .total_label = NULL };
1295           else if (lex_match_id (lexer, "HSUBTOTAL"))
1296             *cat = (struct ctables_category)
1297               { .type = CCT_HSUBTOTAL, .total_label = NULL };
1298           else if (lex_match_id (lexer, "LO"))
1299             {
1300               if (!lex_force_match_id (lexer, "THRU") || lex_force_num (lexer))
1301                 return false;
1302               *cat = cct_range (-DBL_MAX, lex_number (lexer));
1303               lex_get (lexer);
1304             }
1305           else if (lex_is_number (lexer))
1306             {
1307               double number = lex_number (lexer);
1308               lex_get (lexer);
1309               if (lex_match_id (lexer, "THRU"))
1310                 {
1311                   cat->type = CCT_RANGE;
1312                   cat->range[0] = number;
1313                   if (lex_match_id (lexer, "HI"))
1314                     *cat = cct_range (number, DBL_MAX);
1315                   else
1316                     {
1317                       if (!lex_force_num (lexer))
1318                         return false;
1319                       *cat = cct_range (number, lex_number (lexer));
1320                       lex_get (lexer);
1321                     }
1322                 }
1323               else
1324                 *cat = (struct ctables_category) {
1325                   .type = CCT_NUMBER,
1326                   .number = number
1327                 };
1328             }
1329           else if (lex_is_string (lexer))
1330             {
1331               *cat = (struct ctables_category) {
1332                 .type = CCT_STRING,
1333                 .string = ss_xstrdup (lex_tokss (lexer)),
1334               };
1335               lex_get (lexer);
1336             }
1337           else
1338             {
1339               lex_error (lexer, NULL);
1340               return false;
1341             }
1342
1343           if (cat->type == CCT_SUBTOTAL || cat->type == CCT_HSUBTOTAL)
1344             {
1345               if (lex_match (lexer, T_EQUALS))
1346                 {
1347                   if (!lex_force_string (lexer))
1348                     return false;
1349
1350                   cat->total_label = ss_xstrdup (lex_tokss (lexer));
1351                   lex_get (lexer);
1352                 }
1353               else
1354                 cat->total_label = xstrdup (_("Subtotal"));
1355             }
1356
1357           c->n_cats++;
1358           lex_match (lexer, T_COMMA);
1359         }
1360       while (!lex_match (lexer, T_RBRACK));
1361     }
1362
1363   struct ctables_category cat = {
1364     .type = CCT_VALUE,
1365     .include_missing = false,
1366     .sort_ascending = true,
1367   };
1368   bool show_totals = false;
1369   char *total_label = NULL;
1370   bool totals_before = false;
1371   while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
1372     {
1373       if (!c->n_cats && lex_match_id (lexer, "ORDER"))
1374         {
1375           lex_match (lexer, T_EQUALS);
1376           if (lex_match_id (lexer, "A"))
1377             cat.sort_ascending = true;
1378           else if (lex_match_id (lexer, "D"))
1379             cat.sort_ascending = false;
1380           else
1381             {
1382               lex_error_expecting (lexer, "A", "D");
1383               return false;
1384             }
1385         }
1386       else if (!c->n_cats && lex_match_id (lexer, "KEY"))
1387         {
1388           lex_match (lexer, T_EQUALS);
1389           if (lex_match_id (lexer, "VALUE"))
1390             cat.type = CCT_VALUE;
1391           else if (lex_match_id (lexer, "LABEL"))
1392             cat.type = CCT_LABEL;
1393           else
1394             {
1395               cat.type = CCT_FUNCTION;
1396               if (!parse_ctables_summary_function (lexer, &cat.sort_function))
1397                 return false;
1398
1399               if (lex_match (lexer, T_LPAREN))
1400                 {
1401                   cat.sort_var = parse_variable (lexer, dict);
1402                   if (!cat.sort_var)
1403                     return false;
1404
1405                   if (cat.sort_function == CTSF_PTILE)
1406                     {
1407                       lex_match (lexer, T_COMMA);
1408                       if (!lex_force_num_range_closed (lexer, "PTILE", 0, 100))
1409                         return false;
1410                       cat.percentile = lex_number (lexer);
1411                       lex_get (lexer);
1412                     }
1413
1414                   if (!lex_force_match (lexer, T_RPAREN))
1415                     return false;
1416                 }
1417               else if (ctables_function_availability (cat.sort_function)
1418                        == CTFA_SCALE)
1419                 {
1420                   bool UNUSED b = lex_force_match (lexer, T_LPAREN);
1421                   return false;
1422                 }
1423             }
1424         }
1425       else if (!c->n_cats && lex_match_id (lexer, "MISSING"))
1426         {
1427           lex_match (lexer, T_EQUALS);
1428           if (lex_match_id (lexer, "INCLUDE"))
1429             cat.include_missing = true;
1430           else if (lex_match_id (lexer, "EXCLUDE"))
1431             cat.include_missing = false;
1432           else
1433             {
1434               lex_error_expecting (lexer, "INCLUDE", "EXCLUDE");
1435               return false;
1436             }
1437         }
1438       else if (lex_match_id (lexer, "TOTAL"))
1439         {
1440           lex_match (lexer, T_EQUALS);
1441           if (!parse_bool (lexer, &show_totals))
1442             return false;
1443         }
1444       else if (lex_match_id (lexer, "LABEL"))
1445         {
1446           lex_match (lexer, T_EQUALS);
1447           if (!lex_force_string (lexer))
1448             return false;
1449           free (total_label);
1450           total_label = ss_xstrdup (lex_tokss (lexer));
1451           lex_get (lexer);
1452         }
1453       else if (lex_match_id (lexer, "POSITION"))
1454         {
1455           lex_match (lexer, T_EQUALS);
1456           if (lex_match_id (lexer, "BEFORE"))
1457             totals_before = true;
1458           else if (lex_match_id (lexer, "AFTER"))
1459             totals_before = false;
1460           else
1461             {
1462               lex_error_expecting (lexer, "BEFORE", "AFTER");
1463               return false;
1464             }
1465         }
1466       else if (lex_match_id (lexer, "EMPTY"))
1467         {
1468           lex_match (lexer, T_EQUALS);
1469           if (lex_match_id (lexer, "INCLUDE"))
1470             c->show_empty = true;
1471           else if (lex_match_id (lexer, "EXCLUDE"))
1472             c->show_empty = false;
1473           else
1474             {
1475               lex_error_expecting (lexer, "INCLUDE", "EXCLUDE");
1476               return false;
1477             }
1478         }
1479       else
1480         {
1481           if (!c->n_cats)
1482             lex_error_expecting (lexer, "ORDER", "KEY", "MISSING",
1483                                  "TOTAL", "LABEL", "POSITION", "EMPTY");
1484           else
1485             lex_error_expecting (lexer, "TOTAL", "LABEL", "POSITION", "EMPTY");
1486           return false;
1487         }
1488     }
1489
1490   if (!c->n_cats)
1491     {
1492       if (c->n_cats >= allocated_cats)
1493         c->cats = x2nrealloc (c->cats, &allocated_cats,
1494                                 sizeof *c->cats);
1495       c->cats[c->n_cats++] = cat;
1496     }
1497
1498   if (show_totals)
1499     {
1500       if (c->n_cats >= allocated_cats)
1501         c->cats = x2nrealloc (c->cats, &allocated_cats, sizeof *c->cats);
1502
1503       struct ctables_category *totals;
1504       if (totals_before)
1505         {
1506           insert_element (c->cats, c->n_cats, sizeof *c->cats, 0);
1507           totals = &c->cats[0];
1508         }
1509       else
1510         totals = &c->cats[c->n_cats];
1511       c->n_cats++;
1512
1513       *totals = (struct ctables_category) {
1514         .type = CCT_TOTAL,
1515         .total_label = total_label ? total_label : xstrdup (_("Total")),
1516       };
1517     }
1518
1519   struct ctables_category *subtotal = NULL;
1520   for (size_t i = totals_before ? 0 : c->n_cats;
1521        totals_before ? i < c->n_cats : i-- > 0;
1522        totals_before ? i++ : 0)
1523     {
1524       struct ctables_category *cat = &c->cats[i];
1525       switch (cat->type)
1526         {
1527         case CCT_NUMBER:
1528         case CCT_STRING:
1529         case CCT_RANGE:
1530         case CCT_MISSING:
1531         case CCT_OTHERNM:
1532           cat->subtotal = subtotal;
1533           break;
1534
1535         case CCT_SUBTOTAL:
1536         case CCT_HSUBTOTAL:
1537           subtotal = cat;
1538           break;
1539
1540         case CCT_TOTAL:
1541         case CCT_VALUE:
1542         case CCT_LABEL:
1543         case CCT_FUNCTION:
1544           break;
1545         }
1546     }
1547
1548   return true;
1549 }
1550
1551 static void
1552 ctables_nest_uninit (struct ctables_nest *nest)
1553 {
1554   if (nest)
1555     free (nest->vars);
1556 }
1557
1558 static void
1559 ctables_stack_uninit (struct ctables_stack *stack)
1560 {
1561   if (stack)
1562     {
1563       for (size_t i = 0; i < stack->n; i++)
1564         ctables_nest_uninit (&stack->nests[i]);
1565       free (stack->nests);
1566     }
1567 }
1568
1569 static struct ctables_stack
1570 nest_fts (struct ctables_stack s0, struct ctables_stack s1)
1571 {
1572   if (!s0.n)
1573     return s1;
1574   else if (!s1.n)
1575     return s0;
1576
1577   struct ctables_stack stack = { .nests = xnmalloc (s0.n, s1.n * sizeof *stack.nests) };
1578   for (size_t i = 0; i < s0.n; i++)
1579     for (size_t j = 0; j < s1.n; j++)
1580       {
1581         const struct ctables_nest *a = &s0.nests[i];
1582         const struct ctables_nest *b = &s1.nests[j];
1583
1584         size_t allocate = a->n + b->n;
1585         struct variable **vars = xnmalloc (allocate, sizeof *vars);
1586         enum pivot_axis_type *axes = xnmalloc (allocate, sizeof *axes);
1587         size_t n = 0;
1588         for (size_t k = 0; k < a->n; k++)
1589           vars[n++] = a->vars[k];
1590         for (size_t k = 0; k < b->n; k++)
1591           vars[n++] = b->vars[k];
1592         assert (n == allocate);
1593
1594         const struct ctables_nest *summary_src;
1595         if (!a->specs[CSV_CELL].var)
1596           summary_src = b;
1597         else if (!b->specs[CSV_CELL].var)
1598           summary_src = a;
1599         else
1600           NOT_REACHED ();
1601
1602         struct ctables_nest *new = &stack.nests[stack.n++];
1603         *new = (struct ctables_nest) {
1604           .vars = vars,
1605           .scale_idx = (a->scale_idx != SIZE_MAX ? a->scale_idx
1606                         : b->scale_idx != SIZE_MAX ? a->n + b->scale_idx
1607                         : SIZE_MAX),
1608           .n = n,
1609         };
1610         for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
1611           ctables_summary_spec_set_clone (&new->specs[sv], &summary_src->specs[sv]);
1612       }
1613   ctables_stack_uninit (&s0);
1614   ctables_stack_uninit (&s1);
1615   return stack;
1616 }
1617
1618 static struct ctables_stack
1619 stack_fts (struct ctables_stack s0, struct ctables_stack s1)
1620 {
1621   struct ctables_stack stack = { .nests = xnmalloc (s0.n + s1.n, sizeof *stack.nests) };
1622   for (size_t i = 0; i < s0.n; i++)
1623     stack.nests[stack.n++] = s0.nests[i];
1624   for (size_t i = 0; i < s1.n; i++)
1625     stack.nests[stack.n++] = s1.nests[i];
1626   assert (stack.n == s0.n + s1.n);
1627   free (s0.nests);
1628   free (s1.nests);
1629   return stack;
1630 }
1631
1632 static struct ctables_stack
1633 enumerate_fts (enum pivot_axis_type axis_type, const struct ctables_axis *a)
1634 {
1635   if (!a)
1636     return (struct ctables_stack) { .n = 0 };
1637
1638   switch (a->op)
1639     {
1640     case CTAO_VAR:
1641       assert (!a->var.is_mrset);
1642
1643       struct variable **vars = xmalloc (sizeof *vars);
1644       *vars = a->var.var;
1645
1646       struct ctables_nest *nest = xmalloc (sizeof *nest);
1647       *nest = (struct ctables_nest) {
1648         .vars = vars,
1649         .n = 1,
1650         .scale_idx = a->scale ? 0 : SIZE_MAX,
1651       };
1652       if (a->specs[CSV_CELL].n || a->scale)
1653         for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
1654           {
1655             ctables_summary_spec_set_clone (&nest->specs[sv], &a->specs[sv]);
1656             nest->specs[sv].var = a->var.var;
1657           }
1658       return (struct ctables_stack) { .nests = nest, .n = 1 };
1659
1660     case CTAO_STACK:
1661       return stack_fts (enumerate_fts (axis_type, a->subs[0]),
1662                         enumerate_fts (axis_type, a->subs[1]));
1663
1664     case CTAO_NEST:
1665       return nest_fts (enumerate_fts (axis_type, a->subs[0]),
1666                        enumerate_fts (axis_type, a->subs[1]));
1667     }
1668
1669   NOT_REACHED ();
1670 }
1671
1672 union ctables_summary
1673   {
1674     /* COUNT, VALIDN, TOTALN. */
1675     struct
1676       {
1677         double valid;
1678         double missing;
1679       };
1680
1681     /* MINIMUM, MAXIMUM, RANGE. */
1682     struct
1683       {
1684         double min;
1685         double max;
1686       };
1687
1688     /* MEAN, SEMEAN, STDDEV, SUM, VARIANCE, *.SUM. */
1689     struct moments1 *moments;
1690
1691     /* MEDIAN, MODE, PTILE. */
1692     struct
1693       {
1694         struct casewriter *writer;
1695         double ovalid;
1696         double ovalue;
1697       };
1698
1699     /* XXX multiple response */
1700   };
1701
1702 static void
1703 ctables_summary_init (union ctables_summary *s,
1704                       const struct ctables_summary_spec *ss)
1705 {
1706   switch (ss->function)
1707     {
1708     case CTSF_COUNT:
1709     case CTSF_ECOUNT:
1710     case CTSF_ROWPCT_COUNT:
1711     case CTSF_COLPCT_COUNT:
1712     case CTSF_TABLEPCT_COUNT:
1713     case CTSF_SUBTABLEPCT_COUNT:
1714     case CTSF_LAYERPCT_COUNT:
1715     case CTSF_LAYERROWPCT_COUNT:
1716     case CTSF_LAYERCOLPCT_COUNT:
1717     case CTSF_ROWPCT_VALIDN:
1718     case CTSF_COLPCT_VALIDN:
1719     case CTSF_TABLEPCT_VALIDN:
1720     case CTSF_SUBTABLEPCT_VALIDN:
1721     case CTSF_LAYERPCT_VALIDN:
1722     case CTSF_LAYERROWPCT_VALIDN:
1723     case CTSF_LAYERCOLPCT_VALIDN:
1724     case CTSF_ROWPCT_TOTALN:
1725     case CTSF_COLPCT_TOTALN:
1726     case CTSF_TABLEPCT_TOTALN:
1727     case CTSF_SUBTABLEPCT_TOTALN:
1728     case CTSF_LAYERPCT_TOTALN:
1729     case CTSF_LAYERROWPCT_TOTALN:
1730     case CTSF_LAYERCOLPCT_TOTALN:
1731     case CTSF_MISSING:
1732     case CSTF_TOTALN:
1733     case CTSF_ETOTALN:
1734     case CTSF_VALIDN:
1735     case CTSF_EVALIDN:
1736       s->missing = s->valid = 0;
1737       break;
1738
1739     case CTSF_MAXIMUM:
1740     case CTSF_MINIMUM:
1741     case CTSF_RANGE:
1742       s->min = s->max = SYSMIS;
1743       break;
1744
1745     case CTSF_MEAN:
1746     case CTSF_SEMEAN:
1747     case CTSF_STDDEV:
1748     case CTSF_SUM:
1749     case CTSF_VARIANCE:
1750     case CTSF_ROWPCT_SUM:
1751     case CTSF_COLPCT_SUM:
1752     case CTSF_TABLEPCT_SUM:
1753     case CTSF_SUBTABLEPCT_SUM:
1754     case CTSF_LAYERPCT_SUM:
1755     case CTSF_LAYERROWPCT_SUM:
1756     case CTSF_LAYERCOLPCT_SUM:
1757       s->moments = moments1_create (MOMENT_VARIANCE);
1758       break;
1759
1760     case CTSF_MEDIAN:
1761     case CTSF_MODE:
1762     case CTSF_PTILE:
1763       {
1764         struct caseproto *proto = caseproto_create ();
1765         proto = caseproto_add_width (proto, 0);
1766         proto = caseproto_add_width (proto, 0);
1767
1768         struct subcase ordering;
1769         subcase_init (&ordering, 0, 0, SC_ASCEND);
1770         s->writer = sort_create_writer (&ordering, proto);
1771         subcase_uninit (&ordering);
1772         caseproto_unref (proto);
1773
1774         s->ovalid = 0;
1775         s->ovalue = SYSMIS;
1776       }
1777       break;
1778
1779     case CTSF_RESPONSES:
1780     case CTSF_ROWPCT_RESPONSES:
1781     case CTSF_COLPCT_RESPONSES:
1782     case CTSF_TABLEPCT_RESPONSES:
1783     case CTSF_SUBTABLEPCT_RESPONSES:
1784     case CTSF_LAYERPCT_RESPONSES:
1785     case CTSF_LAYERROWPCT_RESPONSES:
1786     case CTSF_LAYERCOLPCT_RESPONSES:
1787     case CTSF_ROWPCT_RESPONSES_COUNT:
1788     case CTSF_COLPCT_RESPONSES_COUNT:
1789     case CTSF_TABLEPCT_RESPONSES_COUNT:
1790     case CTSF_SUBTABLEPCT_RESPONSES_COUNT:
1791     case CTSF_LAYERPCT_RESPONSES_COUNT:
1792     case CTSF_LAYERROWPCT_RESPONSES_COUNT:
1793     case CTSF_LAYERCOLPCT_RESPONSES_COUNT:
1794     case CTSF_ROWPCT_COUNT_RESPONSES:
1795     case CTSF_COLPCT_COUNT_RESPONSES:
1796     case CTSF_TABLEPCT_COUNT_RESPONSES:
1797     case CTSF_SUBTABLEPCT_COUNT_RESPONSES:
1798     case CTSF_LAYERPCT_COUNT_RESPONSES:
1799     case CTSF_LAYERROWPCT_COUNT_RESPONSES:
1800     case CTSF_LAYERCOLPCT_COUNT_RESPONSES:
1801       NOT_REACHED ();
1802     }
1803 }
1804
1805 static void UNUSED
1806 ctables_summary_uninit (union ctables_summary *s,
1807                         const struct ctables_summary_spec *ss)
1808 {
1809   switch (ss->function)
1810     {
1811     case CTSF_COUNT:
1812     case CTSF_ECOUNT:
1813     case CTSF_ROWPCT_COUNT:
1814     case CTSF_COLPCT_COUNT:
1815     case CTSF_TABLEPCT_COUNT:
1816     case CTSF_SUBTABLEPCT_COUNT:
1817     case CTSF_LAYERPCT_COUNT:
1818     case CTSF_LAYERROWPCT_COUNT:
1819     case CTSF_LAYERCOLPCT_COUNT:
1820     case CTSF_ROWPCT_VALIDN:
1821     case CTSF_COLPCT_VALIDN:
1822     case CTSF_TABLEPCT_VALIDN:
1823     case CTSF_SUBTABLEPCT_VALIDN:
1824     case CTSF_LAYERPCT_VALIDN:
1825     case CTSF_LAYERROWPCT_VALIDN:
1826     case CTSF_LAYERCOLPCT_VALIDN:
1827     case CTSF_ROWPCT_TOTALN:
1828     case CTSF_COLPCT_TOTALN:
1829     case CTSF_TABLEPCT_TOTALN:
1830     case CTSF_SUBTABLEPCT_TOTALN:
1831     case CTSF_LAYERPCT_TOTALN:
1832     case CTSF_LAYERROWPCT_TOTALN:
1833     case CTSF_LAYERCOLPCT_TOTALN:
1834     case CTSF_MISSING:
1835     case CSTF_TOTALN:
1836     case CTSF_ETOTALN:
1837     case CTSF_VALIDN:
1838     case CTSF_EVALIDN:
1839       break;
1840
1841     case CTSF_MAXIMUM:
1842     case CTSF_MINIMUM:
1843     case CTSF_RANGE:
1844       break;
1845
1846     case CTSF_MEAN:
1847     case CTSF_SEMEAN:
1848     case CTSF_STDDEV:
1849     case CTSF_SUM:
1850     case CTSF_VARIANCE:
1851     case CTSF_ROWPCT_SUM:
1852     case CTSF_COLPCT_SUM:
1853     case CTSF_TABLEPCT_SUM:
1854     case CTSF_SUBTABLEPCT_SUM:
1855     case CTSF_LAYERPCT_SUM:
1856     case CTSF_LAYERROWPCT_SUM:
1857     case CTSF_LAYERCOLPCT_SUM:
1858       moments1_destroy (s->moments);
1859       break;
1860
1861     case CTSF_MEDIAN:
1862     case CTSF_MODE:
1863     case CTSF_PTILE:
1864       casewriter_destroy (s->writer);
1865       break;
1866
1867     case CTSF_RESPONSES:
1868     case CTSF_ROWPCT_RESPONSES:
1869     case CTSF_COLPCT_RESPONSES:
1870     case CTSF_TABLEPCT_RESPONSES:
1871     case CTSF_SUBTABLEPCT_RESPONSES:
1872     case CTSF_LAYERPCT_RESPONSES:
1873     case CTSF_LAYERROWPCT_RESPONSES:
1874     case CTSF_LAYERCOLPCT_RESPONSES:
1875     case CTSF_ROWPCT_RESPONSES_COUNT:
1876     case CTSF_COLPCT_RESPONSES_COUNT:
1877     case CTSF_TABLEPCT_RESPONSES_COUNT:
1878     case CTSF_SUBTABLEPCT_RESPONSES_COUNT:
1879     case CTSF_LAYERPCT_RESPONSES_COUNT:
1880     case CTSF_LAYERROWPCT_RESPONSES_COUNT:
1881     case CTSF_LAYERCOLPCT_RESPONSES_COUNT:
1882     case CTSF_ROWPCT_COUNT_RESPONSES:
1883     case CTSF_COLPCT_COUNT_RESPONSES:
1884     case CTSF_TABLEPCT_COUNT_RESPONSES:
1885     case CTSF_SUBTABLEPCT_COUNT_RESPONSES:
1886     case CTSF_LAYERPCT_COUNT_RESPONSES:
1887     case CTSF_LAYERROWPCT_COUNT_RESPONSES:
1888     case CTSF_LAYERCOLPCT_COUNT_RESPONSES:
1889       NOT_REACHED ();
1890     }
1891 }
1892
1893 static void
1894 ctables_summary_add (union ctables_summary *s,
1895                      const struct ctables_summary_spec *ss,
1896                      const struct variable *var, const union value *value,
1897                      double d_weight, double e_weight)
1898 {
1899   switch (ss->function)
1900     {
1901     case CTSF_COUNT:
1902     case CSTF_TOTALN:
1903     case CTSF_VALIDN:
1904       if (var_is_value_missing (var, value))
1905         s->missing += d_weight;
1906       else
1907         s->valid += d_weight;
1908       break;
1909
1910     case CTSF_ECOUNT:
1911     case CTSF_ROWPCT_COUNT:
1912     case CTSF_COLPCT_COUNT:
1913     case CTSF_TABLEPCT_COUNT:
1914     case CTSF_SUBTABLEPCT_COUNT:
1915     case CTSF_LAYERPCT_COUNT:
1916     case CTSF_LAYERROWPCT_COUNT:
1917     case CTSF_LAYERCOLPCT_COUNT:
1918     case CTSF_ROWPCT_VALIDN:
1919     case CTSF_COLPCT_VALIDN:
1920     case CTSF_TABLEPCT_VALIDN:
1921     case CTSF_SUBTABLEPCT_VALIDN:
1922     case CTSF_LAYERPCT_VALIDN:
1923     case CTSF_LAYERROWPCT_VALIDN:
1924     case CTSF_LAYERCOLPCT_VALIDN:
1925     case CTSF_ROWPCT_TOTALN:
1926     case CTSF_COLPCT_TOTALN:
1927     case CTSF_TABLEPCT_TOTALN:
1928     case CTSF_SUBTABLEPCT_TOTALN:
1929     case CTSF_LAYERPCT_TOTALN:
1930     case CTSF_LAYERROWPCT_TOTALN:
1931     case CTSF_LAYERCOLPCT_TOTALN:
1932     case CTSF_MISSING:
1933     case CTSF_ETOTALN:
1934     case CTSF_EVALIDN:
1935       if (var_is_value_missing (var, value))
1936         s->missing += e_weight;
1937       else
1938         s->valid += e_weight;
1939       break;
1940
1941     case CTSF_MAXIMUM:
1942     case CTSF_MINIMUM:
1943     case CTSF_RANGE:
1944       if (!var_is_value_missing (var, value))
1945         {
1946           assert (!var_is_alpha (var)); /* XXX? */
1947           if (s->min == SYSMIS || value->f < s->min)
1948             s->min = value->f;
1949           if (s->max == SYSMIS || value->f > s->max)
1950             s->max = value->f;
1951         }
1952       break;
1953
1954     case CTSF_MEAN:
1955     case CTSF_SEMEAN:
1956     case CTSF_STDDEV:
1957     case CTSF_SUM:
1958     case CTSF_VARIANCE:
1959     case CTSF_ROWPCT_SUM:
1960     case CTSF_COLPCT_SUM:
1961     case CTSF_TABLEPCT_SUM:
1962     case CTSF_SUBTABLEPCT_SUM:
1963     case CTSF_LAYERPCT_SUM:
1964     case CTSF_LAYERROWPCT_SUM:
1965     case CTSF_LAYERCOLPCT_SUM:
1966       if (!var_is_value_missing (var, value))
1967         moments1_add (s->moments, value->f, e_weight);
1968       break;
1969
1970     case CTSF_MEDIAN:
1971     case CTSF_MODE:
1972     case CTSF_PTILE:
1973       if (var_is_value_missing (var, value))
1974         {
1975           s->ovalid += e_weight;
1976
1977           struct ccase *c = case_create (casewriter_get_proto (s->writer));
1978           *case_num_rw_idx (c, 0) = value->f;
1979           *case_num_rw_idx (c, 1) = e_weight;
1980           casewriter_write (s->writer, c);
1981         }
1982       break;
1983
1984     case CTSF_RESPONSES:
1985     case CTSF_ROWPCT_RESPONSES:
1986     case CTSF_COLPCT_RESPONSES:
1987     case CTSF_TABLEPCT_RESPONSES:
1988     case CTSF_SUBTABLEPCT_RESPONSES:
1989     case CTSF_LAYERPCT_RESPONSES:
1990     case CTSF_LAYERROWPCT_RESPONSES:
1991     case CTSF_LAYERCOLPCT_RESPONSES:
1992     case CTSF_ROWPCT_RESPONSES_COUNT:
1993     case CTSF_COLPCT_RESPONSES_COUNT:
1994     case CTSF_TABLEPCT_RESPONSES_COUNT:
1995     case CTSF_SUBTABLEPCT_RESPONSES_COUNT:
1996     case CTSF_LAYERPCT_RESPONSES_COUNT:
1997     case CTSF_LAYERROWPCT_RESPONSES_COUNT:
1998     case CTSF_LAYERCOLPCT_RESPONSES_COUNT:
1999     case CTSF_ROWPCT_COUNT_RESPONSES:
2000     case CTSF_COLPCT_COUNT_RESPONSES:
2001     case CTSF_TABLEPCT_COUNT_RESPONSES:
2002     case CTSF_SUBTABLEPCT_COUNT_RESPONSES:
2003     case CTSF_LAYERPCT_COUNT_RESPONSES:
2004     case CTSF_LAYERROWPCT_COUNT_RESPONSES:
2005     case CTSF_LAYERCOLPCT_COUNT_RESPONSES:
2006       NOT_REACHED ();
2007     }
2008 }
2009
2010 static enum ctables_domain_type
2011 ctables_function_domain (enum ctables_summary_function function)
2012 {
2013   switch (function)
2014     {
2015     case CTSF_COUNT:
2016     case CTSF_ECOUNT:
2017     case CTSF_MISSING:
2018     case CSTF_TOTALN:
2019     case CTSF_ETOTALN:
2020     case CTSF_VALIDN:
2021     case CTSF_EVALIDN:
2022     case CTSF_MAXIMUM:
2023     case CTSF_MINIMUM:
2024     case CTSF_RANGE:
2025     case CTSF_MEAN:
2026     case CTSF_SEMEAN:
2027     case CTSF_STDDEV:
2028     case CTSF_SUM:
2029     case CTSF_VARIANCE:
2030     case CTSF_MEDIAN:
2031     case CTSF_PTILE:
2032     case CTSF_MODE:
2033     case CTSF_RESPONSES:
2034       NOT_REACHED ();
2035
2036     case CTSF_COLPCT_COUNT:
2037     case CTSF_COLPCT_COUNT_RESPONSES:
2038     case CTSF_COLPCT_RESPONSES:
2039     case CTSF_COLPCT_RESPONSES_COUNT:
2040     case CTSF_COLPCT_SUM:
2041     case CTSF_COLPCT_TOTALN:
2042     case CTSF_COLPCT_VALIDN:
2043       return CTDT_COL;
2044
2045     case CTSF_LAYERCOLPCT_COUNT:
2046     case CTSF_LAYERCOLPCT_COUNT_RESPONSES:
2047     case CTSF_LAYERCOLPCT_RESPONSES:
2048     case CTSF_LAYERCOLPCT_RESPONSES_COUNT:
2049     case CTSF_LAYERCOLPCT_SUM:
2050     case CTSF_LAYERCOLPCT_TOTALN:
2051     case CTSF_LAYERCOLPCT_VALIDN:
2052       return CTDT_LAYERCOL;
2053
2054     case CTSF_LAYERPCT_COUNT:
2055     case CTSF_LAYERPCT_COUNT_RESPONSES:
2056     case CTSF_LAYERPCT_RESPONSES:
2057     case CTSF_LAYERPCT_RESPONSES_COUNT:
2058     case CTSF_LAYERPCT_SUM:
2059     case CTSF_LAYERPCT_TOTALN:
2060     case CTSF_LAYERPCT_VALIDN:
2061       return CTDT_LAYER;
2062
2063     case CTSF_LAYERROWPCT_COUNT:
2064     case CTSF_LAYERROWPCT_COUNT_RESPONSES:
2065     case CTSF_LAYERROWPCT_RESPONSES:
2066     case CTSF_LAYERROWPCT_RESPONSES_COUNT:
2067     case CTSF_LAYERROWPCT_SUM:
2068     case CTSF_LAYERROWPCT_TOTALN:
2069     case CTSF_LAYERROWPCT_VALIDN:
2070       return CTDT_LAYERROW;
2071
2072     case CTSF_ROWPCT_COUNT:
2073     case CTSF_ROWPCT_COUNT_RESPONSES:
2074     case CTSF_ROWPCT_RESPONSES:
2075     case CTSF_ROWPCT_RESPONSES_COUNT:
2076     case CTSF_ROWPCT_SUM:
2077     case CTSF_ROWPCT_TOTALN:
2078     case CTSF_ROWPCT_VALIDN:
2079       return CTDT_ROW;
2080
2081     case CTSF_SUBTABLEPCT_COUNT:
2082     case CTSF_SUBTABLEPCT_COUNT_RESPONSES:
2083     case CTSF_SUBTABLEPCT_RESPONSES:
2084     case CTSF_SUBTABLEPCT_RESPONSES_COUNT:
2085     case CTSF_SUBTABLEPCT_SUM:
2086     case CTSF_SUBTABLEPCT_TOTALN:
2087     case CTSF_SUBTABLEPCT_VALIDN:
2088       return CTDT_SUBTABLE;
2089
2090     case CTSF_TABLEPCT_COUNT:
2091     case CTSF_TABLEPCT_COUNT_RESPONSES:
2092     case CTSF_TABLEPCT_RESPONSES:
2093     case CTSF_TABLEPCT_RESPONSES_COUNT:
2094     case CTSF_TABLEPCT_SUM:
2095     case CTSF_TABLEPCT_TOTALN:
2096     case CTSF_TABLEPCT_VALIDN:
2097       return CTDT_TABLE;
2098     }
2099
2100   NOT_REACHED ();
2101 }
2102
2103 static double
2104 ctables_summary_value (const struct ctables_cell *cell,
2105                        union ctables_summary *s,
2106                        const struct ctables_summary_spec *ss)
2107 {
2108   switch (ss->function)
2109     {
2110     case CTSF_COUNT:
2111     case CTSF_ECOUNT:
2112       return s->valid;
2113
2114     case CTSF_ROWPCT_COUNT:
2115     case CTSF_COLPCT_COUNT:
2116     case CTSF_TABLEPCT_COUNT:
2117     case CTSF_SUBTABLEPCT_COUNT:
2118     case CTSF_LAYERPCT_COUNT:
2119     case CTSF_LAYERROWPCT_COUNT:
2120     case CTSF_LAYERCOLPCT_COUNT:
2121       {
2122         enum ctables_domain_type d = ctables_function_domain (ss->function);
2123         return (cell->domains[d]->e_valid
2124                 ? s->valid / cell->domains[d]->e_valid * 100
2125                 : SYSMIS);
2126       }
2127
2128     case CTSF_ROWPCT_VALIDN:
2129     case CTSF_COLPCT_VALIDN:
2130     case CTSF_TABLEPCT_VALIDN:
2131     case CTSF_SUBTABLEPCT_VALIDN:
2132     case CTSF_LAYERPCT_VALIDN:
2133     case CTSF_LAYERROWPCT_VALIDN:
2134     case CTSF_LAYERCOLPCT_VALIDN:
2135     case CTSF_ROWPCT_TOTALN:
2136     case CTSF_COLPCT_TOTALN:
2137     case CTSF_TABLEPCT_TOTALN:
2138     case CTSF_SUBTABLEPCT_TOTALN:
2139     case CTSF_LAYERPCT_TOTALN:
2140     case CTSF_LAYERROWPCT_TOTALN:
2141     case CTSF_LAYERCOLPCT_TOTALN:
2142       NOT_REACHED ();
2143
2144     case CTSF_MISSING:
2145       return s->missing;
2146
2147     case CSTF_TOTALN:
2148     case CTSF_ETOTALN:
2149       return s->valid + s->missing;
2150
2151     case CTSF_VALIDN:
2152     case CTSF_EVALIDN:
2153       return s->valid;
2154
2155     case CTSF_MAXIMUM:
2156       return s->max;
2157
2158     case CTSF_MINIMUM:
2159       return s->min;
2160
2161     case CTSF_RANGE:
2162       return s->max != SYSMIS && s->min != SYSMIS ? s->max - s->min : SYSMIS;
2163
2164     case CTSF_MEAN:
2165       {
2166         double mean;
2167         moments1_calculate (s->moments, NULL, &mean, NULL, NULL, NULL);
2168         return mean;
2169       }
2170
2171     case CTSF_SEMEAN:
2172       {
2173         double weight, variance;
2174         moments1_calculate (s->moments, &weight, NULL, &variance, NULL, NULL);
2175         return calc_semean (variance, weight);
2176       }
2177
2178     case CTSF_STDDEV:
2179       {
2180         double variance;
2181         moments1_calculate (s->moments, NULL, NULL, &variance, NULL, NULL);
2182         return variance != SYSMIS ? sqrt (variance) : SYSMIS;
2183       }
2184
2185     case CTSF_SUM:
2186       {
2187         double weight, mean;
2188         moments1_calculate (s->moments, &weight, &mean, NULL, NULL, NULL);
2189         return weight != SYSMIS && mean != SYSMIS ? weight * mean : SYSMIS;
2190       }
2191
2192     case CTSF_VARIANCE:
2193       {
2194         double variance;
2195         moments1_calculate (s->moments, NULL, NULL, &variance, NULL, NULL);
2196         return variance;
2197       }
2198
2199     case CTSF_ROWPCT_SUM:
2200     case CTSF_COLPCT_SUM:
2201     case CTSF_TABLEPCT_SUM:
2202     case CTSF_SUBTABLEPCT_SUM:
2203     case CTSF_LAYERPCT_SUM:
2204     case CTSF_LAYERROWPCT_SUM:
2205     case CTSF_LAYERCOLPCT_SUM:
2206       NOT_REACHED ();
2207
2208     case CTSF_MEDIAN:
2209     case CTSF_PTILE:
2210       if (s->writer)
2211         {
2212           struct casereader *reader = casewriter_make_reader (s->writer);
2213           s->writer = NULL;
2214
2215           struct percentile *ptile = percentile_create (
2216             ss->function == CTSF_PTILE ? ss->percentile : 0.5, s->ovalid);
2217           struct order_stats *os = &ptile->parent;
2218           order_stats_accumulate_idx (&os, 1, reader, 1, 0);
2219           s->ovalue = percentile_calculate (ptile, PC_HAVERAGE);
2220           statistic_destroy (&ptile->parent.parent);
2221         }
2222       return s->ovalue;
2223
2224     case CTSF_MODE:
2225       if (s->writer)
2226         {
2227           struct casereader *reader = casewriter_make_reader (s->writer);
2228           s->writer = NULL;
2229
2230           struct mode *mode = mode_create ();
2231           struct order_stats *os = &mode->parent;
2232           order_stats_accumulate_idx (&os, 1, reader, 1, 0);
2233           s->ovalue = mode->mode;
2234           statistic_destroy (&mode->parent.parent);
2235         }
2236       return s->ovalue;
2237
2238     case CTSF_RESPONSES:
2239     case CTSF_ROWPCT_RESPONSES:
2240     case CTSF_COLPCT_RESPONSES:
2241     case CTSF_TABLEPCT_RESPONSES:
2242     case CTSF_SUBTABLEPCT_RESPONSES:
2243     case CTSF_LAYERPCT_RESPONSES:
2244     case CTSF_LAYERROWPCT_RESPONSES:
2245     case CTSF_LAYERCOLPCT_RESPONSES:
2246     case CTSF_ROWPCT_RESPONSES_COUNT:
2247     case CTSF_COLPCT_RESPONSES_COUNT:
2248     case CTSF_TABLEPCT_RESPONSES_COUNT:
2249     case CTSF_SUBTABLEPCT_RESPONSES_COUNT:
2250     case CTSF_LAYERPCT_RESPONSES_COUNT:
2251     case CTSF_LAYERROWPCT_RESPONSES_COUNT:
2252     case CTSF_LAYERCOLPCT_RESPONSES_COUNT:
2253     case CTSF_ROWPCT_COUNT_RESPONSES:
2254     case CTSF_COLPCT_COUNT_RESPONSES:
2255     case CTSF_TABLEPCT_COUNT_RESPONSES:
2256     case CTSF_SUBTABLEPCT_COUNT_RESPONSES:
2257     case CTSF_LAYERPCT_COUNT_RESPONSES:
2258     case CTSF_LAYERROWPCT_COUNT_RESPONSES:
2259     case CTSF_LAYERCOLPCT_COUNT_RESPONSES:
2260       NOT_REACHED ();
2261     }
2262
2263   NOT_REACHED ();
2264 }
2265
2266 struct ctables_cell_sort_aux
2267   {
2268     const struct ctables_table *t;
2269     enum pivot_axis_type a;
2270   };
2271
2272 static int
2273 ctables_cell_compare_3way (const void *a_, const void *b_, const void *aux_)
2274 {
2275   const struct ctables_cell_sort_aux *aux = aux_;
2276   struct ctables_cell *const *ap = a_;
2277   struct ctables_cell *const *bp = b_;
2278   const struct ctables_cell *a = *ap;
2279   const struct ctables_cell *b = *bp;
2280
2281   size_t a_idx = a->axes[aux->a].nest_idx;
2282   size_t b_idx = b->axes[aux->a].nest_idx;
2283   if (a_idx != b_idx)
2284     return a_idx < b_idx ? -1 : 1;
2285
2286   const struct ctables_nest *nest = &aux->t->stacks[aux->a].nests[a_idx];
2287   for (size_t i = 0; i < nest->n; i++)
2288     if (i != nest->scale_idx)
2289       {
2290         const struct variable *var = nest->vars[i];
2291         const struct ctables_cell_value *a_cv = &a->axes[aux->a].cvs[i];
2292         const struct ctables_cell_value *b_cv = &b->axes[aux->a].cvs[i];
2293         if (a_cv->category != b_cv->category)
2294           return a_cv->category > b_cv->category ? 1 : -1;
2295
2296         const union value *a_val = &a_cv->value;
2297         const union value *b_val = &b_cv->value;
2298         switch (a_cv->category->type)
2299           {
2300           case CCT_NUMBER:
2301           case CCT_STRING:
2302           case CCT_SUBTOTAL:
2303           case CCT_HSUBTOTAL:
2304           case CCT_TOTAL:
2305             /* Must be equal. */
2306             continue;
2307
2308           case CCT_RANGE:
2309           case CCT_MISSING:
2310           case CCT_OTHERNM:
2311             {
2312               int cmp = value_compare_3way (a_val, b_val, var_get_width (var));
2313               if (cmp)
2314                 return cmp;
2315             }
2316             break;
2317
2318           case CCT_VALUE:
2319             {
2320               int cmp = value_compare_3way (a_val, b_val, var_get_width (var));
2321               if (cmp)
2322                 return a_cv->category->sort_ascending ? cmp : -cmp;
2323             }
2324             break;
2325
2326           case CCT_LABEL:
2327             {
2328               const char *a_label = var_lookup_value_label (var, a_val);
2329               const char *b_label = var_lookup_value_label (var, b_val);
2330               int cmp = (a_label
2331                          ? (b_label ? strcmp (a_label, b_label) : 1)
2332                          : (b_label ? -1 : value_compare_3way (
2333                               a_val, b_val, var_get_width (var))));
2334               if (cmp)
2335                 return a_cv->category->sort_ascending ? cmp : -cmp;
2336             }
2337             break;
2338
2339           case CCT_FUNCTION:
2340             NOT_REACHED ();
2341           }
2342       }
2343   return 0;
2344 }
2345
2346 /* Algorithm:
2347
2348    For each row:
2349        For each ctables_table:
2350            For each combination of row vars:
2351                For each combination of column vars:
2352                    For each combination of layer vars:
2353                        Add entry
2354    Make a table of row values:
2355        Sort entries by row values
2356        Assign a 0-based index to each actual value
2357        Construct a dimension
2358    Make a table of column values
2359    Make a table of layer values
2360    For each entry:
2361        Fill the table entry using the indexes from before.
2362  */
2363
2364 static struct ctables_domain *
2365 ctables_domain_insert (struct ctables_table *t, struct ctables_cell *cell,
2366                        enum ctables_domain_type domain)
2367 {
2368   size_t hash = 0;
2369   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2370     {
2371       size_t idx = cell->axes[a].nest_idx;
2372       const struct ctables_nest *nest = &t->stacks[a].nests[idx];
2373       hash = hash_int (idx, hash);
2374       for (size_t i = 0; i < nest->n_domains[domain]; i++)
2375         {
2376           size_t v_idx = nest->domains[domain][i];
2377           hash = value_hash (&cell->axes[a].cvs[v_idx].value,
2378                              var_get_width (nest->vars[v_idx]), hash);
2379         }
2380     }
2381
2382   struct ctables_domain *d;
2383   HMAP_FOR_EACH_WITH_HASH (d, struct ctables_domain, node, hash, &t->domains[domain])
2384     {
2385       const struct ctables_cell *df = d->example;
2386       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2387         {
2388           size_t idx = cell->axes[a].nest_idx;
2389           if (idx != df->axes[a].nest_idx)
2390             goto not_equal;
2391
2392           const struct ctables_nest *nest = &t->stacks[a].nests[idx];
2393           for (size_t i = 0; i < nest->n_domains[domain]; i++)
2394             {
2395               size_t v_idx = nest->domains[domain][i];
2396               if (!value_equal (&df->axes[a].cvs[v_idx].value,
2397                                 &cell->axes[a].cvs[v_idx].value,
2398                                 var_get_width (nest->vars[v_idx])))
2399                 goto not_equal;
2400             }
2401         }
2402       return d;
2403
2404     not_equal: ;
2405     }
2406
2407   d = xmalloc (sizeof *d);
2408   *d = (struct ctables_domain) { .example = cell };
2409   hmap_insert (&t->domains[domain], &d->node, hash);
2410   return d;
2411 }
2412
2413 static const struct ctables_category *
2414 ctables_categories_match (const struct ctables_categories *c,
2415                           const union value *v, const struct variable *var)
2416 {
2417   const struct ctables_category *othernm = NULL;
2418   for (size_t i = c->n_cats; i-- > 0; )
2419     {
2420       const struct ctables_category *cat = &c->cats[i];
2421       switch (cat->type)
2422         {
2423         case CCT_NUMBER:
2424           if (cat->number == v->f)
2425             return cat;
2426           break;
2427
2428         case CCT_STRING:
2429           NOT_REACHED ();
2430
2431         case CCT_RANGE:
2432           if ((cat->range[0] == -DBL_MAX || v->f >= cat->range[0])
2433               && (cat->range[1] == DBL_MAX || v->f <= cat->range[1]))
2434             return cat;
2435           break;
2436
2437         case CCT_MISSING:
2438           if (var_is_value_missing (var, v))
2439             return cat;
2440           break;
2441
2442         case CCT_OTHERNM:
2443           if (!othernm)
2444             othernm = cat;
2445           break;
2446
2447         case CCT_SUBTOTAL:
2448         case CCT_HSUBTOTAL:
2449         case CCT_TOTAL:
2450           break;
2451
2452         case CCT_VALUE:
2453         case CCT_LABEL:
2454         case CCT_FUNCTION:
2455           return (cat->include_missing || !var_is_value_missing (var, v) ? cat
2456                   : NULL);
2457         }
2458     }
2459
2460   return var_is_value_missing (var, v) ? NULL : othernm;
2461 }
2462
2463 static const struct ctables_category *
2464 ctables_categories_total (const struct ctables_categories *c)
2465 {
2466   const struct ctables_category *first = &c->cats[0];
2467   const struct ctables_category *last = &c->cats[c->n_cats - 1];
2468   return (first->type == CCT_TOTAL ? first
2469           : last->type == CCT_TOTAL ? last
2470           : NULL);
2471 }
2472
2473 static struct ctables_cell *
2474 ctables_cell_insert__ (struct ctables_table *t, const struct ccase *c,
2475                        size_t ix[PIVOT_N_AXES],
2476                        const struct ctables_category *cats[PIVOT_N_AXES][10])
2477 {
2478   const struct ctables_nest *ss = &t->stacks[t->summary_axis].nests[ix[t->summary_axis]];
2479
2480   size_t hash = 0;
2481   enum ctables_summary_variant sv = CSV_CELL;
2482   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2483     {
2484       const struct ctables_nest *nest = &t->stacks[a].nests[ix[a]];
2485       hash = hash_int (ix[a], hash);
2486       for (size_t i = 0; i < nest->n; i++)
2487         if (i != nest->scale_idx)
2488           {
2489             hash = hash_pointer (cats[a][i], hash);
2490             if (cats[a][i]->type != CCT_TOTAL
2491                 && cats[a][i]->type != CCT_SUBTOTAL
2492                 && cats[a][i]->type != CCT_HSUBTOTAL)
2493               hash = value_hash (case_data (c, nest->vars[i]),
2494                                  var_get_width (nest->vars[i]), hash);
2495             else
2496               sv = CSV_TOTAL;
2497           }
2498     }
2499
2500   struct ctables_cell *cell;
2501   HMAP_FOR_EACH_WITH_HASH (cell, struct ctables_cell, node, hash, &t->cells)
2502     {
2503       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2504         {
2505           const struct ctables_nest *nest = &t->stacks[a].nests[ix[a]];
2506           if (cell->axes[a].nest_idx != ix[a])
2507             goto not_equal;
2508           for (size_t i = 0; i < nest->n; i++)
2509             if (i != nest->scale_idx
2510                 && (cats[a][i] != cell->axes[a].cvs[i].category
2511                     || (cats[a][i]->type != CCT_TOTAL
2512                         && cats[a][i]->type != CCT_SUBTOTAL
2513                         && cats[a][i]->type != CCT_HSUBTOTAL
2514                         && !value_equal (case_data (c, nest->vars[i]),
2515                                          &cell->axes[a].cvs[i].value,
2516                                          var_get_width (nest->vars[i])))))
2517                 goto not_equal;
2518         }
2519
2520       return cell;
2521
2522     not_equal: ;
2523     }
2524
2525   cell = xmalloc (sizeof *cell);
2526   cell->hide = false;
2527   cell->sv = sv;
2528   cell->contributes_to_domains = true;
2529   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2530     {
2531       const struct ctables_nest *nest = &t->stacks[a].nests[ix[a]];
2532       cell->axes[a].nest_idx = ix[a];
2533       cell->axes[a].cvs = (nest->n
2534                         ? xnmalloc (nest->n, sizeof *cell->axes[a].cvs)
2535                         : NULL);
2536       for (size_t i = 0; i < nest->n; i++)
2537         {
2538           const struct ctables_category *cat = cats[a][i];
2539
2540           if (i != nest->scale_idx)
2541             {
2542               const struct ctables_category *subtotal = cat->subtotal;
2543               if (subtotal && subtotal->type == CCT_HSUBTOTAL)
2544                 cell->hide = true;
2545
2546               if (cat->type == CCT_TOTAL || cat->type == CCT_SUBTOTAL || cat->type == CCT_HSUBTOTAL)
2547                 cell->contributes_to_domains = false;
2548             }
2549
2550           cell->axes[a].cvs[i].category = cat;
2551           value_clone (&cell->axes[a].cvs[i].value, case_data (c, nest->vars[i]),
2552                        var_get_width (nest->vars[i]));
2553         }
2554     }
2555
2556   const struct ctables_summary_spec_set *specs = &ss->specs[cell->sv];
2557   cell->summaries = xmalloc (specs->n * sizeof *cell->summaries);
2558   for (size_t i = 0; i < specs->n; i++)
2559     ctables_summary_init (&cell->summaries[i], &specs->specs[i]);
2560   for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
2561     cell->domains[dt] = ctables_domain_insert (t, cell, dt);
2562   hmap_insert (&t->cells, &cell->node, hash);
2563   return cell;
2564 }
2565
2566 static void
2567 ctables_cell_add__ (struct ctables_table *t, const struct ccase *c,
2568                     size_t ix[PIVOT_N_AXES],
2569                     const struct ctables_category *cats[PIVOT_N_AXES][10],
2570                     double d_weight, double e_weight)
2571 {
2572   struct ctables_cell *cell = ctables_cell_insert__ (t, c, ix, cats);
2573   const struct ctables_nest *ss = &t->stacks[t->summary_axis].nests[ix[t->summary_axis]];
2574
2575   const struct ctables_summary_spec_set *specs = &ss->specs[cell->sv];
2576   for (size_t i = 0; i < specs->n; i++)
2577     ctables_summary_add (&cell->summaries[i], &specs->specs[i], specs->var,
2578                          case_data (c, specs->var), d_weight, e_weight);
2579   if (cell->contributes_to_domains)
2580     {
2581       for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
2582         {
2583           cell->domains[dt]->d_valid += d_weight;
2584           cell->domains[dt]->e_valid += e_weight;
2585         }
2586     }
2587 }
2588
2589 static void
2590 recurse_totals (struct ctables_table *t, const struct ccase *c,
2591                 size_t ix[PIVOT_N_AXES],
2592                 const struct ctables_category *cats[PIVOT_N_AXES][10],
2593                 double d_weight, double e_weight,
2594                 enum pivot_axis_type start_axis, size_t start_nest)
2595 {
2596   for (enum pivot_axis_type a = start_axis; a < PIVOT_N_AXES; a++)
2597     {
2598       const struct ctables_nest *nest = &t->stacks[a].nests[ix[a]];
2599       for (size_t i = start_nest; i < nest->n; i++)
2600         {
2601           if (i == nest->scale_idx)
2602             continue;
2603
2604           const struct variable *var = nest->vars[i];
2605
2606           const struct ctables_category *total = ctables_categories_total (
2607             t->categories[var_get_dict_index (var)]);
2608           if (total)
2609             {
2610               const struct ctables_category *save = cats[a][i];
2611               cats[a][i] = total;
2612               ctables_cell_add__ (t, c, ix, cats, d_weight, e_weight);
2613               recurse_totals (t, c, ix, cats, d_weight, e_weight, a, i + 1);
2614               cats[a][i] = save;
2615             }
2616         }
2617       start_nest = 0;
2618     }
2619 }
2620
2621 static void
2622 recurse_subtotals (struct ctables_table *t, const struct ccase *c,
2623                    size_t ix[PIVOT_N_AXES],
2624                    const struct ctables_category *cats[PIVOT_N_AXES][10],
2625                    double d_weight, double e_weight,
2626                    enum pivot_axis_type start_axis, size_t start_nest)
2627 {
2628   for (enum pivot_axis_type a = start_axis; a < PIVOT_N_AXES; a++)
2629     {
2630       const struct ctables_nest *nest = &t->stacks[a].nests[ix[a]];
2631       for (size_t i = start_nest; i < nest->n; i++)
2632         {
2633           if (i == nest->scale_idx)
2634             continue;
2635
2636           const struct ctables_category *save = cats[a][i];
2637           if (save->subtotal)
2638             {
2639               cats[a][i] = save->subtotal;
2640               ctables_cell_add__ (t, c, ix, cats, d_weight, e_weight);
2641               recurse_subtotals (t, c, ix, cats, d_weight, e_weight, a, i + 1);
2642               cats[a][i] = save;
2643             }
2644         }
2645       start_nest = 0;
2646     }
2647 }
2648
2649 static void
2650 ctables_cell_insert (struct ctables_table *t,
2651                      const struct ccase *c,
2652                      size_t ix[PIVOT_N_AXES],
2653                      double d_weight, double e_weight)
2654 {
2655   const struct ctables_category *cats[PIVOT_N_AXES][10];
2656   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2657     {
2658       const struct ctables_nest *nest = &t->stacks[a].nests[ix[a]];
2659       for (size_t i = 0; i < nest->n; i++)
2660         {
2661           if (i == nest->scale_idx)
2662             continue;
2663
2664           const struct variable *var = nest->vars[i];
2665           const union value *value = case_data (c, var);
2666
2667           if (var_is_numeric (var) && value->f == SYSMIS)
2668             return;
2669
2670           cats[a][i] = ctables_categories_match (
2671             t->categories[var_get_dict_index (var)], value, var);
2672           if (!cats[a][i])
2673             return;
2674         }
2675     }
2676
2677   ctables_cell_add__ (t, c, ix, cats, d_weight, e_weight);
2678
2679   recurse_totals (t, c, ix, cats, d_weight, e_weight, 0, 0);
2680   recurse_subtotals (t, c, ix, cats, d_weight, e_weight, 0, 0);
2681 }
2682
2683 struct merge_item
2684   {
2685     const struct ctables_summary_spec_set *set;
2686     size_t ofs;
2687   };
2688
2689 static int
2690 merge_item_compare_3way (const struct merge_item *a, const struct merge_item *b)
2691 {
2692   const struct ctables_summary_spec *as = &a->set->specs[a->ofs];
2693   const struct ctables_summary_spec *bs = &b->set->specs[b->ofs];
2694   if (as->function != bs->function)
2695     return as->function > bs->function ? 1 : -1;
2696   else if (as->percentile != bs->percentile)
2697     return as->percentile < bs->percentile ? 1 : -1;
2698   return strcmp (as->label, bs->label);
2699 }
2700
2701 static struct pivot_value *
2702 ctables_category_create_label (const struct ctables_category *cat,
2703                                const struct variable *var,
2704                                const union value *value)
2705 {
2706   return (cat->type == CCT_TOTAL || cat->type == CCT_SUBTOTAL || cat->type == CCT_HSUBTOTAL
2707           ? pivot_value_new_user_text (cat->total_label, SIZE_MAX)
2708           : pivot_value_new_var_value (var, value));
2709 }
2710
2711 static struct ctables_value *
2712 ctables_value_find__ (struct ctables_table *t, const union value *value,
2713                       int width, unsigned int hash)
2714 {
2715   struct ctables_value *clv;
2716   HMAP_FOR_EACH_WITH_HASH (clv, struct ctables_value, node,
2717                            hash, &t->clabels_values_map)
2718     if (value_equal (value, &clv->value, width))
2719       return clv;
2720   return NULL;
2721 }
2722
2723 static struct ctables_value *
2724 ctables_value_find (struct ctables_table *t,
2725                     const union value *value, int width)
2726 {
2727   return ctables_value_find__ (t, value, width,
2728                                value_hash (value, width, 0));
2729 }
2730
2731 static void
2732 ctables_table_output (struct ctables *ct, struct ctables_table *t)
2733 {
2734   struct pivot_table *pt = pivot_table_create__ (
2735     (t->title
2736      ? pivot_value_new_user_text (t->title, SIZE_MAX)
2737      : pivot_value_new_text (N_("Custom Tables"))),
2738     "Custom Tables");
2739   if (t->caption)
2740     pivot_table_set_caption (
2741       pt, pivot_value_new_user_text (t->caption, SIZE_MAX));
2742   if (t->corner)
2743     pivot_table_set_caption (
2744       pt, pivot_value_new_user_text (t->corner, SIZE_MAX));
2745
2746   bool summary_dimension = (t->summary_axis != t->slabels_axis
2747                             || (!t->slabels_visible
2748                                 && t->summary_specs.n > 1));
2749   if (summary_dimension)
2750     {
2751       struct pivot_dimension *d = pivot_dimension_create (
2752         pt, t->slabels_axis, N_("Statistics"));
2753       const struct ctables_summary_spec_set *specs = &t->summary_specs;
2754       if (!t->slabels_visible)
2755         d->hide_all_labels = true;
2756       for (size_t i = 0; i < specs->n; i++)
2757         pivot_category_create_leaf (
2758           d->root, pivot_value_new_text (specs->specs[i].label));
2759     }
2760
2761   bool categories_dimension = t->clabels_example != NULL;
2762   if (categories_dimension)
2763     {
2764       struct pivot_dimension *d = pivot_dimension_create (
2765         pt, t->label_axis[t->clabels_from_axis],
2766         t->clabels_from_axis == PIVOT_AXIS_ROW
2767         ? N_("Row Categories")
2768         : N_("Column Categories"));
2769       const struct variable *var = t->clabels_example;
2770       const struct ctables_categories *c = t->categories[var_get_dict_index (var)];
2771       for (size_t i = 0; i < t->n_clabels_values; i++)
2772         {
2773           const struct ctables_value *value = t->clabels_values[i];
2774           const struct ctables_category *cat = ctables_categories_match (c, &value->value, var);
2775           assert (cat != NULL);
2776           pivot_category_create_leaf (d->root, ctables_category_create_label (
2777                                         cat, t->clabels_example, &value->value));
2778         }
2779     }
2780
2781   pivot_table_set_look (pt, ct->look);
2782   struct pivot_dimension *d[PIVOT_N_AXES];
2783   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2784     {
2785       static const char *names[] = {
2786         [PIVOT_AXIS_ROW] = N_("Rows"),
2787         [PIVOT_AXIS_COLUMN] = N_("Columns"),
2788         [PIVOT_AXIS_LAYER] = N_("Layers"),
2789       };
2790       d[a] = (t->axes[a] || a == t->summary_axis
2791               ? pivot_dimension_create (pt, a, names[a])
2792               : NULL);
2793       if (!d[a])
2794         continue;
2795
2796       assert (t->axes[a]);
2797
2798       struct ctables_cell **sorted = xnmalloc (t->cells.count, sizeof *sorted);
2799       size_t n_sorted = 0;
2800
2801       struct ctables_cell *cell;
2802       HMAP_FOR_EACH (cell, struct ctables_cell, node, &t->cells)
2803         if (!cell->hide)
2804           sorted[n_sorted++] = cell;
2805       assert (n_sorted <= t->cells.count);
2806
2807       struct ctables_cell_sort_aux aux = { .t = t, .a = a };
2808       sort (sorted, n_sorted, sizeof *sorted, ctables_cell_compare_3way, &aux);
2809
2810       size_t max_depth = 0;
2811       for (size_t j = 0; j < t->stacks[a].n; j++)
2812         if (t->stacks[a].nests[j].n > max_depth)
2813           max_depth = t->stacks[a].nests[j].n;
2814
2815       /* Pivot categories:
2816
2817          - variable label for nest->vars[0], if vlabel != CTVL_NONE
2818          - category for nest->vars[0], if nest->scale_idx != 0
2819          - variable label for nest->vars[1], if vlabel != CTVL_NONE
2820          - category for nest->vars[1], if nest->scale_idx != 1
2821          ...
2822          - variable label for nest->vars[n - 1], if vlabel != CTVL_NONE
2823          - category for nest->vars[n - 1], if t->label_axis[a] == a && nest->scale_idx != n - 1.
2824          - summary function, if 'a == t->slabels_axis && a ==
2825          t->summary_axis'.
2826
2827          Additional dimensions:
2828
2829          - If 'a == t->slabels_axis && a != t->summary_axis', add a summary
2830          dimension.
2831          - If 't->label_axis[b] == a' for some 'b != a', add a category
2832          dimension to 'a'.
2833       */
2834
2835       struct ctables_level
2836         {
2837           enum ctables_level_type
2838             {
2839               CTL_VAR,          /* Variable label for nest->vars[var_idx]. */
2840               CTL_CATEGORY,     /* Category for nest->vars[var_idx]. */
2841               CTL_SUMMARY,      /* Summary functions. */
2842             }
2843           type;
2844
2845           size_t var_idx;
2846         };
2847       struct ctables_level *levels = xnmalloc (1 + 2 * max_depth, sizeof *levels);
2848       size_t n_levels = 0;
2849
2850       struct pivot_category **groups = xnmalloc (1 + 2 * max_depth, sizeof *groups);
2851       int prev_leaf = 0;
2852       for (size_t j = 0; j < n_sorted; j++)
2853         {
2854           struct ctables_cell *cell = sorted[j];
2855           struct ctables_cell *prev = j > 0 ? sorted[j - 1] : NULL;
2856           const struct ctables_nest *nest = &t->stacks[a].nests[cell->axes[a].nest_idx];
2857
2858           bool new_subtable = !prev || prev->axes[a].nest_idx != cell->axes[a].nest_idx;
2859           if (new_subtable)
2860             {
2861               n_levels = 0;
2862               for (size_t k = 0; k < nest->n; k++)
2863                 {
2864                   enum ctables_vlabel vlabel = ct->vlabels[var_get_dict_index (nest->vars[k])];
2865                   if (vlabel != CTVL_NONE)
2866                     {
2867                       levels[n_levels++] = (struct ctables_level) {
2868                         .type = CTL_VAR,
2869                         .var_idx = k,
2870                       };
2871                     }
2872
2873                   if (nest->scale_idx != k
2874                       && (k != nest->n - 1 || t->label_axis[a] == a))
2875                     {
2876                       levels[n_levels++] = (struct ctables_level) {
2877                         .type = CTL_CATEGORY,
2878                         .var_idx = k,
2879                       };
2880                     }
2881                 }
2882
2883               if (!summary_dimension && a == t->slabels_axis)
2884                 {
2885                   levels[n_levels++] = (struct ctables_level) {
2886                     .type = CTL_SUMMARY,
2887                     .var_idx = SIZE_MAX,
2888                   };
2889                 }
2890             }
2891
2892           size_t n_common = 0;
2893           if (!new_subtable)
2894             {
2895               for (; n_common < n_levels; n_common++)
2896                 {
2897                   const struct ctables_level *level = &levels[n_common];
2898                   if (level->type == CTL_CATEGORY)
2899                     {
2900                       size_t var_idx = level->var_idx;
2901                       const struct ctables_category *c = cell->axes[a].cvs[var_idx].category;
2902                       if (prev->axes[a].cvs[var_idx].category != c)
2903                         break;
2904                       else if (c->type != CCT_SUBTOTAL
2905                                && c->type != CCT_HSUBTOTAL
2906                                && c->type != CCT_TOTAL
2907                                && !value_equal (&prev->axes[a].cvs[var_idx].value,
2908                                                 &cell->axes[a].cvs[var_idx].value,
2909                                                 var_get_type (nest->vars[var_idx])))
2910                         break;
2911                     }
2912                 }
2913             }
2914
2915           for (size_t k = n_common; k < n_levels; k++)
2916             {
2917               const struct ctables_level *level = &levels[k];
2918               struct pivot_category *parent = k ? groups[k - 1] : d[a]->root;
2919               if (level->type == CTL_SUMMARY)
2920                 {
2921                   assert (k == n_levels - 1);
2922
2923                   const struct ctables_summary_spec_set *specs = &t->summary_specs;
2924                   for (size_t m = 0; m < specs->n; m++)
2925                     {
2926                       int leaf = pivot_category_create_leaf (
2927                         parent, pivot_value_new_text (specs->specs[m].label));
2928                       if (!m)
2929                         prev_leaf = leaf;
2930                     }
2931                 }
2932               else
2933                 {
2934                   const struct variable *var = nest->vars[level->var_idx];
2935                   struct pivot_value *label;
2936                   if (level->type == CTL_VAR)
2937                     label = pivot_value_new_variable (var);
2938                   else if (level->type == CTL_CATEGORY)
2939                     {
2940                       const struct ctables_cell_value *cv = &cell->axes[a].cvs[level->var_idx];
2941                       label = ctables_category_create_label (cv->category,
2942                                                              var, &cv->value);
2943                     }
2944                   else
2945                     NOT_REACHED ();
2946
2947                   if (k == n_levels - 1)
2948                     prev_leaf = pivot_category_create_leaf (parent, label);
2949                   else
2950                     groups[k] = pivot_category_create_group__ (parent, label);
2951                 }
2952             }
2953
2954           cell->axes[a].leaf = prev_leaf;
2955         }
2956       free (sorted);
2957       free (groups);
2958     }
2959
2960   struct ctables_cell *cell;
2961   HMAP_FOR_EACH (cell, struct ctables_cell, node, &t->cells)
2962     {
2963       if (cell->hide)
2964         continue;
2965
2966       const struct ctables_nest *specs_nest = &t->stacks[t->summary_axis].nests[cell->axes[t->summary_axis].nest_idx];
2967       const struct ctables_summary_spec_set *specs = &specs_nest->specs[cell->sv];
2968       for (size_t j = 0; j < specs->n; j++)
2969         {
2970           size_t dindexes[5];
2971           size_t n_dindexes = 0;
2972
2973           if (summary_dimension)
2974             dindexes[n_dindexes++] = specs->specs[j].axis_idx;
2975
2976           if (categories_dimension)
2977             {
2978               const struct ctables_nest *clabels_nest = &t->stacks[t->clabels_from_axis].nests[cell->axes[t->clabels_from_axis].nest_idx];
2979               const struct variable *var = clabels_nest->vars[clabels_nest->n - 1];
2980               const union value *value = &cell->axes[t->clabels_from_axis].cvs[clabels_nest->n - 1].value;
2981               const struct ctables_value *ctv = ctables_value_find (t, value, var_get_width (var));
2982               assert (ctv != NULL);
2983               dindexes[n_dindexes++] = ctv->leaf;
2984             }
2985
2986           for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2987             if (d[a])
2988               {
2989                 int leaf = cell->axes[a].leaf;
2990                 if (a == t->summary_axis && !summary_dimension)
2991                   leaf += j;
2992                 dindexes[n_dindexes++] = leaf;
2993               }
2994
2995           double d = ctables_summary_value (cell, &cell->summaries[j], &specs->specs[j]);
2996           struct pivot_value *value = pivot_value_new_number (d);
2997           value->numeric.format = specs->specs[j].format;
2998           pivot_table_put (pt, dindexes, n_dindexes, value);
2999         }
3000     }
3001
3002   pivot_table_submit (pt);
3003 }
3004
3005 static bool
3006 ctables_check_label_position (struct ctables_table *t, enum pivot_axis_type a)
3007 {
3008   enum pivot_axis_type label_pos = t->label_axis[a];
3009   if (label_pos == a)
3010     return true;
3011
3012   t->clabels_from_axis = a;
3013
3014   const char *subcommand_name = a == PIVOT_AXIS_ROW ? "ROWLABELS" : "COLLABELS";
3015   const char *pos_name = label_pos == PIVOT_AXIS_LAYER ? "LAYER" : "OPPOSITE";
3016
3017   const struct ctables_stack *stack = &t->stacks[a];
3018   if (!stack->n)
3019     return true;
3020
3021   const struct ctables_nest *n0 = &stack->nests[0];
3022   assert (n0->n > 0);
3023   const struct variable *v0 = n0->vars[n0->n - 1];
3024   struct ctables_categories *c0 = t->categories[var_get_dict_index (v0)];
3025   t->clabels_example = v0;
3026
3027   for (size_t i = 0; i < c0->n_cats; i++)
3028     if (c0->cats[i].type == CCT_FUNCTION)
3029       {
3030         msg (SE, _("%s=%s is not allowed with sorting based "
3031                    "on a summary function."),
3032              subcommand_name, pos_name);
3033         return false;
3034       }
3035   if (n0->n - 1 == n0->scale_idx)
3036     {
3037       msg (SE, _("%s=%s requires the variables to be moved to be categorical, "
3038                  "but %s is a scale variable."),
3039            subcommand_name, pos_name, var_get_name (v0));
3040       return false;
3041     }
3042
3043   for (size_t i = 1; i < stack->n; i++)
3044     {
3045       const struct ctables_nest *ni = &stack->nests[i];
3046       assert (ni->n > 0);
3047       const struct variable *vi = ni->vars[ni->n - 1];
3048       struct ctables_categories *ci = t->categories[var_get_dict_index (vi)];
3049
3050       if (ni->n - 1 == ni->scale_idx)
3051         {
3052           msg (SE, _("%s=%s requires the variables to be moved to be "
3053                      "categorical, but %s is a scale variable."),
3054                subcommand_name, pos_name, var_get_name (vi));
3055           return false;
3056         }
3057       if (var_get_width (v0) != var_get_width (vi))
3058         {
3059           msg (SE, _("%s=%s requires the variables to be "
3060                      "moved to have the same width, but %s has "
3061                      "width %d and %s has width %d."),
3062                subcommand_name, pos_name,
3063                var_get_name (v0), var_get_width (v0),
3064                var_get_name (vi), var_get_width (vi));
3065           return false;
3066         }
3067       if (!val_labs_equal (var_get_value_labels (v0),
3068                            var_get_value_labels (vi)))
3069         {
3070           msg (SE, _("%s=%s requires the variables to be "
3071                      "moved to have the same value labels, but %s "
3072                      "and %s have different value labels."),
3073                subcommand_name, pos_name,
3074                var_get_name (v0), var_get_name (vi));
3075           return false;
3076         }
3077       if (!ctables_categories_equal (c0, ci))
3078         {
3079           msg (SE, _("%s=%s requires the variables to be "
3080                      "moved to have the same category "
3081                      "specifications, but %s and %s have different "
3082                      "category specifications."),
3083                subcommand_name, pos_name,
3084                var_get_name (v0), var_get_name (vi));
3085           return false;
3086         }
3087     }
3088
3089   return true;
3090 }
3091
3092 static bool
3093 ctables_prepare_table (struct ctables_table *t)
3094 {
3095   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3096     if (t->axes[a])
3097       {
3098         t->stacks[a] = enumerate_fts (a, t->axes[a]);
3099
3100         for (size_t j = 0; j < t->stacks[a].n; j++)
3101           {
3102             struct ctables_nest *nest = &t->stacks[a].nests[j];
3103             for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
3104               {
3105                 nest->domains[dt] = xmalloc (nest->n * sizeof *nest->domains[dt]);
3106                 nest->n_domains[dt] = 0;
3107
3108                 for (size_t k = 0; k < nest->n; k++)
3109                   {
3110                     if (k == nest->scale_idx)
3111                       continue;
3112
3113                     switch (dt)
3114                       {
3115                       case CTDT_TABLE:
3116                         continue;
3117
3118                       case CTDT_LAYER:
3119                         if (a != PIVOT_AXIS_LAYER)
3120                           continue;
3121                         break;
3122
3123                       case CTDT_SUBTABLE:
3124                       case CTDT_ROW:
3125                       case CTDT_COL:
3126                         if (dt == CTDT_SUBTABLE ? a != PIVOT_AXIS_LAYER
3127                             : dt == CTDT_ROW ? a == PIVOT_AXIS_COLUMN
3128                             : a == PIVOT_AXIS_ROW)
3129                           {
3130                             if (k == nest->n - 1
3131                                 || (nest->scale_idx == nest->n - 1
3132                                     && k == nest->n - 2))
3133                               continue;
3134                           }
3135                         break;
3136
3137                       case CTDT_LAYERROW:
3138                         if (a == PIVOT_AXIS_COLUMN)
3139                           continue;
3140                         break;
3141
3142                       case CTDT_LAYERCOL:
3143                         if (a == PIVOT_AXIS_ROW)
3144                           continue;
3145                         break;
3146                       }
3147
3148                     nest->domains[dt][nest->n_domains[dt]++] = k;
3149                   }
3150               }
3151           }
3152       }
3153     else
3154       {
3155         struct ctables_nest *nest = xmalloc (sizeof *nest);
3156         *nest = (struct ctables_nest) { .n = 0 };
3157         t->stacks[a] = (struct ctables_stack) { .nests = nest, .n = 1 };
3158       }
3159
3160   struct ctables_stack *stack = &t->stacks[t->summary_axis];
3161   for (size_t i = 0; i < stack->n; i++)
3162     {
3163       struct ctables_nest *nest = &stack->nests[i];
3164       if (!nest->specs[CSV_CELL].n)
3165         {
3166           struct ctables_summary_spec_set *specs = &nest->specs[CSV_CELL];
3167           specs->specs = xmalloc (sizeof *specs->specs);
3168           specs->n = 1;
3169
3170           enum ctables_summary_function function
3171             = specs->var ? CTSF_MEAN : CTSF_COUNT;
3172           struct ctables_var var = { .is_mrset = false, .var = specs->var };
3173
3174           *specs->specs = (struct ctables_summary_spec) {
3175             .function = function,
3176             .format = ctables_summary_default_format (function, &var),
3177             .label = ctables_summary_default_label (function, 0),
3178           };
3179           if (!specs->var)
3180             specs->var = nest->vars[0];
3181
3182           ctables_summary_spec_set_clone (&nest->specs[CSV_TOTAL],
3183                                           &nest->specs[CSV_CELL]);
3184         }
3185       else if (!nest->specs[CSV_TOTAL].n)
3186         ctables_summary_spec_set_clone (&nest->specs[CSV_TOTAL],
3187                                         &nest->specs[CSV_CELL]);
3188     }
3189
3190   struct ctables_summary_spec_set *merged = &t->summary_specs;
3191   struct merge_item *items = xnmalloc (2 * stack->n, sizeof *items);
3192   size_t n_left = 0;
3193   for (size_t j = 0; j < stack->n; j++)
3194     {
3195       const struct ctables_nest *nest = &stack->nests[j];
3196       if (nest->n)
3197         for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
3198           items[n_left++] = (struct merge_item) { .set = &nest->specs[sv] };
3199     }
3200
3201   while (n_left > 0)
3202     {
3203       struct merge_item min = items[0];
3204       for (size_t j = 1; j < n_left; j++)
3205         if (merge_item_compare_3way (&items[j], &min) < 0)
3206           min = items[j];
3207
3208       if (merged->n >= merged->allocated)
3209         merged->specs = x2nrealloc (merged->specs, &merged->allocated,
3210                                     sizeof *merged->specs);
3211       merged->specs[merged->n++] = min.set->specs[min.ofs];
3212
3213       for (size_t j = 0; j < n_left; )
3214         {
3215           if (merge_item_compare_3way (&items[j], &min) == 0)
3216             {
3217               struct merge_item *item = &items[j];
3218               item->set->specs[item->ofs].axis_idx = merged->n - 1;
3219               if (++item->ofs >= item->set->n)
3220                 {
3221                   items[j] = items[--n_left];
3222                   continue;
3223                 }
3224             }
3225           j++;
3226         }
3227     }
3228
3229 #if 0
3230   for (size_t j = 0; j < merged->n; j++)
3231     printf ("%s\n", ctables_summary_function_name (merged->specs[j].function));
3232
3233   for (size_t j = 0; j < stack->n; j++)
3234     {
3235       const struct ctables_nest *nest = &stack->nests[j];
3236       for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
3237         {
3238           const struct ctables_summary_spec_set *specs = &nest->specs[sv];
3239           for (size_t k = 0; k < specs->n; k++)
3240             printf ("(%s, %zu) ", ctables_summary_function_name (specs->specs[k].function),
3241                     specs->specs[k].axis_idx);
3242           printf ("\n");
3243         }
3244     }
3245 #endif
3246
3247   return (ctables_check_label_position (t, PIVOT_AXIS_ROW)
3248           && ctables_check_label_position (t, PIVOT_AXIS_COLUMN));
3249 }
3250
3251 static void
3252 ctables_insert_clabels_values (struct ctables_table *t, const struct ccase *c,
3253                                enum pivot_axis_type a)
3254 {
3255   struct ctables_stack *stack = &t->stacks[a];
3256   for (size_t i = 0; i < stack->n; i++)
3257     {
3258       const struct ctables_nest *nest = &stack->nests[i];
3259       const struct variable *var = nest->vars[nest->n - 1];
3260       int width = var_get_width (var);
3261       const union value *value = case_data (c, var);
3262
3263       if (var_is_numeric (var) && value->f == SYSMIS)
3264         continue;
3265
3266       if (!ctables_categories_match (t->categories [var_get_dict_index (var)],
3267                                      value, var))
3268         continue;
3269
3270       unsigned int hash = value_hash (value, width, 0);
3271
3272       struct ctables_value *clv = ctables_value_find__ (t, value, width, hash);
3273       if (!clv)
3274         {
3275           clv = xmalloc (sizeof *clv);
3276           value_clone (&clv->value, value, width);
3277           hmap_insert (&t->clabels_values_map, &clv->node, hash);
3278         }
3279     }
3280 }
3281
3282 static int
3283 compare_clabels_values_3way (const void *a_, const void *b_, const void *width_)
3284 {
3285   const struct ctables_value *const *ap = a_;
3286   const struct ctables_value *const *bp = b_;
3287   const struct ctables_value *a = *ap;
3288   const struct ctables_value *b = *bp;
3289   const int *width = width_;
3290   return value_compare_3way (&a->value, &b->value, *width);
3291 }
3292
3293 static void
3294 ctables_sort_clabels_values (struct ctables_table *t)
3295 {
3296   int width = var_get_width (t->clabels_example);
3297
3298   size_t n = hmap_count (&t->clabels_values_map);
3299   t->clabels_values = xnmalloc (n, sizeof *t->clabels_values);
3300
3301   struct ctables_value *clv;
3302   size_t i = 0;
3303   HMAP_FOR_EACH (clv, struct ctables_value, node, &t->clabels_values_map)
3304     t->clabels_values[i++] = clv;
3305   t->n_clabels_values = n;
3306   assert (i == n);
3307
3308   sort (t->clabels_values, n, sizeof *t->clabels_values,
3309         compare_clabels_values_3way, &width);
3310
3311   for (size_t i = 0; i < n; i++)
3312     t->clabels_values[i]->leaf = i;
3313 }
3314
3315 static bool
3316 ctables_execute (struct dataset *ds, struct ctables *ct)
3317 {
3318   struct casereader *input = proc_open (ds);
3319   bool warn_on_invalid = true;
3320   for (struct ccase *c = casereader_read (input); c;
3321        case_unref (c), c = casereader_read (input))
3322     {
3323       double d_weight = dict_get_case_weight (dataset_dict (ds), c,
3324                                               &warn_on_invalid);
3325       double e_weight = (ct->e_weight
3326                          ? var_force_valid_weight (ct->e_weight,
3327                                                    case_num (c, ct->e_weight),
3328                                                    &warn_on_invalid)
3329                          : d_weight);
3330
3331       for (size_t i = 0; i < ct->n_tables; i++)
3332         {
3333           struct ctables_table *t = ct->tables[i];
3334
3335           for (size_t ir = 0; ir < t->stacks[PIVOT_AXIS_ROW].n; ir++)
3336             for (size_t ic = 0; ic < t->stacks[PIVOT_AXIS_COLUMN].n; ic++)
3337               for (size_t il = 0; il < t->stacks[PIVOT_AXIS_LAYER].n; il++)
3338                 {
3339                   size_t ix[PIVOT_N_AXES] = {
3340                     [PIVOT_AXIS_ROW] = ir,
3341                     [PIVOT_AXIS_COLUMN] = ic,
3342                     [PIVOT_AXIS_LAYER] = il,
3343                   };
3344
3345                   ctables_cell_insert (t, c, ix, d_weight, e_weight);
3346                 }
3347
3348           for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3349             if (t->label_axis[a] != a)
3350               ctables_insert_clabels_values (t, c, a);
3351         }
3352     }
3353   casereader_destroy (input);
3354
3355   for (size_t i = 0; i < ct->n_tables; i++)
3356     {
3357       struct ctables_table *t = ct->tables[i];
3358
3359       if (t->clabels_example)
3360         ctables_sort_clabels_values (t);
3361
3362       ctables_table_output (ct, ct->tables[i]);
3363     }
3364   return proc_commit (ds);
3365 }
3366
3367 int
3368 cmd_ctables (struct lexer *lexer, struct dataset *ds)
3369 {
3370   size_t n_vars = dict_get_n_vars (dataset_dict (ds));
3371   enum ctables_vlabel *vlabels = xnmalloc (n_vars, sizeof *vlabels);
3372   enum settings_value_show tvars = settings_get_show_variables ();
3373   for (size_t i = 0; i < n_vars; i++)
3374     vlabels[i] = (enum ctables_vlabel) tvars;
3375
3376   struct ctables *ct = xmalloc (sizeof *ct);
3377   *ct = (struct ctables) {
3378     .look = pivot_table_look_unshare (pivot_table_look_ref (
3379                                         pivot_table_look_get_default ())),
3380     .vlabels = vlabels,
3381     .hide_threshold = 5,
3382   };
3383   ct->look->omit_empty = false;
3384
3385   if (!lex_force_match (lexer, T_SLASH))
3386     goto error;
3387
3388   while (!lex_match_id (lexer, "TABLE"))
3389     {
3390       if (lex_match_id (lexer, "FORMAT"))
3391         {
3392           double widths[2] = { SYSMIS, SYSMIS };
3393           double units_per_inch = 72.0;
3394
3395           while (lex_token (lexer) != T_SLASH)
3396             {
3397               if (lex_match_id (lexer, "MINCOLWIDTH"))
3398                 {
3399                   if (!parse_col_width (lexer, "MINCOLWIDTH", &widths[0]))
3400                     goto error;
3401                 }
3402               else if (lex_match_id (lexer, "MAXCOLWIDTH"))
3403                 {
3404                   if (!parse_col_width (lexer, "MAXCOLWIDTH", &widths[1]))
3405                     goto error;
3406                 }
3407               else if (lex_match_id (lexer, "UNITS"))
3408                 {
3409                   lex_match (lexer, T_EQUALS);
3410                   if (lex_match_id (lexer, "POINTS"))
3411                     units_per_inch = 72.0;
3412                   else if (lex_match_id (lexer, "INCHES"))
3413                     units_per_inch = 1.0;
3414                   else if (lex_match_id (lexer, "CM"))
3415                     units_per_inch = 2.54;
3416                   else
3417                     {
3418                       lex_error_expecting (lexer, "POINTS", "INCHES", "CM");
3419                       goto error;
3420                     }
3421                 }
3422               else if (lex_match_id (lexer, "EMPTY"))
3423                 {
3424                   free (ct->zero);
3425                   ct->zero = NULL;
3426
3427                   lex_match (lexer, T_EQUALS);
3428                   if (lex_match_id (lexer, "ZERO"))
3429                     {
3430                       /* Nothing to do. */
3431                     }
3432                   else if (lex_match_id (lexer, "BLANK"))
3433                     ct->zero = xstrdup ("");
3434                   else if (lex_force_string (lexer))
3435                     {
3436                       ct->zero = ss_xstrdup (lex_tokss (lexer));
3437                       lex_get (lexer);
3438                     }
3439                   else
3440                     goto error;
3441                 }
3442               else if (lex_match_id (lexer, "MISSING"))
3443                 {
3444                   lex_match (lexer, T_EQUALS);
3445                   if (!lex_force_string (lexer))
3446                     goto error;
3447
3448                   free (ct->missing);
3449                   ct->missing = (strcmp (lex_tokcstr (lexer), ".")
3450                                  ? ss_xstrdup (lex_tokss (lexer))
3451                                  : NULL);
3452                   lex_get (lexer);
3453                 }
3454               else
3455                 {
3456                   lex_error_expecting (lexer, "MINCOLWIDTH", "MAXCOLWIDTH",
3457                                        "UNITS", "EMPTY", "MISSING");
3458                   goto error;
3459                 }
3460             }
3461
3462           if (widths[0] != SYSMIS && widths[1] != SYSMIS
3463               && widths[0] > widths[1])
3464             {
3465               msg (SE, _("MINCOLWIDTH must not be greater than MAXCOLWIDTH."));
3466               goto error;
3467             }
3468
3469           for (size_t i = 0; i < 2; i++)
3470             if (widths[i] != SYSMIS)
3471               {
3472                 int *wr = ct->look->width_ranges[TABLE_HORZ];
3473                 wr[i] = widths[i] / units_per_inch * 96.0;
3474                 if (wr[0] > wr[1])
3475                   wr[!i] = wr[i];
3476               }
3477         }
3478       else if (lex_match_id (lexer, "VLABELS"))
3479         {
3480           if (!lex_force_match_id (lexer, "VARIABLES"))
3481             goto error;
3482           lex_match (lexer, T_EQUALS);
3483
3484           struct variable **vars;
3485           size_t n_vars;
3486           if (!parse_variables (lexer, dataset_dict (ds), &vars, &n_vars,
3487                                 PV_NO_SCRATCH))
3488             goto error;
3489
3490           if (!lex_force_match_id (lexer, "DISPLAY"))
3491             {
3492               free (vars);
3493               goto error;
3494             }
3495           lex_match (lexer, T_EQUALS);
3496
3497           enum ctables_vlabel vlabel;
3498           if (lex_match_id (lexer, "DEFAULT"))
3499             vlabel = (enum ctables_vlabel) settings_get_show_variables ();
3500           else if (lex_match_id (lexer, "NAME"))
3501             vlabel = CTVL_NAME;
3502           else if (lex_match_id (lexer, "LABEL"))
3503             vlabel = CTVL_LABEL;
3504           else if (lex_match_id (lexer, "BOTH"))
3505             vlabel = CTVL_BOTH;
3506           else if (lex_match_id (lexer, "NONE"))
3507             vlabel = CTVL_NONE;
3508           else
3509             {
3510               lex_error_expecting (lexer, "DEFAULT", "NAME", "LABEL",
3511                                    "BOTH", "NONE");
3512               free (vars);
3513               goto error;
3514             }
3515
3516           for (size_t i = 0; i < n_vars; i++)
3517             ct->vlabels[var_get_dict_index (vars[i])] = vlabel;
3518           free (vars);
3519         }
3520       else if (lex_match_id (lexer, "MRSETS"))
3521         {
3522           if (!lex_force_match_id (lexer, "COUNTDUPLICATES"))
3523             goto error;
3524           lex_match (lexer, T_EQUALS);
3525           if (!parse_bool (lexer, &ct->mrsets_count_duplicates))
3526             goto error;
3527         }
3528       else if (lex_match_id (lexer, "SMISSING"))
3529         {
3530           if (lex_match_id (lexer, "VARIABLE"))
3531             ct->smissing_listwise = false;
3532           else if (lex_match_id (lexer, "LISTWISE"))
3533             ct->smissing_listwise = true;
3534           else
3535             {
3536               lex_error_expecting (lexer, "VARIABLE", "LISTWISE");
3537               goto error;
3538             }
3539         }
3540       /* XXX PCOMPUTE */
3541       else if (lex_match_id (lexer, "WEIGHT"))
3542         {
3543           if (!lex_force_match_id (lexer, "VARIABLE"))
3544             goto error;
3545           lex_match (lexer, T_EQUALS);
3546           ct->e_weight = parse_variable (lexer, dataset_dict (ds));
3547           if (!ct->e_weight)
3548             goto error;
3549         }
3550       else if (lex_match_id (lexer, "HIDESMALLCOUNTS"))
3551         {
3552           if (!lex_force_match_id (lexer, "COUNT"))
3553             goto error;
3554           lex_match (lexer, T_EQUALS);
3555           if (!lex_force_int_range (lexer, "HIDESMALLCOUNTS COUNT", 2, INT_MAX))
3556             goto error;
3557           ct->hide_threshold = lex_integer (lexer);
3558           lex_get (lexer);
3559         }
3560       else
3561         {
3562           lex_error_expecting (lexer, "FORMAT", "VLABELS", "MRSETS",
3563                                "SMISSING", "PCOMPUTE", "PPROPERTIES",
3564                                "WEIGHT", "HIDESMALLCOUNTS", "TABLE");
3565           goto error;
3566         }
3567
3568       if (!lex_force_match (lexer, T_SLASH))
3569         goto error;
3570     }
3571
3572   size_t allocated_tables = 0;
3573   do
3574     {
3575       if (ct->n_tables >= allocated_tables)
3576         ct->tables = x2nrealloc (ct->tables, &allocated_tables,
3577                                  sizeof *ct->tables);
3578
3579       struct ctables_category *cat = xmalloc (sizeof *cat);
3580       *cat = (struct ctables_category) {
3581         .type = CCT_VALUE,
3582         .include_missing = false,
3583         .sort_ascending = true,
3584       };
3585
3586       struct ctables_categories *c = xmalloc (sizeof *c);
3587       size_t n_vars = dict_get_n_vars (dataset_dict (ds));
3588       *c = (struct ctables_categories) {
3589         .n_refs = n_vars,
3590         .cats = cat,
3591         .n_cats = 1,
3592       };
3593
3594       struct ctables_categories **categories = xnmalloc (n_vars,
3595                                                          sizeof *categories);
3596       for (size_t i = 0; i < n_vars; i++)
3597         categories[i] = c;
3598
3599       struct ctables_table *t = xmalloc (sizeof *t);
3600       *t = (struct ctables_table) {
3601         .cells = HMAP_INITIALIZER (t->cells),
3602         .slabels_axis = PIVOT_AXIS_COLUMN,
3603         .slabels_visible = true,
3604         .clabels_values_map = HMAP_INITIALIZER (t->clabels_values_map),
3605         .label_axis = {
3606           [PIVOT_AXIS_ROW] = PIVOT_AXIS_ROW,
3607           [PIVOT_AXIS_COLUMN] = PIVOT_AXIS_COLUMN,
3608           [PIVOT_AXIS_LAYER] = PIVOT_AXIS_LAYER,
3609         },
3610         .clabels_from_axis = PIVOT_AXIS_LAYER, 
3611         .categories = categories,
3612         .n_categories = n_vars,
3613         .cilevel = 95,
3614       };
3615       for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
3616         hmap_init (&t->domains[dt]);
3617       ct->tables[ct->n_tables++] = t;
3618
3619       lex_match (lexer, T_EQUALS);
3620       if (!ctables_axis_parse (lexer, dataset_dict (ds), ct, t, PIVOT_AXIS_ROW))
3621         goto error;
3622       if (lex_match (lexer, T_BY))
3623         {
3624           if (!ctables_axis_parse (lexer, dataset_dict (ds),
3625                                    ct, t, PIVOT_AXIS_COLUMN))
3626             goto error;
3627
3628           if (lex_match (lexer, T_BY))
3629             {
3630               if (!ctables_axis_parse (lexer, dataset_dict (ds),
3631                                        ct, t, PIVOT_AXIS_LAYER))
3632                 goto error;
3633             }
3634         }
3635
3636       if (!t->axes[PIVOT_AXIS_ROW] && !t->axes[PIVOT_AXIS_COLUMN]
3637           && !t->axes[PIVOT_AXIS_LAYER])
3638         {
3639           lex_error (lexer, _("At least one variable must be specified."));
3640           goto error;
3641         }
3642
3643       const struct ctables_axis *scales[PIVOT_N_AXES];
3644       size_t n_scales = 0;
3645       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3646         {
3647           scales[a] = find_scale (t->axes[a]);
3648           if (scales[a])
3649             n_scales++;
3650         }
3651       if (n_scales > 1)
3652         {
3653           msg (SE, _("Scale variables may appear only on one axis."));
3654           if (scales[PIVOT_AXIS_ROW])
3655             msg_at (SN, scales[PIVOT_AXIS_ROW]->loc,
3656                     _("This scale variable appears on the rows axis."));
3657           if (scales[PIVOT_AXIS_COLUMN])
3658             msg_at (SN, scales[PIVOT_AXIS_COLUMN]->loc,
3659                     _("This scale variable appears on the columns axis."));
3660           if (scales[PIVOT_AXIS_LAYER])
3661             msg_at (SN, scales[PIVOT_AXIS_LAYER]->loc,
3662                     _("This scale variable appears on the layer axis."));
3663           goto error;
3664         }
3665
3666       const struct ctables_axis *summaries[PIVOT_N_AXES];
3667       size_t n_summaries = 0;
3668       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3669         {
3670           summaries[a] = (scales[a]
3671                           ? scales[a]
3672                           : find_categorical_summary_spec (t->axes[a]));
3673           if (summaries[a])
3674             n_summaries++;
3675         }
3676       if (n_summaries > 1)
3677         {
3678           msg (SE, _("Summaries may appear only on one axis."));
3679           if (summaries[PIVOT_AXIS_ROW])
3680             msg_at (SN, summaries[PIVOT_AXIS_ROW]->loc,
3681                     _("This variable on the rows axis has a summary."));
3682           if (summaries[PIVOT_AXIS_COLUMN])
3683             msg_at (SN, summaries[PIVOT_AXIS_COLUMN]->loc,
3684                     _("This variable on the columns axis has a summary."));
3685           if (summaries[PIVOT_AXIS_LAYER])
3686             msg_at (SN, summaries[PIVOT_AXIS_LAYER]->loc,
3687                     _("This variable on the layers axis has a summary."));
3688           goto error;
3689         }
3690       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3691         if (n_summaries ? summaries[a] : t->axes[a])
3692           {
3693             t->summary_axis = a;
3694             break;
3695           }
3696
3697       if (lex_token (lexer) == T_ENDCMD)
3698         {
3699           if (!ctables_prepare_table (t))
3700             goto error;
3701           break;
3702         }
3703       if (!lex_force_match (lexer, T_SLASH))
3704         break;
3705
3706       while (!lex_match_id (lexer, "TABLE") && lex_token (lexer) != T_ENDCMD)
3707         {
3708           if (lex_match_id (lexer, "SLABELS"))
3709             {
3710               while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
3711                 {
3712                   if (lex_match_id (lexer, "POSITION"))
3713                     {
3714                       lex_match (lexer, T_EQUALS);
3715                       if (lex_match_id (lexer, "COLUMN"))
3716                         t->slabels_axis = PIVOT_AXIS_COLUMN;
3717                       else if (lex_match_id (lexer, "ROW"))
3718                         t->slabels_axis = PIVOT_AXIS_ROW;
3719                       else if (lex_match_id (lexer, "LAYER"))
3720                         t->slabels_axis = PIVOT_AXIS_LAYER;
3721                       else
3722                         {
3723                           lex_error_expecting (lexer, "COLUMN", "ROW", "LAYER");
3724                           goto error;
3725                         }
3726                     }
3727                   else if (lex_match_id (lexer, "VISIBLE"))
3728                     {
3729                       lex_match (lexer, T_EQUALS);
3730                       if (!parse_bool (lexer, &t->slabels_visible))
3731                         goto error;
3732                     }
3733                   else
3734                     {
3735                       lex_error_expecting (lexer, "POSITION", "VISIBLE");
3736                       goto error;
3737                     }
3738                 }
3739             }
3740           else if (lex_match_id (lexer, "CLABELS"))
3741             {
3742               while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
3743                 {
3744                   if (lex_match_id (lexer, "AUTO"))
3745                     {
3746                       t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_ROW;
3747                       t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_COLUMN;
3748                     }
3749                   else if (lex_match_id (lexer, "ROWLABELS"))
3750                     {
3751                       lex_match (lexer, T_EQUALS);
3752                       if (lex_match_id (lexer, "OPPOSITE"))
3753                         t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_COLUMN;
3754                       else if (lex_match_id (lexer, "LAYER"))
3755                         t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_LAYER;
3756                       else
3757                         {
3758                           lex_error_expecting (lexer, "OPPOSITE", "LAYER");
3759                           goto error;
3760                         }
3761                     }
3762                   else if (lex_match_id (lexer, "COLLABELS"))
3763                     {
3764                       lex_match (lexer, T_EQUALS);
3765                       if (lex_match_id (lexer, "OPPOSITE"))
3766                         t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_ROW;
3767                       else if (lex_match_id (lexer, "LAYER"))
3768                         t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_LAYER;
3769                       else
3770                         {
3771                           lex_error_expecting (lexer, "OPPOSITE", "LAYER");
3772                           goto error;
3773                         }
3774                     }
3775                   else
3776                     {
3777                       lex_error_expecting (lexer, "AUTO", "ROWLABELS",
3778                                            "COLLABELS");
3779                       goto error;
3780                     }
3781                 }
3782             }
3783           else if (lex_match_id (lexer, "CRITERIA"))
3784             {
3785               if (!lex_force_match_id (lexer, "CILEVEL"))
3786                 goto error;
3787               lex_match (lexer, T_EQUALS);
3788
3789               if (!lex_force_num_range_halfopen (lexer, "CILEVEL", 0, 100))
3790                 goto error;
3791               t->cilevel = lex_number (lexer);
3792               lex_get (lexer);
3793             }
3794           else if (lex_match_id (lexer, "CATEGORIES"))
3795             {
3796               if (!ctables_table_parse_categories (lexer, dataset_dict (ds), t))
3797                 goto error;
3798             }
3799           else if (lex_match_id (lexer, "TITLES"))
3800             {
3801               do
3802                 {
3803                   char **textp;
3804                   if (lex_match_id (lexer, "CAPTION"))
3805                     textp = &t->caption;
3806                   else if (lex_match_id (lexer, "CORNER"))
3807                     textp = &t->corner;
3808                   else if (lex_match_id (lexer, "TITLE"))
3809                     textp = &t->title;
3810                   else
3811                     {
3812                       lex_error_expecting (lexer, "CAPTION", "CORNER", "TITLE");
3813                       goto error;
3814                     }
3815                   lex_match (lexer, T_EQUALS);
3816
3817                   struct string s = DS_EMPTY_INITIALIZER;
3818                   while (lex_is_string (lexer))
3819                     {
3820                       if (!ds_is_empty (&s))
3821                         ds_put_byte (&s, ' ');
3822                       ds_put_substring (&s, lex_tokss (lexer));
3823                       lex_get (lexer);
3824                     }
3825                   free (*textp);
3826                   *textp = ds_steal_cstr (&s);
3827                 }
3828               while (lex_token (lexer) != T_SLASH
3829                      && lex_token (lexer) != T_ENDCMD);
3830             }
3831           else if (lex_match_id (lexer, "SIGTEST"))
3832             {
3833               if (!t->chisq)
3834                 {
3835                   t->chisq = xmalloc (sizeof *t->chisq);
3836                   *t->chisq = (struct ctables_chisq) {
3837                     .alpha = .05,
3838                     .include_mrsets = true,
3839                     .all_visible = true,
3840                   };
3841                 }
3842
3843               do
3844                 {
3845                   if (lex_match_id (lexer, "TYPE"))
3846                     {
3847                       lex_match (lexer, T_EQUALS);
3848                       if (!lex_force_match_id (lexer, "CHISQUARE"))
3849                         goto error;
3850                     }
3851                   else if (lex_match_id (lexer, "ALPHA"))
3852                     {
3853                       lex_match (lexer, T_EQUALS);
3854                       if (!lex_force_num_range_halfopen (lexer, "ALPHA", 0, 1))
3855                         goto error;
3856                       t->chisq->alpha = lex_number (lexer);
3857                       lex_get (lexer);
3858                     }
3859                   else if (lex_match_id (lexer, "INCLUDEMRSETS"))
3860                     {
3861                       lex_match (lexer, T_EQUALS);
3862                       if (parse_bool (lexer, &t->chisq->include_mrsets))
3863                         goto error;
3864                     }
3865                   else if (lex_match_id (lexer, "CATEGORIES"))
3866                     {
3867                       lex_match (lexer, T_EQUALS);
3868                       if (lex_match_id (lexer, "ALLVISIBLE"))
3869                         t->chisq->all_visible = true;
3870                       else if (lex_match_id (lexer, "SUBTOTALS"))
3871                         t->chisq->all_visible = false;
3872                       else
3873                         {
3874                           lex_error_expecting (lexer,
3875                                                "ALLVISIBLE", "SUBTOTALS");
3876                           goto error;
3877                         }
3878                     }
3879                   else
3880                     {
3881                       lex_error_expecting (lexer, "TYPE", "ALPHA",
3882                                            "INCLUDEMRSETS", "CATEGORIES");
3883                       goto error;
3884                     }
3885                 }
3886               while (lex_token (lexer) != T_SLASH
3887                      && lex_token (lexer) != T_ENDCMD);
3888             }
3889           else if (lex_match_id (lexer, "COMPARETEST"))
3890             {
3891               if (!t->pairwise)
3892                 {
3893                   t->pairwise = xmalloc (sizeof *t->pairwise);
3894                   *t->pairwise = (struct ctables_pairwise) {
3895                     .type = PROP,
3896                     .alpha = { .05, .05 },
3897                     .adjust = BONFERRONI,
3898                     .include_mrsets = true,
3899                     .meansvariance_allcats = true,
3900                     .all_visible = true,
3901                     .merge = false,
3902                     .apa_style = true,
3903                     .show_sig = false,
3904                   };
3905                 }
3906
3907               do
3908                 {
3909                   if (lex_match_id (lexer, "TYPE"))
3910                     {
3911                       lex_match (lexer, T_EQUALS);
3912                       if (lex_match_id (lexer, "PROP"))
3913                         t->pairwise->type = PROP;
3914                       else if (lex_match_id (lexer, "MEAN"))
3915                         t->pairwise->type = MEAN;
3916                       else
3917                         {
3918                           lex_error_expecting (lexer, "PROP", "MEAN");
3919                           goto error;
3920                         }
3921                     }
3922                   else if (lex_match_id (lexer, "ALPHA"))
3923                     {
3924                       lex_match (lexer, T_EQUALS);
3925
3926                       if (!lex_force_num_range_open (lexer, "ALPHA", 0, 1))
3927                         goto error;
3928                       double a0 = lex_number (lexer);
3929                       lex_get (lexer);
3930
3931                       lex_match (lexer, T_COMMA);
3932                       if (lex_is_number (lexer))
3933                         {
3934                           if (!lex_force_num_range_open (lexer, "ALPHA", 0, 1))
3935                             goto error;
3936                           double a1 = lex_number (lexer);
3937                           lex_get (lexer);
3938
3939                           t->pairwise->alpha[0] = MIN (a0, a1);
3940                           t->pairwise->alpha[1] = MAX (a0, a1);
3941                         }
3942                       else
3943                         t->pairwise->alpha[0] = t->pairwise->alpha[1] = a0;
3944                     }
3945                   else if (lex_match_id (lexer, "ADJUST"))
3946                     {
3947                       lex_match (lexer, T_EQUALS);
3948                       if (lex_match_id (lexer, "BONFERRONI"))
3949                         t->pairwise->adjust = BONFERRONI;
3950                       else if (lex_match_id (lexer, "BH"))
3951                         t->pairwise->adjust = BH;
3952                       else if (lex_match_id (lexer, "NONE"))
3953                         t->pairwise->adjust = 0;
3954                       else
3955                         {
3956                           lex_error_expecting (lexer, "BONFERRONI", "BH",
3957                                                "NONE");
3958                           goto error;
3959                         }
3960                     }
3961                   else if (lex_match_id (lexer, "INCLUDEMRSETS"))
3962                     {
3963                       lex_match (lexer, T_EQUALS);
3964                       if (!parse_bool (lexer, &t->pairwise->include_mrsets))
3965                         goto error;
3966                     }
3967                   else if (lex_match_id (lexer, "MEANSVARIANCE"))
3968                     {
3969                       lex_match (lexer, T_EQUALS);
3970                       if (lex_match_id (lexer, "ALLCATS"))
3971                         t->pairwise->meansvariance_allcats = true;
3972                       else if (lex_match_id (lexer, "TESTEDCATS"))
3973                         t->pairwise->meansvariance_allcats = false;
3974                       else
3975                         {
3976                           lex_error_expecting (lexer, "ALLCATS", "TESTEDCATS");
3977                           goto error;
3978                         }
3979                     }
3980                   else if (lex_match_id (lexer, "CATEGORIES"))
3981                     {
3982                       lex_match (lexer, T_EQUALS);
3983                       if (lex_match_id (lexer, "ALLVISIBLE"))
3984                         t->pairwise->all_visible = true;
3985                       else if (lex_match_id (lexer, "SUBTOTALS"))
3986                         t->pairwise->all_visible = false;
3987                       else
3988                         {
3989                           lex_error_expecting (lexer, "ALLVISIBLE",
3990                                                "SUBTOTALS");
3991                           goto error;
3992                         }
3993                     }
3994                   else if (lex_match_id (lexer, "MERGE"))
3995                     {
3996                       lex_match (lexer, T_EQUALS);
3997                       if (!parse_bool (lexer, &t->pairwise->merge))
3998                         goto error;
3999                     }
4000                   else if (lex_match_id (lexer, "STYLE"))
4001                     {
4002                       lex_match (lexer, T_EQUALS);
4003                       if (lex_match_id (lexer, "APA"))
4004                         t->pairwise->apa_style = true;
4005                       else if (lex_match_id (lexer, "SIMPLE"))
4006                         t->pairwise->apa_style = false;
4007                       else
4008                         {
4009                           lex_error_expecting (lexer, "APA", "SIMPLE");
4010                           goto error;
4011                         }
4012                     }
4013                   else if (lex_match_id (lexer, "SHOWSIG"))
4014                     {
4015                       lex_match (lexer, T_EQUALS);
4016                       if (!parse_bool (lexer, &t->pairwise->show_sig))
4017                         goto error;
4018                     }
4019                   else
4020                     {
4021                       lex_error_expecting (lexer, "TYPE", "ALPHA", "ADJUST",
4022                                            "INCLUDEMRSETS", "MEANSVARIANCE",
4023                                            "CATEGORIES", "MERGE", "STYLE",
4024                                            "SHOWSIG");
4025                       goto error;
4026                     }
4027                 }
4028               while (lex_token (lexer) != T_SLASH
4029                      && lex_token (lexer) != T_ENDCMD);
4030             }
4031           else
4032             {
4033               lex_error_expecting (lexer, "TABLE", "SLABELS", "CLABELS",
4034                                    "CRITERIA", "CATEGORIES", "TITLES",
4035                                    "SIGTEST", "COMPARETEST");
4036               goto error;
4037             }
4038
4039           if (!lex_match (lexer, T_SLASH))
4040             break;
4041         }
4042
4043       if (t->label_axis[PIVOT_AXIS_ROW] != PIVOT_AXIS_ROW
4044           && t->label_axis[PIVOT_AXIS_COLUMN] != PIVOT_AXIS_COLUMN)
4045         {
4046           msg (SE, _("ROWLABELS and COLLABELS may not both be specified."));
4047           goto error;
4048         }
4049
4050       if (!ctables_prepare_table (t))
4051         goto error;
4052     }
4053   while (lex_token (lexer) != T_ENDCMD);
4054
4055   bool ok = ctables_execute (ds, ct);
4056   ctables_destroy (ct);
4057   return ok ? CMD_SUCCESS : CMD_FAILURE;
4058
4059 error:
4060   ctables_destroy (ct);
4061   return CMD_FAILURE;
4062 }
4063