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