e0f219826dfc4820f55e519dbc9c3c8c4d737929
[pspp] / src / ui / terminal / terminal-reader.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2007, 2009, 2010, 2011, 2013 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 <unistd.h>
21 #include <fcntl.h>
22 #include <stdbool.h>
23 #include <stdio.h>
24
25 #include "libpspp/str.h"
26
27 #if HAVE_READLINE
28 #include <readline/readline.h>
29 #include <readline/history.h>
30 #include <termios.h>
31
32 static char *history_file;
33
34 static char **complete_command_name (const char *, int, int);
35 static char **dont_complete (const char *, int, int);
36 static char *command_generator (const char *text, int state);
37 #endif
38
39
40 #include "ui/terminal/terminal-reader.h"
41 #include <sys/select.h>
42 #include <sys/time.h>
43 #include <sys/types.h>
44
45 #include <errno.h>
46 #include <stdint.h>
47 #include <stdlib.h>
48
49 #include "data/settings.h"
50 #include "language/command.h"
51 #include "language/lexer/lexer.h"
52 #include "libpspp/assertion.h"
53 #include "libpspp/cast.h"
54 #include "libpspp/message.h"
55 #include "libpspp/prompt.h"
56 #include "libpspp/str.h"
57 #include "libpspp/version.h"
58 #include "output/driver.h"
59 #include "output/journal.h"
60
61 #include "gl/minmax.h"
62 #include "gl/xalloc.h"
63
64 #include "gettext.h"
65 #define _(msgid) gettext (msgid)
66
67 struct terminal_reader
68   {
69     struct lex_reader reader;
70     struct substring s;
71     size_t offset;
72     bool eof;
73   };
74
75 static int n_terminal_readers;
76
77 static void readline_init (void);
78 static void readline_done (void);
79 static bool readline_read (struct substring *, enum prompt_style);
80
81 /* Display a welcoming message. */
82 static void
83 welcome (void)
84 {
85   static bool welcomed = false;
86   if (welcomed)
87     return;
88   welcomed = true;
89   fputs ("PSPP is free software and you are welcome to distribute copies of "
90          "it\nunder certain conditions; type \"show copying.\" to see the "
91          "conditions.\nThere is ABSOLUTELY NO WARRANTY for PSPP; type \"show "
92          "warranty.\" for details.\n", stdout);
93   puts (announced_version);
94   journal_init ();
95 }
96
97 static struct terminal_reader *
98 terminal_reader_cast (struct lex_reader *r)
99 {
100   return UP_CAST (r, struct terminal_reader, reader);
101 }
102
103
104 /* Older libreadline versions do not provide rl_outstream.
105    However, it is almost always going to be the same as stdout. */
106 #if ! HAVE_RL_OUTSTREAM
107 # define rl_outstream stdout
108 #endif
109
110
111 #if HAVE_READLINE
112 /* Similarly, rl_echo_signal_char is fairly recent.
113    We provide our own crude version if it is not present. */
114 #if ! HAVE_RL_ECHO_SIGNAL_CHAR
115 static void
116 rl_echo_signal_char (int sig)
117 {
118 #if HAVE_TERMIOS_H
119   struct termios t;
120   if (0 == tcgetattr (0, &t))
121     {
122       cc_t c = t.c_cc[VINTR];
123
124       if (c >= 0  && c <= 'Z' - 'A')
125         fprintf (rl_outstream, "^%c", 'A' + c - 1);
126       else
127         fprintf (rl_outstream, "%c", c);
128     }
129   else
130 #endif
131     fprintf (rl_outstream, "^C");
132
133   fflush (rl_outstream);
134 }
135 #endif
136 #endif
137
138
139 static size_t
140 terminal_reader_read (struct lex_reader *r_, char *buf, size_t n,
141                       enum prompt_style prompt_style)
142 {
143   struct terminal_reader *r = terminal_reader_cast (r_);
144   size_t chunk;
145
146   if (r->offset >= r->s.length && !r->eof)
147     {
148       welcome ();
149       msg_ui_reset_counts ();
150       output_flush ();
151
152       ss_dealloc (&r->s);
153       if (! readline_read (&r->s, prompt_style))
154         {
155           *buf = '\n';
156           fprintf (rl_outstream, "\n");
157           return 1;
158         }
159       r->offset = 0;
160       r->eof = ss_is_empty (r->s);
161     }
162
163   chunk = MIN (n, r->s.length - r->offset);
164   memcpy (buf, r->s.string + r->offset, chunk);
165   r->offset += chunk;
166   return chunk;
167 }
168
169 static void
170 terminal_reader_close (struct lex_reader *r_)
171 {
172   struct terminal_reader *r = terminal_reader_cast (r_);
173
174   ss_dealloc (&r->s);
175   free (r->reader.file_name);
176   free (r);
177
178   if (!--n_terminal_readers)
179     readline_done ();
180 }
181
182 static struct lex_reader_class terminal_reader_class =
183   {
184     terminal_reader_read,
185     terminal_reader_close
186   };
187
188 /* Creates a source which uses readln to get its line */
189 struct lex_reader *
190 terminal_reader_create (void)
191 {
192   struct terminal_reader *r;
193
194   if (!n_terminal_readers++)
195     readline_init ();
196
197   r = xzalloc (sizeof *r);
198   r->reader.class = &terminal_reader_class;
199   r->reader.syntax = LEX_SYNTAX_INTERACTIVE;
200   r->reader.error = LEX_ERROR_TERMINAL;
201   r->reader.file_name = NULL;
202   r->s = ss_empty ();
203   r->offset = 0;
204   r->eof = false;
205   return &r->reader;
206 }
207 \f
208
209
210 static const char *
211 readline_prompt (enum prompt_style style)
212 {
213   switch (style)
214     {
215     case PROMPT_FIRST:
216       return "PSPP> ";
217
218     case PROMPT_LATER:
219       return "    > ";
220
221     case PROMPT_DATA:
222       return "data> ";
223
224     case PROMPT_COMMENT:
225       return "comment> ";
226
227     case PROMPT_DOCUMENT:
228       return "document> ";
229
230     case PROMPT_DO_REPEAT:
231       return "DO REPEAT> ";
232
233     case PROMPT_DEFINE:
234       return "DEFINE> ";
235     }
236
237   NOT_REACHED ();
238 }
239
240
241 #if HAVE_READLINE
242
243 static int pfd[2];
244 static bool sigint_received ;
245
246 /*
247    A function similar to getc from stdio.
248    However this one may be interrupted by SIGINT.
249    If that happens it will return EOF and the global variable
250    sigint_received will be set to true.
251  */
252 static int
253 interruptible_getc (FILE *fp)
254 {
255   int c  = 0;
256   int ret = -1;
257   do
258     {
259       struct timeval timeout = {0, 50000};
260       fd_set what;
261       int max_fd = 0;
262       int fd ;
263       FD_ZERO (&what);
264       fd = fileno (fp);
265       max_fd = (max_fd > fd) ? max_fd : fd;
266       FD_SET (fd, &what);
267       fd = pfd[0];
268       max_fd = (max_fd > fd) ? max_fd : fd;
269       FD_SET (fd, &what);
270       ret = select (max_fd + 1, &what, NULL, NULL, &timeout);
271       if (ret == -1 && errno != EINTR)
272         {
273           perror ("Select failed");
274           continue;
275         }
276
277       if (ret > 0)
278         {
279           if (FD_ISSET (pfd[0], &what))
280             {
281               char dummy[1];
282               read (pfd[0], dummy, 1);
283               sigint_received = true;
284               return EOF;
285             }
286         }
287     }
288   while (ret <= 0);
289
290   /* This will not block! */
291   read (fileno (fp), &c, 1);
292
293   return c;
294 }
295
296 static void
297 handler (int sig)
298 {
299   rl_end = 0;
300
301   write (pfd[1], "x", 1);
302   rl_echo_signal_char (sig);
303 }
304
305
306 static void
307 readline_init (void)
308 {
309   if (0 != pipe2 (pfd, O_NONBLOCK))
310     perror ("Cannot create pipe");
311
312   if (SIG_ERR == signal (SIGINT, handler))
313     perror ("Cannot add signal handler");
314
315   rl_catch_signals = 0;
316   rl_getc_function = interruptible_getc;
317   rl_basic_word_break_characters = "\n";
318   using_history ();
319   stifle_history (500);
320   if (history_file == NULL)
321     {
322       const char *home_dir = getenv ("HOME");
323       if (home_dir != NULL)
324         {
325           history_file = xasprintf ("%s/.pspp_history", home_dir);
326           read_history (history_file);
327         }
328     }
329 }
330
331 static void
332 readline_done (void)
333 {
334   if (history_file != NULL && false == settings_get_testing_mode ())
335     write_history (history_file);
336   clear_history ();
337   free (history_file);
338 }
339
340 /* Prompt the user for a line of input and return it in LINE.
341    Returns true if the LINE should be considered valid, false otherwise.
342  */
343 static bool
344 readline_read (struct substring *line, enum prompt_style style)
345 {
346   char *string;
347
348   rl_attempted_completion_function = (style == PROMPT_FIRST
349                                       ? complete_command_name
350                                       : dont_complete);
351   sigint_received = false;
352   string = readline (readline_prompt (style));
353   if (sigint_received)
354     {
355       *line = ss_empty ();
356       return false;
357     }
358
359   if (string != NULL)
360     {
361       char *end;
362
363       if (string[0])
364         add_history (string);
365
366       end = strchr (string, '\0');
367       *end = '\n';
368       *line = ss_buffer (string, end - string + 1);
369     }
370   else
371     *line = ss_empty ();
372
373   return true;
374 }
375
376 /* Returns a set of command name completions for TEXT.
377    This is of the proper form for assigning to
378    rl_attempted_completion_function. */
379 static char **
380 complete_command_name (const char *text, int start, int end UNUSED)
381 {
382   if (start == 0)
383     {
384       /* Complete command name at start of line. */
385       return rl_completion_matches (text, command_generator);
386     }
387   else
388     {
389       /* Otherwise don't do any completion. */
390       rl_attempted_completion_over = 1;
391       return NULL;
392     }
393 }
394
395 /* Do not do any completion for TEXT. */
396 static char **
397 dont_complete (const char *text UNUSED, int start UNUSED, int end UNUSED)
398 {
399   rl_attempted_completion_over = 1;
400   return NULL;
401 }
402
403 /* If STATE is 0, returns the first command name matching TEXT.
404    Otherwise, returns the next command name matching TEXT.
405    Returns a null pointer when no matches are left. */
406 static char *
407 command_generator (const char *text, int state)
408 {
409   static const struct command *cmd;
410   const char *name;
411
412   if (state == 0)
413     cmd = NULL;
414   name = cmd_complete (text, &cmd);
415   return xstrdup_if_nonnull (name);
416 }
417
418 #else  /* !HAVE_READLINE */
419
420 static const char * the_prompt;
421
422 static void
423 handler (int sig)
424 {
425   if (the_prompt)
426     fputs (the_prompt, stdout);
427   fflush (stdout);
428 }
429
430 static void
431 readline_init (void)
432 {
433   if (SIG_ERR == signal (SIGINT, handler))
434     perror ("Cannot add signal handler");
435 }
436
437 static void
438 readline_done (void)
439 {
440 }
441
442 /* Prompt the user for a line of input and return it in LINE.
443    Returns true if the LINE should be considered valid, false otherwise.
444  */
445 static bool
446 readline_read (struct substring *line, enum prompt_style style)
447 {
448   struct string string;
449   the_prompt = readline_prompt (style);
450
451   fputs (the_prompt, stdout);
452   fflush (stdout);
453   ds_init_empty (&string);
454   ds_read_line (&string, stdin, SIZE_MAX);
455
456   *line = string.ss;
457
458   return true;
459 }
460 #endif /* !HAVE_READLINE */