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