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