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