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