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