Update all #include directives to the currently preferred style.
[pspp-builds.git] / src / ui / terminal / read-line.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2007, 2009, 2011 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 "ui/terminal/read-line.h"
20
21 #include <stdlib.h>
22 #include <stdbool.h>
23 #include <assert.h>
24 #include <errno.h>
25 #if ! HAVE_READLINE
26 #include <stdint.h>
27 #endif
28
29 #include "data/file-name.h"
30 #include "data/settings.h"
31 #include "language/command.h"
32 #include "language/prompt.h"
33 #include "libpspp/cast.h"
34 #include "libpspp/message.h"
35 #include "libpspp/str.h"
36 #include "libpspp/version.h"
37 #include "output/driver.h"
38 #include "output/journal.h"
39 #include "ui/terminal/msg-ui.h"
40 #include "ui/terminal/terminal.h"
41
42 #include "gl/xalloc.h"
43
44 #include "gettext.h"
45 #define _(msgid) gettext (msgid)
46
47 #if HAVE_READLINE
48 #include <readline/readline.h>
49 #include <readline/history.h>
50
51 static char *history_file;
52
53 static char **complete_command_name (const char *, int, int);
54 static char **dont_complete (const char *, int, int);
55 #endif /* HAVE_READLINE */
56
57
58 struct readln_source
59 {
60   struct getl_interface parent ;
61
62   bool (*interactive_func) (struct string *line,
63                             enum prompt_style) ;
64 };
65
66
67 static bool initialised = false;
68
69 /* Initialize getl. */
70 void
71 readln_initialize (void)
72 {
73   initialised = true;
74
75 #if HAVE_READLINE
76   rl_basic_word_break_characters = "\n";
77   using_history ();
78   stifle_history (500);
79   if (history_file == NULL)
80     {
81       const char *home_dir = getenv ("HOME");
82       if (home_dir != NULL)
83         {
84           history_file = xasprintf ("%s/.pspp_history", home_dir);
85           read_history (history_file);
86         }
87     }
88 #endif
89 }
90
91 /* Close getl. */
92 void
93 readln_uninitialize (void)
94 {
95   initialised = false;
96
97 #if HAVE_READLINE
98   if (history_file != NULL && false == settings_get_testing_mode () )
99     write_history (history_file);
100   clear_history ();
101   free (history_file);
102 #endif
103 }
104
105
106 static bool
107 read_interactive (struct getl_interface *s,
108                   struct string *line)
109 {
110   struct readln_source *is  = UP_CAST (s, struct readln_source, parent);
111
112   return is->interactive_func (line, prompt_get_style ());
113 }
114
115 static bool
116 always_true (const struct getl_interface *s UNUSED)
117 {
118   return true;
119 }
120
121 /* Display a welcoming message. */
122 static void
123 welcome (void)
124 {
125   static bool welcomed = false;
126   if (welcomed)
127     return;
128   welcomed = true;
129   fputs ("PSPP is free software and you are welcome to distribute copies of "
130          "it\nunder certain conditions; type \"show copying.\" to see the "
131          "conditions.\nThere is ABSOLUTELY NO WARRANTY for PSPP; type \"show "
132          "warranty.\" for details.\n", stdout);
133   puts (stat_version);
134   readln_initialize ();
135   journal_enable ();
136 }
137
138 /* Gets a line from the user and stores it into LINE.
139    Prompts the user with PROMPT.
140    Returns true if successful, false at end of file.
141    */
142 static bool
143 readln_read (struct string *line, enum prompt_style style)
144 {
145   const char *prompt = prompt_get (style);
146 #if HAVE_READLINE
147   char *string;
148 #endif
149   bool eof;
150
151   assert (initialised);
152
153   msg_ui_reset_counts ();
154
155   welcome ();
156
157   output_flush ();
158
159 #if HAVE_READLINE
160   rl_attempted_completion_function = (style == PROMPT_FIRST
161                                       ? complete_command_name
162                                       : dont_complete);
163   string = readline (prompt);
164   if (string == NULL)
165     eof = true;
166   else
167     {
168       if (string[0])
169         add_history (string);
170       ds_assign_cstr (line, string);
171       free (string);
172       eof = false;
173     }
174 #else
175   fputs (prompt, stdout);
176   fflush (stdout);
177   if (ds_read_line (line, stdin, SIZE_MAX))
178     {
179       ds_chomp (line, '\n');
180       eof = false;
181     }
182   else
183     eof = true;
184 #endif
185
186   /* Check whether the size of the window has changed, so that
187      the output drivers can adjust their settings as needed.  We
188      only do this for the first line of a command, as it's
189      possible that the output drivers are actually in use
190      afterward, and we don't want to confuse them in the middle
191      of output. */
192   if (style == PROMPT_FIRST)
193     terminal_check_size ();
194
195   return !eof;
196 }
197
198 static void
199 readln_close (struct getl_interface *i)
200 {
201   free (i);
202 }
203
204 /* Creates a source which uses readln to get its line */
205 struct getl_interface *
206 create_readln_source (void)
207 {
208   struct readln_source *rlns  = xzalloc (sizeof (*rlns));
209
210   rlns->interactive_func = readln_read;
211
212   rlns->parent.interactive = always_true;
213   rlns->parent.read = read_interactive;
214   rlns->parent.close = readln_close;
215
216   return &rlns->parent;
217 }
218
219
220 #if HAVE_READLINE
221 static char *command_generator (const char *text, int state);
222
223 /* Returns a set of command name completions for TEXT.
224    This is of the proper form for assigning to
225    rl_attempted_completion_function. */
226 static char **
227 complete_command_name (const char *text, int start, int end UNUSED)
228 {
229   if (start == 0)
230     {
231       /* Complete command name at start of line. */
232       return rl_completion_matches (text, command_generator);
233     }
234   else
235     {
236       /* Otherwise don't do any completion. */
237       rl_attempted_completion_over = 1;
238       return NULL;
239     }
240 }
241
242 /* Do not do any completion for TEXT. */
243 static char **
244 dont_complete (const char *text UNUSED, int start UNUSED, int end UNUSED)
245 {
246   rl_attempted_completion_over = 1;
247   return NULL;
248 }
249
250 /* If STATE is 0, returns the first command name matching TEXT.
251    Otherwise, returns the next command name matching TEXT.
252    Returns a null pointer when no matches are left. */
253 static char *
254 command_generator (const char *text, int state)
255 {
256   static const struct command *cmd;
257   const char *name;
258
259   if (state == 0)
260     cmd = NULL;
261   name = cmd_complete (text, &cmd);
262   return name ? xstrdup (name) : NULL;
263 }
264 #endif /* HAVE_READLINE */