05b6150f85fdd4dd78be4ba2343054bd14e4d258
[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,
103                   struct string *line, enum getl_syntax *syntax)
104 {
105   struct readln_source *is  =
106     (struct readln_source *) s ;
107
108   *syntax = GETL_INTERACTIVE;
109   return is->interactive_func (line, prompt_get_style ());
110 }
111
112 static bool
113 always_true (const struct getl_interface *s UNUSED)
114 {
115   return true;
116 }
117
118 /* Display a welcoming message. */
119 static void
120 welcome (void)
121 {
122   static bool welcomed = false;
123   if (welcomed)
124     return;
125   welcomed = true;
126   fputs ("PSPP is free software and you are welcome to distribute copies of "
127          "it\nunder certain conditions; type \"show copying.\" to see the "
128          "conditions.\nThere is ABSOLUTELY NO WARRANTY for PSPP; type \"show "
129          "warranty.\" for details.\n", stdout);
130   puts (stat_version);
131
132 #if HAVE_READLINE && unix
133   if (history_file == NULL)
134     {
135       history_file = tilde_expand ("~/.pspp_history");
136       using_history ();
137       read_history (history_file);
138       stifle_history (500);
139     }
140 #endif
141 }
142
143
144
145
146
147
148 /* Gets a line from the user and stores it into LINE.
149    Prompts the user with PROMPT.
150    Returns true if successful, false at end of file.
151    */
152 static bool
153 readln_read (struct string *line, enum prompt_style style)
154 {
155   const char *prompt = prompt_get (style);
156 #if HAVE_READLINE
157   char *string;
158 #endif
159   
160   assert (initialised);
161
162   reset_msg_count ();
163
164   welcome ();
165
166 #if HAVE_READLINE
167   rl_attempted_completion_function = (style == PROMPT_FIRST
168                                       ? complete_command_name
169                                       : dont_complete);
170   string = readline (prompt);
171   if (string == NULL)
172     return false;
173   else 
174     {
175       if (string[0])
176         add_history (string);
177       ds_assign_cstr (line, string);
178       free (string);
179       return true; 
180     }
181 #else
182   fputs (prompt, stdout);
183   fflush (stdout);
184   if (ds_read_line (line, stdin)) 
185     {
186       ds_chomp (line, '\n');
187       return true;
188     }
189   else
190     return false;
191 #endif
192 }
193
194
195 static void
196 readln_close (struct getl_interface *i)
197 {
198   free (i);
199 }
200
201 /* Creates a source which uses readln to get its line */
202 struct getl_interface *
203 create_readln_source (void)
204 {
205   struct readln_source *rlns  = xzalloc (sizeof (*rlns));
206
207   rlns->interactive_func = readln_read;
208
209   rlns->parent.interactive = always_true;
210   rlns->parent.read = read_interactive;
211   rlns->parent.close = readln_close;
212
213   return (struct getl_interface *) rlns;
214 }
215
216
217 #if HAVE_READLINE
218 static char *command_generator (const char *text, int state);
219
220 /* Returns a set of command name completions for TEXT.
221    This is of the proper form for assigning to
222    rl_attempted_completion_function. */
223 static char **
224 complete_command_name (const char *text, int start, int end UNUSED)
225 {
226   if (start == 0) 
227     {
228       /* Complete command name at start of line. */
229       return rl_completion_matches (text, command_generator); 
230     }
231   else 
232     {
233       /* Otherwise don't do any completion. */
234       rl_attempted_completion_over = 1;
235       return NULL; 
236     }
237 }
238
239 /* Do not do any completion for TEXT. */
240 static char **
241 dont_complete (const char *text UNUSED, int start UNUSED, int end UNUSED)
242 {
243   rl_attempted_completion_over = 1;
244   return NULL; 
245 }
246
247 /* If STATE is 0, returns the first command name matching TEXT.
248    Otherwise, returns the next command name matching TEXT.
249    Returns a null pointer when no matches are left. */
250 static char *
251 command_generator (const char *text, int state) 
252
253   static const struct command *cmd;
254   const char *name;
255
256   if (state == 0)
257     cmd = NULL;
258   name = cmd_complete (text, &cmd);
259   return name ? xstrdup (name) : NULL;
260 }
261 #endif /* HAVE_READLINE */