Fix crash running two consecutive examine commands.
[pspp-builds.git] / src / ui / terminal / terminal-opts.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2008  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 #include <argp.h>
19 #include <stdbool.h>
20 #include <xalloc.h>
21 #include <stdlib.h>
22 #include <data/settings.h>
23 #include <output/output.h>
24 #include "msg-ui.h"
25 #include <ui/command-line.h>
26 #include <libpspp/verbose-msg.h>
27 #include <libpspp/llx.h>
28 #include <data/file-name.h>
29 #include "terminal-opts.h"
30 #include <libpspp/getl.h>
31 #include <language/syntax-file.h>
32 #include "read-line.h"
33
34 #include "gettext.h"
35 #define _(msgid) gettext (msgid)
36 #define N_(msgid) msgid
37
38
39 static const struct argp_option test_options [] =
40   {
41     {"verbose", 'v', 0, 0, N_("Increase diagnostic verbosity level"), 0},
42     {"testing-mode", 'T', 0, OPTION_HIDDEN, 0, 0},
43
44     { 0, 0, 0, 0, 0, 0 }
45   };
46
47 static error_t
48 parse_test_opts (int key, char *arg, struct argp_state *state)
49 {
50   switch (key)
51     {
52     case 'T':
53       settings_set_testing_mode (true);
54       break;
55     case 'v':
56       verbose_increment_level ();
57       break;
58     default:
59       return ARGP_ERR_UNKNOWN;
60     }
61
62   return 0;
63 }
64
65 static const struct argp_option io_options [] =
66   {
67     {"error-file", 'e', "FILE", 0,
68      N_("Send error messages to FILE (appended)"), 0},
69
70     {"device", 'o', "DEVICE", 0,
71      N_("Select output driver DEVICE and disable defaults"), 0},
72
73     {"list", 'l', 0, 0,
74      N_("Print a list of known driver classes, then exit"), 0},
75
76     {"interactive", 'i', 0, 0, N_("Start an interactive session"), 0},
77
78     { 0, 0, 0, 0, 0, 0 }
79   };
80
81
82 static error_t
83 parse_io_opts (int key, char *arg, struct argp_state *state)
84 {
85   struct source_init
86   {
87     struct llx_list file_list;
88     bool cleared_device_defaults;
89     bool interactive;
90   };
91
92   struct fn_element {
93     struct ll ll;
94     const char *fn;
95   };
96
97   struct source_init *sip = state->hook;
98
99   struct source_stream *ss = state->input;
100
101   struct command_line_processor *clp = get_subject (state);
102
103   switch (key)
104     {
105     case ARGP_KEY_INIT:
106       state->hook = sip = xzalloc (sizeof (struct source_init));
107       llx_init (&sip->file_list);
108       break;
109     case ARGP_KEY_ARG:
110       if (strchr (arg, '='))
111         outp_configure_macro (arg);
112       else
113         {
114           llx_push_tail (&sip->file_list, arg, &llx_malloc_mgr);
115         }
116       break;
117     case ARGP_KEY_SUCCESS:
118       {
119       struct llx *llx = llx_null (&sip->file_list);
120       while ((llx = llx_next (llx)) != llx_null (&sip->file_list))
121         {
122           const char *fn = llx_data (llx);
123           /* Assume it's a syntax file */
124           getl_append_source (ss,
125                               create_syntax_file_source (fn),
126                               GETL_BATCH,
127                               ERRMODE_CONTINUE
128                               );
129
130         }
131
132       if (sip->interactive || llx_is_empty (&sip->file_list))
133         {
134           getl_append_source (ss, create_readln_source (),
135                               GETL_INTERACTIVE,
136                               ERRMODE_CONTINUE
137                               );
138
139           if (!sip->cleared_device_defaults)
140             outp_configure_add ("interactive");
141         }
142       }
143       break;
144     case ARGP_KEY_FINI:
145       free (sip);
146       break;
147     case 'e':
148       msg_ui_set_error_file (arg);
149       break;
150     case 'i':
151       sip->interactive = true;
152       break;
153     case 'l':
154       outp_list_classes ();
155       break;
156     case 'o':
157       if (! sip->cleared_device_defaults)
158         {
159           outp_configure_clear ();
160           sip->cleared_device_defaults = true;
161         }
162       outp_configure_add (arg);
163       break;
164     default:
165       return ARGP_ERR_UNKNOWN;
166     }
167
168   return 0;
169 }
170
171 const struct argp io_argp =  {io_options, parse_io_opts, 0, 0, 0, 0, 0};
172 const struct argp test_argp =  {test_options, parse_test_opts, 0, 0, 0, 0, 0};
173
174 #if 0
175 static const struct argp_child children [] =
176   {
177     {&io_argp, 0, N_("Options affecting input and output locations:"), 0},
178     {&test_argp, 0, N_("Diagnostic options:"), 0},
179     {0, 0, 0, 0}
180   };
181
182
183 static error_t
184 propagate_aux (int key, char *arg, struct argp_state *state)
185 {
186   if ( key == ARGP_KEY_INIT)
187     {
188       int i;
189       for (i = 0 ; i < sizeof (children) / sizeof (children[0]) - 1 ; ++i)
190         state->child_inputs[i] = state->input;
191     }
192
193   return ARGP_ERR_UNKNOWN;
194 }
195
196 const struct argp terminal_argp =  {NULL, propagate_aux, 0, 0, children, 0, 0};
197
198 #endif