1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
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.
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.
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/>. */
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"
40 #include "gl/progname.h"
41 #include "gl/xalloc.h"
42 #include "gl/xvasprintf.h"
44 /* --emphasis: Enable emphasis in ASCII driver? */
47 /* --box: ASCII driver box option. */
50 /* -o, --output: Base name for output files. */
51 static const char *output_base = "render";
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 *);
59 main (int argc, char **argv)
61 const char *input_file_name;
63 set_program_name (argv[0]);
65 output_engine_push ();
66 input_file_name = parse_options (argc, argv);
70 struct lex_reader *reader = lex_reader_for_file (input_file_name, NULL,
76 struct lexer *lexer = lex_create ();
77 lex_set_message_handler (lexer, output_msg);
78 lex_include (lexer, reader);
83 while (lex_match (lexer, T_ENDCMD))
85 if (lex_match (lexer, T_STOP))
98 static void PRINTF_FORMAT (2, 3)
99 register_driver (struct string_map *options,
100 const char *output_file, ...)
103 va_start (args, output_file);
104 string_map_insert_nocopy (options, xstrdup ("output-file"),
105 xvasprintf (output_file, args));
108 struct output_driver *driver = output_driver_create (options);
111 output_driver_register (driver);
115 configure_drivers (int width, int length UNUSED, int min_break)
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));
123 string_map_insert_nocopy (&options, xstrdup ("min-hbreak"),
124 xasprintf ("%d", min_break));
125 string_map_insert (&options, "emphasis", emphasis ? "true" : "false");
127 string_map_insert (&options, "box", box);
128 register_driver (&options, "-");
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);
140 /* Render to <base>-paged.pdf. */
141 register_driver (&options, "%s-paged.pdf", output_base);
143 /* Render to <base>.txt. */
144 string_map_insert (&options, "box", "unicode");
145 register_driver (&options, "%s.txt", output_base);
147 /* Render to <base>-ascii.txt. */
148 string_map_insert (&options, "box", "ascii");
149 register_driver (&options, "%s-ascii.txt", output_base);
151 /* Render additional versions. */
152 register_driver (&options, "%s.csv", output_base);
153 register_driver (&options, "%s.odt", output_base);
154 register_driver (&options, "%s.spv", output_base);
155 register_driver (&options, "%s.html", output_base);
156 register_driver (&options, "%s.tex", output_base);
158 string_map_destroy (&options);
162 parse_options (int argc, char **argv)
171 OPT_WIDTH = UCHAR_MAX + 1,
179 static const struct option options[] =
181 {"width", required_argument, NULL, OPT_WIDTH},
182 {"length", required_argument, NULL, OPT_LENGTH},
183 {"min-break", required_argument, NULL, OPT_MIN_BREAK},
184 {"emphasis", no_argument, NULL, OPT_EMPHASIS},
185 {"box", required_argument, NULL, OPT_BOX},
186 {"output", required_argument, NULL, 'o'},
187 {"table-look", required_argument, NULL, OPT_TABLE_LOOK},
188 {"help", no_argument, NULL, OPT_HELP},
192 int c = getopt_long (argc, argv, "o:", options, NULL);
199 width = atoi (optarg);
203 length = atoi (optarg);
207 min_break = atoi (optarg);
219 output_base = optarg;
224 struct pivot_table_look *look;
225 char *err = pivot_table_look_read (optarg, &look);
227 error (1, 0, "%s", err);
228 pivot_table_look_set_default (look);
229 pivot_table_look_unref (look);
249 configure_drivers (width, length, min_break);
251 if (optind + 1 != argc)
252 error (1, 0, "exactly one non-option argument required; "
253 "use --help for help");
260 printf ("%s, to test rendering of PSPP tables\n"
261 "usage: %s [OPTIONS] INPUT\n"
263 " --width=WIDTH set page width in characters\n"
264 " --length=LINE set page length in lines\n",
265 program_name, program_name);
270 force_match (struct lexer *lexer, enum token_type type)
272 if (!lex_force_match (lexer, type))
277 force_string (struct lexer *lexer)
279 if (!lex_force_string (lexer))
284 force_int (struct lexer *lexer)
286 if (!lex_force_int (lexer))
291 force_num (struct lexer *lexer)
293 if (!lex_force_num (lexer))
298 parse_settings_value_show (struct lexer *lexer, const char *name,
299 enum settings_value_show *show)
301 if (lex_match_id (lexer, name))
303 lex_match (lexer, T_EQUALS);
305 if (lex_match_id (lexer, "DEFAULT"))
306 *show = SETTINGS_VALUE_SHOW_DEFAULT;
307 else if (lex_match_id (lexer, "VALUE"))
308 *show = SETTINGS_VALUE_SHOW_VALUE;
309 else if (lex_match_id (lexer, "LABEL"))
310 *show = SETTINGS_VALUE_SHOW_LABEL;
311 else if (lex_match_id (lexer, "BOTH"))
312 *show = SETTINGS_VALUE_SHOW_BOTH;
315 lex_error_expecting (lexer, "DEFAULT", "VALUE", "LABEL", "BOTH");
326 parse_string_setting (struct lexer *lexer, const char *name, char **stringp)
328 if (lex_match_id (lexer, name))
330 lex_match (lexer, T_EQUALS);
331 force_string (lexer);
334 *stringp = xstrdup (lex_tokcstr (lexer));
344 match_kw (struct lexer *lexer, const char *kw)
346 return (!strcmp (kw, "ALL")
347 ? lex_match (lexer, T_ALL)
348 : lex_match_id (lexer, kw));
352 parse_bool_setting_with_default (struct lexer *lexer, const char *name,
353 const char *true_kw, const char *false_kw,
354 int default_value, bool *out)
356 if (lex_match_id (lexer, name))
358 if (default_value >= 0)
360 if (!lex_match (lexer, T_EQUALS))
361 *out = default_value;
365 force_match (lexer, T_EQUALS);
367 if (match_kw (lexer, true_kw))
369 else if (match_kw (lexer, false_kw))
373 lex_error_expecting (lexer, true_kw, false_kw);
384 parse_bool_setting (struct lexer *lexer, const char *name,
385 const char *true_kw, const char *false_kw,
388 return parse_bool_setting_with_default (lexer, name, true_kw, false_kw, -1,
393 parse_yesno_setting (struct lexer *lexer, const char *name, bool *out)
395 return parse_bool_setting_with_default (lexer, name, "YES", "NO", true, out);
398 static struct cell_color
399 read_color (struct lexer *lexer)
401 struct cell_color color;
402 if (!parse_color__ (lex_tokcstr (lexer), &color))
404 msg (SE, "%s: unknown color", lex_tokcstr (lexer));
412 parse_color_pair_setting (struct lexer *lexer, const char *name,
413 struct cell_color out[2])
415 if (lex_match_id (lexer, name))
417 lex_match (lexer, T_EQUALS);
418 out[0] = read_color (lexer);
419 out[1] = lex_is_string (lexer) ? read_color (lexer) : out[0];
427 parse_int_setting (struct lexer *lexer, const char *name, int *out)
429 if (lex_match_id (lexer, name))
431 lex_match (lexer, T_EQUALS);
433 *out = lex_integer (lexer);
442 read_font_style (struct lexer *lexer, struct font_style *fs)
444 while (parse_yesno_setting (lexer, "BOLD", &fs->bold)
445 || parse_yesno_setting (lexer, "ITALIC", &fs->italic)
446 || parse_yesno_setting (lexer, "UNDERLINE", &fs->underline)
447 || parse_yesno_setting (lexer, "MARKUP", &fs->markup)
448 || parse_color_pair_setting (lexer, "FG", fs->fg)
449 || parse_color_pair_setting (lexer, "BG", fs->bg)
450 || parse_string_setting (lexer, "FACE", &fs->typeface)
451 || parse_int_setting (lexer, "SIZE", &fs->size))
456 parse_halign_setting (struct lexer *lexer, enum table_halign *halign,
457 double *decimal_offset)
459 if (lex_match_id (lexer, "RIGHT"))
460 *halign = TABLE_HALIGN_RIGHT;
461 else if (lex_match_id (lexer, "LEFT"))
462 *halign = TABLE_HALIGN_LEFT;
463 else if (lex_match_id (lexer, "CELL"))
464 *halign = TABLE_HALIGN_CENTER;
465 else if (lex_match_id (lexer, "MIXED"))
466 *halign = TABLE_HALIGN_MIXED;
467 else if (lex_match_id (lexer, "DECIMAL"))
469 if (lex_is_number (lexer))
471 *decimal_offset = lex_number (lexer);
482 parse_valign_setting (struct lexer *lexer, enum table_valign *valign)
484 if (lex_match_id (lexer, "TOP"))
485 *valign = TABLE_VALIGN_TOP;
486 else if (lex_match_id (lexer, "MIDDLE"))
487 *valign = TABLE_VALIGN_CENTER;
488 else if (lex_match_id (lexer, "BOTTOM"))
489 *valign = TABLE_VALIGN_BOTTOM;
497 parse_margin_setting (struct lexer *lexer, int margin[TABLE_N_AXES][2])
499 if (lex_match_id (lexer, "MARGINS"))
504 lex_match (lexer, T_EQUALS);
506 while (lex_is_number (lexer) && n < 4)
508 values[n++] = lex_number (lexer);
514 margin[TABLE_HORZ][0] = margin[TABLE_HORZ][1] = values[0];
515 margin[TABLE_VERT][0] = margin[TABLE_VERT][1] = values[0];
519 margin[TABLE_HORZ][0] = margin[TABLE_HORZ][1] = values[1];
520 margin[TABLE_VERT][0] = margin[TABLE_VERT][1] = values[0];
524 margin[TABLE_VERT][0] = values[0];
525 margin[TABLE_HORZ][0] = margin[TABLE_HORZ][1] = values[1];
526 margin[TABLE_VERT][1] = values[2];
531 margin[TABLE_VERT][0] = values[0];
532 margin[TABLE_HORZ][1] = values[1];
533 margin[TABLE_VERT][1] = values[2];
534 margin[TABLE_HORZ][0] = values[3];
544 read_cell_style (struct lexer *lexer, struct cell_style *cs)
546 while (parse_halign_setting (lexer, &cs->halign, &cs->decimal_offset)
547 || parse_valign_setting (lexer, &cs->valign)
548 || parse_margin_setting (lexer, cs->margin))
553 read_value_option (struct lexer *lexer, const struct pivot_table *pt,
554 struct pivot_value *value,
555 const struct table_area_style *base_style)
557 enum settings_value_show *show
558 = (value->type == PIVOT_VALUE_NUMERIC ? &value->numeric.show
559 : value->type == PIVOT_VALUE_STRING ? &value->string.show
560 : value->type == PIVOT_VALUE_VARIABLE ? &value->variable.show
562 if (show && parse_settings_value_show (lexer, "SHOW", show))
566 = (value->type == PIVOT_VALUE_NUMERIC ? &value->numeric.var_name
567 : value->type == PIVOT_VALUE_STRING ? &value->string.var_name
569 if (var_name && parse_string_setting (lexer, "VAR", var_name))
573 = (value->type == PIVOT_VALUE_NUMERIC ? &value->numeric.value_label
574 : value->type == PIVOT_VALUE_STRING ? &value->string.value_label
575 : value->type == PIVOT_VALUE_VARIABLE ? &value->variable.var_label
577 if (label && parse_string_setting (lexer, "LABEL", label))
580 if (value->type == PIVOT_VALUE_STRING && lex_match_id (lexer, "HEX"))
582 value->string.hex = true;
586 if (value->type == PIVOT_VALUE_NUMERIC)
590 bool ok = parse_format_specifier (lexer, &fmt);
595 if (!fmt_check_output (&fmt)
596 || !fmt_check_type_compat (&fmt, VAL_NUMERIC))
599 value->numeric.format = fmt;
604 if (lex_match_id (lexer, "SUBSCRIPTS"))
606 lex_match (lexer, T_EQUALS);
608 struct pivot_value_ex *ex = pivot_value_ex_rw (value);
609 size_t allocated_subscripts = ex->n_subscripts;
610 while (lex_token (lexer) == T_STRING)
612 if (ex->n_subscripts >= allocated_subscripts)
613 ex->subscripts = x2nrealloc (ex->subscripts, &allocated_subscripts,
614 sizeof *ex->subscripts);
616 ex->subscripts[ex->n_subscripts++] = xstrdup (lex_tokcstr (lexer));
622 if (lex_match_id (lexer, "FONT") && base_style)
624 lex_match (lexer, T_EQUALS);
626 struct pivot_value_ex *ex = pivot_value_ex_rw (value);
629 ex->font_style = xmalloc (sizeof *ex->font_style);
630 font_style_copy (NULL, ex->font_style, &base_style->font_style);
632 read_font_style (lexer, ex->font_style);
636 if (lex_match_id (lexer, "CELL") && base_style)
638 lex_match (lexer, T_EQUALS);
640 struct pivot_value_ex *ex = pivot_value_ex_rw (value);
643 ex->cell_style = xmalloc (sizeof *ex->cell_style);
644 *ex->cell_style = base_style->cell_style;
646 read_cell_style (lexer, ex->cell_style);
650 if (lex_match_id (lexer, "FOOTNOTE"))
652 lex_match (lexer, T_EQUALS);
654 while (lex_is_integer (lexer))
656 size_t idx = lex_integer (lexer);
659 if (idx >= pt->n_footnotes)
661 msg (SE, "Footnote %zu not available "
662 "(only %zu footnotes defined)", idx, pt->n_footnotes);
665 pivot_value_add_footnote (value, pt->footnotes[idx]);
670 lex_error (lexer, "Syntax error expecting valid value option.");
674 static struct pivot_value *
675 read_value (struct lexer *lexer, const struct pivot_table *pt,
676 const struct table_area_style *base_style)
678 struct pivot_value *value;
679 if (lex_is_number (lexer))
681 value = pivot_value_new_number (lex_number (lexer));
684 else if (lex_is_string (lexer))
686 value = xmalloc (sizeof *value);
687 *value = (struct pivot_value) {
689 .type = PIVOT_VALUE_STRING,
690 .s = xstrdup (lex_tokcstr (lexer))
695 else if (lex_token (lexer) == T_ID)
697 value = xmalloc (sizeof *value);
698 *value = (struct pivot_value) {
700 .type = PIVOT_VALUE_VARIABLE,
701 .var_name = xstrdup (lex_tokcstr (lexer))
708 msg (SE, "Expecting pivot_value");
712 while (lex_match (lexer, T_LBRACK))
714 read_value_option (lexer, pt, value, base_style);
715 force_match (lexer, T_RBRACK);
722 read_group (struct lexer *lexer, struct pivot_table *pt,
723 struct pivot_category *group,
724 const struct table_area_style *label_style)
726 if (lex_match (lexer, T_ASTERISK))
727 group->show_label = true;
729 force_match (lexer, T_LPAREN);
730 if (lex_match (lexer, T_RPAREN))
735 struct pivot_value *name = read_value (lexer, pt, label_style);
736 if (lex_token (lexer) == T_ASTERISK
737 || lex_token (lexer) == T_LPAREN)
738 read_group (lexer, pt, pivot_category_create_group__ (group, name),
743 if (lex_token (lexer) == T_ID
744 && is_pivot_result_class (lex_tokcstr (lexer)))
746 rc = xstrdup (lex_tokcstr (lexer));
752 pivot_category_create_leaf_rc (group, name, rc);
757 while (lex_match (lexer, T_COMMA));
758 force_match (lexer, T_RPAREN);
762 read_dimension (struct lexer *lexer, struct pivot_table *pt,
763 enum pivot_axis_type a,
764 const struct table_area_style *label_style)
766 if (!pivot_table_is_empty (pt))
767 error (1, 0, "can't add dimensions after adding data");
769 lex_match (lexer, T_EQUALS);
771 struct pivot_value *name = read_value (lexer, pt, label_style);
772 struct pivot_dimension *dim = pivot_dimension_create__ (pt, a, name);
773 read_group (lexer, pt, dim->root, label_style);
777 read_look (struct lexer *lexer, struct pivot_table *pt)
779 lex_match (lexer, T_EQUALS);
781 if (lex_is_string (lexer))
783 struct pivot_table_look *look;
784 char *error = pivot_table_look_read (lex_tokcstr (lexer), &look);
787 msg (SE, "%s", error);
792 pivot_table_set_look (pt, look);
793 pivot_table_look_unref (look);
796 struct pivot_table_look *look = pivot_table_look_unshare (
797 pivot_table_look_ref (pt->look));
800 if (!parse_bool_setting (lexer, "EMPTY", "HIDE", "SHOW",
802 && !parse_bool_setting (lexer, "ROWLABELS", "CORNER", "NESTED",
803 &look->row_labels_in_corner)
804 && !parse_bool_setting (lexer, "MARKERS", "NUMERIC", "ALPHA",
805 &look->show_numeric_markers)
806 && !parse_bool_setting (lexer, "LEVEL", "SUPER", "SUB",
807 &look->footnote_marker_superscripts)
808 && !parse_bool_setting (lexer, "LAYERS", "ALL", "CURRENT",
809 &look->print_all_layers)
810 && !parse_bool_setting (lexer, "PAGINATELAYERS", "YES", "NO",
811 &look->paginate_layers)
812 && !parse_bool_setting (lexer, "HSHRINK", "YES", "NO",
813 &look->shrink_to_fit[TABLE_HORZ])
814 && !parse_bool_setting (lexer, "VSHRINK", "YES", "NO",
815 &look->shrink_to_fit[TABLE_VERT])
816 && !parse_bool_setting (lexer, "TOPCONTINUATION", "YES", "NO",
817 &look->top_continuation)
818 && !parse_bool_setting (lexer, "BOTTOMCONTINUATION", "YES", "NO",
819 &look->bottom_continuation)
820 && !parse_string_setting (lexer, "CONTINUATION",
821 &look->continuation))
824 pivot_table_set_look (pt, look);
825 pivot_table_look_unref (look);
828 static enum table_stroke
829 read_stroke (struct lexer *lexer)
831 for (int stroke = 0; stroke < TABLE_N_STROKES; stroke++)
832 if (lex_match_id (lexer, table_stroke_to_string (stroke)))
835 lex_error (lexer, "Syntax error expecting stroke.");
840 parse_value_setting (struct lexer *lexer, const struct pivot_table *pt,
842 struct pivot_value **valuep,
843 struct table_area_style *base_style)
845 if (lex_match_id (lexer, name))
847 lex_match (lexer, T_EQUALS);
849 pivot_value_destroy (*valuep);
850 *valuep = read_value (lexer, pt, base_style);
859 read_border (struct lexer *lexer, struct pivot_table *pt)
861 static const char *const pivot_border_ids[PIVOT_N_BORDERS] = {
862 [PIVOT_BORDER_TITLE] = "title",
863 [PIVOT_BORDER_OUTER_LEFT] = "outer-left",
864 [PIVOT_BORDER_OUTER_TOP] = "outer-top",
865 [PIVOT_BORDER_OUTER_RIGHT] = "outer-right",
866 [PIVOT_BORDER_OUTER_BOTTOM] = "outer-bottom",
867 [PIVOT_BORDER_INNER_LEFT] = "inner-left",
868 [PIVOT_BORDER_INNER_TOP] = "inner-top",
869 [PIVOT_BORDER_INNER_RIGHT] = "inner-right",
870 [PIVOT_BORDER_INNER_BOTTOM] = "inner-bottom",
871 [PIVOT_BORDER_DATA_LEFT] = "data-left",
872 [PIVOT_BORDER_DATA_TOP] = "data-top",
873 [PIVOT_BORDER_DIM_ROW_HORZ] = "dim-row-horz",
874 [PIVOT_BORDER_DIM_ROW_VERT] = "dim-row-vert",
875 [PIVOT_BORDER_DIM_COL_HORZ] = "dim-col-horz",
876 [PIVOT_BORDER_DIM_COL_VERT] = "dim-col-vert",
877 [PIVOT_BORDER_CAT_ROW_HORZ] = "cat-row-horz",
878 [PIVOT_BORDER_CAT_ROW_VERT] = "cat-row-vert",
879 [PIVOT_BORDER_CAT_COL_HORZ] = "cat-col-horz",
880 [PIVOT_BORDER_CAT_COL_VERT] = "cat-col-vert",
883 lex_match (lexer, T_EQUALS);
885 struct pivot_table_look *look = pivot_table_look_unshare (
886 pivot_table_look_ref (pt->look));
887 while (lex_token (lexer) == T_STRING)
889 char *s = xstrdup (lex_tokcstr (lexer));
891 force_match (lexer, T_LPAREN);
893 struct table_border_style style = TABLE_BORDER_STYLE_INITIALIZER;
894 style.stroke = read_stroke (lexer);
895 if (lex_is_string (lexer))
896 style.color = read_color (lexer);
897 force_match (lexer, T_RPAREN);
900 for (int b = 0; b < PIVOT_N_BORDERS; b++)
902 if (!fnmatch (s, pivot_border_ids[b], 0))
904 look->borders[b] = style;
910 msg (SE, "%s: no matching borders", s);
915 pivot_table_set_look (pt, look);
916 pivot_table_look_unref (look);
920 read_footnote (struct lexer *lexer, struct pivot_table *pt)
923 if (lex_match (lexer, T_LBRACK))
927 idx = lex_integer (lexer);
930 force_match (lexer, T_RBRACK);
933 idx = pt->n_footnotes;
934 lex_match (lexer, T_EQUALS);
936 struct pivot_value *content
937 = read_value (lexer, pt, &pt->look->areas[PIVOT_AREA_FOOTER]);
939 struct pivot_value *marker;
940 if (lex_match_id (lexer, "MARKER"))
942 lex_match (lexer, T_EQUALS);
943 marker = read_value (lexer, pt, &pt->look->areas[PIVOT_AREA_FOOTER]);
948 bool show = !lex_match_id (lexer, "HIDE");
949 pivot_table_create_footnote__ (pt, idx, marker, content)->show = show;
953 read_cell (struct lexer *lexer, struct pivot_table *pt)
955 force_match (lexer, T_LBRACK);
957 size_t *lo = xnmalloc (pt->n_dimensions, sizeof *lo);
958 size_t *hi = xnmalloc (pt->n_dimensions, sizeof *hi);
959 for (size_t i = 0; i < pt->n_dimensions; i++)
961 const struct pivot_dimension *d = pt->dimensions[i];
964 force_match (lexer, T_COMMA);
968 msg (SE, "can't define data because dimension %zu has no categories",
973 if (lex_match (lexer, T_ALL))
976 hi[i] = d->n_leaves - 1;
981 lo[i] = hi[i] = lex_integer (lexer);
984 if (lex_match_id (lexer, "THRU"))
987 hi[i] = lex_integer (lexer);
993 msg (SE, "%zu THRU %zu is not a valid range", lo[i], hi[i]);
996 if (hi[i] >= d->n_leaves)
998 msg (SE, "dimension %zu (%s) has only %zu categories",
999 i, pivot_value_to_string (d->root->name, pt),
1005 force_match (lexer, T_RBRACK);
1007 struct pivot_value *value = NULL;
1008 bool delete = false;
1009 if (lex_match (lexer, T_EQUALS))
1011 if (lex_match_id (lexer, "DELETE"))
1014 value = read_value (lexer, pt, &pt->look->areas[PIVOT_AREA_DATA]);
1017 size_t *dindexes = xmemdup (lo, pt->n_dimensions * sizeof *lo);
1018 for (size_t i = 0; ; i++)
1021 pivot_table_delete (pt, dindexes);
1023 pivot_table_put (pt, dindexes, pt->n_dimensions,
1025 ? pivot_value_clone (value)
1026 : pivot_value_new_integer (i)));
1028 for (size_t j = 0; j < pt->n_dimensions; j++)
1030 if (++dindexes[j] <= hi[j])
1032 dindexes[j] = lo[j];
1039 pivot_value_destroy (value);
1045 static struct pivot_dimension *
1046 parse_dim_name (struct lexer *lexer, struct pivot_table *table)
1048 force_string (lexer);
1049 for (size_t i = 0; i < table->n_dimensions; i++)
1051 struct pivot_dimension *dim = table->dimensions[i];
1053 struct string s = DS_EMPTY_INITIALIZER;
1054 pivot_value_format_body (dim->root->name, table, &s);
1055 bool match = !strcmp (ds_cstr (&s), lex_tokcstr (lexer));
1065 lex_error (lexer, "unknown dimension");
1069 static enum pivot_axis_type
1070 parse_axis_type (struct lexer *lexer)
1072 if (lex_match_id (lexer, "ROW"))
1073 return PIVOT_AXIS_ROW;
1074 else if (lex_match_id (lexer, "COLUMN"))
1075 return PIVOT_AXIS_COLUMN;
1076 else if (lex_match_id (lexer, "LAYER"))
1077 return PIVOT_AXIS_LAYER;
1080 lex_error_expecting (lexer, "ROW", "COLUMN", "LAYER");
1086 move_dimension (struct lexer *lexer, struct pivot_table *table)
1088 struct pivot_dimension *dim = parse_dim_name (lexer, table);
1090 enum pivot_axis_type axis = parse_axis_type (lexer);
1093 if (lex_is_integer (lexer))
1095 position = lex_integer (lexer);
1101 pivot_table_move_dimension (table, dim, axis, position);
1105 swap_axes (struct lexer *lexer, struct pivot_table *table)
1107 enum pivot_axis_type a = parse_axis_type (lexer);
1108 enum pivot_axis_type b = parse_axis_type (lexer);
1109 pivot_table_swap_axes (table, a, b);
1113 read_current_layer (struct lexer *lexer, struct pivot_table *table)
1115 lex_match (lexer, T_EQUALS);
1117 const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
1118 for (size_t i = 0; i < layer_axis->n_dimensions; i++)
1120 const struct pivot_dimension *dim = layer_axis->dimensions[i];
1123 size_t index = lex_integer (lexer);
1124 if (index >= dim->n_leaves)
1126 lex_error (lexer, "only %zu dimensions", dim->n_leaves);
1131 table->current_layer[i] = index;
1136 read_table (struct lexer *lexer)
1138 bool displayed = false;
1140 struct pivot_table *pt = pivot_table_create ("Default Title");
1141 while (lex_match (lexer, T_SLASH))
1143 assert (!pivot_table_is_shared (pt));
1146 if (lex_match_id (lexer, "ROW"))
1147 read_dimension (lexer, pt, PIVOT_AXIS_ROW,
1148 &pt->look->areas[PIVOT_AREA_ROW_LABELS]);
1149 else if (lex_match_id (lexer, "COLUMN"))
1150 read_dimension (lexer, pt, PIVOT_AXIS_COLUMN,
1151 &pt->look->areas[PIVOT_AREA_COLUMN_LABELS]);
1152 else if (lex_match_id (lexer, "LAYER"))
1153 read_dimension (lexer, pt, PIVOT_AXIS_LAYER,
1154 &pt->look->areas[PIVOT_AREA_LAYERS]);
1155 else if (lex_match_id (lexer, "LOOK"))
1156 read_look (lexer, pt);
1157 else if (lex_match_id (lexer, "ROTATE"))
1159 lex_match (lexer, T_EQUALS);
1160 while (lex_token (lexer) == T_ID)
1161 if (!parse_bool_setting (lexer, "INNERCOLUMNS", "YES", "NO",
1162 &pt->rotate_inner_column_labels)
1163 && !parse_bool_setting (lexer, "OUTERROWS", "YES", "NO",
1164 &pt->rotate_outer_row_labels))
1167 else if (lex_match_id (lexer, "SHOW"))
1169 lex_match (lexer, T_EQUALS);
1170 while (lex_token (lexer) == T_ID)
1172 if (parse_bool_setting (lexer, "GRID", "YES", "NO",
1173 &pt->show_grid_lines)
1174 || parse_bool_setting (lexer, "CAPTION", "YES", "NO",
1176 || parse_bool_setting (lexer, "TITLE", "YES", "NO",
1180 if (parse_settings_value_show (lexer, "VALUES", &pt->show_values)
1181 || parse_settings_value_show (lexer, "VARIABLES",
1182 &pt->show_variables))
1185 if (lex_match_id (lexer, "LAYER"))
1186 read_current_layer (lexer, pt);
1191 else if (parse_value_setting (lexer, pt, "TITLE", &pt->title,
1192 &pt->look->areas[PIVOT_AREA_TITLE])
1193 || parse_value_setting (lexer, pt, "SUBTYPE", &pt->subtype,
1195 || parse_value_setting (lexer, pt, "CORNER", &pt->corner_text,
1196 &pt->look->areas[PIVOT_AREA_CORNER])
1197 || parse_value_setting (lexer, pt, "CAPTION", &pt->caption,
1198 &pt->look->areas[PIVOT_AREA_CAPTION])
1199 || parse_string_setting (lexer, "NOTES", &pt->notes))
1203 else if (lex_match_id (lexer, "BORDER"))
1204 read_border (lexer, pt);
1205 else if (lex_match_id (lexer, "TRANSPOSE"))
1206 pivot_table_transpose (pt);
1207 else if (lex_match_id (lexer, "SWAP"))
1208 swap_axes (lexer, pt);
1209 else if (lex_match_id (lexer, "MOVE"))
1210 move_dimension (lexer, pt);
1211 else if (lex_match_id (lexer, "CELLS"))
1212 read_cell (lexer, pt);
1213 else if (lex_match_id (lexer, "FOOTNOTE"))
1214 read_footnote (lexer, pt);
1215 else if (lex_match_id (lexer, "DUMP"))
1216 pivot_table_dump (pt, 0);
1217 else if (lex_match_id (lexer, "DISPLAY"))
1219 pivot_table_submit (pivot_table_ref (pt));
1220 pt = pivot_table_unshare (pt);
1225 msg (SE, "Expecting keyword");
1231 pivot_table_submit (pt);
1233 pivot_table_unref (pt);
1235 force_match (lexer, T_ENDCMD);
1239 output_msg (const struct msg *m_, struct lexer *lexer)
1242 .category = m_->category,
1243 .severity = m_->severity,
1244 .location = (m_->location ? m_->location
1245 : lexer ? lex_get_location (lexer, 0, 0)
1247 .command_name = output_get_uppercase_command_name (),
1251 output_item_submit (message_item_create (&m));
1253 free (m.command_name);
1254 if (m.location != m_->location)
1255 msg_location_destroy (m.location);