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