46b53b7008ebfe0a865b1906c8b679f177a9e801
[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/file-name.h>
33 #include <data/settings.h>
34 #include <language/command.h>
35 #include <libpspp/message.h>
36 #include <libpspp/str.h>
37 #include <libpspp/version.h>
38 #include <output/table.h>
39
40 #include "xalloc.h"
41
42 #include "gettext.h"
43 #define _(msgid) gettext (msgid)
44
45 #if HAVE_READLINE
46 #include <readline/readline.h>
47 #include <readline/history.h>
48
49 static char *history_file;
50
51 static char **complete_command_name (const char *, int, int);
52 static char **dont_complete (const char *, int, int);
53 #endif /* HAVE_READLINE */
54
55 static bool initialised = false;
56
57 /* Initialize getl. */
58 void
59 readln_initialize (void)
60 {
61   initialised = true;
62
63 #if HAVE_READLINE
64   rl_basic_word_break_characters = "\n";
65 #ifdef unix
66   if (history_file == NULL)
67     {
68       history_file = tilde_expand ("~/.pspp_history");
69       using_history ();
70       read_history (history_file);
71       stifle_history (500);
72     }
73 #endif
74 #endif
75 }
76
77 /* Close getl. */
78 void
79 readln_uninitialize (void)
80 {
81   initialised = false;
82
83 #if HAVE_READLINE && unix
84   if (history_file != NULL)
85     write_history (history_file);
86   clear_history ();
87   free (history_file);
88 #endif
89 }
90
91 /* Display a welcoming message. */
92 static void
93 welcome (void)
94 {
95   static bool welcomed = false;
96   if (welcomed)
97     return;
98   welcomed = true;
99   fputs ("PSPP is free software and you are welcome to distribute copies of "
100          "it\nunder certain conditions; type \"show copying.\" to see the "
101          "conditions.\nThere is ABSOLUTELY NO WARRANTY for PSPP; type \"show "
102          "warranty.\" for details.\n", stdout);
103   puts (stat_version);
104
105 #if HAVE_READLINE && unix
106   if (history_file == NULL)
107     {
108       history_file = tilde_expand ("~/.pspp_history");
109       using_history ();
110       read_history (history_file);
111       stifle_history (500);
112     }
113 #endif
114 }
115
116 /* Gets a line from the user and stores it into LINE.
117    Prompts the user with PROMPT.
118    Returns true if successful, false at end of file.
119    Suitable for passing to getl_append_interactive(). */
120 bool
121 readln_read (struct string *line, enum getl_prompt_style style)
122 {
123   const char *prompt = getl_get_prompt (style);
124 #if HAVE_READLINE
125   char *string;
126 #endif
127   
128   assert (initialised);
129
130   reset_msg_count ();
131
132   welcome ();
133
134 #if HAVE_READLINE
135   rl_attempted_completion_function = (style == GETL_PROMPT_FIRST
136                                       ? complete_command_name
137                                       : dont_complete);
138   string = readline (prompt);
139   if (string == NULL)
140     return false;
141   else 
142     {
143       if (string[0])
144         add_history (string);
145       ds_assign_cstr (line, string);
146       free (string);
147       return true; 
148     }
149 #else
150   fputs (prompt, stdout);
151   fflush (stdout);
152   if (ds_read_line (line, stdin)) 
153     {
154       ds_chomp (line, '\n');
155       return true;
156     }
157   else
158     return false;
159 #endif
160 }
161
162 #if HAVE_READLINE
163 static char *command_generator (const char *text, int state);
164
165 /* Returns a set of command name completions for TEXT.
166    This is of the proper form for assigning to
167    rl_attempted_completion_function. */
168 static char **
169 complete_command_name (const char *text, int start, int end UNUSED)
170 {
171   if (start == 0) 
172     {
173       /* Complete command name at start of line. */
174       return rl_completion_matches (text, command_generator); 
175     }
176   else 
177     {
178       /* Otherwise don't do any completion. */
179       rl_attempted_completion_over = 1;
180       return NULL; 
181     }
182 }
183
184 /* Do not do any completion for TEXT. */
185 static char **
186 dont_complete (const char *text UNUSED, int start UNUSED, int end UNUSED)
187 {
188   rl_attempted_completion_over = 1;
189   return NULL; 
190 }
191
192 /* If STATE is 0, returns the first command name matching TEXT.
193    Otherwise, returns the next command name matching TEXT.
194    Returns a null pointer when no matches are left. */
195 static char *
196 command_generator (const char *text, int state) 
197
198   static const struct command *cmd;
199   const char *name;
200
201   if (state == 0)
202     cmd = NULL;
203   name = cmd_complete (text, &cmd);
204   return name ? xstrdup (name) : NULL;
205 }
206 #endif /* HAVE_READLINE */