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