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