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