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