PPROPERTIES FORMAT
[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_if_nonnull (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           : pivot_value_new_var_value (var, value));
3373 }
3374
3375 static struct pivot_value *
3376 ctables_postcompute_label (const struct ctables_categories *cats,
3377                            const struct ctables_category *cat,
3378                            const struct variable *var,
3379                            const union value *value)
3380 {
3381   struct substring in = ss_cstr (cat->pc->label);
3382   struct substring target = ss_cstr (")LABEL[");
3383
3384   struct string out = DS_EMPTY_INITIALIZER;
3385   for (;;)
3386     {
3387       size_t chunk = ss_find_substring (in, target);
3388       if (chunk == SIZE_MAX)
3389         {
3390           if (ds_is_empty (&out))
3391             return pivot_value_new_user_text (in.string, in.length);
3392           else
3393             {
3394               ds_put_substring (&out, in);
3395               return pivot_value_new_user_text_nocopy (ds_steal_cstr (&out));
3396             }
3397         }
3398
3399       ds_put_substring (&out, ss_head (in, chunk));
3400       ss_advance (&in, chunk + target.length);
3401
3402       struct substring idx_s;
3403       if (!ss_get_until (&in, ']', &idx_s))
3404         goto error;
3405       char *tail;
3406       long int idx = strtol (idx_s.string, &tail, 10);
3407       if (idx < 1 || idx > cats->n_cats || tail != ss_end (idx_s))
3408         goto error;
3409
3410       struct ctables_category *cat2 = &cats->cats[idx - 1];
3411       struct pivot_value *label2
3412         = ctables_category_create_label__ (cat2, var, value);
3413       char *label2_s = pivot_value_to_string_defaults (label2);
3414       ds_put_cstr (&out, label2_s);
3415       free (label2_s);
3416       pivot_value_destroy (label2);
3417     }
3418
3419 error:
3420   ds_destroy (&out);
3421   return pivot_value_new_user_text (cat->pc->label, SIZE_MAX);
3422 }
3423
3424 static struct pivot_value *
3425 ctables_category_create_label (const struct ctables_categories *cats,
3426                                const struct ctables_category *cat,
3427                                const struct variable *var,
3428                                const union value *value)
3429 {
3430   return (cat->type == CCT_POSTCOMPUTE && cat->pc->label
3431           ? ctables_postcompute_label (cats, cat, var, value)
3432           : ctables_category_create_label__ (cat, var, value));
3433 }
3434
3435 static struct ctables_value *
3436 ctables_value_find__ (struct ctables_table *t, const union value *value,
3437                       int width, unsigned int hash)
3438 {
3439   struct ctables_value *clv;
3440   HMAP_FOR_EACH_WITH_HASH (clv, struct ctables_value, node,
3441                            hash, &t->clabels_values_map)
3442     if (value_equal (value, &clv->value, width))
3443       return clv;
3444   return NULL;
3445 }
3446
3447 static void
3448 ctables_value_insert (struct ctables_table *t, const union value *value,
3449                       int width)
3450 {
3451   unsigned int hash = value_hash (value, width, 0);
3452   struct ctables_value *clv = ctables_value_find__ (t, value, width, hash);
3453   if (!clv)
3454     {
3455       clv = xmalloc (sizeof *clv);
3456       value_clone (&clv->value, value, width);
3457       hmap_insert (&t->clabels_values_map, &clv->node, hash);
3458     }
3459 }
3460
3461 static struct ctables_value *
3462 ctables_value_find (struct ctables_table *t,
3463                     const union value *value, int width)
3464 {
3465   return ctables_value_find__ (t, value, width,
3466                                value_hash (value, width, 0));
3467 }
3468
3469 static void
3470 ctables_table_add_section (struct ctables_table *t, enum pivot_axis_type a,
3471                            size_t ix[PIVOT_N_AXES])
3472 {
3473   if (a < PIVOT_N_AXES)
3474     {
3475       size_t limit = MAX (t->stacks[a].n, 1);
3476       for (ix[a] = 0; ix[a] < limit; ix[a]++)
3477         ctables_table_add_section (t, a + 1, ix);
3478     }
3479   else
3480     {
3481       struct ctables_section *s = &t->sections[t->n_sections++];
3482       *s = (struct ctables_section) {
3483         .table = t,
3484         .cells = HMAP_INITIALIZER (s->cells),
3485       };
3486       for (a = 0; a < PIVOT_N_AXES; a++)
3487         if (t->stacks[a].n)
3488           {
3489             struct ctables_nest *nest = &t->stacks[a].nests[ix[a]];
3490             s->nests[a] = nest;
3491             s->occurrences[a] = xnmalloc (nest->n, sizeof *s->occurrences[a]);
3492             for (size_t i = 0; i < nest->n; i++)
3493               hmap_init (&s->occurrences[a][i]);
3494         }
3495       for (size_t i = 0; i < N_CTDTS; i++)
3496         hmap_init (&s->domains[i]);
3497     }
3498 }
3499
3500 static double
3501 ctpo_add (double a, double b)
3502 {
3503   return a + b;
3504 }
3505
3506 static double
3507 ctpo_sub (double a, double b)
3508 {
3509   return a - b;
3510 }
3511
3512 static double
3513 ctpo_mul (double a, double b)
3514 {
3515   return a * b;
3516 }
3517
3518 static double
3519 ctpo_div (double a, double b)
3520 {
3521   return b ? a / b : SYSMIS;
3522 }
3523
3524 static double
3525 ctpo_pow (double a, double b)
3526 {
3527   int save_errno = errno;
3528   errno = 0;
3529   double result = pow (a, b);
3530   if (errno)
3531     result = SYSMIS;
3532   errno = save_errno;
3533   return result;
3534 }
3535
3536 static double
3537 ctpo_neg (double a, double b UNUSED)
3538 {
3539   return -a;
3540 }
3541
3542 struct ctables_pcexpr_evaluate_ctx
3543   {
3544     const struct ctables_cell *cell;
3545     const struct ctables_section *section;
3546     const struct ctables_categories *cats;
3547     enum pivot_axis_type pc_a;
3548     size_t pc_a_idx;
3549     size_t summary_idx;
3550   };
3551
3552 static double ctables_pcexpr_evaluate (
3553   const struct ctables_pcexpr_evaluate_ctx *, const struct ctables_pcexpr *);
3554
3555 static double
3556 ctables_pcexpr_evaluate_nonterminal (
3557   const struct ctables_pcexpr_evaluate_ctx *ctx,
3558   const struct ctables_pcexpr *e, size_t n_args,
3559   double evaluate (double, double))
3560 {
3561   double args[2] = { 0, 0 };
3562   for (size_t i = 0; i < n_args; i++)
3563     {
3564       args[i] = ctables_pcexpr_evaluate (ctx, e->subs[i]);
3565       if (!isfinite (args[i]) || args[i] == SYSMIS)
3566         return SYSMIS;
3567     }
3568   return evaluate (args[0], args[1]);
3569 }
3570
3571 static double
3572 ctables_pcexpr_evaluate_category (const struct ctables_pcexpr_evaluate_ctx *ctx,
3573                                   const struct ctables_cell_value *pc_cv)
3574 {
3575   const struct ctables_section *s = ctx->section;
3576
3577   size_t hash = 0;
3578   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3579     {
3580       const struct ctables_nest *nest = s->nests[a];
3581       for (size_t i = 0; i < nest->n; i++)
3582         if (i != nest->scale_idx)
3583           {
3584             const struct ctables_cell_value *cv
3585               = (a == ctx->pc_a && i == ctx->pc_a_idx ? pc_cv
3586                  : &ctx->cell->axes[a].cvs[i]);
3587             hash = hash_pointer (cv->category, hash);
3588             if (cv->category->type != CCT_TOTAL
3589                 && cv->category->type != CCT_SUBTOTAL
3590                 && cv->category->type != CCT_POSTCOMPUTE)
3591               hash = value_hash (&cv->value,
3592                                  var_get_width (nest->vars[i]), hash);
3593           }
3594     }
3595
3596   struct ctables_cell *tc;
3597   HMAP_FOR_EACH_WITH_HASH (tc, struct ctables_cell, node, hash, &s->cells)
3598     {
3599       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3600         {
3601           const struct ctables_nest *nest = s->nests[a];
3602           for (size_t i = 0; i < nest->n; i++)
3603             if (i != nest->scale_idx)
3604               {
3605                 const struct ctables_cell_value *p_cv
3606                   = (a == ctx->pc_a && i == ctx->pc_a_idx ? pc_cv
3607                      : &ctx->cell->axes[a].cvs[i]);
3608                 const struct ctables_cell_value *t_cv = &tc->axes[a].cvs[i];
3609                 if (p_cv->category != t_cv->category
3610                     || (p_cv->category->type != CCT_TOTAL
3611                         && p_cv->category->type != CCT_SUBTOTAL
3612                         && p_cv->category->type != CCT_POSTCOMPUTE
3613                         && !value_equal (&p_cv->value,
3614                                          &t_cv->value,
3615                                          var_get_width (nest->vars[i]))))
3616                   goto not_equal;
3617               }
3618         }
3619
3620       goto found;
3621
3622     not_equal: ;
3623     }
3624   return 0;
3625
3626 found: ;
3627   const struct ctables_table *t = s->table;
3628   const struct ctables_nest *specs_nest = s->nests[t->summary_axis];
3629   const struct ctables_summary_spec_set *specs = &specs_nest->specs[tc->sv];
3630   return ctables_summary_value (tc, &tc->summaries[ctx->summary_idx],
3631                                 &specs->specs[ctx->summary_idx]);
3632 }
3633
3634 static double
3635 ctables_pcexpr_evaluate (const struct ctables_pcexpr_evaluate_ctx *ctx,
3636                          const struct ctables_pcexpr *e)
3637 {
3638   switch (e->op)
3639     {
3640     case CTPO_CONSTANT:
3641       return e->number;
3642
3643     case CTPO_CAT_RANGE:
3644       {
3645         struct ctables_cell_value cv = {
3646           .category = ctables_find_category_for_postcompute (ctx->cats, e)
3647         };
3648         assert (cv.category != NULL);
3649
3650         struct hmap *occurrences = &ctx->section->occurrences[ctx->pc_a][ctx->pc_a_idx];
3651         const struct ctables_occurrence *o;
3652
3653         double sum = 0.0;
3654         const struct variable *var = ctx->section->nests[ctx->pc_a]->vars[ctx->pc_a_idx];
3655         HMAP_FOR_EACH (o, struct ctables_occurrence, node, occurrences)
3656           if (ctables_categories_match (ctx->cats, &o->value, var) == cv.category)
3657             {
3658               cv.value = o->value;
3659               sum += ctables_pcexpr_evaluate_category (ctx, &cv);
3660             }
3661         return sum;
3662       }
3663
3664     case CTPO_CAT_NUMBER:
3665     case CTPO_CAT_STRING:
3666     case CTPO_CAT_MISSING:
3667     case CTPO_CAT_OTHERNM:
3668     case CTPO_CAT_SUBTOTAL:
3669     case CTPO_CAT_TOTAL:
3670       {
3671         struct ctables_cell_value cv = {
3672           .category = ctables_find_category_for_postcompute (ctx->cats, e),
3673           .value = { .f = e->number },
3674         };
3675         assert (cv.category != NULL);
3676         return ctables_pcexpr_evaluate_category (ctx, &cv);
3677       }
3678
3679     case CTPO_ADD:
3680       return ctables_pcexpr_evaluate_nonterminal (ctx, e, 2, ctpo_add);
3681
3682     case CTPO_SUB:
3683       return ctables_pcexpr_evaluate_nonterminal (ctx, e, 2, ctpo_sub);
3684
3685     case CTPO_MUL:
3686       return ctables_pcexpr_evaluate_nonterminal (ctx, e, 2, ctpo_mul);
3687
3688     case CTPO_DIV:
3689       return ctables_pcexpr_evaluate_nonterminal (ctx, e, 2, ctpo_div);
3690
3691     case CTPO_POW:
3692       return ctables_pcexpr_evaluate_nonterminal (ctx, e, 2, ctpo_pow);
3693
3694     case CTPO_NEG:
3695       return ctables_pcexpr_evaluate_nonterminal (ctx, e, 1, ctpo_neg);
3696     }
3697
3698   NOT_REACHED ();
3699 }
3700
3701 /* XXX what if there is a postcompute in more than one dimension?? */
3702 static const struct ctables_postcompute *
3703 ctables_cell_postcompute (const struct ctables_section *s,
3704                           const struct ctables_cell *cell,
3705                           enum pivot_axis_type *pc_a_p,
3706                           size_t *pc_a_idx_p)
3707 {
3708   assert (cell->postcompute);
3709   for (enum pivot_axis_type pc_a = 0; ; pc_a++)
3710     {
3711       assert (pc_a < PIVOT_N_AXES);
3712       for (size_t pc_a_idx = 0; pc_a_idx < s->nests[pc_a]->n; pc_a_idx++)
3713         {
3714           const struct ctables_cell_value *cv = &cell->axes[pc_a].cvs[pc_a_idx];
3715           if (cv->category->type == CCT_POSTCOMPUTE)
3716             {
3717               if (pc_a_p)
3718                 *pc_a_p = pc_a;
3719               if (pc_a_idx_p)
3720                 *pc_a_idx_p = pc_a_idx;
3721               return cv->category->pc;
3722             }
3723         }
3724     }
3725
3726   NOT_REACHED ();
3727 }
3728
3729 static double
3730 ctables_cell_calculate_postcompute (const struct ctables_section *s,
3731                                     const struct ctables_cell *cell,
3732                                     const struct ctables_summary_spec *ss,
3733                                     struct fmt_spec *format,
3734                                     bool *is_ctables_format,
3735                                     size_t summary_idx)
3736 {
3737   enum pivot_axis_type pc_a;
3738   size_t pc_a_idx;
3739   const struct ctables_postcompute *pc = ctables_cell_postcompute (
3740     s, cell, &pc_a, &pc_a_idx);
3741
3742   if (pc->specs)
3743     {
3744       for (size_t i = 0; i < pc->specs->n; i++)
3745         {
3746           const struct ctables_summary_spec *ss2 = &pc->specs->specs[i];
3747           if (ss->function == ss2->function
3748               && ss->percentile == ss2->percentile)
3749             {
3750               *format = ss2->format;
3751               *is_ctables_format = ss2->is_ctables_format;
3752               break;
3753             }
3754         }
3755     }
3756
3757   const struct variable *var = s->nests[pc_a]->vars[pc_a_idx];
3758   const struct ctables_categories *cats = s->table->categories[
3759     var_get_dict_index (var)];
3760   struct ctables_pcexpr_evaluate_ctx ctx = {
3761     .cell = cell,
3762     .section = s,
3763     .cats = cats,
3764     .pc_a = pc_a,
3765     .pc_a_idx = pc_a_idx,
3766     .summary_idx = summary_idx,
3767   };
3768   return ctables_pcexpr_evaluate (&ctx, pc->expr);
3769 }
3770
3771 static void
3772 ctables_table_output (struct ctables *ct, struct ctables_table *t)
3773 {
3774   struct pivot_table *pt = pivot_table_create__ (
3775     (t->title
3776      ? pivot_value_new_user_text (t->title, SIZE_MAX)
3777      : pivot_value_new_text (N_("Custom Tables"))),
3778     "Custom Tables");
3779   if (t->caption)
3780     pivot_table_set_caption (
3781       pt, pivot_value_new_user_text (t->caption, SIZE_MAX));
3782   if (t->corner)
3783     pivot_table_set_corner_text (
3784       pt, pivot_value_new_user_text (t->corner, SIZE_MAX));
3785
3786   bool summary_dimension = (t->summary_axis != t->slabels_axis
3787                             || (!t->slabels_visible
3788                                 && t->summary_specs.n > 1));
3789   if (summary_dimension)
3790     {
3791       struct pivot_dimension *d = pivot_dimension_create (
3792         pt, t->slabels_axis, N_("Statistics"));
3793       const struct ctables_summary_spec_set *specs = &t->summary_specs;
3794       if (!t->slabels_visible)
3795         d->hide_all_labels = true;
3796       for (size_t i = 0; i < specs->n; i++)
3797         pivot_category_create_leaf (
3798           d->root, pivot_value_new_text (specs->specs[i].label));
3799     }
3800
3801   bool categories_dimension = t->clabels_example != NULL;
3802   if (categories_dimension)
3803     {
3804       struct pivot_dimension *d = pivot_dimension_create (
3805         pt, t->label_axis[t->clabels_from_axis],
3806         t->clabels_from_axis == PIVOT_AXIS_ROW
3807         ? N_("Row Categories")
3808         : N_("Column Categories"));
3809       const struct variable *var = t->clabels_example;
3810       const struct ctables_categories *c = t->categories[var_get_dict_index (var)];
3811       for (size_t i = 0; i < t->n_clabels_values; i++)
3812         {
3813           const struct ctables_value *value = t->clabels_values[i];
3814           const struct ctables_category *cat = ctables_categories_match (c, &value->value, var);
3815           assert (cat != NULL);
3816           pivot_category_create_leaf (d->root, ctables_category_create_label (
3817                                         c, cat, t->clabels_example,
3818                                         &value->value));
3819         }
3820     }
3821
3822   pivot_table_set_look (pt, ct->look);
3823   struct pivot_dimension *d[PIVOT_N_AXES];
3824   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3825     {
3826       static const char *names[] = {
3827         [PIVOT_AXIS_ROW] = N_("Rows"),
3828         [PIVOT_AXIS_COLUMN] = N_("Columns"),
3829         [PIVOT_AXIS_LAYER] = N_("Layers"),
3830       };
3831       d[a] = (t->axes[a] || a == t->summary_axis
3832               ? pivot_dimension_create (pt, a, names[a])
3833               : NULL);
3834       if (!d[a])
3835         continue;
3836
3837       assert (t->axes[a]);
3838
3839       for (size_t i = 0; i < t->stacks[a].n; i++)
3840         {
3841           struct ctables_nest *nest = &t->stacks[a].nests[i];
3842           struct ctables_section **sections = xnmalloc (t->n_sections,
3843                                                         sizeof *sections);
3844           size_t n_sections = 0;
3845
3846           size_t n_total_cells = 0;
3847           size_t max_depth = 0;
3848           for (size_t j = 0; j < t->n_sections; j++)
3849             if (t->sections[j].nests[a] == nest)
3850               {
3851                 struct ctables_section *s = &t->sections[j];
3852                 sections[n_sections++] = s;
3853                 n_total_cells += s->cells.count;
3854
3855                 size_t depth = s->nests[a]->n;
3856                 max_depth = MAX (depth, max_depth);
3857               }
3858
3859           struct ctables_cell **sorted = xnmalloc (n_total_cells,
3860                                                    sizeof *sorted);
3861           size_t n_sorted = 0;
3862
3863           for (size_t j = 0; j < n_sections; j++)
3864             {
3865               struct ctables_section *s = sections[j];
3866
3867               struct ctables_cell *cell;
3868               HMAP_FOR_EACH (cell, struct ctables_cell, node, &s->cells)
3869                 if (!cell->hide)
3870                   sorted[n_sorted++] = cell;
3871               assert (n_sorted <= n_total_cells);
3872             }
3873
3874           struct ctables_cell_sort_aux aux = { .nest = nest, .a = a };
3875           sort (sorted, n_sorted, sizeof *sorted, ctables_cell_compare_3way, &aux);
3876
3877 #if 0
3878           for (size_t j = 0; j < n_sorted; j++)
3879             {
3880               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);
3881             }
3882           printf ("\n");
3883 #endif
3884           
3885           struct ctables_level
3886             {
3887               enum ctables_level_type
3888                 {
3889                   CTL_VAR,          /* Variable label for nest->vars[var_idx]. */
3890                   CTL_CATEGORY,     /* Category for nest->vars[var_idx]. */
3891                   CTL_SUMMARY,      /* Summary functions. */
3892                 }
3893                 type;
3894
3895               enum settings_value_show vlabel; /* CTL_VAR only. */
3896               size_t var_idx;
3897             };
3898           struct ctables_level *levels = xnmalloc (1 + 2 * max_depth, sizeof *levels);
3899           size_t n_levels = 0;
3900           for (size_t k = 0; k < nest->n; k++)
3901             {
3902               enum ctables_vlabel vlabel = ct->vlabels[var_get_dict_index (nest->vars[k])];
3903               if (vlabel != CTVL_NONE)
3904                 {
3905                   levels[n_levels++] = (struct ctables_level) {
3906                     .type = CTL_VAR,
3907                     .vlabel = (enum settings_value_show) vlabel,
3908                     .var_idx = k,
3909                   };
3910                 }
3911
3912               if (nest->scale_idx != k
3913                   && (k != nest->n - 1 || t->label_axis[a] == a))
3914                 {
3915                   levels[n_levels++] = (struct ctables_level) {
3916                     .type = CTL_CATEGORY,
3917                     .var_idx = k,
3918                   };
3919                 }
3920             }
3921
3922           if (!summary_dimension && a == t->slabels_axis)
3923             {
3924               levels[n_levels++] = (struct ctables_level) {
3925                 .type = CTL_SUMMARY,
3926                 .var_idx = SIZE_MAX,
3927               };
3928             }
3929
3930           /* Pivot categories:
3931
3932              - variable label for nest->vars[0], if vlabel != CTVL_NONE
3933              - category for nest->vars[0], if nest->scale_idx != 0
3934              - variable label for nest->vars[1], if vlabel != CTVL_NONE
3935              - category for nest->vars[1], if nest->scale_idx != 1
3936              ...
3937              - variable label for nest->vars[n - 1], if vlabel != CTVL_NONE
3938              - category for nest->vars[n - 1], if t->label_axis[a] == a && nest->scale_idx != n - 1.
3939              - summary function, if 'a == t->slabels_axis && a ==
3940              t->summary_axis'.
3941
3942              Additional dimensions:
3943
3944              - If 'a == t->slabels_axis && a != t->summary_axis', add a summary
3945              dimension.
3946              - If 't->label_axis[b] == a' for some 'b != a', add a category
3947              dimension to 'a'.
3948           */
3949
3950
3951           struct pivot_category **groups = xnmalloc (1 + 2 * max_depth, sizeof *groups);
3952           int prev_leaf = 0;
3953           for (size_t j = 0; j < n_sorted; j++)
3954             {
3955               struct ctables_cell *cell = sorted[j];
3956               struct ctables_cell *prev = j > 0 ? sorted[j - 1] : NULL;
3957
3958               size_t n_common = 0;
3959               if (j > 0)
3960                 {
3961                   for (; n_common < n_levels; n_common++)
3962                     {
3963                       const struct ctables_level *level = &levels[n_common];
3964                       if (level->type == CTL_CATEGORY)
3965                         {
3966                           size_t var_idx = level->var_idx;
3967                           const struct ctables_category *c = cell->axes[a].cvs[var_idx].category;
3968                           if (prev->axes[a].cvs[var_idx].category != c)
3969                             break;
3970                           else if (c->type != CCT_SUBTOTAL
3971                                    && c->type != CCT_TOTAL
3972                                    && c->type != CCT_POSTCOMPUTE
3973                                    && !value_equal (&prev->axes[a].cvs[var_idx].value,
3974                                                     &cell->axes[a].cvs[var_idx].value,
3975                                                     var_get_type (nest->vars[var_idx])))
3976                             break;
3977                         }
3978                     }
3979                 }
3980
3981               for (size_t k = n_common; k < n_levels; k++)
3982                 {
3983                   const struct ctables_level *level = &levels[k];
3984                   struct pivot_category *parent = k ? groups[k - 1] : d[a]->root;
3985                   if (level->type == CTL_SUMMARY)
3986                     {
3987                       assert (k == n_levels - 1);
3988
3989                       const struct ctables_summary_spec_set *specs = &t->summary_specs;
3990                       for (size_t m = 0; m < specs->n; m++)
3991                         {
3992                           int leaf = pivot_category_create_leaf (
3993                             parent, pivot_value_new_text (specs->specs[m].label));
3994                           if (!m)
3995                             prev_leaf = leaf;
3996                         }
3997                     }
3998                   else
3999                     {
4000                       const struct variable *var = nest->vars[level->var_idx];
4001                       struct pivot_value *label;
4002                       if (level->type == CTL_VAR)
4003                         {
4004                           label = pivot_value_new_variable (var);
4005                           label->variable.show = level->vlabel;
4006                         }
4007                       else if (level->type == CTL_CATEGORY)
4008                         {
4009                           const struct ctables_cell_value *cv = &cell->axes[a].cvs[level->var_idx];
4010                           label = ctables_category_create_label (
4011                             t->categories[var_get_dict_index (var)],
4012                             cv->category, var, &cv->value);
4013                         }
4014                       else
4015                         NOT_REACHED ();
4016
4017                       if (k == n_levels - 1)
4018                         prev_leaf = pivot_category_create_leaf (parent, label);
4019                       else
4020                         groups[k] = pivot_category_create_group__ (parent, label);
4021                     }
4022                 }
4023
4024               cell->axes[a].leaf = prev_leaf;
4025             }
4026           free (sorted);
4027           free (groups);
4028         }
4029     }
4030
4031   for (size_t i = 0; i < t->n_sections; i++)
4032     {
4033       struct ctables_section *s = &t->sections[i];
4034
4035       struct ctables_cell *cell;
4036       HMAP_FOR_EACH (cell, struct ctables_cell, node, &s->cells)
4037         {
4038           if (cell->hide)
4039             continue;
4040
4041           const struct ctables_nest *specs_nest = s->nests[t->summary_axis];
4042           const struct ctables_summary_spec_set *specs = &specs_nest->specs[cell->sv];
4043           for (size_t j = 0; j < specs->n; j++)
4044             {
4045               size_t dindexes[5];
4046               size_t n_dindexes = 0;
4047
4048               if (summary_dimension)
4049                 dindexes[n_dindexes++] = specs->specs[j].axis_idx;
4050
4051               if (categories_dimension)
4052                 {
4053                   const struct ctables_nest *clabels_nest = s->nests[t->clabels_from_axis];
4054                   const struct variable *var = clabels_nest->vars[clabels_nest->n - 1];
4055                   const union value *value = &cell->axes[t->clabels_from_axis].cvs[clabels_nest->n - 1].value;
4056                   const struct ctables_value *ctv = ctables_value_find (t, value, var_get_width (var));
4057                   if (!ctv)
4058                     continue;
4059                   dindexes[n_dindexes++] = ctv->leaf;
4060                 }
4061
4062               for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
4063                 if (d[a])
4064                   {
4065                     int leaf = cell->axes[a].leaf;
4066                     if (a == t->summary_axis && !summary_dimension)
4067                       leaf += j;
4068                     dindexes[n_dindexes++] = leaf;
4069                   }
4070
4071               const struct ctables_summary_spec *ss = &specs->specs[j];
4072
4073               struct fmt_spec format = specs->specs[j].format;
4074               bool is_ctables_format = ss->is_ctables_format;
4075               double d = (cell->postcompute
4076                           ? ctables_cell_calculate_postcompute (
4077                             s, cell, ss, &format, &is_ctables_format, j)
4078                           : ctables_summary_value (cell, &cell->summaries[j],
4079                                                    ss));
4080
4081               struct pivot_value *value;
4082               if (ct->hide_threshold != 0
4083                   && d < ct->hide_threshold
4084                   && ctables_summary_function_is_count (ss->function))
4085                 {
4086                   value = pivot_value_new_user_text_nocopy (
4087                     xasprintf ("<%d", ct->hide_threshold));
4088                 }
4089               else if (d == 0 && ct->zero)
4090                 value = pivot_value_new_user_text (ct->zero, SIZE_MAX);
4091               else if (d == SYSMIS && ct->missing)
4092                 value = pivot_value_new_user_text (ct->missing, SIZE_MAX);
4093               else if (is_ctables_format)
4094                 {
4095                   char *s = data_out_stretchy (&(union value) { .f = d },
4096                                                "UTF-8", &format,
4097                                                &ct->ctables_formats, NULL);
4098                   value = pivot_value_new_user_text_nocopy (s);
4099                 }
4100               else
4101                 {
4102                   value = pivot_value_new_number (d);
4103                   value->numeric.format = format;
4104                 }
4105               pivot_table_put (pt, dindexes, n_dindexes, value);
4106             }
4107         }
4108     }
4109
4110   pivot_table_submit (pt);
4111 }
4112
4113 static bool
4114 ctables_check_label_position (struct ctables_table *t, enum pivot_axis_type a)
4115 {
4116   enum pivot_axis_type label_pos = t->label_axis[a];
4117   if (label_pos == a)
4118     return true;
4119
4120   t->clabels_from_axis = a;
4121
4122   const char *subcommand_name = a == PIVOT_AXIS_ROW ? "ROWLABELS" : "COLLABELS";
4123   const char *pos_name = label_pos == PIVOT_AXIS_LAYER ? "LAYER" : "OPPOSITE";
4124
4125   const struct ctables_stack *stack = &t->stacks[a];
4126   if (!stack->n)
4127     return true;
4128
4129   const struct ctables_nest *n0 = &stack->nests[0];
4130   assert (n0->n > 0);
4131   const struct variable *v0 = n0->vars[n0->n - 1];
4132   struct ctables_categories *c0 = t->categories[var_get_dict_index (v0)];
4133   t->clabels_example = v0;
4134
4135   for (size_t i = 0; i < c0->n_cats; i++)
4136     if (c0->cats[i].type == CCT_FUNCTION)
4137       {
4138         msg (SE, _("%s=%s is not allowed with sorting based "
4139                    "on a summary function."),
4140              subcommand_name, pos_name);
4141         return false;
4142       }
4143   if (n0->n - 1 == n0->scale_idx)
4144     {
4145       msg (SE, _("%s=%s requires the variables to be moved to be categorical, "
4146                  "but %s is a scale variable."),
4147            subcommand_name, pos_name, var_get_name (v0));
4148       return false;
4149     }
4150
4151   for (size_t i = 1; i < stack->n; i++)
4152     {
4153       const struct ctables_nest *ni = &stack->nests[i];
4154       assert (ni->n > 0);
4155       const struct variable *vi = ni->vars[ni->n - 1];
4156       struct ctables_categories *ci = t->categories[var_get_dict_index (vi)];
4157
4158       if (ni->n - 1 == ni->scale_idx)
4159         {
4160           msg (SE, _("%s=%s requires the variables to be moved to be "
4161                      "categorical, but %s is a scale variable."),
4162                subcommand_name, pos_name, var_get_name (vi));
4163           return false;
4164         }
4165       if (var_get_width (v0) != var_get_width (vi))
4166         {
4167           msg (SE, _("%s=%s requires the variables to be "
4168                      "moved to have the same width, but %s has "
4169                      "width %d and %s has width %d."),
4170                subcommand_name, pos_name,
4171                var_get_name (v0), var_get_width (v0),
4172                var_get_name (vi), var_get_width (vi));
4173           return false;
4174         }
4175       if (!val_labs_equal (var_get_value_labels (v0),
4176                            var_get_value_labels (vi)))
4177         {
4178           msg (SE, _("%s=%s requires the variables to be "
4179                      "moved to have the same value labels, but %s "
4180                      "and %s have different value labels."),
4181                subcommand_name, pos_name,
4182                var_get_name (v0), var_get_name (vi));
4183           return false;
4184         }
4185       if (!ctables_categories_equal (c0, ci))
4186         {
4187           msg (SE, _("%s=%s requires the variables to be "
4188                      "moved to have the same category "
4189                      "specifications, but %s and %s have different "
4190                      "category specifications."),
4191                subcommand_name, pos_name,
4192                var_get_name (v0), var_get_name (vi));
4193           return false;
4194         }
4195     }
4196
4197   return true;
4198 }
4199
4200 static bool
4201 ctables_prepare_table (struct ctables_table *t)
4202 {
4203   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
4204     if (t->axes[a])
4205       {
4206         t->stacks[a] = enumerate_fts (a, t->axes[a]);
4207
4208         for (size_t j = 0; j < t->stacks[a].n; j++)
4209           {
4210             struct ctables_nest *nest = &t->stacks[a].nests[j];
4211             for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
4212               {
4213                 nest->domains[dt] = xmalloc (nest->n * sizeof *nest->domains[dt]);
4214                 nest->n_domains[dt] = 0;
4215
4216                 for (size_t k = 0; k < nest->n; k++)
4217                   {
4218                     if (k == nest->scale_idx)
4219                       continue;
4220
4221                     switch (dt)
4222                       {
4223                       case CTDT_TABLE:
4224                         continue;
4225
4226                       case CTDT_LAYER:
4227                         if (a != PIVOT_AXIS_LAYER)
4228                           continue;
4229                         break;
4230
4231                       case CTDT_SUBTABLE:
4232                       case CTDT_ROW:
4233                       case CTDT_COL:
4234                         if (dt == CTDT_SUBTABLE ? a != PIVOT_AXIS_LAYER
4235                             : dt == CTDT_ROW ? a == PIVOT_AXIS_COLUMN
4236                             : a == PIVOT_AXIS_ROW)
4237                           {
4238                             if (k == nest->n - 1
4239                                 || (nest->scale_idx == nest->n - 1
4240                                     && k == nest->n - 2))
4241                               continue;
4242                           }
4243                         break;
4244
4245                       case CTDT_LAYERROW:
4246                         if (a == PIVOT_AXIS_COLUMN)
4247                           continue;
4248                         break;
4249
4250                       case CTDT_LAYERCOL:
4251                         if (a == PIVOT_AXIS_ROW)
4252                           continue;
4253                         break;
4254                       }
4255
4256                     nest->domains[dt][nest->n_domains[dt]++] = k;
4257                   }
4258               }
4259           }
4260       }
4261     else
4262       {
4263         struct ctables_nest *nest = xmalloc (sizeof *nest);
4264         *nest = (struct ctables_nest) { .n = 0 };
4265         t->stacks[a] = (struct ctables_stack) { .nests = nest, .n = 1 };
4266       }
4267
4268   struct ctables_stack *stack = &t->stacks[t->summary_axis];
4269   for (size_t i = 0; i < stack->n; i++)
4270     {
4271       struct ctables_nest *nest = &stack->nests[i];
4272       if (!nest->specs[CSV_CELL].n)
4273         {
4274           struct ctables_summary_spec_set *specs = &nest->specs[CSV_CELL];
4275           specs->specs = xmalloc (sizeof *specs->specs);
4276           specs->n = 1;
4277
4278           enum ctables_summary_function function
4279             = specs->is_scale ? CTSF_MEAN : CTSF_COUNT;
4280
4281           *specs->specs = (struct ctables_summary_spec) {
4282             .function = function,
4283             .format = ctables_summary_default_format (function, specs->var),
4284             .label = ctables_summary_default_label (function, 0),
4285           };
4286           if (!specs->var)
4287             specs->var = nest->vars[0];
4288
4289           ctables_summary_spec_set_clone (&nest->specs[CSV_TOTAL],
4290                                           &nest->specs[CSV_CELL]);
4291         }
4292       else if (!nest->specs[CSV_TOTAL].n)
4293         ctables_summary_spec_set_clone (&nest->specs[CSV_TOTAL],
4294                                         &nest->specs[CSV_CELL]);
4295
4296       if (t->ctables->smissing_listwise)
4297         {
4298           struct variable **listwise_vars = NULL;
4299           size_t n = 0;
4300           size_t allocated = 0;
4301
4302           for (size_t j = nest->group_head; j < stack->n; j++)
4303             {
4304               const struct ctables_nest *other_nest = &stack->nests[j];
4305               if (other_nest->group_head != nest->group_head)
4306                 break;
4307
4308               if (nest != other_nest && other_nest->scale_idx < other_nest->n)
4309                 {
4310                   if (n >= allocated)
4311                     listwise_vars = x2nrealloc (listwise_vars, &allocated,
4312                                                 sizeof *listwise_vars);
4313                   listwise_vars[n++] = other_nest->vars[other_nest->scale_idx];
4314                 }
4315             }
4316           for (size_t j = 0; j < N_CSVS; j++)
4317             {
4318               nest->specs[j].listwise_vars = listwise_vars;
4319               nest->specs[j].n_listwise_vars = n;
4320             }
4321         }
4322     }
4323
4324   struct ctables_summary_spec_set *merged = &t->summary_specs;
4325   struct merge_item *items = xnmalloc (2 * stack->n, sizeof *items);
4326   size_t n_left = 0;
4327   for (size_t j = 0; j < stack->n; j++)
4328     {
4329       const struct ctables_nest *nest = &stack->nests[j];
4330       if (nest->n)
4331         for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
4332           items[n_left++] = (struct merge_item) { .set = &nest->specs[sv] };
4333     }
4334
4335   while (n_left > 0)
4336     {
4337       struct merge_item min = items[0];
4338       for (size_t j = 1; j < n_left; j++)
4339         if (merge_item_compare_3way (&items[j], &min) < 0)
4340           min = items[j];
4341
4342       if (merged->n >= merged->allocated)
4343         merged->specs = x2nrealloc (merged->specs, &merged->allocated,
4344                                     sizeof *merged->specs);
4345       merged->specs[merged->n++] = min.set->specs[min.ofs];
4346
4347       for (size_t j = 0; j < n_left; )
4348         {
4349           if (merge_item_compare_3way (&items[j], &min) == 0)
4350             {
4351               struct merge_item *item = &items[j];
4352               item->set->specs[item->ofs].axis_idx = merged->n - 1;
4353               if (++item->ofs >= item->set->n)
4354                 {
4355                   items[j] = items[--n_left];
4356                   continue;
4357                 }
4358             }
4359           j++;
4360         }
4361     }
4362
4363 #if 0
4364   for (size_t j = 0; j < merged->n; j++)
4365     printf ("%s\n", ctables_summary_function_name (merged->specs[j].function));
4366
4367   for (size_t j = 0; j < stack->n; j++)
4368     {
4369       const struct ctables_nest *nest = &stack->nests[j];
4370       for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
4371         {
4372           const struct ctables_summary_spec_set *specs = &nest->specs[sv];
4373           for (size_t k = 0; k < specs->n; k++)
4374             printf ("(%s, %zu) ", ctables_summary_function_name (specs->specs[k].function),
4375                     specs->specs[k].axis_idx);
4376           printf ("\n");
4377         }
4378     }
4379 #endif
4380
4381   return (ctables_check_label_position (t, PIVOT_AXIS_ROW)
4382           && ctables_check_label_position (t, PIVOT_AXIS_COLUMN));
4383 }
4384
4385 static void
4386 ctables_insert_clabels_values (struct ctables_table *t, const struct ccase *c,
4387                                enum pivot_axis_type a)
4388 {
4389   struct ctables_stack *stack = &t->stacks[a];
4390   for (size_t i = 0; i < stack->n; i++)
4391     {
4392       const struct ctables_nest *nest = &stack->nests[i];
4393       const struct variable *var = nest->vars[nest->n - 1];
4394       const union value *value = case_data (c, var);
4395
4396       if (var_is_numeric (var) && value->f == SYSMIS)
4397         continue;
4398
4399       if (ctables_categories_match (t->categories [var_get_dict_index (var)],
4400                                     value, var))
4401         ctables_value_insert (t, value, var_get_width (var));
4402     }
4403 }
4404
4405 static int
4406 compare_clabels_values_3way (const void *a_, const void *b_, const void *width_)
4407 {
4408   const struct ctables_value *const *ap = a_;
4409   const struct ctables_value *const *bp = b_;
4410   const struct ctables_value *a = *ap;
4411   const struct ctables_value *b = *bp;
4412   const int *width = width_;
4413   return value_compare_3way (&a->value, &b->value, *width);
4414 }
4415
4416 static void
4417 ctables_sort_clabels_values (struct ctables_table *t)
4418 {
4419   const struct variable *v0 = t->clabels_example;
4420   int width = var_get_width (v0);
4421
4422   struct ctables_categories *c0 = t->categories[var_get_dict_index (v0)];
4423   if (c0->show_empty)
4424     {
4425       const struct val_labs *val_labs = var_get_value_labels (v0);
4426       for (const struct val_lab *vl = val_labs_first (val_labs); vl;
4427            vl = val_labs_next (val_labs, vl))
4428         if (ctables_categories_match (c0, &vl->value, v0))
4429           ctables_value_insert (t, &vl->value, width);
4430     }
4431
4432   size_t n = hmap_count (&t->clabels_values_map);
4433   t->clabels_values = xnmalloc (n, sizeof *t->clabels_values);
4434
4435   struct ctables_value *clv;
4436   size_t i = 0;
4437   HMAP_FOR_EACH (clv, struct ctables_value, node, &t->clabels_values_map)
4438     t->clabels_values[i++] = clv;
4439   t->n_clabels_values = n;
4440   assert (i == n);
4441
4442   sort (t->clabels_values, n, sizeof *t->clabels_values,
4443         compare_clabels_values_3way, &width);
4444
4445   for (size_t i = 0; i < n; i++)
4446     t->clabels_values[i]->leaf = i;
4447 }
4448
4449 static void
4450 ctables_add_category_occurrences (const struct variable *var,
4451                                   struct hmap *occurrences,
4452                                   const struct ctables_categories *cats)
4453 {
4454   const struct val_labs *val_labs = var_get_value_labels (var);
4455
4456   for (size_t i = 0; i < cats->n_cats; i++)
4457     {
4458       const struct ctables_category *c = &cats->cats[i];
4459       switch (c->type)
4460         {
4461         case CCT_NUMBER:
4462           ctables_add_occurrence (var, &(const union value) { .f = c->number },
4463                                   occurrences);
4464           break;
4465
4466         case CCT_STRING:
4467           {
4468             int width = var_get_width (var);
4469             union value value;
4470             value_init (&value, width);
4471             value_copy_buf_rpad (&value, width,
4472                                  CHAR_CAST (uint8_t *, c->string.string),
4473                                  c->string.length, ' ');
4474             ctables_add_occurrence (var, &value, occurrences);
4475             value_destroy (&value, width);
4476           }
4477           break;
4478
4479         case CCT_NRANGE:
4480           assert (var_is_numeric (var));
4481           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
4482                vl = val_labs_next (val_labs, vl))
4483             if (vl->value.f >= c->nrange[0] && vl->value.f <= c->nrange[1])
4484               ctables_add_occurrence (var, &vl->value, occurrences);
4485           break;
4486
4487         case CCT_SRANGE:
4488           assert (var_is_alpha (var));
4489           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
4490                vl = val_labs_next (val_labs, vl))
4491             if (in_string_range (&vl->value, var, c->srange))
4492               ctables_add_occurrence (var, &vl->value, occurrences);
4493           break;
4494
4495         case CCT_MISSING:
4496           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
4497                vl = val_labs_next (val_labs, vl))
4498             if (var_is_value_missing (var, &vl->value))
4499               ctables_add_occurrence (var, &vl->value, occurrences);
4500           break;
4501
4502         case CCT_OTHERNM:
4503           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
4504                vl = val_labs_next (val_labs, vl))
4505             ctables_add_occurrence (var, &vl->value, occurrences);
4506           break;
4507
4508         case CCT_POSTCOMPUTE:
4509           break;
4510
4511         case CCT_SUBTOTAL:
4512         case CCT_TOTAL:
4513           break;
4514
4515         case CCT_VALUE:
4516         case CCT_LABEL:
4517         case CCT_FUNCTION:
4518           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
4519                vl = val_labs_next (val_labs, vl))
4520             if (c->include_missing || !var_is_value_missing (var, &vl->value))
4521               ctables_add_occurrence (var, &vl->value, occurrences);
4522           break;
4523
4524         case CCT_EXCLUDED_MISSING:
4525           break;
4526         }
4527     }
4528 }
4529
4530 static void
4531 ctables_section_recurse_add_empty_categories (
4532   struct ctables_section *s,
4533   const struct ctables_category *cats[PIVOT_N_AXES][10], struct ccase *c,
4534   enum pivot_axis_type a, size_t a_idx)
4535 {
4536   if (a >= PIVOT_N_AXES)
4537     ctables_cell_insert__ (s, c, cats);
4538   else if (!s->nests[a] || a_idx >= s->nests[a]->n)
4539     ctables_section_recurse_add_empty_categories (s, cats, c, a + 1, 0);
4540   else
4541     {
4542       const struct variable *var = s->nests[a]->vars[a_idx];
4543       const struct ctables_categories *categories = s->table->categories[
4544         var_get_dict_index (var)];
4545       int width = var_get_width (var);
4546       const struct hmap *occurrences = &s->occurrences[a][a_idx];
4547       const struct ctables_occurrence *o;
4548       HMAP_FOR_EACH (o, struct ctables_occurrence, node, occurrences)
4549         {
4550           union value *value = case_data_rw (c, var);
4551           value_destroy (value, width);
4552           value_clone (value, &o->value, width);
4553           cats[a][a_idx] = ctables_categories_match (categories, value, var);
4554           assert (cats[a][a_idx] != NULL);
4555           ctables_section_recurse_add_empty_categories (s, cats, c, a, a_idx + 1);
4556         }
4557
4558       for (size_t i = 0; i < categories->n_cats; i++)
4559         {
4560           const struct ctables_category *cat = &categories->cats[i];
4561           if (cat->type == CCT_POSTCOMPUTE)
4562             {
4563               cats[a][a_idx] = cat;
4564               ctables_section_recurse_add_empty_categories (s, cats, c, a, a_idx + 1);
4565             }
4566         }
4567     }
4568 }
4569
4570 static void
4571 ctables_section_add_empty_categories (struct ctables_section *s)
4572 {
4573   bool show_empty = false;
4574   for (size_t a = 0; a < PIVOT_N_AXES; a++)
4575     if (s->nests[a])
4576       for (size_t k = 0; k < s->nests[a]->n; k++)
4577         if (k != s->nests[a]->scale_idx)
4578           {
4579             const struct variable *var = s->nests[a]->vars[k];
4580             const struct ctables_categories *cats = s->table->categories[
4581               var_get_dict_index (var)];
4582             if (cats->show_empty)
4583               {
4584                 show_empty = true;
4585                 ctables_add_category_occurrences (var, &s->occurrences[a][k], cats);
4586               }
4587           }
4588   if (!show_empty)
4589     return;
4590
4591   const struct ctables_category *cats[PIVOT_N_AXES][10]; /* XXX */
4592   struct ccase *c = case_create (dict_get_proto (s->table->ctables->dict));
4593   ctables_section_recurse_add_empty_categories (s, cats, c, 0, 0);
4594   case_unref (c);
4595 }
4596
4597 static bool
4598 ctables_execute (struct dataset *ds, struct ctables *ct)
4599 {
4600   for (size_t i = 0; i < ct->n_tables; i++)
4601     {
4602       struct ctables_table *t = ct->tables[i];
4603       t->sections = xnmalloc (MAX (1, t->stacks[PIVOT_AXIS_ROW].n) *
4604                               MAX (1, t->stacks[PIVOT_AXIS_COLUMN].n) *
4605                               MAX (1, t->stacks[PIVOT_AXIS_LAYER].n),
4606                               sizeof *t->sections);
4607       size_t ix[PIVOT_N_AXES];
4608       ctables_table_add_section (t, 0, ix);
4609     }
4610
4611   struct casereader *input = proc_open (ds);
4612   bool warn_on_invalid = true;
4613   for (struct ccase *c = casereader_read (input); c;
4614        case_unref (c), c = casereader_read (input))
4615     {
4616       double d_weight = dict_get_case_weight (dataset_dict (ds), c,
4617                                               &warn_on_invalid);
4618       double e_weight = (ct->e_weight
4619                          ? var_force_valid_weight (ct->e_weight,
4620                                                    case_num (c, ct->e_weight),
4621                                                    &warn_on_invalid)
4622                          : d_weight);
4623
4624       for (size_t i = 0; i < ct->n_tables; i++)
4625         {
4626           struct ctables_table *t = ct->tables[i];
4627
4628           for (size_t j = 0; j < t->n_sections; j++)
4629             ctables_cell_insert (&t->sections[j], c, d_weight, e_weight);
4630
4631           for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
4632             if (t->label_axis[a] != a)
4633               ctables_insert_clabels_values (t, c, a);
4634         }
4635     }
4636   casereader_destroy (input);
4637
4638   for (size_t i = 0; i < ct->n_tables; i++)
4639     {
4640       struct ctables_table *t = ct->tables[i];
4641
4642       if (t->clabels_example)
4643         ctables_sort_clabels_values (t);
4644
4645       for (size_t j = 0; j < t->n_sections; j++)
4646         ctables_section_add_empty_categories (&t->sections[j]);
4647
4648       ctables_table_output (ct, ct->tables[i]);
4649     }
4650   return proc_commit (ds);
4651 }
4652 \f
4653 /* Postcomputes. */
4654
4655 typedef struct ctables_pcexpr *parse_recursively_func (struct lexer *,
4656                                                        struct dictionary *);
4657
4658 static void
4659 ctables_pcexpr_destroy (struct ctables_pcexpr *e)
4660 {
4661   if (e)
4662     {
4663       switch (e->op)
4664         {
4665         case CTPO_CAT_STRING:
4666           ss_dealloc (&e->string);
4667           break;
4668
4669         case CTPO_ADD:
4670         case CTPO_SUB:
4671         case CTPO_MUL:
4672         case CTPO_DIV:
4673         case CTPO_POW:
4674         case CTPO_NEG:
4675           for (size_t i = 0; i < 2; i++)
4676             ctables_pcexpr_destroy (e->subs[i]);
4677           break;
4678
4679         case CTPO_CONSTANT:
4680         case CTPO_CAT_NUMBER:
4681         case CTPO_CAT_RANGE:
4682         case CTPO_CAT_MISSING:
4683         case CTPO_CAT_OTHERNM:
4684         case CTPO_CAT_SUBTOTAL:
4685         case CTPO_CAT_TOTAL:
4686           break;
4687         }
4688
4689       msg_location_destroy (e->location);
4690       free (e);
4691     }
4692 }
4693
4694 static struct ctables_pcexpr *
4695 ctables_pcexpr_allocate_binary (enum ctables_postcompute_op op,
4696                                 struct ctables_pcexpr *sub0,
4697                                 struct ctables_pcexpr *sub1)
4698 {
4699   struct ctables_pcexpr *e = xmalloc (sizeof *e);
4700   *e = (struct ctables_pcexpr) {
4701     .op = op,
4702     .subs = { sub0, sub1 },
4703     .location = msg_location_merged (sub0->location, sub1->location),
4704   };
4705   return e;
4706 }
4707
4708 /* How to parse an operator. */
4709 struct operator
4710   {
4711     enum token_type token;
4712     enum ctables_postcompute_op op;
4713   };
4714
4715 static const struct operator *
4716 match_operator (struct lexer *lexer, const struct operator ops[], size_t n_ops)
4717 {
4718   for (const struct operator *op = ops; op < ops + n_ops; op++)
4719     if (lex_token (lexer) == op->token)
4720       {
4721         if (op->token != T_NEG_NUM)
4722           lex_get (lexer);
4723
4724         return op;
4725       }
4726
4727   return NULL;
4728 }
4729
4730 static struct ctables_pcexpr *
4731 parse_binary_operators__ (struct lexer *lexer, struct dictionary *dict,
4732                           const struct operator ops[], size_t n_ops,
4733                           parse_recursively_func *parse_next_level,
4734                           const char *chain_warning,
4735                           struct ctables_pcexpr *lhs)
4736 {
4737   for (int op_count = 0; ; op_count++)
4738     {
4739       const struct operator *op = match_operator (lexer, ops, n_ops);
4740       if (!op)
4741         {
4742           if (op_count > 1 && chain_warning)
4743             msg_at (SW, lhs->location, "%s", chain_warning);
4744
4745           return lhs;
4746         }
4747
4748       struct ctables_pcexpr *rhs = parse_next_level (lexer, dict);
4749       if (!rhs)
4750         {
4751           ctables_pcexpr_destroy (lhs);
4752           return NULL;
4753         }
4754
4755       lhs = ctables_pcexpr_allocate_binary (op->op, lhs, rhs);
4756     }
4757 }
4758
4759 static struct ctables_pcexpr *
4760 parse_binary_operators (struct lexer *lexer, struct dictionary *dict,
4761                         const struct operator ops[], size_t n_ops,
4762                         parse_recursively_func *parse_next_level,
4763                         const char *chain_warning)
4764 {
4765   struct ctables_pcexpr *lhs = parse_next_level (lexer, dict);
4766   if (!lhs)
4767     return NULL;
4768
4769   return parse_binary_operators__ (lexer, dict, ops, n_ops, parse_next_level,
4770                                    chain_warning, lhs);
4771 }
4772
4773 static struct ctables_pcexpr *parse_add (struct lexer *, struct dictionary *);
4774
4775 static struct ctables_pcexpr
4776 ctpo_cat_range (double low, double high)
4777 {
4778   return (struct ctables_pcexpr) {
4779     .op = CTPO_CAT_RANGE,
4780     .range = { low, high },
4781   };
4782 }
4783
4784 static struct ctables_pcexpr *
4785 parse_primary (struct lexer *lexer, struct dictionary *dict)
4786 {
4787   int start_ofs = lex_ofs (lexer);
4788   struct ctables_pcexpr e;
4789   if (lex_is_number (lexer))
4790     {
4791       e = (struct ctables_pcexpr) { .op = CTPO_CONSTANT,
4792                                     .number = lex_number (lexer) };
4793       lex_get (lexer);
4794     }
4795   else if (lex_match_id (lexer, "MISSING"))
4796     e = (struct ctables_pcexpr) { .op = CTPO_CAT_MISSING };
4797   else if (lex_match_id (lexer, "OTHERNM"))
4798     e = (struct ctables_pcexpr) { .op = CTPO_CAT_OTHERNM };
4799   else if (lex_match_id (lexer, "TOTAL"))
4800     e = (struct ctables_pcexpr) { .op = CTPO_CAT_TOTAL };
4801   else if (lex_match_id (lexer, "SUBTOTAL"))
4802     {
4803       size_t subtotal_index = 0;
4804       if (lex_match (lexer, T_LBRACK))
4805         {
4806           if (!lex_force_int_range (lexer, "SUBTOTAL", 1, LONG_MAX))
4807             return NULL;
4808           subtotal_index = lex_integer (lexer);
4809           lex_get (lexer);
4810           if (!lex_force_match (lexer, T_RBRACK))
4811             return NULL;
4812         }
4813       e = (struct ctables_pcexpr) { .op = CTPO_CAT_SUBTOTAL,
4814                                     .subtotal_index = subtotal_index };
4815     }
4816   else if (lex_match (lexer, T_LBRACK))
4817     {
4818       if (lex_match_id (lexer, "LO"))
4819         {
4820           if (!lex_force_match_id (lexer, "THRU") || lex_force_num (lexer))
4821             return false;
4822           e = ctpo_cat_range (-DBL_MAX, lex_number (lexer));
4823           lex_get (lexer);
4824         }
4825       else if (lex_is_number (lexer))
4826         {
4827           double number = lex_number (lexer);
4828           lex_get (lexer);
4829           if (lex_match_id (lexer, "THRU"))
4830             {
4831               if (lex_match_id (lexer, "HI"))
4832                 e = ctpo_cat_range (number, DBL_MAX);
4833               else
4834                 {
4835                   if (!lex_force_num (lexer))
4836                     return false;
4837                   e = ctpo_cat_range (number, lex_number (lexer));
4838                   lex_get (lexer);
4839                 }
4840             }
4841           else
4842             e = (struct ctables_pcexpr) { .op = CTPO_CAT_NUMBER,
4843                                           .number = number };
4844         }
4845       else if (lex_is_string (lexer))
4846         {
4847           struct substring s = recode_substring_pool (
4848             dict_get_encoding (dict), "UTF-8", lex_tokss (lexer), NULL);
4849           ss_rtrim (&s, ss_cstr (" "));
4850
4851           e = (struct ctables_pcexpr) { .op = CTPO_CAT_STRING, .string = s };
4852           lex_get (lexer);
4853         }
4854       else
4855         {
4856           lex_error (lexer, NULL);
4857           return NULL;
4858         }
4859
4860       if (!lex_force_match (lexer, T_RBRACK))
4861         {
4862           if (e.op == CTPO_CAT_STRING)
4863             ss_dealloc (&e.string);
4864           return NULL;
4865         }
4866     }
4867   else if (lex_match (lexer, T_LPAREN))
4868     {
4869       struct ctables_pcexpr *ep = parse_add (lexer, dict);
4870       if (!ep)
4871         return NULL;
4872       if (!lex_force_match (lexer, T_RPAREN))
4873         {
4874           ctables_pcexpr_destroy (ep);
4875           return NULL;
4876         }
4877       return ep;
4878     }
4879   else
4880     {
4881       lex_error (lexer, NULL);
4882       return NULL;
4883     }
4884
4885   e.location = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer) - 1);
4886   return xmemdup (&e, sizeof e);
4887 }
4888
4889 static struct ctables_pcexpr *
4890 ctables_pcexpr_allocate_neg (struct ctables_pcexpr *sub,
4891                              struct lexer *lexer, int start_ofs)
4892 {
4893   struct ctables_pcexpr *e = xmalloc (sizeof *e);
4894   *e = (struct ctables_pcexpr) {
4895     .op = CTPO_NEG,
4896     .subs = { sub },
4897     .location = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer) - 1),
4898   };
4899   return e;
4900 }
4901
4902 static struct ctables_pcexpr *
4903 parse_exp (struct lexer *lexer, struct dictionary *dict)
4904 {
4905   static const struct operator op = { T_EXP, CTPO_POW };
4906
4907   const char *chain_warning =
4908     _("The exponentiation operator (`**') is left-associative: "
4909       "`a**b**c' equals `(a**b)**c', not `a**(b**c)'.  "
4910       "To disable this warning, insert parentheses.");
4911
4912   if (lex_token (lexer) != T_NEG_NUM || lex_next_token (lexer, 1) != T_EXP)
4913     return parse_binary_operators (lexer, dict, &op, 1,
4914                                    parse_primary, chain_warning);
4915
4916   /* Special case for situations like "-5**6", which must be parsed as
4917      -(5**6). */
4918
4919   int start_ofs = lex_ofs (lexer);
4920   struct ctables_pcexpr *lhs = xmalloc (sizeof *lhs);
4921   *lhs = (struct ctables_pcexpr) {
4922     .op = CTPO_CONSTANT,
4923     .number = -lex_tokval (lexer),
4924     .location = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer)),
4925   };
4926   lex_get (lexer);
4927
4928   struct ctables_pcexpr *node = parse_binary_operators__ (
4929     lexer, dict, &op, 1, parse_primary, chain_warning, lhs);
4930   if (!node)
4931     return NULL;
4932
4933   return ctables_pcexpr_allocate_neg (node, lexer, start_ofs);
4934 }
4935
4936 /* Parses the unary minus level. */
4937 static struct ctables_pcexpr *
4938 parse_neg (struct lexer *lexer, struct dictionary *dict)
4939 {
4940   int start_ofs = lex_ofs (lexer);
4941   if (!lex_match (lexer, T_DASH))
4942     return parse_exp (lexer, dict);
4943
4944   struct ctables_pcexpr *inner = parse_neg (lexer, dict);
4945   if (!inner)
4946     return NULL;
4947
4948   return ctables_pcexpr_allocate_neg (inner, lexer, start_ofs);
4949 }
4950
4951 /* Parses the multiplication and division level. */
4952 static struct ctables_pcexpr *
4953 parse_mul (struct lexer *lexer, struct dictionary *dict)
4954 {
4955   static const struct operator ops[] =
4956     {
4957       { T_ASTERISK, CTPO_MUL },
4958       { T_SLASH, CTPO_DIV },
4959     };
4960
4961   return parse_binary_operators (lexer, dict, ops, sizeof ops / sizeof *ops,
4962                                  parse_neg, NULL);
4963 }
4964
4965 /* Parses the addition and subtraction level. */
4966 static struct ctables_pcexpr *
4967 parse_add (struct lexer *lexer, struct dictionary *dict)
4968 {
4969   static const struct operator ops[] =
4970     {
4971       { T_PLUS, CTPO_ADD },
4972       { T_DASH, CTPO_SUB },
4973       { T_NEG_NUM, CTPO_ADD },
4974     };
4975
4976   return parse_binary_operators (lexer, dict, ops, sizeof ops / sizeof *ops,
4977                                  parse_mul, NULL);
4978 }
4979
4980 static struct ctables_postcompute *
4981 ctables_find_postcompute (struct ctables *ct, const char *name)
4982 {
4983   struct ctables_postcompute *pc;
4984   HMAP_FOR_EACH_WITH_HASH (pc, struct ctables_postcompute, hmap_node,
4985                            utf8_hash_case_string (name, 0), &ct->postcomputes)
4986     if (!utf8_strcasecmp (pc->name, name))
4987       return pc;
4988   return NULL;
4989 }
4990
4991 static bool
4992 ctables_parse_pcompute (struct lexer *lexer, struct dictionary *dict,
4993                         struct ctables *ct)
4994 {
4995   int pcompute_start = lex_ofs (lexer) - 1;
4996
4997   if (!lex_force_match (lexer, T_AND) || !lex_force_id (lexer))
4998     return false;
4999
5000   char *name = ss_xstrdup (lex_tokss (lexer));
5001
5002   lex_get (lexer);
5003   if (!lex_force_match (lexer, T_EQUALS)
5004       || !lex_force_match_id (lexer, "EXPR")
5005       || !lex_force_match (lexer, T_LPAREN))
5006     {
5007       free (name);
5008       return false;
5009     }
5010
5011   int expr_start = lex_ofs (lexer);
5012   struct ctables_pcexpr *expr = parse_add (lexer, dict);
5013   int expr_end = lex_ofs (lexer) - 1;
5014   if (!expr || !lex_force_match (lexer, T_RPAREN))
5015     {
5016       free (name);
5017       return false;
5018     }
5019   int pcompute_end = lex_ofs (lexer) - 1;
5020
5021   struct msg_location *location = lex_ofs_location (lexer, pcompute_start,
5022                                                     pcompute_end);
5023
5024   struct ctables_postcompute *pc = ctables_find_postcompute (ct, name);
5025   if (pc)
5026     {
5027       msg_at (SW, location, _("New definition of &%s will override the "
5028                               "previous definition."),
5029               pc->name);
5030       msg_at (SN, pc->location, _("This is the previous definition."));
5031
5032       ctables_pcexpr_destroy (pc->expr);
5033       msg_location_destroy (pc->location);
5034       free (name);
5035     }
5036   else
5037     {
5038       pc = xmalloc (sizeof *pc);
5039       *pc = (struct ctables_postcompute) { .name = name };
5040       hmap_insert (&ct->postcomputes, &pc->hmap_node,
5041                    utf8_hash_case_string (pc->name, 0));
5042     }
5043   pc->expr = expr;
5044   pc->location = location;
5045   if (!pc->label)
5046     pc->label = lex_ofs_representation (lexer, expr_start, expr_end);
5047   return true;
5048 }
5049
5050 static bool
5051 ctables_parse_pproperties_format (struct lexer *lexer,
5052                                   struct ctables_summary_spec_set *sss)
5053 {
5054   *sss = (struct ctables_summary_spec_set) { .n = 0 };
5055
5056   while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH
5057          && !(lex_token (lexer) == T_ID
5058               && (lex_id_match (ss_cstr ("LABEL"), lex_tokss (lexer))
5059                   || lex_id_match (ss_cstr ("HIDESOURCECATS"),
5060                                    lex_tokss (lexer)))))
5061     {
5062       /* Parse function. */
5063       enum ctables_summary_function function;
5064       if (!parse_ctables_summary_function (lexer, &function))
5065         goto error;
5066
5067       /* Parse percentile. */
5068       double percentile = 0;
5069       if (function == CTSF_PTILE)
5070         {
5071           if (!lex_force_num_range_closed (lexer, "PTILE", 0, 100))
5072             goto error;
5073           percentile = lex_number (lexer);
5074           lex_get (lexer);
5075         }
5076
5077       /* Parse format. */
5078       struct fmt_spec format;
5079       bool is_ctables_format;
5080       if (!parse_ctables_format_specifier (lexer, &format, &is_ctables_format))
5081         goto error;
5082
5083       if (sss->n >= sss->allocated)
5084         sss->specs = x2nrealloc (sss->specs, &sss->allocated,
5085                                  sizeof *sss->specs);
5086       sss->specs[sss->n++] = (struct ctables_summary_spec) {
5087         .function = function,
5088         .percentile = percentile,
5089         .format = format,
5090         .is_ctables_format = is_ctables_format,
5091       };
5092     }
5093   return true;
5094
5095 error:
5096   ctables_summary_spec_set_uninit (sss);
5097   return false;
5098 }
5099
5100 static bool
5101 ctables_parse_pproperties (struct lexer *lexer, struct ctables *ct)
5102 {
5103   struct ctables_postcompute **pcs = NULL;
5104   size_t n_pcs = 0;
5105   size_t allocated_pcs = 0;
5106
5107   while (lex_match (lexer, T_AND))
5108     {
5109       if (!lex_force_id (lexer))
5110         goto error;
5111       struct ctables_postcompute *pc
5112         = ctables_find_postcompute (ct, lex_tokcstr (lexer));
5113       if (!pc)
5114         {
5115           msg (SE, _("Unknown computed category &%s."), lex_tokcstr (lexer));
5116           goto error;
5117         }
5118       lex_get (lexer);
5119
5120       if (n_pcs >= allocated_pcs)
5121         pcs = x2nrealloc (pcs, &allocated_pcs, sizeof *pcs);
5122       pcs[n_pcs++] = pc;
5123     }
5124
5125   while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
5126     {
5127       if (lex_match_id (lexer, "LABEL"))
5128         {
5129           lex_match (lexer, T_EQUALS);
5130           if (!lex_force_string (lexer))
5131             goto error;
5132
5133           for (size_t i = 0; i < n_pcs; i++)
5134             {
5135               free (pcs[i]->label);
5136               pcs[i]->label = ss_xstrdup (lex_tokss (lexer));
5137             }
5138
5139           lex_get (lexer);
5140         }
5141       else if (lex_match_id (lexer, "FORMAT"))
5142         {
5143           lex_match (lexer, T_EQUALS);
5144
5145           struct ctables_summary_spec_set sss;
5146           if (!ctables_parse_pproperties_format (lexer, &sss))
5147             goto error;
5148
5149           for (size_t i = 0; i < n_pcs; i++)
5150             {
5151               if (pcs[i]->specs)
5152                 ctables_summary_spec_set_uninit (pcs[i]->specs);
5153               else
5154                 pcs[i]->specs = xmalloc (sizeof *pcs[i]->specs);
5155               ctables_summary_spec_set_clone (pcs[i]->specs, &sss);
5156             }
5157           ctables_summary_spec_set_uninit (&sss);
5158         }
5159       else if (lex_match_id (lexer, "HIDESOURCECATS"))
5160         {
5161           lex_match (lexer, T_EQUALS);
5162           bool hide_source_cats;
5163           if (!parse_bool (lexer, &hide_source_cats))
5164             goto error;
5165           for (size_t i = 0; i < n_pcs; i++)
5166             pcs[i]->hide_source_cats = hide_source_cats;
5167         }
5168       else
5169         {
5170           lex_error_expecting (lexer, "LABEL", "FORMAT", "HIDESOURCECATS");
5171           goto error;
5172         }
5173     }
5174   free (pcs);
5175   return true;
5176
5177 error:
5178   free (pcs);
5179   return false;
5180 }
5181
5182 static void
5183 put_strftime (struct string *out, time_t now, const char *format)
5184 {
5185   const struct tm *tm = localtime (&now);
5186   char value[128];
5187   strftime (value, sizeof value, format, tm);
5188   ds_put_cstr (out, value);
5189 }
5190
5191 static bool
5192 skip_prefix (struct substring *s, struct substring prefix)
5193 {
5194   if (ss_starts_with (*s, prefix))
5195     {
5196       ss_advance (s, prefix.length);
5197       return true;
5198     }
5199   else
5200     return false;
5201 }
5202
5203 static void
5204 put_table_expression (struct string *out, struct lexer *lexer,
5205                       struct dictionary *dict, int expr_start, int expr_end)
5206 {
5207   size_t nest = 0;
5208   for (int ofs = expr_start; ofs < expr_end; ofs++)
5209     {
5210       const struct token *t = lex_ofs_token (lexer, ofs);
5211       if (t->type == T_LBRACK)
5212         nest++;
5213       else if (t->type == T_RBRACK && nest > 0)
5214         nest--;
5215       else if (nest > 0)
5216         {
5217           /* Nothing. */
5218         }
5219       else if (t->type == T_ID)
5220         {
5221           const struct variable *var
5222             = dict_lookup_var (dict, t->string.string);
5223           const char *label = var ? var_get_label (var) : NULL;
5224           ds_put_cstr (out, label ? label : t->string.string);
5225         }
5226       else
5227         {
5228           if (ofs != expr_start && t->type != T_RPAREN && ds_last (out) != ' ')
5229             ds_put_byte (out, ' ');
5230
5231           char *repr = lex_ofs_representation (lexer, ofs, ofs);
5232           ds_put_cstr (out, repr);
5233           free (repr);
5234
5235           if (ofs + 1 != expr_end && t->type != T_LPAREN)
5236             ds_put_byte (out, ' ');
5237         }
5238     }
5239 }
5240
5241 static void
5242 put_title_text (struct string *out, struct substring in, time_t now,
5243                 struct lexer *lexer, struct dictionary *dict,
5244                 int expr_start, int expr_end)
5245 {
5246   for (;;)
5247     {
5248       size_t chunk = ss_find_byte (in, ')');
5249       ds_put_substring (out, ss_head (in, chunk));
5250       ss_advance (&in, chunk);
5251       if (ss_is_empty (in))
5252         return;
5253
5254       if (skip_prefix (&in, ss_cstr (")DATE")))
5255         put_strftime (out, now, "%x");
5256       else if (skip_prefix (&in, ss_cstr (")TIME")))
5257         put_strftime (out, now, "%X");
5258       else if (skip_prefix (&in, ss_cstr (")TABLE")))
5259         put_table_expression (out, lexer, dict, expr_start, expr_end);
5260       else
5261         {
5262           ds_put_byte (out, ')');
5263           ss_advance (&in, 1);
5264         }
5265     }
5266 }
5267
5268 int
5269 cmd_ctables (struct lexer *lexer, struct dataset *ds)
5270 {
5271   size_t n_vars = dict_get_n_vars (dataset_dict (ds));
5272   enum ctables_vlabel *vlabels = xnmalloc (n_vars, sizeof *vlabels);
5273   enum settings_value_show tvars = settings_get_show_variables ();
5274   for (size_t i = 0; i < n_vars; i++)
5275     vlabels[i] = (enum ctables_vlabel) tvars;
5276
5277   struct pivot_table_look *look = pivot_table_look_unshare (
5278     pivot_table_look_ref (pivot_table_look_get_default ()));
5279   look->omit_empty = false;
5280
5281   struct ctables *ct = xmalloc (sizeof *ct);
5282   *ct = (struct ctables) {
5283     .dict = dataset_dict (ds),
5284     .look = look,
5285     .ctables_formats = FMT_SETTINGS_INIT,
5286     .vlabels = vlabels,
5287     .postcomputes = HMAP_INITIALIZER (ct->postcomputes),
5288   };
5289
5290   time_t now = time (NULL);
5291
5292   struct ctf
5293     {
5294       enum fmt_type type;
5295       const char *dot_string;
5296       const char *comma_string;
5297     };
5298   static const struct ctf ctfs[4] = {
5299     { CTEF_NEGPAREN, "(,,,)",   "(...)" },
5300     { CTEF_NEQUAL,   "-,N=,,",  "-.N=.." },
5301     { CTEF_PAREN,    "-,(,),",  "-.(.)." },
5302     { CTEF_PCTPAREN, "-,(,%),", "-.(.%)." },
5303   };
5304   bool is_dot = settings_get_fmt_settings ()->decimal == '.';
5305   for (size_t i = 0; i < 4; i++)
5306     {
5307       const char *s = is_dot ? ctfs[i].dot_string : ctfs[i].comma_string;
5308       fmt_settings_set_cc (&ct->ctables_formats, ctfs[i].type,
5309                            fmt_number_style_from_string (s));
5310     }
5311
5312   if (!lex_force_match (lexer, T_SLASH))
5313     goto error;
5314
5315   while (!lex_match_id (lexer, "TABLE"))
5316     {
5317       if (lex_match_id (lexer, "FORMAT"))
5318         {
5319           double widths[2] = { SYSMIS, SYSMIS };
5320           double units_per_inch = 72.0;
5321
5322           while (lex_token (lexer) != T_SLASH)
5323             {
5324               if (lex_match_id (lexer, "MINCOLWIDTH"))
5325                 {
5326                   if (!parse_col_width (lexer, "MINCOLWIDTH", &widths[0]))
5327                     goto error;
5328                 }
5329               else if (lex_match_id (lexer, "MAXCOLWIDTH"))
5330                 {
5331                   if (!parse_col_width (lexer, "MAXCOLWIDTH", &widths[1]))
5332                     goto error;
5333                 }
5334               else if (lex_match_id (lexer, "UNITS"))
5335                 {
5336                   lex_match (lexer, T_EQUALS);
5337                   if (lex_match_id (lexer, "POINTS"))
5338                     units_per_inch = 72.0;
5339                   else if (lex_match_id (lexer, "INCHES"))
5340                     units_per_inch = 1.0;
5341                   else if (lex_match_id (lexer, "CM"))
5342                     units_per_inch = 2.54;
5343                   else
5344                     {
5345                       lex_error_expecting (lexer, "POINTS", "INCHES", "CM");
5346                       goto error;
5347                     }
5348                 }
5349               else if (lex_match_id (lexer, "EMPTY"))
5350                 {
5351                   free (ct->zero);
5352                   ct->zero = NULL;
5353
5354                   lex_match (lexer, T_EQUALS);
5355                   if (lex_match_id (lexer, "ZERO"))
5356                     {
5357                       /* Nothing to do. */
5358                     }
5359                   else if (lex_match_id (lexer, "BLANK"))
5360                     ct->zero = xstrdup ("");
5361                   else if (lex_force_string (lexer))
5362                     {
5363                       ct->zero = ss_xstrdup (lex_tokss (lexer));
5364                       lex_get (lexer);
5365                     }
5366                   else
5367                     goto error;
5368                 }
5369               else if (lex_match_id (lexer, "MISSING"))
5370                 {
5371                   lex_match (lexer, T_EQUALS);
5372                   if (!lex_force_string (lexer))
5373                     goto error;
5374
5375                   free (ct->missing);
5376                   ct->missing = (strcmp (lex_tokcstr (lexer), ".")
5377                                  ? ss_xstrdup (lex_tokss (lexer))
5378                                  : NULL);
5379                   lex_get (lexer);
5380                 }
5381               else
5382                 {
5383                   lex_error_expecting (lexer, "MINCOLWIDTH", "MAXCOLWIDTH",
5384                                        "UNITS", "EMPTY", "MISSING");
5385                   goto error;
5386                 }
5387             }
5388
5389           if (widths[0] != SYSMIS && widths[1] != SYSMIS
5390               && widths[0] > widths[1])
5391             {
5392               msg (SE, _("MINCOLWIDTH must not be greater than MAXCOLWIDTH."));
5393               goto error;
5394             }
5395
5396           for (size_t i = 0; i < 2; i++)
5397             if (widths[i] != SYSMIS)
5398               {
5399                 int *wr = ct->look->width_ranges[TABLE_HORZ];
5400                 wr[i] = widths[i] / units_per_inch * 96.0;
5401                 if (wr[0] > wr[1])
5402                   wr[!i] = wr[i];
5403               }
5404         }
5405       else if (lex_match_id (lexer, "VLABELS"))
5406         {
5407           if (!lex_force_match_id (lexer, "VARIABLES"))
5408             goto error;
5409           lex_match (lexer, T_EQUALS);
5410
5411           struct variable **vars;
5412           size_t n_vars;
5413           if (!parse_variables (lexer, dataset_dict (ds), &vars, &n_vars,
5414                                 PV_NO_SCRATCH))
5415             goto error;
5416
5417           if (!lex_force_match_id (lexer, "DISPLAY"))
5418             {
5419               free (vars);
5420               goto error;
5421             }
5422           lex_match (lexer, T_EQUALS);
5423
5424           enum ctables_vlabel vlabel;
5425           if (lex_match_id (lexer, "DEFAULT"))
5426             vlabel = (enum ctables_vlabel) settings_get_show_variables ();
5427           else if (lex_match_id (lexer, "NAME"))
5428             vlabel = CTVL_NAME;
5429           else if (lex_match_id (lexer, "LABEL"))
5430             vlabel = CTVL_LABEL;
5431           else if (lex_match_id (lexer, "BOTH"))
5432             vlabel = CTVL_BOTH;
5433           else if (lex_match_id (lexer, "NONE"))
5434             vlabel = CTVL_NONE;
5435           else
5436             {
5437               lex_error_expecting (lexer, "DEFAULT", "NAME", "LABEL",
5438                                    "BOTH", "NONE");
5439               free (vars);
5440               goto error;
5441             }
5442
5443           for (size_t i = 0; i < n_vars; i++)
5444             ct->vlabels[var_get_dict_index (vars[i])] = vlabel;
5445           free (vars);
5446         }
5447       else if (lex_match_id (lexer, "MRSETS"))
5448         {
5449           if (!lex_force_match_id (lexer, "COUNTDUPLICATES"))
5450             goto error;
5451           lex_match (lexer, T_EQUALS);
5452           if (!parse_bool (lexer, &ct->mrsets_count_duplicates))
5453             goto error;
5454         }
5455       else if (lex_match_id (lexer, "SMISSING"))
5456         {
5457           if (lex_match_id (lexer, "VARIABLE"))
5458             ct->smissing_listwise = false;
5459           else if (lex_match_id (lexer, "LISTWISE"))
5460             ct->smissing_listwise = true;
5461           else
5462             {
5463               lex_error_expecting (lexer, "VARIABLE", "LISTWISE");
5464               goto error;
5465             }
5466         }
5467       else if (lex_match_id (lexer, "PCOMPUTE"))
5468         {
5469           if (!ctables_parse_pcompute (lexer, dataset_dict (ds), ct))
5470             goto error;
5471         }
5472       else if (lex_match_id (lexer, "PPROPERTIES"))
5473         {
5474           if (!ctables_parse_pproperties (lexer, ct))
5475             goto error;
5476         }
5477       else if (lex_match_id (lexer, "WEIGHT"))
5478         {
5479           if (!lex_force_match_id (lexer, "VARIABLE"))
5480             goto error;
5481           lex_match (lexer, T_EQUALS);
5482           ct->e_weight = parse_variable (lexer, dataset_dict (ds));
5483           if (!ct->e_weight)
5484             goto error;
5485         }
5486       else if (lex_match_id (lexer, " HIDESMALLCOUNTS"))
5487         {
5488           if (lex_match_id (lexer, "COUNT"))
5489             {
5490               lex_match (lexer, T_EQUALS);
5491               if (!lex_force_int_range (lexer, "HIDESMALLCOUNTS COUNT",
5492                                         2, INT_MAX))
5493                 goto error;
5494               ct->hide_threshold = lex_integer (lexer);
5495               lex_get (lexer);
5496             }
5497           else if (ct->hide_threshold == 0)
5498             ct->hide_threshold = 5;
5499         }
5500       else
5501         {
5502           lex_error_expecting (lexer, "FORMAT", "VLABELS", "MRSETS",
5503                                "SMISSING", "PCOMPUTE", "PPROPERTIES",
5504                                "WEIGHT", "HIDESMALLCOUNTS", "TABLE");
5505           goto error;
5506         }
5507
5508       if (!lex_force_match (lexer, T_SLASH))
5509         goto error;
5510     }
5511
5512   size_t allocated_tables = 0;
5513   do
5514     {
5515       if (ct->n_tables >= allocated_tables)
5516         ct->tables = x2nrealloc (ct->tables, &allocated_tables,
5517                                  sizeof *ct->tables);
5518
5519       struct ctables_category *cat = xmalloc (sizeof *cat);
5520       *cat = (struct ctables_category) {
5521         .type = CCT_VALUE,
5522         .include_missing = false,
5523         .sort_ascending = true,
5524       };
5525
5526       struct ctables_categories *c = xmalloc (sizeof *c);
5527       size_t n_vars = dict_get_n_vars (dataset_dict (ds));
5528       *c = (struct ctables_categories) {
5529         .n_refs = n_vars,
5530         .cats = cat,
5531         .n_cats = 1,
5532         .show_empty = true,
5533       };
5534
5535       struct ctables_categories **categories = xnmalloc (n_vars,
5536                                                          sizeof *categories);
5537       for (size_t i = 0; i < n_vars; i++)
5538         categories[i] = c;
5539
5540       struct ctables_table *t = xmalloc (sizeof *t);
5541       *t = (struct ctables_table) {
5542         .ctables = ct,
5543         .slabels_axis = PIVOT_AXIS_COLUMN,
5544         .slabels_visible = true,
5545         .clabels_values_map = HMAP_INITIALIZER (t->clabels_values_map),
5546         .label_axis = {
5547           [PIVOT_AXIS_ROW] = PIVOT_AXIS_ROW,
5548           [PIVOT_AXIS_COLUMN] = PIVOT_AXIS_COLUMN,
5549           [PIVOT_AXIS_LAYER] = PIVOT_AXIS_LAYER,
5550         },
5551         .clabels_from_axis = PIVOT_AXIS_LAYER,
5552         .categories = categories,
5553         .n_categories = n_vars,
5554         .cilevel = 95,
5555       };
5556       ct->tables[ct->n_tables++] = t;
5557
5558       lex_match (lexer, T_EQUALS);
5559       int expr_start = lex_ofs (lexer);
5560       if (!ctables_axis_parse (lexer, dataset_dict (ds), ct, t, PIVOT_AXIS_ROW))
5561         goto error;
5562       if (lex_match (lexer, T_BY))
5563         {
5564           if (!ctables_axis_parse (lexer, dataset_dict (ds),
5565                                    ct, t, PIVOT_AXIS_COLUMN))
5566             goto error;
5567
5568           if (lex_match (lexer, T_BY))
5569             {
5570               if (!ctables_axis_parse (lexer, dataset_dict (ds),
5571                                        ct, t, PIVOT_AXIS_LAYER))
5572                 goto error;
5573             }
5574         }
5575       int expr_end = lex_ofs (lexer);
5576
5577       if (!t->axes[PIVOT_AXIS_ROW] && !t->axes[PIVOT_AXIS_COLUMN]
5578           && !t->axes[PIVOT_AXIS_LAYER])
5579         {
5580           lex_error (lexer, _("At least one variable must be specified."));
5581           goto error;
5582         }
5583
5584       const struct ctables_axis *scales[PIVOT_N_AXES];
5585       size_t n_scales = 0;
5586       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
5587         {
5588           scales[a] = find_scale (t->axes[a]);
5589           if (scales[a])
5590             n_scales++;
5591         }
5592       if (n_scales > 1)
5593         {
5594           msg (SE, _("Scale variables may appear only on one axis."));
5595           if (scales[PIVOT_AXIS_ROW])
5596             msg_at (SN, scales[PIVOT_AXIS_ROW]->loc,
5597                     _("This scale variable appears on the rows axis."));
5598           if (scales[PIVOT_AXIS_COLUMN])
5599             msg_at (SN, scales[PIVOT_AXIS_COLUMN]->loc,
5600                     _("This scale variable appears on the columns axis."));
5601           if (scales[PIVOT_AXIS_LAYER])
5602             msg_at (SN, scales[PIVOT_AXIS_LAYER]->loc,
5603                     _("This scale variable appears on the layer axis."));
5604           goto error;
5605         }
5606
5607       const struct ctables_axis *summaries[PIVOT_N_AXES];
5608       size_t n_summaries = 0;
5609       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
5610         {
5611           summaries[a] = (scales[a]
5612                           ? scales[a]
5613                           : find_categorical_summary_spec (t->axes[a]));
5614           if (summaries[a])
5615             n_summaries++;
5616         }
5617       if (n_summaries > 1)
5618         {
5619           msg (SE, _("Summaries may appear only on one axis."));
5620           if (summaries[PIVOT_AXIS_ROW])
5621             msg_at (SN, summaries[PIVOT_AXIS_ROW]->loc,
5622                     _("This variable on the rows axis has a summary."));
5623           if (summaries[PIVOT_AXIS_COLUMN])
5624             msg_at (SN, summaries[PIVOT_AXIS_COLUMN]->loc,
5625                     _("This variable on the columns axis has a summary."));
5626           if (summaries[PIVOT_AXIS_LAYER])
5627             msg_at (SN, summaries[PIVOT_AXIS_LAYER]->loc,
5628                     _("This variable on the layers axis has a summary."));
5629           goto error;
5630         }
5631       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
5632         if (n_summaries ? summaries[a] : t->axes[a])
5633           {
5634             t->summary_axis = a;
5635             break;
5636           }
5637
5638       if (lex_token (lexer) == T_ENDCMD)
5639         {
5640           if (!ctables_prepare_table (t))
5641             goto error;
5642           break;
5643         }
5644       if (!lex_force_match (lexer, T_SLASH))
5645         break;
5646
5647       while (!lex_match_id (lexer, "TABLE") && lex_token (lexer) != T_ENDCMD)
5648         {
5649           if (lex_match_id (lexer, "SLABELS"))
5650             {
5651               while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
5652                 {
5653                   if (lex_match_id (lexer, "POSITION"))
5654                     {
5655                       lex_match (lexer, T_EQUALS);
5656                       if (lex_match_id (lexer, "COLUMN"))
5657                         t->slabels_axis = PIVOT_AXIS_COLUMN;
5658                       else if (lex_match_id (lexer, "ROW"))
5659                         t->slabels_axis = PIVOT_AXIS_ROW;
5660                       else if (lex_match_id (lexer, "LAYER"))
5661                         t->slabels_axis = PIVOT_AXIS_LAYER;
5662                       else
5663                         {
5664                           lex_error_expecting (lexer, "COLUMN", "ROW", "LAYER");
5665                           goto error;
5666                         }
5667                     }
5668                   else if (lex_match_id (lexer, "VISIBLE"))
5669                     {
5670                       lex_match (lexer, T_EQUALS);
5671                       if (!parse_bool (lexer, &t->slabels_visible))
5672                         goto error;
5673                     }
5674                   else
5675                     {
5676                       lex_error_expecting (lexer, "POSITION", "VISIBLE");
5677                       goto error;
5678                     }
5679                 }
5680             }
5681           else if (lex_match_id (lexer, "CLABELS"))
5682             {
5683               while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
5684                 {
5685                   if (lex_match_id (lexer, "AUTO"))
5686                     {
5687                       t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_ROW;
5688                       t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_COLUMN;
5689                     }
5690                   else if (lex_match_id (lexer, "ROWLABELS"))
5691                     {
5692                       lex_match (lexer, T_EQUALS);
5693                       if (lex_match_id (lexer, "OPPOSITE"))
5694                         t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_COLUMN;
5695                       else if (lex_match_id (lexer, "LAYER"))
5696                         t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_LAYER;
5697                       else
5698                         {
5699                           lex_error_expecting (lexer, "OPPOSITE", "LAYER");
5700                           goto error;
5701                         }
5702                     }
5703                   else if (lex_match_id (lexer, "COLLABELS"))
5704                     {
5705                       lex_match (lexer, T_EQUALS);
5706                       if (lex_match_id (lexer, "OPPOSITE"))
5707                         t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_ROW;
5708                       else if (lex_match_id (lexer, "LAYER"))
5709                         t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_LAYER;
5710                       else
5711                         {
5712                           lex_error_expecting (lexer, "OPPOSITE", "LAYER");
5713                           goto error;
5714                         }
5715                     }
5716                   else
5717                     {
5718                       lex_error_expecting (lexer, "AUTO", "ROWLABELS",
5719                                            "COLLABELS");
5720                       goto error;
5721                     }
5722                 }
5723             }
5724           else if (lex_match_id (lexer, "CRITERIA"))
5725             {
5726               if (!lex_force_match_id (lexer, "CILEVEL"))
5727                 goto error;
5728               lex_match (lexer, T_EQUALS);
5729
5730               if (!lex_force_num_range_halfopen (lexer, "CILEVEL", 0, 100))
5731                 goto error;
5732               t->cilevel = lex_number (lexer);
5733               lex_get (lexer);
5734             }
5735           else if (lex_match_id (lexer, "CATEGORIES"))
5736             {
5737               if (!ctables_table_parse_categories (lexer, dataset_dict (ds),
5738                                                    ct, t))
5739                 goto error;
5740             }
5741           else if (lex_match_id (lexer, "TITLES"))
5742             {
5743               do
5744                 {
5745                   char **textp;
5746                   if (lex_match_id (lexer, "CAPTION"))
5747                     textp = &t->caption;
5748                   else if (lex_match_id (lexer, "CORNER"))
5749                     textp = &t->corner;
5750                   else if (lex_match_id (lexer, "TITLE"))
5751                     textp = &t->title;
5752                   else
5753                     {
5754                       lex_error_expecting (lexer, "CAPTION", "CORNER", "TITLE");
5755                       goto error;
5756                     }
5757                   lex_match (lexer, T_EQUALS);
5758
5759                   struct string s = DS_EMPTY_INITIALIZER;
5760                   while (lex_is_string (lexer))
5761                     {
5762                       if (!ds_is_empty (&s))
5763                         ds_put_byte (&s, ' ');
5764                       put_title_text (&s, lex_tokss (lexer), now,
5765                                       lexer, dataset_dict (ds),
5766                                       expr_start, expr_end);
5767                       lex_get (lexer);
5768                     }
5769                   free (*textp);
5770                   *textp = ds_steal_cstr (&s);
5771                 }
5772               while (lex_token (lexer) != T_SLASH
5773                      && lex_token (lexer) != T_ENDCMD);
5774             }
5775           else if (lex_match_id (lexer, "SIGTEST"))
5776             {
5777               if (!t->chisq)
5778                 {
5779                   t->chisq = xmalloc (sizeof *t->chisq);
5780                   *t->chisq = (struct ctables_chisq) {
5781                     .alpha = .05,
5782                     .include_mrsets = true,
5783                     .all_visible = true,
5784                   };
5785                 }
5786
5787               do
5788                 {
5789                   if (lex_match_id (lexer, "TYPE"))
5790                     {
5791                       lex_match (lexer, T_EQUALS);
5792                       if (!lex_force_match_id (lexer, "CHISQUARE"))
5793                         goto error;
5794                     }
5795                   else if (lex_match_id (lexer, "ALPHA"))
5796                     {
5797                       lex_match (lexer, T_EQUALS);
5798                       if (!lex_force_num_range_halfopen (lexer, "ALPHA", 0, 1))
5799                         goto error;
5800                       t->chisq->alpha = lex_number (lexer);
5801                       lex_get (lexer);
5802                     }
5803                   else if (lex_match_id (lexer, "INCLUDEMRSETS"))
5804                     {
5805                       lex_match (lexer, T_EQUALS);
5806                       if (parse_bool (lexer, &t->chisq->include_mrsets))
5807                         goto error;
5808                     }
5809                   else if (lex_match_id (lexer, "CATEGORIES"))
5810                     {
5811                       lex_match (lexer, T_EQUALS);
5812                       if (lex_match_id (lexer, "ALLVISIBLE"))
5813                         t->chisq->all_visible = true;
5814                       else if (lex_match_id (lexer, "SUBTOTALS"))
5815                         t->chisq->all_visible = false;
5816                       else
5817                         {
5818                           lex_error_expecting (lexer,
5819                                                "ALLVISIBLE", "SUBTOTALS");
5820                           goto error;
5821                         }
5822                     }
5823                   else
5824                     {
5825                       lex_error_expecting (lexer, "TYPE", "ALPHA",
5826                                            "INCLUDEMRSETS", "CATEGORIES");
5827                       goto error;
5828                     }
5829                 }
5830               while (lex_token (lexer) != T_SLASH
5831                      && lex_token (lexer) != T_ENDCMD);
5832             }
5833           else if (lex_match_id (lexer, "COMPARETEST"))
5834             {
5835               if (!t->pairwise)
5836                 {
5837                   t->pairwise = xmalloc (sizeof *t->pairwise);
5838                   *t->pairwise = (struct ctables_pairwise) {
5839                     .type = PROP,
5840                     .alpha = { .05, .05 },
5841                     .adjust = BONFERRONI,
5842                     .include_mrsets = true,
5843                     .meansvariance_allcats = true,
5844                     .all_visible = true,
5845                     .merge = false,
5846                     .apa_style = true,
5847                     .show_sig = false,
5848                   };
5849                 }
5850
5851               do
5852                 {
5853                   if (lex_match_id (lexer, "TYPE"))
5854                     {
5855                       lex_match (lexer, T_EQUALS);
5856                       if (lex_match_id (lexer, "PROP"))
5857                         t->pairwise->type = PROP;
5858                       else if (lex_match_id (lexer, "MEAN"))
5859                         t->pairwise->type = MEAN;
5860                       else
5861                         {
5862                           lex_error_expecting (lexer, "PROP", "MEAN");
5863                           goto error;
5864                         }
5865                     }
5866                   else if (lex_match_id (lexer, "ALPHA"))
5867                     {
5868                       lex_match (lexer, T_EQUALS);
5869
5870                       if (!lex_force_num_range_open (lexer, "ALPHA", 0, 1))
5871                         goto error;
5872                       double a0 = lex_number (lexer);
5873                       lex_get (lexer);
5874
5875                       lex_match (lexer, T_COMMA);
5876                       if (lex_is_number (lexer))
5877                         {
5878                           if (!lex_force_num_range_open (lexer, "ALPHA", 0, 1))
5879                             goto error;
5880                           double a1 = lex_number (lexer);
5881                           lex_get (lexer);
5882
5883                           t->pairwise->alpha[0] = MIN (a0, a1);
5884                           t->pairwise->alpha[1] = MAX (a0, a1);
5885                         }
5886                       else
5887                         t->pairwise->alpha[0] = t->pairwise->alpha[1] = a0;
5888                     }
5889                   else if (lex_match_id (lexer, "ADJUST"))
5890                     {
5891                       lex_match (lexer, T_EQUALS);
5892                       if (lex_match_id (lexer, "BONFERRONI"))
5893                         t->pairwise->adjust = BONFERRONI;
5894                       else if (lex_match_id (lexer, "BH"))
5895                         t->pairwise->adjust = BH;
5896                       else if (lex_match_id (lexer, "NONE"))
5897                         t->pairwise->adjust = 0;
5898                       else
5899                         {
5900                           lex_error_expecting (lexer, "BONFERRONI", "BH",
5901                                                "NONE");
5902                           goto error;
5903                         }
5904                     }
5905                   else if (lex_match_id (lexer, "INCLUDEMRSETS"))
5906                     {
5907                       lex_match (lexer, T_EQUALS);
5908                       if (!parse_bool (lexer, &t->pairwise->include_mrsets))
5909                         goto error;
5910                     }
5911                   else if (lex_match_id (lexer, "MEANSVARIANCE"))
5912                     {
5913                       lex_match (lexer, T_EQUALS);
5914                       if (lex_match_id (lexer, "ALLCATS"))
5915                         t->pairwise->meansvariance_allcats = true;
5916                       else if (lex_match_id (lexer, "TESTEDCATS"))
5917                         t->pairwise->meansvariance_allcats = false;
5918                       else
5919                         {
5920                           lex_error_expecting (lexer, "ALLCATS", "TESTEDCATS");
5921                           goto error;
5922                         }
5923                     }
5924                   else if (lex_match_id (lexer, "CATEGORIES"))
5925                     {
5926                       lex_match (lexer, T_EQUALS);
5927                       if (lex_match_id (lexer, "ALLVISIBLE"))
5928                         t->pairwise->all_visible = true;
5929                       else if (lex_match_id (lexer, "SUBTOTALS"))
5930                         t->pairwise->all_visible = false;
5931                       else
5932                         {
5933                           lex_error_expecting (lexer, "ALLVISIBLE",
5934                                                "SUBTOTALS");
5935                           goto error;
5936                         }
5937                     }
5938                   else if (lex_match_id (lexer, "MERGE"))
5939                     {
5940                       lex_match (lexer, T_EQUALS);
5941                       if (!parse_bool (lexer, &t->pairwise->merge))
5942                         goto error;
5943                     }
5944                   else if (lex_match_id (lexer, "STYLE"))
5945                     {
5946                       lex_match (lexer, T_EQUALS);
5947                       if (lex_match_id (lexer, "APA"))
5948                         t->pairwise->apa_style = true;
5949                       else if (lex_match_id (lexer, "SIMPLE"))
5950                         t->pairwise->apa_style = false;
5951                       else
5952                         {
5953                           lex_error_expecting (lexer, "APA", "SIMPLE");
5954                           goto error;
5955                         }
5956                     }
5957                   else if (lex_match_id (lexer, "SHOWSIG"))
5958                     {
5959                       lex_match (lexer, T_EQUALS);
5960                       if (!parse_bool (lexer, &t->pairwise->show_sig))
5961                         goto error;
5962                     }
5963                   else
5964                     {
5965                       lex_error_expecting (lexer, "TYPE", "ALPHA", "ADJUST",
5966                                            "INCLUDEMRSETS", "MEANSVARIANCE",
5967                                            "CATEGORIES", "MERGE", "STYLE",
5968                                            "SHOWSIG");
5969                       goto error;
5970                     }
5971                 }
5972               while (lex_token (lexer) != T_SLASH
5973                      && lex_token (lexer) != T_ENDCMD);
5974             }
5975           else
5976             {
5977               lex_error_expecting (lexer, "TABLE", "SLABELS", "CLABELS",
5978                                    "CRITERIA", "CATEGORIES", "TITLES",
5979                                    "SIGTEST", "COMPARETEST");
5980               goto error;
5981             }
5982
5983           if (!lex_match (lexer, T_SLASH))
5984             break;
5985         }
5986
5987       if (t->label_axis[PIVOT_AXIS_ROW] != PIVOT_AXIS_ROW
5988           && t->label_axis[PIVOT_AXIS_COLUMN] != PIVOT_AXIS_COLUMN)
5989         {
5990           msg (SE, _("ROWLABELS and COLLABELS may not both be specified."));
5991           goto error;
5992         }
5993
5994       if (!ctables_prepare_table (t))
5995         goto error;
5996     }
5997   while (lex_token (lexer) != T_ENDCMD);
5998
5999   bool ok = ctables_execute (ds, ct);
6000   ctables_destroy (ct);
6001   return ok ? CMD_SUCCESS : CMD_FAILURE;
6002
6003 error:
6004   ctables_destroy (ct);
6005   return CMD_FAILURE;
6006 }
6007