areapct_sum
[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   for (enum pivot_axis_type pc_a = 0; ; pc_a++)
4217     {
4218       assert (pc_a < PIVOT_N_AXES);
4219       for (size_t pc_a_idx = 0; pc_a_idx < s->nests[pc_a]->n; pc_a_idx++)
4220         {
4221           const struct ctables_cell_value *cv = &cell->axes[pc_a].cvs[pc_a_idx];
4222           if (cv->category->type == CCT_POSTCOMPUTE)
4223             {
4224               if (pc_a_p)
4225                 *pc_a_p = pc_a;
4226               if (pc_a_idx_p)
4227                 *pc_a_idx_p = pc_a_idx;
4228               return cv->category->pc;
4229             }
4230         }
4231     }
4232
4233   NOT_REACHED ();
4234 }
4235
4236 static double
4237 ctables_cell_calculate_postcompute (const struct ctables_section *s,
4238                                     const struct ctables_cell *cell,
4239                                     const struct ctables_summary_spec *ss,
4240                                     struct fmt_spec *format,
4241                                     bool *is_ctables_format,
4242                                     size_t summary_idx)
4243 {
4244   enum pivot_axis_type pc_a;
4245   size_t pc_a_idx;
4246   const struct ctables_postcompute *pc = ctables_cell_postcompute (
4247     s, cell, &pc_a, &pc_a_idx);
4248
4249   if (pc->specs)
4250     {
4251       for (size_t i = 0; i < pc->specs->n; i++)
4252         {
4253           const struct ctables_summary_spec *ss2 = &pc->specs->specs[i];
4254           if (ss->function == ss2->function
4255               && ss->percentile == ss2->percentile)
4256             {
4257               *format = ss2->format;
4258               *is_ctables_format = ss2->is_ctables_format;
4259               break;
4260             }
4261         }
4262     }
4263
4264   const struct variable *var = s->nests[pc_a]->vars[pc_a_idx];
4265   const struct ctables_categories *cats = s->table->categories[
4266     var_get_dict_index (var)];
4267   struct ctables_pcexpr_evaluate_ctx ctx = {
4268     .cell = cell,
4269     .section = s,
4270     .cats = cats,
4271     .pc_a = pc_a,
4272     .pc_a_idx = pc_a_idx,
4273     .summary_idx = summary_idx,
4274   };
4275   return ctables_pcexpr_evaluate (&ctx, pc->expr);
4276 }
4277
4278 static void
4279 ctables_table_output (struct ctables *ct, struct ctables_table *t)
4280 {
4281   struct pivot_table *pt = pivot_table_create__ (
4282     (t->title
4283      ? pivot_value_new_user_text (t->title, SIZE_MAX)
4284      : pivot_value_new_text (N_("Custom Tables"))),
4285     "Custom Tables");
4286   if (t->caption)
4287     pivot_table_set_caption (
4288       pt, pivot_value_new_user_text (t->caption, SIZE_MAX));
4289   if (t->corner)
4290     pivot_table_set_corner_text (
4291       pt, pivot_value_new_user_text (t->corner, SIZE_MAX));
4292
4293   bool summary_dimension = (t->summary_axis != t->slabels_axis
4294                             || (!t->slabels_visible
4295                                 && t->summary_specs.n > 1));
4296   if (summary_dimension)
4297     {
4298       struct pivot_dimension *d = pivot_dimension_create (
4299         pt, t->slabels_axis, N_("Statistics"));
4300       const struct ctables_summary_spec_set *specs = &t->summary_specs;
4301       if (!t->slabels_visible)
4302         d->hide_all_labels = true;
4303       for (size_t i = 0; i < specs->n; i++)
4304         pivot_category_create_leaf (
4305           d->root, ctables_summary_label (&specs->specs[i], t->cilevel));
4306     }
4307
4308   bool categories_dimension = t->clabels_example != NULL;
4309   if (categories_dimension)
4310     {
4311       struct pivot_dimension *d = pivot_dimension_create (
4312         pt, t->label_axis[t->clabels_from_axis],
4313         t->clabels_from_axis == PIVOT_AXIS_ROW
4314         ? N_("Row Categories")
4315         : N_("Column Categories"));
4316       const struct variable *var = t->clabels_example;
4317       const struct ctables_categories *c = t->categories[var_get_dict_index (var)];
4318       for (size_t i = 0; i < t->n_clabels_values; i++)
4319         {
4320           const struct ctables_value *value = t->clabels_values[i];
4321           const struct ctables_category *cat = ctables_categories_match (c, &value->value, var);
4322           assert (cat != NULL);
4323           pivot_category_create_leaf (d->root, ctables_category_create_label (
4324                                         c, cat, t->clabels_example,
4325                                         &value->value));
4326         }
4327     }
4328
4329   pivot_table_set_look (pt, ct->look);
4330   struct pivot_dimension *d[PIVOT_N_AXES];
4331   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
4332     {
4333       static const char *names[] = {
4334         [PIVOT_AXIS_ROW] = N_("Rows"),
4335         [PIVOT_AXIS_COLUMN] = N_("Columns"),
4336         [PIVOT_AXIS_LAYER] = N_("Layers"),
4337       };
4338       d[a] = (t->axes[a] || a == t->summary_axis
4339               ? pivot_dimension_create (pt, a, names[a])
4340               : NULL);
4341       if (!d[a])
4342         continue;
4343
4344       assert (t->axes[a]);
4345
4346       for (size_t i = 0; i < t->stacks[a].n; i++)
4347         {
4348           struct ctables_nest *nest = &t->stacks[a].nests[i];
4349           struct ctables_section **sections = xnmalloc (t->n_sections,
4350                                                         sizeof *sections);
4351           size_t n_sections = 0;
4352
4353           size_t n_total_cells = 0;
4354           size_t max_depth = 0;
4355           for (size_t j = 0; j < t->n_sections; j++)
4356             if (t->sections[j].nests[a] == nest)
4357               {
4358                 struct ctables_section *s = &t->sections[j];
4359                 sections[n_sections++] = s;
4360                 n_total_cells += s->cells.count;
4361
4362                 size_t depth = s->nests[a]->n;
4363                 max_depth = MAX (depth, max_depth);
4364               }
4365
4366           struct ctables_cell **sorted = xnmalloc (n_total_cells,
4367                                                    sizeof *sorted);
4368           size_t n_sorted = 0;
4369
4370           for (size_t j = 0; j < n_sections; j++)
4371             {
4372               struct ctables_section *s = sections[j];
4373
4374               struct ctables_cell *cell;
4375               HMAP_FOR_EACH (cell, struct ctables_cell, node, &s->cells)
4376                 if (!cell->hide)
4377                   sorted[n_sorted++] = cell;
4378               assert (n_sorted <= n_total_cells);
4379             }
4380
4381           struct ctables_cell_sort_aux aux = { .nest = nest, .a = a };
4382           sort (sorted, n_sorted, sizeof *sorted, ctables_cell_compare_3way, &aux);
4383
4384 #if 0
4385           for (size_t j = 0; j < n_sorted; j++)
4386             {
4387               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);
4388             }
4389           printf ("\n");
4390 #endif
4391           
4392           struct ctables_level
4393             {
4394               enum ctables_level_type
4395                 {
4396                   CTL_VAR,          /* Variable label for nest->vars[var_idx]. */
4397                   CTL_CATEGORY,     /* Category for nest->vars[var_idx]. */
4398                   CTL_SUMMARY,      /* Summary functions. */
4399                 }
4400                 type;
4401
4402               enum settings_value_show vlabel; /* CTL_VAR only. */
4403               size_t var_idx;
4404             };
4405           struct ctables_level *levels = xnmalloc (1 + 2 * max_depth, sizeof *levels);
4406           size_t n_levels = 0;
4407           for (size_t k = 0; k < nest->n; k++)
4408             {
4409               enum ctables_vlabel vlabel = ct->vlabels[var_get_dict_index (nest->vars[k])];
4410               if (vlabel != CTVL_NONE)
4411                 {
4412                   levels[n_levels++] = (struct ctables_level) {
4413                     .type = CTL_VAR,
4414                     .vlabel = (enum settings_value_show) vlabel,
4415                     .var_idx = k,
4416                   };
4417                 }
4418
4419               if (nest->scale_idx != k
4420                   && (k != nest->n - 1 || t->label_axis[a] == a))
4421                 {
4422                   levels[n_levels++] = (struct ctables_level) {
4423                     .type = CTL_CATEGORY,
4424                     .var_idx = k,
4425                   };
4426                 }
4427             }
4428
4429           if (!summary_dimension && a == t->slabels_axis)
4430             {
4431               levels[n_levels++] = (struct ctables_level) {
4432                 .type = CTL_SUMMARY,
4433                 .var_idx = SIZE_MAX,
4434               };
4435             }
4436
4437           /* Pivot categories:
4438
4439              - variable label for nest->vars[0], if vlabel != CTVL_NONE
4440              - category for nest->vars[0], if nest->scale_idx != 0
4441              - variable label for nest->vars[1], if vlabel != CTVL_NONE
4442              - category for nest->vars[1], if nest->scale_idx != 1
4443              ...
4444              - variable label for nest->vars[n - 1], if vlabel != CTVL_NONE
4445              - category for nest->vars[n - 1], if t->label_axis[a] == a && nest->scale_idx != n - 1.
4446              - summary function, if 'a == t->slabels_axis && a ==
4447              t->summary_axis'.
4448
4449              Additional dimensions:
4450
4451              - If 'a == t->slabels_axis && a != t->summary_axis', add a summary
4452              dimension.
4453              - If 't->label_axis[b] == a' for some 'b != a', add a category
4454              dimension to 'a'.
4455           */
4456
4457
4458           struct pivot_category **groups = xnmalloc (1 + 2 * max_depth, sizeof *groups);
4459           int prev_leaf = 0;
4460           for (size_t j = 0; j < n_sorted; j++)
4461             {
4462               struct ctables_cell *cell = sorted[j];
4463               struct ctables_cell *prev = j > 0 ? sorted[j - 1] : NULL;
4464
4465               size_t n_common = 0;
4466               if (j > 0)
4467                 {
4468                   for (; n_common < n_levels; n_common++)
4469                     {
4470                       const struct ctables_level *level = &levels[n_common];
4471                       if (level->type == CTL_CATEGORY)
4472                         {
4473                           size_t var_idx = level->var_idx;
4474                           const struct ctables_category *c = cell->axes[a].cvs[var_idx].category;
4475                           if (prev->axes[a].cvs[var_idx].category != c)
4476                             break;
4477                           else if (c->type != CCT_SUBTOTAL
4478                                    && c->type != CCT_TOTAL
4479                                    && c->type != CCT_POSTCOMPUTE
4480                                    && !value_equal (&prev->axes[a].cvs[var_idx].value,
4481                                                     &cell->axes[a].cvs[var_idx].value,
4482                                                     var_get_type (nest->vars[var_idx])))
4483                             break;
4484                         }
4485                     }
4486                 }
4487
4488               for (size_t k = n_common; k < n_levels; k++)
4489                 {
4490                   const struct ctables_level *level = &levels[k];
4491                   struct pivot_category *parent = k ? groups[k - 1] : d[a]->root;
4492                   if (level->type == CTL_SUMMARY)
4493                     {
4494                       assert (k == n_levels - 1);
4495
4496                       const struct ctables_summary_spec_set *specs = &t->summary_specs;
4497                       for (size_t m = 0; m < specs->n; m++)
4498                         {
4499                           int leaf = pivot_category_create_leaf (
4500                             parent, ctables_summary_label (&specs->specs[m],
4501                                                            t->cilevel));
4502                           if (!m)
4503                             prev_leaf = leaf;
4504                         }
4505                     }
4506                   else
4507                     {
4508                       const struct variable *var = nest->vars[level->var_idx];
4509                       struct pivot_value *label;
4510                       if (level->type == CTL_VAR)
4511                         {
4512                           label = pivot_value_new_variable (var);
4513                           label->variable.show = level->vlabel;
4514                         }
4515                       else if (level->type == CTL_CATEGORY)
4516                         {
4517                           const struct ctables_cell_value *cv = &cell->axes[a].cvs[level->var_idx];
4518                           label = ctables_category_create_label (
4519                             t->categories[var_get_dict_index (var)],
4520                             cv->category, var, &cv->value);
4521                         }
4522                       else
4523                         NOT_REACHED ();
4524
4525                       if (k == n_levels - 1)
4526                         prev_leaf = pivot_category_create_leaf (parent, label);
4527                       else
4528                         groups[k] = pivot_category_create_group__ (parent, label);
4529                     }
4530                 }
4531
4532               cell->axes[a].leaf = prev_leaf;
4533             }
4534           free (sorted);
4535           free (groups);
4536         }
4537     }
4538
4539   for (size_t i = 0; i < t->n_sections; i++)
4540     {
4541       struct ctables_section *s = &t->sections[i];
4542
4543       struct ctables_cell *cell;
4544       HMAP_FOR_EACH (cell, struct ctables_cell, node, &s->cells)
4545         {
4546           if (cell->hide)
4547             continue;
4548
4549           const struct ctables_nest *specs_nest = s->nests[t->summary_axis];
4550           const struct ctables_summary_spec_set *specs = &specs_nest->specs[cell->sv];
4551           for (size_t j = 0; j < specs->n; j++)
4552             {
4553               size_t dindexes[5];
4554               size_t n_dindexes = 0;
4555
4556               if (summary_dimension)
4557                 dindexes[n_dindexes++] = specs->specs[j].axis_idx;
4558
4559               if (categories_dimension)
4560                 {
4561                   const struct ctables_nest *clabels_nest = s->nests[t->clabels_from_axis];
4562                   const struct variable *var = clabels_nest->vars[clabels_nest->n - 1];
4563                   const union value *value = &cell->axes[t->clabels_from_axis].cvs[clabels_nest->n - 1].value;
4564                   const struct ctables_value *ctv = ctables_value_find (t, value, var_get_width (var));
4565                   if (!ctv)
4566                     continue;
4567                   dindexes[n_dindexes++] = ctv->leaf;
4568                 }
4569
4570               for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
4571                 if (d[a])
4572                   {
4573                     int leaf = cell->axes[a].leaf;
4574                     if (a == t->summary_axis && !summary_dimension)
4575                       leaf += j;
4576                     dindexes[n_dindexes++] = leaf;
4577                   }
4578
4579               const struct ctables_summary_spec *ss = &specs->specs[j];
4580
4581               struct fmt_spec format = specs->specs[j].format;
4582               bool is_ctables_format = ss->is_ctables_format;
4583               double d = (cell->postcompute
4584                           ? ctables_cell_calculate_postcompute (
4585                             s, cell, ss, &format, &is_ctables_format, j)
4586                           : ctables_summary_value (cell, &cell->summaries[j],
4587                                                    ss));
4588
4589               struct pivot_value *value;
4590               if (ct->hide_threshold != 0
4591                   && d < ct->hide_threshold
4592                   && ctables_summary_function_is_count (ss->function))
4593                 {
4594                   value = pivot_value_new_user_text_nocopy (
4595                     xasprintf ("<%d", ct->hide_threshold));
4596                 }
4597               else if (d == 0 && ct->zero)
4598                 value = pivot_value_new_user_text (ct->zero, SIZE_MAX);
4599               else if (d == SYSMIS && ct->missing)
4600                 value = pivot_value_new_user_text (ct->missing, SIZE_MAX);
4601               else if (is_ctables_format)
4602                 {
4603                   char *s = data_out_stretchy (&(union value) { .f = d },
4604                                                "UTF-8", &format,
4605                                                &ct->ctables_formats, NULL);
4606                   value = pivot_value_new_user_text_nocopy (s);
4607                 }
4608               else
4609                 {
4610                   value = pivot_value_new_number (d);
4611                   value->numeric.format = format;
4612                 }
4613               pivot_table_put (pt, dindexes, n_dindexes, value);
4614             }
4615         }
4616     }
4617
4618   pivot_table_submit (pt);
4619 }
4620
4621 static bool
4622 ctables_check_label_position (struct ctables_table *t, enum pivot_axis_type a)
4623 {
4624   enum pivot_axis_type label_pos = t->label_axis[a];
4625   if (label_pos == a)
4626     return true;
4627
4628   t->clabels_from_axis = a;
4629
4630   const char *subcommand_name = a == PIVOT_AXIS_ROW ? "ROWLABELS" : "COLLABELS";
4631   const char *pos_name = label_pos == PIVOT_AXIS_LAYER ? "LAYER" : "OPPOSITE";
4632
4633   const struct ctables_stack *stack = &t->stacks[a];
4634   if (!stack->n)
4635     return true;
4636
4637   const struct ctables_nest *n0 = &stack->nests[0];
4638   assert (n0->n > 0);
4639   const struct variable *v0 = n0->vars[n0->n - 1];
4640   struct ctables_categories *c0 = t->categories[var_get_dict_index (v0)];
4641   t->clabels_example = v0;
4642
4643   for (size_t i = 0; i < c0->n_cats; i++)
4644     if (c0->cats[i].type == CCT_FUNCTION)
4645       {
4646         msg (SE, _("%s=%s is not allowed with sorting based "
4647                    "on a summary function."),
4648              subcommand_name, pos_name);
4649         return false;
4650       }
4651   if (n0->n - 1 == n0->scale_idx)
4652     {
4653       msg (SE, _("%s=%s requires the variables to be moved to be categorical, "
4654                  "but %s is a scale variable."),
4655            subcommand_name, pos_name, var_get_name (v0));
4656       return false;
4657     }
4658
4659   for (size_t i = 1; i < stack->n; i++)
4660     {
4661       const struct ctables_nest *ni = &stack->nests[i];
4662       assert (ni->n > 0);
4663       const struct variable *vi = ni->vars[ni->n - 1];
4664       struct ctables_categories *ci = t->categories[var_get_dict_index (vi)];
4665
4666       if (ni->n - 1 == ni->scale_idx)
4667         {
4668           msg (SE, _("%s=%s requires the variables to be moved to be "
4669                      "categorical, but %s is a scale variable."),
4670                subcommand_name, pos_name, var_get_name (vi));
4671           return false;
4672         }
4673       if (var_get_width (v0) != var_get_width (vi))
4674         {
4675           msg (SE, _("%s=%s requires the variables to be "
4676                      "moved to have the same width, but %s has "
4677                      "width %d and %s has width %d."),
4678                subcommand_name, pos_name,
4679                var_get_name (v0), var_get_width (v0),
4680                var_get_name (vi), var_get_width (vi));
4681           return false;
4682         }
4683       if (!val_labs_equal (var_get_value_labels (v0),
4684                            var_get_value_labels (vi)))
4685         {
4686           msg (SE, _("%s=%s requires the variables to be "
4687                      "moved to have the same value labels, but %s "
4688                      "and %s have different value labels."),
4689                subcommand_name, pos_name,
4690                var_get_name (v0), var_get_name (vi));
4691           return false;
4692         }
4693       if (!ctables_categories_equal (c0, ci))
4694         {
4695           msg (SE, _("%s=%s requires the variables to be "
4696                      "moved to have the same category "
4697                      "specifications, but %s and %s have different "
4698                      "category specifications."),
4699                subcommand_name, pos_name,
4700                var_get_name (v0), var_get_name (vi));
4701           return false;
4702         }
4703     }
4704
4705   return true;
4706 }
4707
4708 static size_t
4709 add_sum_var (struct variable *var,
4710              struct variable ***sum_vars, size_t *n, size_t *allocated)
4711 {
4712   for (size_t i = 0; i < *n; i++)
4713     if (var == (*sum_vars)[i])
4714       return i;
4715
4716   if (*n >= *allocated)
4717     *sum_vars = x2nrealloc (*sum_vars, allocated, sizeof **sum_vars);
4718   (*sum_vars)[*n] = var;
4719   return (*n)++;
4720 }
4721
4722 static void
4723 enumerate_sum_vars (const struct ctables_axis *a,
4724                     struct variable ***sum_vars, size_t *n, size_t *allocated)
4725 {
4726   if (!a)
4727     return;
4728
4729   switch (a->op)
4730     {
4731     case CTAO_VAR:
4732       for (size_t i = 0; i < N_CSVS; i++)
4733         for (size_t j = 0; j < a->specs[i].n; j++)
4734           {
4735             struct ctables_summary_spec *spec = &a->specs[i].specs[j];
4736             if (ctables_function_is_pctsum (spec->function))
4737               spec->sum_var_idx = add_sum_var (a->var, sum_vars, n, allocated);
4738           }
4739       break;
4740
4741     case CTAO_STACK:
4742     case CTAO_NEST:
4743       for (size_t i = 0; i < 2; i++)
4744         enumerate_sum_vars (a->subs[i], sum_vars, n, allocated);
4745       break;
4746     }
4747 }
4748
4749 static bool
4750 ctables_prepare_table (struct ctables_table *t)
4751 {
4752   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
4753     if (t->axes[a])
4754       {
4755         t->stacks[a] = enumerate_fts (a, t->axes[a]);
4756
4757         for (size_t j = 0; j < t->stacks[a].n; j++)
4758           {
4759             struct ctables_nest *nest = &t->stacks[a].nests[j];
4760             for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
4761               {
4762                 nest->domains[dt] = xmalloc (nest->n * sizeof *nest->domains[dt]);
4763                 nest->n_domains[dt] = 0;
4764
4765                 for (size_t k = 0; k < nest->n; k++)
4766                   {
4767                     if (k == nest->scale_idx)
4768                       continue;
4769
4770                     switch (dt)
4771                       {
4772                       case CTDT_TABLE:
4773                         continue;
4774
4775                       case CTDT_LAYER:
4776                         if (a != PIVOT_AXIS_LAYER)
4777                           continue;
4778                         break;
4779
4780                       case CTDT_SUBTABLE:
4781                       case CTDT_ROW:
4782                       case CTDT_COL:
4783                         if (dt == CTDT_SUBTABLE ? a != PIVOT_AXIS_LAYER
4784                             : dt == CTDT_ROW ? a == PIVOT_AXIS_COLUMN
4785                             : a == PIVOT_AXIS_ROW)
4786                           {
4787                             if (k == nest->n - 1
4788                                 || (nest->scale_idx == nest->n - 1
4789                                     && k == nest->n - 2))
4790                               continue;
4791                           }
4792                         break;
4793
4794                       case CTDT_LAYERROW:
4795                         if (a == PIVOT_AXIS_COLUMN)
4796                           continue;
4797                         break;
4798
4799                       case CTDT_LAYERCOL:
4800                         if (a == PIVOT_AXIS_ROW)
4801                           continue;
4802                         break;
4803                       }
4804
4805                     nest->domains[dt][nest->n_domains[dt]++] = k;
4806                   }
4807               }
4808           }
4809       }
4810     else
4811       {
4812         struct ctables_nest *nest = xmalloc (sizeof *nest);
4813         *nest = (struct ctables_nest) { .n = 0 };
4814         t->stacks[a] = (struct ctables_stack) { .nests = nest, .n = 1 };
4815       }
4816
4817   struct ctables_stack *stack = &t->stacks[t->summary_axis];
4818   for (size_t i = 0; i < stack->n; i++)
4819     {
4820       struct ctables_nest *nest = &stack->nests[i];
4821       if (!nest->specs[CSV_CELL].n)
4822         {
4823           struct ctables_summary_spec_set *specs = &nest->specs[CSV_CELL];
4824           specs->specs = xmalloc (sizeof *specs->specs);
4825           specs->n = 1;
4826
4827           enum ctables_summary_function function
4828             = specs->is_scale ? CTSF_MEAN : CTSF_COUNT;
4829
4830           *specs->specs = (struct ctables_summary_spec) {
4831             .function = function,
4832             .format = ctables_summary_default_format (function, specs->var),
4833           };
4834           if (!specs->var)
4835             specs->var = nest->vars[0];
4836
4837           ctables_summary_spec_set_clone (&nest->specs[CSV_TOTAL],
4838                                           &nest->specs[CSV_CELL]);
4839         }
4840       else if (!nest->specs[CSV_TOTAL].n)
4841         ctables_summary_spec_set_clone (&nest->specs[CSV_TOTAL],
4842                                         &nest->specs[CSV_CELL]);
4843
4844       if (t->ctables->smissing_listwise)
4845         {
4846           struct variable **listwise_vars = NULL;
4847           size_t n = 0;
4848           size_t allocated = 0;
4849
4850           for (size_t j = nest->group_head; j < stack->n; j++)
4851             {
4852               const struct ctables_nest *other_nest = &stack->nests[j];
4853               if (other_nest->group_head != nest->group_head)
4854                 break;
4855
4856               if (nest != other_nest && other_nest->scale_idx < other_nest->n)
4857                 {
4858                   if (n >= allocated)
4859                     listwise_vars = x2nrealloc (listwise_vars, &allocated,
4860                                                 sizeof *listwise_vars);
4861                   listwise_vars[n++] = other_nest->vars[other_nest->scale_idx];
4862                 }
4863             }
4864           for (size_t j = 0; j < N_CSVS; j++)
4865             {
4866               nest->specs[j].listwise_vars = listwise_vars;
4867               nest->specs[j].n_listwise_vars = n;
4868             }
4869         }
4870     }
4871
4872   struct ctables_summary_spec_set *merged = &t->summary_specs;
4873   struct merge_item *items = xnmalloc (N_CSVS * stack->n, sizeof *items);
4874   size_t n_left = 0;
4875   for (size_t j = 0; j < stack->n; j++)
4876     {
4877       const struct ctables_nest *nest = &stack->nests[j];
4878       if (nest->n)
4879         for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
4880           items[n_left++] = (struct merge_item) { .set = &nest->specs[sv] };
4881     }
4882
4883   while (n_left > 0)
4884     {
4885       struct merge_item min = items[0];
4886       for (size_t j = 1; j < n_left; j++)
4887         if (merge_item_compare_3way (&items[j], &min) < 0)
4888           min = items[j];
4889
4890       if (merged->n >= merged->allocated)
4891         merged->specs = x2nrealloc (merged->specs, &merged->allocated,
4892                                     sizeof *merged->specs);
4893       merged->specs[merged->n++] = min.set->specs[min.ofs];
4894
4895       for (size_t j = 0; j < n_left; )
4896         {
4897           if (merge_item_compare_3way (&items[j], &min) == 0)
4898             {
4899               struct merge_item *item = &items[j];
4900               item->set->specs[item->ofs].axis_idx = merged->n - 1;
4901               if (++item->ofs >= item->set->n)
4902                 {
4903                   items[j] = items[--n_left];
4904                   continue;
4905                 }
4906             }
4907           j++;
4908         }
4909     }
4910
4911 #if 0
4912   for (size_t j = 0; j < merged->n; j++)
4913     printf ("%s\n", ctables_summary_function_name (merged->specs[j].function));
4914
4915   for (size_t j = 0; j < stack->n; j++)
4916     {
4917       const struct ctables_nest *nest = &stack->nests[j];
4918       for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
4919         {
4920           const struct ctables_summary_spec_set *specs = &nest->specs[sv];
4921           for (size_t k = 0; k < specs->n; k++)
4922             printf ("(%s, %zu) ", ctables_summary_function_name (specs->specs[k].function),
4923                     specs->specs[k].axis_idx);
4924           printf ("\n");
4925         }
4926     }
4927 #endif
4928
4929   size_t allocated_sum_vars = 0;
4930   enumerate_sum_vars (t->axes[t->summary_axis],
4931                       &t->sum_vars, &t->n_sum_vars, &allocated_sum_vars);
4932
4933   return (ctables_check_label_position (t, PIVOT_AXIS_ROW)
4934           && ctables_check_label_position (t, PIVOT_AXIS_COLUMN));
4935 }
4936
4937 static void
4938 ctables_insert_clabels_values (struct ctables_table *t, const struct ccase *c,
4939                                enum pivot_axis_type a)
4940 {
4941   struct ctables_stack *stack = &t->stacks[a];
4942   for (size_t i = 0; i < stack->n; i++)
4943     {
4944       const struct ctables_nest *nest = &stack->nests[i];
4945       const struct variable *var = nest->vars[nest->n - 1];
4946       const union value *value = case_data (c, var);
4947
4948       if (var_is_numeric (var) && value->f == SYSMIS)
4949         continue;
4950
4951       if (ctables_categories_match (t->categories [var_get_dict_index (var)],
4952                                     value, var))
4953         ctables_value_insert (t, value, var_get_width (var));
4954     }
4955 }
4956
4957 static int
4958 compare_clabels_values_3way (const void *a_, const void *b_, const void *width_)
4959 {
4960   const struct ctables_value *const *ap = a_;
4961   const struct ctables_value *const *bp = b_;
4962   const struct ctables_value *a = *ap;
4963   const struct ctables_value *b = *bp;
4964   const int *width = width_;
4965   return value_compare_3way (&a->value, &b->value, *width);
4966 }
4967
4968 static void
4969 ctables_sort_clabels_values (struct ctables_table *t)
4970 {
4971   const struct variable *v0 = t->clabels_example;
4972   int width = var_get_width (v0);
4973
4974   struct ctables_categories *c0 = t->categories[var_get_dict_index (v0)];
4975   if (c0->show_empty)
4976     {
4977       const struct val_labs *val_labs = var_get_value_labels (v0);
4978       for (const struct val_lab *vl = val_labs_first (val_labs); vl;
4979            vl = val_labs_next (val_labs, vl))
4980         if (ctables_categories_match (c0, &vl->value, v0))
4981           ctables_value_insert (t, &vl->value, width);
4982     }
4983
4984   size_t n = hmap_count (&t->clabels_values_map);
4985   t->clabels_values = xnmalloc (n, sizeof *t->clabels_values);
4986
4987   struct ctables_value *clv;
4988   size_t i = 0;
4989   HMAP_FOR_EACH (clv, struct ctables_value, node, &t->clabels_values_map)
4990     t->clabels_values[i++] = clv;
4991   t->n_clabels_values = n;
4992   assert (i == n);
4993
4994   sort (t->clabels_values, n, sizeof *t->clabels_values,
4995         compare_clabels_values_3way, &width);
4996
4997   for (size_t i = 0; i < n; i++)
4998     t->clabels_values[i]->leaf = i;
4999 }
5000
5001 static void
5002 ctables_add_category_occurrences (const struct variable *var,
5003                                   struct hmap *occurrences,
5004                                   const struct ctables_categories *cats)
5005 {
5006   const struct val_labs *val_labs = var_get_value_labels (var);
5007
5008   for (size_t i = 0; i < cats->n_cats; i++)
5009     {
5010       const struct ctables_category *c = &cats->cats[i];
5011       switch (c->type)
5012         {
5013         case CCT_NUMBER:
5014           ctables_add_occurrence (var, &(const union value) { .f = c->number },
5015                                   occurrences);
5016           break;
5017
5018         case CCT_STRING:
5019           {
5020             int width = var_get_width (var);
5021             union value value;
5022             value_init (&value, width);
5023             value_copy_buf_rpad (&value, width,
5024                                  CHAR_CAST (uint8_t *, c->string.string),
5025                                  c->string.length, ' ');
5026             ctables_add_occurrence (var, &value, occurrences);
5027             value_destroy (&value, width);
5028           }
5029           break;
5030
5031         case CCT_NRANGE:
5032           assert (var_is_numeric (var));
5033           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
5034                vl = val_labs_next (val_labs, vl))
5035             if (vl->value.f >= c->nrange[0] && vl->value.f <= c->nrange[1])
5036               ctables_add_occurrence (var, &vl->value, occurrences);
5037           break;
5038
5039         case CCT_SRANGE:
5040           assert (var_is_alpha (var));
5041           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
5042                vl = val_labs_next (val_labs, vl))
5043             if (in_string_range (&vl->value, var, c->srange))
5044               ctables_add_occurrence (var, &vl->value, occurrences);
5045           break;
5046
5047         case CCT_MISSING:
5048           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
5049                vl = val_labs_next (val_labs, vl))
5050             if (var_is_value_missing (var, &vl->value))
5051               ctables_add_occurrence (var, &vl->value, occurrences);
5052           break;
5053
5054         case CCT_OTHERNM:
5055           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
5056                vl = val_labs_next (val_labs, vl))
5057             ctables_add_occurrence (var, &vl->value, occurrences);
5058           break;
5059
5060         case CCT_POSTCOMPUTE:
5061           break;
5062
5063         case CCT_SUBTOTAL:
5064         case CCT_TOTAL:
5065           break;
5066
5067         case CCT_VALUE:
5068         case CCT_LABEL:
5069         case CCT_FUNCTION:
5070           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
5071                vl = val_labs_next (val_labs, vl))
5072             if (c->include_missing || !var_is_value_missing (var, &vl->value))
5073               ctables_add_occurrence (var, &vl->value, occurrences);
5074           break;
5075
5076         case CCT_EXCLUDED_MISSING:
5077           break;
5078         }
5079     }
5080 }
5081
5082 static void
5083 ctables_section_recurse_add_empty_categories (
5084   struct ctables_section *s,
5085   const struct ctables_category *cats[PIVOT_N_AXES][10], struct ccase *c,
5086   enum pivot_axis_type a, size_t a_idx)
5087 {
5088   if (a >= PIVOT_N_AXES)
5089     ctables_cell_insert__ (s, c, cats);
5090   else if (!s->nests[a] || a_idx >= s->nests[a]->n)
5091     ctables_section_recurse_add_empty_categories (s, cats, c, a + 1, 0);
5092   else
5093     {
5094       const struct variable *var = s->nests[a]->vars[a_idx];
5095       const struct ctables_categories *categories = s->table->categories[
5096         var_get_dict_index (var)];
5097       int width = var_get_width (var);
5098       const struct hmap *occurrences = &s->occurrences[a][a_idx];
5099       const struct ctables_occurrence *o;
5100       HMAP_FOR_EACH (o, struct ctables_occurrence, node, occurrences)
5101         {
5102           union value *value = case_data_rw (c, var);
5103           value_destroy (value, width);
5104           value_clone (value, &o->value, width);
5105           cats[a][a_idx] = ctables_categories_match (categories, value, var);
5106           assert (cats[a][a_idx] != NULL);
5107           ctables_section_recurse_add_empty_categories (s, cats, c, a, a_idx + 1);
5108         }
5109
5110       for (size_t i = 0; i < categories->n_cats; i++)
5111         {
5112           const struct ctables_category *cat = &categories->cats[i];
5113           if (cat->type == CCT_POSTCOMPUTE)
5114             {
5115               cats[a][a_idx] = cat;
5116               ctables_section_recurse_add_empty_categories (s, cats, c, a, a_idx + 1);
5117             }
5118         }
5119     }
5120 }
5121
5122 static void
5123 ctables_section_add_empty_categories (struct ctables_section *s)
5124 {
5125   bool show_empty = false;
5126   for (size_t a = 0; a < PIVOT_N_AXES; a++)
5127     if (s->nests[a])
5128       for (size_t k = 0; k < s->nests[a]->n; k++)
5129         if (k != s->nests[a]->scale_idx)
5130           {
5131             const struct variable *var = s->nests[a]->vars[k];
5132             const struct ctables_categories *cats = s->table->categories[
5133               var_get_dict_index (var)];
5134             if (cats->show_empty)
5135               {
5136                 show_empty = true;
5137                 ctables_add_category_occurrences (var, &s->occurrences[a][k], cats);
5138               }
5139           }
5140   if (!show_empty)
5141     return;
5142
5143   const struct ctables_category *cats[PIVOT_N_AXES][10]; /* XXX */
5144   struct ccase *c = case_create (dict_get_proto (s->table->ctables->dict));
5145   ctables_section_recurse_add_empty_categories (s, cats, c, 0, 0);
5146   case_unref (c);
5147 }
5148
5149 static bool
5150 ctables_execute (struct dataset *ds, struct ctables *ct)
5151 {
5152   for (size_t i = 0; i < ct->n_tables; i++)
5153     {
5154       struct ctables_table *t = ct->tables[i];
5155       t->sections = xnmalloc (MAX (1, t->stacks[PIVOT_AXIS_ROW].n) *
5156                               MAX (1, t->stacks[PIVOT_AXIS_COLUMN].n) *
5157                               MAX (1, t->stacks[PIVOT_AXIS_LAYER].n),
5158                               sizeof *t->sections);
5159       size_t ix[PIVOT_N_AXES];
5160       ctables_table_add_section (t, 0, ix);
5161     }
5162
5163   struct casereader *input = proc_open (ds);
5164   bool warn_on_invalid = true;
5165   for (struct ccase *c = casereader_read (input); c;
5166        case_unref (c), c = casereader_read (input))
5167     {
5168       double d_weight = dict_get_case_weight (dataset_dict (ds), c,
5169                                               &warn_on_invalid);
5170       double e_weight = (ct->e_weight
5171                          ? var_force_valid_weight (ct->e_weight,
5172                                                    case_num (c, ct->e_weight),
5173                                                    &warn_on_invalid)
5174                          : d_weight);
5175
5176       for (size_t i = 0; i < ct->n_tables; i++)
5177         {
5178           struct ctables_table *t = ct->tables[i];
5179
5180           for (size_t j = 0; j < t->n_sections; j++)
5181             ctables_cell_insert (&t->sections[j], c, d_weight, e_weight);
5182
5183           for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
5184             if (t->label_axis[a] != a)
5185               ctables_insert_clabels_values (t, c, a);
5186         }
5187     }
5188   casereader_destroy (input);
5189
5190   for (size_t i = 0; i < ct->n_tables; i++)
5191     {
5192       struct ctables_table *t = ct->tables[i];
5193
5194       if (t->clabels_example)
5195         ctables_sort_clabels_values (t);
5196
5197       for (size_t j = 0; j < t->n_sections; j++)
5198         ctables_section_add_empty_categories (&t->sections[j]);
5199
5200       ctables_table_output (ct, ct->tables[i]);
5201     }
5202   return proc_commit (ds);
5203 }
5204 \f
5205 /* Postcomputes. */
5206
5207 typedef struct ctables_pcexpr *parse_recursively_func (struct lexer *,
5208                                                        struct dictionary *);
5209
5210 static void
5211 ctables_pcexpr_destroy (struct ctables_pcexpr *e)
5212 {
5213   if (e)
5214     {
5215       switch (e->op)
5216         {
5217         case CTPO_CAT_STRING:
5218           ss_dealloc (&e->string);
5219           break;
5220
5221         case CTPO_CAT_SRANGE:
5222           for (size_t i = 0; i < 2; i++)
5223             ss_dealloc (&e->srange[i]);
5224           break;
5225
5226         case CTPO_ADD:
5227         case CTPO_SUB:
5228         case CTPO_MUL:
5229         case CTPO_DIV:
5230         case CTPO_POW:
5231         case CTPO_NEG:
5232           for (size_t i = 0; i < 2; i++)
5233             ctables_pcexpr_destroy (e->subs[i]);
5234           break;
5235
5236         case CTPO_CONSTANT:
5237         case CTPO_CAT_NUMBER:
5238         case CTPO_CAT_NRANGE:
5239         case CTPO_CAT_MISSING:
5240         case CTPO_CAT_OTHERNM:
5241         case CTPO_CAT_SUBTOTAL:
5242         case CTPO_CAT_TOTAL:
5243           break;
5244         }
5245
5246       msg_location_destroy (e->location);
5247       free (e);
5248     }
5249 }
5250
5251 static struct ctables_pcexpr *
5252 ctables_pcexpr_allocate_binary (enum ctables_postcompute_op op,
5253                                 struct ctables_pcexpr *sub0,
5254                                 struct ctables_pcexpr *sub1)
5255 {
5256   struct ctables_pcexpr *e = xmalloc (sizeof *e);
5257   *e = (struct ctables_pcexpr) {
5258     .op = op,
5259     .subs = { sub0, sub1 },
5260     .location = msg_location_merged (sub0->location, sub1->location),
5261   };
5262   return e;
5263 }
5264
5265 /* How to parse an operator. */
5266 struct operator
5267   {
5268     enum token_type token;
5269     enum ctables_postcompute_op op;
5270   };
5271
5272 static const struct operator *
5273 ctable_pcexpr_match_operator (struct lexer *lexer,
5274                               const struct operator ops[], size_t n_ops)
5275 {
5276   for (const struct operator *op = ops; op < ops + n_ops; op++)
5277     if (lex_token (lexer) == op->token)
5278       {
5279         if (op->token != T_NEG_NUM)
5280           lex_get (lexer);
5281
5282         return op;
5283       }
5284
5285   return NULL;
5286 }
5287
5288 static struct ctables_pcexpr *
5289 ctable_pcexpr_parse_binary_operators__ (
5290   struct lexer *lexer, struct dictionary *dict,
5291   const struct operator ops[], size_t n_ops,
5292   parse_recursively_func *parse_next_level,
5293   const char *chain_warning, struct ctables_pcexpr *lhs)
5294 {
5295   for (int op_count = 0; ; op_count++)
5296     {
5297       const struct operator *op
5298         = ctable_pcexpr_match_operator (lexer, ops, n_ops);
5299       if (!op)
5300         {
5301           if (op_count > 1 && chain_warning)
5302             msg_at (SW, lhs->location, "%s", chain_warning);
5303
5304           return lhs;
5305         }
5306
5307       struct ctables_pcexpr *rhs = parse_next_level (lexer, dict);
5308       if (!rhs)
5309         {
5310           ctables_pcexpr_destroy (lhs);
5311           return NULL;
5312         }
5313
5314       lhs = ctables_pcexpr_allocate_binary (op->op, lhs, rhs);
5315     }
5316 }
5317
5318 static struct ctables_pcexpr *
5319 ctable_pcexpr_parse_binary_operators (struct lexer *lexer,
5320                                       struct dictionary *dict,
5321                                       const struct operator ops[], size_t n_ops,
5322                                       parse_recursively_func *parse_next_level,
5323                                       const char *chain_warning)
5324 {
5325   struct ctables_pcexpr *lhs = parse_next_level (lexer, dict);
5326   if (!lhs)
5327     return NULL;
5328
5329   return ctable_pcexpr_parse_binary_operators__ (lexer, dict, ops, n_ops,
5330                                                  parse_next_level,
5331                                                  chain_warning, lhs);
5332 }
5333
5334 static struct ctables_pcexpr *ctable_pcexpr_parse_add (struct lexer *,
5335                                                        struct dictionary *);
5336
5337 static struct ctables_pcexpr
5338 ctpo_cat_nrange (double low, double high)
5339 {
5340   return (struct ctables_pcexpr) {
5341     .op = CTPO_CAT_NRANGE,
5342     .nrange = { low, high },
5343   };
5344 }
5345
5346 static struct ctables_pcexpr *
5347 ctable_pcexpr_parse_primary (struct lexer *lexer, struct dictionary *dict)
5348 {
5349   int start_ofs = lex_ofs (lexer);
5350   struct ctables_pcexpr e;
5351   if (lex_is_number (lexer))
5352     {
5353       e = (struct ctables_pcexpr) { .op = CTPO_CONSTANT,
5354                                     .number = lex_number (lexer) };
5355       lex_get (lexer);
5356     }
5357   else if (lex_match_id (lexer, "MISSING"))
5358     e = (struct ctables_pcexpr) { .op = CTPO_CAT_MISSING };
5359   else if (lex_match_id (lexer, "OTHERNM"))
5360     e = (struct ctables_pcexpr) { .op = CTPO_CAT_OTHERNM };
5361   else if (lex_match_id (lexer, "TOTAL"))
5362     e = (struct ctables_pcexpr) { .op = CTPO_CAT_TOTAL };
5363   else if (lex_match_id (lexer, "SUBTOTAL"))
5364     {
5365       size_t subtotal_index = 0;
5366       if (lex_match (lexer, T_LBRACK))
5367         {
5368           if (!lex_force_int_range (lexer, "SUBTOTAL", 1, LONG_MAX))
5369             return NULL;
5370           subtotal_index = lex_integer (lexer);
5371           lex_get (lexer);
5372           if (!lex_force_match (lexer, T_RBRACK))
5373             return NULL;
5374         }
5375       e = (struct ctables_pcexpr) { .op = CTPO_CAT_SUBTOTAL,
5376                                     .subtotal_index = subtotal_index };
5377     }
5378   else if (lex_match (lexer, T_LBRACK))
5379     {
5380       if (lex_match_id (lexer, "LO"))
5381         {
5382           if (!lex_force_match_id (lexer, "THRU") || lex_force_num (lexer))
5383             return false;
5384           e = ctpo_cat_nrange (-DBL_MAX, lex_number (lexer));
5385           lex_get (lexer);
5386         }
5387       else if (lex_is_number (lexer))
5388         {
5389           double number = lex_number (lexer);
5390           lex_get (lexer);
5391           if (lex_match_id (lexer, "THRU"))
5392             {
5393               if (lex_match_id (lexer, "HI"))
5394                 e = ctpo_cat_nrange (number, DBL_MAX);
5395               else
5396                 {
5397                   if (!lex_force_num (lexer))
5398                     return false;
5399                   e = ctpo_cat_nrange (number, lex_number (lexer));
5400                   lex_get (lexer);
5401                 }
5402             }
5403           else
5404             e = (struct ctables_pcexpr) { .op = CTPO_CAT_NUMBER,
5405                                           .number = number };
5406         }
5407       else if (lex_is_string (lexer))
5408         {
5409           struct substring s = recode_substring_pool (
5410             dict_get_encoding (dict), "UTF-8", lex_tokss (lexer), NULL);
5411           ss_rtrim (&s, ss_cstr (" "));
5412
5413           e = (struct ctables_pcexpr) { .op = CTPO_CAT_STRING, .string = s };
5414           lex_get (lexer);
5415         }
5416       else
5417         {
5418           lex_error (lexer, NULL);
5419           return NULL;
5420         }
5421
5422       if (!lex_force_match (lexer, T_RBRACK))
5423         {
5424           if (e.op == CTPO_CAT_STRING)
5425             ss_dealloc (&e.string);
5426           return NULL;
5427         }
5428     }
5429   else if (lex_match (lexer, T_LPAREN))
5430     {
5431       struct ctables_pcexpr *ep = ctable_pcexpr_parse_add (lexer, dict);
5432       if (!ep)
5433         return NULL;
5434       if (!lex_force_match (lexer, T_RPAREN))
5435         {
5436           ctables_pcexpr_destroy (ep);
5437           return NULL;
5438         }
5439       return ep;
5440     }
5441   else
5442     {
5443       lex_error (lexer, NULL);
5444       return NULL;
5445     }
5446
5447   e.location = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer) - 1);
5448   return xmemdup (&e, sizeof e);
5449 }
5450
5451 static struct ctables_pcexpr *
5452 ctables_pcexpr_allocate_neg (struct ctables_pcexpr *sub,
5453                              struct lexer *lexer, int start_ofs)
5454 {
5455   struct ctables_pcexpr *e = xmalloc (sizeof *e);
5456   *e = (struct ctables_pcexpr) {
5457     .op = CTPO_NEG,
5458     .subs = { sub },
5459     .location = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer) - 1),
5460   };
5461   return e;
5462 }
5463
5464 static struct ctables_pcexpr *
5465 ctable_pcexpr_parse_exp (struct lexer *lexer, struct dictionary *dict)
5466 {
5467   static const struct operator op = { T_EXP, CTPO_POW };
5468
5469   const char *chain_warning =
5470     _("The exponentiation operator (`**') is left-associative: "
5471       "`a**b**c' equals `(a**b)**c', not `a**(b**c)'.  "
5472       "To disable this warning, insert parentheses.");
5473
5474   if (lex_token (lexer) != T_NEG_NUM || lex_next_token (lexer, 1) != T_EXP)
5475     return ctable_pcexpr_parse_binary_operators (lexer, dict, &op, 1,
5476                                                  ctable_pcexpr_parse_primary,
5477                                                  chain_warning);
5478
5479   /* Special case for situations like "-5**6", which must be parsed as
5480      -(5**6). */
5481
5482   int start_ofs = lex_ofs (lexer);
5483   struct ctables_pcexpr *lhs = xmalloc (sizeof *lhs);
5484   *lhs = (struct ctables_pcexpr) {
5485     .op = CTPO_CONSTANT,
5486     .number = -lex_tokval (lexer),
5487     .location = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer)),
5488   };
5489   lex_get (lexer);
5490
5491   struct ctables_pcexpr *node = ctable_pcexpr_parse_binary_operators__ (
5492     lexer, dict, &op, 1,
5493     ctable_pcexpr_parse_primary, chain_warning, lhs);
5494   if (!node)
5495     return NULL;
5496
5497   return ctables_pcexpr_allocate_neg (node, lexer, start_ofs);
5498 }
5499
5500 /* Parses the unary minus level. */
5501 static struct ctables_pcexpr *
5502 ctable_pcexpr_parse_neg (struct lexer *lexer, struct dictionary *dict)
5503 {
5504   int start_ofs = lex_ofs (lexer);
5505   if (!lex_match (lexer, T_DASH))
5506     return ctable_pcexpr_parse_exp (lexer, dict);
5507
5508   struct ctables_pcexpr *inner = ctable_pcexpr_parse_neg (lexer, dict);
5509   if (!inner)
5510     return NULL;
5511
5512   return ctables_pcexpr_allocate_neg (inner, lexer, start_ofs);
5513 }
5514
5515 /* Parses the multiplication and division level. */
5516 static struct ctables_pcexpr *
5517 ctable_pcexpr_parse_mul (struct lexer *lexer, struct dictionary *dict)
5518 {
5519   static const struct operator ops[] =
5520     {
5521       { T_ASTERISK, CTPO_MUL },
5522       { T_SLASH, CTPO_DIV },
5523     };
5524
5525   return ctable_pcexpr_parse_binary_operators (lexer, dict, ops,
5526                                                sizeof ops / sizeof *ops,
5527                                                ctable_pcexpr_parse_neg, NULL);
5528 }
5529
5530 /* Parses the addition and subtraction level. */
5531 static struct ctables_pcexpr *
5532 ctable_pcexpr_parse_add (struct lexer *lexer, struct dictionary *dict)
5533 {
5534   static const struct operator ops[] =
5535     {
5536       { T_PLUS, CTPO_ADD },
5537       { T_DASH, CTPO_SUB },
5538       { T_NEG_NUM, CTPO_ADD },
5539     };
5540
5541   return ctable_pcexpr_parse_binary_operators (lexer, dict,
5542                                                ops, sizeof ops / sizeof *ops,
5543                                                ctable_pcexpr_parse_mul, NULL);
5544 }
5545
5546 static struct ctables_postcompute *
5547 ctables_find_postcompute (struct ctables *ct, const char *name)
5548 {
5549   struct ctables_postcompute *pc;
5550   HMAP_FOR_EACH_WITH_HASH (pc, struct ctables_postcompute, hmap_node,
5551                            utf8_hash_case_string (name, 0), &ct->postcomputes)
5552     if (!utf8_strcasecmp (pc->name, name))
5553       return pc;
5554   return NULL;
5555 }
5556
5557 static bool
5558 ctables_parse_pcompute (struct lexer *lexer, struct dictionary *dict,
5559                         struct ctables *ct)
5560 {
5561   int pcompute_start = lex_ofs (lexer) - 1;
5562
5563   if (!lex_force_match (lexer, T_AND) || !lex_force_id (lexer))
5564     return false;
5565
5566   char *name = ss_xstrdup (lex_tokss (lexer));
5567
5568   lex_get (lexer);
5569   if (!lex_force_match (lexer, T_EQUALS)
5570       || !lex_force_match_id (lexer, "EXPR")
5571       || !lex_force_match (lexer, T_LPAREN))
5572     {
5573       free (name);
5574       return false;
5575     }
5576
5577   int expr_start = lex_ofs (lexer);
5578   struct ctables_pcexpr *expr = ctable_pcexpr_parse_add (lexer, dict);
5579   int expr_end = lex_ofs (lexer) - 1;
5580   if (!expr || !lex_force_match (lexer, T_RPAREN))
5581     {
5582       free (name);
5583       return false;
5584     }
5585   int pcompute_end = lex_ofs (lexer) - 1;
5586
5587   struct msg_location *location = lex_ofs_location (lexer, pcompute_start,
5588                                                     pcompute_end);
5589
5590   struct ctables_postcompute *pc = ctables_find_postcompute (ct, name);
5591   if (pc)
5592     {
5593       msg_at (SW, location, _("New definition of &%s will override the "
5594                               "previous definition."),
5595               pc->name);
5596       msg_at (SN, pc->location, _("This is the previous definition."));
5597
5598       ctables_pcexpr_destroy (pc->expr);
5599       msg_location_destroy (pc->location);
5600       free (name);
5601     }
5602   else
5603     {
5604       pc = xmalloc (sizeof *pc);
5605       *pc = (struct ctables_postcompute) { .name = name };
5606       hmap_insert (&ct->postcomputes, &pc->hmap_node,
5607                    utf8_hash_case_string (pc->name, 0));
5608     }
5609   pc->expr = expr;
5610   pc->location = location;
5611   if (!pc->label)
5612     pc->label = lex_ofs_representation (lexer, expr_start, expr_end);
5613   return true;
5614 }
5615
5616 static bool
5617 ctables_parse_pproperties_format (struct lexer *lexer,
5618                                   struct ctables_summary_spec_set *sss)
5619 {
5620   *sss = (struct ctables_summary_spec_set) { .n = 0 };
5621
5622   while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH
5623          && !(lex_token (lexer) == T_ID
5624               && (lex_id_match (ss_cstr ("LABEL"), lex_tokss (lexer))
5625                   || lex_id_match (ss_cstr ("HIDESOURCECATS"),
5626                                    lex_tokss (lexer)))))
5627     {
5628       /* Parse function. */
5629       enum ctables_summary_function function;
5630       if (!parse_ctables_summary_function (lexer, &function))
5631         goto error;
5632
5633       /* Parse percentile. */
5634       double percentile = 0;
5635       if (function == CTSF_PTILE)
5636         {
5637           if (!lex_force_num_range_closed (lexer, "PTILE", 0, 100))
5638             goto error;
5639           percentile = lex_number (lexer);
5640           lex_get (lexer);
5641         }
5642
5643       /* Parse format. */
5644       struct fmt_spec format;
5645       bool is_ctables_format;
5646       if (!parse_ctables_format_specifier (lexer, &format, &is_ctables_format))
5647         goto error;
5648
5649       if (sss->n >= sss->allocated)
5650         sss->specs = x2nrealloc (sss->specs, &sss->allocated,
5651                                  sizeof *sss->specs);
5652       sss->specs[sss->n++] = (struct ctables_summary_spec) {
5653         .function = function,
5654         .percentile = percentile,
5655         .format = format,
5656         .is_ctables_format = is_ctables_format,
5657       };
5658     }
5659   return true;
5660
5661 error:
5662   ctables_summary_spec_set_uninit (sss);
5663   return false;
5664 }
5665
5666 static bool
5667 ctables_parse_pproperties (struct lexer *lexer, struct ctables *ct)
5668 {
5669   struct ctables_postcompute **pcs = NULL;
5670   size_t n_pcs = 0;
5671   size_t allocated_pcs = 0;
5672
5673   while (lex_match (lexer, T_AND))
5674     {
5675       if (!lex_force_id (lexer))
5676         goto error;
5677       struct ctables_postcompute *pc
5678         = ctables_find_postcompute (ct, lex_tokcstr (lexer));
5679       if (!pc)
5680         {
5681           msg (SE, _("Unknown computed category &%s."), lex_tokcstr (lexer));
5682           goto error;
5683         }
5684       lex_get (lexer);
5685
5686       if (n_pcs >= allocated_pcs)
5687         pcs = x2nrealloc (pcs, &allocated_pcs, sizeof *pcs);
5688       pcs[n_pcs++] = pc;
5689     }
5690
5691   while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
5692     {
5693       if (lex_match_id (lexer, "LABEL"))
5694         {
5695           lex_match (lexer, T_EQUALS);
5696           if (!lex_force_string (lexer))
5697             goto error;
5698
5699           for (size_t i = 0; i < n_pcs; i++)
5700             {
5701               free (pcs[i]->label);
5702               pcs[i]->label = ss_xstrdup (lex_tokss (lexer));
5703             }
5704
5705           lex_get (lexer);
5706         }
5707       else if (lex_match_id (lexer, "FORMAT"))
5708         {
5709           lex_match (lexer, T_EQUALS);
5710
5711           struct ctables_summary_spec_set sss;
5712           if (!ctables_parse_pproperties_format (lexer, &sss))
5713             goto error;
5714
5715           for (size_t i = 0; i < n_pcs; i++)
5716             {
5717               if (pcs[i]->specs)
5718                 ctables_summary_spec_set_uninit (pcs[i]->specs);
5719               else
5720                 pcs[i]->specs = xmalloc (sizeof *pcs[i]->specs);
5721               ctables_summary_spec_set_clone (pcs[i]->specs, &sss);
5722             }
5723           ctables_summary_spec_set_uninit (&sss);
5724         }
5725       else if (lex_match_id (lexer, "HIDESOURCECATS"))
5726         {
5727           lex_match (lexer, T_EQUALS);
5728           bool hide_source_cats;
5729           if (!parse_bool (lexer, &hide_source_cats))
5730             goto error;
5731           for (size_t i = 0; i < n_pcs; i++)
5732             pcs[i]->hide_source_cats = hide_source_cats;
5733         }
5734       else
5735         {
5736           lex_error_expecting (lexer, "LABEL", "FORMAT", "HIDESOURCECATS");
5737           goto error;
5738         }
5739     }
5740   free (pcs);
5741   return true;
5742
5743 error:
5744   free (pcs);
5745   return false;
5746 }
5747
5748 static void
5749 put_strftime (struct string *out, time_t now, const char *format)
5750 {
5751   const struct tm *tm = localtime (&now);
5752   char value[128];
5753   strftime (value, sizeof value, format, tm);
5754   ds_put_cstr (out, value);
5755 }
5756
5757 static bool
5758 skip_prefix (struct substring *s, struct substring prefix)
5759 {
5760   if (ss_starts_with (*s, prefix))
5761     {
5762       ss_advance (s, prefix.length);
5763       return true;
5764     }
5765   else
5766     return false;
5767 }
5768
5769 static void
5770 put_table_expression (struct string *out, struct lexer *lexer,
5771                       struct dictionary *dict, int expr_start, int expr_end)
5772 {
5773   size_t nest = 0;
5774   for (int ofs = expr_start; ofs < expr_end; ofs++)
5775     {
5776       const struct token *t = lex_ofs_token (lexer, ofs);
5777       if (t->type == T_LBRACK)
5778         nest++;
5779       else if (t->type == T_RBRACK && nest > 0)
5780         nest--;
5781       else if (nest > 0)
5782         {
5783           /* Nothing. */
5784         }
5785       else if (t->type == T_ID)
5786         {
5787           const struct variable *var
5788             = dict_lookup_var (dict, t->string.string);
5789           const char *label = var ? var_get_label (var) : NULL;
5790           ds_put_cstr (out, label ? label : t->string.string);
5791         }
5792       else
5793         {
5794           if (ofs != expr_start && t->type != T_RPAREN && ds_last (out) != ' ')
5795             ds_put_byte (out, ' ');
5796
5797           char *repr = lex_ofs_representation (lexer, ofs, ofs);
5798           ds_put_cstr (out, repr);
5799           free (repr);
5800
5801           if (ofs + 1 != expr_end && t->type != T_LPAREN)
5802             ds_put_byte (out, ' ');
5803         }
5804     }
5805 }
5806
5807 static void
5808 put_title_text (struct string *out, struct substring in, time_t now,
5809                 struct lexer *lexer, struct dictionary *dict,
5810                 int expr_start, int expr_end)
5811 {
5812   for (;;)
5813     {
5814       size_t chunk = ss_find_byte (in, ')');
5815       ds_put_substring (out, ss_head (in, chunk));
5816       ss_advance (&in, chunk);
5817       if (ss_is_empty (in))
5818         return;
5819
5820       if (skip_prefix (&in, ss_cstr (")DATE")))
5821         put_strftime (out, now, "%x");
5822       else if (skip_prefix (&in, ss_cstr (")TIME")))
5823         put_strftime (out, now, "%X");
5824       else if (skip_prefix (&in, ss_cstr (")TABLE")))
5825         put_table_expression (out, lexer, dict, expr_start, expr_end);
5826       else
5827         {
5828           ds_put_byte (out, ')');
5829           ss_advance (&in, 1);
5830         }
5831     }
5832 }
5833
5834 int
5835 cmd_ctables (struct lexer *lexer, struct dataset *ds)
5836 {
5837   size_t n_vars = dict_get_n_vars (dataset_dict (ds));
5838   enum ctables_vlabel *vlabels = xnmalloc (n_vars, sizeof *vlabels);
5839   enum settings_value_show tvars = settings_get_show_variables ();
5840   for (size_t i = 0; i < n_vars; i++)
5841     vlabels[i] = (enum ctables_vlabel) tvars;
5842
5843   struct pivot_table_look *look = pivot_table_look_unshare (
5844     pivot_table_look_ref (pivot_table_look_get_default ()));
5845   look->omit_empty = false;
5846
5847   struct ctables *ct = xmalloc (sizeof *ct);
5848   *ct = (struct ctables) {
5849     .dict = dataset_dict (ds),
5850     .look = look,
5851     .ctables_formats = FMT_SETTINGS_INIT,
5852     .vlabels = vlabels,
5853     .postcomputes = HMAP_INITIALIZER (ct->postcomputes),
5854   };
5855
5856   time_t now = time (NULL);
5857
5858   struct ctf
5859     {
5860       enum fmt_type type;
5861       const char *dot_string;
5862       const char *comma_string;
5863     };
5864   static const struct ctf ctfs[4] = {
5865     { CTEF_NEGPAREN, "(,,,)",   "(...)" },
5866     { CTEF_NEQUAL,   "-,N=,,",  "-.N=.." },
5867     { CTEF_PAREN,    "-,(,),",  "-.(.)." },
5868     { CTEF_PCTPAREN, "-,(,%),", "-.(.%)." },
5869   };
5870   bool is_dot = settings_get_fmt_settings ()->decimal == '.';
5871   for (size_t i = 0; i < 4; i++)
5872     {
5873       const char *s = is_dot ? ctfs[i].dot_string : ctfs[i].comma_string;
5874       fmt_settings_set_cc (&ct->ctables_formats, ctfs[i].type,
5875                            fmt_number_style_from_string (s));
5876     }
5877
5878   if (!lex_force_match (lexer, T_SLASH))
5879     goto error;
5880
5881   while (!lex_match_id (lexer, "TABLE"))
5882     {
5883       if (lex_match_id (lexer, "FORMAT"))
5884         {
5885           double widths[2] = { SYSMIS, SYSMIS };
5886           double units_per_inch = 72.0;
5887
5888           while (lex_token (lexer) != T_SLASH)
5889             {
5890               if (lex_match_id (lexer, "MINCOLWIDTH"))
5891                 {
5892                   if (!parse_col_width (lexer, "MINCOLWIDTH", &widths[0]))
5893                     goto error;
5894                 }
5895               else if (lex_match_id (lexer, "MAXCOLWIDTH"))
5896                 {
5897                   if (!parse_col_width (lexer, "MAXCOLWIDTH", &widths[1]))
5898                     goto error;
5899                 }
5900               else if (lex_match_id (lexer, "UNITS"))
5901                 {
5902                   lex_match (lexer, T_EQUALS);
5903                   if (lex_match_id (lexer, "POINTS"))
5904                     units_per_inch = 72.0;
5905                   else if (lex_match_id (lexer, "INCHES"))
5906                     units_per_inch = 1.0;
5907                   else if (lex_match_id (lexer, "CM"))
5908                     units_per_inch = 2.54;
5909                   else
5910                     {
5911                       lex_error_expecting (lexer, "POINTS", "INCHES", "CM");
5912                       goto error;
5913                     }
5914                 }
5915               else if (lex_match_id (lexer, "EMPTY"))
5916                 {
5917                   free (ct->zero);
5918                   ct->zero = NULL;
5919
5920                   lex_match (lexer, T_EQUALS);
5921                   if (lex_match_id (lexer, "ZERO"))
5922                     {
5923                       /* Nothing to do. */
5924                     }
5925                   else if (lex_match_id (lexer, "BLANK"))
5926                     ct->zero = xstrdup ("");
5927                   else if (lex_force_string (lexer))
5928                     {
5929                       ct->zero = ss_xstrdup (lex_tokss (lexer));
5930                       lex_get (lexer);
5931                     }
5932                   else
5933                     goto error;
5934                 }
5935               else if (lex_match_id (lexer, "MISSING"))
5936                 {
5937                   lex_match (lexer, T_EQUALS);
5938                   if (!lex_force_string (lexer))
5939                     goto error;
5940
5941                   free (ct->missing);
5942                   ct->missing = (strcmp (lex_tokcstr (lexer), ".")
5943                                  ? ss_xstrdup (lex_tokss (lexer))
5944                                  : NULL);
5945                   lex_get (lexer);
5946                 }
5947               else
5948                 {
5949                   lex_error_expecting (lexer, "MINCOLWIDTH", "MAXCOLWIDTH",
5950                                        "UNITS", "EMPTY", "MISSING");
5951                   goto error;
5952                 }
5953             }
5954
5955           if (widths[0] != SYSMIS && widths[1] != SYSMIS
5956               && widths[0] > widths[1])
5957             {
5958               msg (SE, _("MINCOLWIDTH must not be greater than MAXCOLWIDTH."));
5959               goto error;
5960             }
5961
5962           for (size_t i = 0; i < 2; i++)
5963             if (widths[i] != SYSMIS)
5964               {
5965                 int *wr = ct->look->width_ranges[TABLE_HORZ];
5966                 wr[i] = widths[i] / units_per_inch * 96.0;
5967                 if (wr[0] > wr[1])
5968                   wr[!i] = wr[i];
5969               }
5970         }
5971       else if (lex_match_id (lexer, "VLABELS"))
5972         {
5973           if (!lex_force_match_id (lexer, "VARIABLES"))
5974             goto error;
5975           lex_match (lexer, T_EQUALS);
5976
5977           struct variable **vars;
5978           size_t n_vars;
5979           if (!parse_variables (lexer, dataset_dict (ds), &vars, &n_vars,
5980                                 PV_NO_SCRATCH))
5981             goto error;
5982
5983           if (!lex_force_match_id (lexer, "DISPLAY"))
5984             {
5985               free (vars);
5986               goto error;
5987             }
5988           lex_match (lexer, T_EQUALS);
5989
5990           enum ctables_vlabel vlabel;
5991           if (lex_match_id (lexer, "DEFAULT"))
5992             vlabel = (enum ctables_vlabel) settings_get_show_variables ();
5993           else if (lex_match_id (lexer, "NAME"))
5994             vlabel = CTVL_NAME;
5995           else if (lex_match_id (lexer, "LABEL"))
5996             vlabel = CTVL_LABEL;
5997           else if (lex_match_id (lexer, "BOTH"))
5998             vlabel = CTVL_BOTH;
5999           else if (lex_match_id (lexer, "NONE"))
6000             vlabel = CTVL_NONE;
6001           else
6002             {
6003               lex_error_expecting (lexer, "DEFAULT", "NAME", "LABEL",
6004                                    "BOTH", "NONE");
6005               free (vars);
6006               goto error;
6007             }
6008
6009           for (size_t i = 0; i < n_vars; i++)
6010             ct->vlabels[var_get_dict_index (vars[i])] = vlabel;
6011           free (vars);
6012         }
6013       else if (lex_match_id (lexer, "MRSETS"))
6014         {
6015           if (!lex_force_match_id (lexer, "COUNTDUPLICATES"))
6016             goto error;
6017           lex_match (lexer, T_EQUALS);
6018           if (!parse_bool (lexer, &ct->mrsets_count_duplicates))
6019             goto error;
6020         }
6021       else if (lex_match_id (lexer, "SMISSING"))
6022         {
6023           if (lex_match_id (lexer, "VARIABLE"))
6024             ct->smissing_listwise = false;
6025           else if (lex_match_id (lexer, "LISTWISE"))
6026             ct->smissing_listwise = true;
6027           else
6028             {
6029               lex_error_expecting (lexer, "VARIABLE", "LISTWISE");
6030               goto error;
6031             }
6032         }
6033       else if (lex_match_id (lexer, "PCOMPUTE"))
6034         {
6035           if (!ctables_parse_pcompute (lexer, dataset_dict (ds), ct))
6036             goto error;
6037         }
6038       else if (lex_match_id (lexer, "PPROPERTIES"))
6039         {
6040           if (!ctables_parse_pproperties (lexer, ct))
6041             goto error;
6042         }
6043       else if (lex_match_id (lexer, "WEIGHT"))
6044         {
6045           if (!lex_force_match_id (lexer, "VARIABLE"))
6046             goto error;
6047           lex_match (lexer, T_EQUALS);
6048           ct->e_weight = parse_variable (lexer, dataset_dict (ds));
6049           if (!ct->e_weight)
6050             goto error;
6051         }
6052       else if (lex_match_id (lexer, " HIDESMALLCOUNTS"))
6053         {
6054           if (lex_match_id (lexer, "COUNT"))
6055             {
6056               lex_match (lexer, T_EQUALS);
6057               if (!lex_force_int_range (lexer, "HIDESMALLCOUNTS COUNT",
6058                                         2, INT_MAX))
6059                 goto error;
6060               ct->hide_threshold = lex_integer (lexer);
6061               lex_get (lexer);
6062             }
6063           else if (ct->hide_threshold == 0)
6064             ct->hide_threshold = 5;
6065         }
6066       else
6067         {
6068           lex_error_expecting (lexer, "FORMAT", "VLABELS", "MRSETS",
6069                                "SMISSING", "PCOMPUTE", "PPROPERTIES",
6070                                "WEIGHT", "HIDESMALLCOUNTS", "TABLE");
6071           goto error;
6072         }
6073
6074       if (!lex_force_match (lexer, T_SLASH))
6075         goto error;
6076     }
6077
6078   size_t allocated_tables = 0;
6079   do
6080     {
6081       if (ct->n_tables >= allocated_tables)
6082         ct->tables = x2nrealloc (ct->tables, &allocated_tables,
6083                                  sizeof *ct->tables);
6084
6085       struct ctables_category *cat = xmalloc (sizeof *cat);
6086       *cat = (struct ctables_category) {
6087         .type = CCT_VALUE,
6088         .include_missing = false,
6089         .sort_ascending = true,
6090       };
6091
6092       struct ctables_categories *c = xmalloc (sizeof *c);
6093       size_t n_vars = dict_get_n_vars (dataset_dict (ds));
6094       *c = (struct ctables_categories) {
6095         .n_refs = n_vars,
6096         .cats = cat,
6097         .n_cats = 1,
6098         .show_empty = true,
6099       };
6100
6101       struct ctables_categories **categories = xnmalloc (n_vars,
6102                                                          sizeof *categories);
6103       for (size_t i = 0; i < n_vars; i++)
6104         categories[i] = c;
6105
6106       struct ctables_table *t = xmalloc (sizeof *t);
6107       *t = (struct ctables_table) {
6108         .ctables = ct,
6109         .slabels_axis = PIVOT_AXIS_COLUMN,
6110         .slabels_visible = true,
6111         .clabels_values_map = HMAP_INITIALIZER (t->clabels_values_map),
6112         .label_axis = {
6113           [PIVOT_AXIS_ROW] = PIVOT_AXIS_ROW,
6114           [PIVOT_AXIS_COLUMN] = PIVOT_AXIS_COLUMN,
6115           [PIVOT_AXIS_LAYER] = PIVOT_AXIS_LAYER,
6116         },
6117         .clabels_from_axis = PIVOT_AXIS_LAYER,
6118         .categories = categories,
6119         .n_categories = n_vars,
6120         .cilevel = 95,
6121       };
6122       ct->tables[ct->n_tables++] = t;
6123
6124       lex_match (lexer, T_EQUALS);
6125       int expr_start = lex_ofs (lexer);
6126       if (!ctables_axis_parse (lexer, dataset_dict (ds), ct, t, PIVOT_AXIS_ROW))
6127         goto error;
6128       if (lex_match (lexer, T_BY))
6129         {
6130           if (!ctables_axis_parse (lexer, dataset_dict (ds),
6131                                    ct, t, PIVOT_AXIS_COLUMN))
6132             goto error;
6133
6134           if (lex_match (lexer, T_BY))
6135             {
6136               if (!ctables_axis_parse (lexer, dataset_dict (ds),
6137                                        ct, t, PIVOT_AXIS_LAYER))
6138                 goto error;
6139             }
6140         }
6141       int expr_end = lex_ofs (lexer);
6142
6143       if (!t->axes[PIVOT_AXIS_ROW] && !t->axes[PIVOT_AXIS_COLUMN]
6144           && !t->axes[PIVOT_AXIS_LAYER])
6145         {
6146           lex_error (lexer, _("At least one variable must be specified."));
6147           goto error;
6148         }
6149
6150       const struct ctables_axis *scales[PIVOT_N_AXES];
6151       size_t n_scales = 0;
6152       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
6153         {
6154           scales[a] = find_scale (t->axes[a]);
6155           if (scales[a])
6156             n_scales++;
6157         }
6158       if (n_scales > 1)
6159         {
6160           msg (SE, _("Scale variables may appear only on one axis."));
6161           if (scales[PIVOT_AXIS_ROW])
6162             msg_at (SN, scales[PIVOT_AXIS_ROW]->loc,
6163                     _("This scale variable appears on the rows axis."));
6164           if (scales[PIVOT_AXIS_COLUMN])
6165             msg_at (SN, scales[PIVOT_AXIS_COLUMN]->loc,
6166                     _("This scale variable appears on the columns axis."));
6167           if (scales[PIVOT_AXIS_LAYER])
6168             msg_at (SN, scales[PIVOT_AXIS_LAYER]->loc,
6169                     _("This scale variable appears on the layer axis."));
6170           goto error;
6171         }
6172
6173       const struct ctables_axis *summaries[PIVOT_N_AXES];
6174       size_t n_summaries = 0;
6175       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
6176         {
6177           summaries[a] = (scales[a]
6178                           ? scales[a]
6179                           : find_categorical_summary_spec (t->axes[a]));
6180           if (summaries[a])
6181             n_summaries++;
6182         }
6183       if (n_summaries > 1)
6184         {
6185           msg (SE, _("Summaries may appear only on one axis."));
6186           if (summaries[PIVOT_AXIS_ROW])
6187             msg_at (SN, summaries[PIVOT_AXIS_ROW]->loc,
6188                     _("This variable on the rows axis has a summary."));
6189           if (summaries[PIVOT_AXIS_COLUMN])
6190             msg_at (SN, summaries[PIVOT_AXIS_COLUMN]->loc,
6191                     _("This variable on the columns axis has a summary."));
6192           if (summaries[PIVOT_AXIS_LAYER])
6193             msg_at (SN, summaries[PIVOT_AXIS_LAYER]->loc,
6194                     _("This variable on the layers axis has a summary."));
6195           goto error;
6196         }
6197       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
6198         if (n_summaries ? summaries[a] : t->axes[a])
6199           {
6200             t->summary_axis = a;
6201             break;
6202           }
6203
6204       if (lex_token (lexer) == T_ENDCMD)
6205         {
6206           if (!ctables_prepare_table (t))
6207             goto error;
6208           break;
6209         }
6210       if (!lex_force_match (lexer, T_SLASH))
6211         break;
6212
6213       while (!lex_match_id (lexer, "TABLE") && lex_token (lexer) != T_ENDCMD)
6214         {
6215           if (lex_match_id (lexer, "SLABELS"))
6216             {
6217               while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
6218                 {
6219                   if (lex_match_id (lexer, "POSITION"))
6220                     {
6221                       lex_match (lexer, T_EQUALS);
6222                       if (lex_match_id (lexer, "COLUMN"))
6223                         t->slabels_axis = PIVOT_AXIS_COLUMN;
6224                       else if (lex_match_id (lexer, "ROW"))
6225                         t->slabels_axis = PIVOT_AXIS_ROW;
6226                       else if (lex_match_id (lexer, "LAYER"))
6227                         t->slabels_axis = PIVOT_AXIS_LAYER;
6228                       else
6229                         {
6230                           lex_error_expecting (lexer, "COLUMN", "ROW", "LAYER");
6231                           goto error;
6232                         }
6233                     }
6234                   else if (lex_match_id (lexer, "VISIBLE"))
6235                     {
6236                       lex_match (lexer, T_EQUALS);
6237                       if (!parse_bool (lexer, &t->slabels_visible))
6238                         goto error;
6239                     }
6240                   else
6241                     {
6242                       lex_error_expecting (lexer, "POSITION", "VISIBLE");
6243                       goto error;
6244                     }
6245                 }
6246             }
6247           else if (lex_match_id (lexer, "CLABELS"))
6248             {
6249               while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
6250                 {
6251                   if (lex_match_id (lexer, "AUTO"))
6252                     {
6253                       t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_ROW;
6254                       t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_COLUMN;
6255                     }
6256                   else if (lex_match_id (lexer, "ROWLABELS"))
6257                     {
6258                       lex_match (lexer, T_EQUALS);
6259                       if (lex_match_id (lexer, "OPPOSITE"))
6260                         t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_COLUMN;
6261                       else if (lex_match_id (lexer, "LAYER"))
6262                         t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_LAYER;
6263                       else
6264                         {
6265                           lex_error_expecting (lexer, "OPPOSITE", "LAYER");
6266                           goto error;
6267                         }
6268                     }
6269                   else if (lex_match_id (lexer, "COLLABELS"))
6270                     {
6271                       lex_match (lexer, T_EQUALS);
6272                       if (lex_match_id (lexer, "OPPOSITE"))
6273                         t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_ROW;
6274                       else if (lex_match_id (lexer, "LAYER"))
6275                         t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_LAYER;
6276                       else
6277                         {
6278                           lex_error_expecting (lexer, "OPPOSITE", "LAYER");
6279                           goto error;
6280                         }
6281                     }
6282                   else
6283                     {
6284                       lex_error_expecting (lexer, "AUTO", "ROWLABELS",
6285                                            "COLLABELS");
6286                       goto error;
6287                     }
6288                 }
6289             }
6290           else if (lex_match_id (lexer, "CRITERIA"))
6291             {
6292               if (!lex_force_match_id (lexer, "CILEVEL"))
6293                 goto error;
6294               lex_match (lexer, T_EQUALS);
6295
6296               if (!lex_force_num_range_halfopen (lexer, "CILEVEL", 0, 100))
6297                 goto error;
6298               t->cilevel = lex_number (lexer);
6299               lex_get (lexer);
6300             }
6301           else if (lex_match_id (lexer, "CATEGORIES"))
6302             {
6303               if (!ctables_table_parse_categories (lexer, dataset_dict (ds),
6304                                                    ct, t))
6305                 goto error;
6306             }
6307           else if (lex_match_id (lexer, "TITLES"))
6308             {
6309               do
6310                 {
6311                   char **textp;
6312                   if (lex_match_id (lexer, "CAPTION"))
6313                     textp = &t->caption;
6314                   else if (lex_match_id (lexer, "CORNER"))
6315                     textp = &t->corner;
6316                   else if (lex_match_id (lexer, "TITLE"))
6317                     textp = &t->title;
6318                   else
6319                     {
6320                       lex_error_expecting (lexer, "CAPTION", "CORNER", "TITLE");
6321                       goto error;
6322                     }
6323                   lex_match (lexer, T_EQUALS);
6324
6325                   struct string s = DS_EMPTY_INITIALIZER;
6326                   while (lex_is_string (lexer))
6327                     {
6328                       if (!ds_is_empty (&s))
6329                         ds_put_byte (&s, ' ');
6330                       put_title_text (&s, lex_tokss (lexer), now,
6331                                       lexer, dataset_dict (ds),
6332                                       expr_start, expr_end);
6333                       lex_get (lexer);
6334                     }
6335                   free (*textp);
6336                   *textp = ds_steal_cstr (&s);
6337                 }
6338               while (lex_token (lexer) != T_SLASH
6339                      && lex_token (lexer) != T_ENDCMD);
6340             }
6341           else if (lex_match_id (lexer, "SIGTEST"))
6342             {
6343               if (!t->chisq)
6344                 {
6345                   t->chisq = xmalloc (sizeof *t->chisq);
6346                   *t->chisq = (struct ctables_chisq) {
6347                     .alpha = .05,
6348                     .include_mrsets = true,
6349                     .all_visible = true,
6350                   };
6351                 }
6352
6353               do
6354                 {
6355                   if (lex_match_id (lexer, "TYPE"))
6356                     {
6357                       lex_match (lexer, T_EQUALS);
6358                       if (!lex_force_match_id (lexer, "CHISQUARE"))
6359                         goto error;
6360                     }
6361                   else if (lex_match_id (lexer, "ALPHA"))
6362                     {
6363                       lex_match (lexer, T_EQUALS);
6364                       if (!lex_force_num_range_halfopen (lexer, "ALPHA", 0, 1))
6365                         goto error;
6366                       t->chisq->alpha = lex_number (lexer);
6367                       lex_get (lexer);
6368                     }
6369                   else if (lex_match_id (lexer, "INCLUDEMRSETS"))
6370                     {
6371                       lex_match (lexer, T_EQUALS);
6372                       if (parse_bool (lexer, &t->chisq->include_mrsets))
6373                         goto error;
6374                     }
6375                   else if (lex_match_id (lexer, "CATEGORIES"))
6376                     {
6377                       lex_match (lexer, T_EQUALS);
6378                       if (lex_match_id (lexer, "ALLVISIBLE"))
6379                         t->chisq->all_visible = true;
6380                       else if (lex_match_id (lexer, "SUBTOTALS"))
6381                         t->chisq->all_visible = false;
6382                       else
6383                         {
6384                           lex_error_expecting (lexer,
6385                                                "ALLVISIBLE", "SUBTOTALS");
6386                           goto error;
6387                         }
6388                     }
6389                   else
6390                     {
6391                       lex_error_expecting (lexer, "TYPE", "ALPHA",
6392                                            "INCLUDEMRSETS", "CATEGORIES");
6393                       goto error;
6394                     }
6395                 }
6396               while (lex_token (lexer) != T_SLASH
6397                      && lex_token (lexer) != T_ENDCMD);
6398             }
6399           else if (lex_match_id (lexer, "COMPARETEST"))
6400             {
6401               if (!t->pairwise)
6402                 {
6403                   t->pairwise = xmalloc (sizeof *t->pairwise);
6404                   *t->pairwise = (struct ctables_pairwise) {
6405                     .type = PROP,
6406                     .alpha = { .05, .05 },
6407                     .adjust = BONFERRONI,
6408                     .include_mrsets = true,
6409                     .meansvariance_allcats = true,
6410                     .all_visible = true,
6411                     .merge = false,
6412                     .apa_style = true,
6413                     .show_sig = false,
6414                   };
6415                 }
6416
6417               do
6418                 {
6419                   if (lex_match_id (lexer, "TYPE"))
6420                     {
6421                       lex_match (lexer, T_EQUALS);
6422                       if (lex_match_id (lexer, "PROP"))
6423                         t->pairwise->type = PROP;
6424                       else if (lex_match_id (lexer, "MEAN"))
6425                         t->pairwise->type = MEAN;
6426                       else
6427                         {
6428                           lex_error_expecting (lexer, "PROP", "MEAN");
6429                           goto error;
6430                         }
6431                     }
6432                   else if (lex_match_id (lexer, "ALPHA"))
6433                     {
6434                       lex_match (lexer, T_EQUALS);
6435
6436                       if (!lex_force_num_range_open (lexer, "ALPHA", 0, 1))
6437                         goto error;
6438                       double a0 = lex_number (lexer);
6439                       lex_get (lexer);
6440
6441                       lex_match (lexer, T_COMMA);
6442                       if (lex_is_number (lexer))
6443                         {
6444                           if (!lex_force_num_range_open (lexer, "ALPHA", 0, 1))
6445                             goto error;
6446                           double a1 = lex_number (lexer);
6447                           lex_get (lexer);
6448
6449                           t->pairwise->alpha[0] = MIN (a0, a1);
6450                           t->pairwise->alpha[1] = MAX (a0, a1);
6451                         }
6452                       else
6453                         t->pairwise->alpha[0] = t->pairwise->alpha[1] = a0;
6454                     }
6455                   else if (lex_match_id (lexer, "ADJUST"))
6456                     {
6457                       lex_match (lexer, T_EQUALS);
6458                       if (lex_match_id (lexer, "BONFERRONI"))
6459                         t->pairwise->adjust = BONFERRONI;
6460                       else if (lex_match_id (lexer, "BH"))
6461                         t->pairwise->adjust = BH;
6462                       else if (lex_match_id (lexer, "NONE"))
6463                         t->pairwise->adjust = 0;
6464                       else
6465                         {
6466                           lex_error_expecting (lexer, "BONFERRONI", "BH",
6467                                                "NONE");
6468                           goto error;
6469                         }
6470                     }
6471                   else if (lex_match_id (lexer, "INCLUDEMRSETS"))
6472                     {
6473                       lex_match (lexer, T_EQUALS);
6474                       if (!parse_bool (lexer, &t->pairwise->include_mrsets))
6475                         goto error;
6476                     }
6477                   else if (lex_match_id (lexer, "MEANSVARIANCE"))
6478                     {
6479                       lex_match (lexer, T_EQUALS);
6480                       if (lex_match_id (lexer, "ALLCATS"))
6481                         t->pairwise->meansvariance_allcats = true;
6482                       else if (lex_match_id (lexer, "TESTEDCATS"))
6483                         t->pairwise->meansvariance_allcats = false;
6484                       else
6485                         {
6486                           lex_error_expecting (lexer, "ALLCATS", "TESTEDCATS");
6487                           goto error;
6488                         }
6489                     }
6490                   else if (lex_match_id (lexer, "CATEGORIES"))
6491                     {
6492                       lex_match (lexer, T_EQUALS);
6493                       if (lex_match_id (lexer, "ALLVISIBLE"))
6494                         t->pairwise->all_visible = true;
6495                       else if (lex_match_id (lexer, "SUBTOTALS"))
6496                         t->pairwise->all_visible = false;
6497                       else
6498                         {
6499                           lex_error_expecting (lexer, "ALLVISIBLE",
6500                                                "SUBTOTALS");
6501                           goto error;
6502                         }
6503                     }
6504                   else if (lex_match_id (lexer, "MERGE"))
6505                     {
6506                       lex_match (lexer, T_EQUALS);
6507                       if (!parse_bool (lexer, &t->pairwise->merge))
6508                         goto error;
6509                     }
6510                   else if (lex_match_id (lexer, "STYLE"))
6511                     {
6512                       lex_match (lexer, T_EQUALS);
6513                       if (lex_match_id (lexer, "APA"))
6514                         t->pairwise->apa_style = true;
6515                       else if (lex_match_id (lexer, "SIMPLE"))
6516                         t->pairwise->apa_style = false;
6517                       else
6518                         {
6519                           lex_error_expecting (lexer, "APA", "SIMPLE");
6520                           goto error;
6521                         }
6522                     }
6523                   else if (lex_match_id (lexer, "SHOWSIG"))
6524                     {
6525                       lex_match (lexer, T_EQUALS);
6526                       if (!parse_bool (lexer, &t->pairwise->show_sig))
6527                         goto error;
6528                     }
6529                   else
6530                     {
6531                       lex_error_expecting (lexer, "TYPE", "ALPHA", "ADJUST",
6532                                            "INCLUDEMRSETS", "MEANSVARIANCE",
6533                                            "CATEGORIES", "MERGE", "STYLE",
6534                                            "SHOWSIG");
6535                       goto error;
6536                     }
6537                 }
6538               while (lex_token (lexer) != T_SLASH
6539                      && lex_token (lexer) != T_ENDCMD);
6540             }
6541           else
6542             {
6543               lex_error_expecting (lexer, "TABLE", "SLABELS", "CLABELS",
6544                                    "CRITERIA", "CATEGORIES", "TITLES",
6545                                    "SIGTEST", "COMPARETEST");
6546               goto error;
6547             }
6548
6549           if (!lex_match (lexer, T_SLASH))
6550             break;
6551         }
6552
6553       if (t->label_axis[PIVOT_AXIS_ROW] != PIVOT_AXIS_ROW
6554           && t->label_axis[PIVOT_AXIS_COLUMN] != PIVOT_AXIS_COLUMN)
6555         {
6556           msg (SE, _("ROWLABELS and COLLABELS may not both be specified."));
6557           goto error;
6558         }
6559
6560       if (!ctables_prepare_table (t))
6561         goto error;
6562     }
6563   while (lex_token (lexer) != T_ENDCMD);
6564
6565   bool ok = ctables_execute (ds, ct);
6566   ctables_destroy (ct);
6567   return ok ? CMD_SUCCESS : CMD_FAILURE;
6568
6569 error:
6570   ctables_destroy (ct);
6571   return CMD_FAILURE;
6572 }
6573