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