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