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