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