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