Move all command implementations into a single 'commands' directory.
[pspp] / src / language / commands / output.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 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 <ctype.h>
20 #include <stdlib.h>
21
22 #include "data/dataset.h"
23 #include "data/settings.h"
24 #include "data/format.h"
25 #include "language/command.h"
26 #include "language/lexer/lexer.h"
27 #include "language/lexer/format-parser.h"
28 #include "libpspp/message.h"
29 #include "libpspp/string-set.h"
30 #include "libpspp/version.h"
31 #include "output/pivot-table.h"
32
33 #include "gl/xalloc.h"
34
35 #include "gettext.h"
36 #define _(msgid) gettext (msgid)
37
38 int
39 cmd_output_modify (struct lexer *lexer, struct dataset *ds UNUSED)
40 {
41   struct string_set rc_names = STRING_SET_INITIALIZER (rc_names);
42
43   while (lex_token (lexer) != T_ENDCMD)
44     {
45       lex_match (lexer, T_SLASH);
46
47       if (lex_match_id (lexer, "SELECT"))
48         {
49           if (!lex_force_match_id (lexer, "TABLES"))
50             goto error;
51         }
52       else if (lex_match_id (lexer, "TABLECELLS"))
53         {
54           string_set_clear (&rc_names);
55           struct fmt_spec fmt = { .type = 0 };
56
57           while (lex_token (lexer) != T_SLASH &&
58                  lex_token (lexer) != T_ENDCMD)
59             {
60               if (lex_match_id (lexer, "SELECT"))
61                 {
62                   if (!lex_force_match (lexer, T_EQUALS))
63                     goto error;
64
65                   if (!lex_force_match (lexer, T_LBRACK))
66                     goto error;
67
68                   while (lex_token (lexer) == T_ID)
69                     {
70                       string_set_insert (&rc_names, lex_tokcstr (lexer));
71                       lex_get (lexer);
72                     }
73
74                   if (!lex_force_match (lexer, T_RBRACK))
75                     goto error;
76                 }
77               else if (lex_match_id (lexer, "FORMAT"))
78                 {
79                   char type[FMT_TYPE_LEN_MAX + 1];
80                   uint16_t width;
81                   uint8_t decimals;
82
83                   if (!lex_force_match (lexer, T_EQUALS)
84                       || !parse_abstract_format_specifier (lexer, type,
85                                                            &width, &decimals))
86                     goto error;
87
88                   if (width <= 0)
89                     {
90                       const struct fmt_spec *dflt = settings_get_format ();
91                       width = dflt->w;
92                     }
93
94                   if (!fmt_from_name (type, &fmt.type))
95                     {
96                       lex_error (lexer, _("Unknown format type `%s'."), type);
97                       goto error;
98                     }
99
100                   fmt.w = width;
101                   fmt.d = decimals;
102                 }
103               else
104                 {
105                   lex_error_expecting (lexer, "SELECT", "FORMAT");
106                   goto error;
107                 }
108             }
109
110           if (fmt.w)
111             {
112               const struct string_set_node *node;
113               const char *s;
114               STRING_SET_FOR_EACH (s, node, &rc_names)
115                 if (!pivot_result_class_change (s, &fmt))
116                   lex_error (lexer, _("Unknown cell class %s."), s);
117             }
118         }
119       else
120         {
121           lex_error_expecting (lexer, "SELECT", "TABLECELLS");
122           goto error;
123         }
124     }
125
126   string_set_destroy (&rc_names);
127   return CMD_SUCCESS;
128
129  error:
130   string_set_destroy (&rc_names);
131   return CMD_FAILURE;
132 }