CTABLES comments
[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 #include <errno.h>
21
22 #include "data/casereader.h"
23 #include "data/casewriter.h"
24 #include "data/data-out.h"
25 #include "data/dataset.h"
26 #include "data/dictionary.h"
27 #include "data/mrset.h"
28 #include "data/subcase.h"
29 #include "data/value-labels.h"
30 #include "language/command.h"
31 #include "language/lexer/format-parser.h"
32 #include "language/lexer/lexer.h"
33 #include "language/lexer/variable-parser.h"
34 #include "libpspp/array.h"
35 #include "libpspp/assertion.h"
36 #include "libpspp/hash-functions.h"
37 #include "libpspp/hmap.h"
38 #include "libpspp/i18n.h"
39 #include "libpspp/message.h"
40 #include "libpspp/string-array.h"
41 #include "math/mode.h"
42 #include "math/moments.h"
43 #include "math/percentiles.h"
44 #include "math/sort.h"
45 #include "output/pivot-table.h"
46
47 #include "gl/minmax.h"
48 #include "gl/xalloc.h"
49
50 #include "gettext.h"
51 #define _(msgid) gettext (msgid)
52 #define N_(msgid) (msgid)
53
54 enum ctables_vlabel
55   {
56     CTVL_NONE = SETTINGS_VALUE_SHOW_DEFAULT,
57     CTVL_NAME = SETTINGS_VALUE_SHOW_VALUE,
58     CTVL_LABEL = SETTINGS_VALUE_SHOW_LABEL,
59     CTVL_BOTH = SETTINGS_VALUE_SHOW_BOTH,
60   };
61
62 /* XXX:
63    - unweighted summaries (U*)
64    - lower confidence limits (*.LCL)
65    - upper confidence limits (*.UCL)
66    - standard error (*.SE)
67  */
68 #define SUMMARIES                                                       \
69     /* All variables. */                                                \
70     S(CTSF_COUNT, "COUNT", N_("Count"), CTF_COUNT, CTFA_ALL)            \
71     S(CTSF_ECOUNT, "ECOUNT", N_("Adjusted Count"), CTF_COUNT, CTFA_ALL) \
72     S(CTSF_ROWPCT_COUNT, "ROWPCT.COUNT", N_("Row %"), CTF_PERCENT, CTFA_ALL) \
73     S(CTSF_COLPCT_COUNT, "COLPCT.COUNT", N_("Column %"), CTF_PERCENT, CTFA_ALL) \
74     S(CTSF_TABLEPCT_COUNT, "TABLEPCT.COUNT", N_("Table %"), CTF_PERCENT, CTFA_ALL) \
75     S(CTSF_SUBTABLEPCT_COUNT, "SUBTABLEPCT.COUNT", N_("Subtable %"), CTF_PERCENT, CTFA_ALL) \
76     S(CTSF_LAYERPCT_COUNT, "LAYERPCT.COUNT", N_("Layer %"), CTF_PERCENT, CTFA_ALL) \
77     S(CTSF_LAYERROWPCT_COUNT, "LAYERROWPCT.COUNT", N_("Layer Row %"), CTF_PERCENT, CTFA_ALL) \
78     S(CTSF_LAYERCOLPCT_COUNT, "LAYERCOLPCT.COUNT", N_("Layer Column %"), CTF_PERCENT, CTFA_ALL) \
79     S(CTSF_ROWPCT_VALIDN, "ROWPCT.VALIDN", N_("Row Valid N %"), CTF_PERCENT, CTFA_ALL) \
80     S(CTSF_COLPCT_VALIDN, "COLPCT.VALIDN", N_("Column Valid N %"), CTF_PERCENT, CTFA_ALL) \
81     S(CTSF_TABLEPCT_VALIDN, "TABLEPCT.VALIDN", N_("Table Valid N %"), CTF_PERCENT, CTFA_ALL) \
82     S(CTSF_SUBTABLEPCT_VALIDN, "SUBTABLEPCT.VALIDN", N_("Subtable Valid N %"), CTF_PERCENT, CTFA_ALL) \
83     S(CTSF_LAYERPCT_VALIDN, "LAYERPCT.VALIDN", N_("Layer Valid N %"), CTF_PERCENT, CTFA_ALL) \
84     S(CTSF_LAYERROWPCT_VALIDN, "LAYERROWPCT.VALIDN", N_("Layer Row Valid N %"), CTF_PERCENT, CTFA_ALL) \
85     S(CTSF_LAYERCOLPCT_VALIDN, "LAYERCOLPCT.VALIDN", N_("Layer Column Valid N %"), CTF_PERCENT, CTFA_ALL) \
86     S(CTSF_ROWPCT_TOTALN, "ROWPCT.TOTALN", N_("Row Total N %"), CTF_PERCENT, CTFA_ALL) \
87     S(CTSF_COLPCT_TOTALN, "COLPCT.TOTALN", N_("Column Total N %"), CTF_PERCENT, CTFA_ALL) \
88     S(CTSF_TABLEPCT_TOTALN, "TABLEPCT.TOTALN", N_("Table Total N %"), CTF_PERCENT, CTFA_ALL) \
89     S(CTSF_SUBTABLEPCT_TOTALN, "SUBTABLEPCT.TOTALN", N_("Subtable Total N %"), CTF_PERCENT, CTFA_ALL) \
90     S(CTSF_LAYERPCT_TOTALN, "LAYERPCT.TOTALN", N_("Layer Total N %"), CTF_PERCENT, CTFA_ALL) \
91     S(CTSF_LAYERROWPCT_TOTALN, "LAYERROWPCT.TOTALN", N_("Layer Row Total N %"), CTF_PERCENT, CTFA_ALL) \
92     S(CTSF_LAYERCOLPCT_TOTALN, "LAYERCOLPCT.TOTALN", N_("Layer Column Total N %"), CTF_PERCENT, CTFA_ALL) \
93                                                                         \
94     /* Scale variables, totals, and subtotals. */                       \
95     S(CTSF_MAXIMUM, "MAXIMUM", N_("Maximum"), CTF_GENERAL, CTFA_SCALE)  \
96     S(CTSF_MEAN, "MEAN", N_("Mean"), CTF_GENERAL, CTFA_SCALE)           \
97     S(CTSF_MEDIAN, "MEDIAN", N_("Median"), CTF_GENERAL, CTFA_SCALE)     \
98     S(CTSF_MINIMUM, "MINIMUM", N_("Minimum"), CTF_GENERAL, CTFA_SCALE)  \
99     S(CTSF_MISSING, "MISSING", N_("Missing"), CTF_GENERAL, CTFA_SCALE)  \
100     S(CTSF_MODE, "MODE", N_("Mode"), CTF_GENERAL, CTFA_SCALE)           \
101     S(CTSF_PTILE, "PTILE", N_("Percentile"), CTF_GENERAL, CTFA_SCALE)   \
102     S(CTSF_RANGE, "RANGE", N_("Range"), CTF_GENERAL, CTFA_SCALE)        \
103     S(CTSF_SEMEAN, "SEMEAN", N_("Std Error of Mean"), CTF_GENERAL, CTFA_SCALE) \
104     S(CTSF_STDDEV, "STDDEV", N_("Std Deviation"), CTF_GENERAL, CTFA_SCALE) \
105     S(CTSF_SUM, "SUM", N_("Sum"), CTF_GENERAL, CTFA_SCALE)              \
106     S(CSTF_TOTALN, "TOTALN", N_("Total N"), CTF_COUNT, CTFA_SCALE)      \
107     S(CTSF_ETOTALN, "ETOTALN", N_("Adjusted Total N"), CTF_COUNT, CTFA_SCALE) \
108     S(CTSF_VALIDN, "VALIDN", N_("Valid N"), CTF_COUNT, CTFA_SCALE)      \
109     S(CTSF_EVALIDN, "EVALIDN", N_("Adjusted Valid N"), CTF_COUNT, CTFA_SCALE) \
110     S(CTSF_VARIANCE, "VARIANCE", N_("Variance"), CTF_GENERAL, CTFA_SCALE) \
111     S(CTSF_ROWPCT_SUM, "ROWPCT.SUM", N_("Row Sum %"), CTF_PERCENT, CTFA_SCALE) \
112     S(CTSF_COLPCT_SUM, "COLPCT.SUM", N_("Column Sum %"), CTF_PERCENT, CTFA_SCALE) \
113     S(CTSF_TABLEPCT_SUM, "TABLEPCT.SUM", N_("Table Sum %"), CTF_PERCENT, CTFA_SCALE) \
114     S(CTSF_SUBTABLEPCT_SUM, "SUBTABLEPCT.SUM", N_("Subtable Sum %"), CTF_PERCENT, CTFA_SCALE) \
115     S(CTSF_LAYERPCT_SUM, "LAYERPCT.SUM", N_("Layer Sum %"), CTF_PERCENT, CTFA_SCALE) \
116     S(CTSF_LAYERROWPCT_SUM, "LAYERROWPCT.SUM", N_("Layer Row Sum %"), CTF_PERCENT, CTFA_SCALE) \
117     S(CTSF_LAYERCOLPCT_SUM, "LAYERCOLPCT.SUM", N_("Layer Column Sum %"), CTF_PERCENT, CTFA_SCALE) \
118
119 #if 0         /* Multiple response sets not yet implemented. */
120   S(CTSF_RESPONSES, "RESPONSES", N_("Responses"), CTF_COUNT, CTFA_MRSETS) \
121     S(CTSF_ROWPCT_RESPONSES, "ROWPCT.RESPONSES", N_("Row Responses %"), CTF_PERCENT, CTFA_MRSETS) \
122     S(CTSF_COLPCT_RESPONSES, "COLPCT.RESPONSES", N_("Column Responses %"), CTF_PERCENT, CTFA_MRSETS) \
123     S(CTSF_TABLEPCT_RESPONSES, "TABLEPCT.RESPONSES", N_("Table Responses %"), CTF_PERCENT, CTFA_MRSETS) \
124     S(CTSF_SUBTABLEPCT_RESPONSES, "SUBTABLEPCT.RESPONSES", N_("Subtable Responses %"), CTF_PERCENT, CTFA_MRSETS) \
125     S(CTSF_LAYERPCT_RESPONSES, "LAYERPCT.RESPONSES", N_("Layer Responses %"), CTF_PERCENT, CTFA_MRSETS) \
126     S(CTSF_LAYERROWPCT_RESPONSES, "LAYERROWPCT.RESPONSES", N_("Layer Row Responses %"), CTF_PERCENT, CTFA_MRSETS) \
127     S(CTSF_LAYERCOLPCT_RESPONSES, "LAYERCOLPCT.RESPONSES", N_("Layer Column Responses %"), CTF_PERCENT, CTFA_MRSETS) \
128     S(CTSF_ROWPCT_RESPONSES_COUNT, "ROWPCT.RESPONSES.COUNT", N_("Row Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
129     S(CTSF_COLPCT_RESPONSES_COUNT, "COLPCT.RESPONSES.COUNT", N_("Column Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
130     S(CTSF_TABLEPCT_RESPONSES_COUNT, "TABLEPCT.RESPONSES.COUNT", N_("Table Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
131     S(CTSF_SUBTABLEPCT_RESPONSES_COUNT, "SUBTABLEPCT.RESPONSES.COUNT", N_("Subtable Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
132     S(CTSF_LAYERPCT_RESPONSES_COUNT, "LAYERPCT.RESPONSES.COUNT", N_("Layer Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
133     S(CTSF_LAYERROWPCT_RESPONSES_COUNT, "LAYERROWPCT.RESPONSES.COUNT", N_("Layer Row Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
134     S(CTSF_LAYERCOLPCT_RESPONSES_COUNT, "LAYERCOLPCT.RESPONSES.COUNT", N_("Layer Column Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
135     S(CTSF_ROWPCT_COUNT_RESPONSES, "ROWPCT.COUNT.RESPONSES", N_("Row Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
136     S(CTSF_COLPCT_COUNT_RESPONSES, "COLPCT.COUNT.RESPONSES", N_("Column Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
137     S(CTSF_TABLEPCT_COUNT_RESPONSES, "TABLEPCT.COUNT.RESPONSES", N_("Table Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
138     S(CTSF_SUBTABLEPCT_COUNT_RESPONSES, "SUBTABLEPCT.COUNT.RESPONSES", N_("Subtable Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
139     S(CTSF_LAYERPCT_COUNT_RESPONSES, "LAYERPCT.COUNT.RESPONSES", N_("Layer Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
140     S(CTSF_LAYERROWPCT_COUNT_RESPONSES, "LAYERROWPCT.COUNT.RESPONSES", N_("Layer Row Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
141     S(CTSF_LAYERCOLPCT_COUNT_RESPONSES, "LAYERCOLPCT.RESPONSES.COUNT", N_("Layer Column Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS)
142 #endif
143
144 enum ctables_summary_function
145   {
146 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) ENUM,
147     SUMMARIES
148 #undef S
149   };
150
151 enum {
152 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) +1
153   N_CTSF_FUNCTIONS = SUMMARIES
154 #undef S
155 };
156
157 static bool ctables_summary_function_is_count (enum ctables_summary_function);
158
159 enum ctables_domain_type
160   {
161     /* Within a section, where stacked variables divide one section from
162        another. */
163     CTDT_TABLE,                  /* All layers of a whole section. */
164     CTDT_LAYER,                  /* One layer within a section. */
165     CTDT_LAYERROW,               /* Row in one layer within a section. */
166     CTDT_LAYERCOL,               /* Column in one layer within a section. */
167
168     /* Within a subtable, where a subtable pairs an innermost row variable with
169        an innermost column variable within a single layer.  */
170     CTDT_SUBTABLE,               /* Whole subtable. */
171     CTDT_ROW,                    /* Row within a subtable. */
172     CTDT_COL,                    /* Column within a subtable. */
173 #define N_CTDTS 7
174   };
175
176 struct ctables_domain
177   {
178     struct hmap_node node;
179
180     const struct ctables_cell *example;
181
182     double d_valid;             /* Dictionary weight. */
183     double d_missing;
184     double e_valid;             /* Effective weight */
185     double e_missing;
186   };
187
188 enum ctables_summary_variant
189   {
190     CSV_CELL,
191     CSV_TOTAL
192 #define N_CSVS 2
193   };
194
195 struct ctables_cell
196   {
197     /* In struct ctables_section's 'cells' hmap.  Indexed by all the values in
198        all the axes (except the scalar variable, if any). */
199     struct hmap_node node;
200
201     /* The domains that contain this cell. */
202     bool contributes_to_domains;
203     struct ctables_domain *domains[N_CTDTS];
204
205     bool hide;
206     bool postcompute;
207     enum ctables_summary_variant sv;
208
209     struct ctables_cell_axis
210       {
211         struct ctables_cell_value
212           {
213             const struct ctables_category *category;
214             union value value;
215           }
216         *cvs;
217         int leaf;
218       }
219     axes[PIVOT_N_AXES];
220
221     union ctables_summary *summaries;
222   };
223
224 struct ctables
225   {
226     const struct dictionary *dict;
227     struct pivot_table_look *look;
228
229     /* CTABLES has a number of extra formats that we implement via custom
230        currency specifications on an alternate fmt_settings. */
231 #define CTEF_NEGPAREN FMT_CCA
232 #define CTEF_NEQUAL   FMT_CCB
233 #define CTEF_PAREN    FMT_CCC
234 #define CTEF_PCTPAREN FMT_CCD
235     struct fmt_settings ctables_formats;
236
237     /* If this is NULL, zeros are displayed using the normal print format.
238        Otherwise, this string is displayed. */
239     char *zero;
240
241     /* If this is NULL, missing values are displayed using the normal print
242        format.  Otherwise, this string is displayed. */
243     char *missing;
244
245     /* Indexed by variable dictionary index. */
246     enum ctables_vlabel *vlabels;
247
248     struct hmap postcomputes;   /* Contains "struct ctables_postcompute"s. */
249
250     bool mrsets_count_duplicates; /* MRSETS. */
251     bool smissing_listwise;       /* SMISSING. */
252     struct variable *e_weight;    /* WEIGHT. */
253     int hide_threshold;           /* HIDESMALLCOUNTS. */
254
255     struct ctables_table **tables;
256     size_t n_tables;
257   };
258
259 static struct ctables_postcompute *ctables_find_postcompute (struct ctables *,
260                                                              const char *name);
261
262 struct ctables_postcompute
263   {
264     struct hmap_node hmap_node; /* In struct ctables's 'pcompute' hmap. */
265     char *name;                 /* Name, without leading &. */
266
267     struct msg_location *location; /* Location of definition. */
268     struct ctables_pcexpr *expr;
269     char *label;
270     struct ctables_summary_spec_set *specs;
271     bool hide_source_cats;
272   };
273
274 struct ctables_pcexpr
275   {
276     /* Precedence table:
277
278        ()
279        **
280        -
281        * /
282        - +
283     */
284     enum ctables_postcompute_op
285       {
286         /* Terminals. */
287         CTPO_CONSTANT,          /* 5 */
288         CTPO_CAT_NUMBER,        /* [5] */
289         CTPO_CAT_STRING,        /* ["STRING"] */
290         CTPO_CAT_RANGE,         /* [LO THRU 5] */
291         CTPO_CAT_MISSING,       /* MISSING */
292         CTPO_CAT_OTHERNM,       /* OTHERNM */
293         CTPO_CAT_SUBTOTAL,      /* SUBTOTAL */
294         CTPO_CAT_TOTAL,         /* TOTAL */
295
296         /* Nonterminals. */
297         CTPO_ADD,
298         CTPO_SUB,
299         CTPO_MUL,
300         CTPO_DIV,
301         CTPO_POW,
302         CTPO_NEG,
303       }
304     op;
305
306     union
307       {
308         /* CTPO_CAT_NUMBER. */
309         double number;
310
311         /* CTPO_CAT_STRING. */
312         char *string;
313
314         /* CTPO_CAT_RANGE. */
315         double range[2];
316
317         /* CTPO_CAT_SUBTOTAL. */
318         size_t subtotal_index;
319
320         /* Two elements: CTPO_ADD, CTPO_SUB, CTPO_MUL, CTPO_DIV, CTPO_POW.
321            One element: CTPO_NEG. */
322         struct ctables_pcexpr *subs[2];
323       };
324
325     /* Source location. */
326     struct msg_location *location;
327   };
328
329 static void ctables_pcexpr_destroy (struct ctables_pcexpr *);
330 static struct ctables_pcexpr *ctables_pcexpr_allocate_binary (
331   enum ctables_postcompute_op, struct ctables_pcexpr *sub0,
332   struct ctables_pcexpr *sub1);
333
334 struct ctables_summary_spec_set
335   {
336     struct ctables_summary_spec *specs;
337     size_t n;
338     size_t allocated;
339
340     struct variable *var;
341   };
342
343 static void ctables_summary_spec_set_clone (struct ctables_summary_spec_set *,
344                                             const struct ctables_summary_spec_set *);
345 static void ctables_summary_spec_set_uninit (struct ctables_summary_spec_set *);
346
347 /* A nested sequence of variables, e.g. a > b > c. */
348 struct ctables_nest
349   {
350     struct variable **vars;
351     size_t n;
352     size_t scale_idx;
353     size_t *domains[N_CTDTS];
354     size_t n_domains[N_CTDTS];
355
356     struct ctables_summary_spec_set specs[N_CSVS];
357   };
358
359 /* A stack of nestings, e.g. nest1 + nest2 + ... + nestN. */
360 struct ctables_stack
361   {
362     struct ctables_nest *nests;
363     size_t n;
364   };
365
366 struct ctables_value
367   {
368     struct hmap_node node;
369     union value value;
370     int leaf;
371   };
372
373 struct ctables_occurrence
374   {
375     struct hmap_node node;
376     union value value;
377   };
378
379 struct ctables_section
380   {
381     struct ctables_table *table;
382     struct ctables_nest *nests[PIVOT_N_AXES];
383     struct hmap *occurrences[PIVOT_N_AXES];
384     struct hmap cells;            /* Contains "struct ctable_cell"s. */
385     struct hmap domains[N_CTDTS]; /* Contains "struct ctable_domain"s. */
386   };
387
388 struct ctables_table
389   {
390     struct ctables *ctables;
391     struct ctables_axis *axes[PIVOT_N_AXES];
392     struct ctables_stack stacks[PIVOT_N_AXES];
393     struct ctables_section *sections;
394     size_t n_sections;
395     enum pivot_axis_type summary_axis;
396     struct ctables_summary_spec_set summary_specs;
397
398     const struct variable *clabels_example;
399     struct hmap clabels_values_map;
400     struct ctables_value **clabels_values;
401     size_t n_clabels_values;
402
403     enum pivot_axis_type slabels_axis;
404     bool slabels_visible;
405
406     /* The innermost category labels for axis 'a' appear on axis label_axis[a].
407
408        Most commonly, label_axis[a] == a, and in particular we always have
409        label_axis{PIVOT_AXIS_LAYER] == PIVOT_AXIS_LAYER.
410
411        If ROWLABELS or COLLABELS is specified, then one of
412        label_axis[PIVOT_AXIS_ROW] or label_axis[PIVOT_AXIS_COLUMN] can be the
413        opposite axis or PIVOT_AXIS_LAYER.  Only one of them will differ.
414     */
415     enum pivot_axis_type label_axis[PIVOT_N_AXES];
416     enum pivot_axis_type clabels_from_axis;
417
418     /* Indexed by variable dictionary index. */
419     struct ctables_categories **categories;
420     size_t n_categories;
421
422     double cilevel;
423
424     char *caption;
425     char *corner;
426     char *title;
427
428     struct ctables_chisq *chisq;
429     struct ctables_pairwise *pairwise;
430   };
431
432 struct ctables_var
433   {
434     bool is_mrset;
435     union
436       {
437         struct variable *var;
438         const struct mrset *mrset;
439       };
440   };
441
442 static const struct fmt_spec *
443 ctables_var_get_print_format (const struct ctables_var *var)
444 {
445   return (var->is_mrset
446           ? var_get_print_format (var->mrset->vars[0])
447           : var_get_print_format (var->var));
448 }
449
450 static const char *
451 ctables_var_name (const struct ctables_var *var)
452 {
453   return var->is_mrset ? var->mrset->name : var_get_name (var->var);
454 }
455
456 struct ctables_categories
457   {
458     size_t n_refs;
459     struct ctables_category *cats;
460     size_t n_cats;
461     bool show_empty;
462   };
463
464 struct ctables_category
465   {
466     enum ctables_category_type
467       {
468         /* Explicit category lists. */
469         CCT_NUMBER,
470         CCT_STRING,
471         CCT_RANGE,
472         CCT_MISSING,
473         CCT_OTHERNM,
474         CCT_POSTCOMPUTE,
475
476         /* Totals and subtotals. */
477         CCT_SUBTOTAL,
478         CCT_TOTAL,
479
480         /* Implicit category lists. */
481         CCT_VALUE,
482         CCT_LABEL,
483         CCT_FUNCTION,
484       }
485     type;
486
487     struct ctables_category *subtotal;
488
489     bool hide;
490
491     union
492       {
493         double number;          /* CCT_NUMBER. */
494         char *string;           /* CCT_STRING. */
495         double range[2];        /* CCT_RANGE. */
496
497         struct
498           {
499             char *total_label;      /* CCT_SUBTOTAL, CCT_TOTAL. */
500             bool hide_subcategories; /* CCT_SUBTOTAL. */
501           };
502
503         const struct ctables_postcompute *pc; /* CCT_POSTCOMPUTE. */
504
505         /* CCT_VALUE, CCT_LABEL, CCT_FUNCTION. */
506         struct
507           {
508             bool include_missing;
509             bool sort_ascending;
510
511             /* CCT_FUNCTION. */
512             enum ctables_summary_function sort_function;
513             struct variable *sort_var;
514             double percentile;
515           };
516       };
517
518     /* Source location.  This is null for CCT_TOTAL, CCT_VALUE, CCT_LABEL,
519        CCT_FUNCTION. */
520     struct msg_location *location;
521   };
522
523 static void
524 ctables_category_uninit (struct ctables_category *cat)
525 {
526   if (!cat)
527     return;
528
529   switch (cat->type)
530     {
531     case CCT_NUMBER:
532     case CCT_RANGE:
533     case CCT_MISSING:
534     case CCT_OTHERNM:
535     case CCT_POSTCOMPUTE:
536       break;
537
538     case CCT_STRING:
539       free (cat->string);
540       break;
541
542     case CCT_SUBTOTAL:
543     case CCT_TOTAL:
544       free (cat->total_label);
545       break;
546
547     case CCT_VALUE:
548     case CCT_LABEL:
549     case CCT_FUNCTION:
550       break;
551     }
552 }
553
554 static bool
555 ctables_category_equal (const struct ctables_category *a,
556                         const struct ctables_category *b)
557 {
558   if (a->type != b->type)
559     return false;
560
561   switch (a->type)
562     {
563     case CCT_NUMBER:
564       return a->number == b->number;
565
566     case CCT_STRING:
567       return strcmp (a->string, b->string);
568
569     case CCT_RANGE:
570       return a->range[0] == b->range[0] && a->range[1] == b->range[1];
571
572     case CCT_MISSING:
573     case CCT_OTHERNM:
574       return true;
575
576     case CCT_POSTCOMPUTE:
577       return a->pc == b->pc;
578
579     case CCT_SUBTOTAL:
580     case CCT_TOTAL:
581       return !strcmp (a->total_label, b->total_label);
582
583     case CCT_VALUE:
584     case CCT_LABEL:
585     case CCT_FUNCTION:
586       return (a->include_missing == b->include_missing
587               && a->sort_ascending == b->sort_ascending
588               && a->sort_function == b->sort_function
589               && a->sort_var == b->sort_var
590               && a->percentile == b->percentile);
591     }
592
593   NOT_REACHED ();
594 }
595
596 static void
597 ctables_categories_unref (struct ctables_categories *c)
598 {
599   if (!c)
600     return;
601
602   assert (c->n_refs > 0);
603   if (--c->n_refs)
604     return;
605
606   for (size_t i = 0; i < c->n_cats; i++)
607     ctables_category_uninit (&c->cats[i]);
608   free (c->cats);
609   free (c);
610 }
611
612 static bool
613 ctables_categories_equal (const struct ctables_categories *a,
614                           const struct ctables_categories *b)
615 {
616   if (a->n_cats != b->n_cats || a->show_empty != b->show_empty)
617     return false;
618
619   for (size_t i = 0; i < a->n_cats; i++)
620     if (!ctables_category_equal (&a->cats[i], &b->cats[i]))
621       return false;
622
623   return true;
624 }
625
626 /* Chi-square test (SIGTEST). */
627 struct ctables_chisq
628   {
629     double alpha;
630     bool include_mrsets;
631     bool all_visible;
632   };
633
634 /* Pairwise comparison test (COMPARETEST). */
635 struct ctables_pairwise
636   {
637     enum { PROP, MEAN } type;
638     double alpha[2];
639     bool include_mrsets;
640     bool meansvariance_allcats;
641     bool all_visible;
642     enum { BONFERRONI = 1, BH } adjust;
643     bool merge;
644     bool apa_style;
645     bool show_sig;
646   };
647
648 struct ctables_axis
649   {
650     enum ctables_axis_op
651       {
652         /* Terminals. */
653         CTAO_VAR,
654
655         /* Nonterminals. */
656         CTAO_STACK,             /* + */
657         CTAO_NEST,              /* > */
658       }
659     op;
660
661     union
662       {
663         /* Terminals. */
664         struct
665           {
666             struct ctables_var var;
667             bool scale;
668             struct ctables_summary_spec_set specs[N_CSVS];
669           };
670
671         /* Nonterminals. */
672         struct ctables_axis *subs[2];
673       };
674
675     struct msg_location *loc;
676   };
677
678 static void ctables_axis_destroy (struct ctables_axis *);
679
680 enum ctables_format
681   {
682     CTF_COUNT,
683     CTF_PERCENT,
684     CTF_GENERAL
685   };
686
687 enum ctables_function_availability
688   {
689     CTFA_ALL,                /* Any variables. */
690     CTFA_SCALE,              /* Only scale variables, totals, and subtotals. */
691     CTFA_MRSETS,             /* Only multiple-response sets */
692   };
693
694 struct ctables_summary_spec
695   {
696     enum ctables_summary_function function;
697     double percentile;          /* CTSF_PTILE only. */
698     char *label;
699
700     struct fmt_spec format;
701     bool is_ctables_format;       /* Is 'format' one of CTEF_*? */
702
703     size_t axis_idx;
704   };
705
706 static void
707 ctables_summary_spec_clone (struct ctables_summary_spec *dst,
708                             const struct ctables_summary_spec *src)
709 {
710   *dst = *src;
711   dst->label = xstrdup (src->label);
712 }
713
714 static void
715 ctables_summary_spec_uninit (struct ctables_summary_spec *s)
716 {
717   if (s)
718     free (s->label);
719 }
720
721 static void
722 ctables_summary_spec_set_clone (struct ctables_summary_spec_set *dst,
723                                 const struct ctables_summary_spec_set *src)
724 {
725   struct ctables_summary_spec *specs = xnmalloc (src->n, sizeof *specs);
726   for (size_t i = 0; i < src->n; i++)
727     ctables_summary_spec_clone (&specs[i], &src->specs[i]);
728
729   *dst = (struct ctables_summary_spec_set) {
730     .specs = specs,
731     .n = src->n,
732     .allocated = src->n,
733     .var = src->var
734   };
735 }
736
737 static void
738 ctables_summary_spec_set_uninit (struct ctables_summary_spec_set *set)
739 {
740   for (size_t i = 0; i < set->n; i++)
741     ctables_summary_spec_uninit (&set->specs[i]);
742   free (set->specs);
743 }
744
745 static bool
746 parse_col_width (struct lexer *lexer, const char *name, double *width)
747 {
748   lex_match (lexer, T_EQUALS);
749   if (lex_match_id (lexer, "DEFAULT"))
750     *width = SYSMIS;
751   else if (lex_force_num_range_closed (lexer, name, 0, DBL_MAX))
752     {
753       *width = lex_number (lexer);
754       lex_get (lexer);
755     }
756   else
757     return false;
758
759   return true;
760 }
761
762 static bool
763 parse_bool (struct lexer *lexer, bool *b)
764 {
765   if (lex_match_id (lexer, "NO"))
766     *b = false;
767   else if (lex_match_id (lexer, "YES"))
768     *b = true;
769   else
770     {
771       lex_error_expecting (lexer, "YES", "NO");
772       return false;
773     }
774   return true;
775 }
776
777 static enum ctables_function_availability
778 ctables_function_availability (enum ctables_summary_function f)
779 {
780   static enum ctables_function_availability availability[] = {
781 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = AVAILABILITY,
782     SUMMARIES
783 #undef S
784   };
785
786   return availability[f];
787 }
788
789 static bool
790 ctables_summary_function_is_count (enum ctables_summary_function f)
791 {
792   switch (f)
793     {
794     case CTSF_COUNT:
795     case CTSF_ECOUNT:
796     case CTSF_ROWPCT_COUNT:
797     case CTSF_COLPCT_COUNT:
798     case CTSF_TABLEPCT_COUNT:
799     case CTSF_SUBTABLEPCT_COUNT:
800     case CTSF_LAYERPCT_COUNT:
801     case CTSF_LAYERROWPCT_COUNT:
802     case CTSF_LAYERCOLPCT_COUNT:
803       return true;
804
805     case CTSF_ROWPCT_VALIDN:
806     case CTSF_COLPCT_VALIDN:
807     case CTSF_TABLEPCT_VALIDN:
808     case CTSF_SUBTABLEPCT_VALIDN:
809     case CTSF_LAYERPCT_VALIDN:
810     case CTSF_LAYERROWPCT_VALIDN:
811     case CTSF_LAYERCOLPCT_VALIDN:
812     case CTSF_ROWPCT_TOTALN:
813     case CTSF_COLPCT_TOTALN:
814     case CTSF_TABLEPCT_TOTALN:
815     case CTSF_SUBTABLEPCT_TOTALN:
816     case CTSF_LAYERPCT_TOTALN:
817     case CTSF_LAYERROWPCT_TOTALN:
818     case CTSF_LAYERCOLPCT_TOTALN:
819     case CTSF_MAXIMUM:
820     case CTSF_MEAN:
821     case CTSF_MEDIAN:
822     case CTSF_MINIMUM:
823     case CTSF_MISSING:
824     case CTSF_MODE:
825     case CTSF_PTILE:
826     case CTSF_RANGE:
827     case CTSF_SEMEAN:
828     case CTSF_STDDEV:
829     case CTSF_SUM:
830     case CSTF_TOTALN:
831     case CTSF_ETOTALN:
832     case CTSF_VALIDN:
833     case CTSF_EVALIDN:
834     case CTSF_VARIANCE:
835     case CTSF_ROWPCT_SUM:
836     case CTSF_COLPCT_SUM:
837     case CTSF_TABLEPCT_SUM:
838     case CTSF_SUBTABLEPCT_SUM:
839     case CTSF_LAYERPCT_SUM:
840     case CTSF_LAYERROWPCT_SUM:
841     case CTSF_LAYERCOLPCT_SUM:
842       return false;
843   }
844   NOT_REACHED ();
845 }
846
847
848 static bool
849 parse_ctables_summary_function (struct lexer *lexer,
850                                 enum ctables_summary_function *f)
851 {
852   struct pair
853     {
854       enum ctables_summary_function function;
855       struct substring name;
856     };
857   static struct pair names[] = {
858 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) \
859     { ENUM, SS_LITERAL_INITIALIZER (NAME) },
860     SUMMARIES
861
862     /* The .COUNT suffix may be omitted. */
863     S(CTSF_ROWPCT_COUNT, "ROWPCT", _, _, _)
864     S(CTSF_COLPCT_COUNT, "COLPCT", _, _, _)
865     S(CTSF_TABLEPCT_COUNT, "TABLEPCT", _, _, _)
866     S(CTSF_SUBTABLEPCT_COUNT, "SUBTABLEPCT", _, _, _)
867     S(CTSF_LAYERPCT_COUNT, "LAYERPCT", _, _, _)
868     S(CTSF_LAYERROWPCT_COUNT, "LAYERROWPCT", _, _, _)
869     S(CTSF_LAYERCOLPCT_COUNT, "LAYERCOLPCT", _, _, _)
870 #undef S
871   };
872
873   if (!lex_force_id (lexer))
874     return false;
875
876   for (size_t i = 0; i < sizeof names / sizeof *names; i++)
877     if (ss_equals_case (names[i].name, lex_tokss (lexer)))
878       {
879         *f = names[i].function;
880         lex_get (lexer);
881         return true;
882       }
883
884   lex_error (lexer, _("Expecting summary function name."));
885   return false;
886 }
887
888 static void
889 ctables_axis_destroy (struct ctables_axis *axis)
890 {
891   if (!axis)
892     return;
893
894   switch (axis->op)
895     {
896     case CTAO_VAR:
897       for (size_t i = 0; i < N_CSVS; i++)
898         ctables_summary_spec_set_uninit (&axis->specs[i]);
899       break;
900
901     case CTAO_STACK:
902     case CTAO_NEST:
903       ctables_axis_destroy (axis->subs[0]);
904       ctables_axis_destroy (axis->subs[1]);
905       break;
906     }
907   msg_location_destroy (axis->loc);
908   free (axis);
909 }
910
911 static struct ctables_axis *
912 ctables_axis_new_nonterminal (enum ctables_axis_op op,
913                               struct ctables_axis *sub0,
914                               struct ctables_axis *sub1,
915                               struct lexer *lexer, int start_ofs)
916 {
917   struct ctables_axis *axis = xmalloc (sizeof *axis);
918   *axis = (struct ctables_axis) {
919     .op = op,
920     .subs = { sub0, sub1 },
921     .loc = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer) - 1),
922   };
923   return axis;
924 }
925
926 struct ctables_axis_parse_ctx
927   {
928     struct lexer *lexer;
929     struct dictionary *dict;
930     struct ctables *ct;
931     struct ctables_table *t;
932   };
933
934 static struct fmt_spec
935 ctables_summary_default_format (enum ctables_summary_function function,
936                                 const struct ctables_var *var)
937 {
938   static const enum ctables_format default_formats[] = {
939 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = FORMAT,
940     SUMMARIES
941 #undef S
942   };
943   switch (default_formats[function])
944     {
945     case CTF_COUNT:
946       return (struct fmt_spec) { .type = FMT_F, .w = 40 };
947
948     case CTF_PERCENT:
949       return (struct fmt_spec) { .type = FMT_PCT, .w = 40, .d = 1 };
950
951     case CTF_GENERAL:
952       return *ctables_var_get_print_format (var);
953
954     default:
955       NOT_REACHED ();
956     }
957 }
958
959 static char *
960 ctables_summary_default_label (enum ctables_summary_function function,
961                                double percentile)
962 {
963   static const char *default_labels[] = {
964 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = LABEL,
965     SUMMARIES
966 #undef S
967   };
968
969   return (function == CTSF_PTILE
970           ? xasprintf (_("Percentile %.2f"), percentile)
971           : xstrdup (gettext (default_labels[function])));
972 }
973
974 static const char *
975 ctables_summary_function_name (enum ctables_summary_function function)
976 {
977   static const char *names[] = {
978 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = NAME,
979     SUMMARIES
980 #undef S
981   };
982   return names[function];
983 }
984
985 static bool
986 add_summary_spec (struct ctables_axis *axis,
987                   enum ctables_summary_function function, double percentile,
988                   const char *label, const struct fmt_spec *format,
989                   bool is_ctables_format, const struct msg_location *loc,
990                   enum ctables_summary_variant sv)
991 {
992   if (axis->op == CTAO_VAR)
993     {
994       const char *function_name = ctables_summary_function_name (function);
995       const char *var_name = ctables_var_name (&axis->var);
996       switch (ctables_function_availability (function))
997         {
998         case CTFA_MRSETS:
999           if (!axis->var.is_mrset)
1000             {
1001               msg_at (SE, loc, _("Summary function %s applies only to multiple "
1002                                  "response sets."), function_name);
1003               msg_at (SN, axis->loc, _("'%s' is not a multiple response set."),
1004                       var_name);
1005               return false;
1006             }
1007           break;
1008
1009         case CTFA_SCALE:
1010           if (!axis->scale)
1011             {
1012               msg_at (SE, loc,
1013                       _("Summary function %s applies only to scale variables."),
1014                       function_name);
1015               msg_at (SN, axis->loc, _("'%s' is not a scale variable."),
1016                       var_name);
1017               return false;
1018             }
1019           break;
1020
1021         case CTFA_ALL:
1022           break;
1023         }
1024
1025       struct ctables_summary_spec_set *set = &axis->specs[sv];
1026       if (set->n >= set->allocated)
1027         set->specs = x2nrealloc (set->specs, &set->allocated,
1028                                  sizeof *set->specs);
1029
1030       struct ctables_summary_spec *dst = &set->specs[set->n++];
1031       *dst = (struct ctables_summary_spec) {
1032         .function = function,
1033         .percentile = percentile,
1034         .label = xstrdup (label),
1035         .format = (format ? *format
1036                    : ctables_summary_default_format (function, &axis->var)),
1037         .is_ctables_format = is_ctables_format,
1038       };
1039       return true;
1040     }
1041   else
1042     {
1043       for (size_t i = 0; i < 2; i++)
1044         if (!add_summary_spec (axis->subs[i], function, percentile, label,
1045                                format, is_ctables_format, loc, sv))
1046           return false;
1047       return true;
1048     }
1049 }
1050
1051 static struct ctables_axis *ctables_axis_parse_stack (
1052   struct ctables_axis_parse_ctx *);
1053
1054 static bool
1055 ctables_var_parse (struct lexer *lexer, struct dictionary *dict,
1056                    struct ctables_var *var)
1057 {
1058   if (ss_starts_with (lex_tokss (lexer), ss_cstr ("$")))
1059     {
1060       *var = (struct ctables_var) {
1061         .is_mrset = true,
1062         .mrset = dict_lookup_mrset (dict, lex_tokcstr (lexer))
1063       };
1064       if (!var->mrset)
1065         {
1066           lex_error (lexer, _("'%s' does not name a multiple-response set "
1067                               "in the active file dictionary."),
1068                      lex_tokcstr (lexer));
1069           return false;
1070         }
1071       lex_get (lexer);
1072       return true;
1073     }
1074   else
1075     {
1076       *var = (struct ctables_var) {
1077         .is_mrset = false,
1078         .var = parse_variable (lexer, dict),
1079       };
1080       return var->var != NULL;
1081     }
1082 }
1083
1084 static struct ctables_axis *
1085 ctables_axis_parse_primary (struct ctables_axis_parse_ctx *ctx)
1086 {
1087   if (lex_match (ctx->lexer, T_LPAREN))
1088     {
1089       struct ctables_axis *sub = ctables_axis_parse_stack (ctx);
1090       if (!sub || !lex_force_match (ctx->lexer, T_RPAREN))
1091         {
1092           ctables_axis_destroy (sub);
1093           return NULL;
1094         }
1095       return sub;
1096     }
1097
1098   if (!lex_force_id (ctx->lexer))
1099     return NULL;
1100
1101   int start_ofs = lex_ofs (ctx->lexer);
1102   struct ctables_var var;
1103   if (!ctables_var_parse (ctx->lexer, ctx->dict, &var))
1104     return NULL;
1105
1106   struct ctables_axis *axis = xmalloc (sizeof *axis);
1107   *axis = (struct ctables_axis) { .op = CTAO_VAR, .var = var };
1108
1109   /* XXX should figure out default measures by reading data */
1110   axis->scale = (var.is_mrset ? false
1111                  : lex_match_phrase (ctx->lexer, "[S]") ? true
1112                  : lex_match_phrase (ctx->lexer, "[C]") ? false
1113                  : var_get_measure (var.var) == MEASURE_SCALE);
1114   axis->loc = lex_ofs_location (ctx->lexer, start_ofs,
1115                                 lex_ofs (ctx->lexer) - 1);
1116   return axis;
1117 }
1118
1119 static bool
1120 has_digit (const char *s)
1121 {
1122   return s[strcspn (s, "0123456789")] != '\0';
1123 }
1124
1125 static bool
1126 parse_ctables_format_specifier (struct lexer *lexer, struct fmt_spec *format,
1127                                 bool *is_ctables_format)
1128 {
1129   char type[FMT_TYPE_LEN_MAX + 1];
1130   if (!parse_abstract_format_specifier__ (lexer, type, &format->w, &format->d))
1131     return false;
1132
1133   if (!strcasecmp (type, "NEGPAREN"))
1134     format->type = CTEF_NEGPAREN;
1135   else if (!strcasecmp (type, "NEQUAL"))
1136     format->type = CTEF_NEQUAL;
1137   else if (!strcasecmp (type, "PAREN"))
1138     format->type = CTEF_PAREN;
1139   else if (!strcasecmp (type, "PCTPAREN"))
1140     format->type = CTEF_PCTPAREN;
1141   else
1142     {
1143       *is_ctables_format = false;
1144       return (parse_format_specifier (lexer, format)
1145               && fmt_check_output (format)
1146               && fmt_check_type_compat (format, VAL_NUMERIC));
1147     }
1148
1149   if (format->w < 2)
1150     {
1151       msg (SE, _("Output format %s requires width 2 or greater."), type);
1152       return false;
1153     }
1154   else if (format->d > format->w - 1)
1155     {
1156       msg (SE, _("Output format %s requires width greater than decimals."),
1157            type);
1158       return false;
1159     }
1160   else
1161     {
1162       *is_ctables_format = true;
1163       return true;
1164     }
1165 }
1166
1167 static struct ctables_axis *
1168 ctables_axis_parse_postfix (struct ctables_axis_parse_ctx *ctx)
1169 {
1170   struct ctables_axis *sub = ctables_axis_parse_primary (ctx);
1171   if (!sub || !lex_match (ctx->lexer, T_LBRACK))
1172     return sub;
1173
1174   enum ctables_summary_variant sv = CSV_CELL;
1175   for (;;)
1176     {
1177       int start_ofs = lex_ofs (ctx->lexer);
1178
1179       /* Parse function. */
1180       enum ctables_summary_function function;
1181       if (!parse_ctables_summary_function (ctx->lexer, &function))
1182         goto error;
1183
1184       /* Parse percentile. */
1185       double percentile = 0;
1186       if (function == CTSF_PTILE)
1187         {
1188           if (!lex_force_num_range_closed (ctx->lexer, "PTILE", 0, 100))
1189             goto error;
1190           percentile = lex_number (ctx->lexer);
1191           lex_get (ctx->lexer);
1192         }
1193
1194       /* Parse label. */
1195       char *label;
1196       if (lex_is_string (ctx->lexer))
1197         {
1198           label = ss_xstrdup (lex_tokss (ctx->lexer));
1199           lex_get (ctx->lexer);
1200         }
1201       else
1202         label = ctables_summary_default_label (function, percentile);
1203
1204       /* Parse format. */
1205       struct fmt_spec format;
1206       const struct fmt_spec *formatp;
1207       bool is_ctables_format = false;
1208       if (lex_token (ctx->lexer) == T_ID
1209           && has_digit (lex_tokcstr (ctx->lexer)))
1210         {
1211           if (!parse_ctables_format_specifier (ctx->lexer, &format,
1212                                                &is_ctables_format))
1213             {
1214               free (label);
1215               goto error;
1216             }
1217           formatp = &format;
1218         }
1219       else
1220         formatp = NULL;
1221
1222       struct msg_location *loc = lex_ofs_location (ctx->lexer, start_ofs,
1223                                                    lex_ofs (ctx->lexer) - 1);
1224       add_summary_spec (sub, function, percentile, label, formatp,
1225                         is_ctables_format, loc, sv);
1226       free (label);
1227       msg_location_destroy (loc);
1228
1229       lex_match (ctx->lexer, T_COMMA);
1230       if (sv == CSV_CELL && lex_match_id (ctx->lexer, "TOTALS"))
1231         {
1232           if (!lex_force_match (ctx->lexer, T_LBRACK))
1233             goto error;
1234           sv = CSV_TOTAL;
1235         }
1236       else if (lex_match (ctx->lexer, T_RBRACK))
1237         {
1238           if (sv == CSV_TOTAL && !lex_force_match (ctx->lexer, T_RBRACK))
1239             goto error;
1240           return sub;
1241         }
1242     }
1243
1244 error:
1245   ctables_axis_destroy (sub);
1246   return NULL;
1247 }
1248
1249 static const struct ctables_axis *
1250 find_scale (const struct ctables_axis *axis)
1251 {
1252   if (!axis)
1253     return NULL;
1254   else if (axis->op == CTAO_VAR)
1255     {
1256       if (axis->scale)
1257         {
1258           assert (!axis->var.is_mrset);
1259           return axis;
1260         }
1261       else
1262         return NULL;
1263     }
1264   else
1265     {
1266       for (size_t i = 0; i < 2; i++)
1267         {
1268           const struct ctables_axis *scale = find_scale (axis->subs[i]);
1269           if (scale)
1270             return scale;
1271         }
1272       return NULL;
1273     }
1274 }
1275
1276 static const struct ctables_axis *
1277 find_categorical_summary_spec (const struct ctables_axis *axis)
1278 {
1279   if (!axis)
1280     return NULL;
1281   else if (axis->op == CTAO_VAR)
1282     return !axis->scale && axis->specs[CSV_CELL].n ? axis : NULL;
1283   else
1284     {
1285       for (size_t i = 0; i < 2; i++)
1286         {
1287           const struct ctables_axis *sum
1288             = find_categorical_summary_spec (axis->subs[i]);
1289           if (sum)
1290             return sum;
1291         }
1292       return NULL;
1293     }
1294 }
1295
1296 static struct ctables_axis *
1297 ctables_axis_parse_nest (struct ctables_axis_parse_ctx *ctx)
1298 {
1299   int start_ofs = lex_ofs (ctx->lexer);
1300   struct ctables_axis *lhs = ctables_axis_parse_postfix (ctx);
1301   if (!lhs)
1302     return NULL;
1303
1304   while (lex_match (ctx->lexer, T_GT))
1305     {
1306       struct ctables_axis *rhs = ctables_axis_parse_postfix (ctx);
1307       if (!rhs)
1308         return NULL;
1309
1310       struct ctables_axis *nest = ctables_axis_new_nonterminal (
1311         CTAO_NEST, lhs, rhs, ctx->lexer, start_ofs);
1312
1313       const struct ctables_axis *outer_scale = find_scale (lhs);
1314       const struct ctables_axis *inner_scale = find_scale (rhs);
1315       if (outer_scale && inner_scale)
1316         {
1317           msg_at (SE, nest->loc, _("Cannot nest scale variables."));
1318           msg_at (SN, outer_scale->loc, _("This is an outer scale variable."));
1319           msg_at (SN, inner_scale->loc, _("This is an inner scale variable."));
1320           ctables_axis_destroy (nest);
1321           return NULL;
1322         }
1323
1324       const struct ctables_axis *outer_sum = find_categorical_summary_spec (lhs);
1325       if (outer_sum)
1326         {
1327           msg_at (SE, nest->loc,
1328                   _("Summaries may only be requested for categorical variables "
1329                     "at the innermost nesting level."));
1330           msg_at (SN, outer_sum->loc,
1331                   _("This outer categorical variable has a summary."));
1332           ctables_axis_destroy (nest);
1333           return NULL;
1334         }
1335
1336       lhs = nest;
1337     }
1338
1339   return lhs;
1340 }
1341
1342 static struct ctables_axis *
1343 ctables_axis_parse_stack (struct ctables_axis_parse_ctx *ctx)
1344 {
1345   int start_ofs = lex_ofs (ctx->lexer);
1346   struct ctables_axis *lhs = ctables_axis_parse_nest (ctx);
1347   if (!lhs)
1348     return NULL;
1349
1350   while (lex_match (ctx->lexer, T_PLUS))
1351     {
1352       struct ctables_axis *rhs = ctables_axis_parse_nest (ctx);
1353       if (!rhs)
1354         return NULL;
1355
1356       lhs = ctables_axis_new_nonterminal (CTAO_STACK, lhs, rhs,
1357                                           ctx->lexer, start_ofs);
1358     }
1359
1360   return lhs;
1361 }
1362
1363 static bool
1364 ctables_axis_parse (struct lexer *lexer, struct dictionary *dict,
1365                     struct ctables *ct, struct ctables_table *t,
1366                     enum pivot_axis_type a)
1367 {
1368   if (lex_token (lexer) == T_BY
1369       || lex_token (lexer) == T_SLASH
1370       || lex_token (lexer) == T_ENDCMD)
1371     return true;
1372
1373   struct ctables_axis_parse_ctx ctx = {
1374     .lexer = lexer,
1375     .dict = dict,
1376     .ct = ct,
1377     .t = t
1378   };
1379   t->axes[a] = ctables_axis_parse_stack (&ctx);
1380   return t->axes[a] != NULL;
1381 }
1382
1383 static void
1384 ctables_chisq_destroy (struct ctables_chisq *chisq)
1385 {
1386   free (chisq);
1387 }
1388
1389 static void
1390 ctables_pairwise_destroy (struct ctables_pairwise *pairwise)
1391 {
1392   free (pairwise);
1393 }
1394
1395 static void
1396 ctables_table_destroy (struct ctables_table *t)
1397 {
1398   if (!t)
1399     return;
1400
1401   for (size_t i = 0; i < t->n_categories; i++)
1402     ctables_categories_unref (t->categories[i]);
1403   free (t->categories);
1404
1405   ctables_axis_destroy (t->axes[PIVOT_AXIS_COLUMN]);
1406   ctables_axis_destroy (t->axes[PIVOT_AXIS_ROW]);
1407   ctables_axis_destroy (t->axes[PIVOT_AXIS_LAYER]);
1408   free (t->caption);
1409   free (t->corner);
1410   free (t->title);
1411   ctables_chisq_destroy (t->chisq);
1412   ctables_pairwise_destroy (t->pairwise);
1413   free (t);
1414 }
1415
1416 static void
1417 ctables_destroy (struct ctables *ct)
1418 {
1419   if (!ct)
1420     return;
1421
1422   pivot_table_look_unref (ct->look);
1423   free (ct->zero);
1424   free (ct->missing);
1425   free (ct->vlabels);
1426   for (size_t i = 0; i < ct->n_tables; i++)
1427     ctables_table_destroy (ct->tables[i]);
1428   free (ct->tables);
1429   free (ct);
1430 }
1431
1432 static struct ctables_category
1433 cct_range (double low, double high)
1434 {
1435   return (struct ctables_category) {
1436     .type = CCT_RANGE,
1437     .range = { low, high }
1438   };
1439 }
1440
1441 static bool
1442 ctables_table_parse_subtotal (struct lexer *lexer, bool hide_subcategories,
1443                               struct ctables_category *cat)
1444 {
1445   char *total_label;
1446   if (lex_match (lexer, T_EQUALS))
1447     {
1448       if (!lex_force_string (lexer))
1449         return false;
1450
1451       total_label = ss_xstrdup (lex_tokss (lexer));
1452       lex_get (lexer);
1453     }
1454   else
1455     total_label = xstrdup (_("Subtotal"));
1456
1457   *cat = (struct ctables_category) {
1458     .type = CCT_SUBTOTAL,
1459     .hide_subcategories = hide_subcategories,
1460     .total_label = total_label
1461   };
1462   return true;
1463 }
1464
1465 static bool
1466 ctables_table_parse_explicit_category (struct lexer *lexer, struct ctables *ct,
1467                                        struct ctables_category *cat)
1468 {
1469   if (lex_match_id (lexer, "OTHERNM"))
1470     *cat = (struct ctables_category) { .type = CCT_OTHERNM };
1471   else if (lex_match_id (lexer, "MISSING"))
1472     *cat = (struct ctables_category) { .type = CCT_MISSING };
1473   else if (lex_match_id (lexer, "SUBTOTAL"))
1474     return ctables_table_parse_subtotal (lexer, false, cat);
1475   else if (lex_match_id (lexer, "HSUBTOTAL"))
1476     return ctables_table_parse_subtotal (lexer, true, cat);
1477   else if (lex_match_id (lexer, "LO"))
1478     {
1479       if (!lex_force_match_id (lexer, "THRU") || lex_force_num (lexer))
1480         return false;
1481       *cat = cct_range (-DBL_MAX, lex_number (lexer));
1482       lex_get (lexer);
1483     }
1484   else if (lex_is_number (lexer))
1485     {
1486       double number = lex_number (lexer);
1487       lex_get (lexer);
1488       if (lex_match_id (lexer, "THRU"))
1489         {
1490           if (lex_match_id (lexer, "HI"))
1491             *cat = cct_range (number, DBL_MAX);
1492           else
1493             {
1494               if (!lex_force_num (lexer))
1495                 return false;
1496               *cat = cct_range (number, lex_number (lexer));
1497               lex_get (lexer);
1498             }
1499         }
1500       else
1501         *cat = (struct ctables_category) {
1502           .type = CCT_NUMBER,
1503           .number = number
1504         };
1505     }
1506   else if (lex_is_string (lexer))
1507     {
1508       *cat = (struct ctables_category) {
1509         .type = CCT_STRING,
1510         .string = ss_xstrdup (lex_tokss (lexer)),
1511       };
1512       lex_get (lexer);
1513     }
1514   else if (lex_match (lexer, T_AND))
1515     {
1516       if (!lex_force_id (lexer))
1517         return false;
1518       struct ctables_postcompute *pc = ctables_find_postcompute (
1519         ct, lex_tokcstr (lexer));
1520       if (!pc)
1521         {
1522           struct msg_location *loc = lex_get_location (lexer, -1, 0);
1523           msg_at (SE, loc, _("Unknown postcompute &%s."),
1524                   lex_tokcstr (lexer));
1525           msg_location_destroy (loc);
1526           return false;
1527         }
1528       lex_get (lexer);
1529
1530       *cat = (struct ctables_category) { .type = CCT_POSTCOMPUTE, .pc = pc };
1531     }
1532   else
1533     {
1534       lex_error (lexer, NULL);
1535       return false;
1536     }
1537
1538   return true;
1539 }
1540
1541 static struct ctables_category *
1542 ctables_find_category_for_postcompute (const struct ctables_categories *cats,
1543                                        const struct ctables_pcexpr *e)
1544 {
1545   struct ctables_category *best = NULL;
1546   size_t n_subtotals = 0;
1547   for (size_t i = 0; i < cats->n_cats; i++)
1548     {
1549       struct ctables_category *cat = &cats->cats[i];
1550       switch (e->op)
1551         {
1552         case CTPO_CAT_NUMBER:
1553           if (cat->type == CCT_NUMBER && cat->number == e->number)
1554             best = cat;
1555           break;
1556
1557         case CTPO_CAT_STRING:
1558           if (cat->type == CCT_STRING && !strcmp (cat->string, e->string))
1559             best = cat;
1560           break;
1561
1562         case CTPO_CAT_RANGE:
1563           if (cat->type == CCT_RANGE
1564               && cat->range[0] == e->range[0]
1565               && cat->range[1] == e->range[1])
1566             best = cat;
1567           break;
1568
1569         case CTPO_CAT_MISSING:
1570           if (cat->type == CCT_MISSING)
1571             best = cat;
1572           break;
1573
1574         case CTPO_CAT_OTHERNM:
1575           if (cat->type == CCT_OTHERNM)
1576             best = cat;
1577           break;
1578
1579         case CTPO_CAT_SUBTOTAL:
1580           if (cat->type == CCT_SUBTOTAL)
1581             {
1582               n_subtotals++;
1583               if (e->subtotal_index == n_subtotals)
1584                 return cat;
1585               else if (e->subtotal_index == 0)
1586                 best = cat;
1587             }
1588           break;
1589
1590         case CTPO_CAT_TOTAL:
1591           if (cat->type == CCT_TOTAL)
1592             return cat;
1593           break;
1594
1595         case CTPO_CONSTANT:
1596         case CTPO_ADD:
1597         case CTPO_SUB:
1598         case CTPO_MUL:
1599         case CTPO_DIV:
1600         case CTPO_POW:
1601         case CTPO_NEG:
1602           NOT_REACHED ();
1603         }
1604     }
1605   if (e->op == CTPO_CAT_SUBTOTAL && e->subtotal_index == 0 && n_subtotals > 1)
1606     return NULL;
1607   return best;
1608 }
1609
1610 static bool
1611 ctables_recursive_check_postcompute (const struct ctables_pcexpr *e,
1612                                      struct ctables_category *pc_cat,
1613                                      const struct ctables_categories *cats,
1614                                      const struct msg_location *cats_location)
1615 {
1616   switch (e->op)
1617     {
1618     case CTPO_CAT_NUMBER:
1619     case CTPO_CAT_STRING:
1620     case CTPO_CAT_RANGE:
1621     case CTPO_CAT_MISSING:
1622     case CTPO_CAT_OTHERNM:
1623     case CTPO_CAT_SUBTOTAL:
1624     case CTPO_CAT_TOTAL:
1625       {
1626         struct ctables_category *cat = ctables_find_category_for_postcompute (
1627           cats, e);
1628         if (!cat)
1629           {
1630             if (e->op == CTPO_CAT_SUBTOTAL && e->subtotal_index == 0)
1631               {
1632                 size_t n_subtotals = 0;
1633                 for (size_t i = 0; i < cats->n_cats; i++)
1634                   n_subtotals += cats->cats[i].type == CCT_SUBTOTAL;
1635                 if (n_subtotals > 1)
1636                   {
1637                     msg_at (SE, cats_location,
1638                             ngettext ("These categories include %zu instance "
1639                                       "of SUBTOTAL or HSUBTOTAL, so references "
1640                                       "from computed categories must refer to "
1641                                       "subtotals by position.",
1642                                       "These categories include %zu instances "
1643                                       "of SUBTOTAL or HSUBTOTAL, so references "
1644                                       "from computed categories must refer to "
1645                                       "subtotals by position.",
1646                                       n_subtotals),
1647                             n_subtotals);
1648                     msg_at (SN, e->location,
1649                             _("This is the reference that lacks a position."));
1650                     return NULL;
1651                   }
1652               }
1653
1654             msg_at (SE, pc_cat->location,
1655                     _("Computed category &%s references a category not included "
1656                       "in the category list."),
1657                     pc_cat->pc->name);
1658             msg_at (SN, e->location, _("This is the missing category."));
1659             msg_at (SN, cats_location,
1660                     _("To fix the problem, add the missing category to the "
1661                       "list of categories here."));
1662             return false;
1663           }
1664         if (pc_cat->pc->hide_source_cats)
1665           cat->hide = true;
1666         return true;
1667       }
1668
1669     case CTPO_CONSTANT:
1670       return true;
1671
1672     case CTPO_ADD:
1673     case CTPO_SUB:
1674     case CTPO_MUL:
1675     case CTPO_DIV:
1676     case CTPO_POW:
1677     case CTPO_NEG:
1678       for (size_t i = 0; i < 2; i++)
1679         if (e->subs[i] && !ctables_recursive_check_postcompute (
1680               e->subs[i], pc_cat, cats, cats_location))
1681           return false;
1682       return true;
1683
1684     default:
1685       NOT_REACHED ();
1686     }
1687 }
1688
1689 static bool
1690 ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
1691                                 struct ctables *ct, struct ctables_table *t)
1692 {
1693   if (!lex_match_id (lexer, "VARIABLES"))
1694     return false;
1695   lex_match (lexer, T_EQUALS);
1696
1697   struct variable **vars;
1698   size_t n_vars;
1699   if (!parse_variables (lexer, dict, &vars, &n_vars, PV_NO_SCRATCH))
1700     return false;
1701
1702   struct ctables_categories *c = xmalloc (sizeof *c);
1703   *c = (struct ctables_categories) { .n_refs = n_vars, .show_empty = true };
1704   for (size_t i = 0; i < n_vars; i++)
1705     {
1706       struct ctables_categories **cp
1707         = &t->categories[var_get_dict_index (vars[i])];
1708       ctables_categories_unref (*cp);
1709       *cp = c;
1710     }
1711   free (vars);
1712
1713   size_t allocated_cats = 0;
1714   if (lex_match (lexer, T_LBRACK))
1715     {
1716       int cats_start_ofs = lex_ofs (lexer);
1717       do
1718         {
1719           if (c->n_cats >= allocated_cats)
1720             c->cats = x2nrealloc (c->cats, &allocated_cats, sizeof *c->cats);
1721
1722           int start_ofs = lex_ofs (lexer);
1723           struct ctables_category *cat = &c->cats[c->n_cats];
1724           if (!ctables_table_parse_explicit_category (lexer, ct, cat))
1725             return false;
1726           cat->location = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer) - 1);
1727           c->n_cats++;
1728
1729           lex_match (lexer, T_COMMA);
1730         }
1731       while (!lex_match (lexer, T_RBRACK));
1732
1733       struct msg_location *cats_location
1734         = lex_ofs_location (lexer, cats_start_ofs, lex_ofs (lexer) - 1);
1735       for (size_t i = 0; i < c->n_cats; i++)
1736         {
1737           struct ctables_category *cat = &c->cats[i];
1738           if (cat->type == CCT_POSTCOMPUTE
1739               && !ctables_recursive_check_postcompute (cat->pc->expr, cat,
1740                                                        c, cats_location))
1741             return false;
1742         }
1743     }
1744
1745   struct ctables_category cat = {
1746     .type = CCT_VALUE,
1747     .include_missing = false,
1748     .sort_ascending = true,
1749   };
1750   bool show_totals = false;
1751   char *total_label = NULL;
1752   bool totals_before = false;
1753   while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
1754     {
1755       if (!c->n_cats && lex_match_id (lexer, "ORDER"))
1756         {
1757           lex_match (lexer, T_EQUALS);
1758           if (lex_match_id (lexer, "A"))
1759             cat.sort_ascending = true;
1760           else if (lex_match_id (lexer, "D"))
1761             cat.sort_ascending = false;
1762           else
1763             {
1764               lex_error_expecting (lexer, "A", "D");
1765               return false;
1766             }
1767         }
1768       else if (!c->n_cats && lex_match_id (lexer, "KEY"))
1769         {
1770           lex_match (lexer, T_EQUALS);
1771           if (lex_match_id (lexer, "VALUE"))
1772             cat.type = CCT_VALUE;
1773           else if (lex_match_id (lexer, "LABEL"))
1774             cat.type = CCT_LABEL;
1775           else
1776             {
1777               cat.type = CCT_FUNCTION;
1778               if (!parse_ctables_summary_function (lexer, &cat.sort_function))
1779                 return false;
1780
1781               if (lex_match (lexer, T_LPAREN))
1782                 {
1783                   cat.sort_var = parse_variable (lexer, dict);
1784                   if (!cat.sort_var)
1785                     return false;
1786
1787                   if (cat.sort_function == CTSF_PTILE)
1788                     {
1789                       lex_match (lexer, T_COMMA);
1790                       if (!lex_force_num_range_closed (lexer, "PTILE", 0, 100))
1791                         return false;
1792                       cat.percentile = lex_number (lexer);
1793                       lex_get (lexer);
1794                     }
1795
1796                   if (!lex_force_match (lexer, T_RPAREN))
1797                     return false;
1798                 }
1799               else if (ctables_function_availability (cat.sort_function)
1800                        == CTFA_SCALE)
1801                 {
1802                   bool UNUSED b = lex_force_match (lexer, T_LPAREN);
1803                   return false;
1804                 }
1805             }
1806         }
1807       else if (!c->n_cats && lex_match_id (lexer, "MISSING"))
1808         {
1809           lex_match (lexer, T_EQUALS);
1810           if (lex_match_id (lexer, "INCLUDE"))
1811             cat.include_missing = true;
1812           else if (lex_match_id (lexer, "EXCLUDE"))
1813             cat.include_missing = false;
1814           else
1815             {
1816               lex_error_expecting (lexer, "INCLUDE", "EXCLUDE");
1817               return false;
1818             }
1819         }
1820       else if (lex_match_id (lexer, "TOTAL"))
1821         {
1822           lex_match (lexer, T_EQUALS);
1823           if (!parse_bool (lexer, &show_totals))
1824             return false;
1825         }
1826       else if (lex_match_id (lexer, "LABEL"))
1827         {
1828           lex_match (lexer, T_EQUALS);
1829           if (!lex_force_string (lexer))
1830             return false;
1831           free (total_label);
1832           total_label = ss_xstrdup (lex_tokss (lexer));
1833           lex_get (lexer);
1834         }
1835       else if (lex_match_id (lexer, "POSITION"))
1836         {
1837           lex_match (lexer, T_EQUALS);
1838           if (lex_match_id (lexer, "BEFORE"))
1839             totals_before = true;
1840           else if (lex_match_id (lexer, "AFTER"))
1841             totals_before = false;
1842           else
1843             {
1844               lex_error_expecting (lexer, "BEFORE", "AFTER");
1845               return false;
1846             }
1847         }
1848       else if (lex_match_id (lexer, "EMPTY"))
1849         {
1850           lex_match (lexer, T_EQUALS);
1851           if (lex_match_id (lexer, "INCLUDE"))
1852             c->show_empty = true;
1853           else if (lex_match_id (lexer, "EXCLUDE"))
1854             c->show_empty = false;
1855           else
1856             {
1857               lex_error_expecting (lexer, "INCLUDE", "EXCLUDE");
1858               return false;
1859             }
1860         }
1861       else
1862         {
1863           if (!c->n_cats)
1864             lex_error_expecting (lexer, "ORDER", "KEY", "MISSING",
1865                                  "TOTAL", "LABEL", "POSITION", "EMPTY");
1866           else
1867             lex_error_expecting (lexer, "TOTAL", "LABEL", "POSITION", "EMPTY");
1868           return false;
1869         }
1870     }
1871
1872   if (!c->n_cats)
1873     {
1874       if (c->n_cats >= allocated_cats)
1875         c->cats = x2nrealloc (c->cats, &allocated_cats, sizeof *c->cats);
1876       c->cats[c->n_cats++] = cat;
1877     }
1878
1879   if (show_totals)
1880     {
1881       if (c->n_cats >= allocated_cats)
1882         c->cats = x2nrealloc (c->cats, &allocated_cats, sizeof *c->cats);
1883
1884       struct ctables_category *totals;
1885       if (totals_before)
1886         {
1887           insert_element (c->cats, c->n_cats, sizeof *c->cats, 0);
1888           totals = &c->cats[0];
1889         }
1890       else
1891         totals = &c->cats[c->n_cats];
1892       c->n_cats++;
1893
1894       *totals = (struct ctables_category) {
1895         .type = CCT_TOTAL,
1896         .total_label = total_label ? total_label : xstrdup (_("Total")),
1897       };
1898     }
1899
1900   struct ctables_category *subtotal = NULL;
1901   for (size_t i = totals_before ? 0 : c->n_cats;
1902        totals_before ? i < c->n_cats : i-- > 0;
1903        totals_before ? i++ : 0)
1904     {
1905       struct ctables_category *cat = &c->cats[i];
1906       switch (cat->type)
1907         {
1908         case CCT_NUMBER:
1909         case CCT_STRING:
1910         case CCT_RANGE:
1911         case CCT_MISSING:
1912         case CCT_OTHERNM:
1913           cat->subtotal = subtotal;
1914           break;
1915
1916         case CCT_POSTCOMPUTE:
1917           break;
1918
1919         case CCT_SUBTOTAL:
1920           subtotal = cat;
1921           break;
1922
1923         case CCT_TOTAL:
1924         case CCT_VALUE:
1925         case CCT_LABEL:
1926         case CCT_FUNCTION:
1927           break;
1928         }
1929     }
1930
1931   return true;
1932 }
1933
1934 static void
1935 ctables_nest_uninit (struct ctables_nest *nest)
1936 {
1937   if (nest)
1938     free (nest->vars);
1939 }
1940
1941 static void
1942 ctables_stack_uninit (struct ctables_stack *stack)
1943 {
1944   if (stack)
1945     {
1946       for (size_t i = 0; i < stack->n; i++)
1947         ctables_nest_uninit (&stack->nests[i]);
1948       free (stack->nests);
1949     }
1950 }
1951
1952 static struct ctables_stack
1953 nest_fts (struct ctables_stack s0, struct ctables_stack s1)
1954 {
1955   if (!s0.n)
1956     return s1;
1957   else if (!s1.n)
1958     return s0;
1959
1960   struct ctables_stack stack = { .nests = xnmalloc (s0.n, s1.n * sizeof *stack.nests) };
1961   for (size_t i = 0; i < s0.n; i++)
1962     for (size_t j = 0; j < s1.n; j++)
1963       {
1964         const struct ctables_nest *a = &s0.nests[i];
1965         const struct ctables_nest *b = &s1.nests[j];
1966
1967         size_t allocate = a->n + b->n;
1968         struct variable **vars = xnmalloc (allocate, sizeof *vars);
1969         enum pivot_axis_type *axes = xnmalloc (allocate, sizeof *axes);
1970         size_t n = 0;
1971         for (size_t k = 0; k < a->n; k++)
1972           vars[n++] = a->vars[k];
1973         for (size_t k = 0; k < b->n; k++)
1974           vars[n++] = b->vars[k];
1975         assert (n == allocate);
1976
1977         const struct ctables_nest *summary_src;
1978         if (!a->specs[CSV_CELL].var)
1979           summary_src = b;
1980         else if (!b->specs[CSV_CELL].var)
1981           summary_src = a;
1982         else
1983           NOT_REACHED ();
1984
1985         struct ctables_nest *new = &stack.nests[stack.n++];
1986         *new = (struct ctables_nest) {
1987           .vars = vars,
1988           .scale_idx = (a->scale_idx != SIZE_MAX ? a->scale_idx
1989                         : b->scale_idx != SIZE_MAX ? a->n + b->scale_idx
1990                         : SIZE_MAX),
1991           .n = n,
1992         };
1993         for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
1994           ctables_summary_spec_set_clone (&new->specs[sv], &summary_src->specs[sv]);
1995       }
1996   ctables_stack_uninit (&s0);
1997   ctables_stack_uninit (&s1);
1998   return stack;
1999 }
2000
2001 static struct ctables_stack
2002 stack_fts (struct ctables_stack s0, struct ctables_stack s1)
2003 {
2004   struct ctables_stack stack = { .nests = xnmalloc (s0.n + s1.n, sizeof *stack.nests) };
2005   for (size_t i = 0; i < s0.n; i++)
2006     stack.nests[stack.n++] = s0.nests[i];
2007   for (size_t i = 0; i < s1.n; i++)
2008     stack.nests[stack.n++] = s1.nests[i];
2009   assert (stack.n == s0.n + s1.n);
2010   free (s0.nests);
2011   free (s1.nests);
2012   return stack;
2013 }
2014
2015 static struct ctables_stack
2016 enumerate_fts (enum pivot_axis_type axis_type, const struct ctables_axis *a)
2017 {
2018   if (!a)
2019     return (struct ctables_stack) { .n = 0 };
2020
2021   switch (a->op)
2022     {
2023     case CTAO_VAR:
2024       assert (!a->var.is_mrset);
2025
2026       struct variable **vars = xmalloc (sizeof *vars);
2027       *vars = a->var.var;
2028
2029       struct ctables_nest *nest = xmalloc (sizeof *nest);
2030       *nest = (struct ctables_nest) {
2031         .vars = vars,
2032         .n = 1,
2033         .scale_idx = a->scale ? 0 : SIZE_MAX,
2034       };
2035       if (a->specs[CSV_CELL].n || a->scale)
2036         for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
2037           {
2038             ctables_summary_spec_set_clone (&nest->specs[sv], &a->specs[sv]);
2039             nest->specs[sv].var = a->var.var;
2040           }
2041       return (struct ctables_stack) { .nests = nest, .n = 1 };
2042
2043     case CTAO_STACK:
2044       return stack_fts (enumerate_fts (axis_type, a->subs[0]),
2045                         enumerate_fts (axis_type, a->subs[1]));
2046
2047     case CTAO_NEST:
2048       return nest_fts (enumerate_fts (axis_type, a->subs[0]),
2049                        enumerate_fts (axis_type, a->subs[1]));
2050     }
2051
2052   NOT_REACHED ();
2053 }
2054
2055 union ctables_summary
2056   {
2057     /* COUNT, VALIDN, TOTALN. */
2058     struct
2059       {
2060         double valid;
2061         double missing;
2062       };
2063
2064     /* MINIMUM, MAXIMUM, RANGE. */
2065     struct
2066       {
2067         double min;
2068         double max;
2069       };
2070
2071     /* MEAN, SEMEAN, STDDEV, SUM, VARIANCE, *.SUM. */
2072     struct moments1 *moments;
2073
2074     /* MEDIAN, MODE, PTILE. */
2075     struct
2076       {
2077         struct casewriter *writer;
2078         double ovalid;
2079         double ovalue;
2080       };
2081
2082     /* XXX multiple response */
2083   };
2084
2085 static void
2086 ctables_summary_init (union ctables_summary *s,
2087                       const struct ctables_summary_spec *ss)
2088 {
2089   switch (ss->function)
2090     {
2091     case CTSF_COUNT:
2092     case CTSF_ECOUNT:
2093     case CTSF_ROWPCT_COUNT:
2094     case CTSF_COLPCT_COUNT:
2095     case CTSF_TABLEPCT_COUNT:
2096     case CTSF_SUBTABLEPCT_COUNT:
2097     case CTSF_LAYERPCT_COUNT:
2098     case CTSF_LAYERROWPCT_COUNT:
2099     case CTSF_LAYERCOLPCT_COUNT:
2100     case CTSF_ROWPCT_VALIDN:
2101     case CTSF_COLPCT_VALIDN:
2102     case CTSF_TABLEPCT_VALIDN:
2103     case CTSF_SUBTABLEPCT_VALIDN:
2104     case CTSF_LAYERPCT_VALIDN:
2105     case CTSF_LAYERROWPCT_VALIDN:
2106     case CTSF_LAYERCOLPCT_VALIDN:
2107     case CTSF_ROWPCT_TOTALN:
2108     case CTSF_COLPCT_TOTALN:
2109     case CTSF_TABLEPCT_TOTALN:
2110     case CTSF_SUBTABLEPCT_TOTALN:
2111     case CTSF_LAYERPCT_TOTALN:
2112     case CTSF_LAYERROWPCT_TOTALN:
2113     case CTSF_LAYERCOLPCT_TOTALN:
2114     case CTSF_MISSING:
2115     case CSTF_TOTALN:
2116     case CTSF_ETOTALN:
2117     case CTSF_VALIDN:
2118     case CTSF_EVALIDN:
2119       s->missing = s->valid = 0;
2120       break;
2121
2122     case CTSF_MAXIMUM:
2123     case CTSF_MINIMUM:
2124     case CTSF_RANGE:
2125       s->min = s->max = SYSMIS;
2126       break;
2127
2128     case CTSF_MEAN:
2129     case CTSF_SEMEAN:
2130     case CTSF_STDDEV:
2131     case CTSF_SUM:
2132     case CTSF_VARIANCE:
2133     case CTSF_ROWPCT_SUM:
2134     case CTSF_COLPCT_SUM:
2135     case CTSF_TABLEPCT_SUM:
2136     case CTSF_SUBTABLEPCT_SUM:
2137     case CTSF_LAYERPCT_SUM:
2138     case CTSF_LAYERROWPCT_SUM:
2139     case CTSF_LAYERCOLPCT_SUM:
2140       s->moments = moments1_create (MOMENT_VARIANCE);
2141       break;
2142
2143     case CTSF_MEDIAN:
2144     case CTSF_MODE:
2145     case CTSF_PTILE:
2146       {
2147         struct caseproto *proto = caseproto_create ();
2148         proto = caseproto_add_width (proto, 0);
2149         proto = caseproto_add_width (proto, 0);
2150
2151         struct subcase ordering;
2152         subcase_init (&ordering, 0, 0, SC_ASCEND);
2153         s->writer = sort_create_writer (&ordering, proto);
2154         subcase_uninit (&ordering);
2155         caseproto_unref (proto);
2156
2157         s->ovalid = 0;
2158         s->ovalue = SYSMIS;
2159       }
2160       break;
2161     }
2162 }
2163
2164 static void UNUSED
2165 ctables_summary_uninit (union ctables_summary *s,
2166                         const struct ctables_summary_spec *ss)
2167 {
2168   switch (ss->function)
2169     {
2170     case CTSF_COUNT:
2171     case CTSF_ECOUNT:
2172     case CTSF_ROWPCT_COUNT:
2173     case CTSF_COLPCT_COUNT:
2174     case CTSF_TABLEPCT_COUNT:
2175     case CTSF_SUBTABLEPCT_COUNT:
2176     case CTSF_LAYERPCT_COUNT:
2177     case CTSF_LAYERROWPCT_COUNT:
2178     case CTSF_LAYERCOLPCT_COUNT:
2179     case CTSF_ROWPCT_VALIDN:
2180     case CTSF_COLPCT_VALIDN:
2181     case CTSF_TABLEPCT_VALIDN:
2182     case CTSF_SUBTABLEPCT_VALIDN:
2183     case CTSF_LAYERPCT_VALIDN:
2184     case CTSF_LAYERROWPCT_VALIDN:
2185     case CTSF_LAYERCOLPCT_VALIDN:
2186     case CTSF_ROWPCT_TOTALN:
2187     case CTSF_COLPCT_TOTALN:
2188     case CTSF_TABLEPCT_TOTALN:
2189     case CTSF_SUBTABLEPCT_TOTALN:
2190     case CTSF_LAYERPCT_TOTALN:
2191     case CTSF_LAYERROWPCT_TOTALN:
2192     case CTSF_LAYERCOLPCT_TOTALN:
2193     case CTSF_MISSING:
2194     case CSTF_TOTALN:
2195     case CTSF_ETOTALN:
2196     case CTSF_VALIDN:
2197     case CTSF_EVALIDN:
2198       break;
2199
2200     case CTSF_MAXIMUM:
2201     case CTSF_MINIMUM:
2202     case CTSF_RANGE:
2203       break;
2204
2205     case CTSF_MEAN:
2206     case CTSF_SEMEAN:
2207     case CTSF_STDDEV:
2208     case CTSF_SUM:
2209     case CTSF_VARIANCE:
2210     case CTSF_ROWPCT_SUM:
2211     case CTSF_COLPCT_SUM:
2212     case CTSF_TABLEPCT_SUM:
2213     case CTSF_SUBTABLEPCT_SUM:
2214     case CTSF_LAYERPCT_SUM:
2215     case CTSF_LAYERROWPCT_SUM:
2216     case CTSF_LAYERCOLPCT_SUM:
2217       moments1_destroy (s->moments);
2218       break;
2219
2220     case CTSF_MEDIAN:
2221     case CTSF_MODE:
2222     case CTSF_PTILE:
2223       casewriter_destroy (s->writer);
2224       break;
2225     }
2226 }
2227
2228 static void
2229 ctables_summary_add (union ctables_summary *s,
2230                      const struct ctables_summary_spec *ss,
2231                      const struct variable *var, const union value *value,
2232                      double d_weight, double e_weight)
2233 {
2234   /* To determine whether a case is included in a given table for a particular
2235      kind of summary, consider the following charts for each variable in the
2236      table.  Only if "yes" appears for every variable for the summary is the
2237      case counted.
2238
2239      Categorical variables:                    VALIDN   COUNT   TOTALN
2240        Valid values in included categories       yes     yes      yes
2241        Missing values in included categories     ---     yes      yes
2242        Missing values in excluded categories     ---     ---      yes
2243        Valid values in excluded categories       ---     ---      ---
2244
2245      Scale variables:                          VALIDN   COUNT   TOTALN
2246        Valid value                               yes     yes      yes
2247        Missing value                             ---     yes      yes
2248
2249      Missing values include both user- and system-missing.  (The system-missing
2250      value is always in an excluded category.)
2251   */
2252   switch (ss->function)
2253     {
2254     case CTSF_COUNT:
2255     case CSTF_TOTALN:
2256     case CTSF_VALIDN:
2257       if (var_is_value_missing (var, value))
2258         s->missing += d_weight;
2259       else
2260         s->valid += d_weight;
2261       break;
2262
2263     case CTSF_ECOUNT:
2264     case CTSF_ROWPCT_COUNT:
2265     case CTSF_COLPCT_COUNT:
2266     case CTSF_TABLEPCT_COUNT:
2267     case CTSF_SUBTABLEPCT_COUNT:
2268     case CTSF_LAYERPCT_COUNT:
2269     case CTSF_LAYERROWPCT_COUNT:
2270     case CTSF_LAYERCOLPCT_COUNT:
2271     case CTSF_ROWPCT_VALIDN:
2272     case CTSF_COLPCT_VALIDN:
2273     case CTSF_TABLEPCT_VALIDN:
2274     case CTSF_SUBTABLEPCT_VALIDN:
2275     case CTSF_LAYERPCT_VALIDN:
2276     case CTSF_LAYERROWPCT_VALIDN:
2277     case CTSF_LAYERCOLPCT_VALIDN:
2278     case CTSF_ROWPCT_TOTALN:
2279     case CTSF_COLPCT_TOTALN:
2280     case CTSF_TABLEPCT_TOTALN:
2281     case CTSF_SUBTABLEPCT_TOTALN:
2282     case CTSF_LAYERPCT_TOTALN:
2283     case CTSF_LAYERROWPCT_TOTALN:
2284     case CTSF_LAYERCOLPCT_TOTALN:
2285     case CTSF_MISSING:
2286     case CTSF_ETOTALN:
2287     case CTSF_EVALIDN:
2288       if (var_is_value_missing (var, value))
2289         s->missing += e_weight;
2290       else
2291         s->valid += e_weight;
2292       break;
2293
2294     case CTSF_MAXIMUM:
2295     case CTSF_MINIMUM:
2296     case CTSF_RANGE:
2297       if (!var_is_value_missing (var, value))
2298         {
2299           assert (!var_is_alpha (var)); /* XXX? */
2300           if (s->min == SYSMIS || value->f < s->min)
2301             s->min = value->f;
2302           if (s->max == SYSMIS || value->f > s->max)
2303             s->max = value->f;
2304         }
2305       break;
2306
2307     case CTSF_MEAN:
2308     case CTSF_SEMEAN:
2309     case CTSF_STDDEV:
2310     case CTSF_SUM:
2311     case CTSF_VARIANCE:
2312     case CTSF_ROWPCT_SUM:
2313     case CTSF_COLPCT_SUM:
2314     case CTSF_TABLEPCT_SUM:
2315     case CTSF_SUBTABLEPCT_SUM:
2316     case CTSF_LAYERPCT_SUM:
2317     case CTSF_LAYERROWPCT_SUM:
2318     case CTSF_LAYERCOLPCT_SUM:
2319       if (!var_is_value_missing (var, value))
2320         moments1_add (s->moments, value->f, e_weight);
2321       break;
2322
2323     case CTSF_MEDIAN:
2324     case CTSF_MODE:
2325     case CTSF_PTILE:
2326       if (var_is_value_missing (var, value))
2327         {
2328           s->ovalid += e_weight;
2329
2330           struct ccase *c = case_create (casewriter_get_proto (s->writer));
2331           *case_num_rw_idx (c, 0) = value->f;
2332           *case_num_rw_idx (c, 1) = e_weight;
2333           casewriter_write (s->writer, c);
2334         }
2335       break;
2336     }
2337 }
2338
2339 static enum ctables_domain_type
2340 ctables_function_domain (enum ctables_summary_function function)
2341 {
2342   switch (function)
2343     {
2344     case CTSF_COUNT:
2345     case CTSF_ECOUNT:
2346     case CTSF_MISSING:
2347     case CSTF_TOTALN:
2348     case CTSF_ETOTALN:
2349     case CTSF_VALIDN:
2350     case CTSF_EVALIDN:
2351     case CTSF_MAXIMUM:
2352     case CTSF_MINIMUM:
2353     case CTSF_RANGE:
2354     case CTSF_MEAN:
2355     case CTSF_SEMEAN:
2356     case CTSF_STDDEV:
2357     case CTSF_SUM:
2358     case CTSF_VARIANCE:
2359     case CTSF_MEDIAN:
2360     case CTSF_PTILE:
2361     case CTSF_MODE:
2362       NOT_REACHED ();
2363
2364     case CTSF_COLPCT_COUNT:
2365     case CTSF_COLPCT_SUM:
2366     case CTSF_COLPCT_TOTALN:
2367     case CTSF_COLPCT_VALIDN:
2368       return CTDT_COL;
2369
2370     case CTSF_LAYERCOLPCT_COUNT:
2371     case CTSF_LAYERCOLPCT_SUM:
2372     case CTSF_LAYERCOLPCT_TOTALN:
2373     case CTSF_LAYERCOLPCT_VALIDN:
2374       return CTDT_LAYERCOL;
2375
2376     case CTSF_LAYERPCT_COUNT:
2377     case CTSF_LAYERPCT_SUM:
2378     case CTSF_LAYERPCT_TOTALN:
2379     case CTSF_LAYERPCT_VALIDN:
2380       return CTDT_LAYER;
2381
2382     case CTSF_LAYERROWPCT_COUNT:
2383     case CTSF_LAYERROWPCT_SUM:
2384     case CTSF_LAYERROWPCT_TOTALN:
2385     case CTSF_LAYERROWPCT_VALIDN:
2386       return CTDT_LAYERROW;
2387
2388     case CTSF_ROWPCT_COUNT:
2389     case CTSF_ROWPCT_SUM:
2390     case CTSF_ROWPCT_TOTALN:
2391     case CTSF_ROWPCT_VALIDN:
2392       return CTDT_ROW;
2393
2394     case CTSF_SUBTABLEPCT_COUNT:
2395     case CTSF_SUBTABLEPCT_SUM:
2396     case CTSF_SUBTABLEPCT_TOTALN:
2397     case CTSF_SUBTABLEPCT_VALIDN:
2398       return CTDT_SUBTABLE;
2399
2400     case CTSF_TABLEPCT_COUNT:
2401     case CTSF_TABLEPCT_SUM:
2402     case CTSF_TABLEPCT_TOTALN:
2403     case CTSF_TABLEPCT_VALIDN:
2404       return CTDT_TABLE;
2405     }
2406
2407   NOT_REACHED ();
2408 }
2409
2410 static double
2411 ctables_summary_value (const struct ctables_cell *cell,
2412                        union ctables_summary *s,
2413                        const struct ctables_summary_spec *ss)
2414 {
2415   switch (ss->function)
2416     {
2417     case CTSF_COUNT:
2418     case CTSF_ECOUNT:
2419       return s->valid;
2420
2421     case CTSF_ROWPCT_COUNT:
2422     case CTSF_COLPCT_COUNT:
2423     case CTSF_TABLEPCT_COUNT:
2424     case CTSF_SUBTABLEPCT_COUNT:
2425     case CTSF_LAYERPCT_COUNT:
2426     case CTSF_LAYERROWPCT_COUNT:
2427     case CTSF_LAYERCOLPCT_COUNT:
2428       {
2429         enum ctables_domain_type d = ctables_function_domain (ss->function);
2430         return (cell->domains[d]->e_valid
2431                 ? s->valid / cell->domains[d]->e_valid * 100
2432                 : SYSMIS);
2433       }
2434
2435     case CTSF_ROWPCT_VALIDN:
2436     case CTSF_COLPCT_VALIDN:
2437     case CTSF_TABLEPCT_VALIDN:
2438     case CTSF_SUBTABLEPCT_VALIDN:
2439     case CTSF_LAYERPCT_VALIDN:
2440     case CTSF_LAYERROWPCT_VALIDN:
2441     case CTSF_LAYERCOLPCT_VALIDN:
2442     case CTSF_ROWPCT_TOTALN:
2443     case CTSF_COLPCT_TOTALN:
2444     case CTSF_TABLEPCT_TOTALN:
2445     case CTSF_SUBTABLEPCT_TOTALN:
2446     case CTSF_LAYERPCT_TOTALN:
2447     case CTSF_LAYERROWPCT_TOTALN:
2448     case CTSF_LAYERCOLPCT_TOTALN:
2449       NOT_REACHED ();
2450
2451     case CTSF_MISSING:
2452       return s->missing;
2453
2454     case CSTF_TOTALN:
2455     case CTSF_ETOTALN:
2456       return s->valid + s->missing;
2457
2458     case CTSF_VALIDN:
2459     case CTSF_EVALIDN:
2460       return s->valid;
2461
2462     case CTSF_MAXIMUM:
2463       return s->max;
2464
2465     case CTSF_MINIMUM:
2466       return s->min;
2467
2468     case CTSF_RANGE:
2469       return s->max != SYSMIS && s->min != SYSMIS ? s->max - s->min : SYSMIS;
2470
2471     case CTSF_MEAN:
2472       {
2473         double mean;
2474         moments1_calculate (s->moments, NULL, &mean, NULL, NULL, NULL);
2475         return mean;
2476       }
2477
2478     case CTSF_SEMEAN:
2479       {
2480         double weight, variance;
2481         moments1_calculate (s->moments, &weight, NULL, &variance, NULL, NULL);
2482         return calc_semean (variance, weight);
2483       }
2484
2485     case CTSF_STDDEV:
2486       {
2487         double variance;
2488         moments1_calculate (s->moments, NULL, NULL, &variance, NULL, NULL);
2489         return variance != SYSMIS ? sqrt (variance) : SYSMIS;
2490       }
2491
2492     case CTSF_SUM:
2493       {
2494         double weight, mean;
2495         moments1_calculate (s->moments, &weight, &mean, NULL, NULL, NULL);
2496         return weight != SYSMIS && mean != SYSMIS ? weight * mean : SYSMIS;
2497       }
2498
2499     case CTSF_VARIANCE:
2500       {
2501         double variance;
2502         moments1_calculate (s->moments, NULL, NULL, &variance, NULL, NULL);
2503         return variance;
2504       }
2505
2506     case CTSF_ROWPCT_SUM:
2507     case CTSF_COLPCT_SUM:
2508     case CTSF_TABLEPCT_SUM:
2509     case CTSF_SUBTABLEPCT_SUM:
2510     case CTSF_LAYERPCT_SUM:
2511     case CTSF_LAYERROWPCT_SUM:
2512     case CTSF_LAYERCOLPCT_SUM:
2513       NOT_REACHED ();
2514
2515     case CTSF_MEDIAN:
2516     case CTSF_PTILE:
2517       if (s->writer)
2518         {
2519           struct casereader *reader = casewriter_make_reader (s->writer);
2520           s->writer = NULL;
2521
2522           struct percentile *ptile = percentile_create (
2523             ss->function == CTSF_PTILE ? ss->percentile : 0.5, s->ovalid);
2524           struct order_stats *os = &ptile->parent;
2525           order_stats_accumulate_idx (&os, 1, reader, 1, 0);
2526           s->ovalue = percentile_calculate (ptile, PC_HAVERAGE);
2527           statistic_destroy (&ptile->parent.parent);
2528         }
2529       return s->ovalue;
2530
2531     case CTSF_MODE:
2532       if (s->writer)
2533         {
2534           struct casereader *reader = casewriter_make_reader (s->writer);
2535           s->writer = NULL;
2536
2537           struct mode *mode = mode_create ();
2538           struct order_stats *os = &mode->parent;
2539           order_stats_accumulate_idx (&os, 1, reader, 1, 0);
2540           s->ovalue = mode->mode;
2541           statistic_destroy (&mode->parent.parent);
2542         }
2543       return s->ovalue;
2544     }
2545
2546   NOT_REACHED ();
2547 }
2548
2549 struct ctables_cell_sort_aux
2550   {
2551     const struct ctables_nest *nest;
2552     enum pivot_axis_type a;
2553   };
2554
2555 static int
2556 ctables_cell_compare_3way (const void *a_, const void *b_, const void *aux_)
2557 {
2558   const struct ctables_cell_sort_aux *aux = aux_;
2559   struct ctables_cell *const *ap = a_;
2560   struct ctables_cell *const *bp = b_;
2561   const struct ctables_cell *a = *ap;
2562   const struct ctables_cell *b = *bp;
2563
2564   const struct ctables_nest *nest = aux->nest;
2565   for (size_t i = 0; i < nest->n; i++)
2566     if (i != nest->scale_idx)
2567       {
2568         const struct variable *var = nest->vars[i];
2569         const struct ctables_cell_value *a_cv = &a->axes[aux->a].cvs[i];
2570         const struct ctables_cell_value *b_cv = &b->axes[aux->a].cvs[i];
2571         if (a_cv->category != b_cv->category)
2572           return a_cv->category > b_cv->category ? 1 : -1;
2573
2574         const union value *a_val = &a_cv->value;
2575         const union value *b_val = &b_cv->value;
2576         switch (a_cv->category->type)
2577           {
2578           case CCT_NUMBER:
2579           case CCT_STRING:
2580           case CCT_SUBTOTAL:
2581           case CCT_TOTAL:
2582           case CCT_POSTCOMPUTE:
2583             /* Must be equal. */
2584             continue;
2585
2586           case CCT_RANGE:
2587           case CCT_MISSING:
2588           case CCT_OTHERNM:
2589             {
2590               int cmp = value_compare_3way (a_val, b_val, var_get_width (var));
2591               if (cmp)
2592                 return cmp;
2593             }
2594             break;
2595
2596           case CCT_VALUE:
2597             {
2598               int cmp = value_compare_3way (a_val, b_val, var_get_width (var));
2599               if (cmp)
2600                 return a_cv->category->sort_ascending ? cmp : -cmp;
2601             }
2602             break;
2603
2604           case CCT_LABEL:
2605             {
2606               const char *a_label = var_lookup_value_label (var, a_val);
2607               const char *b_label = var_lookup_value_label (var, b_val);
2608               int cmp = (a_label
2609                          ? (b_label ? strcmp (a_label, b_label) : 1)
2610                          : (b_label ? -1 : value_compare_3way (
2611                               a_val, b_val, var_get_width (var))));
2612               if (cmp)
2613                 return a_cv->category->sort_ascending ? cmp : -cmp;
2614             }
2615             break;
2616
2617           case CCT_FUNCTION:
2618             NOT_REACHED ();
2619           }
2620       }
2621   return 0;
2622 }
2623
2624 /* Algorithm:
2625
2626    For each row:
2627        For each ctables_table:
2628            For each combination of row vars:
2629                For each combination of column vars:
2630                    For each combination of layer vars:
2631                        Add entry
2632    Make a table of row values:
2633        Sort entries by row values
2634        Assign a 0-based index to each actual value
2635        Construct a dimension
2636    Make a table of column values
2637    Make a table of layer values
2638    For each entry:
2639        Fill the table entry using the indexes from before.
2640  */
2641
2642 static struct ctables_domain *
2643 ctables_domain_insert (struct ctables_section *s, struct ctables_cell *cell,
2644                        enum ctables_domain_type domain)
2645 {
2646   size_t hash = 0;
2647   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2648     {
2649       const struct ctables_nest *nest = s->nests[a];
2650       for (size_t i = 0; i < nest->n_domains[domain]; i++)
2651         {
2652           size_t v_idx = nest->domains[domain][i];
2653           hash = value_hash (&cell->axes[a].cvs[v_idx].value,
2654                              var_get_width (nest->vars[v_idx]), hash);
2655         }
2656     }
2657
2658   struct ctables_domain *d;
2659   HMAP_FOR_EACH_WITH_HASH (d, struct ctables_domain, node, hash, &s->domains[domain])
2660     {
2661       const struct ctables_cell *df = d->example;
2662       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2663         {
2664           const struct ctables_nest *nest = s->nests[a];
2665           for (size_t i = 0; i < nest->n_domains[domain]; i++)
2666             {
2667               size_t v_idx = nest->domains[domain][i];
2668               if (!value_equal (&df->axes[a].cvs[v_idx].value,
2669                                 &cell->axes[a].cvs[v_idx].value,
2670                                 var_get_width (nest->vars[v_idx])))
2671                 goto not_equal;
2672             }
2673         }
2674       return d;
2675
2676     not_equal: ;
2677     }
2678
2679   d = xmalloc (sizeof *d);
2680   *d = (struct ctables_domain) { .example = cell };
2681   hmap_insert (&s->domains[domain], &d->node, hash);
2682   return d;
2683 }
2684
2685 static const struct ctables_category *
2686 ctables_categories_match (const struct ctables_categories *c,
2687                           const union value *v, const struct variable *var)
2688 {
2689   const struct ctables_category *othernm = NULL;
2690   for (size_t i = c->n_cats; i-- > 0; )
2691     {
2692       const struct ctables_category *cat = &c->cats[i];
2693       switch (cat->type)
2694         {
2695         case CCT_NUMBER:
2696           if (cat->number == v->f)
2697             return cat;
2698           break;
2699
2700         case CCT_STRING:
2701           NOT_REACHED ();
2702
2703         case CCT_RANGE:
2704           if ((cat->range[0] == -DBL_MAX || v->f >= cat->range[0])
2705               && (cat->range[1] == DBL_MAX || v->f <= cat->range[1]))
2706             return cat;
2707           break;
2708
2709         case CCT_MISSING:
2710           if (var_is_value_missing (var, v))
2711             return cat;
2712           break;
2713
2714         case CCT_POSTCOMPUTE:
2715           break;
2716
2717         case CCT_OTHERNM:
2718           if (!othernm)
2719             othernm = cat;
2720           break;
2721
2722         case CCT_SUBTOTAL:
2723         case CCT_TOTAL:
2724           break;
2725
2726         case CCT_VALUE:
2727         case CCT_LABEL:
2728         case CCT_FUNCTION:
2729           return (cat->include_missing || !var_is_value_missing (var, v) ? cat
2730                   : NULL);
2731         }
2732     }
2733
2734   return var_is_value_missing (var, v) ? NULL : othernm;
2735 }
2736
2737 static const struct ctables_category *
2738 ctables_categories_total (const struct ctables_categories *c)
2739 {
2740   const struct ctables_category *first = &c->cats[0];
2741   const struct ctables_category *last = &c->cats[c->n_cats - 1];
2742   return (first->type == CCT_TOTAL ? first
2743           : last->type == CCT_TOTAL ? last
2744           : NULL);
2745 }
2746
2747 static struct ctables_cell *
2748 ctables_cell_insert__ (struct ctables_section *s, const struct ccase *c,
2749                        const struct ctables_category *cats[PIVOT_N_AXES][10])
2750 {
2751   size_t hash = 0;
2752   enum ctables_summary_variant sv = CSV_CELL;
2753   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2754     {
2755       const struct ctables_nest *nest = s->nests[a];
2756       for (size_t i = 0; i < nest->n; i++)
2757         if (i != nest->scale_idx)
2758           {
2759             hash = hash_pointer (cats[a][i], hash);
2760             if (cats[a][i]->type != CCT_TOTAL
2761                 && cats[a][i]->type != CCT_SUBTOTAL
2762                 && cats[a][i]->type != CCT_POSTCOMPUTE)
2763               hash = value_hash (case_data (c, nest->vars[i]),
2764                                  var_get_width (nest->vars[i]), hash);
2765             else
2766               sv = CSV_TOTAL;
2767           }
2768     }
2769
2770   struct ctables_cell *cell;
2771   HMAP_FOR_EACH_WITH_HASH (cell, struct ctables_cell, node, hash, &s->cells)
2772     {
2773       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2774         {
2775           const struct ctables_nest *nest = s->nests[a];
2776           for (size_t i = 0; i < nest->n; i++)
2777             if (i != nest->scale_idx
2778                 && (cats[a][i] != cell->axes[a].cvs[i].category
2779                     || (cats[a][i]->type != CCT_TOTAL
2780                         && cats[a][i]->type != CCT_SUBTOTAL
2781                         && cats[a][i]->type != CCT_POSTCOMPUTE
2782                         && !value_equal (case_data (c, nest->vars[i]),
2783                                          &cell->axes[a].cvs[i].value,
2784                                          var_get_width (nest->vars[i])))))
2785                 goto not_equal;
2786         }
2787
2788       return cell;
2789
2790     not_equal: ;
2791     }
2792
2793   cell = xmalloc (sizeof *cell);
2794   cell->hide = false;
2795   cell->sv = sv;
2796   cell->contributes_to_domains = true;
2797   cell->postcompute = false;
2798   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2799     {
2800       const struct ctables_nest *nest = s->nests[a];
2801       cell->axes[a].cvs = (nest->n
2802                         ? xnmalloc (nest->n, sizeof *cell->axes[a].cvs)
2803                         : NULL);
2804       for (size_t i = 0; i < nest->n; i++)
2805         {
2806           const struct ctables_category *cat = cats[a][i];
2807           if (i != nest->scale_idx)
2808             {
2809               const struct ctables_category *subtotal = cat->subtotal;
2810               if (cat->hide || (subtotal && subtotal->hide_subcategories))
2811                 cell->hide = true;
2812
2813               if (cat->type == CCT_TOTAL
2814                   || cat->type == CCT_SUBTOTAL
2815                   || cat->type == CCT_POSTCOMPUTE)
2816                 cell->contributes_to_domains = false;
2817               if (cat->type == CCT_POSTCOMPUTE)
2818                 cell->postcompute = true;
2819             }
2820
2821           cell->axes[a].cvs[i].category = cat;
2822           value_clone (&cell->axes[a].cvs[i].value, case_data (c, nest->vars[i]),
2823                        var_get_width (nest->vars[i]));
2824         }
2825     }
2826
2827   const struct ctables_nest *ss = s->nests[s->table->summary_axis];
2828   const struct ctables_summary_spec_set *specs = &ss->specs[cell->sv];
2829   cell->summaries = xmalloc (specs->n * sizeof *cell->summaries);
2830   for (size_t i = 0; i < specs->n; i++)
2831     ctables_summary_init (&cell->summaries[i], &specs->specs[i]);
2832   for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
2833     cell->domains[dt] = ctables_domain_insert (s, cell, dt);
2834   hmap_insert (&s->cells, &cell->node, hash);
2835   return cell;
2836 }
2837
2838 static void
2839 ctables_cell_add__ (struct ctables_section *s, const struct ccase *c,
2840                     const struct ctables_category *cats[PIVOT_N_AXES][10],
2841                     double d_weight, double e_weight)
2842 {
2843   struct ctables_cell *cell = ctables_cell_insert__ (s, c, cats);
2844   const struct ctables_nest *ss = s->nests[s->table->summary_axis];
2845
2846   const struct ctables_summary_spec_set *specs = &ss->specs[cell->sv];
2847   for (size_t i = 0; i < specs->n; i++)
2848     ctables_summary_add (&cell->summaries[i], &specs->specs[i], specs->var,
2849                          case_data (c, specs->var), d_weight, e_weight);
2850   if (cell->contributes_to_domains)
2851     {
2852       for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
2853         {
2854           cell->domains[dt]->d_valid += d_weight;
2855           cell->domains[dt]->e_valid += e_weight;
2856         }
2857     }
2858 }
2859
2860 static void
2861 recurse_totals (struct ctables_section *s, const struct ccase *c,
2862                 const struct ctables_category *cats[PIVOT_N_AXES][10],
2863                 double d_weight, double e_weight,
2864                 enum pivot_axis_type start_axis, size_t start_nest)
2865 {
2866   for (enum pivot_axis_type a = start_axis; a < PIVOT_N_AXES; a++)
2867     {
2868       const struct ctables_nest *nest = s->nests[a];
2869       for (size_t i = start_nest; i < nest->n; i++)
2870         {
2871           if (i == nest->scale_idx)
2872             continue;
2873
2874           const struct variable *var = nest->vars[i];
2875
2876           const struct ctables_category *total = ctables_categories_total (
2877             s->table->categories[var_get_dict_index (var)]);
2878           if (total)
2879             {
2880               const struct ctables_category *save = cats[a][i];
2881               cats[a][i] = total;
2882               ctables_cell_add__ (s, c, cats, d_weight, e_weight);
2883               recurse_totals (s, c, cats, d_weight, e_weight, a, i + 1);
2884               cats[a][i] = save;
2885             }
2886         }
2887       start_nest = 0;
2888     }
2889 }
2890
2891 static void
2892 recurse_subtotals (struct ctables_section *s, const struct ccase *c,
2893                    const struct ctables_category *cats[PIVOT_N_AXES][10],
2894                    double d_weight, double e_weight,
2895                    enum pivot_axis_type start_axis, size_t start_nest)
2896 {
2897   for (enum pivot_axis_type a = start_axis; a < PIVOT_N_AXES; a++)
2898     {
2899       const struct ctables_nest *nest = s->nests[a];
2900       for (size_t i = start_nest; i < nest->n; i++)
2901         {
2902           if (i == nest->scale_idx)
2903             continue;
2904
2905           const struct ctables_category *save = cats[a][i];
2906           if (save->subtotal)
2907             {
2908               cats[a][i] = save->subtotal;
2909               ctables_cell_add__ (s, c, cats, d_weight, e_weight);
2910               recurse_subtotals (s, c, cats, d_weight, e_weight, a, i + 1);
2911               cats[a][i] = save;
2912             }
2913         }
2914       start_nest = 0;
2915     }
2916 }
2917
2918 static void
2919 ctables_add_occurrence (const struct variable *var,
2920                         const union value *value,
2921                         struct hmap *occurrences)
2922 {
2923   int width = var_get_width (var);
2924   unsigned int hash = value_hash (value, width, 0);
2925
2926   struct ctables_occurrence *o;
2927   HMAP_FOR_EACH_WITH_HASH (o, struct ctables_occurrence, node, hash,
2928                            occurrences)
2929     if (value_equal (value, &o->value, width))
2930       return;
2931
2932   o = xmalloc (sizeof *o);
2933   value_clone (&o->value, value, width);
2934   hmap_insert (occurrences, &o->node, hash);
2935 }
2936
2937 static void
2938 ctables_cell_insert (struct ctables_section *s,
2939                      const struct ccase *c,
2940                      double d_weight, double e_weight)
2941 {
2942   const struct ctables_category *cats[PIVOT_N_AXES][10]; /* XXX */
2943   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2944     {
2945       const struct ctables_nest *nest = s->nests[a];
2946       for (size_t i = 0; i < nest->n; i++)
2947         {
2948           if (i == nest->scale_idx)
2949             continue;
2950
2951           const struct variable *var = nest->vars[i];
2952           const union value *value = case_data (c, var);
2953
2954           if (var_is_numeric (var) && value->f == SYSMIS)
2955             return;
2956
2957           cats[a][i] = ctables_categories_match (
2958             s->table->categories[var_get_dict_index (var)], value, var);
2959           if (!cats[a][i])
2960             return;
2961         }
2962     }
2963
2964   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2965     {
2966       const struct ctables_nest *nest = s->nests[a];
2967       for (size_t i = 0; i < nest->n; i++)
2968         if (i != nest->scale_idx)
2969           {
2970             const struct variable *var = nest->vars[i];
2971             const union value *value = case_data (c, var);
2972             ctables_add_occurrence (var, value, &s->occurrences[a][i]);
2973           }
2974     }
2975
2976   ctables_cell_add__ (s, c, cats, d_weight, e_weight);
2977
2978   recurse_totals (s, c, cats, d_weight, e_weight, 0, 0);
2979   recurse_subtotals (s, c, cats, d_weight, e_weight, 0, 0);
2980 }
2981
2982 struct merge_item
2983   {
2984     const struct ctables_summary_spec_set *set;
2985     size_t ofs;
2986   };
2987
2988 static int
2989 merge_item_compare_3way (const struct merge_item *a, const struct merge_item *b)
2990 {
2991   const struct ctables_summary_spec *as = &a->set->specs[a->ofs];
2992   const struct ctables_summary_spec *bs = &b->set->specs[b->ofs];
2993   if (as->function != bs->function)
2994     return as->function > bs->function ? 1 : -1;
2995   else if (as->percentile != bs->percentile)
2996     return as->percentile < bs->percentile ? 1 : -1;
2997   return strcmp (as->label, bs->label);
2998 }
2999
3000 static struct pivot_value *
3001 ctables_category_create_label (const struct ctables_category *cat,
3002                                const struct variable *var,
3003                                const union value *value)
3004 {
3005   return (cat->type == CCT_TOTAL || cat->type == CCT_SUBTOTAL
3006           ? pivot_value_new_user_text (cat->total_label, SIZE_MAX)
3007           : cat->type == CCT_POSTCOMPUTE && cat->pc->label
3008           ? pivot_value_new_user_text (cat->pc->label, SIZE_MAX)
3009           : pivot_value_new_var_value (var, value));
3010 }
3011
3012 static struct ctables_value *
3013 ctables_value_find__ (struct ctables_table *t, const union value *value,
3014                       int width, unsigned int hash)
3015 {
3016   struct ctables_value *clv;
3017   HMAP_FOR_EACH_WITH_HASH (clv, struct ctables_value, node,
3018                            hash, &t->clabels_values_map)
3019     if (value_equal (value, &clv->value, width))
3020       return clv;
3021   return NULL;
3022 }
3023
3024 static void
3025 ctables_value_insert (struct ctables_table *t, const union value *value,
3026                       int width)
3027 {
3028   unsigned int hash = value_hash (value, width, 0);
3029   struct ctables_value *clv = ctables_value_find__ (t, value, width, hash);
3030   if (!clv)
3031     {
3032       clv = xmalloc (sizeof *clv);
3033       value_clone (&clv->value, value, width);
3034       hmap_insert (&t->clabels_values_map, &clv->node, hash);
3035     }
3036 }
3037
3038 static struct ctables_value *
3039 ctables_value_find (struct ctables_table *t,
3040                     const union value *value, int width)
3041 {
3042   return ctables_value_find__ (t, value, width,
3043                                value_hash (value, width, 0));
3044 }
3045
3046 static void
3047 ctables_table_add_section (struct ctables_table *t, enum pivot_axis_type a,
3048                            size_t ix[PIVOT_N_AXES])
3049 {
3050   if (a < PIVOT_N_AXES)
3051     {
3052       size_t limit = MAX (t->stacks[a].n, 1);
3053       for (ix[a] = 0; ix[a] < limit; ix[a]++)
3054         ctables_table_add_section (t, a + 1, ix);
3055     }
3056   else
3057     {
3058       struct ctables_section *s = &t->sections[t->n_sections++];
3059       *s = (struct ctables_section) {
3060         .table = t,
3061         .cells = HMAP_INITIALIZER (s->cells),
3062       };
3063       for (a = 0; a < PIVOT_N_AXES; a++)
3064         if (t->stacks[a].n)
3065           {
3066             struct ctables_nest *nest = &t->stacks[a].nests[ix[a]];
3067             s->nests[a] = nest;
3068             s->occurrences[a] = xnmalloc (nest->n, sizeof *s->occurrences[a]);
3069             for (size_t i = 0; i < nest->n; i++)
3070               hmap_init (&s->occurrences[a][i]);
3071         }
3072       for (size_t i = 0; i < N_CTDTS; i++)
3073         hmap_init (&s->domains[i]);
3074     }
3075 }
3076
3077 static double
3078 ctpo_add (double a, double b)
3079 {
3080   return a + b;
3081 }
3082
3083 static double
3084 ctpo_sub (double a, double b)
3085 {
3086   return a - b;
3087 }
3088
3089 static double
3090 ctpo_mul (double a, double b)
3091 {
3092   return a * b;
3093 }
3094
3095 static double
3096 ctpo_div (double a, double b)
3097 {
3098   return b ? a / b : SYSMIS;
3099 }
3100
3101 static double
3102 ctpo_pow (double a, double b)
3103 {
3104   int save_errno = errno;
3105   errno = 0;
3106   double result = pow (a, b);
3107   if (errno)
3108     result = SYSMIS;
3109   errno = save_errno;
3110   return result;
3111 }
3112
3113 static double
3114 ctpo_neg (double a, double b UNUSED)
3115 {
3116   return -a;
3117 }
3118
3119 struct ctables_pcexpr_evaluate_ctx
3120   {
3121     const struct ctables_cell *cell;
3122     const struct ctables_section *section;
3123     const struct ctables_categories *cats;
3124     enum pivot_axis_type pc_a;
3125     size_t pc_a_idx;
3126   };
3127
3128 static double ctables_pcexpr_evaluate (
3129   const struct ctables_pcexpr_evaluate_ctx *, const struct ctables_pcexpr *);
3130
3131 static double
3132 ctables_pcexpr_evaluate_nonterminal (
3133   const struct ctables_pcexpr_evaluate_ctx *ctx,
3134   const struct ctables_pcexpr *e, size_t n_args,
3135   double evaluate (double, double))
3136 {
3137   double args[2] = { 0, 0 };
3138   for (size_t i = 0; i < n_args; i++)
3139     {
3140       args[i] = ctables_pcexpr_evaluate (ctx, e->subs[i]);
3141       if (!isfinite (args[i]) || args[i] == SYSMIS)
3142         return SYSMIS;
3143     }
3144   return evaluate (args[0], args[1]);
3145 }
3146
3147 static double
3148 ctables_pcexpr_evaluate_category (const struct ctables_pcexpr_evaluate_ctx *ctx,
3149                                   const struct ctables_cell_value *pc_cv)
3150 {
3151   const struct ctables_section *s = ctx->section;
3152
3153   size_t hash = 0;
3154   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3155     {
3156       const struct ctables_nest *nest = s->nests[a];
3157       for (size_t i = 0; i < nest->n; i++)
3158         if (i != nest->scale_idx)
3159           {
3160             const struct ctables_cell_value *cv
3161               = (a == ctx->pc_a && i == ctx->pc_a_idx ? pc_cv
3162                  : &ctx->cell->axes[a].cvs[i]);
3163             hash = hash_pointer (cv->category, hash);
3164             if (cv->category->type != CCT_TOTAL
3165                 && cv->category->type != CCT_SUBTOTAL
3166                 && cv->category->type != CCT_POSTCOMPUTE)
3167               hash = value_hash (&cv->value,
3168                                  var_get_width (nest->vars[i]), hash);
3169           }
3170     }
3171
3172   struct ctables_cell *tc;
3173   HMAP_FOR_EACH_WITH_HASH (tc, struct ctables_cell, node, hash, &s->cells)
3174     {
3175       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3176         {
3177           const struct ctables_nest *nest = s->nests[a];
3178           for (size_t i = 0; i < nest->n; i++)
3179             if (i != nest->scale_idx)
3180               {
3181                 const struct ctables_cell_value *p_cv
3182                   = (a == ctx->pc_a && i == ctx->pc_a_idx ? pc_cv
3183                      : &ctx->cell->axes[a].cvs[i]);
3184                 const struct ctables_cell_value *t_cv = &tc->axes[a].cvs[i];
3185                 if (p_cv->category != t_cv->category
3186                     || (p_cv->category->type != CCT_TOTAL
3187                         && p_cv->category->type != CCT_SUBTOTAL
3188                         && p_cv->category->type != CCT_POSTCOMPUTE
3189                         && !value_equal (&p_cv->value,
3190                                          &t_cv->value,
3191                                          var_get_width (nest->vars[i]))))
3192                   goto not_equal;
3193               }
3194         }
3195
3196       goto found;
3197
3198     not_equal: ;
3199     }
3200   return 0;
3201
3202 found: ;
3203   const struct ctables_table *t = s->table;
3204   const struct ctables_nest *specs_nest = s->nests[t->summary_axis];
3205   const struct ctables_summary_spec_set *specs = &specs_nest->specs[tc->sv];
3206   size_t j = 0 /* XXX */;
3207   return ctables_summary_value (tc, &tc->summaries[j], &specs->specs[j]);
3208 }
3209
3210 static double
3211 ctables_pcexpr_evaluate (const struct ctables_pcexpr_evaluate_ctx *ctx,
3212                          const struct ctables_pcexpr *e)
3213 {
3214   switch (e->op)
3215     {
3216     case CTPO_CONSTANT:
3217       return e->number;
3218
3219     case CTPO_CAT_RANGE:
3220       {
3221         struct ctables_cell_value cv = {
3222           .category = ctables_find_category_for_postcompute (ctx->cats, e)
3223         };
3224         assert (cv.category != NULL);
3225
3226         struct hmap *occurrences = &ctx->section->occurrences[ctx->pc_a][ctx->pc_a_idx];
3227         const struct ctables_occurrence *o;
3228
3229         double sum = 0.0;
3230         const struct variable *var = ctx->section->nests[ctx->pc_a]->vars[ctx->pc_a_idx];
3231         HMAP_FOR_EACH (o, struct ctables_occurrence, node, occurrences)
3232           if (ctables_categories_match (ctx->cats, &o->value, var) == cv.category)
3233             {
3234               cv.value = o->value;
3235               sum += ctables_pcexpr_evaluate_category (ctx, &cv);
3236             }
3237         return sum;
3238       }
3239
3240     case CTPO_CAT_NUMBER:
3241     case CTPO_CAT_STRING:
3242     case CTPO_CAT_MISSING:
3243     case CTPO_CAT_OTHERNM:
3244     case CTPO_CAT_SUBTOTAL:
3245     case CTPO_CAT_TOTAL:
3246       {
3247         struct ctables_cell_value cv = {
3248           .category = ctables_find_category_for_postcompute (ctx->cats, e),
3249           .value = { .f = e->number },
3250         };
3251         assert (cv.category != NULL);
3252         return ctables_pcexpr_evaluate_category (ctx, &cv);
3253       }
3254
3255     case CTPO_ADD:
3256       return ctables_pcexpr_evaluate_nonterminal (ctx, e, 2, ctpo_add);
3257
3258     case CTPO_SUB:
3259       return ctables_pcexpr_evaluate_nonterminal (ctx, e, 2, ctpo_sub);
3260
3261     case CTPO_MUL:
3262       return ctables_pcexpr_evaluate_nonterminal (ctx, e, 2, ctpo_mul);
3263
3264     case CTPO_DIV:
3265       return ctables_pcexpr_evaluate_nonterminal (ctx, e, 2, ctpo_div);
3266
3267     case CTPO_POW:
3268       return ctables_pcexpr_evaluate_nonterminal (ctx, e, 2, ctpo_pow);
3269
3270     case CTPO_NEG:
3271       return ctables_pcexpr_evaluate_nonterminal (ctx, e, 1, ctpo_neg);
3272     }
3273
3274   NOT_REACHED ();
3275 }
3276
3277 static double
3278 ctables_cell_calculate_postcompute (const struct ctables_section *s,
3279                                     const struct ctables_cell *cell)
3280 {
3281   enum pivot_axis_type pc_a;
3282   size_t pc_a_idx;
3283   const struct ctables_postcompute *pc;
3284   for (pc_a = 0; ; pc_a++)
3285     {
3286       assert (pc_a < PIVOT_N_AXES);
3287       for (pc_a_idx = 0; pc_a_idx < s->nests[pc_a]->n; pc_a_idx++)
3288         {
3289           const struct ctables_cell_value *cv = &cell->axes[pc_a].cvs[pc_a_idx];
3290           if (cv->category->type == CCT_POSTCOMPUTE)
3291             {
3292               pc = cv->category->pc;
3293               goto found;
3294             }
3295         }
3296     }
3297 found: ;
3298
3299   const struct variable *var = s->nests[pc_a]->vars[pc_a_idx];
3300   const struct ctables_categories *cats = s->table->categories[
3301     var_get_dict_index (var)];
3302   struct ctables_pcexpr_evaluate_ctx ctx = {
3303     .cell = cell,
3304     .section = s,
3305     .cats = cats,
3306     .pc_a = pc_a,
3307     .pc_a_idx = pc_a_idx,
3308   };
3309   return ctables_pcexpr_evaluate (&ctx, pc->expr);
3310 }
3311
3312 static void
3313 ctables_table_output (struct ctables *ct, struct ctables_table *t)
3314 {
3315   struct pivot_table *pt = pivot_table_create__ (
3316     (t->title
3317      ? pivot_value_new_user_text (t->title, SIZE_MAX)
3318      : pivot_value_new_text (N_("Custom Tables"))),
3319     "Custom Tables");
3320   if (t->caption)
3321     pivot_table_set_caption (
3322       pt, pivot_value_new_user_text (t->caption, SIZE_MAX));
3323   if (t->corner)
3324     pivot_table_set_caption (
3325       pt, pivot_value_new_user_text (t->corner, SIZE_MAX));
3326
3327   bool summary_dimension = (t->summary_axis != t->slabels_axis
3328                             || (!t->slabels_visible
3329                                 && t->summary_specs.n > 1));
3330   if (summary_dimension)
3331     {
3332       struct pivot_dimension *d = pivot_dimension_create (
3333         pt, t->slabels_axis, N_("Statistics"));
3334       const struct ctables_summary_spec_set *specs = &t->summary_specs;
3335       if (!t->slabels_visible)
3336         d->hide_all_labels = true;
3337       for (size_t i = 0; i < specs->n; i++)
3338         pivot_category_create_leaf (
3339           d->root, pivot_value_new_text (specs->specs[i].label));
3340     }
3341
3342   bool categories_dimension = t->clabels_example != NULL;
3343   if (categories_dimension)
3344     {
3345       struct pivot_dimension *d = pivot_dimension_create (
3346         pt, t->label_axis[t->clabels_from_axis],
3347         t->clabels_from_axis == PIVOT_AXIS_ROW
3348         ? N_("Row Categories")
3349         : N_("Column Categories"));
3350       const struct variable *var = t->clabels_example;
3351       const struct ctables_categories *c = t->categories[var_get_dict_index (var)];
3352       for (size_t i = 0; i < t->n_clabels_values; i++)
3353         {
3354           const struct ctables_value *value = t->clabels_values[i];
3355           const struct ctables_category *cat = ctables_categories_match (c, &value->value, var);
3356           assert (cat != NULL);
3357           pivot_category_create_leaf (d->root, ctables_category_create_label (
3358                                         cat, t->clabels_example, &value->value));
3359         }
3360     }
3361
3362   pivot_table_set_look (pt, ct->look);
3363   struct pivot_dimension *d[PIVOT_N_AXES];
3364   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3365     {
3366       static const char *names[] = {
3367         [PIVOT_AXIS_ROW] = N_("Rows"),
3368         [PIVOT_AXIS_COLUMN] = N_("Columns"),
3369         [PIVOT_AXIS_LAYER] = N_("Layers"),
3370       };
3371       d[a] = (t->axes[a] || a == t->summary_axis
3372               ? pivot_dimension_create (pt, a, names[a])
3373               : NULL);
3374       if (!d[a])
3375         continue;
3376
3377       assert (t->axes[a]);
3378
3379       for (size_t i = 0; i < t->stacks[a].n; i++)
3380         {
3381           struct ctables_nest *nest = &t->stacks[a].nests[i];
3382           struct ctables_section **sections = xnmalloc (t->n_sections,
3383                                                         sizeof *sections);
3384           size_t n_sections = 0;
3385
3386           size_t n_total_cells = 0;
3387           size_t max_depth = 0;
3388           for (size_t j = 0; j < t->n_sections; j++)
3389             if (t->sections[j].nests[a] == nest)
3390               {
3391                 struct ctables_section *s = &t->sections[j];
3392                 sections[n_sections++] = s;
3393                 n_total_cells += s->cells.count;
3394
3395                 size_t depth = s->nests[a]->n;
3396                 max_depth = MAX (depth, max_depth);
3397               }
3398
3399           struct ctables_cell **sorted = xnmalloc (n_total_cells,
3400                                                    sizeof *sorted);
3401           size_t n_sorted = 0;
3402
3403           for (size_t j = 0; j < n_sections; j++)
3404             {
3405               struct ctables_section *s = sections[j];
3406
3407               struct ctables_cell *cell;
3408               HMAP_FOR_EACH (cell, struct ctables_cell, node, &s->cells)
3409                 if (!cell->hide)
3410                   sorted[n_sorted++] = cell;
3411               assert (n_sorted <= n_total_cells);
3412             }
3413
3414           struct ctables_cell_sort_aux aux = { .nest = nest, .a = a };
3415           sort (sorted, n_sorted, sizeof *sorted, ctables_cell_compare_3way, &aux);
3416
3417           struct ctables_level
3418             {
3419               enum ctables_level_type
3420                 {
3421                   CTL_VAR,          /* Variable label for nest->vars[var_idx]. */
3422                   CTL_CATEGORY,     /* Category for nest->vars[var_idx]. */
3423                   CTL_SUMMARY,      /* Summary functions. */
3424                 }
3425                 type;
3426
3427               enum settings_value_show vlabel; /* CTL_VAR only. */
3428               size_t var_idx;
3429             };
3430           struct ctables_level *levels = xnmalloc (1 + 2 * max_depth, sizeof *levels);
3431           size_t n_levels = 0;
3432           for (size_t k = 0; k < nest->n; k++)
3433             {
3434               enum ctables_vlabel vlabel = ct->vlabels[var_get_dict_index (nest->vars[k])];
3435               if (vlabel != CTVL_NONE)
3436                 {
3437                   levels[n_levels++] = (struct ctables_level) {
3438                     .type = CTL_VAR,
3439                     .vlabel = (enum settings_value_show) vlabel,
3440                     .var_idx = k,
3441                   };
3442                 }
3443
3444               if (nest->scale_idx != k
3445                   && (k != nest->n - 1 || t->label_axis[a] == a))
3446                 {
3447                   levels[n_levels++] = (struct ctables_level) {
3448                     .type = CTL_CATEGORY,
3449                     .var_idx = k,
3450                   };
3451                 }
3452             }
3453
3454           if (!summary_dimension && a == t->slabels_axis)
3455             {
3456               levels[n_levels++] = (struct ctables_level) {
3457                 .type = CTL_SUMMARY,
3458                 .var_idx = SIZE_MAX,
3459               };
3460             }
3461
3462           /* Pivot categories:
3463
3464              - variable label for nest->vars[0], if vlabel != CTVL_NONE
3465              - category for nest->vars[0], if nest->scale_idx != 0
3466              - variable label for nest->vars[1], if vlabel != CTVL_NONE
3467              - category for nest->vars[1], if nest->scale_idx != 1
3468              ...
3469              - variable label for nest->vars[n - 1], if vlabel != CTVL_NONE
3470              - category for nest->vars[n - 1], if t->label_axis[a] == a && nest->scale_idx != n - 1.
3471              - summary function, if 'a == t->slabels_axis && a ==
3472              t->summary_axis'.
3473
3474              Additional dimensions:
3475
3476              - If 'a == t->slabels_axis && a != t->summary_axis', add a summary
3477              dimension.
3478              - If 't->label_axis[b] == a' for some 'b != a', add a category
3479              dimension to 'a'.
3480           */
3481
3482
3483           struct pivot_category **groups = xnmalloc (1 + 2 * max_depth, sizeof *groups);
3484           int prev_leaf = 0;
3485           for (size_t j = 0; j < n_sorted; j++)
3486             {
3487               struct ctables_cell *cell = sorted[j];
3488               struct ctables_cell *prev = j > 0 ? sorted[j - 1] : NULL;
3489
3490               size_t n_common = 0;
3491               if (j > 0)
3492                 {
3493                   for (; n_common < n_levels; n_common++)
3494                     {
3495                       const struct ctables_level *level = &levels[n_common];
3496                       if (level->type == CTL_CATEGORY)
3497                         {
3498                           size_t var_idx = level->var_idx;
3499                           const struct ctables_category *c = cell->axes[a].cvs[var_idx].category;
3500                           if (prev->axes[a].cvs[var_idx].category != c)
3501                             break;
3502                           else if (c->type != CCT_SUBTOTAL
3503                                    && c->type != CCT_TOTAL
3504                                    && c->type != CCT_POSTCOMPUTE
3505                                    && !value_equal (&prev->axes[a].cvs[var_idx].value,
3506                                                     &cell->axes[a].cvs[var_idx].value,
3507                                                     var_get_type (nest->vars[var_idx])))
3508                             break;
3509                         }
3510                     }
3511                 }
3512
3513               for (size_t k = n_common; k < n_levels; k++)
3514                 {
3515                   const struct ctables_level *level = &levels[k];
3516                   struct pivot_category *parent = k ? groups[k - 1] : d[a]->root;
3517                   if (level->type == CTL_SUMMARY)
3518                     {
3519                       assert (k == n_levels - 1);
3520
3521                       const struct ctables_summary_spec_set *specs = &t->summary_specs;
3522                       for (size_t m = 0; m < specs->n; m++)
3523                         {
3524                           int leaf = pivot_category_create_leaf (
3525                             parent, pivot_value_new_text (specs->specs[m].label));
3526                           if (!m)
3527                             prev_leaf = leaf;
3528                         }
3529                     }
3530                   else
3531                     {
3532                       const struct variable *var = nest->vars[level->var_idx];
3533                       struct pivot_value *label;
3534                       if (level->type == CTL_VAR)
3535                         {
3536                           label = pivot_value_new_variable (var);
3537                           label->variable.show = level->vlabel;
3538                         }
3539                       else if (level->type == CTL_CATEGORY)
3540                         {
3541                           const struct ctables_cell_value *cv = &cell->axes[a].cvs[level->var_idx];
3542                           label = ctables_category_create_label (cv->category,
3543                                                                  var, &cv->value);
3544                         }
3545                       else
3546                         NOT_REACHED ();
3547
3548                       if (k == n_levels - 1)
3549                         prev_leaf = pivot_category_create_leaf (parent, label);
3550                       else
3551                         groups[k] = pivot_category_create_group__ (parent, label);
3552                     }
3553                 }
3554
3555               cell->axes[a].leaf = prev_leaf;
3556             }
3557           free (sorted);
3558           free (groups);
3559         }
3560     }
3561
3562   for (size_t i = 0; i < t->n_sections; i++)
3563     {
3564       struct ctables_section *s = &t->sections[i];
3565
3566       struct ctables_cell *cell;
3567       HMAP_FOR_EACH (cell, struct ctables_cell, node, &s->cells)
3568         {
3569           if (cell->hide)
3570             continue;
3571
3572           const struct ctables_nest *specs_nest = s->nests[t->summary_axis];
3573           const struct ctables_summary_spec_set *specs = &specs_nest->specs[cell->sv];
3574           for (size_t j = 0; j < specs->n; j++)
3575             {
3576               size_t dindexes[5];
3577               size_t n_dindexes = 0;
3578
3579               if (summary_dimension)
3580                 dindexes[n_dindexes++] = specs->specs[j].axis_idx;
3581
3582               if (categories_dimension)
3583                 {
3584                   const struct ctables_nest *clabels_nest = s->nests[t->clabels_from_axis];
3585                   const struct variable *var = clabels_nest->vars[clabels_nest->n - 1];
3586                   const union value *value = &cell->axes[t->clabels_from_axis].cvs[clabels_nest->n - 1].value;
3587                   const struct ctables_value *ctv = ctables_value_find (t, value, var_get_width (var));
3588                   if (!ctv)
3589                     continue;
3590                   dindexes[n_dindexes++] = ctv->leaf;
3591                 }
3592
3593               for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3594                 if (d[a])
3595                   {
3596                     int leaf = cell->axes[a].leaf;
3597                     if (a == t->summary_axis && !summary_dimension)
3598                       leaf += j;
3599                     dindexes[n_dindexes++] = leaf;
3600                   }
3601
3602               const struct ctables_summary_spec *ss = &specs->specs[j];
3603
3604               double d = (cell->postcompute
3605                           ? ctables_cell_calculate_postcompute (s, cell)
3606                           : ctables_summary_value (cell, &cell->summaries[j], ss));
3607               struct pivot_value *value;
3608               if (ct->hide_threshold != 0
3609                   && d < ct->hide_threshold
3610                   && (cell->postcompute
3611                       ? false /* XXX */
3612                       : ctables_summary_function_is_count (ss->function)))
3613                 {
3614                   value = pivot_value_new_user_text_nocopy (
3615                     xasprintf ("<%d", ct->hide_threshold));
3616                 }
3617               else if (d == 0 && ct->zero)
3618                 value = pivot_value_new_user_text (ct->zero, SIZE_MAX);
3619               else if (d == SYSMIS && ct->missing)
3620                 value = pivot_value_new_user_text (ct->missing, SIZE_MAX);
3621               else if (specs->specs[j].is_ctables_format)
3622                 {
3623                   char *s = data_out_stretchy (&(union value) { .f = d },
3624                                                "UTF-8",
3625                                                &specs->specs[j].format,
3626                                                &ct->ctables_formats, NULL);
3627                   value = pivot_value_new_user_text_nocopy (s);
3628                 }
3629               else
3630                 {
3631                   value = pivot_value_new_number (d);
3632                   value->numeric.format = specs->specs[j].format;
3633                 }
3634               pivot_table_put (pt, dindexes, n_dindexes, value);
3635             }
3636         }
3637     }
3638
3639   pivot_table_submit (pt);
3640 }
3641
3642 static bool
3643 ctables_check_label_position (struct ctables_table *t, enum pivot_axis_type a)
3644 {
3645   enum pivot_axis_type label_pos = t->label_axis[a];
3646   if (label_pos == a)
3647     return true;
3648
3649   t->clabels_from_axis = a;
3650
3651   const char *subcommand_name = a == PIVOT_AXIS_ROW ? "ROWLABELS" : "COLLABELS";
3652   const char *pos_name = label_pos == PIVOT_AXIS_LAYER ? "LAYER" : "OPPOSITE";
3653
3654   const struct ctables_stack *stack = &t->stacks[a];
3655   if (!stack->n)
3656     return true;
3657
3658   const struct ctables_nest *n0 = &stack->nests[0];
3659   assert (n0->n > 0);
3660   const struct variable *v0 = n0->vars[n0->n - 1];
3661   struct ctables_categories *c0 = t->categories[var_get_dict_index (v0)];
3662   t->clabels_example = v0;
3663
3664   for (size_t i = 0; i < c0->n_cats; i++)
3665     if (c0->cats[i].type == CCT_FUNCTION)
3666       {
3667         msg (SE, _("%s=%s is not allowed with sorting based "
3668                    "on a summary function."),
3669              subcommand_name, pos_name);
3670         return false;
3671       }
3672   if (n0->n - 1 == n0->scale_idx)
3673     {
3674       msg (SE, _("%s=%s requires the variables to be moved to be categorical, "
3675                  "but %s is a scale variable."),
3676            subcommand_name, pos_name, var_get_name (v0));
3677       return false;
3678     }
3679
3680   for (size_t i = 1; i < stack->n; i++)
3681     {
3682       const struct ctables_nest *ni = &stack->nests[i];
3683       assert (ni->n > 0);
3684       const struct variable *vi = ni->vars[ni->n - 1];
3685       struct ctables_categories *ci = t->categories[var_get_dict_index (vi)];
3686
3687       if (ni->n - 1 == ni->scale_idx)
3688         {
3689           msg (SE, _("%s=%s requires the variables to be moved to be "
3690                      "categorical, but %s is a scale variable."),
3691                subcommand_name, pos_name, var_get_name (vi));
3692           return false;
3693         }
3694       if (var_get_width (v0) != var_get_width (vi))
3695         {
3696           msg (SE, _("%s=%s requires the variables to be "
3697                      "moved to have the same width, but %s has "
3698                      "width %d and %s has width %d."),
3699                subcommand_name, pos_name,
3700                var_get_name (v0), var_get_width (v0),
3701                var_get_name (vi), var_get_width (vi));
3702           return false;
3703         }
3704       if (!val_labs_equal (var_get_value_labels (v0),
3705                            var_get_value_labels (vi)))
3706         {
3707           msg (SE, _("%s=%s requires the variables to be "
3708                      "moved to have the same value labels, but %s "
3709                      "and %s have different value labels."),
3710                subcommand_name, pos_name,
3711                var_get_name (v0), var_get_name (vi));
3712           return false;
3713         }
3714       if (!ctables_categories_equal (c0, ci))
3715         {
3716           msg (SE, _("%s=%s requires the variables to be "
3717                      "moved to have the same category "
3718                      "specifications, but %s and %s have different "
3719                      "category specifications."),
3720                subcommand_name, pos_name,
3721                var_get_name (v0), var_get_name (vi));
3722           return false;
3723         }
3724     }
3725
3726   return true;
3727 }
3728
3729 static bool
3730 ctables_prepare_table (struct ctables_table *t)
3731 {
3732   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3733     if (t->axes[a])
3734       {
3735         t->stacks[a] = enumerate_fts (a, t->axes[a]);
3736
3737         for (size_t j = 0; j < t->stacks[a].n; j++)
3738           {
3739             struct ctables_nest *nest = &t->stacks[a].nests[j];
3740             for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
3741               {
3742                 nest->domains[dt] = xmalloc (nest->n * sizeof *nest->domains[dt]);
3743                 nest->n_domains[dt] = 0;
3744
3745                 for (size_t k = 0; k < nest->n; k++)
3746                   {
3747                     if (k == nest->scale_idx)
3748                       continue;
3749
3750                     switch (dt)
3751                       {
3752                       case CTDT_TABLE:
3753                         continue;
3754
3755                       case CTDT_LAYER:
3756                         if (a != PIVOT_AXIS_LAYER)
3757                           continue;
3758                         break;
3759
3760                       case CTDT_SUBTABLE:
3761                       case CTDT_ROW:
3762                       case CTDT_COL:
3763                         if (dt == CTDT_SUBTABLE ? a != PIVOT_AXIS_LAYER
3764                             : dt == CTDT_ROW ? a == PIVOT_AXIS_COLUMN
3765                             : a == PIVOT_AXIS_ROW)
3766                           {
3767                             if (k == nest->n - 1
3768                                 || (nest->scale_idx == nest->n - 1
3769                                     && k == nest->n - 2))
3770                               continue;
3771                           }
3772                         break;
3773
3774                       case CTDT_LAYERROW:
3775                         if (a == PIVOT_AXIS_COLUMN)
3776                           continue;
3777                         break;
3778
3779                       case CTDT_LAYERCOL:
3780                         if (a == PIVOT_AXIS_ROW)
3781                           continue;
3782                         break;
3783                       }
3784
3785                     nest->domains[dt][nest->n_domains[dt]++] = k;
3786                   }
3787               }
3788           }
3789       }
3790     else
3791       {
3792         struct ctables_nest *nest = xmalloc (sizeof *nest);
3793         *nest = (struct ctables_nest) { .n = 0 };
3794         t->stacks[a] = (struct ctables_stack) { .nests = nest, .n = 1 };
3795       }
3796
3797   struct ctables_stack *stack = &t->stacks[t->summary_axis];
3798   for (size_t i = 0; i < stack->n; i++)
3799     {
3800       struct ctables_nest *nest = &stack->nests[i];
3801       if (!nest->specs[CSV_CELL].n)
3802         {
3803           struct ctables_summary_spec_set *specs = &nest->specs[CSV_CELL];
3804           specs->specs = xmalloc (sizeof *specs->specs);
3805           specs->n = 1;
3806
3807           enum ctables_summary_function function
3808             = specs->var ? CTSF_MEAN : CTSF_COUNT;
3809           struct ctables_var var = { .is_mrset = false, .var = specs->var };
3810
3811           *specs->specs = (struct ctables_summary_spec) {
3812             .function = function,
3813             .format = ctables_summary_default_format (function, &var),
3814             .label = ctables_summary_default_label (function, 0),
3815           };
3816           if (!specs->var)
3817             specs->var = nest->vars[0];
3818
3819           ctables_summary_spec_set_clone (&nest->specs[CSV_TOTAL],
3820                                           &nest->specs[CSV_CELL]);
3821         }
3822       else if (!nest->specs[CSV_TOTAL].n)
3823         ctables_summary_spec_set_clone (&nest->specs[CSV_TOTAL],
3824                                         &nest->specs[CSV_CELL]);
3825     }
3826
3827   struct ctables_summary_spec_set *merged = &t->summary_specs;
3828   struct merge_item *items = xnmalloc (2 * stack->n, sizeof *items);
3829   size_t n_left = 0;
3830   for (size_t j = 0; j < stack->n; j++)
3831     {
3832       const struct ctables_nest *nest = &stack->nests[j];
3833       if (nest->n)
3834         for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
3835           items[n_left++] = (struct merge_item) { .set = &nest->specs[sv] };
3836     }
3837
3838   while (n_left > 0)
3839     {
3840       struct merge_item min = items[0];
3841       for (size_t j = 1; j < n_left; j++)
3842         if (merge_item_compare_3way (&items[j], &min) < 0)
3843           min = items[j];
3844
3845       if (merged->n >= merged->allocated)
3846         merged->specs = x2nrealloc (merged->specs, &merged->allocated,
3847                                     sizeof *merged->specs);
3848       merged->specs[merged->n++] = min.set->specs[min.ofs];
3849
3850       for (size_t j = 0; j < n_left; )
3851         {
3852           if (merge_item_compare_3way (&items[j], &min) == 0)
3853             {
3854               struct merge_item *item = &items[j];
3855               item->set->specs[item->ofs].axis_idx = merged->n - 1;
3856               if (++item->ofs >= item->set->n)
3857                 {
3858                   items[j] = items[--n_left];
3859                   continue;
3860                 }
3861             }
3862           j++;
3863         }
3864     }
3865
3866 #if 0
3867   for (size_t j = 0; j < merged->n; j++)
3868     printf ("%s\n", ctables_summary_function_name (merged->specs[j].function));
3869
3870   for (size_t j = 0; j < stack->n; j++)
3871     {
3872       const struct ctables_nest *nest = &stack->nests[j];
3873       for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
3874         {
3875           const struct ctables_summary_spec_set *specs = &nest->specs[sv];
3876           for (size_t k = 0; k < specs->n; k++)
3877             printf ("(%s, %zu) ", ctables_summary_function_name (specs->specs[k].function),
3878                     specs->specs[k].axis_idx);
3879           printf ("\n");
3880         }
3881     }
3882 #endif
3883
3884   return (ctables_check_label_position (t, PIVOT_AXIS_ROW)
3885           && ctables_check_label_position (t, PIVOT_AXIS_COLUMN));
3886 }
3887
3888 static void
3889 ctables_insert_clabels_values (struct ctables_table *t, const struct ccase *c,
3890                                enum pivot_axis_type a)
3891 {
3892   struct ctables_stack *stack = &t->stacks[a];
3893   for (size_t i = 0; i < stack->n; i++)
3894     {
3895       const struct ctables_nest *nest = &stack->nests[i];
3896       const struct variable *var = nest->vars[nest->n - 1];
3897       const union value *value = case_data (c, var);
3898
3899       if (var_is_numeric (var) && value->f == SYSMIS)
3900         continue;
3901
3902       if (ctables_categories_match (t->categories [var_get_dict_index (var)],
3903                                     value, var))
3904         ctables_value_insert (t, value, var_get_width (var));
3905     }
3906 }
3907
3908 static int
3909 compare_clabels_values_3way (const void *a_, const void *b_, const void *width_)
3910 {
3911   const struct ctables_value *const *ap = a_;
3912   const struct ctables_value *const *bp = b_;
3913   const struct ctables_value *a = *ap;
3914   const struct ctables_value *b = *bp;
3915   const int *width = width_;
3916   return value_compare_3way (&a->value, &b->value, *width);
3917 }
3918
3919 static void
3920 ctables_sort_clabels_values (struct ctables_table *t)
3921 {
3922   const struct variable *v0 = t->clabels_example;
3923   int width = var_get_width (v0);
3924
3925   struct ctables_categories *c0 = t->categories[var_get_dict_index (v0)];
3926   if (c0->show_empty)
3927     {
3928       const struct val_labs *val_labs = var_get_value_labels (v0);
3929       for (const struct val_lab *vl = val_labs_first (val_labs); vl;
3930            vl = val_labs_next (val_labs, vl))
3931         if (ctables_categories_match (c0, &vl->value, v0))
3932           ctables_value_insert (t, &vl->value, width);
3933     }
3934
3935   size_t n = hmap_count (&t->clabels_values_map);
3936   t->clabels_values = xnmalloc (n, sizeof *t->clabels_values);
3937
3938   struct ctables_value *clv;
3939   size_t i = 0;
3940   HMAP_FOR_EACH (clv, struct ctables_value, node, &t->clabels_values_map)
3941     t->clabels_values[i++] = clv;
3942   t->n_clabels_values = n;
3943   assert (i == n);
3944
3945   sort (t->clabels_values, n, sizeof *t->clabels_values,
3946         compare_clabels_values_3way, &width);
3947
3948   for (size_t i = 0; i < n; i++)
3949     t->clabels_values[i]->leaf = i;
3950 }
3951
3952 static void
3953 ctables_add_category_occurrences (const struct variable *var,
3954                                   struct hmap *occurrences,
3955                                   const struct ctables_categories *cats)
3956 {
3957   const struct val_labs *val_labs = var_get_value_labels (var);
3958
3959   for (size_t i = 0; i < cats->n_cats; i++)
3960     {
3961       const struct ctables_category *c = &cats->cats[i];
3962       switch (c->type)
3963         {
3964         case CCT_NUMBER:
3965           ctables_add_occurrence (var, &(const union value) { .f = c->number },
3966                                   occurrences);
3967           break;
3968
3969         case CCT_STRING:
3970           abort ();             /* XXX */
3971
3972         case CCT_RANGE:
3973           assert (var_is_numeric (var));
3974           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
3975                vl = val_labs_next (val_labs, vl))
3976             if (vl->value.f >= c->range[0] && vl->value.f <= c->range[1])
3977               ctables_add_occurrence (var, &vl->value, occurrences);
3978           break;
3979
3980         case CCT_MISSING:
3981           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
3982                vl = val_labs_next (val_labs, vl))
3983             if (var_is_value_missing (var, &vl->value))
3984               ctables_add_occurrence (var, &vl->value, occurrences);
3985           break;
3986
3987         case CCT_OTHERNM:
3988           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
3989                vl = val_labs_next (val_labs, vl))
3990             ctables_add_occurrence (var, &vl->value, occurrences);
3991           break;
3992
3993         case CCT_POSTCOMPUTE:
3994           break;
3995
3996         case CCT_SUBTOTAL:
3997         case CCT_TOTAL:
3998           break;
3999
4000         case CCT_VALUE:
4001         case CCT_LABEL:
4002         case CCT_FUNCTION:
4003           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
4004                vl = val_labs_next (val_labs, vl))
4005             if (c->include_missing || !var_is_value_missing (var, &vl->value))
4006               ctables_add_occurrence (var, &vl->value, occurrences);
4007           break;
4008         }
4009     }
4010 }
4011
4012 static void
4013 ctables_section_recurse_add_empty_categories (
4014   struct ctables_section *s,
4015   const struct ctables_category *cats[PIVOT_N_AXES][10], struct ccase *c,
4016   enum pivot_axis_type a, size_t a_idx)
4017 {
4018   if (a >= PIVOT_N_AXES)
4019     ctables_cell_insert__ (s, c, cats);
4020   else if (!s->nests[a] || a_idx >= s->nests[a]->n)
4021     ctables_section_recurse_add_empty_categories (s, cats, c, a + 1, 0);
4022   else
4023     {
4024       const struct variable *var = s->nests[a]->vars[a_idx];
4025       const struct ctables_categories *categories = s->table->categories[
4026         var_get_dict_index (var)];
4027       int width = var_get_width (var);
4028       const struct hmap *occurrences = &s->occurrences[a][a_idx];
4029       const struct ctables_occurrence *o;
4030       HMAP_FOR_EACH (o, struct ctables_occurrence, node, occurrences)
4031         {
4032           union value *value = case_data_rw (c, var);
4033           value_destroy (value, width);
4034           value_clone (value, &o->value, width);
4035           cats[a][a_idx] = ctables_categories_match (categories, value, var);
4036           assert (cats[a][a_idx] != NULL);
4037           ctables_section_recurse_add_empty_categories (s, cats, c, a, a_idx + 1);
4038         }
4039
4040       for (size_t i = 0; i < categories->n_cats; i++)
4041         {
4042           const struct ctables_category *cat = &categories->cats[i];
4043           if (cat->type == CCT_POSTCOMPUTE)
4044             {
4045               cats[a][a_idx] = cat;
4046               ctables_section_recurse_add_empty_categories (s, cats, c, a, a_idx + 1);
4047             }
4048         }
4049     }
4050 }
4051
4052 static void
4053 ctables_section_add_empty_categories (struct ctables_section *s)
4054 {
4055   bool show_empty = false;
4056   for (size_t a = 0; a < PIVOT_N_AXES; a++)
4057     if (s->nests[a])
4058       for (size_t k = 0; k < s->nests[a]->n; k++)
4059         if (k != s->nests[a]->scale_idx)
4060           {
4061             const struct variable *var = s->nests[a]->vars[k];
4062             const struct ctables_categories *cats = s->table->categories[
4063               var_get_dict_index (var)];
4064             if (cats->show_empty)
4065               {
4066                 show_empty = true;
4067                 ctables_add_category_occurrences (var, &s->occurrences[a][k], cats);
4068               }
4069           }
4070   if (!show_empty)
4071     return;
4072
4073   const struct ctables_category *cats[PIVOT_N_AXES][10]; /* XXX */
4074   struct ccase *c = case_create (dict_get_proto (s->table->ctables->dict));
4075   ctables_section_recurse_add_empty_categories (s, cats, c, 0, 0);
4076   case_unref (c);
4077 }
4078
4079 static bool
4080 ctables_execute (struct dataset *ds, struct ctables *ct)
4081 {
4082   for (size_t i = 0; i < ct->n_tables; i++)
4083     {
4084       struct ctables_table *t = ct->tables[i];
4085       t->sections = xnmalloc (MAX (1, t->stacks[PIVOT_AXIS_ROW].n) *
4086                               MAX (1, t->stacks[PIVOT_AXIS_COLUMN].n) *
4087                               MAX (1, t->stacks[PIVOT_AXIS_LAYER].n),
4088                               sizeof *t->sections);
4089       size_t ix[PIVOT_N_AXES];
4090       ctables_table_add_section (t, 0, ix);
4091     }
4092
4093   struct casereader *input = proc_open (ds);
4094   bool warn_on_invalid = true;
4095   for (struct ccase *c = casereader_read (input); c;
4096        case_unref (c), c = casereader_read (input))
4097     {
4098       double d_weight = dict_get_case_weight (dataset_dict (ds), c,
4099                                               &warn_on_invalid);
4100       double e_weight = (ct->e_weight
4101                          ? var_force_valid_weight (ct->e_weight,
4102                                                    case_num (c, ct->e_weight),
4103                                                    &warn_on_invalid)
4104                          : d_weight);
4105
4106       for (size_t i = 0; i < ct->n_tables; i++)
4107         {
4108           struct ctables_table *t = ct->tables[i];
4109
4110           for (size_t j = 0; j < t->n_sections; j++)
4111             ctables_cell_insert (&t->sections[j], c, d_weight, e_weight);
4112
4113           for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
4114             if (t->label_axis[a] != a)
4115               ctables_insert_clabels_values (t, c, a);
4116         }
4117     }
4118   casereader_destroy (input);
4119
4120   for (size_t i = 0; i < ct->n_tables; i++)
4121     {
4122       struct ctables_table *t = ct->tables[i];
4123
4124       if (t->clabels_example)
4125         ctables_sort_clabels_values (t);
4126
4127       for (size_t j = 0; j < t->n_sections; j++)
4128         ctables_section_add_empty_categories (&t->sections[j]);
4129
4130       ctables_table_output (ct, ct->tables[i]);
4131     }
4132   return proc_commit (ds);
4133 }
4134 \f
4135 /* Postcomputes. */
4136
4137 typedef struct ctables_pcexpr *parse_recursively_func (struct lexer *);
4138
4139 static void
4140 ctables_pcexpr_destroy (struct ctables_pcexpr *e)
4141 {
4142   if (e)
4143     {
4144       switch (e->op)
4145         {
4146         case CTPO_CAT_STRING:
4147           free (e->string);
4148           break;
4149
4150         case CTPO_ADD:
4151         case CTPO_SUB:
4152         case CTPO_MUL:
4153         case CTPO_DIV:
4154         case CTPO_POW:
4155         case CTPO_NEG:
4156           for (size_t i = 0; i < 2; i++)
4157             ctables_pcexpr_destroy (e->subs[i]);
4158           break;
4159
4160         case CTPO_CONSTANT:
4161         case CTPO_CAT_NUMBER:
4162         case CTPO_CAT_RANGE:
4163         case CTPO_CAT_MISSING:
4164         case CTPO_CAT_OTHERNM:
4165         case CTPO_CAT_SUBTOTAL:
4166         case CTPO_CAT_TOTAL:
4167           break;
4168         }
4169
4170       msg_location_destroy (e->location);
4171       free (e);
4172     }
4173 }
4174
4175 static struct ctables_pcexpr *
4176 ctables_pcexpr_allocate_binary (enum ctables_postcompute_op op,
4177                                 struct ctables_pcexpr *sub0,
4178                                 struct ctables_pcexpr *sub1)
4179 {
4180   struct ctables_pcexpr *e = xmalloc (sizeof *e);
4181   *e = (struct ctables_pcexpr) {
4182     .op = op,
4183     .subs = { sub0, sub1 },
4184     .location = msg_location_merged (sub0->location, sub1->location),
4185   };
4186   return e;
4187 }
4188
4189 /* How to parse an operator. */
4190 struct operator
4191   {
4192     enum token_type token;
4193     enum ctables_postcompute_op op;
4194   };
4195
4196 static const struct operator *
4197 match_operator (struct lexer *lexer, const struct operator ops[], size_t n_ops)
4198 {
4199   for (const struct operator *op = ops; op < ops + n_ops; op++)
4200     if (lex_token (lexer) == op->token)
4201       {
4202         if (op->token != T_NEG_NUM)
4203           lex_get (lexer);
4204
4205         return op;
4206       }
4207
4208   return NULL;
4209 }
4210
4211 static struct ctables_pcexpr *
4212 parse_binary_operators__ (struct lexer *lexer,
4213                           const struct operator ops[], size_t n_ops,
4214                           parse_recursively_func *parse_next_level,
4215                           const char *chain_warning,
4216                           struct ctables_pcexpr *lhs)
4217 {
4218   for (int op_count = 0; ; op_count++)
4219     {
4220       const struct operator *op = match_operator (lexer, ops, n_ops);
4221       if (!op)
4222         {
4223           if (op_count > 1 && chain_warning)
4224             msg_at (SW, lhs->location, "%s", chain_warning);
4225
4226           return lhs;
4227         }
4228
4229       struct ctables_pcexpr *rhs = parse_next_level (lexer);
4230       if (!rhs)
4231         {
4232           ctables_pcexpr_destroy (lhs);
4233           return NULL;
4234         }
4235
4236       lhs = ctables_pcexpr_allocate_binary (op->op, lhs, rhs);
4237     }
4238 }
4239
4240 static struct ctables_pcexpr *
4241 parse_binary_operators (struct lexer *lexer,
4242                         const struct operator ops[], size_t n_ops,
4243                         parse_recursively_func *parse_next_level,
4244                         const char *chain_warning)
4245 {
4246   struct ctables_pcexpr *lhs = parse_next_level (lexer);
4247   if (!lhs)
4248     return NULL;
4249
4250   return parse_binary_operators__ (lexer, ops, n_ops, parse_next_level,
4251                                    chain_warning, lhs);
4252 }
4253
4254 static struct ctables_pcexpr *parse_add (struct lexer *);
4255
4256 static struct ctables_pcexpr
4257 ctpo_cat_range (double low, double high)
4258 {
4259   return (struct ctables_pcexpr) {
4260     .op = CTPO_CAT_RANGE,
4261     .range = { low, high },
4262   };
4263 }
4264
4265 static struct ctables_pcexpr *
4266 parse_primary (struct lexer *lexer)
4267 {
4268   int start_ofs = lex_ofs (lexer);
4269   struct ctables_pcexpr e;
4270   if (lex_is_number (lexer))
4271     {
4272       e = (struct ctables_pcexpr) { .op = CTPO_CONSTANT,
4273                                     .number = lex_number (lexer) };
4274       lex_get (lexer);
4275     }
4276   else if (lex_match_id (lexer, "MISSING"))
4277     e = (struct ctables_pcexpr) { .op = CTPO_CAT_MISSING };
4278   else if (lex_match_id (lexer, "OTHERNM"))
4279     e = (struct ctables_pcexpr) { .op = CTPO_CAT_OTHERNM };
4280   else if (lex_match_id (lexer, "TOTAL"))
4281     e = (struct ctables_pcexpr) { .op = CTPO_CAT_TOTAL };
4282   else if (lex_match_id (lexer, "SUBTOTAL"))
4283     {
4284       size_t subtotal_index = 0;
4285       if (lex_match (lexer, T_LBRACK))
4286         {
4287           if (!lex_force_int_range (lexer, "SUBTOTAL", 1, LONG_MAX))
4288             return NULL;
4289           subtotal_index = lex_integer (lexer);
4290           lex_get (lexer);
4291           if (!lex_force_match (lexer, T_RBRACK))
4292             return NULL;
4293         }
4294       e = (struct ctables_pcexpr) { .op = CTPO_CAT_SUBTOTAL,
4295                                     .subtotal_index = subtotal_index };
4296     }
4297   else if (lex_match (lexer, T_LBRACK))
4298     {
4299       if (lex_match_id (lexer, "LO"))
4300         {
4301           if (!lex_force_match_id (lexer, "THRU") || lex_force_num (lexer))
4302             return false;
4303           e = ctpo_cat_range (-DBL_MAX, lex_number (lexer));
4304           lex_get (lexer);
4305         }
4306       else if (lex_is_number (lexer))
4307         {
4308           double number = lex_number (lexer);
4309           lex_get (lexer);
4310           if (lex_match_id (lexer, "THRU"))
4311             {
4312               if (lex_match_id (lexer, "HI"))
4313                 e = ctpo_cat_range (number, DBL_MAX);
4314               else
4315                 {
4316                   if (!lex_force_num (lexer))
4317                     return false;
4318                   e = ctpo_cat_range (number, lex_number (lexer));
4319                   lex_get (lexer);
4320                 }
4321             }
4322           else
4323             e = (struct ctables_pcexpr) { .op = CTPO_CAT_NUMBER,
4324                                           .number = number };
4325         }
4326       else if (lex_is_string (lexer))
4327         {
4328           e = (struct ctables_pcexpr) {
4329             .op = CTPO_CAT_STRING,
4330             .string = ss_xstrdup (lex_tokss (lexer)),
4331           };
4332           lex_get (lexer);
4333         }
4334       else
4335         {
4336           lex_error (lexer, NULL);
4337           return NULL;
4338         }
4339
4340       if (!lex_force_match (lexer, T_RBRACK))
4341         {
4342           if (e.op == CTPO_CAT_STRING)
4343             free (e.string);
4344           return NULL;
4345         }
4346     }
4347   else if (lex_match (lexer, T_LPAREN))
4348     {
4349       struct ctables_pcexpr *ep = parse_add (lexer);
4350       if (!ep)
4351         return NULL;
4352       if (!lex_force_match (lexer, T_RPAREN))
4353         {
4354           ctables_pcexpr_destroy (ep);
4355           return NULL;
4356         }
4357       return ep;
4358     }
4359   else
4360     {
4361       lex_error (lexer, NULL);
4362       return NULL;
4363     }
4364
4365   e.location = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer) - 1);
4366   return xmemdup (&e, sizeof e);
4367 }
4368
4369 static struct ctables_pcexpr *
4370 ctables_pcexpr_allocate_neg (struct ctables_pcexpr *sub,
4371                              struct lexer *lexer, int start_ofs)
4372 {
4373   struct ctables_pcexpr *e = xmalloc (sizeof *e);
4374   *e = (struct ctables_pcexpr) {
4375     .op = CTPO_NEG,
4376     .subs = { sub },
4377     .location = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer) - 1),
4378   };
4379   return e;
4380 }
4381
4382 static struct ctables_pcexpr *
4383 parse_exp (struct lexer *lexer)
4384 {
4385   static const struct operator op = { T_EXP, CTPO_POW };
4386
4387   const char *chain_warning =
4388     _("The exponentiation operator (`**') is left-associative: "
4389       "`a**b**c' equals `(a**b)**c', not `a**(b**c)'.  "
4390       "To disable this warning, insert parentheses.");
4391
4392   if (lex_token (lexer) != T_NEG_NUM || lex_next_token (lexer, 1) != T_EXP)
4393     return parse_binary_operators (lexer, &op, 1,
4394                                    parse_primary, chain_warning);
4395
4396   /* Special case for situations like "-5**6", which must be parsed as
4397      -(5**6). */
4398
4399   int start_ofs = lex_ofs (lexer);
4400   struct ctables_pcexpr *lhs = xmalloc (sizeof *lhs);
4401   *lhs = (struct ctables_pcexpr) {
4402     .op = CTPO_CONSTANT,
4403     .number = -lex_tokval (lexer),
4404     .location = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer)),
4405   };
4406   lex_get (lexer);
4407
4408   struct ctables_pcexpr *node = parse_binary_operators__ (
4409     lexer, &op, 1, parse_primary, chain_warning, lhs);
4410   if (!node)
4411     return NULL;
4412
4413   return ctables_pcexpr_allocate_neg (node, lexer, start_ofs);
4414 }
4415
4416 /* Parses the unary minus level. */
4417 static struct ctables_pcexpr *
4418 parse_neg (struct lexer *lexer)
4419 {
4420   int start_ofs = lex_ofs (lexer);
4421   if (!lex_match (lexer, T_DASH))
4422     return parse_exp (lexer);
4423
4424   struct ctables_pcexpr *inner = parse_neg (lexer);
4425   if (!inner)
4426     return NULL;
4427
4428   return ctables_pcexpr_allocate_neg (inner, lexer, start_ofs);
4429 }
4430
4431 /* Parses the multiplication and division level. */
4432 static struct ctables_pcexpr *
4433 parse_mul (struct lexer *lexer)
4434 {
4435   static const struct operator ops[] =
4436     {
4437       { T_ASTERISK, CTPO_MUL },
4438       { T_SLASH, CTPO_DIV },
4439     };
4440
4441   return parse_binary_operators (lexer, ops, sizeof ops / sizeof *ops,
4442                                  parse_neg, NULL);
4443 }
4444
4445 /* Parses the addition and subtraction level. */
4446 static struct ctables_pcexpr *
4447 parse_add (struct lexer *lexer)
4448 {
4449   static const struct operator ops[] =
4450     {
4451       { T_PLUS, CTPO_ADD },
4452       { T_DASH, CTPO_SUB },
4453       { T_NEG_NUM, CTPO_ADD },
4454     };
4455
4456   return parse_binary_operators (lexer, ops, sizeof ops / sizeof *ops,
4457                                  parse_mul, NULL);
4458 }
4459
4460 static struct ctables_postcompute *
4461 ctables_find_postcompute (struct ctables *ct, const char *name)
4462 {
4463   struct ctables_postcompute *pc;
4464   HMAP_FOR_EACH_WITH_HASH (pc, struct ctables_postcompute, hmap_node,
4465                            utf8_hash_case_string (name, 0), &ct->postcomputes)
4466     if (!utf8_strcasecmp (pc->name, name))
4467       return pc;
4468   return NULL;
4469 }
4470
4471 static bool
4472 ctables_parse_pcompute (struct lexer *lexer, struct ctables *ct)
4473 {
4474   int pcompute_start = lex_ofs (lexer) - 1;
4475
4476   if (!lex_force_match (lexer, T_AND) || !lex_force_id (lexer))
4477     return false;
4478
4479   char *name = ss_xstrdup (lex_tokss (lexer));
4480
4481   lex_get (lexer);
4482   if (!lex_force_match (lexer, T_EQUALS)
4483       || !lex_force_match_id (lexer, "EXPR")
4484       || !lex_force_match (lexer, T_LPAREN))
4485     {
4486       free (name);
4487       return false;
4488     }
4489
4490   int expr_start = lex_ofs (lexer);
4491   struct ctables_pcexpr *expr = parse_add (lexer);
4492   int expr_end = lex_ofs (lexer) - 1;
4493   if (!expr || !lex_force_match (lexer, T_RPAREN))
4494     {
4495       free (name);
4496       return false;
4497     }
4498   int pcompute_end = lex_ofs (lexer) - 1;
4499
4500   struct msg_location *location = lex_ofs_location (lexer, pcompute_start,
4501                                                     pcompute_end);
4502
4503   struct ctables_postcompute *pc = ctables_find_postcompute (ct, name);
4504   if (pc)
4505     {
4506       msg_at (SW, location, _("New definition of &%s will override the "
4507                               "previous definition."),
4508               pc->name);
4509       msg_at (SN, pc->location, _("This is the previous definition."));
4510
4511       ctables_pcexpr_destroy (pc->expr);
4512       msg_location_destroy (pc->location);
4513       free (name);
4514     }
4515   else
4516     {
4517       pc = xmalloc (sizeof *pc);
4518       *pc = (struct ctables_postcompute) { .name = name };
4519       hmap_insert (&ct->postcomputes, &pc->hmap_node,
4520                    utf8_hash_case_string (pc->name, 0));
4521     }
4522   pc->expr = expr;
4523   pc->location = location;
4524   if (!pc->label)
4525     pc->label = lex_ofs_representation (lexer, expr_start, expr_end);
4526   return true;
4527 }
4528
4529 static bool
4530 ctables_parse_pproperties_format (struct lexer *lexer,
4531                                   struct ctables_summary_spec_set *sss)
4532 {
4533   *sss = (struct ctables_summary_spec_set) { .n = 0 };
4534
4535   while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH
4536          && !(lex_token (lexer) == T_ID
4537               && (lex_id_match (ss_cstr ("LABEL"), lex_tokss (lexer))
4538                   || lex_id_match (ss_cstr ("HIDESOURCECATS"),
4539                                    lex_tokss (lexer)))))
4540     {
4541       /* Parse function. */
4542       enum ctables_summary_function function;
4543       if (!parse_ctables_summary_function (lexer, &function))
4544         goto error;
4545
4546       /* Parse percentile. */
4547       double percentile = 0;
4548       if (function == CTSF_PTILE)
4549         {
4550           if (!lex_force_num_range_closed (lexer, "PTILE", 0, 100))
4551             goto error;
4552           percentile = lex_number (lexer);
4553           lex_get (lexer);
4554         }
4555
4556       /* Parse format. */
4557       struct fmt_spec format;
4558       if (!parse_format_specifier (lexer, &format)
4559           || !fmt_check_output (&format)
4560           || !fmt_check_type_compat (&format, VAL_NUMERIC))
4561         goto error;
4562
4563       if (sss->n >= sss->allocated)
4564         sss->specs = x2nrealloc (sss->specs, &sss->allocated,
4565                                  sizeof *sss->specs);
4566       sss->specs[sss->n++] = (struct ctables_summary_spec) {
4567         .function = function,
4568         .percentile = percentile,
4569         .format = format,
4570       };
4571     }
4572   return true;
4573
4574 error:
4575   ctables_summary_spec_set_uninit (sss);
4576   return false;
4577 }
4578
4579 static bool
4580 ctables_parse_pproperties (struct lexer *lexer, struct ctables *ct)
4581 {
4582   struct ctables_postcompute **pcs = NULL;
4583   size_t n_pcs = 0;
4584   size_t allocated_pcs = 0;
4585
4586   while (lex_match (lexer, T_AND))
4587     {
4588       if (!lex_force_id (lexer))
4589         goto error;
4590       struct ctables_postcompute *pc
4591         = ctables_find_postcompute (ct, lex_tokcstr (lexer));
4592       if (!pc)
4593         {
4594           msg (SE, _("Unknown computed category &%s."), lex_tokcstr (lexer));
4595           goto error;
4596         }
4597       lex_get (lexer);
4598
4599       if (n_pcs >= allocated_pcs)
4600         pcs = x2nrealloc (pcs, &allocated_pcs, sizeof *pcs);
4601       pcs[n_pcs++] = pc;
4602     }
4603
4604   while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
4605     {
4606       if (lex_match_id (lexer, "LABEL"))
4607         {
4608           lex_match (lexer, T_EQUALS);
4609           if (!lex_force_string (lexer))
4610             goto error;
4611
4612           for (size_t i = 0; i < n_pcs; i++)
4613             {
4614               free (pcs[i]->label);
4615               pcs[i]->label = ss_xstrdup (lex_tokss (lexer));
4616             }
4617
4618           lex_get (lexer);
4619         }
4620       else if (lex_match_id (lexer, "FORMAT"))
4621         {
4622           lex_match (lexer, T_EQUALS);
4623
4624           struct ctables_summary_spec_set sss;
4625           if (!ctables_parse_pproperties_format (lexer, &sss))
4626             goto error;
4627
4628           for (size_t i = 0; i < n_pcs; i++)
4629             {
4630               if (pcs[i]->specs)
4631                 ctables_summary_spec_set_uninit (pcs[i]->specs);
4632               else
4633                 pcs[i]->specs = xmalloc (sizeof *pcs[i]->specs);
4634               ctables_summary_spec_set_clone (pcs[i]->specs, &sss);
4635             }
4636           ctables_summary_spec_set_uninit (&sss);
4637         }
4638       else if (lex_match_id (lexer, "HIDESOURCECATS"))
4639         {
4640           lex_match (lexer, T_EQUALS);
4641           bool hide_source_cats;
4642           if (!parse_bool (lexer, &hide_source_cats))
4643             goto error;
4644           for (size_t i = 0; i < n_pcs; i++)
4645             pcs[i]->hide_source_cats = hide_source_cats;
4646         }
4647       else
4648         {
4649           lex_error_expecting (lexer, "LABEL", "FORMAT", "HIDESOURCECATS");
4650           goto error;
4651         }
4652     }
4653   free (pcs);
4654   return true;
4655
4656 error:
4657   free (pcs);
4658   return false;
4659 }
4660
4661 int
4662 cmd_ctables (struct lexer *lexer, struct dataset *ds)
4663 {
4664   size_t n_vars = dict_get_n_vars (dataset_dict (ds));
4665   enum ctables_vlabel *vlabels = xnmalloc (n_vars, sizeof *vlabels);
4666   enum settings_value_show tvars = settings_get_show_variables ();
4667   for (size_t i = 0; i < n_vars; i++)
4668     vlabels[i] = (enum ctables_vlabel) tvars;
4669
4670   struct pivot_table_look *look = pivot_table_look_unshare (
4671     pivot_table_look_ref (pivot_table_look_get_default ()));
4672   look->omit_empty = false;
4673
4674   struct ctables *ct = xmalloc (sizeof *ct);
4675   *ct = (struct ctables) {
4676     .dict = dataset_dict (ds),
4677     .look = look,
4678     .ctables_formats = FMT_SETTINGS_INIT,
4679     .vlabels = vlabels,
4680     .postcomputes = HMAP_INITIALIZER (ct->postcomputes),
4681   };
4682
4683   struct ctf
4684     {
4685       enum fmt_type type;
4686       const char *dot_string;
4687       const char *comma_string;
4688     };
4689   static const struct ctf ctfs[4] = {
4690     { CTEF_NEGPAREN, "(,,,)",   "(...)" },
4691     { CTEF_NEQUAL,   "-,N=,,",  "-.N=.." },
4692     { CTEF_PAREN,    "-,(,),",  "-.(.)." },
4693     { CTEF_PCTPAREN, "-,(,%),", "-.(.%)." },
4694   };
4695   bool is_dot = settings_get_fmt_settings ()->decimal == '.';
4696   for (size_t i = 0; i < 4; i++)
4697     {
4698       const char *s = is_dot ? ctfs[i].dot_string : ctfs[i].comma_string;
4699       fmt_settings_set_cc (&ct->ctables_formats, ctfs[i].type,
4700                            fmt_number_style_from_string (s));
4701     }
4702
4703   if (!lex_force_match (lexer, T_SLASH))
4704     goto error;
4705
4706   while (!lex_match_id (lexer, "TABLE"))
4707     {
4708       if (lex_match_id (lexer, "FORMAT"))
4709         {
4710           double widths[2] = { SYSMIS, SYSMIS };
4711           double units_per_inch = 72.0;
4712
4713           while (lex_token (lexer) != T_SLASH)
4714             {
4715               if (lex_match_id (lexer, "MINCOLWIDTH"))
4716                 {
4717                   if (!parse_col_width (lexer, "MINCOLWIDTH", &widths[0]))
4718                     goto error;
4719                 }
4720               else if (lex_match_id (lexer, "MAXCOLWIDTH"))
4721                 {
4722                   if (!parse_col_width (lexer, "MAXCOLWIDTH", &widths[1]))
4723                     goto error;
4724                 }
4725               else if (lex_match_id (lexer, "UNITS"))
4726                 {
4727                   lex_match (lexer, T_EQUALS);
4728                   if (lex_match_id (lexer, "POINTS"))
4729                     units_per_inch = 72.0;
4730                   else if (lex_match_id (lexer, "INCHES"))
4731                     units_per_inch = 1.0;
4732                   else if (lex_match_id (lexer, "CM"))
4733                     units_per_inch = 2.54;
4734                   else
4735                     {
4736                       lex_error_expecting (lexer, "POINTS", "INCHES", "CM");
4737                       goto error;
4738                     }
4739                 }
4740               else if (lex_match_id (lexer, "EMPTY"))
4741                 {
4742                   free (ct->zero);
4743                   ct->zero = NULL;
4744
4745                   lex_match (lexer, T_EQUALS);
4746                   if (lex_match_id (lexer, "ZERO"))
4747                     {
4748                       /* Nothing to do. */
4749                     }
4750                   else if (lex_match_id (lexer, "BLANK"))
4751                     ct->zero = xstrdup ("");
4752                   else if (lex_force_string (lexer))
4753                     {
4754                       ct->zero = ss_xstrdup (lex_tokss (lexer));
4755                       lex_get (lexer);
4756                     }
4757                   else
4758                     goto error;
4759                 }
4760               else if (lex_match_id (lexer, "MISSING"))
4761                 {
4762                   lex_match (lexer, T_EQUALS);
4763                   if (!lex_force_string (lexer))
4764                     goto error;
4765
4766                   free (ct->missing);
4767                   ct->missing = (strcmp (lex_tokcstr (lexer), ".")
4768                                  ? ss_xstrdup (lex_tokss (lexer))
4769                                  : NULL);
4770                   lex_get (lexer);
4771                 }
4772               else
4773                 {
4774                   lex_error_expecting (lexer, "MINCOLWIDTH", "MAXCOLWIDTH",
4775                                        "UNITS", "EMPTY", "MISSING");
4776                   goto error;
4777                 }
4778             }
4779
4780           if (widths[0] != SYSMIS && widths[1] != SYSMIS
4781               && widths[0] > widths[1])
4782             {
4783               msg (SE, _("MINCOLWIDTH must not be greater than MAXCOLWIDTH."));
4784               goto error;
4785             }
4786
4787           for (size_t i = 0; i < 2; i++)
4788             if (widths[i] != SYSMIS)
4789               {
4790                 int *wr = ct->look->width_ranges[TABLE_HORZ];
4791                 wr[i] = widths[i] / units_per_inch * 96.0;
4792                 if (wr[0] > wr[1])
4793                   wr[!i] = wr[i];
4794               }
4795         }
4796       else if (lex_match_id (lexer, "VLABELS"))
4797         {
4798           if (!lex_force_match_id (lexer, "VARIABLES"))
4799             goto error;
4800           lex_match (lexer, T_EQUALS);
4801
4802           struct variable **vars;
4803           size_t n_vars;
4804           if (!parse_variables (lexer, dataset_dict (ds), &vars, &n_vars,
4805                                 PV_NO_SCRATCH))
4806             goto error;
4807
4808           if (!lex_force_match_id (lexer, "DISPLAY"))
4809             {
4810               free (vars);
4811               goto error;
4812             }
4813           lex_match (lexer, T_EQUALS);
4814
4815           enum ctables_vlabel vlabel;
4816           if (lex_match_id (lexer, "DEFAULT"))
4817             vlabel = (enum ctables_vlabel) settings_get_show_variables ();
4818           else if (lex_match_id (lexer, "NAME"))
4819             vlabel = CTVL_NAME;
4820           else if (lex_match_id (lexer, "LABEL"))
4821             vlabel = CTVL_LABEL;
4822           else if (lex_match_id (lexer, "BOTH"))
4823             vlabel = CTVL_BOTH;
4824           else if (lex_match_id (lexer, "NONE"))
4825             vlabel = CTVL_NONE;
4826           else
4827             {
4828               lex_error_expecting (lexer, "DEFAULT", "NAME", "LABEL",
4829                                    "BOTH", "NONE");
4830               free (vars);
4831               goto error;
4832             }
4833
4834           for (size_t i = 0; i < n_vars; i++)
4835             ct->vlabels[var_get_dict_index (vars[i])] = vlabel;
4836           free (vars);
4837         }
4838       else if (lex_match_id (lexer, "MRSETS"))
4839         {
4840           if (!lex_force_match_id (lexer, "COUNTDUPLICATES"))
4841             goto error;
4842           lex_match (lexer, T_EQUALS);
4843           if (!parse_bool (lexer, &ct->mrsets_count_duplicates))
4844             goto error;
4845         }
4846       else if (lex_match_id (lexer, "SMISSING"))
4847         {
4848           if (lex_match_id (lexer, "VARIABLE"))
4849             ct->smissing_listwise = false;
4850           else if (lex_match_id (lexer, "LISTWISE"))
4851             ct->smissing_listwise = true;
4852           else
4853             {
4854               lex_error_expecting (lexer, "VARIABLE", "LISTWISE");
4855               goto error;
4856             }
4857         }
4858       else if (lex_match_id (lexer, "PCOMPUTE"))
4859         {
4860           if (!ctables_parse_pcompute (lexer, ct))
4861             goto error;
4862         }
4863       else if (lex_match_id (lexer, "PPROPERTIES"))
4864         {
4865           if (!ctables_parse_pproperties (lexer, ct))
4866             goto error;
4867         }
4868       else if (lex_match_id (lexer, "WEIGHT"))
4869         {
4870           if (!lex_force_match_id (lexer, "VARIABLE"))
4871             goto error;
4872           lex_match (lexer, T_EQUALS);
4873           ct->e_weight = parse_variable (lexer, dataset_dict (ds));
4874           if (!ct->e_weight)
4875             goto error;
4876         }
4877       else if (lex_match_id (lexer, " HIDESMALLCOUNTS"))
4878         {
4879           if (lex_match_id (lexer, "COUNT"))
4880             {
4881               lex_match (lexer, T_EQUALS);
4882               if (!lex_force_int_range (lexer, "HIDESMALLCOUNTS COUNT",
4883                                         2, INT_MAX))
4884                 goto error;
4885               ct->hide_threshold = lex_integer (lexer);
4886               lex_get (lexer);
4887             }
4888           else if (ct->hide_threshold == 0)
4889             ct->hide_threshold = 5;
4890         }
4891       else
4892         {
4893           lex_error_expecting (lexer, "FORMAT", "VLABELS", "MRSETS",
4894                                "SMISSING", "PCOMPUTE", "PPROPERTIES",
4895                                "WEIGHT", "HIDESMALLCOUNTS", "TABLE");
4896           goto error;
4897         }
4898
4899       if (!lex_force_match (lexer, T_SLASH))
4900         goto error;
4901     }
4902
4903   size_t allocated_tables = 0;
4904   do
4905     {
4906       if (ct->n_tables >= allocated_tables)
4907         ct->tables = x2nrealloc (ct->tables, &allocated_tables,
4908                                  sizeof *ct->tables);
4909
4910       struct ctables_category *cat = xmalloc (sizeof *cat);
4911       *cat = (struct ctables_category) {
4912         .type = CCT_VALUE,
4913         .include_missing = false,
4914         .sort_ascending = true,
4915       };
4916
4917       struct ctables_categories *c = xmalloc (sizeof *c);
4918       size_t n_vars = dict_get_n_vars (dataset_dict (ds));
4919       *c = (struct ctables_categories) {
4920         .n_refs = n_vars,
4921         .cats = cat,
4922         .n_cats = 1,
4923         .show_empty = true,
4924       };
4925
4926       struct ctables_categories **categories = xnmalloc (n_vars,
4927                                                          sizeof *categories);
4928       for (size_t i = 0; i < n_vars; i++)
4929         categories[i] = c;
4930
4931       struct ctables_table *t = xmalloc (sizeof *t);
4932       *t = (struct ctables_table) {
4933         .ctables = ct,
4934         .slabels_axis = PIVOT_AXIS_COLUMN,
4935         .slabels_visible = true,
4936         .clabels_values_map = HMAP_INITIALIZER (t->clabels_values_map),
4937         .label_axis = {
4938           [PIVOT_AXIS_ROW] = PIVOT_AXIS_ROW,
4939           [PIVOT_AXIS_COLUMN] = PIVOT_AXIS_COLUMN,
4940           [PIVOT_AXIS_LAYER] = PIVOT_AXIS_LAYER,
4941         },
4942         .clabels_from_axis = PIVOT_AXIS_LAYER,
4943         .categories = categories,
4944         .n_categories = n_vars,
4945         .cilevel = 95,
4946       };
4947       ct->tables[ct->n_tables++] = t;
4948
4949       lex_match (lexer, T_EQUALS);
4950       if (!ctables_axis_parse (lexer, dataset_dict (ds), ct, t, PIVOT_AXIS_ROW))
4951         goto error;
4952       if (lex_match (lexer, T_BY))
4953         {
4954           if (!ctables_axis_parse (lexer, dataset_dict (ds),
4955                                    ct, t, PIVOT_AXIS_COLUMN))
4956             goto error;
4957
4958           if (lex_match (lexer, T_BY))
4959             {
4960               if (!ctables_axis_parse (lexer, dataset_dict (ds),
4961                                        ct, t, PIVOT_AXIS_LAYER))
4962                 goto error;
4963             }
4964         }
4965
4966       if (!t->axes[PIVOT_AXIS_ROW] && !t->axes[PIVOT_AXIS_COLUMN]
4967           && !t->axes[PIVOT_AXIS_LAYER])
4968         {
4969           lex_error (lexer, _("At least one variable must be specified."));
4970           goto error;
4971         }
4972
4973       const struct ctables_axis *scales[PIVOT_N_AXES];
4974       size_t n_scales = 0;
4975       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
4976         {
4977           scales[a] = find_scale (t->axes[a]);
4978           if (scales[a])
4979             n_scales++;
4980         }
4981       if (n_scales > 1)
4982         {
4983           msg (SE, _("Scale variables may appear only on one axis."));
4984           if (scales[PIVOT_AXIS_ROW])
4985             msg_at (SN, scales[PIVOT_AXIS_ROW]->loc,
4986                     _("This scale variable appears on the rows axis."));
4987           if (scales[PIVOT_AXIS_COLUMN])
4988             msg_at (SN, scales[PIVOT_AXIS_COLUMN]->loc,
4989                     _("This scale variable appears on the columns axis."));
4990           if (scales[PIVOT_AXIS_LAYER])
4991             msg_at (SN, scales[PIVOT_AXIS_LAYER]->loc,
4992                     _("This scale variable appears on the layer axis."));
4993           goto error;
4994         }
4995
4996       const struct ctables_axis *summaries[PIVOT_N_AXES];
4997       size_t n_summaries = 0;
4998       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
4999         {
5000           summaries[a] = (scales[a]
5001                           ? scales[a]
5002                           : find_categorical_summary_spec (t->axes[a]));
5003           if (summaries[a])
5004             n_summaries++;
5005         }
5006       if (n_summaries > 1)
5007         {
5008           msg (SE, _("Summaries may appear only on one axis."));
5009           if (summaries[PIVOT_AXIS_ROW])
5010             msg_at (SN, summaries[PIVOT_AXIS_ROW]->loc,
5011                     _("This variable on the rows axis has a summary."));
5012           if (summaries[PIVOT_AXIS_COLUMN])
5013             msg_at (SN, summaries[PIVOT_AXIS_COLUMN]->loc,
5014                     _("This variable on the columns axis has a summary."));
5015           if (summaries[PIVOT_AXIS_LAYER])
5016             msg_at (SN, summaries[PIVOT_AXIS_LAYER]->loc,
5017                     _("This variable on the layers axis has a summary."));
5018           goto error;
5019         }
5020       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
5021         if (n_summaries ? summaries[a] : t->axes[a])
5022           {
5023             t->summary_axis = a;
5024             break;
5025           }
5026
5027       if (lex_token (lexer) == T_ENDCMD)
5028         {
5029           if (!ctables_prepare_table (t))
5030             goto error;
5031           break;
5032         }
5033       if (!lex_force_match (lexer, T_SLASH))
5034         break;
5035
5036       while (!lex_match_id (lexer, "TABLE") && lex_token (lexer) != T_ENDCMD)
5037         {
5038           if (lex_match_id (lexer, "SLABELS"))
5039             {
5040               while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
5041                 {
5042                   if (lex_match_id (lexer, "POSITION"))
5043                     {
5044                       lex_match (lexer, T_EQUALS);
5045                       if (lex_match_id (lexer, "COLUMN"))
5046                         t->slabels_axis = PIVOT_AXIS_COLUMN;
5047                       else if (lex_match_id (lexer, "ROW"))
5048                         t->slabels_axis = PIVOT_AXIS_ROW;
5049                       else if (lex_match_id (lexer, "LAYER"))
5050                         t->slabels_axis = PIVOT_AXIS_LAYER;
5051                       else
5052                         {
5053                           lex_error_expecting (lexer, "COLUMN", "ROW", "LAYER");
5054                           goto error;
5055                         }
5056                     }
5057                   else if (lex_match_id (lexer, "VISIBLE"))
5058                     {
5059                       lex_match (lexer, T_EQUALS);
5060                       if (!parse_bool (lexer, &t->slabels_visible))
5061                         goto error;
5062                     }
5063                   else
5064                     {
5065                       lex_error_expecting (lexer, "POSITION", "VISIBLE");
5066                       goto error;
5067                     }
5068                 }
5069             }
5070           else if (lex_match_id (lexer, "CLABELS"))
5071             {
5072               while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
5073                 {
5074                   if (lex_match_id (lexer, "AUTO"))
5075                     {
5076                       t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_ROW;
5077                       t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_COLUMN;
5078                     }
5079                   else if (lex_match_id (lexer, "ROWLABELS"))
5080                     {
5081                       lex_match (lexer, T_EQUALS);
5082                       if (lex_match_id (lexer, "OPPOSITE"))
5083                         t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_COLUMN;
5084                       else if (lex_match_id (lexer, "LAYER"))
5085                         t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_LAYER;
5086                       else
5087                         {
5088                           lex_error_expecting (lexer, "OPPOSITE", "LAYER");
5089                           goto error;
5090                         }
5091                     }
5092                   else if (lex_match_id (lexer, "COLLABELS"))
5093                     {
5094                       lex_match (lexer, T_EQUALS);
5095                       if (lex_match_id (lexer, "OPPOSITE"))
5096                         t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_ROW;
5097                       else if (lex_match_id (lexer, "LAYER"))
5098                         t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_LAYER;
5099                       else
5100                         {
5101                           lex_error_expecting (lexer, "OPPOSITE", "LAYER");
5102                           goto error;
5103                         }
5104                     }
5105                   else
5106                     {
5107                       lex_error_expecting (lexer, "AUTO", "ROWLABELS",
5108                                            "COLLABELS");
5109                       goto error;
5110                     }
5111                 }
5112             }
5113           else if (lex_match_id (lexer, "CRITERIA"))
5114             {
5115               if (!lex_force_match_id (lexer, "CILEVEL"))
5116                 goto error;
5117               lex_match (lexer, T_EQUALS);
5118
5119               if (!lex_force_num_range_halfopen (lexer, "CILEVEL", 0, 100))
5120                 goto error;
5121               t->cilevel = lex_number (lexer);
5122               lex_get (lexer);
5123             }
5124           else if (lex_match_id (lexer, "CATEGORIES"))
5125             {
5126               if (!ctables_table_parse_categories (lexer, dataset_dict (ds),
5127                                                    ct, t))
5128                 goto error;
5129             }
5130           else if (lex_match_id (lexer, "TITLES"))
5131             {
5132               do
5133                 {
5134                   char **textp;
5135                   if (lex_match_id (lexer, "CAPTION"))
5136                     textp = &t->caption;
5137                   else if (lex_match_id (lexer, "CORNER"))
5138                     textp = &t->corner;
5139                   else if (lex_match_id (lexer, "TITLE"))
5140                     textp = &t->title;
5141                   else
5142                     {
5143                       lex_error_expecting (lexer, "CAPTION", "CORNER", "TITLE");
5144                       goto error;
5145                     }
5146                   lex_match (lexer, T_EQUALS);
5147
5148                   struct string s = DS_EMPTY_INITIALIZER;
5149                   while (lex_is_string (lexer))
5150                     {
5151                       if (!ds_is_empty (&s))
5152                         ds_put_byte (&s, ' ');
5153                       ds_put_substring (&s, lex_tokss (lexer));
5154                       lex_get (lexer);
5155                     }
5156                   free (*textp);
5157                   *textp = ds_steal_cstr (&s);
5158                 }
5159               while (lex_token (lexer) != T_SLASH
5160                      && lex_token (lexer) != T_ENDCMD);
5161             }
5162           else if (lex_match_id (lexer, "SIGTEST"))
5163             {
5164               if (!t->chisq)
5165                 {
5166                   t->chisq = xmalloc (sizeof *t->chisq);
5167                   *t->chisq = (struct ctables_chisq) {
5168                     .alpha = .05,
5169                     .include_mrsets = true,
5170                     .all_visible = true,
5171                   };
5172                 }
5173
5174               do
5175                 {
5176                   if (lex_match_id (lexer, "TYPE"))
5177                     {
5178                       lex_match (lexer, T_EQUALS);
5179                       if (!lex_force_match_id (lexer, "CHISQUARE"))
5180                         goto error;
5181                     }
5182                   else if (lex_match_id (lexer, "ALPHA"))
5183                     {
5184                       lex_match (lexer, T_EQUALS);
5185                       if (!lex_force_num_range_halfopen (lexer, "ALPHA", 0, 1))
5186                         goto error;
5187                       t->chisq->alpha = lex_number (lexer);
5188                       lex_get (lexer);
5189                     }
5190                   else if (lex_match_id (lexer, "INCLUDEMRSETS"))
5191                     {
5192                       lex_match (lexer, T_EQUALS);
5193                       if (parse_bool (lexer, &t->chisq->include_mrsets))
5194                         goto error;
5195                     }
5196                   else if (lex_match_id (lexer, "CATEGORIES"))
5197                     {
5198                       lex_match (lexer, T_EQUALS);
5199                       if (lex_match_id (lexer, "ALLVISIBLE"))
5200                         t->chisq->all_visible = true;
5201                       else if (lex_match_id (lexer, "SUBTOTALS"))
5202                         t->chisq->all_visible = false;
5203                       else
5204                         {
5205                           lex_error_expecting (lexer,
5206                                                "ALLVISIBLE", "SUBTOTALS");
5207                           goto error;
5208                         }
5209                     }
5210                   else
5211                     {
5212                       lex_error_expecting (lexer, "TYPE", "ALPHA",
5213                                            "INCLUDEMRSETS", "CATEGORIES");
5214                       goto error;
5215                     }
5216                 }
5217               while (lex_token (lexer) != T_SLASH
5218                      && lex_token (lexer) != T_ENDCMD);
5219             }
5220           else if (lex_match_id (lexer, "COMPARETEST"))
5221             {
5222               if (!t->pairwise)
5223                 {
5224                   t->pairwise = xmalloc (sizeof *t->pairwise);
5225                   *t->pairwise = (struct ctables_pairwise) {
5226                     .type = PROP,
5227                     .alpha = { .05, .05 },
5228                     .adjust = BONFERRONI,
5229                     .include_mrsets = true,
5230                     .meansvariance_allcats = true,
5231                     .all_visible = true,
5232                     .merge = false,
5233                     .apa_style = true,
5234                     .show_sig = false,
5235                   };
5236                 }
5237
5238               do
5239                 {
5240                   if (lex_match_id (lexer, "TYPE"))
5241                     {
5242                       lex_match (lexer, T_EQUALS);
5243                       if (lex_match_id (lexer, "PROP"))
5244                         t->pairwise->type = PROP;
5245                       else if (lex_match_id (lexer, "MEAN"))
5246                         t->pairwise->type = MEAN;
5247                       else
5248                         {
5249                           lex_error_expecting (lexer, "PROP", "MEAN");
5250                           goto error;
5251                         }
5252                     }
5253                   else if (lex_match_id (lexer, "ALPHA"))
5254                     {
5255                       lex_match (lexer, T_EQUALS);
5256
5257                       if (!lex_force_num_range_open (lexer, "ALPHA", 0, 1))
5258                         goto error;
5259                       double a0 = lex_number (lexer);
5260                       lex_get (lexer);
5261
5262                       lex_match (lexer, T_COMMA);
5263                       if (lex_is_number (lexer))
5264                         {
5265                           if (!lex_force_num_range_open (lexer, "ALPHA", 0, 1))
5266                             goto error;
5267                           double a1 = lex_number (lexer);
5268                           lex_get (lexer);
5269
5270                           t->pairwise->alpha[0] = MIN (a0, a1);
5271                           t->pairwise->alpha[1] = MAX (a0, a1);
5272                         }
5273                       else
5274                         t->pairwise->alpha[0] = t->pairwise->alpha[1] = a0;
5275                     }
5276                   else if (lex_match_id (lexer, "ADJUST"))
5277                     {
5278                       lex_match (lexer, T_EQUALS);
5279                       if (lex_match_id (lexer, "BONFERRONI"))
5280                         t->pairwise->adjust = BONFERRONI;
5281                       else if (lex_match_id (lexer, "BH"))
5282                         t->pairwise->adjust = BH;
5283                       else if (lex_match_id (lexer, "NONE"))
5284                         t->pairwise->adjust = 0;
5285                       else
5286                         {
5287                           lex_error_expecting (lexer, "BONFERRONI", "BH",
5288                                                "NONE");
5289                           goto error;
5290                         }
5291                     }
5292                   else if (lex_match_id (lexer, "INCLUDEMRSETS"))
5293                     {
5294                       lex_match (lexer, T_EQUALS);
5295                       if (!parse_bool (lexer, &t->pairwise->include_mrsets))
5296                         goto error;
5297                     }
5298                   else if (lex_match_id (lexer, "MEANSVARIANCE"))
5299                     {
5300                       lex_match (lexer, T_EQUALS);
5301                       if (lex_match_id (lexer, "ALLCATS"))
5302                         t->pairwise->meansvariance_allcats = true;
5303                       else if (lex_match_id (lexer, "TESTEDCATS"))
5304                         t->pairwise->meansvariance_allcats = false;
5305                       else
5306                         {
5307                           lex_error_expecting (lexer, "ALLCATS", "TESTEDCATS");
5308                           goto error;
5309                         }
5310                     }
5311                   else if (lex_match_id (lexer, "CATEGORIES"))
5312                     {
5313                       lex_match (lexer, T_EQUALS);
5314                       if (lex_match_id (lexer, "ALLVISIBLE"))
5315                         t->pairwise->all_visible = true;
5316                       else if (lex_match_id (lexer, "SUBTOTALS"))
5317                         t->pairwise->all_visible = false;
5318                       else
5319                         {
5320                           lex_error_expecting (lexer, "ALLVISIBLE",
5321                                                "SUBTOTALS");
5322                           goto error;
5323                         }
5324                     }
5325                   else if (lex_match_id (lexer, "MERGE"))
5326                     {
5327                       lex_match (lexer, T_EQUALS);
5328                       if (!parse_bool (lexer, &t->pairwise->merge))
5329                         goto error;
5330                     }
5331                   else if (lex_match_id (lexer, "STYLE"))
5332                     {
5333                       lex_match (lexer, T_EQUALS);
5334                       if (lex_match_id (lexer, "APA"))
5335                         t->pairwise->apa_style = true;
5336                       else if (lex_match_id (lexer, "SIMPLE"))
5337                         t->pairwise->apa_style = false;
5338                       else
5339                         {
5340                           lex_error_expecting (lexer, "APA", "SIMPLE");
5341                           goto error;
5342                         }
5343                     }
5344                   else if (lex_match_id (lexer, "SHOWSIG"))
5345                     {
5346                       lex_match (lexer, T_EQUALS);
5347                       if (!parse_bool (lexer, &t->pairwise->show_sig))
5348                         goto error;
5349                     }
5350                   else
5351                     {
5352                       lex_error_expecting (lexer, "TYPE", "ALPHA", "ADJUST",
5353                                            "INCLUDEMRSETS", "MEANSVARIANCE",
5354                                            "CATEGORIES", "MERGE", "STYLE",
5355                                            "SHOWSIG");
5356                       goto error;
5357                     }
5358                 }
5359               while (lex_token (lexer) != T_SLASH
5360                      && lex_token (lexer) != T_ENDCMD);
5361             }
5362           else
5363             {
5364               lex_error_expecting (lexer, "TABLE", "SLABELS", "CLABELS",
5365                                    "CRITERIA", "CATEGORIES", "TITLES",
5366                                    "SIGTEST", "COMPARETEST");
5367               goto error;
5368             }
5369
5370           if (!lex_match (lexer, T_SLASH))
5371             break;
5372         }
5373
5374       if (t->label_axis[PIVOT_AXIS_ROW] != PIVOT_AXIS_ROW
5375           && t->label_axis[PIVOT_AXIS_COLUMN] != PIVOT_AXIS_COLUMN)
5376         {
5377           msg (SE, _("ROWLABELS and COLLABELS may not both be specified."));
5378           goto error;
5379         }
5380
5381       if (!ctables_prepare_table (t))
5382         goto error;
5383     }
5384   while (lex_token (lexer) != T_ENDCMD);
5385
5386   bool ok = ctables_execute (ds, ct);
5387   ctables_destroy (ct);
5388   return ok ? CMD_SUCCESS : CMD_FAILURE;
5389
5390 error:
5391   ctables_destroy (ct);
5392   return CMD_FAILURE;
5393 }
5394