ad76cb1a43e361d467b4379d293076ddc97bdb54
[pspp-builds.git] / src / ui / terminal / main.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006 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 <signal.h>
20 #include <stdio.h>
21
22 #include <ui/debugger.h>
23 #include "command-line.h"
24 #include "msg-ui.h"
25 #include "progname.h"
26 #include "read-line.h"
27
28 #include <data/dictionary.h>
29 #include <data/file-handle-def.h>
30 #include <libpspp/getl.h>
31 #include <data/file-name.h>
32 #include <data/format.h>
33 #include <data/procedure.h>
34 #include <data/settings.h>
35 #include <data/variable.h>
36 #include <gsl/gsl_errno.h>
37 #include <language/command.h>
38 #include <language/lexer/lexer.h>
39 #include <language/prompt.h>
40 #include <libpspp/compiler.h>
41 #include <libpspp/message.h>
42 #include <libpspp/version.h>
43 #include <math/random.h>
44 #include <output/output.h>
45
46 #if HAVE_FPU_CONTROL_H
47 #include <fpu_control.h>
48 #endif
49
50 #if HAVE_LOCALE_H
51 #include <locale.h>
52 #endif
53
54 #if HAVE_FENV_H
55 #include <fenv.h>
56 #endif
57
58 #if HAVE_IEEEFP_H
59 #include <ieeefp.h>
60 #endif
61
62 #include "gettext.h"
63 #define _(msgid) gettext (msgid)
64
65 #include <stdlib.h>
66
67 static void i18n_init (void);
68 static void fpu_init (void);
69 static void terminate (bool success) NO_RETURN;
70
71 /* If a segfault happens, issue a message to that effect and halt */
72 void bug_handler(int sig);
73
74 /* Handle quit/term/int signals */
75 void interrupt_handler(int sig);
76 static struct dataset * the_dataset = NULL;
77
78 static struct lexer *the_lexer;
79 static struct source_stream *the_source_stream ;
80
81 static int view_length = -1;
82 static int view_width = -1;
83
84 static void get_termcap_viewport (int);
85
86
87 /* Program entry point. */
88 int
89 main (int argc, char **argv)
90 {
91   signal (SIGABRT, bug_handler);
92   signal (SIGSEGV, bug_handler);
93   signal (SIGFPE, bug_handler);
94   signal (SIGINT, interrupt_handler);
95   signal (SIGWINCH, get_termcap_viewport);
96
97   set_program_name (argv[0]);
98
99   i18n_init ();
100   fpu_init ();
101   gsl_set_error_handler_off ();
102
103   fmt_init ();
104   outp_init ();
105   fn_init ();
106   fh_init ();
107   the_source_stream =
108     create_source_stream (
109                           fn_getenv_default ("STAT_INCLUDE_PATH", include_path)
110                           );
111   prompt_init ();
112   readln_initialize ();
113   get_termcap_viewport (0);
114   settings_init (&view_width, &view_length);
115   random_init ();
116
117   the_dataset = create_dataset ();
118
119   if (parse_command_line (argc, argv, the_source_stream))
120     {
121       msg_ui_init (the_source_stream);
122       if (!get_testing_mode ())
123         outp_read_devices ();
124       else
125         outp_configure_driver_line (
126           ss_cstr ("raw-ascii:ascii:listing:width=9999 length=9999 "
127                    "output-file=\"pspp.list\" emphasis=none "
128                    "headers=off paginate=off squeeze=on "
129                    "top-margin=0 bottom-margin=0"));
130       the_lexer = lex_create (the_source_stream);
131
132       for (;;)
133         {
134           int result = cmd_parse (the_lexer, the_dataset);
135
136           if (result == CMD_EOF || result == CMD_FINISH)
137             break;
138           if (result == CMD_CASCADING_FAILURE &&
139               !getl_is_interactive (the_source_stream))
140             {
141               msg (SE, _("Stopping syntax file processing here to avoid "
142                          "a cascade of dependent command failures."));
143               getl_abort_noninteractive (the_source_stream);
144             }
145           else
146             check_msg_count (the_source_stream);
147         }
148     }
149
150   terminate (!any_errors ());
151 }
152 \f
153 static void
154 i18n_init (void)
155 {
156 #if ENABLE_NLS
157 #if HAVE_LC_MESSAGES
158   setlocale (LC_MESSAGES, "");
159 #endif
160 #if HAVE_LC_PAPER
161   setlocale (LC_PAPER, "");
162 #endif
163   bindtextdomain (PACKAGE, locale_dir);
164   textdomain (PACKAGE);
165 #endif /* ENABLE_NLS */
166 }
167
168 static void
169 fpu_init (void)
170 {
171 #if HAVE_FEHOLDEXCEPT
172   fenv_t foo;
173   feholdexcept (&foo);
174 #elif HAVE___SETFPUCW && defined(_FPU_IEEE)
175   __setfpucw (_FPU_IEEE);
176 #elif HAVE_FPSETMASK
177   fpsetmask (0);
178 #endif
179 }
180
181 /* If a segfault happens, issue a message to that effect and halt */
182 void
183 bug_handler(int sig)
184 {
185 #if DEBUGGING
186   connect_debugger ();
187 #endif
188   switch (sig)
189     {
190     case SIGABRT:
191       request_bug_report_and_abort("Assertion Failure/Abort");
192     case SIGFPE:
193       request_bug_report_and_abort("Floating Point Exception");
194     case SIGSEGV:
195       request_bug_report_and_abort("Segmentation Violation");
196     default:
197       request_bug_report_and_abort("Unknown");
198     }
199 }
200
201 void
202 interrupt_handler(int sig UNUSED)
203 {
204   terminate (false);
205 }
206
207
208 /* Terminate PSPP.  SUCCESS should be true to exit successfully,
209    false to exit as a failure.  */
210 static void
211 terminate (bool success)
212 {
213   static bool terminating = false;
214   if (!terminating)
215     {
216       terminating = true;
217
218       destroy_dataset (the_dataset);
219
220       random_done ();
221       settings_done ();
222       fh_done ();
223       lex_destroy (the_lexer);
224       destroy_source_stream (the_source_stream);
225       prompt_done ();
226       readln_uninitialize ();
227
228       outp_done ();
229       msg_ui_done ();
230       fmt_done ();
231     }
232   exit (success ? EXIT_SUCCESS : EXIT_FAILURE);
233 }
234
235 \f
236 #include "error.h"
237
238 #include "gettext.h"
239 #define _(msgid) gettext (msgid)
240
241 /* If view_width or view_length has not yet been set to a
242    reasonable value, takes a guess. */
243 static void
244 set_fallback_viewport (void)
245 {
246   if (view_width <= 0)
247     {
248       if (getenv ("COLUMNS") != NULL)
249         view_width = atoi (getenv ("COLUMNS"));
250       if (view_width <= 0)
251         view_width = 79;
252     }
253
254   if (view_length <= 0)
255     {
256       if (getenv ("LINES") != NULL)
257         view_length = atoi (getenv ("LINES"));
258       if (view_length <= 0)
259         view_length = 24;
260     }
261 }
262
263 /* Code that interfaces to ncurses.  This must be at the very end
264    of this file because curses.h redefines "bool" on some systems
265    (e.g. OpenBSD), causing declaration mismatches with functions
266    that have parameters or return values of type "bool". */
267 #if HAVE_LIBNCURSES
268 #include <curses.h>
269 #include <term.h>
270
271 static void
272 get_termcap_viewport (int sig UNUSED)
273 {
274   char term_buffer [16384];
275
276   if (getenv ("TERM") != NULL)
277     {
278       if (tgetent (term_buffer, getenv ("TERM")) > 0)
279         {
280           if (tgetnum ("li") > 0)
281             view_length = tgetnum ("li");
282           if (tgetnum ("co") > 1)
283             view_width = tgetnum ("co") - 1;
284         }
285       else
286         error (0, 0, _("could not access definition for terminal `%s'"),
287                getenv ("TERM"));
288     }
289
290   set_fallback_viewport ();
291 }
292
293 #else /* !HAVE_LIBNCURSES */
294
295 static void
296 get_termcap_viewport (int sig UNUSED)
297 {
298   set_fallback_viewport ();
299 }
300
301 #endif /* !HAVE_LIBNCURSES */
302
303