eeb10356d8ecf7f971dc82f7c280b12231c1e504
[pspp] / src / ui / terminal / terminal-opts.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2008, 2010  Free Software Foundation
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 "terminal-opts.h"
20
21 #include <stdbool.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "data/settings.h"
26 #include "language/lexer/include-path.h"
27 #include "libpspp/argv-parser.h"
28 #include "libpspp/assertion.h"
29 #include "libpspp/cast.h"
30 #include "libpspp/compiler.h"
31 #include "libpspp/llx.h"
32 #include "libpspp/str.h"
33 #include "libpspp/string-array.h"
34 #include "libpspp/string-map.h"
35 #include "libpspp/string-set.h"
36 #include "libpspp/version.h"
37 #include "output/driver.h"
38 #include "output/driver-provider.h"
39 #include "output/msglog.h"
40 #include "output/pivot-table.h"
41
42 #include "gl/error.h"
43 #include "gl/localcharset.h"
44 #include "gl/progname.h"
45 #include "gl/version-etc.h"
46 #include "gl/xmemdup0.h"
47 #include "gl/xalloc.h"
48
49 #include "gettext.h"
50 #define _(msgid) gettext (msgid)
51 #define N_(msgid) msgid
52
53 struct terminal_opts
54   {
55     struct string_map options;  /* Output driver options. */
56     bool has_output_driver;
57     bool has_terminal_driver;
58     bool has_error_file;
59     enum lex_syntax_mode *syntax_mode;
60     bool *process_statrc;
61     char **syntax_encoding;
62     char *table_look;
63   };
64
65 enum
66   {
67     OPT_TESTING_MODE,
68     OPT_ERROR_FILE,
69     OPT_OUTPUT,
70     OPT_OUTPUT_OPTION,
71     OPT_NO_OUTPUT,
72     OPT_BATCH,
73     OPT_INTERACTIVE,
74     OPT_SYNTAX_ENCODING,
75     OPT_NO_STATRC,
76     OPT_TABLE_LOOK,
77     OPT_HELP,
78     OPT_VERSION,
79     N_TERMINAL_OPTIONS
80   };
81
82 static struct argv_option terminal_argv_options[N_TERMINAL_OPTIONS] =
83   {
84     {"testing-mode", 0, no_argument, OPT_TESTING_MODE},
85     {"error-file", 'e', required_argument, OPT_ERROR_FILE},
86     {"output", 'o', required_argument, OPT_OUTPUT},
87     {NULL, 'O', required_argument, OPT_OUTPUT_OPTION},
88     {"no-output", 0, no_argument, OPT_NO_OUTPUT},
89     {"batch", 'b', no_argument, OPT_BATCH},
90     {"interactive", 'i', no_argument, OPT_INTERACTIVE},
91     {"syntax-encoding", 0, required_argument, OPT_SYNTAX_ENCODING},
92     {"no-statrc", 'r', no_argument, OPT_NO_STATRC},
93     {"table-look", 0, required_argument, OPT_TABLE_LOOK},
94     {"help", 'h', no_argument, OPT_HELP},
95     {"version", 'V', no_argument, OPT_VERSION},
96   };
97
98 static void
99 register_output_driver (struct terminal_opts *to)
100 {
101   if (!string_map_is_empty (&to->options))
102     {
103       struct output_driver *driver;
104
105       driver = output_driver_create (&to->options);
106       if (driver != NULL)
107         {
108           output_driver_register (driver);
109
110           to->has_output_driver = true;
111           if (driver->device_type == SETTINGS_DEVICE_TERMINAL)
112             to->has_terminal_driver = true;
113         }
114       string_map_clear (&to->options);
115     }
116 }
117
118 static char *
119 get_supported_formats (void)
120 {
121   const struct string_set_node *node;
122   struct string_array format_array;
123   struct string_set format_set;
124   char *format_string;
125   const char *format;
126
127   /* Get supported formats as unordered set. */
128   string_set_init (&format_set);
129   output_get_supported_formats (&format_set);
130
131   /* Converted supported formats to sorted array. */
132   string_array_init (&format_array);
133   STRING_SET_FOR_EACH (format, node, &format_set)
134     string_array_append (&format_array, format);
135   string_array_sort (&format_array);
136   string_set_destroy (&format_set);
137
138   /* Converted supported formats to string. */
139   format_string = string_array_join (&format_array, " ");
140   string_array_destroy (&format_array);
141   return format_string;
142 }
143
144 static void
145 usage (void)
146 {
147   char *supported_formats = get_supported_formats ();
148   char *inc_path = string_array_join (include_path_default (), " ");
149
150   printf (_("\
151 PSPP, a program for statistical analysis of sampled data.\n\
152 Usage: %s [OPTION]... FILE...\n\
153 \n\
154 Arguments to long options also apply to equivalent short options.\n\
155 \n\
156 Output options:\n\
157   -o, --output=FILE         output to FILE, default format from FILE's name\n\
158   -O format=FORMAT          override format for previous -o\n\
159   -O OPTION=VALUE           set output option to customize previous -o\n\
160   -O device={terminal|listing}  override device type for previous -o\n\
161   -e, --error-file=FILE     append errors, warnings, and notes to FILE\n\
162   --no-output               disable default output driver\n\
163   --table-look=FILE         use output style read from FILE\n\
164 Supported output formats: %s\n\
165 \n\
166 Language options:\n\
167   -I, --include=DIR         append DIR to search path\n\
168   -I-, --no-include         clear search path\n\
169   -r, --no-statrc           disable running rc file at startup\n\
170   -a, --algorithm={compatible|enhanced}\n\
171                             set to `compatible' if you want output\n\
172                             calculated from broken algorithms\n\
173   -x, --syntax={compatible|enhanced}\n\
174                             set to `compatible' to disable PSPP extensions\n\
175   -b, --batch               interpret syntax in batch mode\n\
176   -i, --interactive         interpret syntax in interactive mode\n\
177   --syntax-encoding=ENCODING  specify encoding for syntax files\n\
178   -s, --safer               don't allow some unsafe operations\n\
179 Default search path: %s\n\
180 \n\
181 Informative output:\n\
182   -h, --help                display this help and exit\n\
183   -V, --version             output version information and exit\n\
184 \n\
185 Non-option arguments are interpreted as syntax files to execute.\n"),
186           program_name, supported_formats, inc_path);
187
188   free (supported_formats);
189   free (inc_path);
190
191   emit_bug_reporting_address ();
192   exit (EXIT_SUCCESS);
193 }
194
195 static void
196 terminal_option_callback (int id, void *to_)
197 {
198   struct terminal_opts *to = to_;
199
200   switch (id)
201     {
202     case OPT_TESTING_MODE:
203       settings_set_testing_mode (true);
204       break;
205
206     case OPT_ERROR_FILE:
207       if (!strcmp (optarg, "none") || msglog_create (optarg))
208         to->has_error_file = true;
209       break;
210
211     case OPT_OUTPUT:
212       register_output_driver (to);
213       string_map_insert (&to->options, "output-file", optarg);
214       break;
215
216     case OPT_OUTPUT_OPTION:
217       output_driver_parse_option (optarg, &to->options);
218       break;
219
220     case OPT_NO_OUTPUT:
221       /* Pretend that we already have an output driver, which disables adding
222          one in terminal_opts_done() when we don't already have one. */
223       to->has_output_driver = true;
224       break;
225
226     case OPT_BATCH:
227       *to->syntax_mode = LEX_SYNTAX_BATCH;
228       break;
229
230     case OPT_INTERACTIVE:
231       *to->syntax_mode = LEX_SYNTAX_INTERACTIVE;
232       break;
233
234     case OPT_SYNTAX_ENCODING:
235       *to->syntax_encoding = optarg;
236       break;
237
238     case OPT_NO_STATRC:
239       *to->process_statrc = false;
240       break;
241
242     case OPT_TABLE_LOOK:
243       to->table_look = optarg;
244       break;
245
246     case OPT_HELP:
247       usage ();
248       exit (EXIT_SUCCESS);
249
250     case OPT_VERSION:
251       version_etc (stdout, "pspp", PACKAGE_NAME, PACKAGE_VERSION,
252                    "Ben Pfaff", "John Darrington", "Jason Stover",
253                    NULL_SENTINEL);
254       exit (EXIT_SUCCESS);
255
256     default:
257       NOT_REACHED ();
258     }
259 }
260
261 struct terminal_opts *
262 terminal_opts_init (struct argv_parser *ap,
263                     enum lex_syntax_mode *syntax_mode, bool *process_statrc,
264                     char **syntax_encoding)
265 {
266   struct terminal_opts *to;
267
268   *syntax_mode = LEX_SYNTAX_AUTO;
269   *process_statrc = true;
270   *syntax_encoding = "Auto";
271
272   to = xzalloc (sizeof *to);
273   to->syntax_mode = syntax_mode;
274   string_map_init (&to->options);
275   to->has_output_driver = false;
276   to->has_error_file = false;
277   to->syntax_mode = syntax_mode;
278   to->process_statrc = process_statrc;
279   to->syntax_encoding = syntax_encoding;
280
281   argv_parser_add_options (ap, terminal_argv_options, N_TERMINAL_OPTIONS,
282                            terminal_option_callback, to);
283   return to;
284 }
285
286 void
287 terminal_opts_done (struct terminal_opts *to, int argc, char *argv[])
288 {
289   register_output_driver (to);
290   if (!to->has_output_driver)
291     {
292       string_map_insert (&to->options, "output-file", "-");
293       string_map_insert (&to->options, "format", "txt");
294       register_output_driver (to);
295     }
296
297   if (!to->has_terminal_driver && !to->has_error_file)
298     msglog_create ("-");
299
300   string_map_destroy (&to->options);
301
302   if (to->table_look)
303     {
304       struct pivot_table_look *look;
305       char *s = pivot_table_look_read (to->table_look, &look);
306       if (s)
307         error (1, 0, "%s", s);
308       pivot_table_look_set_default (look);
309       pivot_table_look_unref (look);
310     }
311
312   free (to);
313 }