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