Work on weighting.
[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
21 #include "data/casereader.h"
22 #include "data/casewriter.h"
23 #include "data/dataset.h"
24 #include "data/dictionary.h"
25 #include "data/mrset.h"
26 #include "data/subcase.h"
27 #include "data/value-labels.h"
28 #include "language/command.h"
29 #include "language/lexer/format-parser.h"
30 #include "language/lexer/lexer.h"
31 #include "language/lexer/variable-parser.h"
32 #include "libpspp/array.h"
33 #include "libpspp/assertion.h"
34 #include "libpspp/hash-functions.h"
35 #include "libpspp/hmap.h"
36 #include "libpspp/message.h"
37 #include "libpspp/string-array.h"
38 #include "math/mode.h"
39 #include "math/moments.h"
40 #include "math/percentiles.h"
41 #include "math/sort.h"
42 #include "output/pivot-table.h"
43
44 #include "gl/minmax.h"
45 #include "gl/xalloc.h"
46
47 #include "gettext.h"
48 #define _(msgid) gettext (msgid)
49 #define N_(msgid) (msgid)
50
51 enum ctables_vlabel
52   {
53     CTVL_NONE = SETTINGS_VALUE_SHOW_DEFAULT,
54     CTVL_NAME = SETTINGS_VALUE_SHOW_VALUE,
55     CTVL_LABEL = SETTINGS_VALUE_SHOW_LABEL,
56     CTVL_BOTH = SETTINGS_VALUE_SHOW_BOTH,
57   };
58
59 /* XXX:
60    - unweighted summaries (U*)
61    - lower confidence limits (*.LCL)
62    - upper confidence limits (*.UCL)
63    - standard error (*.SE)
64  */
65 #define SUMMARIES                                                       \
66     /* All variables. */                                                \
67     S(CTSF_COUNT, "COUNT", N_("Count"), CTF_COUNT, CTFA_ALL)            \
68     S(CTSF_ECOUNT, "ECOUNT", N_("Adjusted Count"), CTF_COUNT, CTFA_ALL) \
69     S(CTSF_ROWPCT_COUNT, "ROWPCT.COUNT", N_("Row %"), CTF_PERCENT, CTFA_ALL) \
70     S(CTSF_COLPCT_COUNT, "COLPCT.COUNT", N_("Column %"), CTF_PERCENT, CTFA_ALL) \
71     S(CTSF_TABLEPCT_COUNT, "TABLEPCT.COUNT", N_("Table %"), CTF_PERCENT, CTFA_ALL) \
72     S(CTSF_SUBTABLEPCT_COUNT, "SUBTABLEPCT.COUNT", N_("Subtable %"), CTF_PERCENT, CTFA_ALL) \
73     S(CTSF_LAYERPCT_COUNT, "LAYERPCT.COUNT", N_("Layer %"), CTF_PERCENT, CTFA_ALL) \
74     S(CTSF_LAYERROWPCT_COUNT, "LAYERROWPCT.COUNT", N_("Layer Row %"), CTF_PERCENT, CTFA_ALL) \
75     S(CTSF_LAYERCOLPCT_COUNT, "LAYERCOLPCT.COUNT", N_("Layer Column %"), CTF_PERCENT, CTFA_ALL) \
76     S(CTSF_ROWPCT_VALIDN, "ROWPCT.VALIDN", N_("Row Valid N %"), CTF_PERCENT, CTFA_ALL) \
77     S(CTSF_COLPCT_VALIDN, "COLPCT.VALIDN", N_("Column Valid N %"), CTF_PERCENT, CTFA_ALL) \
78     S(CTSF_TABLEPCT_VALIDN, "TABLEPCT.VALIDN", N_("Table Valid N %"), CTF_PERCENT, CTFA_ALL) \
79     S(CTSF_SUBTABLEPCT_VALIDN, "SUBTABLEPCT.VALIDN", N_("Subtable Valid N %"), CTF_PERCENT, CTFA_ALL) \
80     S(CTSF_LAYERPCT_VALIDN, "LAYERPCT.VALIDN", N_("Layer Valid N %"), CTF_PERCENT, CTFA_ALL) \
81     S(CTSF_LAYERROWPCT_VALIDN, "LAYERROWPCT.VALIDN", N_("Layer Row Valid N %"), CTF_PERCENT, CTFA_ALL) \
82     S(CTSF_LAYERCOLPCT_VALIDN, "LAYERCOLPCT.VALIDN", N_("Layer Column Valid N %"), CTF_PERCENT, CTFA_ALL) \
83     S(CTSF_ROWPCT_TOTALN, "ROWPCT.TOTALN", N_("Row Total N %"), CTF_PERCENT, CTFA_ALL) \
84     S(CTSF_COLPCT_TOTALN, "COLPCT.TOTALN", N_("Column Total N %"), CTF_PERCENT, CTFA_ALL) \
85     S(CTSF_TABLEPCT_TOTALN, "TABLEPCT.TOTALN", N_("Table Total N %"), CTF_PERCENT, CTFA_ALL) \
86     S(CTSF_SUBTABLEPCT_TOTALN, "SUBTABLEPCT.TOTALN", N_("Subtable Total N %"), CTF_PERCENT, CTFA_ALL) \
87     S(CTSF_LAYERPCT_TOTALN, "LAYERPCT.TOTALN", N_("Layer Total N %"), CTF_PERCENT, CTFA_ALL) \
88     S(CTSF_LAYERROWPCT_TOTALN, "LAYERROWPCT.TOTALN", N_("Layer Row Total N %"), CTF_PERCENT, CTFA_ALL) \
89     S(CTSF_LAYERCOLPCT_TOTALN, "LAYERCOLPCT.TOTALN", N_("Layer Column Total N %"), CTF_PERCENT, CTFA_ALL) \
90                                                                         \
91     /* Scale variables, totals, and subtotals. */                       \
92     S(CTSF_MAXIMUM, "MAXIMUM", N_("Maximum"), CTF_GENERAL, CTFA_SCALE)  \
93     S(CTSF_MEAN, "MEAN", N_("Mean"), CTF_GENERAL, CTFA_SCALE)           \
94     S(CTSF_MEDIAN, "MEDIAN", N_("Median"), CTF_GENERAL, CTFA_SCALE)     \
95     S(CTSF_MINIMUM, "MINIMUM", N_("Minimum"), CTF_GENERAL, CTFA_SCALE)  \
96     S(CTSF_MISSING, "MISSING", N_("Missing"), CTF_GENERAL, CTFA_SCALE)  \
97     S(CTSF_MODE, "MODE", N_("Mode"), CTF_GENERAL, CTFA_SCALE)           \
98     S(CTSF_PTILE, "PTILE", N_("Percentile"), CTF_GENERAL, CTFA_SCALE)   \
99     S(CTSF_RANGE, "RANGE", N_("Range"), CTF_GENERAL, CTFA_SCALE)        \
100     S(CTSF_SEMEAN, "SEMEAN", N_("Std Error of Mean"), CTF_GENERAL, CTFA_SCALE) \
101     S(CTSF_STDDEV, "STDDEV", N_("Std Deviation"), CTF_GENERAL, CTFA_SCALE) \
102     S(CTSF_SUM, "SUM", N_("Sum"), CTF_GENERAL, CTFA_SCALE)              \
103     S(CSTF_TOTALN, "TOTALN", N_("Total N"), CTF_COUNT, CTFA_SCALE)      \
104     S(CTSF_ETOTALN, "ETOTALN", N_("Adjusted Total N"), CTF_COUNT, CTFA_SCALE) \
105     S(CTSF_VALIDN, "VALIDN", N_("Valid N"), CTF_COUNT, CTFA_SCALE)      \
106     S(CTSF_EVALIDN, "EVALIDN", N_("Adjusted Valid N"), CTF_COUNT, CTFA_SCALE) \
107     S(CTSF_VARIANCE, "VARIANCE", N_("Variance"), CTF_GENERAL, CTFA_SCALE) \
108     S(CTSF_ROWPCT_SUM, "ROWPCT.SUM", N_("Row Sum %"), CTF_PERCENT, CTFA_SCALE) \
109     S(CTSF_COLPCT_SUM, "COLPCT.SUM", N_("Column Sum %"), CTF_PERCENT, CTFA_SCALE) \
110     S(CTSF_TABLEPCT_SUM, "TABLEPCT.SUM", N_("Table Sum %"), CTF_PERCENT, CTFA_SCALE) \
111     S(CTSF_SUBTABLEPCT_SUM, "SUBTABLEPCT.SUM", N_("Subtable Sum %"), CTF_PERCENT, CTFA_SCALE) \
112     S(CTSF_LAYERPCT_SUM, "LAYERPCT.SUM", N_("Layer Sum %"), CTF_PERCENT, CTFA_SCALE) \
113     S(CTSF_LAYERROWPCT_SUM, "LAYERROWPCT.SUM", N_("Layer Row Sum %"), CTF_PERCENT, CTFA_SCALE) \
114     S(CTSF_LAYERCOLPCT_SUM, "LAYERCOLPCT.SUM", N_("Layer Column Sum %"), CTF_PERCENT, CTFA_SCALE) \
115                                                                         \
116     /* Multiple response sets. */                                       \
117   S(CTSF_RESPONSES, "RESPONSES", N_("Responses"), CTF_COUNT, CTFA_MRSETS) \
118     S(CTSF_ROWPCT_RESPONSES, "ROWPCT.RESPONSES", N_("Row Responses %"), CTF_PERCENT, CTFA_MRSETS) \
119     S(CTSF_COLPCT_RESPONSES, "COLPCT.RESPONSES", N_("Column Responses %"), CTF_PERCENT, CTFA_MRSETS) \
120     S(CTSF_TABLEPCT_RESPONSES, "TABLEPCT.RESPONSES", N_("Table Responses %"), CTF_PERCENT, CTFA_MRSETS) \
121     S(CTSF_SUBTABLEPCT_RESPONSES, "SUBTABLEPCT.RESPONSES", N_("Subtable Responses %"), CTF_PERCENT, CTFA_MRSETS) \
122     S(CTSF_LAYERPCT_RESPONSES, "LAYERPCT.RESPONSES", N_("Layer Responses %"), CTF_PERCENT, CTFA_MRSETS) \
123     S(CTSF_LAYERROWPCT_RESPONSES, "LAYERROWPCT.RESPONSES", N_("Layer Row Responses %"), CTF_PERCENT, CTFA_MRSETS) \
124     S(CTSF_LAYERCOLPCT_RESPONSES, "LAYERCOLPCT.RESPONSES", N_("Layer Column Responses %"), CTF_PERCENT, CTFA_MRSETS) \
125     S(CTSF_ROWPCT_RESPONSES_COUNT, "ROWPCT.RESPONSES.COUNT", N_("Row Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
126     S(CTSF_COLPCT_RESPONSES_COUNT, "COLPCT.RESPONSES.COUNT", N_("Column Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
127     S(CTSF_TABLEPCT_RESPONSES_COUNT, "TABLEPCT.RESPONSES.COUNT", N_("Table Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
128     S(CTSF_SUBTABLEPCT_RESPONSES_COUNT, "SUBTABLEPCT.RESPONSES.COUNT", N_("Subtable Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
129     S(CTSF_LAYERPCT_RESPONSES_COUNT, "LAYERPCT.RESPONSES.COUNT", N_("Layer Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
130     S(CTSF_LAYERROWPCT_RESPONSES_COUNT, "LAYERROWPCT.RESPONSES.COUNT", N_("Layer Row Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
131     S(CTSF_LAYERCOLPCT_RESPONSES_COUNT, "LAYERCOLPCT.RESPONSES.COUNT", N_("Layer Column Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
132     S(CTSF_ROWPCT_COUNT_RESPONSES, "ROWPCT.COUNT.RESPONSES", N_("Row Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
133     S(CTSF_COLPCT_COUNT_RESPONSES, "COLPCT.COUNT.RESPONSES", N_("Column Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
134     S(CTSF_TABLEPCT_COUNT_RESPONSES, "TABLEPCT.COUNT.RESPONSES", N_("Table Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
135     S(CTSF_SUBTABLEPCT_COUNT_RESPONSES, "SUBTABLEPCT.COUNT.RESPONSES", N_("Subtable Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
136     S(CTSF_LAYERPCT_COUNT_RESPONSES, "LAYERPCT.COUNT.RESPONSES", N_("Layer Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
137     S(CTSF_LAYERROWPCT_COUNT_RESPONSES, "LAYERROWPCT.COUNT.RESPONSES", N_("Layer Row Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
138     S(CTSF_LAYERCOLPCT_COUNT_RESPONSES, "LAYERCOLPCT.RESPONSES.COUNT", N_("Layer Column Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS)
139
140 enum ctables_summary_function
141   {
142 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) ENUM,
143     SUMMARIES
144 #undef S
145   };
146
147 enum {
148 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) +1
149   N_CTSF_FUNCTIONS = SUMMARIES
150 #undef S
151 };
152
153 enum ctables_domain_type
154   {
155     /* Within a section, where stacked variables divide one section from
156        another. */
157     CTDT_TABLE,                  /* All layers of a whole section. */
158     CTDT_LAYER,                  /* One layer within a section. */
159     CTDT_LAYERROW,               /* Row in one layer within a section. */
160     CTDT_LAYERCOL,               /* Column in one layer within a section. */
161
162     /* Within a subtable, where a subtable pairs an innermost row variable with
163        an innermost column variable within a single layer.  */
164     CTDT_SUBTABLE,               /* Whole subtable. */
165     CTDT_ROW,                    /* Row within a subtable. */
166     CTDT_COL,                    /* Column within a subtable. */
167 #define N_CTDTS 7
168   };
169
170 struct ctables_domain
171   {
172     struct hmap_node node;
173
174     const struct ctables_cell *example;
175
176     double d_valid;             /* Dictionary weight. */
177     double d_missing;
178     double e_valid;             /* Effective weight */
179     double e_missing;
180   };
181
182 enum ctables_summary_variant
183   {
184     CSV_CELL,
185     CSV_TOTAL
186 #define N_CSVS 2
187   };
188
189 struct ctables_cell
190   {
191     /* In struct ctables's 'cells' hmap.  Indexed by all the values in all the
192        axes (except the scalar variable, if any). */
193     struct hmap_node node;
194
195     /* The domains that contain this cell. */
196     bool contributes_to_domains;
197     struct ctables_domain *domains[N_CTDTS];
198
199     bool hide;
200     enum ctables_summary_variant sv;
201
202     struct
203       {
204         size_t nest_idx;
205         struct ctables_cell_value
206           {
207             const struct ctables_category *category;
208             union value value;
209           }
210         *cvs;
211         int leaf;
212       }
213     axes[PIVOT_N_AXES];
214
215     union ctables_summary *summaries;
216   };
217
218 struct ctables
219   {
220     struct pivot_table_look *look;
221
222     /* If this is NULL, zeros are displayed using the normal print format.
223        Otherwise, this string is displayed. */
224     char *zero;
225
226     /* If this is NULL, missing values are displayed using the normal print
227        format.  Otherwise, this string is displayed. */
228     char *missing;
229
230     /* Indexed by variable dictionary index. */
231     enum ctables_vlabel *vlabels;
232
233     bool mrsets_count_duplicates; /* MRSETS. */
234     bool smissing_listwise;       /* SMISSING. */
235     struct variable *e_weight;    /* WEIGHT. */
236     int hide_threshold;           /* HIDESMALLCOUNTS. */
237
238     struct ctables_table **tables;
239     size_t n_tables;
240   };
241
242 struct ctables_postcompute
243   {
244     struct hmap_node hmap_node; /* In struct ctables's 'pcompute' hmap. */
245     const char *name;           /* Name, without leading &. */
246
247     struct ctables_postcompute_expr *expr;
248     char *label;
249     /* XXX FORMAT */
250     bool hide_source_cats;
251   };
252
253 struct ctables_postcompute_expr
254   {
255     enum ctables_postcompute_op
256       {
257         /* Terminals. */
258         CTPO_CAT_NUMBER,
259         CTPO_CAT_STRING,
260         CTPO_CAT_RANGE,
261         CTPO_CAT_MISSING,
262         /* XXX OTHERNM */
263         /* XXX SUBTOTAL and HSUBTOTAL */
264
265         /* Nonterminals. */
266         CTPO_ADD,
267         CTPO_SUB,
268         CTPO_MUL,
269         CTPO_DIV,
270         CTPO_POW,
271       }
272     op;
273
274     union
275       {
276         /* CTPO_CAT_NUMBER, CTPO_NUMBER. */
277         double number;
278
279         /* CTPO_CAT_RANGE.
280
281            XXX what about string ranges? */
282         double range[2];
283
284         /* CTPO_ADD, CTPO_SUB, CTPO_MUL, CTPO_DIV, CTPO_POW. */
285         struct ctables_postcompute_expr *subs[2];
286       };
287   };
288
289 struct ctables_summary_spec_set
290   {
291     struct ctables_summary_spec *specs;
292     size_t n;
293     size_t allocated;
294
295     struct variable *var;
296   };
297
298 static void ctables_summary_spec_set_clone (struct ctables_summary_spec_set *,
299                                             const struct ctables_summary_spec_set *);
300 static void ctables_summary_spec_set_uninit (struct ctables_summary_spec_set *);
301
302 /* A nested sequence of variables, e.g. a > b > c. */
303 struct ctables_nest
304   {
305     struct variable **vars;
306     size_t n;
307     size_t scale_idx;
308     size_t *domains[N_CTDTS];
309     size_t n_domains[N_CTDTS];
310
311     struct ctables_summary_spec_set specs[N_CSVS];
312   };
313
314 /* A stack of nestings, e.g. nest1 + nest2 + ... + nestN. */
315 struct ctables_stack
316   {
317     struct ctables_nest *nests;
318     size_t n;
319   };
320
321 struct ctables_value
322   {
323     struct hmap_node node;
324     union value value;
325     int leaf;
326   };
327
328 struct ctables_table
329   {
330     struct ctables_axis *axes[PIVOT_N_AXES];
331     struct ctables_stack stacks[PIVOT_N_AXES];
332     enum pivot_axis_type summary_axis;
333     struct ctables_summary_spec_set summary_specs;
334     struct hmap cells;
335     struct hmap domains[N_CTDTS];
336
337     const struct variable *clabels_example;
338     struct hmap clabels_values_map;
339     struct ctables_value **clabels_values;
340     size_t n_clabels_values;
341
342     enum pivot_axis_type slabels_axis;
343     bool slabels_visible;
344
345     /* The innermost category labels for axis 'a' appear on axis label_axis[a].
346
347        Most commonly, label_axis[a] == a, and in particular we always have
348        label_axis{PIVOT_AXIS_LAYER] == PIVOT_AXIS_LAYER.
349
350        If ROWLABELS or COLLABELS is specified, then one of
351        label_axis[PIVOT_AXIS_ROW] or label_axis[PIVOT_AXIS_COLUMN] can be the
352        opposite axis or PIVOT_AXIS_LAYER.  Only one of them will differ.
353     */
354     enum pivot_axis_type label_axis[PIVOT_N_AXES];
355     enum pivot_axis_type clabels_from_axis;
356
357     /* Indexed by variable dictionary index. */
358     struct ctables_categories **categories;
359     size_t n_categories;
360
361     double cilevel;
362
363     char *caption;
364     char *corner;
365     char *title;
366
367     struct ctables_chisq *chisq;
368     struct ctables_pairwise *pairwise;
369   };
370
371 struct ctables_var
372   {
373     bool is_mrset;
374     union
375       {
376         struct variable *var;
377         const struct mrset *mrset;
378       };
379   };
380
381 static const struct fmt_spec *
382 ctables_var_get_print_format (const struct ctables_var *var)
383 {
384   return (var->is_mrset
385           ? var_get_print_format (var->mrset->vars[0])
386           : var_get_print_format (var->var));
387 }
388
389 static const char *
390 ctables_var_name (const struct ctables_var *var)
391 {
392   return var->is_mrset ? var->mrset->name : var_get_name (var->var);
393 }
394
395 struct ctables_categories
396   {
397     size_t n_refs;
398     struct ctables_category *cats;
399     size_t n_cats;
400     bool show_empty;
401   };
402
403 struct ctables_category
404   {
405     enum ctables_category_type
406       {
407         CCT_NUMBER,
408         CCT_STRING,
409         CCT_RANGE,
410         CCT_MISSING,
411         CCT_OTHERNM,
412
413         CCT_SUBTOTAL,
414         CCT_HSUBTOTAL,
415         CCT_TOTAL,
416
417         CCT_VALUE,
418         CCT_LABEL,
419         CCT_FUNCTION,
420       }
421     type;
422
423     struct ctables_category *subtotal;
424
425     union
426       {
427         double number;          /* CCT_NUMBER. */
428         char *string;           /* CCT_STRING. */
429         double range[2];        /* CCT_RANGE. */
430         char *total_label;   /* CCT_SUBTOTAL, CCT_HSUBTOTAL, CCT_TOTAL. */
431
432         /* CCT_VALUE, CCT_LABEL, CCT_FUNCTION. */
433         struct
434           {
435             bool include_missing;
436             bool sort_ascending;
437
438             /* CCT_FUNCTION. */
439             enum ctables_summary_function sort_function;
440             struct variable *sort_var;
441             double percentile;
442           };
443       };
444   };
445
446 static void
447 ctables_category_uninit (struct ctables_category *cat)
448 {
449   if (!cat)
450     return;
451
452   switch (cat->type)
453     {
454     case CCT_NUMBER:
455     case CCT_RANGE:
456     case CCT_MISSING:
457     case CCT_OTHERNM:
458       break;
459
460     case CCT_STRING:
461       free (cat->string);
462       break;
463
464     case CCT_SUBTOTAL:
465     case CCT_HSUBTOTAL:
466     case CCT_TOTAL:
467       free (cat->total_label);
468       break;
469
470     case CCT_VALUE:
471     case CCT_LABEL:
472     case CCT_FUNCTION:
473       break;
474     }
475 }
476
477 static bool
478 ctables_category_equal (const struct ctables_category *a,
479                         const struct ctables_category *b)
480 {
481   if (a->type != b->type)
482     return false;
483
484   switch (a->type)
485     {
486     case CCT_NUMBER:
487       return a->number == b->number;
488
489     case CCT_STRING:
490       return strcmp (a->string, b->string);
491
492     case CCT_RANGE:
493       return a->range[0] == b->range[0] && a->range[1] == b->range[1];
494
495     case CCT_MISSING:
496     case CCT_OTHERNM:
497       return true;
498
499     case CCT_SUBTOTAL:
500     case CCT_HSUBTOTAL:
501     case CCT_TOTAL:
502       return !strcmp (a->total_label, b->total_label);
503
504     case CCT_VALUE:
505     case CCT_LABEL:
506     case CCT_FUNCTION:
507       return (a->include_missing == b->include_missing
508               && a->sort_ascending == b->sort_ascending
509               && a->sort_function == b->sort_function
510               && a->sort_var == b->sort_var
511               && a->percentile == b->percentile);
512     }
513
514   NOT_REACHED ();
515 }
516
517 static void
518 ctables_categories_unref (struct ctables_categories *c)
519 {
520   if (!c)
521     return;
522
523   assert (c->n_refs > 0);
524   if (--c->n_refs)
525     return;
526
527   for (size_t i = 0; i < c->n_cats; i++)
528     ctables_category_uninit (&c->cats[i]);
529   free (c->cats);
530   free (c);
531 }
532
533 static bool
534 ctables_categories_equal (const struct ctables_categories *a,
535                           const struct ctables_categories *b)
536 {
537   if (a->n_cats != b->n_cats || a->show_empty != b->show_empty)
538     return false;
539
540   for (size_t i = 0; i < a->n_cats; i++)
541     if (!ctables_category_equal (&a->cats[i], &b->cats[i]))
542       return false;
543
544   return true;
545 }
546
547 /* Chi-square test (SIGTEST). */
548 struct ctables_chisq
549   {
550     double alpha;
551     bool include_mrsets;
552     bool all_visible;
553   };
554
555 /* Pairwise comparison test (COMPARETEST). */
556 struct ctables_pairwise
557   {
558     enum { PROP, MEAN } type;
559     double alpha[2];
560     bool include_mrsets;
561     bool meansvariance_allcats;
562     bool all_visible;
563     enum { BONFERRONI = 1, BH } adjust;
564     bool merge;
565     bool apa_style;
566     bool show_sig;
567   };
568
569 struct ctables_axis
570   {
571     enum ctables_axis_op
572       {
573         /* Terminals. */
574         CTAO_VAR,
575
576         /* Nonterminals. */
577         CTAO_STACK,             /* + */
578         CTAO_NEST,              /* > */
579       }
580     op;
581
582     union
583       {
584         /* Terminals. */
585         struct
586           {
587             struct ctables_var var;
588             bool scale;
589             struct ctables_summary_spec_set specs[N_CSVS];
590           };
591
592         /* Nonterminals. */
593         struct ctables_axis *subs[2];
594       };
595
596     struct msg_location *loc;
597   };
598
599 static void ctables_axis_destroy (struct ctables_axis *);
600
601 enum ctables_format
602   {
603     CTF_COUNT,
604     CTF_PERCENT,
605     CTF_GENERAL
606   };
607
608 enum ctables_function_availability
609   {
610     CTFA_ALL,                /* Any variables. */
611     CTFA_SCALE,              /* Only scale variables, totals, and subtotals. */
612     CTFA_MRSETS,             /* Only multiple-response sets */
613   };
614
615 struct ctables_summary_spec
616   {
617     enum ctables_summary_function function;
618     double percentile;          /* CTSF_PTILE only. */
619     char *label;
620     struct fmt_spec format;     /* XXX extra CTABLES formats */
621     size_t axis_idx;
622   };
623
624 static void
625 ctables_summary_spec_clone (struct ctables_summary_spec *dst,
626                             const struct ctables_summary_spec *src)
627 {
628   *dst = *src;
629   dst->label = xstrdup (src->label);
630 }
631
632 static void
633 ctables_summary_spec_uninit (struct ctables_summary_spec *s)
634 {
635   if (s)
636     free (s->label);
637 }
638
639 static void
640 ctables_summary_spec_set_clone (struct ctables_summary_spec_set *dst,
641                                 const struct ctables_summary_spec_set *src)
642 {
643   struct ctables_summary_spec *specs = xnmalloc (src->n, sizeof *specs);
644   for (size_t i = 0; i < src->n; i++)
645     ctables_summary_spec_clone (&specs[i], &src->specs[i]);
646
647   *dst = (struct ctables_summary_spec_set) {
648     .specs = specs,
649     .n = src->n,
650     .allocated = src->n,
651     .var = src->var
652   };
653 }
654
655 static void
656 ctables_summary_spec_set_uninit (struct ctables_summary_spec_set *set)
657 {
658   for (size_t i = 0; i < set->n; i++)
659     ctables_summary_spec_uninit (&set->specs[i]);
660   free (set->specs);
661 }
662
663 static bool
664 parse_col_width (struct lexer *lexer, const char *name, double *width)
665 {
666   lex_match (lexer, T_EQUALS);
667   if (lex_match_id (lexer, "DEFAULT"))
668     *width = SYSMIS;
669   else if (lex_force_num_range_closed (lexer, name, 0, DBL_MAX))
670     {
671       *width = lex_number (lexer);
672       lex_get (lexer);
673     }
674   else
675     return false;
676
677   return true;
678 }
679
680 static bool
681 parse_bool (struct lexer *lexer, bool *b)
682 {
683   if (lex_match_id (lexer, "NO"))
684     *b = false;
685   else if (lex_match_id (lexer, "YES"))
686     *b = true;
687   else
688     {
689       lex_error_expecting (lexer, "YES", "NO");
690       return false;
691     }
692   return true;
693 }
694
695 static enum ctables_function_availability
696 ctables_function_availability (enum ctables_summary_function f)
697 {
698   static enum ctables_function_availability availability[] = {
699 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = AVAILABILITY,
700     SUMMARIES
701 #undef S
702   };
703
704   return availability[f];
705 }
706
707 static bool
708 parse_ctables_summary_function (struct lexer *lexer,
709                                 enum ctables_summary_function *f)
710 {
711   struct pair
712     {
713       enum ctables_summary_function function;
714       struct substring name;
715     };
716   static struct pair names[] = {
717 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) \
718     { ENUM, SS_LITERAL_INITIALIZER (NAME) },
719     SUMMARIES
720
721     /* The .COUNT suffix may be omitted. */
722     S(CTSF_ROWPCT_COUNT, "ROWPCT", _, _, _)
723     S(CTSF_COLPCT_COUNT, "COLPCT", _, _, _)
724     S(CTSF_TABLEPCT_COUNT, "TABLEPCT", _, _, _)
725     S(CTSF_SUBTABLEPCT_COUNT, "SUBTABLEPCT", _, _, _)
726     S(CTSF_LAYERPCT_COUNT, "LAYERPCT", _, _, _)
727     S(CTSF_LAYERROWPCT_COUNT, "LAYERROWPCT", _, _, _)
728     S(CTSF_LAYERCOLPCT_COUNT, "LAYERCOLPCT", _, _, _)
729 #undef S
730   };
731
732   if (!lex_force_id (lexer))
733     return false;
734
735   for (size_t i = 0; i < sizeof names / sizeof *names; i++)
736     if (ss_equals_case (names[i].name, lex_tokss (lexer)))
737       {
738         *f = names[i].function;
739         lex_get (lexer);
740         return true;
741       }
742
743   lex_error (lexer, _("Expecting summary function name."));
744   return false;
745 }
746
747 static void
748 ctables_axis_destroy (struct ctables_axis *axis)
749 {
750   if (!axis)
751     return;
752
753   switch (axis->op)
754     {
755     case CTAO_VAR:
756       for (size_t i = 0; i < N_CSVS; i++)
757         ctables_summary_spec_set_uninit (&axis->specs[i]);
758       break;
759
760     case CTAO_STACK:
761     case CTAO_NEST:
762       ctables_axis_destroy (axis->subs[0]);
763       ctables_axis_destroy (axis->subs[1]);
764       break;
765     }
766   msg_location_destroy (axis->loc);
767   free (axis);
768 }
769
770 static struct ctables_axis *
771 ctables_axis_new_nonterminal (enum ctables_axis_op op,
772                               struct ctables_axis *sub0,
773                               struct ctables_axis *sub1,
774                               struct lexer *lexer, int start_ofs)
775 {
776   struct ctables_axis *axis = xmalloc (sizeof *axis);
777   *axis = (struct ctables_axis) {
778     .op = op,
779     .subs = { sub0, sub1 },
780     .loc = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer) - 1),
781   };
782   return axis;
783 }
784
785 struct ctables_axis_parse_ctx
786   {
787     struct lexer *lexer;
788     struct dictionary *dict;
789     struct ctables *ct;
790     struct ctables_table *t;
791   };
792
793 static struct fmt_spec
794 ctables_summary_default_format (enum ctables_summary_function function,
795                                 const struct ctables_var *var)
796 {
797   static const enum ctables_format default_formats[] = {
798 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = FORMAT,
799     SUMMARIES
800 #undef S
801   };
802   switch (default_formats[function])
803     {
804     case CTF_COUNT:
805       return (struct fmt_spec) { .type = FMT_F, .w = 40 };
806
807     case CTF_PERCENT:
808       return (struct fmt_spec) { .type = FMT_PCT, .w = 40, .d = 1 };
809
810     case CTF_GENERAL:
811       return *ctables_var_get_print_format (var);
812
813     default:
814       NOT_REACHED ();
815     }
816 }
817
818 static char *
819 ctables_summary_default_label (enum ctables_summary_function function,
820                                double percentile)
821 {
822   static const char *default_labels[] = {
823 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = LABEL,
824     SUMMARIES
825 #undef S
826   };
827
828   return (function == CTSF_PTILE
829           ? xasprintf (_("Percentile %.2f"), percentile)
830           : xstrdup (gettext (default_labels[function])));
831 }
832
833 static const char *
834 ctables_summary_function_name (enum ctables_summary_function function)
835 {
836   static const char *names[] = {
837 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = NAME,
838     SUMMARIES
839 #undef S
840   };
841   return names[function];
842 }
843
844 static bool
845 add_summary_spec (struct ctables_axis *axis,
846                   enum ctables_summary_function function, double percentile,
847                   const char *label, const struct fmt_spec *format,
848                   const struct msg_location *loc, enum ctables_summary_variant sv)
849 {
850   if (axis->op == CTAO_VAR)
851     {
852       const char *function_name = ctables_summary_function_name (function);
853       const char *var_name = ctables_var_name (&axis->var);
854       switch (ctables_function_availability (function))
855         {
856         case CTFA_MRSETS:
857           if (!axis->var.is_mrset)
858             {
859               msg_at (SE, loc, _("Summary function %s applies only to multiple "
860                                  "response sets."), function_name);
861               msg_at (SN, axis->loc, _("'%s' is not a multiple response set."),
862                       var_name);
863               return false;
864             }
865           break;
866
867         case CTFA_SCALE:
868           if (!axis->scale)
869             {
870               msg_at (SE, loc,
871                       _("Summary function %s applies only to scale variables."),
872                       function_name);
873               msg_at (SN, axis->loc, _("'%s' is not a scale variable."),
874                       var_name);
875               return false;
876             }
877           break;
878
879         case CTFA_ALL:
880           break;
881         }
882
883       struct ctables_summary_spec_set *set = &axis->specs[sv];
884       if (set->n >= set->allocated)
885         set->specs = x2nrealloc (set->specs, &set->allocated,
886                                  sizeof *set->specs);
887
888       struct ctables_summary_spec *dst = &set->specs[set->n++];
889       *dst = (struct ctables_summary_spec) {
890         .function = function,
891         .percentile = percentile,
892         .label = xstrdup (label),
893         .format = (format ? *format
894                    : ctables_summary_default_format (function, &axis->var)),
895       };
896       return true;
897     }
898   else
899     {
900       for (size_t i = 0; i < 2; i++)
901         if (!add_summary_spec (axis->subs[i], function, percentile, label,
902                                format, loc, sv))
903           return false;
904       return true;
905     }
906 }
907
908 static struct ctables_axis *ctables_axis_parse_stack (
909   struct ctables_axis_parse_ctx *);
910
911 static bool
912 ctables_var_parse (struct lexer *lexer, struct dictionary *dict,
913                    struct ctables_var *var)
914 {
915   if (ss_starts_with (lex_tokss (lexer), ss_cstr ("$")))
916     {
917       *var = (struct ctables_var) {
918         .is_mrset = true,
919         .mrset = dict_lookup_mrset (dict, lex_tokcstr (lexer))
920       };
921       if (!var->mrset)
922         {
923           lex_error (lexer, _("'%s' does not name a multiple-response set "
924                               "in the active file dictionary."),
925                      lex_tokcstr (lexer));
926           return false;
927         }
928       lex_get (lexer);
929       return true;
930     }
931   else
932     {
933       *var = (struct ctables_var) {
934         .is_mrset = false,
935         .var = parse_variable (lexer, dict),
936       };
937       return var->var != NULL;
938     }
939 }
940
941 static struct ctables_axis *
942 ctables_axis_parse_primary (struct ctables_axis_parse_ctx *ctx)
943 {
944   if (lex_match (ctx->lexer, T_LPAREN))
945     {
946       struct ctables_axis *sub = ctables_axis_parse_stack (ctx);
947       if (!sub || !lex_force_match (ctx->lexer, T_RPAREN))
948         {
949           ctables_axis_destroy (sub);
950           return NULL;
951         }
952       return sub;
953     }
954
955   if (!lex_force_id (ctx->lexer))
956     return NULL;
957
958   int start_ofs = lex_ofs (ctx->lexer);
959   struct ctables_var var;
960   if (!ctables_var_parse (ctx->lexer, ctx->dict, &var))
961     return NULL;
962
963   struct ctables_axis *axis = xmalloc (sizeof *axis);
964   *axis = (struct ctables_axis) { .op = CTAO_VAR, .var = var };
965
966   /* XXX should figure out default measures by reading data */
967   axis->scale = (var.is_mrset ? false
968                  : lex_match_phrase (ctx->lexer, "[S]") ? true
969                  : lex_match_phrase (ctx->lexer, "[C]") ? false
970                  : var_get_measure (var.var) == MEASURE_SCALE);
971   axis->loc = lex_ofs_location (ctx->lexer, start_ofs,
972                                 lex_ofs (ctx->lexer) - 1);
973   return axis;
974 }
975
976 static bool
977 has_digit (const char *s)
978 {
979   return s[strcspn (s, "0123456789")] != '\0';
980 }
981
982 static struct ctables_axis *
983 ctables_axis_parse_postfix (struct ctables_axis_parse_ctx *ctx)
984 {
985   struct ctables_axis *sub = ctables_axis_parse_primary (ctx);
986   if (!sub || !lex_match (ctx->lexer, T_LBRACK))
987     return sub;
988
989   enum ctables_summary_variant sv = CSV_CELL;
990   for (;;)
991     {
992       int start_ofs = lex_ofs (ctx->lexer);
993
994       /* Parse function. */
995       enum ctables_summary_function function;
996       if (!parse_ctables_summary_function (ctx->lexer, &function))
997         goto error;
998
999       /* Parse percentile. */
1000       double percentile = 0;
1001       if (function == CTSF_PTILE)
1002         {
1003           if (!lex_force_num_range_closed (ctx->lexer, "PTILE", 0, 100))
1004             goto error;
1005           percentile = lex_number (ctx->lexer);
1006           lex_get (ctx->lexer);
1007         }
1008
1009       /* Parse label. */
1010       char *label;
1011       if (lex_is_string (ctx->lexer))
1012         {
1013           label = ss_xstrdup (lex_tokss (ctx->lexer));
1014           lex_get (ctx->lexer);
1015         }
1016       else
1017         label = ctables_summary_default_label (function, percentile);
1018
1019       /* Parse format. */
1020       struct fmt_spec format;
1021       const struct fmt_spec *formatp;
1022       if (lex_token (ctx->lexer) == T_ID
1023           && has_digit (lex_tokcstr (ctx->lexer)))
1024         {
1025           if (!parse_format_specifier (ctx->lexer, &format)
1026               || !fmt_check_output (&format)
1027               || !fmt_check_type_compat (&format, VAL_NUMERIC))
1028             {
1029               free (label);
1030               goto error;
1031             }
1032           formatp = &format;
1033         }
1034       else
1035         formatp = NULL;
1036
1037       struct msg_location *loc = lex_ofs_location (ctx->lexer, start_ofs,
1038                                                    lex_ofs (ctx->lexer) - 1);
1039       add_summary_spec (sub, function, percentile, label, formatp, loc, sv);
1040       free (label);
1041       msg_location_destroy (loc);
1042
1043       lex_match (ctx->lexer, T_COMMA);
1044       if (sv == CSV_CELL && lex_match_id (ctx->lexer, "TOTALS"))
1045         {
1046           if (!lex_force_match (ctx->lexer, T_LBRACK))
1047             goto error;
1048           sv = CSV_TOTAL;
1049         }
1050       else if (lex_match (ctx->lexer, T_RBRACK))
1051         {
1052           if (sv == CSV_TOTAL && !lex_force_match (ctx->lexer, T_RBRACK))
1053             goto error;
1054           return sub;
1055         }
1056     }
1057
1058 error:
1059   ctables_axis_destroy (sub);
1060   return NULL;
1061 }
1062
1063 static const struct ctables_axis *
1064 find_scale (const struct ctables_axis *axis)
1065 {
1066   if (!axis)
1067     return NULL;
1068   else if (axis->op == CTAO_VAR)
1069     {
1070       if (axis->scale)
1071         {
1072           assert (!axis->var.is_mrset);
1073           return axis;
1074         }
1075       else
1076         return NULL;
1077     }
1078   else
1079     {
1080       for (size_t i = 0; i < 2; i++)
1081         {
1082           const struct ctables_axis *scale = find_scale (axis->subs[i]);
1083           if (scale)
1084             return scale;
1085         }
1086       return NULL;
1087     }
1088 }
1089
1090 static const struct ctables_axis *
1091 find_categorical_summary_spec (const struct ctables_axis *axis)
1092 {
1093   if (!axis)
1094     return NULL;
1095   else if (axis->op == CTAO_VAR)
1096     return !axis->scale && axis->specs[CSV_CELL].n ? axis : NULL;
1097   else
1098     {
1099       for (size_t i = 0; i < 2; i++)
1100         {
1101           const struct ctables_axis *sum
1102             = find_categorical_summary_spec (axis->subs[i]);
1103           if (sum)
1104             return sum;
1105         }
1106       return NULL;
1107     }
1108 }
1109
1110 static struct ctables_axis *
1111 ctables_axis_parse_nest (struct ctables_axis_parse_ctx *ctx)
1112 {
1113   int start_ofs = lex_ofs (ctx->lexer);
1114   struct ctables_axis *lhs = ctables_axis_parse_postfix (ctx);
1115   if (!lhs)
1116     return NULL;
1117
1118   while (lex_match (ctx->lexer, T_GT))
1119     {
1120       struct ctables_axis *rhs = ctables_axis_parse_postfix (ctx);
1121       if (!rhs)
1122         return NULL;
1123
1124       struct ctables_axis *nest = ctables_axis_new_nonterminal (
1125         CTAO_NEST, lhs, rhs, ctx->lexer, start_ofs);
1126
1127       const struct ctables_axis *outer_scale = find_scale (lhs);
1128       const struct ctables_axis *inner_scale = find_scale (rhs);
1129       if (outer_scale && inner_scale)
1130         {
1131           msg_at (SE, nest->loc, _("Cannot nest scale variables."));
1132           msg_at (SN, outer_scale->loc, _("This is an outer scale variable."));
1133           msg_at (SN, inner_scale->loc, _("This is an inner scale variable."));
1134           ctables_axis_destroy (nest);
1135           return NULL;
1136         }
1137
1138       const struct ctables_axis *outer_sum = find_categorical_summary_spec (lhs);
1139       if (outer_sum)
1140         {
1141           msg_at (SE, nest->loc,
1142                   _("Summaries may only be requested for categorical variables "
1143                     "at the innermost nesting level."));
1144           msg_at (SN, outer_sum->loc,
1145                   _("This outer categorical variable has a summary."));
1146           ctables_axis_destroy (nest);
1147           return NULL;
1148         }
1149
1150       lhs = nest;
1151     }
1152
1153   return lhs;
1154 }
1155
1156 static struct ctables_axis *
1157 ctables_axis_parse_stack (struct ctables_axis_parse_ctx *ctx)
1158 {
1159   int start_ofs = lex_ofs (ctx->lexer);
1160   struct ctables_axis *lhs = ctables_axis_parse_nest (ctx);
1161   if (!lhs)
1162     return NULL;
1163
1164   while (lex_match (ctx->lexer, T_PLUS))
1165     {
1166       struct ctables_axis *rhs = ctables_axis_parse_nest (ctx);
1167       if (!rhs)
1168         return NULL;
1169
1170       lhs = ctables_axis_new_nonterminal (CTAO_STACK, lhs, rhs,
1171                                           ctx->lexer, start_ofs);
1172     }
1173
1174   return lhs;
1175 }
1176
1177 static bool
1178 ctables_axis_parse (struct lexer *lexer, struct dictionary *dict,
1179                     struct ctables *ct, struct ctables_table *t,
1180                     enum pivot_axis_type a)
1181 {
1182   if (lex_token (lexer) == T_BY
1183       || lex_token (lexer) == T_SLASH
1184       || lex_token (lexer) == T_ENDCMD)
1185     return true;
1186
1187   struct ctables_axis_parse_ctx ctx = {
1188     .lexer = lexer,
1189     .dict = dict,
1190     .ct = ct,
1191     .t = t
1192   };
1193   t->axes[a] = ctables_axis_parse_stack (&ctx);
1194   return t->axes[a] != NULL;
1195 }
1196
1197 static void
1198 ctables_chisq_destroy (struct ctables_chisq *chisq)
1199 {
1200   free (chisq);
1201 }
1202
1203 static void
1204 ctables_pairwise_destroy (struct ctables_pairwise *pairwise)
1205 {
1206   free (pairwise);
1207 }
1208
1209 static void
1210 ctables_table_destroy (struct ctables_table *t)
1211 {
1212   if (!t)
1213     return;
1214
1215   for (size_t i = 0; i < t->n_categories; i++)
1216     ctables_categories_unref (t->categories[i]);
1217   free (t->categories);
1218
1219   ctables_axis_destroy (t->axes[PIVOT_AXIS_COLUMN]);
1220   ctables_axis_destroy (t->axes[PIVOT_AXIS_ROW]);
1221   ctables_axis_destroy (t->axes[PIVOT_AXIS_LAYER]);
1222   free (t->caption);
1223   free (t->corner);
1224   free (t->title);
1225   ctables_chisq_destroy (t->chisq);
1226   ctables_pairwise_destroy (t->pairwise);
1227   free (t);
1228 }
1229
1230 static void
1231 ctables_destroy (struct ctables *ct)
1232 {
1233   if (!ct)
1234     return;
1235
1236   pivot_table_look_unref (ct->look);
1237   free (ct->zero);
1238   free (ct->missing);
1239   free (ct->vlabels);
1240   for (size_t i = 0; i < ct->n_tables; i++)
1241     ctables_table_destroy (ct->tables[i]);
1242   free (ct->tables);
1243   free (ct);
1244 }
1245
1246 static struct ctables_category
1247 cct_range (double low, double high)
1248 {
1249   return (struct ctables_category) {
1250     .type = CCT_RANGE,
1251     .range = { low, high }
1252   };
1253 }
1254
1255 static bool
1256 ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
1257                                 struct ctables_table *t)
1258 {
1259   if (!lex_match_id (lexer, "VARIABLES"))
1260     return false;
1261   lex_match (lexer, T_EQUALS);
1262
1263   struct variable **vars;
1264   size_t n_vars;
1265   if (!parse_variables (lexer, dict, &vars, &n_vars, PV_NO_SCRATCH))
1266     return false;
1267
1268   struct ctables_categories *c = xmalloc (sizeof *c);
1269   *c = (struct ctables_categories) { .n_refs = n_vars };
1270   for (size_t i = 0; i < n_vars; i++)
1271     {
1272       struct ctables_categories **cp
1273         = &t->categories[var_get_dict_index (vars[i])];
1274       ctables_categories_unref (*cp);
1275       *cp = c;
1276     }
1277   free (vars);
1278
1279   size_t allocated_cats = 0;
1280   if (lex_match (lexer, T_LBRACK))
1281     {
1282       do
1283         {
1284           if (c->n_cats >= allocated_cats)
1285             c->cats = x2nrealloc (c->cats, &allocated_cats, sizeof *c->cats);
1286
1287           struct ctables_category *cat = &c->cats[c->n_cats];
1288           if (lex_match_id (lexer, "OTHERNM"))
1289             cat->type = CCT_OTHERNM;
1290           else if (lex_match_id (lexer, "MISSING"))
1291             cat->type = CCT_MISSING;
1292           else if (lex_match_id (lexer, "SUBTOTAL"))
1293             *cat = (struct ctables_category)
1294               { .type = CCT_SUBTOTAL, .total_label = NULL };
1295           else if (lex_match_id (lexer, "HSUBTOTAL"))
1296             *cat = (struct ctables_category)
1297               { .type = CCT_HSUBTOTAL, .total_label = NULL };
1298           else if (lex_match_id (lexer, "LO"))
1299             {
1300               if (!lex_force_match_id (lexer, "THRU") || lex_force_num (lexer))
1301                 return false;
1302               *cat = cct_range (-DBL_MAX, lex_number (lexer));
1303               lex_get (lexer);
1304             }
1305           else if (lex_is_number (lexer))
1306             {
1307               double number = lex_number (lexer);
1308               lex_get (lexer);
1309               if (lex_match_id (lexer, "THRU"))
1310                 {
1311                   cat->type = CCT_RANGE;
1312                   cat->range[0] = number;
1313                   if (lex_match_id (lexer, "HI"))
1314                     *cat = cct_range (number, DBL_MAX);
1315                   else
1316                     {
1317                       if (!lex_force_num (lexer))
1318                         return false;
1319                       *cat = cct_range (number, lex_number (lexer));
1320                       lex_get (lexer);
1321                     }
1322                 }
1323               else
1324                 *cat = (struct ctables_category) {
1325                   .type = CCT_NUMBER,
1326                   .number = number
1327                 };
1328             }
1329           else if (lex_is_string (lexer))
1330             {
1331               *cat = (struct ctables_category) {
1332                 .type = CCT_STRING,
1333                 .string = ss_xstrdup (lex_tokss (lexer)),
1334               };
1335               lex_get (lexer);
1336             }
1337           else
1338             {
1339               lex_error (lexer, NULL);
1340               return false;
1341             }
1342
1343           if (cat->type == CCT_SUBTOTAL || cat->type == CCT_HSUBTOTAL)
1344             {
1345               if (lex_match (lexer, T_EQUALS))
1346                 {
1347                   if (!lex_force_string (lexer))
1348                     return false;
1349
1350                   cat->total_label = ss_xstrdup (lex_tokss (lexer));
1351                   lex_get (lexer);
1352                 }
1353               else
1354                 cat->total_label = xstrdup (_("Subtotal"));
1355             }
1356
1357           c->n_cats++;
1358           lex_match (lexer, T_COMMA);
1359         }
1360       while (!lex_match (lexer, T_RBRACK));
1361     }
1362
1363   struct ctables_category cat = {
1364     .type = CCT_VALUE,
1365     .include_missing = false,
1366     .sort_ascending = true,
1367   };
1368   bool show_totals = false;
1369   char *total_label = NULL;
1370   bool totals_before = false;
1371   while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
1372     {
1373       if (!c->n_cats && lex_match_id (lexer, "ORDER"))
1374         {
1375           lex_match (lexer, T_EQUALS);
1376           if (lex_match_id (lexer, "A"))
1377             cat.sort_ascending = true;
1378           else if (lex_match_id (lexer, "D"))
1379             cat.sort_ascending = false;
1380           else
1381             {
1382               lex_error_expecting (lexer, "A", "D");
1383               return false;
1384             }
1385         }
1386       else if (!c->n_cats && lex_match_id (lexer, "KEY"))
1387         {
1388           lex_match (lexer, T_EQUALS);
1389           if (lex_match_id (lexer, "VALUE"))
1390             cat.type = CCT_VALUE;
1391           else if (lex_match_id (lexer, "LABEL"))
1392             cat.type = CCT_LABEL;
1393           else
1394             {
1395               cat.type = CCT_FUNCTION;
1396               if (!parse_ctables_summary_function (lexer, &cat.sort_function))
1397                 return false;
1398
1399               if (lex_match (lexer, T_LPAREN))
1400                 {
1401                   cat.sort_var = parse_variable (lexer, dict);
1402                   if (!cat.sort_var)
1403                     return false;
1404
1405                   if (cat.sort_function == CTSF_PTILE)
1406                     {
1407                       lex_match (lexer, T_COMMA);
1408                       if (!lex_force_num_range_closed (lexer, "PTILE", 0, 100))
1409                         return false;
1410                       cat.percentile = lex_number (lexer);
1411                       lex_get (lexer);
1412                     }
1413
1414                   if (!lex_force_match (lexer, T_RPAREN))
1415                     return false;
1416                 }
1417               else if (ctables_function_availability (cat.sort_function)
1418                        == CTFA_SCALE)
1419                 {
1420                   bool UNUSED b = lex_force_match (lexer, T_LPAREN);
1421                   return false;
1422                 }
1423             }
1424         }
1425       else if (!c->n_cats && lex_match_id (lexer, "MISSING"))
1426         {
1427           lex_match (lexer, T_EQUALS);
1428           if (lex_match_id (lexer, "INCLUDE"))
1429             cat.include_missing = true;
1430           else if (lex_match_id (lexer, "EXCLUDE"))
1431             cat.include_missing = false;
1432           else
1433             {
1434               lex_error_expecting (lexer, "INCLUDE", "EXCLUDE");
1435               return false;
1436             }
1437         }
1438       else if (lex_match_id (lexer, "TOTAL"))
1439         {
1440           lex_match (lexer, T_EQUALS);
1441           if (!parse_bool (lexer, &show_totals))
1442             return false;
1443         }
1444       else if (lex_match_id (lexer, "LABEL"))
1445         {
1446           lex_match (lexer, T_EQUALS);
1447           if (!lex_force_string (lexer))
1448             return false;
1449           free (total_label);
1450           total_label = ss_xstrdup (lex_tokss (lexer));
1451           lex_get (lexer);
1452         }
1453       else if (lex_match_id (lexer, "POSITION"))
1454         {
1455           lex_match (lexer, T_EQUALS);
1456           if (lex_match_id (lexer, "BEFORE"))
1457             totals_before = true;
1458           else if (lex_match_id (lexer, "AFTER"))
1459             totals_before = false;
1460           else
1461             {
1462               lex_error_expecting (lexer, "BEFORE", "AFTER");
1463               return false;
1464             }
1465         }
1466       else if (lex_match_id (lexer, "EMPTY"))
1467         {
1468           lex_match (lexer, T_EQUALS);
1469           if (lex_match_id (lexer, "INCLUDE"))
1470             c->show_empty = true;
1471           else if (lex_match_id (lexer, "EXCLUDE"))
1472             c->show_empty = false;
1473           else
1474             {
1475               lex_error_expecting (lexer, "INCLUDE", "EXCLUDE");
1476               return false;
1477             }
1478         }
1479       else
1480         {
1481           if (!c->n_cats)
1482             lex_error_expecting (lexer, "ORDER", "KEY", "MISSING",
1483                                  "TOTAL", "LABEL", "POSITION", "EMPTY");
1484           else
1485             lex_error_expecting (lexer, "TOTAL", "LABEL", "POSITION", "EMPTY");
1486           return false;
1487         }
1488     }
1489
1490   if (!c->n_cats)
1491     {
1492       if (c->n_cats >= allocated_cats)
1493         c->cats = x2nrealloc (c->cats, &allocated_cats,
1494                                 sizeof *c->cats);
1495       c->cats[c->n_cats++] = cat;
1496     }
1497
1498   if (show_totals)
1499     {
1500       if (c->n_cats >= allocated_cats)
1501         c->cats = x2nrealloc (c->cats, &allocated_cats, sizeof *c->cats);
1502
1503       struct ctables_category *totals;
1504       if (totals_before)
1505         {
1506           insert_element (c->cats, c->n_cats, sizeof *c->cats, 0);
1507           totals = &c->cats[0];
1508         }
1509       else
1510         totals = &c->cats[c->n_cats];
1511       c->n_cats++;
1512
1513       *totals = (struct ctables_category) {
1514         .type = CCT_TOTAL,
1515         .total_label = total_label ? total_label : xstrdup (_("Total")),
1516       };
1517     }
1518
1519   struct ctables_category *subtotal = NULL;
1520   for (size_t i = totals_before ? 0 : c->n_cats;
1521        totals_before ? i < c->n_cats : i-- > 0;
1522        totals_before ? i++ : 0)
1523     {
1524       struct ctables_category *cat = &c->cats[i];
1525       switch (cat->type)
1526         {
1527         case CCT_NUMBER:
1528         case CCT_STRING:
1529         case CCT_RANGE:
1530         case CCT_MISSING:
1531         case CCT_OTHERNM:
1532           cat->subtotal = subtotal;
1533           break;
1534
1535         case CCT_SUBTOTAL:
1536         case CCT_HSUBTOTAL:
1537           subtotal = cat;
1538           break;
1539
1540         case CCT_TOTAL:
1541         case CCT_VALUE:
1542         case CCT_LABEL:
1543         case CCT_FUNCTION:
1544           break;
1545         }
1546     }
1547
1548   return true;
1549 }
1550
1551 static void
1552 ctables_nest_uninit (struct ctables_nest *nest)
1553 {
1554   if (nest)
1555     free (nest->vars);
1556 }
1557
1558 static void
1559 ctables_stack_uninit (struct ctables_stack *stack)
1560 {
1561   if (stack)
1562     {
1563       for (size_t i = 0; i < stack->n; i++)
1564         ctables_nest_uninit (&stack->nests[i]);
1565       free (stack->nests);
1566     }
1567 }
1568
1569 static struct ctables_stack
1570 nest_fts (struct ctables_stack s0, struct ctables_stack s1)
1571 {
1572   if (!s0.n)
1573     return s1;
1574   else if (!s1.n)
1575     return s0;
1576
1577   struct ctables_stack stack = { .nests = xnmalloc (s0.n, s1.n * sizeof *stack.nests) };
1578   for (size_t i = 0; i < s0.n; i++)
1579     for (size_t j = 0; j < s1.n; j++)
1580       {
1581         const struct ctables_nest *a = &s0.nests[i];
1582         const struct ctables_nest *b = &s1.nests[j];
1583
1584         size_t allocate = a->n + b->n;
1585         struct variable **vars = xnmalloc (allocate, sizeof *vars);
1586         enum pivot_axis_type *axes = xnmalloc (allocate, sizeof *axes);
1587         size_t n = 0;
1588         for (size_t k = 0; k < a->n; k++)
1589           vars[n++] = a->vars[k];
1590         for (size_t k = 0; k < b->n; k++)
1591           vars[n++] = b->vars[k];
1592         assert (n == allocate);
1593
1594         const struct ctables_nest *summary_src;
1595         if (!a->specs[CSV_CELL].var)
1596           summary_src = b;
1597         else if (!b->specs[CSV_CELL].var)
1598           summary_src = a;
1599         else
1600           NOT_REACHED ();
1601
1602         struct ctables_nest *new = &stack.nests[stack.n++];
1603         *new = (struct ctables_nest) {
1604           .vars = vars,
1605           .scale_idx = (a->scale_idx != SIZE_MAX ? a->scale_idx
1606                         : b->scale_idx != SIZE_MAX ? a->n + b->scale_idx
1607                         : SIZE_MAX),
1608           .n = n,
1609         };
1610         for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
1611           ctables_summary_spec_set_clone (&new->specs[sv], &summary_src->specs[sv]);
1612       }
1613   ctables_stack_uninit (&s0);
1614   ctables_stack_uninit (&s1);
1615   return stack;
1616 }
1617
1618 static struct ctables_stack
1619 stack_fts (struct ctables_stack s0, struct ctables_stack s1)
1620 {
1621   struct ctables_stack stack = { .nests = xnmalloc (s0.n + s1.n, sizeof *stack.nests) };
1622   for (size_t i = 0; i < s0.n; i++)
1623     stack.nests[stack.n++] = s0.nests[i];
1624   for (size_t i = 0; i < s1.n; i++)
1625     stack.nests[stack.n++] = s1.nests[i];
1626   assert (stack.n == s0.n + s1.n);
1627   free (s0.nests);
1628   free (s1.nests);
1629   return stack;
1630 }
1631
1632 static struct ctables_stack
1633 enumerate_fts (enum pivot_axis_type axis_type, const struct ctables_axis *a)
1634 {
1635   if (!a)
1636     return (struct ctables_stack) { .n = 0 };
1637
1638   switch (a->op)
1639     {
1640     case CTAO_VAR:
1641       assert (!a->var.is_mrset);
1642
1643       struct variable **vars = xmalloc (sizeof *vars);
1644       *vars = a->var.var;
1645
1646       struct ctables_nest *nest = xmalloc (sizeof *nest);
1647       *nest = (struct ctables_nest) {
1648         .vars = vars,
1649         .n = 1,
1650         .scale_idx = a->scale ? 0 : SIZE_MAX,
1651       };
1652       if (a->specs[CSV_CELL].n || a->scale)
1653         for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
1654           {
1655             ctables_summary_spec_set_clone (&nest->specs[sv], &a->specs[sv]);
1656             nest->specs[sv].var = a->var.var;
1657           }
1658       return (struct ctables_stack) { .nests = nest, .n = 1 };
1659
1660     case CTAO_STACK:
1661       return stack_fts (enumerate_fts (axis_type, a->subs[0]),
1662                         enumerate_fts (axis_type, a->subs[1]));
1663
1664     case CTAO_NEST:
1665       return nest_fts (enumerate_fts (axis_type, a->subs[0]),
1666                        enumerate_fts (axis_type, a->subs[1]));
1667     }
1668
1669   NOT_REACHED ();
1670 }
1671
1672 union ctables_summary
1673   {
1674     /* COUNT, VALIDN, TOTALN. */
1675     struct
1676       {
1677         double valid;
1678         double missing;
1679       };
1680
1681     /* MINIMUM, MAXIMUM, RANGE. */
1682     struct
1683       {
1684         double min;
1685         double max;
1686       };
1687
1688     /* MEAN, SEMEAN, STDDEV, SUM, VARIANCE, *.SUM. */
1689     struct moments1 *moments;
1690
1691     /* MEDIAN, MODE, PTILE. */
1692     struct
1693       {
1694         struct casewriter *writer;
1695         double ovalid;
1696         double ovalue;
1697       };
1698
1699     /* XXX multiple response */
1700   };
1701
1702 static void
1703 ctables_summary_init (union ctables_summary *s,
1704                       const struct ctables_summary_spec *ss)
1705 {
1706   switch (ss->function)
1707     {
1708     case CTSF_COUNT:
1709     case CTSF_ECOUNT:
1710     case CTSF_ROWPCT_COUNT:
1711     case CTSF_COLPCT_COUNT:
1712     case CTSF_TABLEPCT_COUNT:
1713     case CTSF_SUBTABLEPCT_COUNT:
1714     case CTSF_LAYERPCT_COUNT:
1715     case CTSF_LAYERROWPCT_COUNT:
1716     case CTSF_LAYERCOLPCT_COUNT:
1717     case CTSF_ROWPCT_VALIDN:
1718     case CTSF_COLPCT_VALIDN:
1719     case CTSF_TABLEPCT_VALIDN:
1720     case CTSF_SUBTABLEPCT_VALIDN:
1721     case CTSF_LAYERPCT_VALIDN:
1722     case CTSF_LAYERROWPCT_VALIDN:
1723     case CTSF_LAYERCOLPCT_VALIDN:
1724     case CTSF_ROWPCT_TOTALN:
1725     case CTSF_COLPCT_TOTALN:
1726     case CTSF_TABLEPCT_TOTALN:
1727     case CTSF_SUBTABLEPCT_TOTALN:
1728     case CTSF_LAYERPCT_TOTALN:
1729     case CTSF_LAYERROWPCT_TOTALN:
1730     case CTSF_LAYERCOLPCT_TOTALN:
1731     case CTSF_MISSING:
1732     case CSTF_TOTALN:
1733     case CTSF_ETOTALN:
1734     case CTSF_VALIDN:
1735     case CTSF_EVALIDN:
1736       s->missing = s->valid = 0;
1737       break;
1738
1739     case CTSF_MAXIMUM:
1740     case CTSF_MINIMUM:
1741     case CTSF_RANGE:
1742       s->min = s->max = SYSMIS;
1743       break;
1744
1745     case CTSF_MEAN:
1746     case CTSF_SEMEAN:
1747     case CTSF_STDDEV:
1748     case CTSF_SUM:
1749     case CTSF_VARIANCE:
1750     case CTSF_ROWPCT_SUM:
1751     case CTSF_COLPCT_SUM:
1752     case CTSF_TABLEPCT_SUM:
1753     case CTSF_SUBTABLEPCT_SUM:
1754     case CTSF_LAYERPCT_SUM:
1755     case CTSF_LAYERROWPCT_SUM:
1756     case CTSF_LAYERCOLPCT_SUM:
1757       s->moments = moments1_create (MOMENT_VARIANCE);
1758       break;
1759
1760     case CTSF_MEDIAN:
1761     case CTSF_MODE:
1762     case CTSF_PTILE:
1763       {
1764         struct caseproto *proto = caseproto_create ();
1765         proto = caseproto_add_width (proto, 0);
1766         proto = caseproto_add_width (proto, 0);
1767
1768         struct subcase ordering;
1769         subcase_init (&ordering, 0, 0, SC_ASCEND);
1770         s->writer = sort_create_writer (&ordering, proto);
1771         subcase_uninit (&ordering);
1772         caseproto_unref (proto);
1773
1774         s->ovalid = 0;
1775         s->ovalue = SYSMIS;
1776       }
1777       break;
1778
1779     case CTSF_RESPONSES:
1780     case CTSF_ROWPCT_RESPONSES:
1781     case CTSF_COLPCT_RESPONSES:
1782     case CTSF_TABLEPCT_RESPONSES:
1783     case CTSF_SUBTABLEPCT_RESPONSES:
1784     case CTSF_LAYERPCT_RESPONSES:
1785     case CTSF_LAYERROWPCT_RESPONSES:
1786     case CTSF_LAYERCOLPCT_RESPONSES:
1787     case CTSF_ROWPCT_RESPONSES_COUNT:
1788     case CTSF_COLPCT_RESPONSES_COUNT:
1789     case CTSF_TABLEPCT_RESPONSES_COUNT:
1790     case CTSF_SUBTABLEPCT_RESPONSES_COUNT:
1791     case CTSF_LAYERPCT_RESPONSES_COUNT:
1792     case CTSF_LAYERROWPCT_RESPONSES_COUNT:
1793     case CTSF_LAYERCOLPCT_RESPONSES_COUNT:
1794     case CTSF_ROWPCT_COUNT_RESPONSES:
1795     case CTSF_COLPCT_COUNT_RESPONSES:
1796     case CTSF_TABLEPCT_COUNT_RESPONSES:
1797     case CTSF_SUBTABLEPCT_COUNT_RESPONSES:
1798     case CTSF_LAYERPCT_COUNT_RESPONSES:
1799     case CTSF_LAYERROWPCT_COUNT_RESPONSES:
1800     case CTSF_LAYERCOLPCT_COUNT_RESPONSES:
1801       NOT_REACHED ();
1802     }
1803 }
1804
1805 static void UNUSED
1806 ctables_summary_uninit (union ctables_summary *s,
1807                         const struct ctables_summary_spec *ss)
1808 {
1809   switch (ss->function)
1810     {
1811     case CTSF_COUNT:
1812     case CTSF_ECOUNT:
1813     case CTSF_ROWPCT_COUNT:
1814     case CTSF_COLPCT_COUNT:
1815     case CTSF_TABLEPCT_COUNT:
1816     case CTSF_SUBTABLEPCT_COUNT:
1817     case CTSF_LAYERPCT_COUNT:
1818     case CTSF_LAYERROWPCT_COUNT:
1819     case CTSF_LAYERCOLPCT_COUNT:
1820     case CTSF_ROWPCT_VALIDN:
1821     case CTSF_COLPCT_VALIDN:
1822     case CTSF_TABLEPCT_VALIDN:
1823     case CTSF_SUBTABLEPCT_VALIDN:
1824     case CTSF_LAYERPCT_VALIDN:
1825     case CTSF_LAYERROWPCT_VALIDN:
1826     case CTSF_LAYERCOLPCT_VALIDN:
1827     case CTSF_ROWPCT_TOTALN:
1828     case CTSF_COLPCT_TOTALN:
1829     case CTSF_TABLEPCT_TOTALN:
1830     case CTSF_SUBTABLEPCT_TOTALN:
1831     case CTSF_LAYERPCT_TOTALN:
1832     case CTSF_LAYERROWPCT_TOTALN:
1833     case CTSF_LAYERCOLPCT_TOTALN:
1834     case CTSF_MISSING:
1835     case CSTF_TOTALN:
1836     case CTSF_ETOTALN:
1837     case CTSF_VALIDN:
1838     case CTSF_EVALIDN:
1839       break;
1840
1841     case CTSF_MAXIMUM:
1842     case CTSF_MINIMUM:
1843     case CTSF_RANGE:
1844       break;
1845
1846     case CTSF_MEAN:
1847     case CTSF_SEMEAN:
1848     case CTSF_STDDEV:
1849     case CTSF_SUM:
1850     case CTSF_VARIANCE:
1851     case CTSF_ROWPCT_SUM:
1852     case CTSF_COLPCT_SUM:
1853     case CTSF_TABLEPCT_SUM:
1854     case CTSF_SUBTABLEPCT_SUM:
1855     case CTSF_LAYERPCT_SUM:
1856     case CTSF_LAYERROWPCT_SUM:
1857     case CTSF_LAYERCOLPCT_SUM:
1858       moments1_destroy (s->moments);
1859       break;
1860
1861     case CTSF_MEDIAN:
1862     case CTSF_MODE:
1863     case CTSF_PTILE:
1864       casewriter_destroy (s->writer);
1865       break;
1866
1867     case CTSF_RESPONSES:
1868     case CTSF_ROWPCT_RESPONSES:
1869     case CTSF_COLPCT_RESPONSES:
1870     case CTSF_TABLEPCT_RESPONSES:
1871     case CTSF_SUBTABLEPCT_RESPONSES:
1872     case CTSF_LAYERPCT_RESPONSES:
1873     case CTSF_LAYERROWPCT_RESPONSES:
1874     case CTSF_LAYERCOLPCT_RESPONSES:
1875     case CTSF_ROWPCT_RESPONSES_COUNT:
1876     case CTSF_COLPCT_RESPONSES_COUNT:
1877     case CTSF_TABLEPCT_RESPONSES_COUNT:
1878     case CTSF_SUBTABLEPCT_RESPONSES_COUNT:
1879     case CTSF_LAYERPCT_RESPONSES_COUNT:
1880     case CTSF_LAYERROWPCT_RESPONSES_COUNT:
1881     case CTSF_LAYERCOLPCT_RESPONSES_COUNT:
1882     case CTSF_ROWPCT_COUNT_RESPONSES:
1883     case CTSF_COLPCT_COUNT_RESPONSES:
1884     case CTSF_TABLEPCT_COUNT_RESPONSES:
1885     case CTSF_SUBTABLEPCT_COUNT_RESPONSES:
1886     case CTSF_LAYERPCT_COUNT_RESPONSES:
1887     case CTSF_LAYERROWPCT_COUNT_RESPONSES:
1888     case CTSF_LAYERCOLPCT_COUNT_RESPONSES:
1889       NOT_REACHED ();
1890     }
1891 }
1892
1893 static void
1894 ctables_summary_add (union ctables_summary *s,
1895                      const struct ctables_summary_spec *ss,
1896                      const struct variable *var, const union value *value,
1897                      double d_weight, double e_weight)
1898 {
1899   switch (ss->function)
1900     {
1901     case CTSF_COUNT:
1902     case CSTF_TOTALN:
1903     case CTSF_VALIDN:
1904       if (var_is_value_missing (var, value))
1905         s->missing += d_weight;
1906       else
1907         s->valid += d_weight;
1908       break;
1909
1910     case CTSF_ECOUNT:
1911     case CTSF_ROWPCT_COUNT:
1912     case CTSF_COLPCT_COUNT:
1913     case CTSF_TABLEPCT_COUNT:
1914     case CTSF_SUBTABLEPCT_COUNT:
1915     case CTSF_LAYERPCT_COUNT:
1916     case CTSF_LAYERROWPCT_COUNT:
1917     case CTSF_LAYERCOLPCT_COUNT:
1918     case CTSF_ROWPCT_VALIDN:
1919     case CTSF_COLPCT_VALIDN:
1920     case CTSF_TABLEPCT_VALIDN:
1921     case CTSF_SUBTABLEPCT_VALIDN:
1922     case CTSF_LAYERPCT_VALIDN:
1923     case CTSF_LAYERROWPCT_VALIDN:
1924     case CTSF_LAYERCOLPCT_VALIDN:
1925     case CTSF_ROWPCT_TOTALN:
1926     case CTSF_COLPCT_TOTALN:
1927     case CTSF_TABLEPCT_TOTALN:
1928     case CTSF_SUBTABLEPCT_TOTALN:
1929     case CTSF_LAYERPCT_TOTALN:
1930     case CTSF_LAYERROWPCT_TOTALN:
1931     case CTSF_LAYERCOLPCT_TOTALN:
1932     case CTSF_MISSING:
1933     case CTSF_ETOTALN:
1934     case CTSF_EVALIDN:
1935       if (var_is_value_missing (var, value))
1936         s->missing += e_weight;
1937       else
1938         s->valid += e_weight;
1939       break;
1940
1941     case CTSF_MAXIMUM:
1942     case CTSF_MINIMUM:
1943     case CTSF_RANGE:
1944       if (!var_is_value_missing (var, value))
1945         {
1946           assert (!var_is_alpha (var)); /* XXX? */
1947           if (s->min == SYSMIS || value->f < s->min)
1948             s->min = value->f;
1949           if (s->max == SYSMIS || value->f > s->max)
1950             s->max = value->f;
1951         }
1952       break;
1953
1954     case CTSF_MEAN:
1955     case CTSF_SEMEAN:
1956     case CTSF_STDDEV:
1957     case CTSF_SUM:
1958     case CTSF_VARIANCE:
1959     case CTSF_ROWPCT_SUM:
1960     case CTSF_COLPCT_SUM:
1961     case CTSF_TABLEPCT_SUM:
1962     case CTSF_SUBTABLEPCT_SUM:
1963     case CTSF_LAYERPCT_SUM:
1964     case CTSF_LAYERROWPCT_SUM:
1965     case CTSF_LAYERCOLPCT_SUM:
1966       if (!var_is_value_missing (var, value))
1967         moments1_add (s->moments, value->f, e_weight);
1968       break;
1969
1970     case CTSF_MEDIAN:
1971     case CTSF_MODE:
1972     case CTSF_PTILE:
1973       if (var_is_value_missing (var, value))
1974         {
1975           s->ovalid += e_weight;
1976
1977           struct ccase *c = case_create (casewriter_get_proto (s->writer));
1978           *case_num_rw_idx (c, 0) = value->f;
1979           *case_num_rw_idx (c, 1) = e_weight;
1980           casewriter_write (s->writer, c);
1981         }
1982       break;
1983
1984     case CTSF_RESPONSES:
1985     case CTSF_ROWPCT_RESPONSES:
1986     case CTSF_COLPCT_RESPONSES:
1987     case CTSF_TABLEPCT_RESPONSES:
1988     case CTSF_SUBTABLEPCT_RESPONSES:
1989     case CTSF_LAYERPCT_RESPONSES:
1990     case CTSF_LAYERROWPCT_RESPONSES:
1991     case CTSF_LAYERCOLPCT_RESPONSES:
1992     case CTSF_ROWPCT_RESPONSES_COUNT:
1993     case CTSF_COLPCT_RESPONSES_COUNT:
1994     case CTSF_TABLEPCT_RESPONSES_COUNT:
1995     case CTSF_SUBTABLEPCT_RESPONSES_COUNT:
1996     case CTSF_LAYERPCT_RESPONSES_COUNT:
1997     case CTSF_LAYERROWPCT_RESPONSES_COUNT:
1998     case CTSF_LAYERCOLPCT_RESPONSES_COUNT:
1999     case CTSF_ROWPCT_COUNT_RESPONSES:
2000     case CTSF_COLPCT_COUNT_RESPONSES:
2001     case CTSF_TABLEPCT_COUNT_RESPONSES:
2002     case CTSF_SUBTABLEPCT_COUNT_RESPONSES:
2003     case CTSF_LAYERPCT_COUNT_RESPONSES:
2004     case CTSF_LAYERROWPCT_COUNT_RESPONSES:
2005     case CTSF_LAYERCOLPCT_COUNT_RESPONSES:
2006       NOT_REACHED ();
2007     }
2008 }
2009
2010 static enum ctables_domain_type
2011 ctables_function_domain (enum ctables_summary_function function)
2012 {
2013   switch (function)
2014     {
2015     case CTSF_COUNT:
2016     case CTSF_ECOUNT:
2017     case CTSF_MISSING:
2018     case CSTF_TOTALN:
2019     case CTSF_ETOTALN:
2020     case CTSF_VALIDN:
2021     case CTSF_EVALIDN:
2022     case CTSF_MAXIMUM:
2023     case CTSF_MINIMUM:
2024     case CTSF_RANGE:
2025     case CTSF_MEAN:
2026     case CTSF_SEMEAN:
2027     case CTSF_STDDEV:
2028     case CTSF_SUM:
2029     case CTSF_VARIANCE:
2030     case CTSF_MEDIAN:
2031     case CTSF_PTILE:
2032     case CTSF_MODE:
2033     case CTSF_RESPONSES:
2034       NOT_REACHED ();
2035
2036     case CTSF_COLPCT_COUNT:
2037     case CTSF_COLPCT_COUNT_RESPONSES:
2038     case CTSF_COLPCT_RESPONSES:
2039     case CTSF_COLPCT_RESPONSES_COUNT:
2040     case CTSF_COLPCT_SUM:
2041     case CTSF_COLPCT_TOTALN:
2042     case CTSF_COLPCT_VALIDN:
2043       return CTDT_COL;
2044
2045     case CTSF_LAYERCOLPCT_COUNT:
2046     case CTSF_LAYERCOLPCT_COUNT_RESPONSES:
2047     case CTSF_LAYERCOLPCT_RESPONSES:
2048     case CTSF_LAYERCOLPCT_RESPONSES_COUNT:
2049     case CTSF_LAYERCOLPCT_SUM:
2050     case CTSF_LAYERCOLPCT_TOTALN:
2051     case CTSF_LAYERCOLPCT_VALIDN:
2052       return CTDT_LAYERCOL;
2053
2054     case CTSF_LAYERPCT_COUNT:
2055     case CTSF_LAYERPCT_COUNT_RESPONSES:
2056     case CTSF_LAYERPCT_RESPONSES:
2057     case CTSF_LAYERPCT_RESPONSES_COUNT:
2058     case CTSF_LAYERPCT_SUM:
2059     case CTSF_LAYERPCT_TOTALN:
2060     case CTSF_LAYERPCT_VALIDN:
2061       return CTDT_LAYER;
2062
2063     case CTSF_LAYERROWPCT_COUNT:
2064     case CTSF_LAYERROWPCT_COUNT_RESPONSES:
2065     case CTSF_LAYERROWPCT_RESPONSES:
2066     case CTSF_LAYERROWPCT_RESPONSES_COUNT:
2067     case CTSF_LAYERROWPCT_SUM:
2068     case CTSF_LAYERROWPCT_TOTALN:
2069     case CTSF_LAYERROWPCT_VALIDN:
2070       return CTDT_LAYERROW;
2071
2072     case CTSF_ROWPCT_COUNT:
2073     case CTSF_ROWPCT_COUNT_RESPONSES:
2074     case CTSF_ROWPCT_RESPONSES:
2075     case CTSF_ROWPCT_RESPONSES_COUNT:
2076     case CTSF_ROWPCT_SUM:
2077     case CTSF_ROWPCT_TOTALN:
2078     case CTSF_ROWPCT_VALIDN:
2079       return CTDT_ROW;
2080
2081     case CTSF_SUBTABLEPCT_COUNT:
2082     case CTSF_SUBTABLEPCT_COUNT_RESPONSES:
2083     case CTSF_SUBTABLEPCT_RESPONSES:
2084     case CTSF_SUBTABLEPCT_RESPONSES_COUNT:
2085     case CTSF_SUBTABLEPCT_SUM:
2086     case CTSF_SUBTABLEPCT_TOTALN:
2087     case CTSF_SUBTABLEPCT_VALIDN:
2088       return CTDT_SUBTABLE;
2089
2090     case CTSF_TABLEPCT_COUNT:
2091     case CTSF_TABLEPCT_COUNT_RESPONSES:
2092     case CTSF_TABLEPCT_RESPONSES:
2093     case CTSF_TABLEPCT_RESPONSES_COUNT:
2094     case CTSF_TABLEPCT_SUM:
2095     case CTSF_TABLEPCT_TOTALN:
2096     case CTSF_TABLEPCT_VALIDN:
2097       return CTDT_TABLE;
2098     }
2099
2100   NOT_REACHED ();
2101 }
2102
2103 static double
2104 ctables_summary_value (const struct ctables_cell *cell,
2105                        union ctables_summary *s,
2106                        const struct ctables_summary_spec *ss)
2107 {
2108   switch (ss->function)
2109     {
2110     case CTSF_COUNT:
2111     case CTSF_ECOUNT:
2112       return s->valid;
2113
2114     case CTSF_ROWPCT_COUNT:
2115     case CTSF_COLPCT_COUNT:
2116     case CTSF_TABLEPCT_COUNT:
2117     case CTSF_SUBTABLEPCT_COUNT:
2118     case CTSF_LAYERPCT_COUNT:
2119     case CTSF_LAYERROWPCT_COUNT:
2120     case CTSF_LAYERCOLPCT_COUNT:
2121       {
2122         enum ctables_domain_type d = ctables_function_domain (ss->function);
2123         return (cell->domains[d]->e_valid
2124                 ? s->valid / cell->domains[d]->e_valid * 100
2125                 : SYSMIS);
2126       }
2127
2128     case CTSF_ROWPCT_VALIDN:
2129     case CTSF_COLPCT_VALIDN:
2130     case CTSF_TABLEPCT_VALIDN:
2131     case CTSF_SUBTABLEPCT_VALIDN:
2132     case CTSF_LAYERPCT_VALIDN:
2133     case CTSF_LAYERROWPCT_VALIDN:
2134     case CTSF_LAYERCOLPCT_VALIDN:
2135     case CTSF_ROWPCT_TOTALN:
2136     case CTSF_COLPCT_TOTALN:
2137     case CTSF_TABLEPCT_TOTALN:
2138     case CTSF_SUBTABLEPCT_TOTALN:
2139     case CTSF_LAYERPCT_TOTALN:
2140     case CTSF_LAYERROWPCT_TOTALN:
2141     case CTSF_LAYERCOLPCT_TOTALN:
2142       NOT_REACHED ();
2143
2144     case CTSF_MISSING:
2145       return s->missing;
2146
2147     case CSTF_TOTALN:
2148     case CTSF_ETOTALN:
2149       return s->valid + s->missing;
2150
2151     case CTSF_VALIDN:
2152     case CTSF_EVALIDN:
2153       return s->valid;
2154
2155     case CTSF_MAXIMUM:
2156       return s->max;
2157
2158     case CTSF_MINIMUM:
2159       return s->min;
2160
2161     case CTSF_RANGE:
2162       return s->max != SYSMIS && s->min != SYSMIS ? s->max - s->min : SYSMIS;
2163
2164     case CTSF_MEAN:
2165       {
2166         double mean;
2167         moments1_calculate (s->moments, NULL, &mean, NULL, NULL, NULL);
2168         return mean;
2169       }
2170
2171     case CTSF_SEMEAN:
2172       {
2173         double weight, variance;
2174         moments1_calculate (s->moments, &weight, NULL, &variance, NULL, NULL);
2175         return calc_semean (variance, weight);
2176       }
2177
2178     case CTSF_STDDEV:
2179       {
2180         double variance;
2181         moments1_calculate (s->moments, NULL, NULL, &variance, NULL, NULL);
2182         return variance != SYSMIS ? sqrt (variance) : SYSMIS;
2183       }
2184
2185     case CTSF_SUM:
2186       {
2187         double weight, mean;
2188         moments1_calculate (s->moments, &weight, &mean, NULL, NULL, NULL);
2189         return weight != SYSMIS && mean != SYSMIS ? weight * mean : SYSMIS;
2190       }
2191
2192     case CTSF_VARIANCE:
2193       {
2194         double variance;
2195         moments1_calculate (s->moments, NULL, NULL, &variance, NULL, NULL);
2196         return variance;
2197       }
2198
2199     case CTSF_ROWPCT_SUM:
2200     case CTSF_COLPCT_SUM:
2201     case CTSF_TABLEPCT_SUM:
2202     case CTSF_SUBTABLEPCT_SUM:
2203     case CTSF_LAYERPCT_SUM:
2204     case CTSF_LAYERROWPCT_SUM:
2205     case CTSF_LAYERCOLPCT_SUM:
2206       NOT_REACHED ();
2207
2208     case CTSF_MEDIAN:
2209     case CTSF_PTILE:
2210       if (s->writer)
2211         {
2212           struct casereader *reader = casewriter_make_reader (s->writer);
2213           s->writer = NULL;
2214
2215           struct percentile *ptile = percentile_create (
2216             ss->function == CTSF_PTILE ? ss->percentile : 0.5, s->ovalid);
2217           struct order_stats *os = &ptile->parent;
2218           order_stats_accumulate_idx (&os, 1, reader, 1, 0);
2219           s->ovalue = percentile_calculate (ptile, PC_HAVERAGE);
2220           statistic_destroy (&ptile->parent.parent);
2221         }
2222       return s->ovalue;
2223
2224     case CTSF_MODE:
2225       if (s->writer)
2226         {
2227           struct casereader *reader = casewriter_make_reader (s->writer);
2228           s->writer = NULL;
2229
2230           struct mode *mode = mode_create ();
2231           struct order_stats *os = &mode->parent;
2232           order_stats_accumulate_idx (&os, 1, reader, 1, 0);
2233           s->ovalue = mode->mode;
2234           statistic_destroy (&mode->parent.parent);
2235         }
2236       return s->ovalue;
2237
2238     case CTSF_RESPONSES:
2239     case CTSF_ROWPCT_RESPONSES:
2240     case CTSF_COLPCT_RESPONSES:
2241     case CTSF_TABLEPCT_RESPONSES:
2242     case CTSF_SUBTABLEPCT_RESPONSES:
2243     case CTSF_LAYERPCT_RESPONSES:
2244     case CTSF_LAYERROWPCT_RESPONSES:
2245     case CTSF_LAYERCOLPCT_RESPONSES:
2246     case CTSF_ROWPCT_RESPONSES_COUNT:
2247     case CTSF_COLPCT_RESPONSES_COUNT:
2248     case CTSF_TABLEPCT_RESPONSES_COUNT:
2249     case CTSF_SUBTABLEPCT_RESPONSES_COUNT:
2250     case CTSF_LAYERPCT_RESPONSES_COUNT:
2251     case CTSF_LAYERROWPCT_RESPONSES_COUNT:
2252     case CTSF_LAYERCOLPCT_RESPONSES_COUNT:
2253     case CTSF_ROWPCT_COUNT_RESPONSES:
2254     case CTSF_COLPCT_COUNT_RESPONSES:
2255     case CTSF_TABLEPCT_COUNT_RESPONSES:
2256     case CTSF_SUBTABLEPCT_COUNT_RESPONSES:
2257     case CTSF_LAYERPCT_COUNT_RESPONSES:
2258     case CTSF_LAYERROWPCT_COUNT_RESPONSES:
2259     case CTSF_LAYERCOLPCT_COUNT_RESPONSES:
2260       NOT_REACHED ();
2261     }
2262
2263   NOT_REACHED ();
2264 }
2265
2266 struct ctables_cell_sort_aux
2267   {
2268     const struct ctables_table *t;
2269     enum pivot_axis_type a;
2270   };
2271
2272 static int
2273 ctables_cell_compare_3way (const void *a_, const void *b_, const void *aux_)
2274 {
2275   const struct ctables_cell_sort_aux *aux = aux_;
2276   struct ctables_cell *const *ap = a_;
2277   struct ctables_cell *const *bp = b_;
2278   const struct ctables_cell *a = *ap;
2279   const struct ctables_cell *b = *bp;
2280
2281   size_t a_idx = a->axes[aux->a].nest_idx;
2282   size_t b_idx = b->axes[aux->a].nest_idx;
2283   if (a_idx != b_idx)
2284     return a_idx < b_idx ? -1 : 1;
2285
2286   const struct ctables_nest *nest = &aux->t->stacks[aux->a].nests[a_idx];
2287   for (size_t i = 0; i < nest->n; i++)
2288     if (i != nest->scale_idx)
2289       {
2290         const struct variable *var = nest->vars[i];
2291         const struct ctables_cell_value *a_cv = &a->axes[aux->a].cvs[i];
2292         const struct ctables_cell_value *b_cv = &b->axes[aux->a].cvs[i];
2293         if (a_cv->category != b_cv->category)
2294           return a_cv->category > b_cv->category ? 1 : -1;
2295
2296         const union value *a_val = &a_cv->value;
2297         const union value *b_val = &b_cv->value;
2298         switch (a_cv->category->type)
2299           {
2300           case CCT_NUMBER:
2301           case CCT_STRING:
2302           case CCT_SUBTOTAL:
2303           case CCT_HSUBTOTAL:
2304           case CCT_TOTAL:
2305             /* Must be equal. */
2306             continue;
2307
2308           case CCT_RANGE:
2309           case CCT_MISSING:
2310           case CCT_OTHERNM:
2311             {
2312               int cmp = value_compare_3way (a_val, b_val, var_get_width (var));
2313               if (cmp)
2314                 return cmp;
2315             }
2316             break;
2317
2318           case CCT_VALUE:
2319             {
2320               int cmp = value_compare_3way (a_val, b_val, var_get_width (var));
2321               if (cmp)
2322                 return a_cv->category->sort_ascending ? cmp : -cmp;
2323             }
2324             break;
2325
2326           case CCT_LABEL:
2327             {
2328               const char *a_label = var_lookup_value_label (var, a_val);
2329               const char *b_label = var_lookup_value_label (var, b_val);
2330               int cmp = (a_label
2331                          ? (b_label ? strcmp (a_label, b_label) : 1)
2332                          : (b_label ? -1 : value_compare_3way (
2333                               a_val, b_val, var_get_width (var))));
2334               if (cmp)
2335                 return a_cv->category->sort_ascending ? cmp : -cmp;
2336             }
2337             break;
2338
2339           case CCT_FUNCTION:
2340             NOT_REACHED ();
2341           }
2342       }
2343   return 0;
2344 }
2345
2346 /* Algorithm:
2347
2348    For each row:
2349        For each ctables_table:
2350            For each combination of row vars:
2351                For each combination of column vars:
2352                    For each combination of layer vars:
2353                        Add entry
2354    Make a table of row values:
2355        Sort entries by row values
2356        Assign a 0-based index to each actual value
2357        Construct a dimension
2358    Make a table of column values
2359    Make a table of layer values
2360    For each entry:
2361        Fill the table entry using the indexes from before.
2362  */
2363
2364 static struct ctables_domain *
2365 ctables_domain_insert (struct ctables_table *t, struct ctables_cell *cell,
2366                        enum ctables_domain_type domain)
2367 {
2368   size_t hash = 0;
2369   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2370     {
2371       size_t idx = cell->axes[a].nest_idx;
2372       const struct ctables_nest *nest = &t->stacks[a].nests[idx];
2373       hash = hash_int (idx, hash);
2374       for (size_t i = 0; i < nest->n_domains[domain]; i++)
2375         {
2376           size_t v_idx = nest->domains[domain][i];
2377           hash = value_hash (&cell->axes[a].cvs[v_idx].value,
2378                              var_get_width (nest->vars[v_idx]), hash);
2379         }
2380     }
2381
2382   struct ctables_domain *d;
2383   HMAP_FOR_EACH_WITH_HASH (d, struct ctables_domain, node, hash, &t->domains[domain])
2384     {
2385       const struct ctables_cell *df = d->example;
2386       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2387         {
2388           size_t idx = cell->axes[a].nest_idx;
2389           if (idx != df->axes[a].nest_idx)
2390             goto not_equal;
2391
2392           const struct ctables_nest *nest = &t->stacks[a].nests[idx];
2393           for (size_t i = 0; i < nest->n_domains[domain]; i++)
2394             {
2395               size_t v_idx = nest->domains[domain][i];
2396               if (!value_equal (&df->axes[a].cvs[v_idx].value,
2397                                 &cell->axes[a].cvs[v_idx].value,
2398                                 var_get_width (nest->vars[v_idx])))
2399                 goto not_equal;
2400             }
2401         }
2402       return d;
2403
2404     not_equal: ;
2405     }
2406
2407   d = xmalloc (sizeof *d);
2408   *d = (struct ctables_domain) { .example = cell };
2409   hmap_insert (&t->domains[domain], &d->node, hash);
2410   return d;
2411 }
2412
2413 static const struct ctables_category *
2414 ctables_categories_match (const struct ctables_categories *c,
2415                           const union value *v, const struct variable *var)
2416 {
2417   const struct ctables_category *othernm = NULL;
2418   for (size_t i = c->n_cats; i-- > 0; )
2419     {
2420       const struct ctables_category *cat = &c->cats[i];
2421       switch (cat->type)
2422         {
2423         case CCT_NUMBER:
2424           if (cat->number == v->f)
2425             return cat;
2426           break;
2427
2428         case CCT_STRING:
2429           NOT_REACHED ();
2430
2431         case CCT_RANGE:
2432           if ((cat->range[0] == -DBL_MAX || v->f >= cat->range[0])
2433               && (cat->range[1] == DBL_MAX || v->f <= cat->range[1]))
2434             return cat;
2435           break;
2436
2437         case CCT_MISSING:
2438           if (var_is_value_missing (var, v))
2439             return cat;
2440           break;
2441
2442         case CCT_OTHERNM:
2443           if (!othernm)
2444             othernm = cat;
2445           break;
2446
2447         case CCT_SUBTOTAL:
2448         case CCT_HSUBTOTAL:
2449         case CCT_TOTAL:
2450           break;
2451
2452         case CCT_VALUE:
2453         case CCT_LABEL:
2454         case CCT_FUNCTION:
2455           return (cat->include_missing || !var_is_value_missing (var, v) ? cat
2456                   : NULL);
2457         }
2458     }
2459
2460   return var_is_value_missing (var, v) ? NULL : othernm;
2461 }
2462
2463 static const struct ctables_category *
2464 ctables_categories_total (const struct ctables_categories *c)
2465 {
2466   const struct ctables_category *first = &c->cats[0];
2467   const struct ctables_category *last = &c->cats[c->n_cats - 1];
2468   return (first->type == CCT_TOTAL ? first
2469           : last->type == CCT_TOTAL ? last
2470           : NULL);
2471 }
2472
2473 static struct ctables_cell *
2474 ctables_cell_insert__ (struct ctables_table *t, const struct ccase *c,
2475                        size_t ix[PIVOT_N_AXES],
2476                        const struct ctables_category *cats[PIVOT_N_AXES][10])
2477 {
2478   const struct ctables_nest *ss = &t->stacks[t->summary_axis].nests[ix[t->summary_axis]];
2479
2480   size_t hash = 0;
2481   enum ctables_summary_variant sv = CSV_CELL;
2482   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2483     {
2484       const struct ctables_nest *nest = &t->stacks[a].nests[ix[a]];
2485       hash = hash_int (ix[a], hash);
2486       for (size_t i = 0; i < nest->n; i++)
2487         if (i != nest->scale_idx)
2488           {
2489             hash = hash_pointer (cats[a][i], hash);
2490             if (cats[a][i]->type != CCT_TOTAL
2491                 && cats[a][i]->type != CCT_SUBTOTAL
2492                 && cats[a][i]->type != CCT_HSUBTOTAL)
2493               hash = value_hash (case_data (c, nest->vars[i]),
2494                                  var_get_width (nest->vars[i]), hash);
2495             else
2496               sv = CSV_TOTAL;
2497           }
2498     }
2499
2500   struct ctables_cell *cell;
2501   HMAP_FOR_EACH_WITH_HASH (cell, struct ctables_cell, node, hash, &t->cells)
2502     {
2503       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2504         {
2505           const struct ctables_nest *nest = &t->stacks[a].nests[ix[a]];
2506           if (cell->axes[a].nest_idx != ix[a])
2507             goto not_equal;
2508           for (size_t i = 0; i < nest->n; i++)
2509             if (i != nest->scale_idx
2510                 && (cats[a][i] != cell->axes[a].cvs[i].category
2511                     || (cats[a][i]->type != CCT_TOTAL
2512                         && cats[a][i]->type != CCT_SUBTOTAL
2513                         && cats[a][i]->type != CCT_HSUBTOTAL
2514                         && !value_equal (case_data (c, nest->vars[i]),
2515                                          &cell->axes[a].cvs[i].value,
2516                                          var_get_width (nest->vars[i])))))
2517                 goto not_equal;
2518         }
2519
2520       return cell;
2521
2522     not_equal: ;
2523     }
2524
2525   cell = xmalloc (sizeof *cell);
2526   cell->hide = false;
2527   cell->sv = sv;
2528   cell->contributes_to_domains = true;
2529   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2530     {
2531       const struct ctables_nest *nest = &t->stacks[a].nests[ix[a]];
2532       cell->axes[a].nest_idx = ix[a];
2533       cell->axes[a].cvs = (nest->n
2534                         ? xnmalloc (nest->n, sizeof *cell->axes[a].cvs)
2535                         : NULL);
2536       for (size_t i = 0; i < nest->n; i++)
2537         {
2538           const struct ctables_category *cat = cats[a][i];
2539
2540           if (i != nest->scale_idx)
2541             {
2542               const struct ctables_category *subtotal = cat->subtotal;
2543               if (subtotal && subtotal->type == CCT_HSUBTOTAL)
2544                 cell->hide = true;
2545
2546               if (cat->type == CCT_TOTAL || cat->type == CCT_SUBTOTAL || cat->type == CCT_HSUBTOTAL)
2547                 cell->contributes_to_domains = false;
2548             }
2549
2550           cell->axes[a].cvs[i].category = cat;
2551           value_clone (&cell->axes[a].cvs[i].value, case_data (c, nest->vars[i]),
2552                        var_get_width (nest->vars[i]));
2553         }
2554     }
2555
2556   const struct ctables_summary_spec_set *specs = &ss->specs[cell->sv];
2557   cell->summaries = xmalloc (specs->n * sizeof *cell->summaries);
2558   for (size_t i = 0; i < specs->n; i++)
2559     ctables_summary_init (&cell->summaries[i], &specs->specs[i]);
2560   for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
2561     cell->domains[dt] = ctables_domain_insert (t, cell, dt);
2562   hmap_insert (&t->cells, &cell->node, hash);
2563   return cell;
2564 }
2565
2566 static void
2567 ctables_cell_add__ (struct ctables_table *t, const struct ccase *c,
2568                     size_t ix[PIVOT_N_AXES],
2569                     const struct ctables_category *cats[PIVOT_N_AXES][10],
2570                     double d_weight, double e_weight)
2571 {
2572   struct ctables_cell *cell = ctables_cell_insert__ (t, c, ix, cats);
2573   const struct ctables_nest *ss = &t->stacks[t->summary_axis].nests[ix[t->summary_axis]];
2574
2575   const struct ctables_summary_spec_set *specs = &ss->specs[cell->sv];
2576   for (size_t i = 0; i < specs->n; i++)
2577     ctables_summary_add (&cell->summaries[i], &specs->specs[i], specs->var,
2578                          case_data (c, specs->var), d_weight, e_weight);
2579   if (cell->contributes_to_domains)
2580     {
2581       for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
2582         {
2583           cell->domains[dt]->d_valid += d_weight;
2584           cell->domains[dt]->e_valid += e_weight;
2585         }
2586     }
2587 }
2588
2589 static void
2590 recurse_totals (struct ctables_table *t, const struct ccase *c,
2591                 size_t ix[PIVOT_N_AXES],
2592                 const struct ctables_category *cats[PIVOT_N_AXES][10],
2593                 double d_weight, double e_weight,
2594                 enum pivot_axis_type start_axis, size_t start_nest)
2595 {
2596   for (enum pivot_axis_type a = start_axis; a < PIVOT_N_AXES; a++)
2597     {
2598       const struct ctables_nest *nest = &t->stacks[a].nests[ix[a]];
2599       for (size_t i = start_nest; i < nest->n; i++)
2600         {
2601           if (i == nest->scale_idx)
2602             continue;
2603
2604           const struct variable *var = nest->vars[i];
2605
2606           const struct ctables_category *total = ctables_categories_total (
2607             t->categories[var_get_dict_index (var)]);
2608           if (total)
2609             {
2610               const struct ctables_category *save = cats[a][i];
2611               cats[a][i] = total;
2612               ctables_cell_add__ (t, c, ix, cats, d_weight, e_weight);
2613               recurse_totals (t, c, ix, cats, d_weight, e_weight, a, i + 1);
2614               cats[a][i] = save;
2615             }
2616         }
2617       start_nest = 0;
2618     }
2619 }
2620
2621 static void
2622 recurse_subtotals (struct ctables_table *t, const struct ccase *c,
2623                    size_t ix[PIVOT_N_AXES],
2624                    const struct ctables_category *cats[PIVOT_N_AXES][10],
2625                    double d_weight, double e_weight,
2626                    enum pivot_axis_type start_axis, size_t start_nest)
2627 {
2628   for (enum pivot_axis_type a = start_axis; a < PIVOT_N_AXES; a++)
2629     {
2630       const struct ctables_nest *nest = &t->stacks[a].nests[ix[a]];
2631       for (size_t i = start_nest; i < nest->n; i++)
2632         {
2633           if (i == nest->scale_idx)
2634             continue;
2635
2636           const struct ctables_category *save = cats[a][i];
2637           if (save->subtotal)
2638             {
2639               cats[a][i] = save->subtotal;
2640               ctables_cell_add__ (t, c, ix, cats, d_weight, e_weight);
2641               recurse_subtotals (t, c, ix, cats, d_weight, e_weight, a, i + 1);
2642               cats[a][i] = save;
2643             }
2644         }
2645       start_nest = 0;
2646     }
2647 }
2648
2649 static void
2650 ctables_cell_insert (struct ctables_table *t,
2651                      const struct ccase *c,
2652                      size_t ir, size_t ic, size_t il,
2653                      double d_weight, double e_weight)
2654 {
2655   size_t ix[PIVOT_N_AXES] = {
2656     [PIVOT_AXIS_ROW] = ir,
2657     [PIVOT_AXIS_COLUMN] = ic,
2658     [PIVOT_AXIS_LAYER] = il,
2659   };
2660
2661   const struct ctables_category *cats[PIVOT_N_AXES][10];
2662   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2663     {
2664       const struct ctables_nest *nest = &t->stacks[a].nests[ix[a]];
2665       for (size_t i = 0; i < nest->n; i++)
2666         {
2667           if (i == nest->scale_idx)
2668             continue;
2669
2670           const struct variable *var = nest->vars[i];
2671           const union value *value = case_data (c, var);
2672
2673           if (var_is_numeric (var) && value->f == SYSMIS)
2674             return;
2675
2676           cats[a][i] = ctables_categories_match (
2677             t->categories[var_get_dict_index (var)], value, var);
2678           if (!cats[a][i])
2679             return;
2680         }
2681     }
2682
2683   ctables_cell_add__ (t, c, ix, cats, d_weight, e_weight);
2684
2685   recurse_totals (t, c, ix, cats, d_weight, e_weight, 0, 0);
2686   recurse_subtotals (t, c, ix, cats, d_weight, e_weight, 0, 0);
2687 }
2688
2689 struct merge_item
2690   {
2691     const struct ctables_summary_spec_set *set;
2692     size_t ofs;
2693   };
2694
2695 static int
2696 merge_item_compare_3way (const struct merge_item *a, const struct merge_item *b)
2697 {
2698   const struct ctables_summary_spec *as = &a->set->specs[a->ofs];
2699   const struct ctables_summary_spec *bs = &b->set->specs[b->ofs];
2700   if (as->function != bs->function)
2701     return as->function > bs->function ? 1 : -1;
2702   else if (as->percentile != bs->percentile)
2703     return as->percentile < bs->percentile ? 1 : -1;
2704   return strcmp (as->label, bs->label);
2705 }
2706
2707 static struct pivot_value *
2708 ctables_category_create_label (const struct ctables_category *cat,
2709                                const struct variable *var,
2710                                const union value *value)
2711 {
2712   return (cat->type == CCT_TOTAL || cat->type == CCT_SUBTOTAL || cat->type == CCT_HSUBTOTAL
2713           ? pivot_value_new_user_text (cat->total_label, SIZE_MAX)
2714           : pivot_value_new_var_value (var, value));
2715 }
2716
2717 static struct ctables_value *
2718 ctables_value_find__ (struct ctables_table *t, const union value *value,
2719                       int width, unsigned int hash)
2720 {
2721   struct ctables_value *clv;
2722   HMAP_FOR_EACH_WITH_HASH (clv, struct ctables_value, node,
2723                            hash, &t->clabels_values_map)
2724     if (value_equal (value, &clv->value, width))
2725       return clv;
2726   return NULL;
2727 }
2728
2729 static struct ctables_value *
2730 ctables_value_find (struct ctables_table *t,
2731                     const union value *value, int width)
2732 {
2733   return ctables_value_find__ (t, value, width,
2734                                value_hash (value, width, 0));
2735 }
2736
2737 static void
2738 ctables_table_output (struct ctables *ct, struct ctables_table *t)
2739 {
2740   struct pivot_table *pt = pivot_table_create__ (
2741     (t->title
2742      ? pivot_value_new_user_text (t->title, SIZE_MAX)
2743      : pivot_value_new_text (N_("Custom Tables"))),
2744     "Custom Tables");
2745   if (t->caption)
2746     pivot_table_set_caption (
2747       pt, pivot_value_new_user_text (t->caption, SIZE_MAX));
2748   if (t->corner)
2749     pivot_table_set_caption (
2750       pt, pivot_value_new_user_text (t->corner, SIZE_MAX));
2751
2752   bool summary_dimension = (t->summary_axis != t->slabels_axis
2753                             || (!t->slabels_visible
2754                                 && t->summary_specs.n > 1));
2755   if (summary_dimension)
2756     {
2757       struct pivot_dimension *d = pivot_dimension_create (
2758         pt, t->slabels_axis, N_("Statistics"));
2759       const struct ctables_summary_spec_set *specs = &t->summary_specs;
2760       if (!t->slabels_visible)
2761         d->hide_all_labels = true;
2762       for (size_t i = 0; i < specs->n; i++)
2763         pivot_category_create_leaf (
2764           d->root, pivot_value_new_text (specs->specs[i].label));
2765     }
2766
2767   bool categories_dimension = t->clabels_example != NULL;
2768   if (categories_dimension)
2769     {
2770       struct pivot_dimension *d = pivot_dimension_create (
2771         pt, t->label_axis[t->clabels_from_axis],
2772         t->clabels_from_axis == PIVOT_AXIS_ROW
2773         ? N_("Row Categories")
2774         : N_("Column Categories"));
2775       const struct variable *var = t->clabels_example;
2776       const struct ctables_categories *c = t->categories[var_get_dict_index (var)];
2777       for (size_t i = 0; i < t->n_clabels_values; i++)
2778         {
2779           const struct ctables_value *value = t->clabels_values[i];
2780           const struct ctables_category *cat = ctables_categories_match (c, &value->value, var);
2781           assert (cat != NULL);
2782           pivot_category_create_leaf (d->root, ctables_category_create_label (
2783                                         cat, t->clabels_example, &value->value));
2784         }
2785     }
2786
2787   pivot_table_set_look (pt, ct->look);
2788   struct pivot_dimension *d[PIVOT_N_AXES];
2789   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2790     {
2791       static const char *names[] = {
2792         [PIVOT_AXIS_ROW] = N_("Rows"),
2793         [PIVOT_AXIS_COLUMN] = N_("Columns"),
2794         [PIVOT_AXIS_LAYER] = N_("Layers"),
2795       };
2796       d[a] = (t->axes[a] || a == t->summary_axis
2797               ? pivot_dimension_create (pt, a, names[a])
2798               : NULL);
2799       if (!d[a])
2800         continue;
2801
2802       assert (t->axes[a]);
2803
2804       struct ctables_cell **sorted = xnmalloc (t->cells.count, sizeof *sorted);
2805       size_t n_sorted = 0;
2806
2807       struct ctables_cell *cell;
2808       HMAP_FOR_EACH (cell, struct ctables_cell, node, &t->cells)
2809         if (!cell->hide)
2810           sorted[n_sorted++] = cell;
2811       assert (n_sorted <= t->cells.count);
2812
2813       struct ctables_cell_sort_aux aux = { .t = t, .a = a };
2814       sort (sorted, n_sorted, sizeof *sorted, ctables_cell_compare_3way, &aux);
2815
2816       size_t max_depth = 0;
2817       for (size_t j = 0; j < t->stacks[a].n; j++)
2818         if (t->stacks[a].nests[j].n > max_depth)
2819           max_depth = t->stacks[a].nests[j].n;
2820
2821       /* Pivot categories:
2822
2823          - variable label for nest->vars[0], if vlabel != CTVL_NONE
2824          - category for nest->vars[0], if nest->scale_idx != 0
2825          - variable label for nest->vars[1], if vlabel != CTVL_NONE
2826          - category for nest->vars[1], if nest->scale_idx != 1
2827          ...
2828          - variable label for nest->vars[n - 1], if vlabel != CTVL_NONE
2829          - category for nest->vars[n - 1], if t->label_axis[a] == a && nest->scale_idx != n - 1.
2830          - summary function, if 'a == t->slabels_axis && a ==
2831          t->summary_axis'.
2832
2833          Additional dimensions:
2834
2835          - If 'a == t->slabels_axis && a != t->summary_axis', add a summary
2836          dimension.
2837          - If 't->label_axis[b] == a' for some 'b != a', add a category
2838          dimension to 'a'.
2839       */
2840
2841       struct ctables_level
2842         {
2843           enum ctables_level_type
2844             {
2845               CTL_VAR,          /* Variable label for nest->vars[var_idx]. */
2846               CTL_CATEGORY,     /* Category for nest->vars[var_idx]. */
2847               CTL_SUMMARY,      /* Summary functions. */
2848             }
2849           type;
2850
2851           size_t var_idx;
2852         };
2853       struct ctables_level *levels = xnmalloc (1 + 2 * max_depth, sizeof *levels);
2854       size_t n_levels = 0;
2855
2856       struct pivot_category **groups = xnmalloc (1 + 2 * max_depth, sizeof *groups);
2857       int prev_leaf = 0;
2858       for (size_t j = 0; j < n_sorted; j++)
2859         {
2860           struct ctables_cell *cell = sorted[j];
2861           struct ctables_cell *prev = j > 0 ? sorted[j - 1] : NULL;
2862           const struct ctables_nest *nest = &t->stacks[a].nests[cell->axes[a].nest_idx];
2863
2864           bool new_subtable = !prev || prev->axes[a].nest_idx != cell->axes[a].nest_idx;
2865           if (new_subtable)
2866             {
2867               n_levels = 0;
2868               for (size_t k = 0; k < nest->n; k++)
2869                 {
2870                   enum ctables_vlabel vlabel = ct->vlabels[var_get_dict_index (nest->vars[k])];
2871                   if (vlabel != CTVL_NONE)
2872                     {
2873                       levels[n_levels++] = (struct ctables_level) {
2874                         .type = CTL_VAR,
2875                         .var_idx = k,
2876                       };
2877                     }
2878
2879                   if (nest->scale_idx != k
2880                       && (k != nest->n - 1 || t->label_axis[a] == a))
2881                     {
2882                       levels[n_levels++] = (struct ctables_level) {
2883                         .type = CTL_CATEGORY,
2884                         .var_idx = k,
2885                       };
2886                     }
2887                 }
2888
2889               if (!summary_dimension && a == t->slabels_axis)
2890                 {
2891                   levels[n_levels++] = (struct ctables_level) {
2892                     .type = CTL_SUMMARY,
2893                     .var_idx = SIZE_MAX,
2894                   };
2895                 }
2896             }
2897
2898           size_t n_common = 0;
2899           if (!new_subtable)
2900             {
2901               for (; n_common < n_levels; n_common++)
2902                 {
2903                   const struct ctables_level *level = &levels[n_common];
2904                   if (level->type == CTL_CATEGORY)
2905                     {
2906                       size_t var_idx = level->var_idx;
2907                       const struct ctables_category *c = cell->axes[a].cvs[var_idx].category;
2908                       if (prev->axes[a].cvs[var_idx].category != c)
2909                         break;
2910                       else if (c->type != CCT_SUBTOTAL
2911                                && c->type != CCT_HSUBTOTAL
2912                                && c->type != CCT_TOTAL
2913                                && !value_equal (&prev->axes[a].cvs[var_idx].value,
2914                                                 &cell->axes[a].cvs[var_idx].value,
2915                                                 var_get_type (nest->vars[var_idx])))
2916                         break;
2917                     }
2918                 }
2919             }
2920
2921           for (size_t k = n_common; k < n_levels; k++)
2922             {
2923               const struct ctables_level *level = &levels[k];
2924               struct pivot_category *parent = k ? groups[k - 1] : d[a]->root;
2925               if (level->type == CTL_SUMMARY)
2926                 {
2927                   const struct ctables_summary_spec_set *specs = &t->summary_specs;
2928                   for (size_t m = 0; m < specs->n; m++)
2929                     {
2930                       int leaf = pivot_category_create_leaf (
2931                         parent, pivot_value_new_text (specs->specs[m].label));
2932                       if (!m)
2933                         prev_leaf = leaf;
2934                     }
2935                 }
2936               else
2937                 {
2938                   const struct variable *var = nest->vars[level->var_idx];
2939                   struct pivot_value *label;
2940                   if (level->type == CTL_VAR)
2941                     label = pivot_value_new_variable (var);
2942                   else if (level->type == CTL_CATEGORY)
2943                     {
2944                       const struct ctables_cell_value *cv = &cell->axes[a].cvs[level->var_idx];
2945                       label = ctables_category_create_label (cv->category,
2946                                                              var, &cv->value);
2947                     }
2948                   else
2949                     NOT_REACHED ();
2950
2951                   if (k == n_levels - 1)
2952                     prev_leaf = pivot_category_create_leaf (parent, label);
2953                   else
2954                     groups[k] = pivot_category_create_group__ (parent, label);
2955                 }
2956             }
2957
2958           cell->axes[a].leaf = prev_leaf;
2959         }
2960       free (sorted);
2961       free (groups);
2962     }
2963
2964   struct ctables_cell *cell;
2965   HMAP_FOR_EACH (cell, struct ctables_cell, node, &t->cells)
2966     {
2967       if (cell->hide)
2968         continue;
2969
2970       const struct ctables_nest *specs_nest = &t->stacks[t->summary_axis].nests[cell->axes[t->summary_axis].nest_idx];
2971       const struct ctables_summary_spec_set *specs = &specs_nest->specs[cell->sv];
2972       for (size_t j = 0; j < specs->n; j++)
2973         {
2974           size_t dindexes[5];
2975           size_t n_dindexes = 0;
2976
2977           if (summary_dimension)
2978             dindexes[n_dindexes++] = specs->specs[j].axis_idx;
2979
2980           if (categories_dimension)
2981             {
2982               const struct ctables_nest *clabels_nest = &t->stacks[t->clabels_from_axis].nests[cell->axes[t->clabels_from_axis].nest_idx];
2983               const struct variable *var = clabels_nest->vars[clabels_nest->n - 1];
2984               const union value *value = &cell->axes[t->clabels_from_axis].cvs[clabels_nest->n - 1].value;
2985               const struct ctables_value *ctv = ctables_value_find (t, value, var_get_width (var));
2986               assert (ctv != NULL);
2987               dindexes[n_dindexes++] = ctv->leaf;
2988             }
2989
2990           for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2991             if (d[a])
2992               {
2993                 int leaf = cell->axes[a].leaf;
2994                 if (a == t->summary_axis && !summary_dimension)
2995                   leaf += j;
2996                 dindexes[n_dindexes++] = leaf;
2997               }
2998
2999           double d = ctables_summary_value (cell, &cell->summaries[j], &specs->specs[j]);
3000           struct pivot_value *value = pivot_value_new_number (d);
3001           value->numeric.format = specs->specs[j].format;
3002           pivot_table_put (pt, dindexes, n_dindexes, value);
3003         }
3004     }
3005
3006   pivot_table_submit (pt);
3007 }
3008
3009 static bool
3010 ctables_check_label_position (struct ctables_table *t, enum pivot_axis_type a)
3011 {
3012   enum pivot_axis_type label_pos = t->label_axis[a];
3013   if (label_pos == a)
3014     return true;
3015
3016   t->clabels_from_axis = a;
3017
3018   const char *subcommand_name = a == PIVOT_AXIS_ROW ? "ROWLABELS" : "COLLABELS";
3019   const char *pos_name = label_pos == PIVOT_AXIS_LAYER ? "LAYER" : "OPPOSITE";
3020
3021   const struct ctables_stack *stack = &t->stacks[a];
3022   if (!stack->n)
3023     return true;
3024
3025   const struct ctables_nest *n0 = &stack->nests[0];
3026   assert (n0->n > 0);
3027   const struct variable *v0 = n0->vars[n0->n - 1];
3028   struct ctables_categories *c0 = t->categories[var_get_dict_index (v0)];
3029   t->clabels_example = v0;
3030
3031   for (size_t i = 0; i < c0->n_cats; i++)
3032     if (c0->cats[i].type == CCT_FUNCTION)
3033       {
3034         msg (SE, _("%s=%s is not allowed with sorting based "
3035                    "on a summary function."),
3036              subcommand_name, pos_name);
3037         return false;
3038       }
3039   if (n0->n - 1 == n0->scale_idx)
3040     {
3041       msg (SE, _("%s=%s requires the variables to be moved to be categorical, "
3042                  "but %s is a scale variable."),
3043            subcommand_name, pos_name, var_get_name (v0));
3044       return false;
3045     }
3046
3047   for (size_t i = 1; i < stack->n; i++)
3048     {
3049       const struct ctables_nest *ni = &stack->nests[i];
3050       assert (ni->n > 0);
3051       const struct variable *vi = ni->vars[ni->n - 1];
3052       struct ctables_categories *ci = t->categories[var_get_dict_index (vi)];
3053
3054       if (ni->n - 1 == ni->scale_idx)
3055         {
3056           msg (SE, _("%s=%s requires the variables to be moved to be "
3057                      "categorical, but %s is a scale variable."),
3058                subcommand_name, pos_name, var_get_name (vi));
3059           return false;
3060         }
3061       if (var_get_width (v0) != var_get_width (vi))
3062         {
3063           msg (SE, _("%s=%s requires the variables to be "
3064                      "moved to have the same width, but %s has "
3065                      "width %d and %s has width %d."),
3066                subcommand_name, pos_name,
3067                var_get_name (v0), var_get_width (v0),
3068                var_get_name (vi), var_get_width (vi));
3069           return false;
3070         }
3071       if (!val_labs_equal (var_get_value_labels (v0),
3072                            var_get_value_labels (vi)))
3073         {
3074           msg (SE, _("%s=%s requires the variables to be "
3075                      "moved to have the same value labels, but %s "
3076                      "and %s have different value labels."),
3077                subcommand_name, pos_name,
3078                var_get_name (v0), var_get_name (vi));
3079           return false;
3080         }
3081       if (!ctables_categories_equal (c0, ci))
3082         {
3083           msg (SE, _("%s=%s requires the variables to be "
3084                      "moved to have the same category "
3085                      "specifications, but %s and %s have different "
3086                      "category specifications."),
3087                subcommand_name, pos_name,
3088                var_get_name (v0), var_get_name (vi));
3089           return false;
3090         }
3091     }
3092
3093   return true;
3094 }
3095
3096 static bool
3097 ctables_prepare_table (struct ctables_table *t)
3098 {
3099   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3100     if (t->axes[a])
3101       {
3102         t->stacks[a] = enumerate_fts (a, t->axes[a]);
3103
3104         for (size_t j = 0; j < t->stacks[a].n; j++)
3105           {
3106             struct ctables_nest *nest = &t->stacks[a].nests[j];
3107             for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
3108               {
3109                 nest->domains[dt] = xmalloc (nest->n * sizeof *nest->domains[dt]);
3110                 nest->n_domains[dt] = 0;
3111
3112                 for (size_t k = 0; k < nest->n; k++)
3113                   {
3114                     if (k == nest->scale_idx)
3115                       continue;
3116
3117                     switch (dt)
3118                       {
3119                       case CTDT_TABLE:
3120                         continue;
3121
3122                       case CTDT_LAYER:
3123                         if (a != PIVOT_AXIS_LAYER)
3124                           continue;
3125                         break;
3126
3127                       case CTDT_SUBTABLE:
3128                       case CTDT_ROW:
3129                       case CTDT_COL:
3130                         if (dt == CTDT_SUBTABLE ? a != PIVOT_AXIS_LAYER
3131                             : dt == CTDT_ROW ? a == PIVOT_AXIS_COLUMN
3132                             : a == PIVOT_AXIS_ROW)
3133                           {
3134                             if (k == nest->n - 1
3135                                 || (nest->scale_idx == nest->n - 1
3136                                     && k == nest->n - 2))
3137                               continue;
3138                           }
3139                         break;
3140
3141                       case CTDT_LAYERROW:
3142                         if (a == PIVOT_AXIS_COLUMN)
3143                           continue;
3144                         break;
3145
3146                       case CTDT_LAYERCOL:
3147                         if (a == PIVOT_AXIS_ROW)
3148                           continue;
3149                         break;
3150                       }
3151
3152                     nest->domains[dt][nest->n_domains[dt]++] = k;
3153                   }
3154               }
3155           }
3156       }
3157     else
3158       {
3159         struct ctables_nest *nest = xmalloc (sizeof *nest);
3160         *nest = (struct ctables_nest) { .n = 0 };
3161         t->stacks[a] = (struct ctables_stack) { .nests = nest, .n = 1 };
3162       }
3163
3164   struct ctables_stack *stack = &t->stacks[t->summary_axis];
3165   for (size_t i = 0; i < stack->n; i++)
3166     {
3167       struct ctables_nest *nest = &stack->nests[i];
3168       if (!nest->specs[CSV_CELL].n)
3169         {
3170           struct ctables_summary_spec_set *specs = &nest->specs[CSV_CELL];
3171           specs->specs = xmalloc (sizeof *specs->specs);
3172           specs->n = 1;
3173
3174           enum ctables_summary_function function
3175             = specs->var ? CTSF_MEAN : CTSF_COUNT;
3176           struct ctables_var var = { .is_mrset = false, .var = specs->var };
3177
3178           *specs->specs = (struct ctables_summary_spec) {
3179             .function = function,
3180             .format = ctables_summary_default_format (function, &var),
3181             .label = ctables_summary_default_label (function, 0),
3182           };
3183           if (!specs->var)
3184             specs->var = nest->vars[0];
3185
3186           ctables_summary_spec_set_clone (&nest->specs[CSV_TOTAL],
3187                                           &nest->specs[CSV_CELL]);
3188         }
3189       else if (!nest->specs[CSV_TOTAL].n)
3190         ctables_summary_spec_set_clone (&nest->specs[CSV_TOTAL],
3191                                         &nest->specs[CSV_CELL]);
3192     }
3193
3194   struct ctables_summary_spec_set *merged = &t->summary_specs;
3195   struct merge_item *items = xnmalloc (2 * stack->n, sizeof *items);
3196   size_t n_left = 0;
3197   for (size_t j = 0; j < stack->n; j++)
3198     {
3199       const struct ctables_nest *nest = &stack->nests[j];
3200       if (nest->n)
3201         for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
3202           items[n_left++] = (struct merge_item) { .set = &nest->specs[sv] };
3203     }
3204
3205   while (n_left > 0)
3206     {
3207       struct merge_item min = items[0];
3208       for (size_t j = 1; j < n_left; j++)
3209         if (merge_item_compare_3way (&items[j], &min) < 0)
3210           min = items[j];
3211
3212       if (merged->n >= merged->allocated)
3213         merged->specs = x2nrealloc (merged->specs, &merged->allocated,
3214                                     sizeof *merged->specs);
3215       merged->specs[merged->n++] = min.set->specs[min.ofs];
3216
3217       for (size_t j = 0; j < n_left; )
3218         {
3219           if (merge_item_compare_3way (&items[j], &min) == 0)
3220             {
3221               struct merge_item *item = &items[j];
3222               item->set->specs[item->ofs].axis_idx = merged->n - 1;
3223               if (++item->ofs >= item->set->n)
3224                 {
3225                   items[j] = items[--n_left];
3226                   continue;
3227                 }
3228             }
3229           j++;
3230         }
3231     }
3232
3233 #if 0
3234   for (size_t j = 0; j < merged->n; j++)
3235     printf ("%s\n", ctables_summary_function_name (merged->specs[j].function));
3236
3237   for (size_t j = 0; j < stack->n; j++)
3238     {
3239       const struct ctables_nest *nest = &stack->nests[j];
3240       for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
3241         {
3242           const struct ctables_summary_spec_set *specs = &nest->specs[sv];
3243           for (size_t k = 0; k < specs->n; k++)
3244             printf ("(%s, %zu) ", ctables_summary_function_name (specs->specs[k].function),
3245                     specs->specs[k].axis_idx);
3246           printf ("\n");
3247         }
3248     }
3249 #endif
3250
3251   return (ctables_check_label_position (t, PIVOT_AXIS_ROW)
3252           && ctables_check_label_position (t, PIVOT_AXIS_COLUMN));
3253 }
3254
3255 static void
3256 ctables_insert_clabels_values (struct ctables_table *t, const struct ccase *c,
3257                                enum pivot_axis_type a)
3258 {
3259   struct ctables_stack *stack = &t->stacks[a];
3260   for (size_t i = 0; i < stack->n; i++)
3261     {
3262       const struct ctables_nest *nest = &stack->nests[i];
3263       const struct variable *var = nest->vars[nest->n - 1];
3264       int width = var_get_width (var);
3265       const union value *value = case_data (c, var);
3266
3267       if (var_is_numeric (var) && value->f == SYSMIS)
3268         continue;
3269
3270       if (!ctables_categories_match (t->categories [var_get_dict_index (var)],
3271                                      value, var))
3272         continue;
3273
3274       unsigned int hash = value_hash (value, width, 0);
3275
3276       struct ctables_value *clv = ctables_value_find__ (t, value, width, hash);
3277       if (!clv)
3278         {
3279           clv = xmalloc (sizeof *clv);
3280           value_clone (&clv->value, value, width);
3281           hmap_insert (&t->clabels_values_map, &clv->node, hash);
3282         }
3283     }
3284 }
3285
3286 static int
3287 compare_clabels_values_3way (const void *a_, const void *b_, const void *width_)
3288 {
3289   const struct ctables_value *const *ap = a_;
3290   const struct ctables_value *const *bp = b_;
3291   const struct ctables_value *a = *ap;
3292   const struct ctables_value *b = *bp;
3293   const int *width = width_;
3294   return value_compare_3way (&a->value, &b->value, *width);
3295 }
3296
3297 static void
3298 ctables_sort_clabels_values (struct ctables_table *t)
3299 {
3300   int width = var_get_width (t->clabels_example);
3301
3302   size_t n = hmap_count (&t->clabels_values_map);
3303   t->clabels_values = xnmalloc (n, sizeof *t->clabels_values);
3304
3305   struct ctables_value *clv;
3306   size_t i = 0;
3307   HMAP_FOR_EACH (clv, struct ctables_value, node, &t->clabels_values_map)
3308     t->clabels_values[i++] = clv;
3309   t->n_clabels_values = n;
3310   assert (i == n);
3311
3312   sort (t->clabels_values, n, sizeof *t->clabels_values,
3313         compare_clabels_values_3way, &width);
3314
3315   for (size_t i = 0; i < n; i++)
3316     t->clabels_values[i]->leaf = i;
3317 }
3318
3319 static bool
3320 ctables_execute (struct dataset *ds, struct ctables *ct)
3321 {
3322   struct casereader *input = proc_open (ds);
3323   bool warn_on_invalid = true;
3324   for (struct ccase *c = casereader_read (input); c;
3325        case_unref (c), c = casereader_read (input))
3326     {
3327       double d_weight = dict_get_case_weight (dataset_dict (ds), c,
3328                                               &warn_on_invalid);
3329       double e_weight = (ct->e_weight
3330                          ? var_force_valid_weight (ct->e_weight,
3331                                                    case_num (c, ct->e_weight),
3332                                                    &warn_on_invalid)
3333                          : d_weight);
3334
3335       for (size_t i = 0; i < ct->n_tables; i++)
3336         {
3337           struct ctables_table *t = ct->tables[i];
3338
3339           for (size_t ir = 0; ir < t->stacks[PIVOT_AXIS_ROW].n; ir++)
3340             for (size_t ic = 0; ic < t->stacks[PIVOT_AXIS_COLUMN].n; ic++)
3341               for (size_t il = 0; il < t->stacks[PIVOT_AXIS_LAYER].n; il++)
3342                 ctables_cell_insert (t, c, ir, ic, il, d_weight, e_weight);
3343
3344           for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3345             if (t->label_axis[a] != a)
3346               ctables_insert_clabels_values (t, c, a);
3347         }
3348     }
3349   casereader_destroy (input);
3350
3351   for (size_t i = 0; i < ct->n_tables; i++)
3352     {
3353       struct ctables_table *t = ct->tables[i];
3354
3355       if (t->clabels_example)
3356         ctables_sort_clabels_values (t);
3357
3358       ctables_table_output (ct, ct->tables[i]);
3359     }
3360   return proc_commit (ds);
3361 }
3362
3363 int
3364 cmd_ctables (struct lexer *lexer, struct dataset *ds)
3365 {
3366   size_t n_vars = dict_get_n_vars (dataset_dict (ds));
3367   enum ctables_vlabel *vlabels = xnmalloc (n_vars, sizeof *vlabels);
3368   enum settings_value_show tvars = settings_get_show_variables ();
3369   for (size_t i = 0; i < n_vars; i++)
3370     vlabels[i] = (enum ctables_vlabel) tvars;
3371
3372   struct ctables *ct = xmalloc (sizeof *ct);
3373   *ct = (struct ctables) {
3374     .look = pivot_table_look_unshare (pivot_table_look_ref (
3375                                         pivot_table_look_get_default ())),
3376     .vlabels = vlabels,
3377     .hide_threshold = 5,
3378   };
3379   ct->look->omit_empty = false;
3380
3381   if (!lex_force_match (lexer, T_SLASH))
3382     goto error;
3383
3384   while (!lex_match_id (lexer, "TABLE"))
3385     {
3386       if (lex_match_id (lexer, "FORMAT"))
3387         {
3388           double widths[2] = { SYSMIS, SYSMIS };
3389           double units_per_inch = 72.0;
3390
3391           while (lex_token (lexer) != T_SLASH)
3392             {
3393               if (lex_match_id (lexer, "MINCOLWIDTH"))
3394                 {
3395                   if (!parse_col_width (lexer, "MINCOLWIDTH", &widths[0]))
3396                     goto error;
3397                 }
3398               else if (lex_match_id (lexer, "MAXCOLWIDTH"))
3399                 {
3400                   if (!parse_col_width (lexer, "MAXCOLWIDTH", &widths[1]))
3401                     goto error;
3402                 }
3403               else if (lex_match_id (lexer, "UNITS"))
3404                 {
3405                   lex_match (lexer, T_EQUALS);
3406                   if (lex_match_id (lexer, "POINTS"))
3407                     units_per_inch = 72.0;
3408                   else if (lex_match_id (lexer, "INCHES"))
3409                     units_per_inch = 1.0;
3410                   else if (lex_match_id (lexer, "CM"))
3411                     units_per_inch = 2.54;
3412                   else
3413                     {
3414                       lex_error_expecting (lexer, "POINTS", "INCHES", "CM");
3415                       goto error;
3416                     }
3417                 }
3418               else if (lex_match_id (lexer, "EMPTY"))
3419                 {
3420                   free (ct->zero);
3421                   ct->zero = NULL;
3422
3423                   lex_match (lexer, T_EQUALS);
3424                   if (lex_match_id (lexer, "ZERO"))
3425                     {
3426                       /* Nothing to do. */
3427                     }
3428                   else if (lex_match_id (lexer, "BLANK"))
3429                     ct->zero = xstrdup ("");
3430                   else if (lex_force_string (lexer))
3431                     {
3432                       ct->zero = ss_xstrdup (lex_tokss (lexer));
3433                       lex_get (lexer);
3434                     }
3435                   else
3436                     goto error;
3437                 }
3438               else if (lex_match_id (lexer, "MISSING"))
3439                 {
3440                   lex_match (lexer, T_EQUALS);
3441                   if (!lex_force_string (lexer))
3442                     goto error;
3443
3444                   free (ct->missing);
3445                   ct->missing = (strcmp (lex_tokcstr (lexer), ".")
3446                                  ? ss_xstrdup (lex_tokss (lexer))
3447                                  : NULL);
3448                   lex_get (lexer);
3449                 }
3450               else
3451                 {
3452                   lex_error_expecting (lexer, "MINCOLWIDTH", "MAXCOLWIDTH",
3453                                        "UNITS", "EMPTY", "MISSING");
3454                   goto error;
3455                 }
3456             }
3457
3458           if (widths[0] != SYSMIS && widths[1] != SYSMIS
3459               && widths[0] > widths[1])
3460             {
3461               msg (SE, _("MINCOLWIDTH must not be greater than MAXCOLWIDTH."));
3462               goto error;
3463             }
3464
3465           for (size_t i = 0; i < 2; i++)
3466             if (widths[i] != SYSMIS)
3467               {
3468                 int *wr = ct->look->width_ranges[TABLE_HORZ];
3469                 wr[i] = widths[i] / units_per_inch * 96.0;
3470                 if (wr[0] > wr[1])
3471                   wr[!i] = wr[i];
3472               }
3473         }
3474       else if (lex_match_id (lexer, "VLABELS"))
3475         {
3476           if (!lex_force_match_id (lexer, "VARIABLES"))
3477             goto error;
3478           lex_match (lexer, T_EQUALS);
3479
3480           struct variable **vars;
3481           size_t n_vars;
3482           if (!parse_variables (lexer, dataset_dict (ds), &vars, &n_vars,
3483                                 PV_NO_SCRATCH))
3484             goto error;
3485
3486           if (!lex_force_match_id (lexer, "DISPLAY"))
3487             {
3488               free (vars);
3489               goto error;
3490             }
3491           lex_match (lexer, T_EQUALS);
3492
3493           enum ctables_vlabel vlabel;
3494           if (lex_match_id (lexer, "DEFAULT"))
3495             vlabel = (enum ctables_vlabel) settings_get_show_variables ();
3496           else if (lex_match_id (lexer, "NAME"))
3497             vlabel = CTVL_NAME;
3498           else if (lex_match_id (lexer, "LABEL"))
3499             vlabel = CTVL_LABEL;
3500           else if (lex_match_id (lexer, "BOTH"))
3501             vlabel = CTVL_BOTH;
3502           else if (lex_match_id (lexer, "NONE"))
3503             vlabel = CTVL_NONE;
3504           else
3505             {
3506               lex_error_expecting (lexer, "DEFAULT", "NAME", "LABEL",
3507                                    "BOTH", "NONE");
3508               free (vars);
3509               goto error;
3510             }
3511
3512           for (size_t i = 0; i < n_vars; i++)
3513             ct->vlabels[var_get_dict_index (vars[i])] = vlabel;
3514           free (vars);
3515         }
3516       else if (lex_match_id (lexer, "MRSETS"))
3517         {
3518           if (!lex_force_match_id (lexer, "COUNTDUPLICATES"))
3519             goto error;
3520           lex_match (lexer, T_EQUALS);
3521           if (!parse_bool (lexer, &ct->mrsets_count_duplicates))
3522             goto error;
3523         }
3524       else if (lex_match_id (lexer, "SMISSING"))
3525         {
3526           if (lex_match_id (lexer, "VARIABLE"))
3527             ct->smissing_listwise = false;
3528           else if (lex_match_id (lexer, "LISTWISE"))
3529             ct->smissing_listwise = true;
3530           else
3531             {
3532               lex_error_expecting (lexer, "VARIABLE", "LISTWISE");
3533               goto error;
3534             }
3535         }
3536       /* XXX PCOMPUTE */
3537       else if (lex_match_id (lexer, "WEIGHT"))
3538         {
3539           if (!lex_force_match_id (lexer, "VARIABLE"))
3540             goto error;
3541           lex_match (lexer, T_EQUALS);
3542           ct->e_weight = parse_variable (lexer, dataset_dict (ds));
3543           if (!ct->e_weight)
3544             goto error;
3545         }
3546       else if (lex_match_id (lexer, "HIDESMALLCOUNTS"))
3547         {
3548           if (!lex_force_match_id (lexer, "COUNT"))
3549             goto error;
3550           lex_match (lexer, T_EQUALS);
3551           if (!lex_force_int_range (lexer, "HIDESMALLCOUNTS COUNT", 2, INT_MAX))
3552             goto error;
3553           ct->hide_threshold = lex_integer (lexer);
3554           lex_get (lexer);
3555         }
3556       else
3557         {
3558           lex_error_expecting (lexer, "FORMAT", "VLABELS", "MRSETS",
3559                                "SMISSING", "PCOMPUTE", "PPROPERTIES",
3560                                "WEIGHT", "HIDESMALLCOUNTS", "TABLE");
3561           goto error;
3562         }
3563
3564       if (!lex_force_match (lexer, T_SLASH))
3565         goto error;
3566     }
3567
3568   size_t allocated_tables = 0;
3569   do
3570     {
3571       if (ct->n_tables >= allocated_tables)
3572         ct->tables = x2nrealloc (ct->tables, &allocated_tables,
3573                                  sizeof *ct->tables);
3574
3575       struct ctables_category *cat = xmalloc (sizeof *cat);
3576       *cat = (struct ctables_category) {
3577         .type = CCT_VALUE,
3578         .include_missing = false,
3579         .sort_ascending = true,
3580       };
3581
3582       struct ctables_categories *c = xmalloc (sizeof *c);
3583       size_t n_vars = dict_get_n_vars (dataset_dict (ds));
3584       *c = (struct ctables_categories) {
3585         .n_refs = n_vars,
3586         .cats = cat,
3587         .n_cats = 1,
3588       };
3589
3590       struct ctables_categories **categories = xnmalloc (n_vars,
3591                                                          sizeof *categories);
3592       for (size_t i = 0; i < n_vars; i++)
3593         categories[i] = c;
3594
3595       struct ctables_table *t = xmalloc (sizeof *t);
3596       *t = (struct ctables_table) {
3597         .cells = HMAP_INITIALIZER (t->cells),
3598         .slabels_axis = PIVOT_AXIS_COLUMN,
3599         .slabels_visible = true,
3600         .clabels_values_map = HMAP_INITIALIZER (t->clabels_values_map),
3601         .label_axis = {
3602           [PIVOT_AXIS_ROW] = PIVOT_AXIS_ROW,
3603           [PIVOT_AXIS_COLUMN] = PIVOT_AXIS_COLUMN,
3604           [PIVOT_AXIS_LAYER] = PIVOT_AXIS_LAYER,
3605         },
3606         .clabels_from_axis = PIVOT_AXIS_LAYER, 
3607         .categories = categories,
3608         .n_categories = n_vars,
3609         .cilevel = 95,
3610       };
3611       for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
3612         hmap_init (&t->domains[dt]);
3613       ct->tables[ct->n_tables++] = t;
3614
3615       lex_match (lexer, T_EQUALS);
3616       if (!ctables_axis_parse (lexer, dataset_dict (ds), ct, t, PIVOT_AXIS_ROW))
3617         goto error;
3618       if (lex_match (lexer, T_BY))
3619         {
3620           if (!ctables_axis_parse (lexer, dataset_dict (ds),
3621                                    ct, t, PIVOT_AXIS_COLUMN))
3622             goto error;
3623
3624           if (lex_match (lexer, T_BY))
3625             {
3626               if (!ctables_axis_parse (lexer, dataset_dict (ds),
3627                                        ct, t, PIVOT_AXIS_LAYER))
3628                 goto error;
3629             }
3630         }
3631
3632       if (!t->axes[PIVOT_AXIS_ROW] && !t->axes[PIVOT_AXIS_COLUMN]
3633           && !t->axes[PIVOT_AXIS_LAYER])
3634         {
3635           lex_error (lexer, _("At least one variable must be specified."));
3636           goto error;
3637         }
3638
3639       const struct ctables_axis *scales[PIVOT_N_AXES];
3640       size_t n_scales = 0;
3641       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3642         {
3643           scales[a] = find_scale (t->axes[a]);
3644           if (scales[a])
3645             n_scales++;
3646         }
3647       if (n_scales > 1)
3648         {
3649           msg (SE, _("Scale variables may appear only on one axis."));
3650           if (scales[PIVOT_AXIS_ROW])
3651             msg_at (SN, scales[PIVOT_AXIS_ROW]->loc,
3652                     _("This scale variable appears on the rows axis."));
3653           if (scales[PIVOT_AXIS_COLUMN])
3654             msg_at (SN, scales[PIVOT_AXIS_COLUMN]->loc,
3655                     _("This scale variable appears on the columns axis."));
3656           if (scales[PIVOT_AXIS_LAYER])
3657             msg_at (SN, scales[PIVOT_AXIS_LAYER]->loc,
3658                     _("This scale variable appears on the layer axis."));
3659           goto error;
3660         }
3661
3662       const struct ctables_axis *summaries[PIVOT_N_AXES];
3663       size_t n_summaries = 0;
3664       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3665         {
3666           summaries[a] = (scales[a]
3667                           ? scales[a]
3668                           : find_categorical_summary_spec (t->axes[a]));
3669           if (summaries[a])
3670             n_summaries++;
3671         }
3672       if (n_summaries > 1)
3673         {
3674           msg (SE, _("Summaries may appear only on one axis."));
3675           if (summaries[PIVOT_AXIS_ROW])
3676             msg_at (SN, summaries[PIVOT_AXIS_ROW]->loc,
3677                     _("This variable on the rows axis has a summary."));
3678           if (summaries[PIVOT_AXIS_COLUMN])
3679             msg_at (SN, summaries[PIVOT_AXIS_COLUMN]->loc,
3680                     _("This variable on the columns axis has a summary."));
3681           if (summaries[PIVOT_AXIS_LAYER])
3682             msg_at (SN, summaries[PIVOT_AXIS_LAYER]->loc,
3683                     _("This variable on the layers axis has a summary."));
3684           goto error;
3685         }
3686       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3687         if (n_summaries ? summaries[a] : t->axes[a])
3688           {
3689             t->summary_axis = a;
3690             break;
3691           }
3692
3693       if (lex_token (lexer) == T_ENDCMD)
3694         {
3695           if (!ctables_prepare_table (t))
3696             goto error;
3697           break;
3698         }
3699       if (!lex_force_match (lexer, T_SLASH))
3700         break;
3701
3702       while (!lex_match_id (lexer, "TABLE") && lex_token (lexer) != T_ENDCMD)
3703         {
3704           if (lex_match_id (lexer, "SLABELS"))
3705             {
3706               while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
3707                 {
3708                   if (lex_match_id (lexer, "POSITION"))
3709                     {
3710                       lex_match (lexer, T_EQUALS);
3711                       if (lex_match_id (lexer, "COLUMN"))
3712                         t->slabels_axis = PIVOT_AXIS_COLUMN;
3713                       else if (lex_match_id (lexer, "ROW"))
3714                         t->slabels_axis = PIVOT_AXIS_ROW;
3715                       else if (lex_match_id (lexer, "LAYER"))
3716                         t->slabels_axis = PIVOT_AXIS_LAYER;
3717                       else
3718                         {
3719                           lex_error_expecting (lexer, "COLUMN", "ROW", "LAYER");
3720                           goto error;
3721                         }
3722                     }
3723                   else if (lex_match_id (lexer, "VISIBLE"))
3724                     {
3725                       lex_match (lexer, T_EQUALS);
3726                       if (!parse_bool (lexer, &t->slabels_visible))
3727                         goto error;
3728                     }
3729                   else
3730                     {
3731                       lex_error_expecting (lexer, "POSITION", "VISIBLE");
3732                       goto error;
3733                     }
3734                 }
3735             }
3736           else if (lex_match_id (lexer, "CLABELS"))
3737             {
3738               while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
3739                 {
3740                   if (lex_match_id (lexer, "AUTO"))
3741                     {
3742                       t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_ROW;
3743                       t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_COLUMN;
3744                     }
3745                   else if (lex_match_id (lexer, "ROWLABELS"))
3746                     {
3747                       lex_match (lexer, T_EQUALS);
3748                       if (lex_match_id (lexer, "OPPOSITE"))
3749                         t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_COLUMN;
3750                       else if (lex_match_id (lexer, "LAYER"))
3751                         t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_LAYER;
3752                       else
3753                         {
3754                           lex_error_expecting (lexer, "OPPOSITE", "LAYER");
3755                           goto error;
3756                         }
3757                     }
3758                   else if (lex_match_id (lexer, "COLLABELS"))
3759                     {
3760                       lex_match (lexer, T_EQUALS);
3761                       if (lex_match_id (lexer, "OPPOSITE"))
3762                         t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_ROW;
3763                       else if (lex_match_id (lexer, "LAYER"))
3764                         t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_LAYER;
3765                       else
3766                         {
3767                           lex_error_expecting (lexer, "OPPOSITE", "LAYER");
3768                           goto error;
3769                         }
3770                     }
3771                   else
3772                     {
3773                       lex_error_expecting (lexer, "AUTO", "ROWLABELS",
3774                                            "COLLABELS");
3775                       goto error;
3776                     }
3777                 }
3778             }
3779           else if (lex_match_id (lexer, "CRITERIA"))
3780             {
3781               if (!lex_force_match_id (lexer, "CILEVEL"))
3782                 goto error;
3783               lex_match (lexer, T_EQUALS);
3784
3785               if (!lex_force_num_range_halfopen (lexer, "CILEVEL", 0, 100))
3786                 goto error;
3787               t->cilevel = lex_number (lexer);
3788               lex_get (lexer);
3789             }
3790           else if (lex_match_id (lexer, "CATEGORIES"))
3791             {
3792               if (!ctables_table_parse_categories (lexer, dataset_dict (ds), t))
3793                 goto error;
3794             }
3795           else if (lex_match_id (lexer, "TITLES"))
3796             {
3797               do
3798                 {
3799                   char **textp;
3800                   if (lex_match_id (lexer, "CAPTION"))
3801                     textp = &t->caption;
3802                   else if (lex_match_id (lexer, "CORNER"))
3803                     textp = &t->corner;
3804                   else if (lex_match_id (lexer, "TITLE"))
3805                     textp = &t->title;
3806                   else
3807                     {
3808                       lex_error_expecting (lexer, "CAPTION", "CORNER", "TITLE");
3809                       goto error;
3810                     }
3811                   lex_match (lexer, T_EQUALS);
3812
3813                   struct string s = DS_EMPTY_INITIALIZER;
3814                   while (lex_is_string (lexer))
3815                     {
3816                       if (!ds_is_empty (&s))
3817                         ds_put_byte (&s, ' ');
3818                       ds_put_substring (&s, lex_tokss (lexer));
3819                       lex_get (lexer);
3820                     }
3821                   free (*textp);
3822                   *textp = ds_steal_cstr (&s);
3823                 }
3824               while (lex_token (lexer) != T_SLASH
3825                      && lex_token (lexer) != T_ENDCMD);
3826             }
3827           else if (lex_match_id (lexer, "SIGTEST"))
3828             {
3829               if (!t->chisq)
3830                 {
3831                   t->chisq = xmalloc (sizeof *t->chisq);
3832                   *t->chisq = (struct ctables_chisq) {
3833                     .alpha = .05,
3834                     .include_mrsets = true,
3835                     .all_visible = true,
3836                   };
3837                 }
3838
3839               do
3840                 {
3841                   if (lex_match_id (lexer, "TYPE"))
3842                     {
3843                       lex_match (lexer, T_EQUALS);
3844                       if (!lex_force_match_id (lexer, "CHISQUARE"))
3845                         goto error;
3846                     }
3847                   else if (lex_match_id (lexer, "ALPHA"))
3848                     {
3849                       lex_match (lexer, T_EQUALS);
3850                       if (!lex_force_num_range_halfopen (lexer, "ALPHA", 0, 1))
3851                         goto error;
3852                       t->chisq->alpha = lex_number (lexer);
3853                       lex_get (lexer);
3854                     }
3855                   else if (lex_match_id (lexer, "INCLUDEMRSETS"))
3856                     {
3857                       lex_match (lexer, T_EQUALS);
3858                       if (parse_bool (lexer, &t->chisq->include_mrsets))
3859                         goto error;
3860                     }
3861                   else if (lex_match_id (lexer, "CATEGORIES"))
3862                     {
3863                       lex_match (lexer, T_EQUALS);
3864                       if (lex_match_id (lexer, "ALLVISIBLE"))
3865                         t->chisq->all_visible = true;
3866                       else if (lex_match_id (lexer, "SUBTOTALS"))
3867                         t->chisq->all_visible = false;
3868                       else
3869                         {
3870                           lex_error_expecting (lexer,
3871                                                "ALLVISIBLE", "SUBTOTALS");
3872                           goto error;
3873                         }
3874                     }
3875                   else
3876                     {
3877                       lex_error_expecting (lexer, "TYPE", "ALPHA",
3878                                            "INCLUDEMRSETS", "CATEGORIES");
3879                       goto error;
3880                     }
3881                 }
3882               while (lex_token (lexer) != T_SLASH
3883                      && lex_token (lexer) != T_ENDCMD);
3884             }
3885           else if (lex_match_id (lexer, "COMPARETEST"))
3886             {
3887               if (!t->pairwise)
3888                 {
3889                   t->pairwise = xmalloc (sizeof *t->pairwise);
3890                   *t->pairwise = (struct ctables_pairwise) {
3891                     .type = PROP,
3892                     .alpha = { .05, .05 },
3893                     .adjust = BONFERRONI,
3894                     .include_mrsets = true,
3895                     .meansvariance_allcats = true,
3896                     .all_visible = true,
3897                     .merge = false,
3898                     .apa_style = true,
3899                     .show_sig = false,
3900                   };
3901                 }
3902
3903               do
3904                 {
3905                   if (lex_match_id (lexer, "TYPE"))
3906                     {
3907                       lex_match (lexer, T_EQUALS);
3908                       if (lex_match_id (lexer, "PROP"))
3909                         t->pairwise->type = PROP;
3910                       else if (lex_match_id (lexer, "MEAN"))
3911                         t->pairwise->type = MEAN;
3912                       else
3913                         {
3914                           lex_error_expecting (lexer, "PROP", "MEAN");
3915                           goto error;
3916                         }
3917                     }
3918                   else if (lex_match_id (lexer, "ALPHA"))
3919                     {
3920                       lex_match (lexer, T_EQUALS);
3921
3922                       if (!lex_force_num_range_open (lexer, "ALPHA", 0, 1))
3923                         goto error;
3924                       double a0 = lex_number (lexer);
3925                       lex_get (lexer);
3926
3927                       lex_match (lexer, T_COMMA);
3928                       if (lex_is_number (lexer))
3929                         {
3930                           if (!lex_force_num_range_open (lexer, "ALPHA", 0, 1))
3931                             goto error;
3932                           double a1 = lex_number (lexer);
3933                           lex_get (lexer);
3934
3935                           t->pairwise->alpha[0] = MIN (a0, a1);
3936                           t->pairwise->alpha[1] = MAX (a0, a1);
3937                         }
3938                       else
3939                         t->pairwise->alpha[0] = t->pairwise->alpha[1] = a0;
3940                     }
3941                   else if (lex_match_id (lexer, "ADJUST"))
3942                     {
3943                       lex_match (lexer, T_EQUALS);
3944                       if (lex_match_id (lexer, "BONFERRONI"))
3945                         t->pairwise->adjust = BONFERRONI;
3946                       else if (lex_match_id (lexer, "BH"))
3947                         t->pairwise->adjust = BH;
3948                       else if (lex_match_id (lexer, "NONE"))
3949                         t->pairwise->adjust = 0;
3950                       else
3951                         {
3952                           lex_error_expecting (lexer, "BONFERRONI", "BH",
3953                                                "NONE");
3954                           goto error;
3955                         }
3956                     }
3957                   else if (lex_match_id (lexer, "INCLUDEMRSETS"))
3958                     {
3959                       lex_match (lexer, T_EQUALS);
3960                       if (!parse_bool (lexer, &t->pairwise->include_mrsets))
3961                         goto error;
3962                     }
3963                   else if (lex_match_id (lexer, "MEANSVARIANCE"))
3964                     {
3965                       lex_match (lexer, T_EQUALS);
3966                       if (lex_match_id (lexer, "ALLCATS"))
3967                         t->pairwise->meansvariance_allcats = true;
3968                       else if (lex_match_id (lexer, "TESTEDCATS"))
3969                         t->pairwise->meansvariance_allcats = false;
3970                       else
3971                         {
3972                           lex_error_expecting (lexer, "ALLCATS", "TESTEDCATS");
3973                           goto error;
3974                         }
3975                     }
3976                   else if (lex_match_id (lexer, "CATEGORIES"))
3977                     {
3978                       lex_match (lexer, T_EQUALS);
3979                       if (lex_match_id (lexer, "ALLVISIBLE"))
3980                         t->pairwise->all_visible = true;
3981                       else if (lex_match_id (lexer, "SUBTOTALS"))
3982                         t->pairwise->all_visible = false;
3983                       else
3984                         {
3985                           lex_error_expecting (lexer, "ALLVISIBLE",
3986                                                "SUBTOTALS");
3987                           goto error;
3988                         }
3989                     }
3990                   else if (lex_match_id (lexer, "MERGE"))
3991                     {
3992                       lex_match (lexer, T_EQUALS);
3993                       if (!parse_bool (lexer, &t->pairwise->merge))
3994                         goto error;
3995                     }
3996                   else if (lex_match_id (lexer, "STYLE"))
3997                     {
3998                       lex_match (lexer, T_EQUALS);
3999                       if (lex_match_id (lexer, "APA"))
4000                         t->pairwise->apa_style = true;
4001                       else if (lex_match_id (lexer, "SIMPLE"))
4002                         t->pairwise->apa_style = false;
4003                       else
4004                         {
4005                           lex_error_expecting (lexer, "APA", "SIMPLE");
4006                           goto error;
4007                         }
4008                     }
4009                   else if (lex_match_id (lexer, "SHOWSIG"))
4010                     {
4011                       lex_match (lexer, T_EQUALS);
4012                       if (!parse_bool (lexer, &t->pairwise->show_sig))
4013                         goto error;
4014                     }
4015                   else
4016                     {
4017                       lex_error_expecting (lexer, "TYPE", "ALPHA", "ADJUST",
4018                                            "INCLUDEMRSETS", "MEANSVARIANCE",
4019                                            "CATEGORIES", "MERGE", "STYLE",
4020                                            "SHOWSIG");
4021                       goto error;
4022                     }
4023                 }
4024               while (lex_token (lexer) != T_SLASH
4025                      && lex_token (lexer) != T_ENDCMD);
4026             }
4027           else
4028             {
4029               lex_error_expecting (lexer, "TABLE", "SLABELS", "CLABELS",
4030                                    "CRITERIA", "CATEGORIES", "TITLES",
4031                                    "SIGTEST", "COMPARETEST");
4032               goto error;
4033             }
4034
4035           if (!lex_match (lexer, T_SLASH))
4036             break;
4037         }
4038
4039       if (t->label_axis[PIVOT_AXIS_ROW] != PIVOT_AXIS_ROW
4040           && t->label_axis[PIVOT_AXIS_COLUMN] != PIVOT_AXIS_COLUMN)
4041         {
4042           msg (SE, _("ROWLABELS and COLLABELS may not both be specified."));
4043           goto error;
4044         }
4045
4046       if (!ctables_prepare_table (t))
4047         goto error;
4048     }
4049   while (lex_token (lexer) != T_ENDCMD);
4050
4051   bool ok = ctables_execute (ds, ct);
4052   ctables_destroy (ct);
4053   return ok ? CMD_SUCCESS : CMD_FAILURE;
4054
4055 error:
4056   ctables_destroy (ct);
4057   return CMD_FAILURE;
4058 }
4059