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