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