no leaks?
[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               pivot_table_put (pt, dindexes, n_dindexes, value);
4792             }
4793         }
4794     }
4795
4796   pivot_table_submit (pt);
4797 }
4798
4799 static bool
4800 ctables_check_label_position (struct ctables_table *t, enum pivot_axis_type a)
4801 {
4802   enum pivot_axis_type label_pos = t->label_axis[a];
4803   if (label_pos == a)
4804     return true;
4805
4806   t->clabels_from_axis = a;
4807
4808   const char *subcommand_name = a == PIVOT_AXIS_ROW ? "ROWLABELS" : "COLLABELS";
4809   const char *pos_name = label_pos == PIVOT_AXIS_LAYER ? "LAYER" : "OPPOSITE";
4810
4811   const struct ctables_stack *stack = &t->stacks[a];
4812   if (!stack->n)
4813     return true;
4814
4815   const struct ctables_nest *n0 = &stack->nests[0];
4816   if (n0->n == 0)
4817     {
4818       assert (stack->n == 1);
4819       return true;
4820     }
4821
4822   const struct variable *v0 = n0->vars[n0->n - 1];
4823   struct ctables_categories *c0 = t->categories[var_get_dict_index (v0)];
4824   t->clabels_example = v0;
4825
4826   for (size_t i = 0; i < c0->n_cats; i++)
4827     if (c0->cats[i].type == CCT_FUNCTION)
4828       {
4829         msg (SE, _("%s=%s is not allowed with sorting based "
4830                    "on a summary function."),
4831              subcommand_name, pos_name);
4832         return false;
4833       }
4834   if (n0->n - 1 == n0->scale_idx)
4835     {
4836       msg (SE, _("%s=%s requires the variables to be moved to be categorical, "
4837                  "but %s is a scale variable."),
4838            subcommand_name, pos_name, var_get_name (v0));
4839       return false;
4840     }
4841
4842   for (size_t i = 1; i < stack->n; i++)
4843     {
4844       const struct ctables_nest *ni = &stack->nests[i];
4845       assert (ni->n > 0);
4846       const struct variable *vi = ni->vars[ni->n - 1];
4847       struct ctables_categories *ci = t->categories[var_get_dict_index (vi)];
4848
4849       if (ni->n - 1 == ni->scale_idx)
4850         {
4851           msg (SE, _("%s=%s requires the variables to be moved to be "
4852                      "categorical, but %s is a scale variable."),
4853                subcommand_name, pos_name, var_get_name (vi));
4854           return false;
4855         }
4856       if (var_get_width (v0) != var_get_width (vi))
4857         {
4858           msg (SE, _("%s=%s requires the variables to be "
4859                      "moved to have the same width, but %s has "
4860                      "width %d and %s has width %d."),
4861                subcommand_name, pos_name,
4862                var_get_name (v0), var_get_width (v0),
4863                var_get_name (vi), var_get_width (vi));
4864           return false;
4865         }
4866       if (!val_labs_equal (var_get_value_labels (v0),
4867                            var_get_value_labels (vi)))
4868         {
4869           msg (SE, _("%s=%s requires the variables to be "
4870                      "moved to have the same value labels, but %s "
4871                      "and %s have different value labels."),
4872                subcommand_name, pos_name,
4873                var_get_name (v0), var_get_name (vi));
4874           return false;
4875         }
4876       if (!ctables_categories_equal (c0, ci))
4877         {
4878           msg (SE, _("%s=%s requires the variables to be "
4879                      "moved to have the same category "
4880                      "specifications, but %s and %s have different "
4881                      "category specifications."),
4882                subcommand_name, pos_name,
4883                var_get_name (v0), var_get_name (vi));
4884           return false;
4885         }
4886     }
4887
4888   return true;
4889 }
4890
4891 static size_t
4892 add_sum_var (struct variable *var,
4893              struct variable ***sum_vars, size_t *n, size_t *allocated)
4894 {
4895   for (size_t i = 0; i < *n; i++)
4896     if (var == (*sum_vars)[i])
4897       return i;
4898
4899   if (*n >= *allocated)
4900     *sum_vars = x2nrealloc (*sum_vars, allocated, sizeof **sum_vars);
4901   (*sum_vars)[*n] = var;
4902   return (*n)++;
4903 }
4904
4905 static void
4906 enumerate_sum_vars (const struct ctables_axis *a,
4907                     struct variable ***sum_vars, size_t *n, size_t *allocated)
4908 {
4909   if (!a)
4910     return;
4911
4912   switch (a->op)
4913     {
4914     case CTAO_VAR:
4915       for (size_t i = 0; i < N_CSVS; i++)
4916         for (size_t j = 0; j < a->specs[i].n; j++)
4917           {
4918             struct ctables_summary_spec *spec = &a->specs[i].specs[j];
4919             if (ctables_function_is_pctsum (spec->function))
4920               spec->sum_var_idx = add_sum_var (a->var, sum_vars, n, allocated);
4921           }
4922       break;
4923
4924     case CTAO_STACK:
4925     case CTAO_NEST:
4926       for (size_t i = 0; i < 2; i++)
4927         enumerate_sum_vars (a->subs[i], sum_vars, n, allocated);
4928       break;
4929     }
4930 }
4931
4932 static bool
4933 ctables_prepare_table (struct ctables_table *t)
4934 {
4935   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
4936     if (t->axes[a])
4937       {
4938         t->stacks[a] = enumerate_fts (a, t->axes[a]);
4939
4940         for (size_t j = 0; j < t->stacks[a].n; j++)
4941           {
4942             struct ctables_nest *nest = &t->stacks[a].nests[j];
4943             for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
4944               {
4945                 nest->domains[dt] = xmalloc (nest->n * sizeof *nest->domains[dt]);
4946                 nest->n_domains[dt] = 0;
4947
4948                 for (size_t k = 0; k < nest->n; k++)
4949                   {
4950                     if (k == nest->scale_idx)
4951                       continue;
4952
4953                     switch (dt)
4954                       {
4955                       case CTDT_TABLE:
4956                         continue;
4957
4958                       case CTDT_LAYER:
4959                         if (a != PIVOT_AXIS_LAYER)
4960                           continue;
4961                         break;
4962
4963                       case CTDT_SUBTABLE:
4964                       case CTDT_ROW:
4965                       case CTDT_COL:
4966                         if (dt == CTDT_SUBTABLE ? a != PIVOT_AXIS_LAYER
4967                             : dt == CTDT_ROW ? a == PIVOT_AXIS_COLUMN
4968                             : a == PIVOT_AXIS_ROW)
4969                           {
4970                             if (k == nest->n - 1
4971                                 || (nest->scale_idx == nest->n - 1
4972                                     && k == nest->n - 2))
4973                               continue;
4974                           }
4975                         break;
4976
4977                       case CTDT_LAYERROW:
4978                         if (a == PIVOT_AXIS_COLUMN)
4979                           continue;
4980                         break;
4981
4982                       case CTDT_LAYERCOL:
4983                         if (a == PIVOT_AXIS_ROW)
4984                           continue;
4985                         break;
4986                       }
4987
4988                     nest->domains[dt][nest->n_domains[dt]++] = k;
4989                   }
4990               }
4991           }
4992       }
4993     else
4994       {
4995         struct ctables_nest *nest = xmalloc (sizeof *nest);
4996         *nest = (struct ctables_nest) { .n = 0 };
4997         t->stacks[a] = (struct ctables_stack) { .nests = nest, .n = 1 };
4998
4999         /* There's no point in moving labels away from an axis that has no
5000            labels, so avoid dealing with the special cases around that. */
5001         t->label_axis[a] = a;
5002       }
5003
5004   struct ctables_stack *stack = &t->stacks[t->summary_axis];
5005   for (size_t i = 0; i < stack->n; i++)
5006     {
5007       struct ctables_nest *nest = &stack->nests[i];
5008       if (!nest->specs[CSV_CELL].n)
5009         {
5010           struct ctables_summary_spec_set *specs = &nest->specs[CSV_CELL];
5011           specs->specs = xmalloc (sizeof *specs->specs);
5012           specs->n = 1;
5013
5014           enum ctables_summary_function function
5015             = specs->is_scale ? CTSF_MEAN : CTSF_COUNT;
5016
5017           *specs->specs = (struct ctables_summary_spec) {
5018             .function = function,
5019             .format = ctables_summary_default_format (function, specs->var),
5020           };
5021           if (!specs->var)
5022             specs->var = nest->vars[0];
5023
5024           ctables_summary_spec_set_clone (&nest->specs[CSV_TOTAL],
5025                                           &nest->specs[CSV_CELL]);
5026         }
5027       else if (!nest->specs[CSV_TOTAL].n)
5028         ctables_summary_spec_set_clone (&nest->specs[CSV_TOTAL],
5029                                         &nest->specs[CSV_CELL]);
5030
5031       if (t->ctables->smissing_listwise)
5032         {
5033           struct variable **listwise_vars = NULL;
5034           size_t n = 0;
5035           size_t allocated = 0;
5036
5037           for (size_t j = nest->group_head; j < stack->n; j++)
5038             {
5039               const struct ctables_nest *other_nest = &stack->nests[j];
5040               if (other_nest->group_head != nest->group_head)
5041                 break;
5042
5043               if (nest != other_nest && other_nest->scale_idx < other_nest->n)
5044                 {
5045                   if (n >= allocated)
5046                     listwise_vars = x2nrealloc (listwise_vars, &allocated,
5047                                                 sizeof *listwise_vars);
5048                   listwise_vars[n++] = other_nest->vars[other_nest->scale_idx];
5049                 }
5050             }
5051           for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
5052             {
5053               if (sv > 0)
5054                 listwise_vars = xmemdup (listwise_vars,
5055                                          n * sizeof *listwise_vars);
5056               nest->specs[sv].listwise_vars = listwise_vars;
5057               nest->specs[sv].n_listwise_vars = n;
5058             }
5059         }
5060     }
5061
5062   struct ctables_summary_spec_set *merged = &t->summary_specs;
5063   struct merge_item *items = xnmalloc (N_CSVS * stack->n, sizeof *items);
5064   size_t n_left = 0;
5065   for (size_t j = 0; j < stack->n; j++)
5066     {
5067       const struct ctables_nest *nest = &stack->nests[j];
5068       if (nest->n)
5069         for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
5070           items[n_left++] = (struct merge_item) { .set = &nest->specs[sv] };
5071     }
5072
5073   while (n_left > 0)
5074     {
5075       struct merge_item min = items[0];
5076       for (size_t j = 1; j < n_left; j++)
5077         if (merge_item_compare_3way (&items[j], &min) < 0)
5078           min = items[j];
5079
5080       if (merged->n >= merged->allocated)
5081         merged->specs = x2nrealloc (merged->specs, &merged->allocated,
5082                                     sizeof *merged->specs);
5083       merged->specs[merged->n++] = min.set->specs[min.ofs];
5084
5085       for (size_t j = 0; j < n_left; )
5086         {
5087           if (merge_item_compare_3way (&items[j], &min) == 0)
5088             {
5089               struct merge_item *item = &items[j];
5090               item->set->specs[item->ofs].axis_idx = merged->n - 1;
5091               if (++item->ofs >= item->set->n)
5092                 {
5093                   items[j] = items[--n_left];
5094                   continue;
5095                 }
5096             }
5097           j++;
5098         }
5099     }
5100   free (items);
5101
5102 #if 0
5103   for (size_t j = 0; j < merged->n; j++)
5104     printf ("%s\n", ctables_summary_function_name (merged->specs[j].function));
5105
5106   for (size_t j = 0; j < stack->n; j++)
5107     {
5108       const struct ctables_nest *nest = &stack->nests[j];
5109       for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
5110         {
5111           const struct ctables_summary_spec_set *specs = &nest->specs[sv];
5112           for (size_t k = 0; k < specs->n; k++)
5113             printf ("(%s, %zu) ", ctables_summary_function_name (specs->specs[k].function),
5114                     specs->specs[k].axis_idx);
5115           printf ("\n");
5116         }
5117     }
5118 #endif
5119
5120   size_t allocated_sum_vars = 0;
5121   enumerate_sum_vars (t->axes[t->summary_axis],
5122                       &t->sum_vars, &t->n_sum_vars, &allocated_sum_vars);
5123
5124   return (ctables_check_label_position (t, PIVOT_AXIS_ROW)
5125           && ctables_check_label_position (t, PIVOT_AXIS_COLUMN));
5126 }
5127
5128 static void
5129 ctables_insert_clabels_values (struct ctables_table *t, const struct ccase *c,
5130                                enum pivot_axis_type a)
5131 {
5132   struct ctables_stack *stack = &t->stacks[a];
5133   for (size_t i = 0; i < stack->n; i++)
5134     {
5135       const struct ctables_nest *nest = &stack->nests[i];
5136       const struct variable *var = nest->vars[nest->n - 1];
5137       const union value *value = case_data (c, var);
5138
5139       if (var_is_numeric (var) && value->f == SYSMIS)
5140         continue;
5141
5142       if (ctables_categories_match (t->categories [var_get_dict_index (var)],
5143                                     value, var))
5144         ctables_value_insert (t, value, var_get_width (var));
5145     }
5146 }
5147
5148 static int
5149 compare_clabels_values_3way (const void *a_, const void *b_, const void *width_)
5150 {
5151   const struct ctables_value *const *ap = a_;
5152   const struct ctables_value *const *bp = b_;
5153   const struct ctables_value *a = *ap;
5154   const struct ctables_value *b = *bp;
5155   const int *width = width_;
5156   return value_compare_3way (&a->value, &b->value, *width);
5157 }
5158
5159 static void
5160 ctables_sort_clabels_values (struct ctables_table *t)
5161 {
5162   const struct variable *v0 = t->clabels_example;
5163   int width = var_get_width (v0);
5164
5165   struct ctables_categories *c0 = t->categories[var_get_dict_index (v0)];
5166   if (c0->show_empty)
5167     {
5168       const struct val_labs *val_labs = var_get_value_labels (v0);
5169       for (const struct val_lab *vl = val_labs_first (val_labs); vl;
5170            vl = val_labs_next (val_labs, vl))
5171         if (ctables_categories_match (c0, &vl->value, v0))
5172           ctables_value_insert (t, &vl->value, width);
5173     }
5174
5175   size_t n = hmap_count (&t->clabels_values_map);
5176   t->clabels_values = xnmalloc (n, sizeof *t->clabels_values);
5177
5178   struct ctables_value *clv;
5179   size_t i = 0;
5180   HMAP_FOR_EACH (clv, struct ctables_value, node, &t->clabels_values_map)
5181     t->clabels_values[i++] = clv;
5182   t->n_clabels_values = n;
5183   assert (i == n);
5184
5185   sort (t->clabels_values, n, sizeof *t->clabels_values,
5186         compare_clabels_values_3way, &width);
5187
5188   for (size_t i = 0; i < n; i++)
5189     t->clabels_values[i]->leaf = i;
5190 }
5191
5192 static void
5193 ctables_add_category_occurrences (const struct variable *var,
5194                                   struct hmap *occurrences,
5195                                   const struct ctables_categories *cats)
5196 {
5197   const struct val_labs *val_labs = var_get_value_labels (var);
5198
5199   for (size_t i = 0; i < cats->n_cats; i++)
5200     {
5201       const struct ctables_category *c = &cats->cats[i];
5202       switch (c->type)
5203         {
5204         case CCT_NUMBER:
5205           ctables_add_occurrence (var, &(const union value) { .f = c->number },
5206                                   occurrences);
5207           break;
5208
5209         case CCT_STRING:
5210           {
5211             int width = var_get_width (var);
5212             union value value;
5213             value_init (&value, width);
5214             value_copy_buf_rpad (&value, width,
5215                                  CHAR_CAST (uint8_t *, c->string.string),
5216                                  c->string.length, ' ');
5217             ctables_add_occurrence (var, &value, occurrences);
5218             value_destroy (&value, width);
5219           }
5220           break;
5221
5222         case CCT_NRANGE:
5223           assert (var_is_numeric (var));
5224           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
5225                vl = val_labs_next (val_labs, vl))
5226             if (vl->value.f >= c->nrange[0] && vl->value.f <= c->nrange[1])
5227               ctables_add_occurrence (var, &vl->value, occurrences);
5228           break;
5229
5230         case CCT_SRANGE:
5231           assert (var_is_alpha (var));
5232           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
5233                vl = val_labs_next (val_labs, vl))
5234             if (in_string_range (&vl->value, var, c->srange))
5235               ctables_add_occurrence (var, &vl->value, occurrences);
5236           break;
5237
5238         case CCT_MISSING:
5239           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
5240                vl = val_labs_next (val_labs, vl))
5241             if (var_is_value_missing (var, &vl->value))
5242               ctables_add_occurrence (var, &vl->value, occurrences);
5243           break;
5244
5245         case CCT_OTHERNM:
5246           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
5247                vl = val_labs_next (val_labs, vl))
5248             ctables_add_occurrence (var, &vl->value, occurrences);
5249           break;
5250
5251         case CCT_POSTCOMPUTE:
5252           break;
5253
5254         case CCT_SUBTOTAL:
5255         case CCT_TOTAL:
5256           break;
5257
5258         case CCT_VALUE:
5259         case CCT_LABEL:
5260         case CCT_FUNCTION:
5261           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
5262                vl = val_labs_next (val_labs, vl))
5263             if (c->include_missing || !var_is_value_missing (var, &vl->value))
5264               ctables_add_occurrence (var, &vl->value, occurrences);
5265           break;
5266
5267         case CCT_EXCLUDED_MISSING:
5268           break;
5269         }
5270     }
5271 }
5272
5273 static void
5274 ctables_section_recurse_add_empty_categories (
5275   struct ctables_section *s,
5276   const struct ctables_category *cats[PIVOT_N_AXES][10], struct ccase *c,
5277   enum pivot_axis_type a, size_t a_idx)
5278 {
5279   if (a >= PIVOT_N_AXES)
5280     ctables_cell_insert__ (s, c, cats);
5281   else if (!s->nests[a] || a_idx >= s->nests[a]->n)
5282     ctables_section_recurse_add_empty_categories (s, cats, c, a + 1, 0);
5283   else
5284     {
5285       const struct variable *var = s->nests[a]->vars[a_idx];
5286       const struct ctables_categories *categories = s->table->categories[
5287         var_get_dict_index (var)];
5288       int width = var_get_width (var);
5289       const struct hmap *occurrences = &s->occurrences[a][a_idx];
5290       const struct ctables_occurrence *o;
5291       HMAP_FOR_EACH (o, struct ctables_occurrence, node, occurrences)
5292         {
5293           union value *value = case_data_rw (c, var);
5294           value_destroy (value, width);
5295           value_clone (value, &o->value, width);
5296           cats[a][a_idx] = ctables_categories_match (categories, value, var);
5297           assert (cats[a][a_idx] != NULL);
5298           ctables_section_recurse_add_empty_categories (s, cats, c, a, a_idx + 1);
5299         }
5300
5301       for (size_t i = 0; i < categories->n_cats; i++)
5302         {
5303           const struct ctables_category *cat = &categories->cats[i];
5304           if (cat->type == CCT_POSTCOMPUTE)
5305             {
5306               cats[a][a_idx] = cat;
5307               ctables_section_recurse_add_empty_categories (s, cats, c, a, a_idx + 1);
5308             }
5309         }
5310     }
5311 }
5312
5313 static void
5314 ctables_section_add_empty_categories (struct ctables_section *s)
5315 {
5316   bool show_empty = false;
5317   for (size_t a = 0; a < PIVOT_N_AXES; a++)
5318     if (s->nests[a])
5319       for (size_t k = 0; k < s->nests[a]->n; k++)
5320         if (k != s->nests[a]->scale_idx)
5321           {
5322             const struct variable *var = s->nests[a]->vars[k];
5323             const struct ctables_categories *cats = s->table->categories[
5324               var_get_dict_index (var)];
5325             if (cats->show_empty)
5326               {
5327                 show_empty = true;
5328                 ctables_add_category_occurrences (var, &s->occurrences[a][k], cats);
5329               }
5330           }
5331   if (!show_empty)
5332     return;
5333
5334   const struct ctables_category *cats[PIVOT_N_AXES][10]; /* XXX */
5335   struct ccase *c = case_create (dict_get_proto (s->table->ctables->dict));
5336   ctables_section_recurse_add_empty_categories (s, cats, c, 0, 0);
5337   case_unref (c);
5338 }
5339
5340 static void
5341 ctables_section_clear (struct ctables_section *s)
5342 {
5343   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
5344     {
5345       const struct ctables_nest *nest = s->nests[a];
5346       for (size_t i = 0; i < nest->n; i++)
5347         if (i != nest->scale_idx)
5348           {
5349             const struct variable *var = nest->vars[i];
5350             int width = var_get_width (var);
5351             struct ctables_occurrence *o, *next;
5352             struct hmap *map = &s->occurrences[a][i];
5353             HMAP_FOR_EACH_SAFE (o, next, struct ctables_occurrence, node, map)
5354               {
5355                 value_destroy (&o->value, width);
5356                 hmap_delete (map, &o->node);
5357                 free (o);
5358               }
5359             hmap_shrink (map);
5360           }
5361     }
5362
5363   struct ctables_cell *cell, *next_cell;
5364   HMAP_FOR_EACH_SAFE (cell, next_cell, struct ctables_cell, node, &s->cells)
5365     {
5366       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
5367         {
5368           const struct ctables_nest *nest = s->nests[a];
5369           for (size_t i = 0; i < nest->n; i++)
5370             if (i != nest->scale_idx)
5371               value_destroy (&cell->axes[a].cvs[i].value,
5372                              var_get_width (nest->vars[i]));
5373           free (cell->axes[a].cvs);
5374         }
5375
5376       const struct ctables_nest *ss = s->nests[s->table->summary_axis];
5377       const struct ctables_summary_spec_set *specs = &ss->specs[cell->sv];
5378       for (size_t i = 0; i < specs->n; i++)
5379         ctables_summary_uninit (&cell->summaries[i], &specs->specs[i]);
5380       free (cell->summaries);
5381
5382       hmap_delete (&s->cells, &cell->node);
5383       free (cell);
5384     }
5385   hmap_shrink (&s->cells);
5386
5387   for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
5388     {
5389       struct ctables_domain *domain, *next_domain;
5390       HMAP_FOR_EACH_SAFE (domain, next_domain, struct ctables_domain, node,
5391                           &s->domains[dt])
5392         {
5393           free (domain->sums);
5394           hmap_delete (&s->domains[dt], &domain->node);
5395           free (domain);
5396         }
5397       hmap_shrink (&s->domains[dt]);
5398     }
5399 }
5400
5401 static void
5402 ctables_section_uninit (struct ctables_section *s)
5403 {
5404   ctables_section_clear (s);
5405
5406   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
5407     {
5408       struct ctables_nest *nest = s->nests[a];
5409       for (size_t i = 0; i < nest->n; i++)
5410         hmap_destroy (&s->occurrences[a][i]);
5411       free (s->occurrences[a]);
5412     }
5413
5414   hmap_destroy (&s->cells);
5415   for (size_t i = 0; i < N_CTDTS; i++)
5416     hmap_destroy (&s->domains[i]);
5417 }
5418
5419 static void
5420 ctables_table_clear (struct ctables_table *t)
5421 {
5422   for (size_t i = 0; i < t->n_sections; i++)
5423     ctables_section_clear (&t->sections[i]);
5424
5425   if (t->clabels_example)
5426     {
5427       int width = var_get_width (t->clabels_example);
5428       struct ctables_value *value, *next_value;
5429       HMAP_FOR_EACH_SAFE (value, next_value, struct ctables_value, node,
5430                           &t->clabels_values_map)
5431         {
5432           value_destroy (&value->value, width);
5433           hmap_delete (&t->clabels_values_map, &value->node);
5434           free (value);
5435         }
5436       hmap_shrink (&t->clabels_values_map);
5437
5438       free (t->clabels_values);
5439       t->clabels_values = NULL;
5440       t->n_clabels_values = 0;
5441     }
5442 }
5443
5444 static bool
5445 ctables_execute (struct dataset *ds, struct casereader *input,
5446                  struct ctables *ct)
5447 {
5448   for (size_t i = 0; i < ct->n_tables; i++)
5449     {
5450       struct ctables_table *t = ct->tables[i];
5451       t->sections = xnmalloc (MAX (1, t->stacks[PIVOT_AXIS_ROW].n) *
5452                               MAX (1, t->stacks[PIVOT_AXIS_COLUMN].n) *
5453                               MAX (1, t->stacks[PIVOT_AXIS_LAYER].n),
5454                               sizeof *t->sections);
5455       size_t ix[PIVOT_N_AXES];
5456       ctables_table_add_section (t, 0, ix);
5457     }
5458
5459   struct dictionary *dict = dataset_dict (ds);
5460   struct casegrouper *grouper
5461     = (dict_get_split_type (dict) == SPLIT_SEPARATE
5462        ? casegrouper_create_splits (input, dict)
5463        : casegrouper_create_vars (input, NULL, 0));
5464   struct casereader *group;
5465   while (casegrouper_get_next_group (grouper, &group))
5466     {
5467       /* Output SPLIT FILE variables. */
5468       struct ccase *c = casereader_peek (group, 0);
5469       if (c != NULL)
5470         {
5471           output_split_file_values (ds, c);
5472           case_unref (c);
5473         }
5474
5475       bool warn_on_invalid = true;
5476       for (c = casereader_read (group); c;
5477            case_unref (c), c = casereader_read (group))
5478         {
5479           double d_weight = dict_get_case_weight (dict, c, &warn_on_invalid);
5480           double e_weight = (ct->e_weight
5481                              ? var_force_valid_weight (ct->e_weight,
5482                                                        case_num (c, ct->e_weight),
5483                                                        &warn_on_invalid)
5484                              : d_weight);
5485
5486           for (size_t i = 0; i < ct->n_tables; i++)
5487             {
5488               struct ctables_table *t = ct->tables[i];
5489
5490               for (size_t j = 0; j < t->n_sections; j++)
5491                 ctables_cell_insert (&t->sections[j], c, d_weight, e_weight);
5492
5493               for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
5494                 if (t->label_axis[a] != a)
5495                   ctables_insert_clabels_values (t, c, a);
5496             }
5497         }
5498       casereader_destroy (group);
5499
5500       for (size_t i = 0; i < ct->n_tables; i++)
5501         {
5502           struct ctables_table *t = ct->tables[i];
5503
5504           if (t->clabels_example)
5505             ctables_sort_clabels_values (t);
5506
5507           for (size_t j = 0; j < t->n_sections; j++)
5508             ctables_section_add_empty_categories (&t->sections[j]);
5509
5510           ctables_table_output (ct, t);
5511           ctables_table_clear (t);
5512         }
5513     }
5514   return casegrouper_destroy (grouper);
5515 }
5516 \f
5517 /* Postcomputes. */
5518
5519 typedef struct ctables_pcexpr *parse_recursively_func (struct lexer *,
5520                                                        struct dictionary *);
5521
5522 static void
5523 ctables_pcexpr_destroy (struct ctables_pcexpr *e)
5524 {
5525   if (e)
5526     {
5527       switch (e->op)
5528         {
5529         case CTPO_CAT_STRING:
5530           ss_dealloc (&e->string);
5531           break;
5532
5533         case CTPO_CAT_SRANGE:
5534           for (size_t i = 0; i < 2; i++)
5535             ss_dealloc (&e->srange[i]);
5536           break;
5537
5538         case CTPO_ADD:
5539         case CTPO_SUB:
5540         case CTPO_MUL:
5541         case CTPO_DIV:
5542         case CTPO_POW:
5543         case CTPO_NEG:
5544           for (size_t i = 0; i < 2; i++)
5545             ctables_pcexpr_destroy (e->subs[i]);
5546           break;
5547
5548         case CTPO_CONSTANT:
5549         case CTPO_CAT_NUMBER:
5550         case CTPO_CAT_NRANGE:
5551         case CTPO_CAT_MISSING:
5552         case CTPO_CAT_OTHERNM:
5553         case CTPO_CAT_SUBTOTAL:
5554         case CTPO_CAT_TOTAL:
5555           break;
5556         }
5557
5558       msg_location_destroy (e->location);
5559       free (e);
5560     }
5561 }
5562
5563 static struct ctables_pcexpr *
5564 ctables_pcexpr_allocate_binary (enum ctables_postcompute_op op,
5565                                 struct ctables_pcexpr *sub0,
5566                                 struct ctables_pcexpr *sub1)
5567 {
5568   struct ctables_pcexpr *e = xmalloc (sizeof *e);
5569   *e = (struct ctables_pcexpr) {
5570     .op = op,
5571     .subs = { sub0, sub1 },
5572     .location = msg_location_merged (sub0->location, sub1->location),
5573   };
5574   return e;
5575 }
5576
5577 /* How to parse an operator. */
5578 struct operator
5579   {
5580     enum token_type token;
5581     enum ctables_postcompute_op op;
5582   };
5583
5584 static const struct operator *
5585 ctables_pcexpr_match_operator (struct lexer *lexer,
5586                               const struct operator ops[], size_t n_ops)
5587 {
5588   for (const struct operator *op = ops; op < ops + n_ops; op++)
5589     if (lex_token (lexer) == op->token)
5590       {
5591         if (op->token != T_NEG_NUM)
5592           lex_get (lexer);
5593
5594         return op;
5595       }
5596
5597   return NULL;
5598 }
5599
5600 static struct ctables_pcexpr *
5601 ctables_pcexpr_parse_binary_operators__ (
5602   struct lexer *lexer, struct dictionary *dict,
5603   const struct operator ops[], size_t n_ops,
5604   parse_recursively_func *parse_next_level,
5605   const char *chain_warning, struct ctables_pcexpr *lhs)
5606 {
5607   for (int op_count = 0; ; op_count++)
5608     {
5609       const struct operator *op
5610         = ctables_pcexpr_match_operator (lexer, ops, n_ops);
5611       if (!op)
5612         {
5613           if (op_count > 1 && chain_warning)
5614             msg_at (SW, lhs->location, "%s", chain_warning);
5615
5616           return lhs;
5617         }
5618
5619       struct ctables_pcexpr *rhs = parse_next_level (lexer, dict);
5620       if (!rhs)
5621         {
5622           ctables_pcexpr_destroy (lhs);
5623           return NULL;
5624         }
5625
5626       lhs = ctables_pcexpr_allocate_binary (op->op, lhs, rhs);
5627     }
5628 }
5629
5630 static struct ctables_pcexpr *
5631 ctables_pcexpr_parse_binary_operators (
5632   struct lexer *lexer, struct dictionary *dict,
5633   const struct operator ops[], size_t n_ops,
5634   parse_recursively_func *parse_next_level, const char *chain_warning)
5635 {
5636   struct ctables_pcexpr *lhs = parse_next_level (lexer, dict);
5637   if (!lhs)
5638     return NULL;
5639
5640   return ctables_pcexpr_parse_binary_operators__ (lexer, dict, ops, n_ops,
5641                                                  parse_next_level,
5642                                                  chain_warning, lhs);
5643 }
5644
5645 static struct ctables_pcexpr *ctables_pcexpr_parse_add (struct lexer *,
5646                                                         struct dictionary *);
5647
5648 static struct ctables_pcexpr
5649 ctpo_cat_nrange (double low, double high)
5650 {
5651   return (struct ctables_pcexpr) {
5652     .op = CTPO_CAT_NRANGE,
5653     .nrange = { low, high },
5654   };
5655 }
5656
5657 static struct ctables_pcexpr
5658 ctpo_cat_srange (struct substring low, struct substring high)
5659 {
5660   return (struct ctables_pcexpr) {
5661     .op = CTPO_CAT_SRANGE,
5662     .srange = { low, high },
5663   };
5664 }
5665
5666 static struct ctables_pcexpr *
5667 ctables_pcexpr_parse_primary (struct lexer *lexer, struct dictionary *dict)
5668 {
5669   int start_ofs = lex_ofs (lexer);
5670   struct ctables_pcexpr e;
5671   if (lex_is_number (lexer))
5672     {
5673       e = (struct ctables_pcexpr) { .op = CTPO_CONSTANT,
5674                                     .number = lex_number (lexer) };
5675       lex_get (lexer);
5676     }
5677   else if (lex_match_id (lexer, "MISSING"))
5678     e = (struct ctables_pcexpr) { .op = CTPO_CAT_MISSING };
5679   else if (lex_match_id (lexer, "OTHERNM"))
5680     e = (struct ctables_pcexpr) { .op = CTPO_CAT_OTHERNM };
5681   else if (lex_match_id (lexer, "TOTAL"))
5682     e = (struct ctables_pcexpr) { .op = CTPO_CAT_TOTAL };
5683   else if (lex_match_id (lexer, "SUBTOTAL"))
5684     {
5685       size_t subtotal_index = 0;
5686       if (lex_match (lexer, T_LBRACK))
5687         {
5688           if (!lex_force_int_range (lexer, "SUBTOTAL", 1, LONG_MAX))
5689             return NULL;
5690           subtotal_index = lex_integer (lexer);
5691           lex_get (lexer);
5692           if (!lex_force_match (lexer, T_RBRACK))
5693             return NULL;
5694         }
5695       e = (struct ctables_pcexpr) { .op = CTPO_CAT_SUBTOTAL,
5696                                     .subtotal_index = subtotal_index };
5697     }
5698   else if (lex_match (lexer, T_LBRACK))
5699     {
5700       if (lex_match_id (lexer, "LO"))
5701         {
5702           if (!lex_force_match_id (lexer, "THRU"))
5703             return false;
5704
5705           if (lex_is_string (lexer))
5706             {
5707               struct substring low = { .string = NULL };
5708               struct substring high = parse_substring (lexer, dict);
5709               e = ctpo_cat_srange (low, high);
5710             }
5711           else
5712             {
5713               if (!lex_force_num (lexer))
5714                 return false;
5715               e = ctpo_cat_nrange (-DBL_MAX, lex_number (lexer));
5716               lex_get (lexer);
5717             }
5718         }
5719       else if (lex_is_number (lexer))
5720         {
5721           double number = lex_number (lexer);
5722           lex_get (lexer);
5723           if (lex_match_id (lexer, "THRU"))
5724             {
5725               if (lex_match_id (lexer, "HI"))
5726                 e = ctpo_cat_nrange (number, DBL_MAX);
5727               else
5728                 {
5729                   if (!lex_force_num (lexer))
5730                     return false;
5731                   e = ctpo_cat_nrange (number, lex_number (lexer));
5732                   lex_get (lexer);
5733                 }
5734             }
5735           else
5736             e = (struct ctables_pcexpr) { .op = CTPO_CAT_NUMBER,
5737                                           .number = number };
5738         }
5739       else if (lex_is_string (lexer))
5740         {
5741           struct substring s = parse_substring (lexer, dict);
5742
5743           if (lex_match_id (lexer, "THRU"))
5744             {
5745               struct substring high;
5746
5747               if (lex_match_id (lexer, "HI"))
5748                 high = (struct substring) { .string = NULL };
5749               else
5750                 {
5751                   if (!lex_force_string (lexer))
5752                     {
5753                       ss_dealloc (&s);
5754                       return false;
5755                     }
5756                   high = parse_substring (lexer, dict);
5757                 }
5758
5759               e = ctpo_cat_srange (s, high);
5760             }
5761           else
5762             e = (struct ctables_pcexpr) { .op = CTPO_CAT_STRING, .string = s };
5763         }
5764       else
5765         {
5766           lex_error (lexer, NULL);
5767           return NULL;
5768         }
5769
5770       if (!lex_force_match (lexer, T_RBRACK))
5771         {
5772           if (e.op == CTPO_CAT_STRING)
5773             ss_dealloc (&e.string);
5774           else if (e.op == CTPO_CAT_SRANGE)
5775             {
5776               ss_dealloc (&e.srange[0]);
5777               ss_dealloc (&e.srange[1]);
5778             }
5779           return NULL;
5780         }
5781     }
5782   else if (lex_match (lexer, T_LPAREN))
5783     {
5784       struct ctables_pcexpr *ep = ctables_pcexpr_parse_add (lexer, dict);
5785       if (!ep)
5786         return NULL;
5787       if (!lex_force_match (lexer, T_RPAREN))
5788         {
5789           ctables_pcexpr_destroy (ep);
5790           return NULL;
5791         }
5792       return ep;
5793     }
5794   else
5795     {
5796       lex_error (lexer, NULL);
5797       return NULL;
5798     }
5799
5800   e.location = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer) - 1);
5801   return xmemdup (&e, sizeof e);
5802 }
5803
5804 static struct ctables_pcexpr *
5805 ctables_pcexpr_allocate_neg (struct ctables_pcexpr *sub,
5806                              struct lexer *lexer, int start_ofs)
5807 {
5808   struct ctables_pcexpr *e = xmalloc (sizeof *e);
5809   *e = (struct ctables_pcexpr) {
5810     .op = CTPO_NEG,
5811     .subs = { sub },
5812     .location = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer) - 1),
5813   };
5814   return e;
5815 }
5816
5817 static struct ctables_pcexpr *
5818 ctables_pcexpr_parse_exp (struct lexer *lexer, struct dictionary *dict)
5819 {
5820   static const struct operator op = { T_EXP, CTPO_POW };
5821
5822   const char *chain_warning =
5823     _("The exponentiation operator (`**') is left-associative: "
5824       "`a**b**c' equals `(a**b)**c', not `a**(b**c)'.  "
5825       "To disable this warning, insert parentheses.");
5826
5827   if (lex_token (lexer) != T_NEG_NUM || lex_next_token (lexer, 1) != T_EXP)
5828     return ctables_pcexpr_parse_binary_operators (lexer, dict, &op, 1,
5829                                                   ctables_pcexpr_parse_primary,
5830                                                   chain_warning);
5831
5832   /* Special case for situations like "-5**6", which must be parsed as
5833      -(5**6). */
5834
5835   int start_ofs = lex_ofs (lexer);
5836   struct ctables_pcexpr *lhs = xmalloc (sizeof *lhs);
5837   *lhs = (struct ctables_pcexpr) {
5838     .op = CTPO_CONSTANT,
5839     .number = -lex_tokval (lexer),
5840     .location = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer)),
5841   };
5842   lex_get (lexer);
5843
5844   struct ctables_pcexpr *node = ctables_pcexpr_parse_binary_operators__ (
5845     lexer, dict, &op, 1,
5846     ctables_pcexpr_parse_primary, chain_warning, lhs);
5847   if (!node)
5848     return NULL;
5849
5850   return ctables_pcexpr_allocate_neg (node, lexer, start_ofs);
5851 }
5852
5853 /* Parses the unary minus level. */
5854 static struct ctables_pcexpr *
5855 ctables_pcexpr_parse_neg (struct lexer *lexer, struct dictionary *dict)
5856 {
5857   int start_ofs = lex_ofs (lexer);
5858   if (!lex_match (lexer, T_DASH))
5859     return ctables_pcexpr_parse_exp (lexer, dict);
5860
5861   struct ctables_pcexpr *inner = ctables_pcexpr_parse_neg (lexer, dict);
5862   if (!inner)
5863     return NULL;
5864
5865   return ctables_pcexpr_allocate_neg (inner, lexer, start_ofs);
5866 }
5867
5868 /* Parses the multiplication and division level. */
5869 static struct ctables_pcexpr *
5870 ctables_pcexpr_parse_mul (struct lexer *lexer, struct dictionary *dict)
5871 {
5872   static const struct operator ops[] =
5873     {
5874       { T_ASTERISK, CTPO_MUL },
5875       { T_SLASH, CTPO_DIV },
5876     };
5877
5878   return ctables_pcexpr_parse_binary_operators (lexer, dict, ops,
5879                                                sizeof ops / sizeof *ops,
5880                                                ctables_pcexpr_parse_neg, NULL);
5881 }
5882
5883 /* Parses the addition and subtraction level. */
5884 static struct ctables_pcexpr *
5885 ctables_pcexpr_parse_add (struct lexer *lexer, struct dictionary *dict)
5886 {
5887   static const struct operator ops[] =
5888     {
5889       { T_PLUS, CTPO_ADD },
5890       { T_DASH, CTPO_SUB },
5891       { T_NEG_NUM, CTPO_ADD },
5892     };
5893
5894   return ctables_pcexpr_parse_binary_operators (lexer, dict,
5895                                                ops, sizeof ops / sizeof *ops,
5896                                                ctables_pcexpr_parse_mul, NULL);
5897 }
5898
5899 static struct ctables_postcompute *
5900 ctables_find_postcompute (struct ctables *ct, const char *name)
5901 {
5902   struct ctables_postcompute *pc;
5903   HMAP_FOR_EACH_WITH_HASH (pc, struct ctables_postcompute, hmap_node,
5904                            utf8_hash_case_string (name, 0), &ct->postcomputes)
5905     if (!utf8_strcasecmp (pc->name, name))
5906       return pc;
5907   return NULL;
5908 }
5909
5910 static bool
5911 ctables_parse_pcompute (struct lexer *lexer, struct dictionary *dict,
5912                         struct ctables *ct)
5913 {
5914   int pcompute_start = lex_ofs (lexer) - 1;
5915
5916   if (!lex_match (lexer, T_AND))
5917     {
5918       lex_error_expecting (lexer, "&");
5919       return false;
5920     }
5921   if (!lex_force_id (lexer))
5922     return false;
5923
5924   char *name = ss_xstrdup (lex_tokss (lexer));
5925
5926   lex_get (lexer);
5927   if (!lex_force_match (lexer, T_EQUALS)
5928       || !lex_force_match_id (lexer, "EXPR")
5929       || !lex_force_match (lexer, T_LPAREN))
5930     {
5931       free (name);
5932       return false;
5933     }
5934
5935   int expr_start = lex_ofs (lexer);
5936   struct ctables_pcexpr *expr = ctables_pcexpr_parse_add (lexer, dict);
5937   int expr_end = lex_ofs (lexer) - 1;
5938   if (!expr || !lex_force_match (lexer, T_RPAREN))
5939     {
5940       ctables_pcexpr_destroy (expr);
5941       free (name);
5942       return false;
5943     }
5944   int pcompute_end = lex_ofs (lexer) - 1;
5945
5946   struct msg_location *location = lex_ofs_location (lexer, pcompute_start,
5947                                                     pcompute_end);
5948
5949   struct ctables_postcompute *pc = ctables_find_postcompute (ct, name);
5950   if (pc)
5951     {
5952       msg_at (SW, location, _("New definition of &%s will override the "
5953                               "previous definition."),
5954               pc->name);
5955       msg_at (SN, pc->location, _("This is the previous definition."));
5956
5957       ctables_pcexpr_destroy (pc->expr);
5958       msg_location_destroy (pc->location);
5959       free (name);
5960     }
5961   else
5962     {
5963       pc = xmalloc (sizeof *pc);
5964       *pc = (struct ctables_postcompute) { .name = name };
5965       hmap_insert (&ct->postcomputes, &pc->hmap_node,
5966                    utf8_hash_case_string (pc->name, 0));
5967     }
5968   pc->expr = expr;
5969   pc->location = location;
5970   if (!pc->label)
5971     pc->label = lex_ofs_representation (lexer, expr_start, expr_end);
5972   return true;
5973 }
5974
5975 static bool
5976 ctables_parse_pproperties_format (struct lexer *lexer,
5977                                   struct ctables_summary_spec_set *sss)
5978 {
5979   *sss = (struct ctables_summary_spec_set) { .n = 0 };
5980
5981   while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH
5982          && !(lex_token (lexer) == T_ID
5983               && (lex_id_match (ss_cstr ("LABEL"), lex_tokss (lexer))
5984                   || lex_id_match (ss_cstr ("HIDESOURCECATS"),
5985                                    lex_tokss (lexer)))))
5986     {
5987       /* Parse function. */
5988       enum ctables_summary_function function;
5989       if (!parse_ctables_summary_function (lexer, &function))
5990         goto error;
5991
5992       /* Parse percentile. */
5993       double percentile = 0;
5994       if (function == CTSF_PTILE)
5995         {
5996           if (!lex_force_num_range_closed (lexer, "PTILE", 0, 100))
5997             goto error;
5998           percentile = lex_number (lexer);
5999           lex_get (lexer);
6000         }
6001
6002       /* Parse format. */
6003       struct fmt_spec format;
6004       bool is_ctables_format;
6005       if (!parse_ctables_format_specifier (lexer, &format, &is_ctables_format))
6006         goto error;
6007
6008       if (sss->n >= sss->allocated)
6009         sss->specs = x2nrealloc (sss->specs, &sss->allocated,
6010                                  sizeof *sss->specs);
6011       sss->specs[sss->n++] = (struct ctables_summary_spec) {
6012         .function = function,
6013         .percentile = percentile,
6014         .format = format,
6015         .is_ctables_format = is_ctables_format,
6016       };
6017     }
6018   return true;
6019
6020 error:
6021   ctables_summary_spec_set_uninit (sss);
6022   return false;
6023 }
6024
6025 static bool
6026 ctables_parse_pproperties (struct lexer *lexer, struct ctables *ct)
6027 {
6028   struct ctables_postcompute **pcs = NULL;
6029   size_t n_pcs = 0;
6030   size_t allocated_pcs = 0;
6031
6032   while (lex_match (lexer, T_AND))
6033     {
6034       if (!lex_force_id (lexer))
6035         goto error;
6036       struct ctables_postcompute *pc
6037         = ctables_find_postcompute (ct, lex_tokcstr (lexer));
6038       if (!pc)
6039         {
6040           msg (SE, _("Unknown computed category &%s."), lex_tokcstr (lexer));
6041           goto error;
6042         }
6043       lex_get (lexer);
6044
6045       if (n_pcs >= allocated_pcs)
6046         pcs = x2nrealloc (pcs, &allocated_pcs, sizeof *pcs);
6047       pcs[n_pcs++] = pc;
6048     }
6049
6050   while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
6051     {
6052       if (lex_match_id (lexer, "LABEL"))
6053         {
6054           lex_match (lexer, T_EQUALS);
6055           if (!lex_force_string (lexer))
6056             goto error;
6057
6058           for (size_t i = 0; i < n_pcs; i++)
6059             {
6060               free (pcs[i]->label);
6061               pcs[i]->label = ss_xstrdup (lex_tokss (lexer));
6062             }
6063
6064           lex_get (lexer);
6065         }
6066       else if (lex_match_id (lexer, "FORMAT"))
6067         {
6068           lex_match (lexer, T_EQUALS);
6069
6070           struct ctables_summary_spec_set sss;
6071           if (!ctables_parse_pproperties_format (lexer, &sss))
6072             goto error;
6073
6074           for (size_t i = 0; i < n_pcs; i++)
6075             {
6076               if (pcs[i]->specs)
6077                 ctables_summary_spec_set_uninit (pcs[i]->specs);
6078               else
6079                 pcs[i]->specs = xmalloc (sizeof *pcs[i]->specs);
6080               ctables_summary_spec_set_clone (pcs[i]->specs, &sss);
6081             }
6082           ctables_summary_spec_set_uninit (&sss);
6083         }
6084       else if (lex_match_id (lexer, "HIDESOURCECATS"))
6085         {
6086           lex_match (lexer, T_EQUALS);
6087           bool hide_source_cats;
6088           if (!parse_bool (lexer, &hide_source_cats))
6089             goto error;
6090           for (size_t i = 0; i < n_pcs; i++)
6091             pcs[i]->hide_source_cats = hide_source_cats;
6092         }
6093       else
6094         {
6095           lex_error_expecting (lexer, "LABEL", "FORMAT", "HIDESOURCECATS");
6096           goto error;
6097         }
6098     }
6099   free (pcs);
6100   return true;
6101
6102 error:
6103   free (pcs);
6104   return false;
6105 }
6106
6107 static void
6108 put_strftime (struct string *out, time_t now, const char *format)
6109 {
6110   const struct tm *tm = localtime (&now);
6111   char value[128];
6112   strftime (value, sizeof value, format, tm);
6113   ds_put_cstr (out, value);
6114 }
6115
6116 static bool
6117 skip_prefix (struct substring *s, struct substring prefix)
6118 {
6119   if (ss_starts_with (*s, prefix))
6120     {
6121       ss_advance (s, prefix.length);
6122       return true;
6123     }
6124   else
6125     return false;
6126 }
6127
6128 static void
6129 put_table_expression (struct string *out, struct lexer *lexer,
6130                       struct dictionary *dict, int expr_start, int expr_end)
6131 {
6132   size_t nest = 0;
6133   for (int ofs = expr_start; ofs < expr_end; ofs++)
6134     {
6135       const struct token *t = lex_ofs_token (lexer, ofs);
6136       if (t->type == T_LBRACK)
6137         nest++;
6138       else if (t->type == T_RBRACK && nest > 0)
6139         nest--;
6140       else if (nest > 0)
6141         {
6142           /* Nothing. */
6143         }
6144       else if (t->type == T_ID)
6145         {
6146           const struct variable *var
6147             = dict_lookup_var (dict, t->string.string);
6148           const char *label = var ? var_get_label (var) : NULL;
6149           ds_put_cstr (out, label ? label : t->string.string);
6150         }
6151       else
6152         {
6153           if (ofs != expr_start && t->type != T_RPAREN && ds_last (out) != ' ')
6154             ds_put_byte (out, ' ');
6155
6156           char *repr = lex_ofs_representation (lexer, ofs, ofs);
6157           ds_put_cstr (out, repr);
6158           free (repr);
6159
6160           if (ofs + 1 != expr_end && t->type != T_LPAREN)
6161             ds_put_byte (out, ' ');
6162         }
6163     }
6164 }
6165
6166 static void
6167 put_title_text (struct string *out, struct substring in, time_t now,
6168                 struct lexer *lexer, struct dictionary *dict,
6169                 int expr_start, int expr_end)
6170 {
6171   for (;;)
6172     {
6173       size_t chunk = ss_find_byte (in, ')');
6174       ds_put_substring (out, ss_head (in, chunk));
6175       ss_advance (&in, chunk);
6176       if (ss_is_empty (in))
6177         return;
6178
6179       if (skip_prefix (&in, ss_cstr (")DATE")))
6180         put_strftime (out, now, "%x");
6181       else if (skip_prefix (&in, ss_cstr (")TIME")))
6182         put_strftime (out, now, "%X");
6183       else if (skip_prefix (&in, ss_cstr (")TABLE")))
6184         put_table_expression (out, lexer, dict, expr_start, expr_end);
6185       else
6186         {
6187           ds_put_byte (out, ')');
6188           ss_advance (&in, 1);
6189         }
6190     }
6191 }
6192
6193 int
6194 cmd_ctables (struct lexer *lexer, struct dataset *ds)
6195 {
6196   struct casereader *input = NULL;
6197
6198   struct measure_guesser *mg = measure_guesser_create (ds);
6199   if (mg)
6200     {
6201       input = proc_open (ds);
6202       measure_guesser_run (mg, input);
6203       measure_guesser_destroy (mg);
6204     }
6205
6206   size_t n_vars = dict_get_n_vars (dataset_dict (ds));
6207   enum ctables_vlabel *vlabels = xnmalloc (n_vars, sizeof *vlabels);
6208   enum settings_value_show tvars = settings_get_show_variables ();
6209   for (size_t i = 0; i < n_vars; i++)
6210     vlabels[i] = (enum ctables_vlabel) tvars;
6211
6212   struct pivot_table_look *look = pivot_table_look_unshare (
6213     pivot_table_look_ref (pivot_table_look_get_default ()));
6214   look->omit_empty = false;
6215
6216   struct ctables *ct = xmalloc (sizeof *ct);
6217   *ct = (struct ctables) {
6218     .dict = dataset_dict (ds),
6219     .look = look,
6220     .ctables_formats = FMT_SETTINGS_INIT,
6221     .vlabels = vlabels,
6222     .postcomputes = HMAP_INITIALIZER (ct->postcomputes),
6223   };
6224
6225   time_t now = time (NULL);
6226
6227   struct ctf
6228     {
6229       enum fmt_type type;
6230       const char *dot_string;
6231       const char *comma_string;
6232     };
6233   static const struct ctf ctfs[4] = {
6234     { CTEF_NEGPAREN, "(,,,)",   "(...)" },
6235     { CTEF_NEQUAL,   "-,N=,,",  "-.N=.." },
6236     { CTEF_PAREN,    "-,(,),",  "-.(.)." },
6237     { CTEF_PCTPAREN, "-,(,%),", "-.(.%)." },
6238   };
6239   bool is_dot = settings_get_fmt_settings ()->decimal == '.';
6240   for (size_t i = 0; i < 4; i++)
6241     {
6242       const char *s = is_dot ? ctfs[i].dot_string : ctfs[i].comma_string;
6243       fmt_settings_set_cc (&ct->ctables_formats, ctfs[i].type,
6244                            fmt_number_style_from_string (s));
6245     }
6246
6247   if (!lex_force_match (lexer, T_SLASH))
6248     goto error;
6249
6250   while (!lex_match_id (lexer, "TABLE"))
6251     {
6252       if (lex_match_id (lexer, "FORMAT"))
6253         {
6254           double widths[2] = { SYSMIS, SYSMIS };
6255           double units_per_inch = 72.0;
6256
6257           while (lex_token (lexer) != T_SLASH)
6258             {
6259               if (lex_match_id (lexer, "MINCOLWIDTH"))
6260                 {
6261                   if (!parse_col_width (lexer, "MINCOLWIDTH", &widths[0]))
6262                     goto error;
6263                 }
6264               else if (lex_match_id (lexer, "MAXCOLWIDTH"))
6265                 {
6266                   if (!parse_col_width (lexer, "MAXCOLWIDTH", &widths[1]))
6267                     goto error;
6268                 }
6269               else if (lex_match_id (lexer, "UNITS"))
6270                 {
6271                   lex_match (lexer, T_EQUALS);
6272                   if (lex_match_id (lexer, "POINTS"))
6273                     units_per_inch = 72.0;
6274                   else if (lex_match_id (lexer, "INCHES"))
6275                     units_per_inch = 1.0;
6276                   else if (lex_match_id (lexer, "CM"))
6277                     units_per_inch = 2.54;
6278                   else
6279                     {
6280                       lex_error_expecting (lexer, "POINTS", "INCHES", "CM");
6281                       goto error;
6282                     }
6283                 }
6284               else if (lex_match_id (lexer, "EMPTY"))
6285                 {
6286                   free (ct->zero);
6287                   ct->zero = NULL;
6288
6289                   lex_match (lexer, T_EQUALS);
6290                   if (lex_match_id (lexer, "ZERO"))
6291                     {
6292                       /* Nothing to do. */
6293                     }
6294                   else if (lex_match_id (lexer, "BLANK"))
6295                     ct->zero = xstrdup ("");
6296                   else if (lex_force_string (lexer))
6297                     {
6298                       ct->zero = ss_xstrdup (lex_tokss (lexer));
6299                       lex_get (lexer);
6300                     }
6301                   else
6302                     goto error;
6303                 }
6304               else if (lex_match_id (lexer, "MISSING"))
6305                 {
6306                   lex_match (lexer, T_EQUALS);
6307                   if (!lex_force_string (lexer))
6308                     goto error;
6309
6310                   free (ct->missing);
6311                   ct->missing = (strcmp (lex_tokcstr (lexer), ".")
6312                                  ? ss_xstrdup (lex_tokss (lexer))
6313                                  : NULL);
6314                   lex_get (lexer);
6315                 }
6316               else
6317                 {
6318                   lex_error_expecting (lexer, "MINCOLWIDTH", "MAXCOLWIDTH",
6319                                        "UNITS", "EMPTY", "MISSING");
6320                   goto error;
6321                 }
6322             }
6323
6324           if (widths[0] != SYSMIS && widths[1] != SYSMIS
6325               && widths[0] > widths[1])
6326             {
6327               msg (SE, _("MINCOLWIDTH must not be greater than MAXCOLWIDTH."));
6328               goto error;
6329             }
6330
6331           for (size_t i = 0; i < 2; i++)
6332             if (widths[i] != SYSMIS)
6333               {
6334                 int *wr = ct->look->width_ranges[TABLE_HORZ];
6335                 wr[i] = widths[i] / units_per_inch * 96.0;
6336                 if (wr[0] > wr[1])
6337                   wr[!i] = wr[i];
6338               }
6339         }
6340       else if (lex_match_id (lexer, "VLABELS"))
6341         {
6342           if (!lex_force_match_id (lexer, "VARIABLES"))
6343             goto error;
6344           lex_match (lexer, T_EQUALS);
6345
6346           struct variable **vars;
6347           size_t n_vars;
6348           if (!parse_variables (lexer, dataset_dict (ds), &vars, &n_vars,
6349                                 PV_NO_SCRATCH))
6350             goto error;
6351
6352           if (!lex_force_match_id (lexer, "DISPLAY"))
6353             {
6354               free (vars);
6355               goto error;
6356             }
6357           lex_match (lexer, T_EQUALS);
6358
6359           enum ctables_vlabel vlabel;
6360           if (lex_match_id (lexer, "DEFAULT"))
6361             vlabel = (enum ctables_vlabel) settings_get_show_variables ();
6362           else if (lex_match_id (lexer, "NAME"))
6363             vlabel = CTVL_NAME;
6364           else if (lex_match_id (lexer, "LABEL"))
6365             vlabel = CTVL_LABEL;
6366           else if (lex_match_id (lexer, "BOTH"))
6367             vlabel = CTVL_BOTH;
6368           else if (lex_match_id (lexer, "NONE"))
6369             vlabel = CTVL_NONE;
6370           else
6371             {
6372               lex_error_expecting (lexer, "DEFAULT", "NAME", "LABEL",
6373                                    "BOTH", "NONE");
6374               free (vars);
6375               goto error;
6376             }
6377
6378           for (size_t i = 0; i < n_vars; i++)
6379             ct->vlabels[var_get_dict_index (vars[i])] = vlabel;
6380           free (vars);
6381         }
6382       else if (lex_match_id (lexer, "MRSETS"))
6383         {
6384           if (!lex_force_match_id (lexer, "COUNTDUPLICATES"))
6385             goto error;
6386           lex_match (lexer, T_EQUALS);
6387           if (!parse_bool (lexer, &ct->mrsets_count_duplicates))
6388             goto error;
6389         }
6390       else if (lex_match_id (lexer, "SMISSING"))
6391         {
6392           if (lex_match_id (lexer, "VARIABLE"))
6393             ct->smissing_listwise = false;
6394           else if (lex_match_id (lexer, "LISTWISE"))
6395             ct->smissing_listwise = true;
6396           else
6397             {
6398               lex_error_expecting (lexer, "VARIABLE", "LISTWISE");
6399               goto error;
6400             }
6401         }
6402       else if (lex_match_id (lexer, "PCOMPUTE"))
6403         {
6404           if (!ctables_parse_pcompute (lexer, dataset_dict (ds), ct))
6405             goto error;
6406         }
6407       else if (lex_match_id (lexer, "PPROPERTIES"))
6408         {
6409           if (!ctables_parse_pproperties (lexer, ct))
6410             goto error;
6411         }
6412       else if (lex_match_id (lexer, "WEIGHT"))
6413         {
6414           if (!lex_force_match_id (lexer, "VARIABLE"))
6415             goto error;
6416           lex_match (lexer, T_EQUALS);
6417           ct->e_weight = parse_variable (lexer, dataset_dict (ds));
6418           if (!ct->e_weight)
6419             goto error;
6420         }
6421       else if (lex_match_id (lexer, "HIDESMALLCOUNTS"))
6422         {
6423           if (lex_match_id (lexer, "COUNT"))
6424             {
6425               lex_match (lexer, T_EQUALS);
6426               if (!lex_force_int_range (lexer, "HIDESMALLCOUNTS COUNT",
6427                                         2, INT_MAX))
6428                 goto error;
6429               ct->hide_threshold = lex_integer (lexer);
6430               lex_get (lexer);
6431             }
6432           else if (ct->hide_threshold == 0)
6433             ct->hide_threshold = 5;
6434         }
6435       else
6436         {
6437           lex_error_expecting (lexer, "FORMAT", "VLABELS", "MRSETS",
6438                                "SMISSING", "PCOMPUTE", "PPROPERTIES",
6439                                "WEIGHT", "HIDESMALLCOUNTS", "TABLE");
6440           goto error;
6441         }
6442
6443       if (!lex_force_match (lexer, T_SLASH))
6444         goto error;
6445     }
6446
6447   size_t allocated_tables = 0;
6448   do
6449     {
6450       if (ct->n_tables >= allocated_tables)
6451         ct->tables = x2nrealloc (ct->tables, &allocated_tables,
6452                                  sizeof *ct->tables);
6453
6454       struct ctables_category *cat = xmalloc (sizeof *cat);
6455       *cat = (struct ctables_category) {
6456         .type = CCT_VALUE,
6457         .include_missing = false,
6458         .sort_ascending = true,
6459       };
6460
6461       struct ctables_categories *c = xmalloc (sizeof *c);
6462       size_t n_vars = dict_get_n_vars (dataset_dict (ds));
6463       *c = (struct ctables_categories) {
6464         .n_refs = n_vars,
6465         .cats = cat,
6466         .n_cats = 1,
6467         .show_empty = true,
6468       };
6469
6470       struct ctables_categories **categories = xnmalloc (n_vars,
6471                                                          sizeof *categories);
6472       for (size_t i = 0; i < n_vars; i++)
6473         categories[i] = c;
6474
6475       struct ctables_table *t = xmalloc (sizeof *t);
6476       *t = (struct ctables_table) {
6477         .ctables = ct,
6478         .slabels_axis = PIVOT_AXIS_COLUMN,
6479         .slabels_visible = true,
6480         .clabels_values_map = HMAP_INITIALIZER (t->clabels_values_map),
6481         .label_axis = {
6482           [PIVOT_AXIS_ROW] = PIVOT_AXIS_ROW,
6483           [PIVOT_AXIS_COLUMN] = PIVOT_AXIS_COLUMN,
6484           [PIVOT_AXIS_LAYER] = PIVOT_AXIS_LAYER,
6485         },
6486         .clabels_from_axis = PIVOT_AXIS_LAYER,
6487         .categories = categories,
6488         .n_categories = n_vars,
6489         .cilevel = 95,
6490       };
6491       ct->tables[ct->n_tables++] = t;
6492
6493       lex_match (lexer, T_EQUALS);
6494       int expr_start = lex_ofs (lexer);
6495       if (!ctables_axis_parse (lexer, dataset_dict (ds), ct, t, PIVOT_AXIS_ROW))
6496         goto error;
6497       if (lex_match (lexer, T_BY))
6498         {
6499           if (!ctables_axis_parse (lexer, dataset_dict (ds),
6500                                    ct, t, PIVOT_AXIS_COLUMN))
6501             goto error;
6502
6503           if (lex_match (lexer, T_BY))
6504             {
6505               if (!ctables_axis_parse (lexer, dataset_dict (ds),
6506                                        ct, t, PIVOT_AXIS_LAYER))
6507                 goto error;
6508             }
6509         }
6510       int expr_end = lex_ofs (lexer);
6511
6512       if (!t->axes[PIVOT_AXIS_ROW] && !t->axes[PIVOT_AXIS_COLUMN]
6513           && !t->axes[PIVOT_AXIS_LAYER])
6514         {
6515           lex_error (lexer, _("At least one variable must be specified."));
6516           goto error;
6517         }
6518
6519       const struct ctables_axis *scales[PIVOT_N_AXES];
6520       size_t n_scales = 0;
6521       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
6522         {
6523           scales[a] = find_scale (t->axes[a]);
6524           if (scales[a])
6525             n_scales++;
6526         }
6527       if (n_scales > 1)
6528         {
6529           msg (SE, _("Scale variables may appear only on one axis."));
6530           if (scales[PIVOT_AXIS_ROW])
6531             msg_at (SN, scales[PIVOT_AXIS_ROW]->loc,
6532                     _("This scale variable appears on the rows axis."));
6533           if (scales[PIVOT_AXIS_COLUMN])
6534             msg_at (SN, scales[PIVOT_AXIS_COLUMN]->loc,
6535                     _("This scale variable appears on the columns axis."));
6536           if (scales[PIVOT_AXIS_LAYER])
6537             msg_at (SN, scales[PIVOT_AXIS_LAYER]->loc,
6538                     _("This scale variable appears on the layer axis."));
6539           goto error;
6540         }
6541
6542       const struct ctables_axis *summaries[PIVOT_N_AXES];
6543       size_t n_summaries = 0;
6544       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
6545         {
6546           summaries[a] = (scales[a]
6547                           ? scales[a]
6548                           : find_categorical_summary_spec (t->axes[a]));
6549           if (summaries[a])
6550             n_summaries++;
6551         }
6552       if (n_summaries > 1)
6553         {
6554           msg (SE, _("Summaries may appear only on one axis."));
6555           if (summaries[PIVOT_AXIS_ROW])
6556             msg_at (SN, summaries[PIVOT_AXIS_ROW]->loc,
6557                     _("This variable on the rows axis has a summary."));
6558           if (summaries[PIVOT_AXIS_COLUMN])
6559             msg_at (SN, summaries[PIVOT_AXIS_COLUMN]->loc,
6560                     _("This variable on the columns axis has a summary."));
6561           if (summaries[PIVOT_AXIS_LAYER])
6562             msg_at (SN, summaries[PIVOT_AXIS_LAYER]->loc,
6563                     _("This variable on the layers axis has a summary."));
6564           goto error;
6565         }
6566       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
6567         if (n_summaries ? summaries[a] : t->axes[a])
6568           {
6569             t->summary_axis = a;
6570             break;
6571           }
6572
6573       if (lex_token (lexer) == T_ENDCMD)
6574         {
6575           if (!ctables_prepare_table (t))
6576             goto error;
6577           break;
6578         }
6579       if (!lex_force_match (lexer, T_SLASH))
6580         goto error;
6581
6582       while (!lex_match_id (lexer, "TABLE") && lex_token (lexer) != T_ENDCMD)
6583         {
6584           if (lex_match_id (lexer, "SLABELS"))
6585             {
6586               while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
6587                 {
6588                   if (lex_match_id (lexer, "POSITION"))
6589                     {
6590                       lex_match (lexer, T_EQUALS);
6591                       if (lex_match_id (lexer, "COLUMN"))
6592                         t->slabels_axis = PIVOT_AXIS_COLUMN;
6593                       else if (lex_match_id (lexer, "ROW"))
6594                         t->slabels_axis = PIVOT_AXIS_ROW;
6595                       else if (lex_match_id (lexer, "LAYER"))
6596                         t->slabels_axis = PIVOT_AXIS_LAYER;
6597                       else
6598                         {
6599                           lex_error_expecting (lexer, "COLUMN", "ROW", "LAYER");
6600                           goto error;
6601                         }
6602                     }
6603                   else if (lex_match_id (lexer, "VISIBLE"))
6604                     {
6605                       lex_match (lexer, T_EQUALS);
6606                       if (!parse_bool (lexer, &t->slabels_visible))
6607                         goto error;
6608                     }
6609                   else
6610                     {
6611                       lex_error_expecting (lexer, "POSITION", "VISIBLE");
6612                       goto error;
6613                     }
6614                 }
6615             }
6616           else if (lex_match_id (lexer, "CLABELS"))
6617             {
6618               if (lex_match_id (lexer, "AUTO"))
6619                 {
6620                   t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_ROW;
6621                   t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_COLUMN;
6622                 }
6623               else if (lex_match_id (lexer, "ROWLABELS"))
6624                 {
6625                   lex_match (lexer, T_EQUALS);
6626                   if (lex_match_id (lexer, "OPPOSITE"))
6627                     t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_COLUMN;
6628                   else if (lex_match_id (lexer, "LAYER"))
6629                     t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_LAYER;
6630                   else
6631                     {
6632                       lex_error_expecting (lexer, "OPPOSITE", "LAYER");
6633                       goto error;
6634                     }
6635                 }
6636               else if (lex_match_id (lexer, "COLLABELS"))
6637                 {
6638                   lex_match (lexer, T_EQUALS);
6639                   if (lex_match_id (lexer, "OPPOSITE"))
6640                     t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_ROW;
6641                   else if (lex_match_id (lexer, "LAYER"))
6642                     t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_LAYER;
6643                   else
6644                     {
6645                       lex_error_expecting (lexer, "OPPOSITE", "LAYER");
6646                       goto error;
6647                     }
6648                 }
6649               else
6650                 {
6651                   lex_error_expecting (lexer, "AUTO", "ROWLABELS",
6652                                        "COLLABELS");
6653                   goto error;
6654                 }
6655             }
6656           else if (lex_match_id (lexer, "CRITERIA"))
6657             {
6658               if (!lex_force_match_id (lexer, "CILEVEL"))
6659                 goto error;
6660               lex_match (lexer, T_EQUALS);
6661
6662               if (!lex_force_num_range_halfopen (lexer, "CILEVEL", 0, 100))
6663                 goto error;
6664               t->cilevel = lex_number (lexer);
6665               lex_get (lexer);
6666             }
6667           else if (lex_match_id (lexer, "CATEGORIES"))
6668             {
6669               if (!ctables_table_parse_categories (lexer, dataset_dict (ds),
6670                                                    ct, t))
6671                 goto error;
6672             }
6673           else if (lex_match_id (lexer, "TITLES"))
6674             {
6675               do
6676                 {
6677                   char **textp;
6678                   if (lex_match_id (lexer, "CAPTION"))
6679                     textp = &t->caption;
6680                   else if (lex_match_id (lexer, "CORNER"))
6681                     textp = &t->corner;
6682                   else if (lex_match_id (lexer, "TITLE"))
6683                     textp = &t->title;
6684                   else
6685                     {
6686                       lex_error_expecting (lexer, "CAPTION", "CORNER", "TITLE");
6687                       goto error;
6688                     }
6689                   lex_match (lexer, T_EQUALS);
6690
6691                   struct string s = DS_EMPTY_INITIALIZER;
6692                   while (lex_is_string (lexer))
6693                     {
6694                       if (!ds_is_empty (&s))
6695                         ds_put_byte (&s, ' ');
6696                       put_title_text (&s, lex_tokss (lexer), now,
6697                                       lexer, dataset_dict (ds),
6698                                       expr_start, expr_end);
6699                       lex_get (lexer);
6700                     }
6701                   free (*textp);
6702                   *textp = ds_steal_cstr (&s);
6703                 }
6704               while (lex_token (lexer) != T_SLASH
6705                      && lex_token (lexer) != T_ENDCMD);
6706             }
6707           else if (lex_match_id (lexer, "SIGTEST"))
6708             {
6709               if (!t->chisq)
6710                 {
6711                   t->chisq = xmalloc (sizeof *t->chisq);
6712                   *t->chisq = (struct ctables_chisq) {
6713                     .alpha = .05,
6714                     .include_mrsets = true,
6715                     .all_visible = true,
6716                   };
6717                 }
6718
6719               do
6720                 {
6721                   if (lex_match_id (lexer, "TYPE"))
6722                     {
6723                       lex_match (lexer, T_EQUALS);
6724                       if (!lex_force_match_id (lexer, "CHISQUARE"))
6725                         goto error;
6726                     }
6727                   else if (lex_match_id (lexer, "ALPHA"))
6728                     {
6729                       lex_match (lexer, T_EQUALS);
6730                       if (!lex_force_num_range_halfopen (lexer, "ALPHA", 0, 1))
6731                         goto error;
6732                       t->chisq->alpha = lex_number (lexer);
6733                       lex_get (lexer);
6734                     }
6735                   else if (lex_match_id (lexer, "INCLUDEMRSETS"))
6736                     {
6737                       lex_match (lexer, T_EQUALS);
6738                       if (!parse_bool (lexer, &t->chisq->include_mrsets))
6739                         goto error;
6740                     }
6741                   else if (lex_match_id (lexer, "CATEGORIES"))
6742                     {
6743                       lex_match (lexer, T_EQUALS);
6744                       if (lex_match_id (lexer, "ALLVISIBLE"))
6745                         t->chisq->all_visible = true;
6746                       else if (lex_match_id (lexer, "SUBTOTALS"))
6747                         t->chisq->all_visible = false;
6748                       else
6749                         {
6750                           lex_error_expecting (lexer,
6751                                                "ALLVISIBLE", "SUBTOTALS");
6752                           goto error;
6753                         }
6754                     }
6755                   else
6756                     {
6757                       lex_error_expecting (lexer, "TYPE", "ALPHA",
6758                                            "INCLUDEMRSETS", "CATEGORIES");
6759                       goto error;
6760                     }
6761                 }
6762               while (lex_token (lexer) != T_SLASH
6763                      && lex_token (lexer) != T_ENDCMD);
6764             }
6765           else if (lex_match_id (lexer, "COMPARETEST"))
6766             {
6767               if (!t->pairwise)
6768                 {
6769                   t->pairwise = xmalloc (sizeof *t->pairwise);
6770                   *t->pairwise = (struct ctables_pairwise) {
6771                     .type = PROP,
6772                     .alpha = { .05, .05 },
6773                     .adjust = BONFERRONI,
6774                     .include_mrsets = true,
6775                     .meansvariance_allcats = true,
6776                     .all_visible = true,
6777                     .merge = false,
6778                     .apa_style = true,
6779                     .show_sig = false,
6780                   };
6781                 }
6782
6783               do
6784                 {
6785                   if (lex_match_id (lexer, "TYPE"))
6786                     {
6787                       lex_match (lexer, T_EQUALS);
6788                       if (lex_match_id (lexer, "PROP"))
6789                         t->pairwise->type = PROP;
6790                       else if (lex_match_id (lexer, "MEAN"))
6791                         t->pairwise->type = MEAN;
6792                       else
6793                         {
6794                           lex_error_expecting (lexer, "PROP", "MEAN");
6795                           goto error;
6796                         }
6797                     }
6798                   else if (lex_match_id (lexer, "ALPHA"))
6799                     {
6800                       lex_match (lexer, T_EQUALS);
6801
6802                       if (!lex_force_num_range_open (lexer, "ALPHA", 0, 1))
6803                         goto error;
6804                       double a0 = lex_number (lexer);
6805                       lex_get (lexer);
6806
6807                       lex_match (lexer, T_COMMA);
6808                       if (lex_is_number (lexer))
6809                         {
6810                           if (!lex_force_num_range_open (lexer, "ALPHA", 0, 1))
6811                             goto error;
6812                           double a1 = lex_number (lexer);
6813                           lex_get (lexer);
6814
6815                           t->pairwise->alpha[0] = MIN (a0, a1);
6816                           t->pairwise->alpha[1] = MAX (a0, a1);
6817                         }
6818                       else
6819                         t->pairwise->alpha[0] = t->pairwise->alpha[1] = a0;
6820                     }
6821                   else if (lex_match_id (lexer, "ADJUST"))
6822                     {
6823                       lex_match (lexer, T_EQUALS);
6824                       if (lex_match_id (lexer, "BONFERRONI"))
6825                         t->pairwise->adjust = BONFERRONI;
6826                       else if (lex_match_id (lexer, "BH"))
6827                         t->pairwise->adjust = BH;
6828                       else if (lex_match_id (lexer, "NONE"))
6829                         t->pairwise->adjust = 0;
6830                       else
6831                         {
6832                           lex_error_expecting (lexer, "BONFERRONI", "BH",
6833                                                "NONE");
6834                           goto error;
6835                         }
6836                     }
6837                   else if (lex_match_id (lexer, "INCLUDEMRSETS"))
6838                     {
6839                       lex_match (lexer, T_EQUALS);
6840                       if (!parse_bool (lexer, &t->pairwise->include_mrsets))
6841                         goto error;
6842                     }
6843                   else if (lex_match_id (lexer, "MEANSVARIANCE"))
6844                     {
6845                       lex_match (lexer, T_EQUALS);
6846                       if (lex_match_id (lexer, "ALLCATS"))
6847                         t->pairwise->meansvariance_allcats = true;
6848                       else if (lex_match_id (lexer, "TESTEDCATS"))
6849                         t->pairwise->meansvariance_allcats = false;
6850                       else
6851                         {
6852                           lex_error_expecting (lexer, "ALLCATS", "TESTEDCATS");
6853                           goto error;
6854                         }
6855                     }
6856                   else if (lex_match_id (lexer, "CATEGORIES"))
6857                     {
6858                       lex_match (lexer, T_EQUALS);
6859                       if (lex_match_id (lexer, "ALLVISIBLE"))
6860                         t->pairwise->all_visible = true;
6861                       else if (lex_match_id (lexer, "SUBTOTALS"))
6862                         t->pairwise->all_visible = false;
6863                       else
6864                         {
6865                           lex_error_expecting (lexer, "ALLVISIBLE",
6866                                                "SUBTOTALS");
6867                           goto error;
6868                         }
6869                     }
6870                   else if (lex_match_id (lexer, "MERGE"))
6871                     {
6872                       lex_match (lexer, T_EQUALS);
6873                       if (!parse_bool (lexer, &t->pairwise->merge))
6874                         goto error;
6875                     }
6876                   else if (lex_match_id (lexer, "STYLE"))
6877                     {
6878                       lex_match (lexer, T_EQUALS);
6879                       if (lex_match_id (lexer, "APA"))
6880                         t->pairwise->apa_style = true;
6881                       else if (lex_match_id (lexer, "SIMPLE"))
6882                         t->pairwise->apa_style = false;
6883                       else
6884                         {
6885                           lex_error_expecting (lexer, "APA", "SIMPLE");
6886                           goto error;
6887                         }
6888                     }
6889                   else if (lex_match_id (lexer, "SHOWSIG"))
6890                     {
6891                       lex_match (lexer, T_EQUALS);
6892                       if (!parse_bool (lexer, &t->pairwise->show_sig))
6893                         goto error;
6894                     }
6895                   else
6896                     {
6897                       lex_error_expecting (lexer, "TYPE", "ALPHA", "ADJUST",
6898                                            "INCLUDEMRSETS", "MEANSVARIANCE",
6899                                            "CATEGORIES", "MERGE", "STYLE",
6900                                            "SHOWSIG");
6901                       goto error;
6902                     }
6903                 }
6904               while (lex_token (lexer) != T_SLASH
6905                      && lex_token (lexer) != T_ENDCMD);
6906             }
6907           else
6908             {
6909               lex_error_expecting (lexer, "TABLE", "SLABELS", "CLABELS",
6910                                    "CRITERIA", "CATEGORIES", "TITLES",
6911                                    "SIGTEST", "COMPARETEST");
6912               goto error;
6913             }
6914
6915           if (!lex_match (lexer, T_SLASH))
6916             break;
6917         }
6918
6919       if (t->label_axis[PIVOT_AXIS_ROW] != PIVOT_AXIS_ROW
6920           && t->label_axis[PIVOT_AXIS_COLUMN] != PIVOT_AXIS_COLUMN)
6921         {
6922           msg (SE, _("ROWLABELS and COLLABELS may not both be specified."));
6923           goto error;
6924         }
6925
6926       if (!ctables_prepare_table (t))
6927         goto error;
6928     }
6929   while (lex_token (lexer) != T_ENDCMD);
6930
6931   if (!input)
6932     input = proc_open (ds);
6933   bool ok = ctables_execute (ds, input, ct);
6934   ok = proc_commit (ds) && ok;
6935
6936   ctables_destroy (ct);
6937   return ok ? CMD_SUCCESS : CMD_FAILURE;
6938
6939 error:
6940   if (input)
6941     proc_commit (ds);
6942   ctables_destroy (ct);
6943   return CMD_FAILURE;
6944 }
6945