]> git.ipfire.org Git - thirdparty/bash.git/blame - builtins/read.def
Imported from ../bash-2.0.tar.gz.
[thirdparty/bash.git] / builtins / read.def
CommitLineData
726f6388
JA
1This file is read.def, from which is created read.c.
2It implements the builtin "read" in Bash.
3
4Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
5
6This file is part of GNU Bash, the Bourne Again SHell.
7
8Bash is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 1, or (at your option) any later
11version.
12
13Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License along
19with Bash; see the file COPYING. If not, write to the Free Software
20Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21
22$PRODUCES read.c
23
24$BUILTIN read
25$FUNCTION read_builtin
ccc6cda3 26$SHORT_DOC read [-r] [-p prompt] [-a array] [-e] [name ...]
726f6388 27One line is read from the standard input, and the first word is
ccc6cda3
JA
28assigned to the first NAME, the second word to the second NAME, and so
29on, with leftover words assigned to the last NAME. Only the characters
726f6388 30found in $IFS are recognized as word delimiters. The return code is
ccc6cda3
JA
31zero, unless end-of-file is encountered. If no NAMEs are supplied, the
32line read is stored in the REPLY variable. If the -r option is given,
33this signifies `raw' input, and backslash escaping is disabled. If
34the `-p' option is supplied, the string supplied as an argument is
35output without a trailing newline before attempting to read. If -a is
36supplied, the words read are assigned to sequential indices of ARRAY,
37starting at zero. If -e is supplied and the shell is interactive,
38readline is used to obtain the line.
726f6388
JA
39$END
40
ccc6cda3
JA
41#include <config.h>
42
726f6388 43#include <stdio.h>
ccc6cda3
JA
44
45#if defined (HAVE_UNISTD_H)
46# include <unistd.h>
47#endif
48
726f6388
JA
49#include "../shell.h"
50#include "common.h"
ccc6cda3 51#include "bashgetopt.h"
726f6388 52
ccc6cda3
JA
53#if defined (READLINE)
54#include "../bashline.h"
55#include <readline/readline.h>
56#endif
726f6388 57
ccc6cda3 58#define issep(c) (strchr (ifs_chars, (c)))
726f6388
JA
59
60extern int interrupt_immediately;
61
ccc6cda3
JA
62#if defined (READLINE)
63static char *edit_line ();
64#endif
65static SHELL_VAR *bind_read_variable ();
66
726f6388
JA
67/* Read the value of the shell variables whose names follow.
68 The reading is done from the current input stream, whatever
69 that may be. Successive words of the input line are assigned
70 to the variables mentioned in LIST. The last variable in LIST
71 gets the remainder of the words on the line. If no variables
ccc6cda3
JA
72 are mentioned in LIST, then the default variable is $REPLY. */
73int
726f6388
JA
74read_builtin (list)
75 WORD_LIST *list;
76{
77 register char *varname;
ccc6cda3
JA
78 int size, i, raw, pass_next, saw_escape, eof, opt, retval, edit;
79 char c;
80 char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname;
81 char *e, *t, *t1;
726f6388 82 SHELL_VAR *var;
ccc6cda3
JA
83#if defined (ARRAY_VARS)
84 WORD_LIST *alist;
85#endif
86#if defined (READLINE)
87 char *rlbuf;
88 int rlind;
89#endif
726f6388
JA
90
91 i = 0; /* Index into the string that we are reading. */
ccc6cda3
JA
92 raw = edit = 0; /* Not reading raw input by default. */
93 arrayname = prompt = (char *)NULL;
94
95#if defined (READLINE)
96 rlbuf = (char *)0;
97 rlind = 0;
98#endif
726f6388 99
ccc6cda3
JA
100 reset_internal_getopt ();
101 while ((opt = internal_getopt (list, "erp:a:")) != -1)
726f6388 102 {
ccc6cda3
JA
103 switch (opt)
104 {
105 case 'r':
106 raw = 1;
726f6388 107 break;
ccc6cda3
JA
108 case 'p':
109 prompt = list_optarg;
110 break;
111 case 'e':
112#if defined (READLINE)
113 edit = 1;
114#endif
115 break;
116#if defined (ARRAY_VARS)
117 case 'a':
118 arrayname = list_optarg;
119 break;
120#endif
121 default:
122 builtin_usage ();
726f6388
JA
123 return (EX_USAGE);
124 }
726f6388 125 }
ccc6cda3 126 list = loptend;
726f6388 127
ccc6cda3 128 /* IF IFS is unset, we use the default of " \t\n". */
726f6388
JA
129 var = find_variable ("IFS");
130 ifs_chars = var ? value_cell (var) : " \t\n";
ccc6cda3
JA
131 if (ifs_chars == 0) /* XXX */
132 ifs_chars = ""; /* XXX */
726f6388 133
ccc6cda3 134 input_string = xmalloc (size = 128);
726f6388
JA
135
136 begin_unwind_frame ("read_builtin");
137 add_unwind_protect (xfree, input_string);
ccc6cda3
JA
138#if defined (READLINE)
139 add_unwind_protect (xfree, rlbuf);
140#endif
726f6388
JA
141 interrupt_immediately++;
142
ccc6cda3
JA
143 /* If the -p or -e flags were given, but input is not coming from the
144 terminal, turn them off. */
145 if ((prompt || edit) && (isatty (0) == 0))
146 {
147 prompt = (char *)NULL;
148 edit = 0;
149 }
150
151 if (prompt && edit == 0)
152 {
153 fprintf (stderr, "%s", prompt);
154 fflush (stderr);
155 }
156
726f6388
JA
157 pass_next = 0; /* Non-zero signifies last char was backslash. */
158 saw_escape = 0; /* Non-zero signifies that we saw an escape char */
159
ccc6cda3 160 for (eof = 0;;)
726f6388 161 {
ccc6cda3
JA
162#if defined (READLINE)
163 if (edit)
164 {
165 if (rlbuf && rlbuf[rlind] == '\0')
166 {
167 free (rlbuf);
168 rlbuf = (char *)0;
169 }
170 if (rlbuf == 0)
171 {
172 rlbuf = edit_line (prompt ? prompt : "");
173 rlind = 0;
174 }
175 if (rlbuf == 0)
176 {
177 eof = 1;
178 break;
179 }
180 c = rlbuf[rlind++];
181 }
182 else
183#endif
184 if (read (0, &c, 1) != 1)
185 {
186 eof = 1;
187 break;
188 }
189
726f6388
JA
190 if (i + 2 >= size)
191 input_string = xrealloc (input_string, size += 128);
192
193 /* If the next character is to be accepted verbatim, a backslash
194 newline pair still disappears from the input. */
195 if (pass_next)
196 {
197 if (c == '\n')
198 i--; /* back up over the CTLESC */
199 else
200 input_string[i++] = c;
201 pass_next = 0;
202 continue;
203 }
204
ccc6cda3 205 if (c == '\\' && raw == 0)
726f6388
JA
206 {
207 pass_next++;
208 saw_escape++;
209 input_string[i++] = CTLESC;
210 continue;
211 }
212
213 if (c == '\n')
214 break;
215
216 if (c == CTLESC || c == CTLNUL)
217 {
218 saw_escape++;
219 input_string[i++] = CTLESC;
220 }
221
222 input_string[i++] = c;
223 }
224 input_string[i] = '\0';
225
226 interrupt_immediately--;
227 discard_unwind_frame ("read_builtin");
228
ccc6cda3 229 retval = eof ? EXECUTION_FAILURE : EXECUTION_SUCCESS;
726f6388 230
ccc6cda3
JA
231#if defined (ARRAY_VARS)
232 /* If -a was given, take the string read, break it into a list of words,
233 an assign them to `arrayname' in turn. */
234 if (arrayname)
726f6388 235 {
ccc6cda3
JA
236 var = find_variable (arrayname);
237 if (var == 0)
238 var = make_new_array_variable (arrayname);
239 else if (array_p (var) == 0)
240 var = convert_var_to_array (var);
241
242 empty_array (array_cell (var));
243
244 alist = list_string (input_string, ifs_chars, 0);
245 if (alist)
246 {
247 assign_array_var_from_word_list (var, alist);
248 dispose_words (alist);
249 }
250 free (input_string);
251 return (retval);
726f6388 252 }
ccc6cda3 253#endif /* ARRAY_VARS */
726f6388
JA
254
255 if (!list)
256 {
257 if (saw_escape)
258 {
259 t = dequote_string (input_string);
260 var = bind_variable ("REPLY", t);
261 free (t);
262 }
263 else
264 var = bind_variable ("REPLY", input_string);
265 var->attributes &= ~att_invisible;
266 free (input_string);
ccc6cda3 267 return (retval);
726f6388 268 }
ccc6cda3
JA
269
270 /* This code implements the Posix.2 spec for splitting the words
271 read and assigning them to variables. */
272 orig_input_string = input_string;
273
274 /* Remove IFS white space at the beginning of the input string. If
275 $IFS is null, no field splitting is performed. */
276 for (t = input_string; ifs_chars && *ifs_chars && spctabnl(*t) && issep(*t); t++)
277 ;
278 input_string = t;
279
280 for (; list->next; list = list->next)
726f6388 281 {
ccc6cda3
JA
282 varname = list->word->word;
283#if defined (ARRAY_VARS)
284 if (legal_identifier (varname) == 0 && valid_array_reference (varname) == 0)
285#else
286 if (legal_identifier (varname) == 0)
287#endif
726f6388 288 {
ccc6cda3
JA
289 builtin_error ("`%s': not a valid identifier", varname);
290 free (orig_input_string);
291 return (EXECUTION_FAILURE);
292 }
726f6388 293
ccc6cda3
JA
294 /* If there are more variables than words read from the input,
295 the remaining variables are set to the empty string. */
296 if (*input_string)
297 {
298 /* This call updates INPUT_STRING. */
299 t = get_word_from_string (&input_string, ifs_chars, &e);
300 if (t)
301 *e = '\0';
302 /* Don't bother to remove the CTLESC unless we added one
303 somewhere while reading the string. */
304 if (t && saw_escape)
726f6388 305 {
ccc6cda3
JA
306 t1 = dequote_string (t);
307 var = bind_read_variable (varname, t1);
308 free (t1);
726f6388
JA
309 }
310 else
ccc6cda3
JA
311 var = bind_read_variable (varname, t);
312 }
313 else
314 {
315 t = (char *)0;
316 var = bind_read_variable (varname, "");
726f6388
JA
317 }
318
ccc6cda3
JA
319 FREE (t);
320 if (var == 0)
726f6388 321 {
726f6388
JA
322 free (orig_input_string);
323 return (EXECUTION_FAILURE);
324 }
325
ccc6cda3 326 stupidly_hack_special_variables (varname);
726f6388 327 var->attributes &= ~att_invisible;
ccc6cda3
JA
328 }
329
330 /* Now assign the rest of the line to the last variable argument. */
331#if defined (ARRAY_VARS)
332 if (legal_identifier (list->word->word) == 0 && valid_array_reference (list->word->word) == 0)
333#else
334 if (legal_identifier (list->word->word) == 0)
335#endif
336 {
337 builtin_error ("`%s': not a valid identifier", list->word->word);
726f6388 338 free (orig_input_string);
ccc6cda3 339 return (EXECUTION_FAILURE);
726f6388
JA
340 }
341
ccc6cda3
JA
342 /* This has to be done this way rather than using string_list
343 and list_string because Posix.2 says that the last variable gets the
344 remaining words and their intervening separators. */
345 input_string = strip_trailing_ifs_whitespace (input_string, ifs_chars, saw_escape);
346
347 if (saw_escape)
348 {
349 t = dequote_string (input_string);
350 var = bind_read_variable (list->word->word, t);
351 free (t);
352 }
353 else
354 var = bind_read_variable (list->word->word, input_string);
355 stupidly_hack_special_variables (list->word->word);
356 if (var)
357 var->attributes &= ~att_invisible;
358 free (orig_input_string);
359
726f6388
JA
360 return (retval);
361}
362
ccc6cda3
JA
363static SHELL_VAR *
364bind_read_variable (name, value)
365 char *name, *value;
366{
367#if defined (ARRAY_VARS)
368 if (valid_array_reference (name) == 0)
369 {
370 if (legal_identifier (name) == 0)
371 {
372 builtin_error ("`%s': not a valid identifier", name);
373 return ((SHELL_VAR *)NULL);
374 }
375 return (bind_variable (name, value));
376 }
377 else
378 return (do_array_element_assignment (name, value));
379#else
380 return bind_variable (name, value);
381#endif
382}
383
384#if defined (READLINE)
385static char *
386edit_line (p)
387 char *p;
726f6388 388{
ccc6cda3
JA
389 char *ret;
390 int len;
391
392 if (!bash_readline_initialized)
393 initialize_readline ();
394 ret = readline (p);
395 if (ret == 0)
396 return ret;
397 len = strlen (ret);
398 ret = xrealloc (ret, len + 2);
399 ret[len++] = '\n';
400 ret[len] = '\0';
401 return ret;
726f6388 402}
ccc6cda3 403#endif