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