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