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