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