Applying patch #5562
[pspp-builds.git] / src / ui / terminal / read-line.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301, USA. */
19
20 #include <config.h>
21
22 #include "read-line.h"
23
24 #include <stdlib.h>
25 #include <stdbool.h>
26 #include <assert.h>
27 #include <errno.h>
28
29 #include "msg-ui.h"
30
31 #include <data/file-name.h>
32 #include <data/settings.h>
33 #include <language/command.h>
34 #include <libpspp/message.h>
35 #include <libpspp/str.h>
36 #include <libpspp/version.h>
37 #include <language/prompt.h>
38
39 #include "xalloc.h"
40
41 #include "gettext.h"
42 #define _(msgid) gettext (msgid)
43
44 #if HAVE_READLINE
45 #include <readline/readline.h>
46 #include <readline/history.h>
47
48 static char *history_file;
49
50 static char **complete_command_name (const char *, int, int);
51 static char **dont_complete (const char *, int, int);
52 #endif /* HAVE_READLINE */
53
54
55 struct readln_source 
56 {
57   struct getl_interface parent ;
58
59   bool (*interactive_func) (struct string *line,
60                             enum prompt_style) ;
61 };
62
63
64 static bool initialised = false;
65
66 /* Initialize getl. */
67 void
68 readln_initialize (void)
69 {
70   initialised = true;
71
72 #if HAVE_READLINE
73   rl_basic_word_break_characters = "\n";
74 #ifdef unix
75   if (history_file == NULL)
76     {
77       history_file = tilde_expand ("~/.pspp_history");
78       using_history ();
79       read_history (history_file);
80       stifle_history (500);
81     }
82 #endif
83 #endif
84 }
85
86 /* Close getl. */
87 void
88 readln_uninitialize (void)
89 {
90   initialised = false;
91
92 #if HAVE_READLINE && unix
93   if (history_file != NULL && false == get_testing_mode() )
94     write_history (history_file);
95   clear_history ();
96   free (history_file);
97 #endif
98 }
99
100
101 static bool
102 read_interactive (struct getl_interface *s, struct string *line)
103 {
104   struct readln_source *is  =
105     (struct readln_source *) s ;
106
107   return is->interactive_func (line, prompt_get_style ());
108 }
109
110 static bool
111 always_true (const struct getl_interface *s UNUSED)
112 {
113   return true;
114 }
115
116 /* Display a welcoming message. */
117 static void
118 welcome (void)
119 {
120   static bool welcomed = false;
121   if (welcomed)
122     return;
123   welcomed = true;
124   fputs ("PSPP is free software and you are welcome to distribute copies of "
125          "it\nunder certain conditions; type \"show copying.\" to see the "
126          "conditions.\nThere is ABSOLUTELY NO WARRANTY for PSPP; type \"show "
127          "warranty.\" for details.\n", stdout);
128   puts (stat_version);
129
130 #if HAVE_READLINE && unix
131   if (history_file == NULL)
132     {
133       history_file = tilde_expand ("~/.pspp_history");
134       using_history ();
135       read_history (history_file);
136       stifle_history (500);
137     }
138 #endif
139 }
140
141
142
143
144
145
146 /* Gets a line from the user and stores it into LINE.
147    Prompts the user with PROMPT.
148    Returns true if successful, false at end of file.
149    */
150 static bool
151 readln_read (struct string *line, enum prompt_style style)
152 {
153   const char *prompt = prompt_get (style);
154 #if HAVE_READLINE
155   char *string;
156 #endif
157   
158   assert (initialised);
159
160   reset_msg_count ();
161
162   welcome ();
163
164 #if HAVE_READLINE
165   rl_attempted_completion_function = (style == PROMPT_FIRST
166                                       ? complete_command_name
167                                       : dont_complete);
168   string = readline (prompt);
169   if (string == NULL)
170     return false;
171   else 
172     {
173       if (string[0])
174         add_history (string);
175       ds_assign_cstr (line, string);
176       free (string);
177       return true; 
178     }
179 #else
180   fputs (prompt, stdout);
181   fflush (stdout);
182   if (ds_read_line (line, stdin)) 
183     {
184       ds_chomp (line, '\n');
185       return true;
186     }
187   else
188     return false;
189 #endif
190 }
191
192
193 static void
194 readln_close (struct getl_interface *i)
195 {
196   free (i);
197 }
198
199 /* Creates a source which uses readln to get its line */
200 struct getl_interface *
201 create_readln_source (void)
202 {
203   struct readln_source *rlns  = xzalloc (sizeof (*rlns));
204
205   rlns->interactive_func = readln_read;
206
207   rlns->parent.interactive = always_true;
208   rlns->parent.read = read_interactive;
209   rlns->parent.close = readln_close;
210
211   return (struct getl_interface *) rlns;
212 }
213
214
215 #if HAVE_READLINE
216 static char *command_generator (const char *text, int state);
217
218 /* Returns a set of command name completions for TEXT.
219    This is of the proper form for assigning to
220    rl_attempted_completion_function. */
221 static char **
222 complete_command_name (const char *text, int start, int end UNUSED)
223 {
224   if (start == 0) 
225     {
226       /* Complete command name at start of line. */
227       return rl_completion_matches (text, command_generator); 
228     }
229   else 
230     {
231       /* Otherwise don't do any completion. */
232       rl_attempted_completion_over = 1;
233       return NULL; 
234     }
235 }
236
237 /* Do not do any completion for TEXT. */
238 static char **
239 dont_complete (const char *text UNUSED, int start UNUSED, int end UNUSED)
240 {
241   rl_attempted_completion_over = 1;
242   return NULL; 
243 }
244
245 /* If STATE is 0, returns the first command name matching TEXT.
246    Otherwise, returns the next command name matching TEXT.
247    Returns a null pointer when no matches are left. */
248 static char *
249 command_generator (const char *text, int state) 
250
251   static const struct command *cmd;
252   const char *name;
253
254   if (state == 0)
255     cmd = NULL;
256   name = cmd_complete (text, &cmd);
257   return name ? xstrdup (name) : NULL;
258 }
259 #endif /* HAVE_READLINE */