]>
Commit | Line | Data |
---|---|---|
726f6388 JA |
1 | This file is read.def, from which is created read.c. |
2 | It implements the builtin "read" in Bash. | |
3 | ||
4 | Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc. | |
5 | ||
6 | This file is part of GNU Bash, the Bourne Again SHell. | |
7 | ||
8 | Bash is free software; you can redistribute it and/or modify it under | |
9 | the terms of the GNU General Public License as published by the Free | |
10 | Software Foundation; either version 1, or (at your option) any later | |
11 | version. | |
12 | ||
13 | Bash is distributed in the hope that it will be useful, but WITHOUT ANY | |
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 | for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License along | |
19 | with Bash; see the file COPYING. If not, write to the Free Software | |
20 | Foundation, 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 | 27 | One line is read from the standard input, and the first word is |
ccc6cda3 JA |
28 | assigned to the first NAME, the second word to the second NAME, and so |
29 | on, with leftover words assigned to the last NAME. Only the characters | |
726f6388 | 30 | found in $IFS are recognized as word delimiters. The return code is |
ccc6cda3 JA |
31 | zero, unless end-of-file is encountered. If no NAMEs are supplied, the |
32 | line read is stored in the REPLY variable. If the -r option is given, | |
33 | this signifies `raw' input, and backslash escaping is disabled. If | |
34 | the `-p' option is supplied, the string supplied as an argument is | |
35 | output without a trailing newline before attempting to read. If -a is | |
36 | supplied, the words read are assigned to sequential indices of ARRAY, | |
37 | starting at zero. If -e is supplied and the shell is interactive, | |
38 | readline 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 | |
60 | extern int interrupt_immediately; | |
61 | ||
ccc6cda3 JA |
62 | #if defined (READLINE) |
63 | static char *edit_line (); | |
64 | #endif | |
65 | static 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. */ |
73 | int | |
726f6388 JA |
74 | read_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 |
363 | static SHELL_VAR * |
364 | bind_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) | |
385 | static char * | |
386 | edit_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 |