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