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