Sorting categories by explicit values.
[pspp] / tests / output / pivot-table-test.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 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 <errno.h>
20 #include <fnmatch.h>
21 #include <getopt.h>
22 #include <limits.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 #include "data/file-handle-def.h"
28 #include "language/lexer/lexer.h"
29 #include "language/lexer/format-parser.h"
30 #include "libpspp/assertion.h"
31 #include "libpspp/compiler.h"
32 #include "libpspp/i18n.h"
33 #include "libpspp/string-map.h"
34 #include "output/driver.h"
35 #include "output/options.h"
36 #include "output/output-item.h"
37 #include "output/pivot-table.h"
38
39 #include "gl/error.h"
40 #include "gl/progname.h"
41 #include "gl/xalloc.h"
42 #include "gl/xvasprintf.h"
43
44 /* --emphasis: Enable emphasis in ASCII driver? */
45 static bool emphasis;
46
47 /* --box: ASCII driver box option. */
48 static char *box;
49
50 /* -o, --output: Base name for output files. */
51 static const char *output_base = "render";
52
53 static const char *parse_options (int argc, char **argv);
54 static void usage (void) NO_RETURN;
55 static void read_table (struct lexer *);
56 static void output_msg (const struct msg *, struct lexer *);
57
58 int
59 main (int argc, char **argv)
60 {
61   const char *input_file_name;
62
63   set_program_name (argv[0]);
64   i18n_init ();
65   output_engine_push ();
66   input_file_name = parse_options (argc, argv);
67
68   settings_init ();
69
70   struct lex_reader *reader = lex_reader_for_file (input_file_name, NULL,
71                                                    SEG_MODE_AUTO,
72                                                    LEX_ERROR_CONTINUE);
73   if (!reader)
74     exit (1);
75
76   struct lexer *lexer = lex_create ();
77   lex_set_message_handler (lexer, output_msg);
78   lex_include (lexer, reader);
79   lex_get (lexer);
80
81   for (;;)
82     {
83       while (lex_match (lexer, T_ENDCMD))
84         continue;
85       if (lex_match (lexer, T_STOP))
86         break;
87
88       read_table (lexer);
89     }
90
91   lex_destroy (lexer);
92   output_engine_pop ();
93   fh_done ();
94
95   return 0;
96 }
97
98 static void PRINTF_FORMAT (2, 3)
99 register_driver (struct string_map *options,
100                  const char *output_file, ...)
101 {
102   va_list args;
103   va_start (args, output_file);
104   string_map_insert_nocopy (options, xstrdup ("output-file"),
105                             xvasprintf (output_file, args));
106   va_end (args);
107
108   struct output_driver *driver = output_driver_create (options);
109   if (driver == NULL)
110     exit (EXIT_FAILURE);
111   output_driver_register (driver);
112 }
113
114 static void
115 configure_drivers (int width, int length UNUSED, int min_break)
116 {
117   /* Render to stdout. */
118   struct string_map options = STRING_MAP_INITIALIZER (options);
119   string_map_insert (&options, "format", "txt");
120   string_map_insert_nocopy (&options, xstrdup ("width"),
121                             xasprintf ("%d", width));
122   if (min_break >= 0)
123     string_map_insert_nocopy (&options, xstrdup ("min-hbreak"),
124                               xasprintf ("%d", min_break));
125   string_map_insert (&options, "emphasis", emphasis ? "true" : "false");
126   if (box != NULL)
127     string_map_insert (&options, "box", box);
128   register_driver (&options, "-");
129
130
131   /* Render to <base>.pdf. */
132   string_map_insert (&options, "top-margin", "0");
133   string_map_insert (&options, "bottom-margin", "0");
134   string_map_insert (&options, "left-margin", "0");
135   string_map_insert (&options, "right-margin", "0");
136   string_map_insert (&options, "paper-size", "99x99in");
137   string_map_insert (&options, "trim", "true");
138   register_driver (&options, "%s.pdf", output_base);
139
140   string_map_insert (&options, "box", "unicode");
141   register_driver (&options, "%s.txt", output_base);
142
143   string_map_insert (&options, "box", "ascii");
144   register_driver (&options, "%s-ascii.txt", output_base);
145
146   register_driver (&options, "%s.csv", output_base);
147   register_driver (&options, "%s.odt", output_base);
148   register_driver (&options, "%s.spv", output_base);
149   register_driver (&options, "%s.html", output_base);
150   register_driver (&options, "%s.tex", output_base);
151
152   string_map_destroy (&options);
153 }
154
155 static const char *
156 parse_options (int argc, char **argv)
157 {
158   int width = 79;
159   int length = 66;
160   int min_break = -1;
161
162   for (;;)
163     {
164       enum {
165         OPT_WIDTH = UCHAR_MAX + 1,
166         OPT_LENGTH,
167         OPT_MIN_BREAK,
168         OPT_EMPHASIS,
169         OPT_BOX,
170         OPT_TABLE_LOOK,
171         OPT_HELP
172       };
173       static const struct option options[] =
174         {
175           {"width", required_argument, NULL, OPT_WIDTH},
176           {"length", required_argument, NULL, OPT_LENGTH},
177           {"min-break", required_argument, NULL, OPT_MIN_BREAK},
178           {"emphasis", no_argument, NULL, OPT_EMPHASIS},
179           {"box", required_argument, NULL, OPT_BOX},
180           {"output", required_argument, NULL, 'o'},
181           {"table-look", required_argument, NULL, OPT_TABLE_LOOK},
182           {"help", no_argument, NULL, OPT_HELP},
183           {NULL, 0, NULL, 0},
184         };
185
186       int c = getopt_long (argc, argv, "o:", options, NULL);
187       if (c == -1)
188         break;
189
190       switch (c)
191         {
192         case OPT_WIDTH:
193           width = atoi (optarg);
194           break;
195
196         case OPT_LENGTH:
197           length = atoi (optarg);
198           break;
199
200         case OPT_MIN_BREAK:
201           min_break = atoi (optarg);
202           break;
203
204         case OPT_EMPHASIS:
205           emphasis = true;
206           break;
207
208         case OPT_BOX:
209           box = optarg;
210           break;
211
212         case 'o':
213           output_base = optarg;
214           break;
215
216         case OPT_TABLE_LOOK:
217           {
218             struct pivot_table_look *look;
219             char *err = pivot_table_look_read (optarg, &look);
220             if (err)
221               error (1, 0, "%s", err);
222             pivot_table_look_set_default (look);
223             pivot_table_look_unref (look);
224           }
225           break;
226
227         case OPT_HELP:
228           usage ();
229
230         case 0:
231           break;
232
233         case '?':
234           exit (EXIT_FAILURE);
235           break;
236
237         default:
238           NOT_REACHED ();
239         }
240
241     }
242
243   configure_drivers (width, length, min_break);
244
245   if (optind + 1 != argc)
246     error (1, 0, "exactly one non-option argument required; "
247            "use --help for help");
248   return argv[optind];
249 }
250
251 static void
252 usage (void)
253 {
254   printf ("%s, to test rendering of PSPP tables\n"
255           "usage: %s [OPTIONS] INPUT\n"
256           "\nOptions:\n"
257           "  --width=WIDTH   set page width in characters\n"
258           "  --length=LINE   set page length in lines\n",
259           program_name, program_name);
260   exit (EXIT_SUCCESS);
261 }
262
263 static void
264 force_match (struct lexer *lexer, enum token_type type)
265 {
266   if (!lex_force_match (lexer, type))
267     exit (1);
268 }
269
270 static void
271 force_string (struct lexer *lexer)
272 {
273   if (!lex_force_string (lexer))
274     exit (1);
275 }
276
277 static void
278 force_int (struct lexer *lexer)
279 {
280   if (!lex_force_int (lexer))
281     exit (1);
282 }
283
284 static void
285 force_num (struct lexer *lexer)
286 {
287   if (!lex_force_num (lexer))
288     exit (1);
289 }
290
291 static bool
292 parse_settings_value_show (struct lexer *lexer, const char *name,
293                            enum settings_value_show *show)
294 {
295   if (lex_match_id (lexer, name))
296     {
297       lex_match (lexer, T_EQUALS);
298
299       if (lex_match_id (lexer, "DEFAULT"))
300         *show = SETTINGS_VALUE_SHOW_DEFAULT;
301       else if (lex_match_id (lexer, "VALUE"))
302         *show = SETTINGS_VALUE_SHOW_VALUE;
303       else if (lex_match_id (lexer, "LABEL"))
304         *show = SETTINGS_VALUE_SHOW_LABEL;
305       else if (lex_match_id (lexer, "BOTH"))
306         *show = SETTINGS_VALUE_SHOW_BOTH;
307       else
308         {
309           lex_error_expecting (lexer, "DEFAULT", "VALUE", "LABEL", "BOTH");
310           exit (1);
311         }
312
313       return true;
314     }
315   else
316     return false;
317 }
318
319 static bool
320 parse_string_setting (struct lexer *lexer, const char *name, char **stringp)
321 {
322   if (lex_match_id (lexer, name))
323     {
324       lex_match (lexer, T_EQUALS);
325       force_string (lexer);
326
327       free (*stringp);
328       *stringp = xstrdup (lex_tokcstr (lexer));
329
330       lex_get (lexer);
331       return true;
332     }
333   else
334     return false;
335 }
336
337 static bool
338 match_kw (struct lexer *lexer, const char *kw)
339 {
340   return (!strcmp (kw, "ALL")
341           ? lex_match (lexer, T_ALL)
342           : lex_match_id (lexer, kw));
343 }
344
345 static bool
346 parse_bool_setting_with_default (struct lexer *lexer, const char *name,
347                                  const char *true_kw, const char *false_kw,
348                                  int default_value, bool *out)
349 {
350   if (lex_match_id (lexer, name))
351     {
352       if (default_value >= 0)
353         {
354           if (!lex_match (lexer, T_EQUALS))
355             *out = default_value;
356           return true;
357         }
358       else
359         force_match (lexer, T_EQUALS);
360
361       if (match_kw (lexer, true_kw))
362         *out = true;
363       else if (match_kw (lexer, false_kw))
364         *out = false;
365       else
366         {
367           lex_error_expecting (lexer, true_kw, false_kw);
368           exit (1);
369         }
370
371       return true;
372     }
373   else
374     return false;
375 }
376
377 static bool
378 parse_bool_setting (struct lexer *lexer, const char *name,
379                     const char *true_kw, const char *false_kw,
380                     bool *out)
381 {
382   return parse_bool_setting_with_default (lexer, name, true_kw, false_kw, -1,
383                                           out);
384 }
385
386 static bool
387 parse_yesno_setting (struct lexer *lexer, const char *name, bool *out)
388 {
389   return parse_bool_setting_with_default (lexer, name, "YES", "NO", true, out);
390 }
391
392 static struct cell_color
393 read_color (struct lexer *lexer)
394 {
395   struct cell_color color;
396   if (!parse_color__ (lex_tokcstr (lexer), &color))
397     {
398       msg (SE, "%s: unknown color", lex_tokcstr (lexer));
399       exit (1);
400     }
401   lex_get (lexer);
402   return color;
403 }
404
405 static bool
406 parse_color_pair_setting (struct lexer *lexer, const char *name,
407                           struct cell_color out[2])
408 {
409   if (lex_match_id (lexer, name))
410     {
411       lex_match (lexer, T_EQUALS);
412       out[0] = read_color (lexer);
413       out[1] = lex_is_string (lexer) ? read_color (lexer) : out[0];
414       return true;
415     }
416   else
417     return false;
418 }
419
420 static bool
421 parse_int_setting (struct lexer *lexer, const char *name, int *out)
422 {
423   if (lex_match_id (lexer, name))
424     {
425       lex_match (lexer, T_EQUALS);
426       force_int (lexer);
427       *out = lex_integer (lexer);
428       lex_get (lexer);
429       return true;
430     }
431   else
432     return false;
433 }
434
435 static void
436 read_font_style (struct lexer *lexer, struct font_style *fs)
437 {
438   while (parse_yesno_setting (lexer, "BOLD", &fs->bold)
439          || parse_yesno_setting (lexer, "ITALIC", &fs->italic)
440          || parse_yesno_setting (lexer, "UNDERLINE", &fs->underline)
441          || parse_yesno_setting (lexer, "MARKUP", &fs->markup)
442          || parse_color_pair_setting (lexer, "FG", fs->fg)
443          || parse_color_pair_setting (lexer, "BG", fs->bg)
444          || parse_string_setting (lexer, "FACE", &fs->typeface)
445          || parse_int_setting (lexer, "SIZE", &fs->size))
446     continue;
447 }
448
449 static bool
450 parse_halign_setting (struct lexer *lexer, enum table_halign *halign,
451                       double *decimal_offset)
452 {
453   if (lex_match_id (lexer, "RIGHT"))
454     *halign = TABLE_HALIGN_RIGHT;
455   else if (lex_match_id (lexer, "LEFT"))
456     *halign = TABLE_HALIGN_LEFT;
457   else if (lex_match_id (lexer, "CELL"))
458     *halign = TABLE_HALIGN_CENTER;
459   else if (lex_match_id (lexer, "MIXED"))
460     *halign = TABLE_HALIGN_MIXED;
461   else if (lex_match_id (lexer, "DECIMAL"))
462     {
463       if (lex_is_number (lexer))
464         {
465           *decimal_offset = lex_number (lexer);
466           lex_get (lexer);
467         }
468     }
469   else
470     return false;
471
472   return true;
473 }
474
475 static bool
476 parse_valign_setting (struct lexer *lexer, enum table_valign *valign)
477 {
478   if (lex_match_id (lexer, "TOP"))
479     *valign = TABLE_VALIGN_TOP;
480   else if (lex_match_id (lexer, "MIDDLE"))
481     *valign = TABLE_VALIGN_CENTER;
482   else if (lex_match_id (lexer, "BOTTOM"))
483     *valign = TABLE_VALIGN_BOTTOM;
484   else
485     return false;
486
487   return true;
488 }
489
490 static bool
491 parse_margin_setting (struct lexer *lexer, int margin[TABLE_N_AXES][2])
492 {
493   if (lex_match_id (lexer, "MARGINS"))
494     {
495       int values[4];
496       int n = 0;
497
498       lex_match (lexer, T_EQUALS);
499       force_num (lexer);
500       while (lex_is_number (lexer) && n < 4)
501         {
502           values[n++] = lex_number (lexer);
503           lex_get (lexer);
504         }
505
506       if (n == 1)
507         {
508           margin[TABLE_HORZ][0] = margin[TABLE_HORZ][1] = values[0];
509           margin[TABLE_VERT][0] = margin[TABLE_VERT][1] = values[0];
510         }
511       else if (n == 2)
512         {
513           margin[TABLE_HORZ][0] = margin[TABLE_HORZ][1] = values[1];
514           margin[TABLE_VERT][0] = margin[TABLE_VERT][1] = values[0];
515         }
516       else if (n == 3)
517         {
518           margin[TABLE_VERT][0] = values[0];
519           margin[TABLE_HORZ][0] = margin[TABLE_HORZ][1] = values[1];
520           margin[TABLE_VERT][1] = values[2];
521         }
522       else
523         {
524           assert (n == 4);
525           margin[TABLE_VERT][0] = values[0];
526           margin[TABLE_HORZ][1] = values[1];
527           margin[TABLE_VERT][1] = values[2];
528           margin[TABLE_HORZ][0] = values[3];
529         }
530
531       return true;
532     }
533   else
534     return false;
535 }
536
537 static void
538 read_cell_style (struct lexer *lexer, struct cell_style *cs)
539 {
540   while (parse_halign_setting (lexer, &cs->halign, &cs->decimal_offset)
541          || parse_valign_setting (lexer, &cs->valign)
542          || parse_margin_setting (lexer, cs->margin))
543     continue;
544 }
545
546 static void
547 read_value_option (struct lexer *lexer, const struct pivot_table *pt,
548                    struct pivot_value *value,
549                    const struct table_area_style *base_style)
550 {
551   enum settings_value_show *show
552     = (value->type == PIVOT_VALUE_NUMERIC ? &value->numeric.show
553        : value->type == PIVOT_VALUE_STRING ? &value->string.show
554        : value->type == PIVOT_VALUE_VARIABLE ? &value->variable.show
555        : NULL);
556   if (show && parse_settings_value_show (lexer, "SHOW", show))
557     return;
558
559   char **var_name
560     = (value->type == PIVOT_VALUE_NUMERIC ? &value->numeric.var_name
561        : value->type == PIVOT_VALUE_STRING ? &value->string.var_name
562        : NULL);
563   if (var_name && parse_string_setting (lexer, "VAR", var_name))
564     return;
565
566   char **label
567     = (value->type == PIVOT_VALUE_NUMERIC ? &value->numeric.value_label
568        : value->type == PIVOT_VALUE_STRING ? &value->string.value_label
569        : value->type == PIVOT_VALUE_VARIABLE ? &value->variable.var_label
570        : NULL);
571   if (label && parse_string_setting (lexer, "LABEL", label))
572     return;
573
574   if (value->type == PIVOT_VALUE_STRING && lex_match_id (lexer, "HEX"))
575     {
576       value->string.hex = true;
577       return;
578     }
579
580   if (value->type == PIVOT_VALUE_NUMERIC)
581     {
582       msg_disable ();
583       struct fmt_spec fmt;
584       bool ok = parse_format_specifier (lexer, &fmt);
585       msg_enable ();
586
587       if (ok)
588         {
589           if (!fmt_check_output (&fmt)
590               || !fmt_check_type_compat (&fmt, VAL_NUMERIC))
591             exit (1);
592
593           value->numeric.format = fmt;
594           return;
595         }
596     }
597
598   if (lex_match_id (lexer, "SUBSCRIPTS"))
599     {
600       lex_match (lexer, T_EQUALS);
601
602       struct pivot_value_ex *ex = pivot_value_ex_rw (value);
603       size_t allocated_subscripts = ex->n_subscripts;
604       while (lex_token (lexer) == T_STRING)
605         {
606           if (ex->n_subscripts >= allocated_subscripts)
607             ex->subscripts = x2nrealloc (ex->subscripts, &allocated_subscripts,
608                                          sizeof *ex->subscripts);
609
610           ex->subscripts[ex->n_subscripts++] = xstrdup (lex_tokcstr (lexer));
611           lex_get (lexer);
612         }
613       return;
614     }
615
616   if (lex_match_id (lexer, "FONT") && base_style)
617     {
618       lex_match (lexer, T_EQUALS);
619
620       struct pivot_value_ex *ex = pivot_value_ex_rw (value);
621       if (!ex->font_style)
622         {
623           ex->font_style = xmalloc (sizeof *ex->font_style);
624           font_style_copy (NULL, ex->font_style, &base_style->font_style);
625         }
626       read_font_style (lexer, ex->font_style);
627       return;
628     }
629
630   if (lex_match_id (lexer, "CELL") && base_style)
631     {
632       lex_match (lexer, T_EQUALS);
633
634       struct pivot_value_ex *ex = pivot_value_ex_rw (value);
635       if (!ex->cell_style)
636         {
637           ex->cell_style = xmalloc (sizeof *ex->cell_style);
638           *ex->cell_style = base_style->cell_style;
639         }
640       read_cell_style (lexer, ex->cell_style);
641       return;
642     }
643
644   if (lex_match_id (lexer, "FOOTNOTE"))
645     {
646       lex_match (lexer, T_EQUALS);
647
648       while (lex_is_integer (lexer))
649         {
650           size_t idx = lex_integer (lexer);
651           lex_get (lexer);
652
653           if (idx >= pt->n_footnotes)
654             {
655               msg (SE, "Footnote %zu not available "
656                    "(only %zu footnotes defined)", idx, pt->n_footnotes);
657               exit (1);
658             }
659           pivot_value_add_footnote (value, pt->footnotes[idx]);
660         }
661       return;
662     }
663
664   lex_error (lexer, "Expecting valid value option");
665   exit (1);
666 }
667
668 static struct pivot_value *
669 read_value (struct lexer *lexer, const struct pivot_table *pt,
670             const struct table_area_style *base_style)
671 {
672   struct pivot_value *value;
673   if (lex_is_number (lexer))
674     {
675       value = pivot_value_new_number (lex_number (lexer));
676       lex_get (lexer);
677     }
678   else if (lex_is_string (lexer))
679     {
680       value = xmalloc (sizeof *value);
681       *value = (struct pivot_value) {
682         .string = {
683           .type = PIVOT_VALUE_STRING,
684           .s = xstrdup (lex_tokcstr (lexer))
685         },
686       };
687       lex_get (lexer);
688     }
689   else if (lex_token (lexer) == T_ID)
690     {
691       value = xmalloc (sizeof *value);
692       *value = (struct pivot_value) {
693         .variable = {
694           .type = PIVOT_VALUE_VARIABLE,
695           .var_name = xstrdup (lex_tokcstr (lexer))
696         },
697       };
698       lex_get (lexer);
699     }
700   else
701     {
702       msg (SE, "Expecting pivot_value");
703       exit (1);
704     }
705
706   while (lex_match (lexer, T_LBRACK))
707     {
708       read_value_option (lexer, pt, value, base_style);
709       force_match (lexer, T_RBRACK);
710     }
711
712   return value;
713 }
714
715 static void
716 read_group (struct lexer *lexer, struct pivot_table *pt,
717             struct pivot_category *group,
718             const struct table_area_style *label_style)
719 {
720   if (lex_match (lexer, T_ASTERISK))
721     group->show_label = true;
722
723   force_match (lexer, T_LPAREN);
724   if (lex_match (lexer, T_RPAREN))
725     return;
726
727   do
728     {
729       struct pivot_value *name = read_value (lexer, pt, label_style);
730       if (lex_token (lexer) == T_ASTERISK
731           || lex_token (lexer) == T_LPAREN)
732         read_group (lexer, pt, pivot_category_create_group__ (group, name),
733                     label_style);
734       else
735         {
736           char *rc;
737           if (lex_token (lexer) == T_ID
738               && is_pivot_result_class (lex_tokcstr (lexer)))
739             {
740               rc = xstrdup (lex_tokcstr (lexer));
741               lex_get (lexer);
742             }
743           else
744             rc = NULL;
745
746           pivot_category_create_leaf_rc (group, name, rc);
747
748           free (rc);
749         }
750     }
751   while (lex_match (lexer, T_COMMA));
752   force_match (lexer, T_RPAREN);
753 }
754
755 static void
756 read_dimension (struct lexer *lexer, struct pivot_table *pt,
757                 enum pivot_axis_type a,
758                 const struct table_area_style *label_style)
759 {
760   if (!pivot_table_is_empty (pt))
761     error (1, 0, "can't add dimensions after adding data");
762
763   lex_match (lexer, T_EQUALS);
764
765   struct pivot_value *name = read_value (lexer, pt, label_style);
766   struct pivot_dimension *dim = pivot_dimension_create__ (pt, a, name);
767   read_group (lexer, pt, dim->root, label_style);
768 }
769
770 static void
771 read_look (struct lexer *lexer, struct pivot_table *pt)
772 {
773   lex_match (lexer, T_EQUALS);
774
775   if (lex_is_string (lexer))
776     {
777       struct pivot_table_look *look;
778       char *error = pivot_table_look_read (lex_tokcstr (lexer), &look);
779       if (error)
780         {
781           msg (SE, "%s", error);
782           exit (1);
783         }
784       lex_get (lexer);
785
786       pivot_table_set_look (pt, look);
787       pivot_table_look_unref (look);
788     }
789
790   struct pivot_table_look *look = pivot_table_look_unshare (
791     pivot_table_look_ref (pt->look));
792   for (;;)
793     {
794       if (!parse_bool_setting (lexer, "EMPTY", "HIDE", "SHOW",
795                                &look->omit_empty)
796           && !parse_bool_setting (lexer, "ROWLABELS", "CORNER", "NESTED",
797                                   &look->row_labels_in_corner)
798           && !parse_bool_setting (lexer, "MARKERS", "NUMERIC", "ALPHA",
799                                   &look->show_numeric_markers)
800           && !parse_bool_setting (lexer, "LEVEL", "SUPER", "SUB",
801                                   &look->footnote_marker_superscripts)
802           && !parse_bool_setting (lexer, "LAYERS", "ALL", "CURRENT",
803                                   &look->print_all_layers)
804           && !parse_bool_setting (lexer, "PAGINATELAYERS", "YES", "NO",
805                                   &look->paginate_layers)
806           && !parse_bool_setting (lexer, "HSHRINK", "YES", "NO",
807                                   &look->shrink_to_fit[TABLE_HORZ])
808           && !parse_bool_setting (lexer, "VSHRINK", "YES", "NO",
809                                   &look->shrink_to_fit[TABLE_VERT])
810           && !parse_bool_setting (lexer, "TOPCONTINUATION", "YES", "NO",
811                                   &look->top_continuation)
812           && !parse_bool_setting (lexer, "BOTTOMCONTINUATION", "YES", "NO",
813                                   &look->bottom_continuation)
814           && !parse_string_setting (lexer, "CONTINUATION",
815                                     &look->continuation))
816         break;
817     }
818   pivot_table_set_look (pt, look);
819   pivot_table_look_unref (look);
820 }
821
822 static enum table_stroke
823 read_stroke (struct lexer *lexer)
824 {
825   for (int stroke = 0; stroke < TABLE_N_STROKES; stroke++)
826     if (lex_match_id (lexer, table_stroke_to_string (stroke)))
827       return stroke;
828
829   lex_error (lexer, "expecting stroke");
830   exit (1);
831 }
832
833 static bool
834 parse_value_setting (struct lexer *lexer, const struct pivot_table *pt,
835                      const char *name,
836                      struct pivot_value **valuep,
837                      struct table_area_style *base_style)
838 {
839   if (lex_match_id (lexer, name))
840     {
841       lex_match (lexer, T_EQUALS);
842
843       pivot_value_destroy (*valuep);
844       *valuep = read_value (lexer, pt, base_style);
845
846       return true;
847     }
848   else
849     return false;
850 }
851
852 static void
853 read_border (struct lexer *lexer, struct pivot_table *pt)
854 {
855   static const char *const pivot_border_ids[PIVOT_N_BORDERS] = {
856     [PIVOT_BORDER_TITLE] = "title",
857     [PIVOT_BORDER_OUTER_LEFT] = "outer-left",
858     [PIVOT_BORDER_OUTER_TOP] = "outer-top",
859     [PIVOT_BORDER_OUTER_RIGHT] = "outer-right",
860     [PIVOT_BORDER_OUTER_BOTTOM] = "outer-bottom",
861     [PIVOT_BORDER_INNER_LEFT] = "inner-left",
862     [PIVOT_BORDER_INNER_TOP] = "inner-top",
863     [PIVOT_BORDER_INNER_RIGHT] = "inner-right",
864     [PIVOT_BORDER_INNER_BOTTOM] = "inner-bottom",
865     [PIVOT_BORDER_DATA_LEFT] = "data-left",
866     [PIVOT_BORDER_DATA_TOP] = "data-top",
867     [PIVOT_BORDER_DIM_ROW_HORZ] = "dim-row-horz",
868     [PIVOT_BORDER_DIM_ROW_VERT] = "dim-row-vert",
869     [PIVOT_BORDER_DIM_COL_HORZ] = "dim-col-horz",
870     [PIVOT_BORDER_DIM_COL_VERT] = "dim-col-vert",
871     [PIVOT_BORDER_CAT_ROW_HORZ] = "cat-row-horz",
872     [PIVOT_BORDER_CAT_ROW_VERT] = "cat-row-vert",
873     [PIVOT_BORDER_CAT_COL_HORZ] = "cat-col-horz",
874     [PIVOT_BORDER_CAT_COL_VERT] = "cat-col-vert",
875   };
876
877   lex_match (lexer, T_EQUALS);
878
879   struct pivot_table_look *look = pivot_table_look_unshare (
880     pivot_table_look_ref (pt->look));
881   while (lex_token (lexer) == T_STRING)
882     {
883       char *s = xstrdup (lex_tokcstr (lexer));
884       lex_get (lexer);
885       force_match (lexer, T_LPAREN);
886
887       struct table_border_style style = TABLE_BORDER_STYLE_INITIALIZER;
888       style.stroke = read_stroke (lexer);
889       if (lex_is_string (lexer))
890         style.color = read_color (lexer);
891       force_match (lexer, T_RPAREN);
892
893       int n = 0;
894       for (int b = 0; b < PIVOT_N_BORDERS; b++)
895         {
896           if (!fnmatch (s, pivot_border_ids[b], 0))
897             {
898               look->borders[b] = style;
899               n++;
900             }
901         }
902       if (!n)
903         {
904           msg (SE, "%s: no matching borders", s);
905           exit (1);
906         }
907       free (s);
908     }
909   pivot_table_set_look (pt, look);
910   pivot_table_look_unref (look);
911 }
912
913 static void
914 read_footnote (struct lexer *lexer, struct pivot_table *pt)
915 {
916   size_t idx;
917   if (lex_match (lexer, T_LBRACK))
918     {
919       force_int (lexer);
920
921       idx = lex_integer (lexer);
922       lex_get (lexer);
923
924       force_match (lexer, T_RBRACK);
925     }
926   else
927     idx = pt->n_footnotes;
928   lex_match (lexer, T_EQUALS);
929
930   struct pivot_value *content
931     = read_value (lexer, pt, &pt->look->areas[PIVOT_AREA_FOOTER]);
932
933   struct pivot_value *marker;
934   if (lex_match_id (lexer, "MARKER"))
935     {
936       lex_match (lexer, T_EQUALS);
937       marker = read_value (lexer, pt, &pt->look->areas[PIVOT_AREA_FOOTER]);
938     }
939   else
940     marker = NULL;
941
942   bool show = !lex_match_id (lexer, "HIDE");
943   pivot_table_create_footnote__ (pt, idx, marker, content)->show = show;
944 }
945
946 static void
947 read_cell (struct lexer *lexer, struct pivot_table *pt)
948 {
949   force_match (lexer, T_LBRACK);
950
951   size_t *lo = xnmalloc (pt->n_dimensions, sizeof *lo);
952   size_t *hi = xnmalloc (pt->n_dimensions, sizeof *hi);
953   for (size_t i = 0; i < pt->n_dimensions; i++)
954     {
955       const struct pivot_dimension *d = pt->dimensions[i];
956
957       if (i)
958         force_match (lexer, T_COMMA);
959
960       if (!d->n_leaves)
961         {
962           msg (SE, "can't define data because dimension %zu has no categories",
963                i);
964           exit (1);
965         }
966
967       if (lex_match (lexer, T_ALL))
968         {
969           lo[i] = 0;
970           hi[i] = d->n_leaves - 1;
971         }
972       else
973         {
974           force_int (lexer);
975           lo[i] = hi[i] = lex_integer (lexer);
976           lex_get (lexer);
977
978           if (lex_match_id (lexer, "THRU"))
979             {
980               force_int (lexer);
981               hi[i] = lex_integer (lexer);
982               lex_get (lexer);
983             }
984
985           if (hi[i] < lo[i])
986             {
987               msg (SE, "%zu THRU %zu is not a valid range", lo[i], hi[i]);
988               exit (1);
989             }
990           if (hi[i] >= d->n_leaves)
991             {
992               msg (SE, "dimension %zu (%s) has only %zu categories",
993                    i, pivot_value_to_string (d->root->name, pt),
994                    d->n_leaves);
995               exit (1);
996             }
997         }
998     }
999   force_match (lexer, T_RBRACK);
1000
1001   struct pivot_value *value = NULL;
1002   bool delete = false;
1003   if (lex_match (lexer, T_EQUALS))
1004     {
1005       if (lex_match_id (lexer, "DELETE"))
1006         delete = true;
1007       else
1008         value = read_value (lexer, pt, &pt->look->areas[PIVOT_AREA_DATA]);
1009     }
1010
1011   size_t *dindexes = xmemdup (lo, pt->n_dimensions * sizeof *lo);
1012   for (size_t i = 0; ; i++)
1013     {
1014       if (delete)
1015         pivot_table_delete (pt, dindexes);
1016       else
1017         pivot_table_put (pt, dindexes, pt->n_dimensions,
1018                          (value
1019                           ? pivot_value_clone (value)
1020                           : pivot_value_new_integer (i)));
1021
1022       for (size_t j = 0; j < pt->n_dimensions; j++)
1023         {
1024           if (++dindexes[j] <= hi[j])
1025             goto next;
1026           dindexes[j] = lo[j];
1027         }
1028         break;
1029     next:;
1030     }
1031   free (dindexes);
1032
1033   pivot_value_destroy (value);
1034
1035   free (lo);
1036   free (hi);
1037 }
1038
1039 static struct pivot_dimension *
1040 parse_dim_name (struct lexer *lexer, struct pivot_table *table)
1041 {
1042   force_string (lexer);
1043   for (size_t i = 0; i < table->n_dimensions; i++)
1044     {
1045       struct pivot_dimension *dim = table->dimensions[i];
1046
1047       struct string s = DS_EMPTY_INITIALIZER;
1048       pivot_value_format_body (dim->root->name, table, &s);
1049       bool match = !strcmp (ds_cstr (&s), lex_tokcstr (lexer));
1050       ds_destroy (&s);
1051
1052       if (match)
1053         {
1054           lex_get (lexer);
1055           return dim;
1056         }
1057     }
1058
1059   lex_error (lexer, "unknown dimension");
1060   exit (1);
1061 }
1062
1063 static enum pivot_axis_type
1064 parse_axis_type (struct lexer *lexer)
1065 {
1066   if (lex_match_id (lexer, "ROW"))
1067     return PIVOT_AXIS_ROW;
1068   else if (lex_match_id (lexer, "COLUMN"))
1069     return PIVOT_AXIS_COLUMN;
1070   else if (lex_match_id (lexer, "LAYER"))
1071     return PIVOT_AXIS_LAYER;
1072   else
1073     {
1074       lex_error_expecting (lexer, "ROW", "COLUMN", "LAYER");
1075       exit (1);
1076     }
1077 }
1078
1079 static void
1080 move_dimension (struct lexer *lexer, struct pivot_table *table)
1081 {
1082   struct pivot_dimension *dim = parse_dim_name (lexer, table);
1083
1084   enum pivot_axis_type axis = parse_axis_type (lexer);
1085
1086   size_t position;
1087   if (lex_is_integer (lexer))
1088     {
1089       position = lex_integer (lexer);
1090       lex_get (lexer);
1091     }
1092   else
1093     position = 0;
1094
1095   pivot_table_move_dimension (table, dim, axis, position);
1096 }
1097
1098 static void
1099 swap_axes (struct lexer *lexer, struct pivot_table *table)
1100 {
1101   enum pivot_axis_type a = parse_axis_type (lexer);
1102   enum pivot_axis_type b = parse_axis_type (lexer);
1103   pivot_table_swap_axes (table, a, b);
1104 }
1105
1106 static void
1107 read_current_layer (struct lexer *lexer, struct pivot_table *table)
1108 {
1109   lex_match (lexer, T_EQUALS);
1110
1111   const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1112   for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1113     {
1114       const struct pivot_dimension *dim = layer_axis->dimensions[i];
1115
1116       force_int (lexer);
1117       size_t index = lex_integer (lexer);
1118       if (index >= dim->n_leaves)
1119         {
1120           lex_error (lexer, "only %zu dimensions", dim->n_leaves);
1121           exit (1);
1122         }
1123       lex_get (lexer);
1124
1125       table->current_layer[i] = index;
1126     }
1127 }
1128
1129 static void
1130 read_table (struct lexer *lexer)
1131 {
1132   bool displayed = false;
1133
1134   struct pivot_table *pt = pivot_table_create ("Default Title");
1135   while (lex_match (lexer, T_SLASH))
1136     {
1137       assert (!pivot_table_is_shared (pt));
1138       displayed = false;
1139
1140       if (lex_match_id (lexer, "ROW"))
1141         read_dimension (lexer, pt, PIVOT_AXIS_ROW,
1142                         &pt->look->areas[PIVOT_AREA_ROW_LABELS]);
1143       else if (lex_match_id (lexer, "COLUMN"))
1144         read_dimension (lexer, pt, PIVOT_AXIS_COLUMN,
1145                         &pt->look->areas[PIVOT_AREA_COLUMN_LABELS]);
1146       else if (lex_match_id (lexer, "LAYER"))
1147         read_dimension (lexer, pt, PIVOT_AXIS_LAYER,
1148                         &pt->look->areas[PIVOT_AREA_LAYERS]);
1149       else if (lex_match_id (lexer, "LOOK"))
1150         read_look (lexer, pt);
1151       else if (lex_match_id (lexer, "ROTATE"))
1152         {
1153           lex_match (lexer, T_EQUALS);
1154           while (lex_token (lexer) == T_ID)
1155             if (!parse_bool_setting (lexer, "INNERCOLUMNS", "YES", "NO",
1156                                      &pt->rotate_inner_column_labels)
1157                 && !parse_bool_setting (lexer, "OUTERROWS", "YES", "NO",
1158                                         &pt->rotate_outer_row_labels))
1159               break;
1160         }
1161       else if (lex_match_id (lexer, "SHOW"))
1162         {
1163           lex_match (lexer, T_EQUALS);
1164           while (lex_token (lexer) == T_ID)
1165             {
1166               if (parse_bool_setting (lexer, "GRID", "YES", "NO",
1167                                       &pt->show_grid_lines)
1168                   || parse_bool_setting (lexer, "CAPTION", "YES", "NO",
1169                                          &pt->show_caption)
1170                   || parse_bool_setting (lexer, "TITLE", "YES", "NO",
1171                                          &pt->show_title))
1172                 continue;
1173
1174               if (parse_settings_value_show (lexer, "VALUES", &pt->show_values)
1175                   || parse_settings_value_show (lexer, "VARIABLES",
1176                                                 &pt->show_variables))
1177                 continue;
1178
1179               if (lex_match_id (lexer, "LAYER"))
1180                 read_current_layer (lexer, pt);
1181
1182               break;
1183             }
1184         }
1185       else if (parse_value_setting (lexer, pt, "TITLE", &pt->title,
1186                                     &pt->look->areas[PIVOT_AREA_TITLE])
1187                || parse_value_setting (lexer, pt, "SUBTYPE", &pt->subtype,
1188                                        NULL)
1189                || parse_value_setting (lexer, pt, "CORNER", &pt->corner_text,
1190                                        &pt->look->areas[PIVOT_AREA_CORNER])
1191                || parse_value_setting (lexer, pt, "CAPTION", &pt->caption,
1192                                        &pt->look->areas[PIVOT_AREA_CAPTION])
1193                || parse_string_setting (lexer, "NOTES", &pt->notes))
1194         {
1195           /* Nothing. */
1196         }
1197       else if (lex_match_id (lexer, "BORDER"))
1198         read_border (lexer, pt);
1199       else if (lex_match_id (lexer, "TRANSPOSE"))
1200         pivot_table_transpose (pt);
1201       else if (lex_match_id (lexer, "SWAP"))
1202         swap_axes (lexer, pt);
1203       else if (lex_match_id (lexer, "MOVE"))
1204         move_dimension (lexer, pt);
1205       else if (lex_match_id (lexer, "CELLS"))
1206         read_cell (lexer, pt);
1207       else if (lex_match_id (lexer, "FOOTNOTE"))
1208         read_footnote (lexer, pt);
1209       else if (lex_match_id (lexer, "DUMP"))
1210         pivot_table_dump (pt, 0);
1211       else if (lex_match_id (lexer, "DISPLAY"))
1212         {
1213           pivot_table_submit (pivot_table_ref (pt));
1214           pt = pivot_table_unshare (pt);
1215           displayed = true;
1216         }
1217       else
1218         {
1219           msg (SE, "Expecting keyword");
1220           exit (1);
1221         }
1222     }
1223
1224   if (!displayed)
1225     pivot_table_submit (pt);
1226   else
1227     pivot_table_unref (pt);
1228
1229   force_match (lexer, T_ENDCMD);
1230 }
1231
1232 static void
1233 output_msg (const struct msg *m_, struct lexer *lexer)
1234 {
1235   struct msg m = {
1236     .category = m_->category,
1237     .severity = m_->severity,
1238     .location = (m_->location ? m_->location
1239                  : lexer ? lex_get_location (lexer, 0, 0)
1240                  : NULL),
1241     .command_name = output_get_uppercase_command_name (),
1242     .text = m_->text,
1243   };
1244
1245   output_item_submit (message_item_create (&m));
1246
1247   free (m.command_name);
1248   if (m.location != m_->location)
1249     msg_location_destroy (m.location);
1250 }