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/message-item.h"
36 #include "output/options.h"
37 #include "output/pivot-table.h"
38 #include "output/table-item.h"
41 #include "gl/progname.h"
42 #include "gl/xalloc.h"
43 #include "gl/xvasprintf.h"
45 /* --emphasis: Enable emphasis in ASCII driver? */
48 /* --box: ASCII driver box option. */
51 /* -o, --output: Base name for output files. */
52 static const char *output_base
= "render";
54 static const char *parse_options (int argc
, char **argv
);
55 static void usage (void) NO_RETURN
;
56 static void read_table (struct lexer
*);
57 static void output_msg (const struct msg
*, void *);
60 main (int argc
, char **argv
)
62 const char *input_file_name
;
64 set_program_name (argv
[0]);
66 output_engine_push ();
67 input_file_name
= parse_options (argc
, argv
);
71 struct lex_reader
*reader
= lex_reader_for_file (input_file_name
, NULL
,
77 struct lexer
*lexer
= lex_create ();
78 msg_set_handler (output_msg
, lexer
);
79 lex_include (lexer
, reader
);
84 while (lex_match (lexer
, T_ENDCMD
))
86 if (lex_match (lexer
, T_STOP
))
99 static void PRINTF_FORMAT (2, 3)
100 register_driver (struct string_map
*options
,
101 const char *output_file
, ...)
104 va_start (args
, output_file
);
105 string_map_insert_nocopy (options
, xstrdup ("output-file"),
106 xvasprintf (output_file
, args
));
109 struct output_driver
*driver
= output_driver_create (options
);
112 output_driver_register (driver
);
116 configure_drivers (int width
, int length UNUSED
, int min_break
)
118 /* Render to stdout. */
119 struct string_map options
= STRING_MAP_INITIALIZER (options
);
120 string_map_insert (&options
, "format", "txt");
121 string_map_insert_nocopy (&options
, xstrdup ("width"),
122 xasprintf ("%d", width
));
124 string_map_insert_nocopy (&options
, xstrdup ("min-hbreak"),
125 xasprintf ("%d", min_break
));
126 string_map_insert (&options
, "emphasis", emphasis
? "true" : "false");
128 string_map_insert (&options
, "box", box
);
129 register_driver (&options
, "-");
133 /* Render to <base>.pdf. */
134 string_map_insert (&options
, "top-margin", "0");
135 string_map_insert (&options
, "bottom-margin", "0");
136 string_map_insert (&options
, "left-margin", "0");
137 string_map_insert (&options
, "right-margin", "0");
138 string_map_insert (&options
, "paper-size", "99x99in");
139 string_map_insert (&options
, "trim", "true");
140 register_driver (&options
, "%s.pdf", output_base
);
143 string_map_insert (&options
, "box", "unicode");
144 register_driver (&options
, "%s.txt", output_base
);
146 string_map_insert (&options
, "box", "ascii");
147 register_driver (&options
, "%s-ascii.txt", output_base
);
149 register_driver (&options
, "%s.csv", output_base
);
150 register_driver (&options
, "%s.odt", output_base
);
151 register_driver (&options
, "%s.spv", output_base
);
152 register_driver (&options
, "%s.html", output_base
);
153 register_driver (&options
, "%s.tex", output_base
);
155 string_map_destroy (&options
);
159 parse_options (int argc
, char **argv
)
168 OPT_WIDTH
= UCHAR_MAX
+ 1,
176 static const struct option options
[] =
178 {"width", required_argument
, NULL
, OPT_WIDTH
},
179 {"length", required_argument
, NULL
, OPT_LENGTH
},
180 {"min-break", required_argument
, NULL
, OPT_MIN_BREAK
},
181 {"emphasis", no_argument
, NULL
, OPT_EMPHASIS
},
182 {"box", required_argument
, NULL
, OPT_BOX
},
183 {"output", required_argument
, NULL
, 'o'},
184 {"table-look", required_argument
, NULL
, OPT_TABLE_LOOK
},
185 {"help", no_argument
, NULL
, OPT_HELP
},
189 int c
= getopt_long (argc
, argv
, "o:", options
, NULL
);
196 width
= atoi (optarg
);
200 length
= atoi (optarg
);
204 min_break
= atoi (optarg
);
216 output_base
= optarg
;
221 struct pivot_table_look
*look
;
222 char *err
= pivot_table_look_read (optarg
, &look
);
224 error (1, 0, "%s", err
);
225 pivot_table_look_set_default (look
);
226 pivot_table_look_unref (look
);
246 configure_drivers (width
, length
, min_break
);
248 if (optind
+ 1 != argc
)
249 error (1, 0, "exactly one non-option argument required; "
250 "use --help for help");
257 printf ("%s, to test rendering of PSPP tables\n"
258 "usage: %s [OPTIONS] INPUT\n"
260 " --width=WIDTH set page width in characters\n"
261 " --length=LINE set page length in lines\n",
262 program_name
, program_name
);
267 force_match (struct lexer
*lexer
, enum token_type type
)
269 if (!lex_force_match (lexer
, type
))
274 force_string (struct lexer
*lexer
)
276 if (!lex_force_string (lexer
))
281 force_int (struct lexer
*lexer
)
283 if (!lex_force_int (lexer
))
288 force_num (struct lexer
*lexer
)
290 if (!lex_force_num (lexer
))
295 parse_settings_value_show (struct lexer
*lexer
, const char *name
,
296 enum settings_value_show
*show
)
298 if (lex_match_id (lexer
, name
))
300 lex_match (lexer
, T_EQUALS
);
302 if (lex_match_id (lexer
, "DEFAULT"))
303 *show
= SETTINGS_VALUE_SHOW_DEFAULT
;
304 else if (lex_match_id (lexer
, "VALUE"))
305 *show
= SETTINGS_VALUE_SHOW_VALUE
;
306 else if (lex_match_id (lexer
, "LABEL"))
307 *show
= SETTINGS_VALUE_SHOW_LABEL
;
308 else if (lex_match_id (lexer
, "BOTH"))
309 *show
= SETTINGS_VALUE_SHOW_BOTH
;
312 lex_error_expecting (lexer
, "DEFAULT", "VALUE", "LABEL", "BOTH");
323 parse_string_setting (struct lexer
*lexer
, const char *name
, char **stringp
)
325 if (lex_match_id (lexer
, name
))
327 lex_match (lexer
, T_EQUALS
);
328 force_string (lexer
);
331 *stringp
= xstrdup (lex_tokcstr (lexer
));
341 match_kw (struct lexer
*lexer
, const char *kw
)
343 return (!strcmp (kw
, "ALL")
344 ? lex_match (lexer
, T_ALL
)
345 : lex_match_id (lexer
, kw
));
349 parse_bool_setting_with_default (struct lexer
*lexer
, const char *name
,
350 const char *true_kw
, const char *false_kw
,
351 int default_value
, bool *out
)
353 if (lex_match_id (lexer
, name
))
355 if (default_value
>= 0)
357 if (!lex_match (lexer
, T_EQUALS
))
358 *out
= default_value
;
362 force_match (lexer
, T_EQUALS
);
364 if (match_kw (lexer
, true_kw
))
366 else if (match_kw (lexer
, false_kw
))
370 lex_error_expecting (lexer
, true_kw
, false_kw
);
381 parse_bool_setting (struct lexer
*lexer
, const char *name
,
382 const char *true_kw
, const char *false_kw
,
385 return parse_bool_setting_with_default (lexer
, name
, true_kw
, false_kw
, -1,
390 parse_yesno_setting (struct lexer
*lexer
, const char *name
, bool *out
)
392 return parse_bool_setting_with_default (lexer
, name
, "YES", "NO", true, out
);
395 static struct cell_color
396 read_color (struct lexer
*lexer
)
398 struct cell_color color
;
399 if (!parse_color__ (lex_tokcstr (lexer
), &color
))
401 msg (SE
, "%s: unknown color", lex_tokcstr (lexer
));
409 parse_color_pair_setting (struct lexer
*lexer
, const char *name
,
410 struct cell_color out
[2])
412 if (lex_match_id (lexer
, name
))
414 lex_match (lexer
, T_EQUALS
);
415 out
[0] = read_color (lexer
);
416 out
[1] = lex_is_string (lexer
) ? read_color (lexer
) : out
[0];
424 parse_int_setting (struct lexer
*lexer
, const char *name
, int *out
)
426 if (lex_match_id (lexer
, name
))
428 lex_match (lexer
, T_EQUALS
);
430 *out
= lex_integer (lexer
);
439 read_font_style (struct lexer
*lexer
, struct font_style
*fs
)
441 while (parse_yesno_setting (lexer
, "BOLD", &fs
->bold
)
442 || parse_yesno_setting (lexer
, "ITALIC", &fs
->italic
)
443 || parse_yesno_setting (lexer
, "UNDERLINE", &fs
->underline
)
444 || parse_yesno_setting (lexer
, "MARKUP", &fs
->markup
)
445 || parse_color_pair_setting (lexer
, "FG", fs
->fg
)
446 || parse_color_pair_setting (lexer
, "BG", fs
->bg
)
447 || parse_string_setting (lexer
, "FACE", &fs
->typeface
)
448 || parse_int_setting (lexer
, "SIZE", &fs
->size
))
453 parse_halign_setting (struct lexer
*lexer
, enum table_halign
*halign
,
454 double *decimal_offset
)
456 if (lex_match_id (lexer
, "RIGHT"))
457 *halign
= TABLE_HALIGN_RIGHT
;
458 else if (lex_match_id (lexer
, "LEFT"))
459 *halign
= TABLE_HALIGN_LEFT
;
460 else if (lex_match_id (lexer
, "CELL"))
461 *halign
= TABLE_HALIGN_CENTER
;
462 else if (lex_match_id (lexer
, "MIXED"))
463 *halign
= TABLE_HALIGN_MIXED
;
464 else if (lex_match_id (lexer
, "DECIMAL"))
466 if (lex_is_number (lexer
))
468 *decimal_offset
= lex_number (lexer
);
479 parse_valign_setting (struct lexer
*lexer
, enum table_valign
*valign
)
481 if (lex_match_id (lexer
, "TOP"))
482 *valign
= TABLE_VALIGN_TOP
;
483 else if (lex_match_id (lexer
, "MIDDLE"))
484 *valign
= TABLE_VALIGN_CENTER
;
485 else if (lex_match_id (lexer
, "BOTTOM"))
486 *valign
= TABLE_VALIGN_BOTTOM
;
494 parse_margin_setting (struct lexer
*lexer
, int margin
[TABLE_N_AXES
][2])
496 if (lex_match_id (lexer
, "MARGINS"))
501 lex_match (lexer
, T_EQUALS
);
503 while (lex_is_number (lexer
) && n
< 4)
505 values
[n
++] = lex_number (lexer
);
511 margin
[TABLE_HORZ
][0] = margin
[TABLE_HORZ
][1] = values
[0];
512 margin
[TABLE_VERT
][0] = margin
[TABLE_VERT
][1] = values
[0];
516 margin
[TABLE_HORZ
][0] = margin
[TABLE_HORZ
][1] = values
[1];
517 margin
[TABLE_VERT
][0] = margin
[TABLE_VERT
][1] = values
[0];
521 margin
[TABLE_VERT
][0] = values
[0];
522 margin
[TABLE_HORZ
][0] = margin
[TABLE_HORZ
][1] = values
[1];
523 margin
[TABLE_VERT
][1] = values
[2];
528 margin
[TABLE_VERT
][0] = values
[0];
529 margin
[TABLE_HORZ
][1] = values
[1];
530 margin
[TABLE_VERT
][1] = values
[2];
531 margin
[TABLE_HORZ
][0] = values
[3];
541 read_cell_style (struct lexer
*lexer
, struct cell_style
*cs
)
543 while (parse_halign_setting (lexer
, &cs
->halign
, &cs
->decimal_offset
)
544 || parse_valign_setting (lexer
, &cs
->valign
)
545 || parse_margin_setting (lexer
, cs
->margin
))
550 read_value_option (struct lexer
*lexer
, const struct pivot_table
*pt
,
551 struct pivot_value
*value
,
552 const struct table_area_style
*base_style
)
554 enum settings_value_show
*show
555 = (value
->type
== PIVOT_VALUE_NUMERIC
? &value
->numeric
.show
556 : value
->type
== PIVOT_VALUE_STRING
? &value
->string
.show
557 : value
->type
== PIVOT_VALUE_VARIABLE
? &value
->variable
.show
559 if (show
&& parse_settings_value_show (lexer
, "SHOW", show
))
563 = (value
->type
== PIVOT_VALUE_NUMERIC
? &value
->numeric
.var_name
564 : value
->type
== PIVOT_VALUE_STRING
? &value
->string
.var_name
566 if (var_name
&& parse_string_setting (lexer
, "VAR", var_name
))
570 = (value
->type
== PIVOT_VALUE_NUMERIC
? &value
->numeric
.value_label
571 : value
->type
== PIVOT_VALUE_STRING
? &value
->string
.value_label
572 : value
->type
== PIVOT_VALUE_VARIABLE
? &value
->variable
.var_label
574 if (label
&& parse_string_setting (lexer
, "LABEL", label
))
577 if (value
->type
== PIVOT_VALUE_STRING
&& lex_match_id (lexer
, "HEX"))
579 value
->string
.hex
= true;
583 if (value
->type
== PIVOT_VALUE_NUMERIC
)
587 bool ok
= parse_format_specifier (lexer
, &fmt
);
592 if (!fmt_check_output (&fmt
)
593 || !fmt_check_type_compat (&fmt
, VAL_NUMERIC
))
596 value
->numeric
.format
= fmt
;
601 if (lex_match_id (lexer
, "SUBSCRIPTS"))
603 lex_match (lexer
, T_EQUALS
);
604 size_t allocated_subscripts
= value
->n_subscripts
;
605 while (lex_token (lexer
) == T_STRING
)
607 if (value
->n_subscripts
>= allocated_subscripts
)
608 value
->subscripts
= x2nrealloc (value
->subscripts
,
609 &allocated_subscripts
,
610 sizeof *value
->subscripts
);
612 value
->subscripts
[value
->n_subscripts
++] = xstrdup (
613 lex_tokcstr (lexer
));
619 if (lex_match_id (lexer
, "FONT") && base_style
)
621 lex_match (lexer
, T_EQUALS
);
623 if (!value
->font_style
)
625 value
->font_style
= xmalloc (sizeof *value
->font_style
);
626 font_style_copy (NULL
, value
->font_style
, &base_style
->font_style
);
628 read_font_style (lexer
, value
->font_style
);
632 if (lex_match_id (lexer
, "CELL") && base_style
)
634 lex_match (lexer
, T_EQUALS
);
636 if (!value
->cell_style
)
638 value
->cell_style
= xmalloc (sizeof *value
->cell_style
);
639 *value
->cell_style
= base_style
->cell_style
;
641 read_cell_style (lexer
, value
->cell_style
);
645 if (lex_match_id (lexer
, "FOOTNOTE"))
647 lex_match (lexer
, T_EQUALS
);
649 while (lex_is_integer (lexer
))
651 size_t idx
= lex_integer (lexer
);
654 if (idx
>= pt
->n_footnotes
)
656 msg (SE
, "Footnote %zu not available "
657 "(only %zu footnotes defined)", idx
, pt
->n_footnotes
);
660 pivot_value_add_footnote (value
, pt
->footnotes
[idx
]);
665 lex_error (lexer
, "Expecting valid value option");
669 static struct pivot_value
*
670 read_value (struct lexer
*lexer
, const struct pivot_table
*pt
,
671 const struct table_area_style
*base_style
)
673 struct pivot_value
*value
;
674 if (lex_is_number (lexer
))
676 value
= pivot_value_new_number (lex_number (lexer
));
679 else if (lex_is_string (lexer
))
681 value
= xmalloc (sizeof *value
);
682 *value
= (struct pivot_value
) {
683 .type
= PIVOT_VALUE_STRING
,
684 .string
= { .s
= xstrdup (lex_tokcstr (lexer
)) },
688 else if (lex_token (lexer
) == T_ID
)
690 value
= xmalloc (sizeof *value
);
691 *value
= (struct pivot_value
) {
692 .type
= PIVOT_VALUE_VARIABLE
,
693 .variable
= { .var_name
= xstrdup (lex_tokcstr (lexer
)) },
699 msg (SE
, "Expecting pivot_value");
703 while (lex_match (lexer
, T_LBRACK
))
705 read_value_option (lexer
, pt
, value
, base_style
);
706 force_match (lexer
, T_RBRACK
);
713 read_group (struct lexer
*lexer
, struct pivot_table
*pt
,
714 struct pivot_category
*group
,
715 const struct table_area_style
*label_style
)
717 if (lex_match (lexer
, T_ASTERISK
))
718 group
->show_label
= true;
720 force_match (lexer
, T_LPAREN
);
721 if (lex_match (lexer
, T_RPAREN
))
726 struct pivot_value
*name
= read_value (lexer
, pt
, label_style
);
727 if (lex_token (lexer
) == T_ASTERISK
728 || lex_token (lexer
) == T_LPAREN
)
729 read_group (lexer
, pt
, pivot_category_create_group__ (group
, name
),
734 if (lex_token (lexer
) == T_ID
735 && is_pivot_result_class (lex_tokcstr (lexer
)))
737 rc
= xstrdup (lex_tokcstr (lexer
));
743 pivot_category_create_leaf_rc (group
, name
, rc
);
748 while (lex_match (lexer
, T_COMMA
));
749 force_match (lexer
, T_RPAREN
);
753 read_dimension (struct lexer
*lexer
, struct pivot_table
*pt
,
754 enum pivot_axis_type a
,
755 const struct table_area_style
*label_style
)
757 if (!pivot_table_is_empty (pt
))
758 error (1, 0, "can't add dimensions after adding data");
760 lex_match (lexer
, T_EQUALS
);
762 struct pivot_value
*name
= read_value (lexer
, pt
, label_style
);
763 struct pivot_dimension
*dim
= pivot_dimension_create__ (pt
, a
, name
);
764 read_group (lexer
, pt
, dim
->root
, label_style
);
768 read_look (struct lexer
*lexer
, struct pivot_table
*pt
)
770 lex_match (lexer
, T_EQUALS
);
772 if (lex_is_string (lexer
))
774 struct pivot_table_look
*look
;
775 char *error
= pivot_table_look_read (lex_tokcstr (lexer
), &look
);
778 msg (SE
, "%s", error
);
783 pivot_table_set_look (pt
, look
);
784 pivot_table_look_unref (look
);
787 struct pivot_table_look
*look
= pivot_table_look_unshare (
788 pivot_table_look_ref (pt
->look
));
791 if (!parse_bool_setting (lexer
, "EMPTY", "HIDE", "SHOW",
793 && !parse_bool_setting (lexer
, "ROWLABELS", "CORNER", "NESTED",
794 &look
->row_labels_in_corner
)
795 && !parse_bool_setting (lexer
, "MARKERS", "NUMERIC", "ALPHA",
796 &look
->show_numeric_markers
)
797 && !parse_bool_setting (lexer
, "LEVEL", "SUPER", "SUB",
798 &look
->footnote_marker_superscripts
)
799 && !parse_bool_setting (lexer
, "LAYERS", "ALL", "CURRENT",
800 &look
->print_all_layers
)
801 && !parse_bool_setting (lexer
, "PAGINATELAYERS", "YES", "NO",
802 &look
->paginate_layers
)
803 && !parse_bool_setting (lexer
, "HSHRINK", "YES", "NO",
804 &look
->shrink_to_fit
[TABLE_HORZ
])
805 && !parse_bool_setting (lexer
, "VSHRINK", "YES", "NO",
806 &look
->shrink_to_fit
[TABLE_VERT
])
807 && !parse_bool_setting (lexer
, "TOPCONTINUATION", "YES", "NO",
808 &look
->top_continuation
)
809 && !parse_bool_setting (lexer
, "BOTTOMCONTINUATION", "YES", "NO",
810 &look
->bottom_continuation
)
811 && !parse_string_setting (lexer
, "CONTINUATION",
812 &look
->continuation
))
815 pivot_table_set_look (pt
, look
);
816 pivot_table_look_unref (look
);
819 static enum table_stroke
820 read_stroke (struct lexer
*lexer
)
822 for (int stroke
= 0; stroke
< TABLE_N_STROKES
; stroke
++)
823 if (lex_match_id (lexer
, table_stroke_to_string (stroke
)))
826 lex_error (lexer
, "expecting stroke");
831 parse_value_setting (struct lexer
*lexer
, const struct pivot_table
*pt
,
833 struct pivot_value
**valuep
,
834 struct table_area_style
*base_style
)
836 if (lex_match_id (lexer
, name
))
838 lex_match (lexer
, T_EQUALS
);
840 pivot_value_destroy (*valuep
);
841 *valuep
= read_value (lexer
, pt
, base_style
);
850 read_border (struct lexer
*lexer
, struct pivot_table
*pt
)
852 static const char *const pivot_border_ids
[PIVOT_N_BORDERS
] = {
853 [PIVOT_BORDER_TITLE
] = "title",
854 [PIVOT_BORDER_OUTER_LEFT
] = "outer-left",
855 [PIVOT_BORDER_OUTER_TOP
] = "outer-top",
856 [PIVOT_BORDER_OUTER_RIGHT
] = "outer-right",
857 [PIVOT_BORDER_OUTER_BOTTOM
] = "outer-bottom",
858 [PIVOT_BORDER_INNER_LEFT
] = "inner-left",
859 [PIVOT_BORDER_INNER_TOP
] = "inner-top",
860 [PIVOT_BORDER_INNER_RIGHT
] = "inner-right",
861 [PIVOT_BORDER_INNER_BOTTOM
] = "inner-bottom",
862 [PIVOT_BORDER_DATA_LEFT
] = "data-left",
863 [PIVOT_BORDER_DATA_TOP
] = "data-top",
864 [PIVOT_BORDER_DIM_ROW_HORZ
] = "dim-row-horz",
865 [PIVOT_BORDER_DIM_ROW_VERT
] = "dim-row-vert",
866 [PIVOT_BORDER_DIM_COL_HORZ
] = "dim-col-horz",
867 [PIVOT_BORDER_DIM_COL_VERT
] = "dim-col-vert",
868 [PIVOT_BORDER_CAT_ROW_HORZ
] = "cat-row-horz",
869 [PIVOT_BORDER_CAT_ROW_VERT
] = "cat-row-vert",
870 [PIVOT_BORDER_CAT_COL_HORZ
] = "cat-col-horz",
871 [PIVOT_BORDER_CAT_COL_VERT
] = "cat-col-vert",
874 lex_match (lexer
, T_EQUALS
);
876 struct pivot_table_look
*look
= pivot_table_look_unshare (
877 pivot_table_look_ref (pt
->look
));
878 while (lex_token (lexer
) == T_STRING
)
880 char *s
= xstrdup (lex_tokcstr (lexer
));
882 force_match (lexer
, T_LPAREN
);
884 struct table_border_style style
= TABLE_BORDER_STYLE_INITIALIZER
;
885 style
.stroke
= read_stroke (lexer
);
886 if (lex_is_string (lexer
))
887 style
.color
= read_color (lexer
);
888 force_match (lexer
, T_RPAREN
);
891 for (int b
= 0; b
< PIVOT_N_BORDERS
; b
++)
893 if (!fnmatch (s
, pivot_border_ids
[b
], 0))
895 look
->borders
[b
] = style
;
901 msg (SE
, "%s: no matching borders", s
);
906 pivot_table_set_look (pt
, look
);
907 pivot_table_look_unref (look
);
911 read_footnote (struct lexer
*lexer
, struct pivot_table
*pt
)
914 if (lex_match (lexer
, T_LBRACK
))
918 idx
= lex_integer (lexer
);
921 force_match (lexer
, T_RBRACK
);
924 idx
= pt
->n_footnotes
;
925 lex_match (lexer
, T_EQUALS
);
927 struct pivot_value
*content
928 = read_value (lexer
, pt
, &pt
->look
->areas
[PIVOT_AREA_FOOTER
]);
930 struct pivot_value
*marker
;
931 if (lex_match_id (lexer
, "MARKER"))
933 lex_match (lexer
, T_EQUALS
);
934 marker
= read_value (lexer
, pt
, &pt
->look
->areas
[PIVOT_AREA_FOOTER
]);
939 pivot_table_create_footnote__ (pt
, idx
, marker
, content
);
943 read_cell (struct lexer
*lexer
, struct pivot_table
*pt
)
945 force_match (lexer
, T_LBRACK
);
947 size_t *lo
= xnmalloc (pt
->n_dimensions
, sizeof *lo
);
948 size_t *hi
= xnmalloc (pt
->n_dimensions
, sizeof *hi
);
949 for (size_t i
= 0; i
< pt
->n_dimensions
; i
++)
951 const struct pivot_dimension
*d
= pt
->dimensions
[i
];
954 force_match (lexer
, T_COMMA
);
958 msg (SE
, "can't define data because dimension %zu has no categories",
963 if (lex_match (lexer
, T_ALL
))
966 hi
[i
] = d
->n_leaves
- 1;
971 lo
[i
] = hi
[i
] = lex_integer (lexer
);
974 if (lex_match_id (lexer
, "THRU"))
977 hi
[i
] = lex_integer (lexer
);
983 msg (SE
, "%zu THRU %zu is not a valid range", lo
[i
], hi
[i
]);
986 if (hi
[i
] >= d
->n_leaves
)
988 msg (SE
, "dimension %zu (%s) has only %zu categories",
989 i
, pivot_value_to_string (d
->root
->name
, pt
),
995 force_match (lexer
, T_RBRACK
);
997 struct pivot_value
*value
= NULL
;
999 if (lex_match (lexer
, T_EQUALS
))
1001 if (lex_match_id (lexer
, "DELETE"))
1004 value
= read_value (lexer
, pt
, &pt
->look
->areas
[PIVOT_AREA_DATA
]);
1007 size_t *dindexes
= xmemdup (lo
, pt
->n_dimensions
* sizeof *lo
);
1008 for (size_t i
= 0; ; i
++)
1011 pivot_table_delete (pt
, dindexes
);
1013 pivot_table_put (pt
, dindexes
, pt
->n_dimensions
,
1015 ? pivot_value_clone (value
)
1016 : pivot_value_new_integer (i
)));
1018 for (size_t j
= 0; j
< pt
->n_dimensions
; j
++)
1020 if (++dindexes
[j
] <= hi
[j
])
1022 dindexes
[j
] = lo
[j
];
1029 pivot_value_destroy (value
);
1035 static struct pivot_dimension
*
1036 parse_dim_name (struct lexer
*lexer
, struct pivot_table
*table
)
1038 force_string (lexer
);
1039 for (size_t i
= 0; i
< table
->n_dimensions
; i
++)
1041 struct pivot_dimension
*dim
= table
->dimensions
[i
];
1043 struct string s
= DS_EMPTY_INITIALIZER
;
1044 pivot_value_format_body (dim
->root
->name
, table
, &s
);
1045 bool match
= !strcmp (ds_cstr (&s
), lex_tokcstr (lexer
));
1055 lex_error (lexer
, "unknown dimension");
1059 static enum pivot_axis_type
1060 parse_axis_type (struct lexer
*lexer
)
1062 if (lex_match_id (lexer
, "ROW"))
1063 return PIVOT_AXIS_ROW
;
1064 else if (lex_match_id (lexer
, "COLUMN"))
1065 return PIVOT_AXIS_COLUMN
;
1066 else if (lex_match_id (lexer
, "LAYER"))
1067 return PIVOT_AXIS_LAYER
;
1070 lex_error_expecting (lexer
, "ROW", "COLUMN", "LAYER");
1076 move_dimension (struct lexer
*lexer
, struct pivot_table
*table
)
1078 struct pivot_dimension
*dim
= parse_dim_name (lexer
, table
);
1080 enum pivot_axis_type axis
= parse_axis_type (lexer
);
1083 if (lex_is_integer (lexer
))
1085 position
= lex_integer (lexer
);
1091 pivot_table_move_dimension (table
, dim
, axis
, position
);
1095 swap_axes (struct lexer
*lexer
, struct pivot_table
*table
)
1097 enum pivot_axis_type a
= parse_axis_type (lexer
);
1098 enum pivot_axis_type b
= parse_axis_type (lexer
);
1099 pivot_table_swap_axes (table
, a
, b
);
1103 read_current_layer (struct lexer
*lexer
, struct pivot_table
*table
)
1105 lex_match (lexer
, T_EQUALS
);
1107 const struct pivot_axis
*layer_axis
= &table
->axes
[PIVOT_AXIS_LAYER
];
1108 for (size_t i
= 0; i
< layer_axis
->n_dimensions
; i
++)
1110 const struct pivot_dimension
*dim
= layer_axis
->dimensions
[i
];
1113 size_t index
= lex_integer (lexer
);
1114 if (index
>= dim
->n_leaves
)
1116 lex_error (lexer
, "only %zu dimensions", dim
->n_leaves
);
1121 table
->current_layer
[i
] = index
;
1126 read_table (struct lexer
*lexer
)
1128 bool displayed
= false;
1130 struct pivot_table
*pt
= pivot_table_create ("Default Title");
1131 while (lex_match (lexer
, T_SLASH
))
1133 assert (!pivot_table_is_shared (pt
));
1136 if (lex_match_id (lexer
, "ROW"))
1137 read_dimension (lexer
, pt
, PIVOT_AXIS_ROW
,
1138 &pt
->look
->areas
[PIVOT_AREA_ROW_LABELS
]);
1139 else if (lex_match_id (lexer
, "COLUMN"))
1140 read_dimension (lexer
, pt
, PIVOT_AXIS_COLUMN
,
1141 &pt
->look
->areas
[PIVOT_AREA_COLUMN_LABELS
]);
1142 else if (lex_match_id (lexer
, "LAYER"))
1143 read_dimension (lexer
, pt
, PIVOT_AXIS_LAYER
,
1144 &pt
->look
->areas
[PIVOT_AREA_LAYERS
]);
1145 else if (lex_match_id (lexer
, "LOOK"))
1146 read_look (lexer
, pt
);
1147 else if (lex_match_id (lexer
, "ROTATE"))
1149 lex_match (lexer
, T_EQUALS
);
1150 while (lex_token (lexer
) == T_ID
)
1151 if (!parse_bool_setting (lexer
, "INNERCOLUMNS", "YES", "NO",
1152 &pt
->rotate_inner_column_labels
)
1153 && !parse_bool_setting (lexer
, "OUTERROWS", "YES", "NO",
1154 &pt
->rotate_outer_row_labels
))
1157 else if (lex_match_id (lexer
, "SHOW"))
1159 lex_match (lexer
, T_EQUALS
);
1160 while (lex_token (lexer
) == T_ID
)
1162 if (parse_bool_setting (lexer
, "GRID", "YES", "NO",
1163 &pt
->show_grid_lines
)
1164 || parse_bool_setting (lexer
, "CAPTION", "YES", "NO",
1166 || parse_bool_setting (lexer
, "TITLE", "YES", "NO",
1170 if (parse_settings_value_show (lexer
, "VALUES", &pt
->show_values
)
1171 || parse_settings_value_show (lexer
, "VARIABLES",
1172 &pt
->show_variables
))
1175 if (lex_match_id (lexer
, "LAYER"))
1176 read_current_layer (lexer
, pt
);
1181 else if (parse_value_setting (lexer
, pt
, "TITLE", &pt
->title
,
1182 &pt
->look
->areas
[PIVOT_AREA_TITLE
])
1183 || parse_value_setting (lexer
, pt
, "SUBTYPE", &pt
->subtype
,
1185 || parse_value_setting (lexer
, pt
, "CORNER", &pt
->corner_text
,
1186 &pt
->look
->areas
[PIVOT_AREA_CORNER
])
1187 || parse_value_setting (lexer
, pt
, "CAPTION", &pt
->caption
,
1188 &pt
->look
->areas
[PIVOT_AREA_CAPTION
])
1189 || parse_string_setting (lexer
, "NOTES", &pt
->notes
))
1193 else if (lex_match_id (lexer
, "BORDER"))
1194 read_border (lexer
, pt
);
1195 else if (lex_match_id (lexer
, "TRANSPOSE"))
1196 pivot_table_transpose (pt
);
1197 else if (lex_match_id (lexer
, "SWAP"))
1198 swap_axes (lexer
, pt
);
1199 else if (lex_match_id (lexer
, "MOVE"))
1200 move_dimension (lexer
, pt
);
1201 else if (lex_match_id (lexer
, "CELLS"))
1202 read_cell (lexer
, pt
);
1203 else if (lex_match_id (lexer
, "FOOTNOTE"))
1204 read_footnote (lexer
, pt
);
1205 else if (lex_match_id (lexer
, "DUMP"))
1206 pivot_table_dump (pt
, 0);
1207 else if (lex_match_id (lexer
, "DISPLAY"))
1209 pivot_table_submit (pivot_table_ref (pt
));
1210 pt
= pivot_table_unshare (pt
);
1215 msg (SE
, "Expecting keyword");
1221 pivot_table_submit (pt
);
1223 pivot_table_unshare (pt
);
1225 force_match (lexer
, T_ENDCMD
);
1229 output_msg (const struct msg
*m_
, void *lexer_
)
1231 struct lexer
*lexer
= lexer_
;
1234 if (m
.file_name
== NULL
)
1236 m
.file_name
= CONST_CAST (char *, lex_get_file_name (lexer
));
1237 m
.first_line
= lex_get_first_line_number (lexer
, 0);
1238 m
.last_line
= lex_get_last_line_number (lexer
, 0);
1241 m
.command_name
= output_get_command_name ();
1243 message_item_submit (message_item_create (&m
));
1245 free (m
.command_name
);