diff options
Diffstat (limited to 'builtins/read.def')
-rw-r--r-- | builtins/read.def | 143 |
1 files changed, 93 insertions, 50 deletions
diff --git a/builtins/read.def b/builtins/read.def index a9d4a406..46a0407b 100644 --- a/builtins/read.def +++ b/builtins/read.def @@ -1,7 +1,7 @@ This file is read.def, from which is created read.c. It implements the builtin "read" in Bash. -Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc. +Copyright (C) 1987-2002 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -23,25 +23,28 @@ $PRODUCES read.c $BUILTIN read $FUNCTION read_builtin -$SHORT_DOC read [-ers] [-t timeout] [-p prompt] [-a array] [-n nchars] [-d delim] [name ...] -One line is read from the standard input, and the first word is -assigned to the first NAME, the second word to the second NAME, and so -on, with leftover words assigned to the last NAME. Only the characters -found in $IFS are recognized as word delimiters. If no NAMEs are supplied, -the line read is stored in the REPLY variable. If the -r option is given, -this signifies `raw' input, and backslash escaping is disabled. The --d option causes read to continue until the first character of DELIM is -read, rather than newline. If the `-p' option is supplied, the string -PROMPT is output without a trailing newline before attempting to read. -If -a is supplied, the words read are assigned to sequential indices of -ARRAY, starting at zero. If -e is supplied and the shell is interactive, -readline is used to obtain the line. If -n is supplied with a non-zero -NCHARS argument, read returns after NCHARS characters have been read. -The -s option causes input coming from a terminal to not be echoed. +$SHORT_DOC read [-ers] [-u fd] [-t timeout] [-p prompt] [-a array] [-n nchars] [-d delim] [name ...] +One line is read from the standard input, or from file descriptor FD if the +-u option is supplied, and the first word is assigned to the first NAME, +the second word to the second NAME, and so on, with leftover words assigned +to the last NAME. Only the characters found in $IFS are recognized as word +delimiters. If no NAMEs are supplied, the line read is stored in the REPLY +variable. If the -r option is given, this signifies `raw' input, and +backslash escaping is disabled. The -d option causes read to continue +until the first character of DELIM is read, rather than newline. If the -p +option is supplied, the string PROMPT is output without a trailing newline +before attempting to read. If -a is supplied, the words read are assigned +to sequential indices of ARRAY, starting at zero. If -e is supplied and +the shell is interactive, readline is used to obtain the line. If -n is +supplied with a non-zero NCHARS argument, read returns after NCHARS +characters have been read. The -s option causes input coming from a +terminal to not be echoed. The -t option causes read to time out and return failure if a complete line -of input is not read within TIMEOUT seconds. The return code is zero, -unless end-of-file is encountered or read times out. +of input is not read within TIMEOUT seconds. If the TMOUT variable is set, +its value is the default timeout. The return code is zero, unless end-of-file +is encountered, read times out, or an invalid file descriptor is supplied as +the argument to -u. $END #include <config.h> @@ -78,8 +81,6 @@ $END extern int errno; #endif -#define issep(c) (strchr (ifs_chars, (c))) - extern int interrupt_immediately; #if defined (READLINE) @@ -123,9 +124,9 @@ read_builtin (list) register char *varname; int size, i, pass_next, saw_escape, eof, opt, retval, code; int input_is_tty, input_is_pipe, unbuffered_read; - int raw, edit, nchars, silent, have_timeout; + int raw, edit, nchars, silent, have_timeout, fd; unsigned int tmout; - long timeoutval, ncharsval; + intmax_t intval; char c; char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname; char *e, *t, *t1; @@ -162,6 +163,7 @@ read_builtin (list) raw = edit = 0; /* Not reading raw input by default. */ silent = 0; arrayname = prompt = (char *)NULL; + fd = 0; /* file descriptor to read from */ #if defined (READLINE) rlbuf = (char *)0; @@ -173,7 +175,7 @@ read_builtin (list) delim = '\n'; /* read until newline */ reset_internal_getopt (); - while ((opt = internal_getopt (list, "erp:a:d:t:n:s")) != -1) + while ((opt = internal_getopt (list, "ersa:d:n:p:t:u:")) != -1) { switch (opt) { @@ -197,8 +199,8 @@ read_builtin (list) break; #endif case 't': - code = legal_number (list_optarg, &timeoutval); - if (code == 0 || timeoutval < 0 || timeoutval != (unsigned int)timeoutval) + code = legal_number (list_optarg, &intval); + if (code == 0 || intval < 0 || intval != (unsigned int)intval) { builtin_error ("%s: invalid timeout specification", list_optarg); return (EXECUTION_FAILURE); @@ -206,18 +208,33 @@ read_builtin (list) else { have_timeout = 1; - tmout = timeoutval; + tmout = intval; } break; case 'n': - code = legal_number (list_optarg, &ncharsval); - if (code == 0 || ncharsval < 0 || ncharsval != (int)ncharsval) + code = legal_number (list_optarg, &intval); + if (code == 0 || intval < 0 || intval != (int)intval) { - builtin_error ("%s: invalid number specification", list_optarg); + sh_invalidnum (list_optarg); return (EXECUTION_FAILURE); } else - nchars = ncharsval; + nchars = intval; + break; + case 'u': + code = legal_number (list_optarg, &intval); + if (code == 0 || intval < 0 || intval != (int)intval) + { + builtin_error ("%s: invalid file descriptor specification", list_optarg); + return (EXECUTION_FAILURE); + } + else + fd = intval; + if (sh_validfd (fd) == 0) + { + builtin_error ("%d: invalid file descriptor: %s", fd, strerror (errno)); + return (EXECUTION_FAILURE); + } break; case 'd': delim = *list_optarg; @@ -229,24 +246,32 @@ read_builtin (list) } list = loptend; - /* `read -t 0 var' returns failure immediately. */ + /* `read -t 0 var' returns failure immediately. XXX - should it test + whether input is available with select/FIONREAD, and fail if those + are unavailable? */ if (have_timeout && tmout == 0) return (EXECUTION_FAILURE); /* IF IFS is unset, we use the default of " \t\n". */ - var = find_variable ("IFS"); - ifs_chars = var ? value_cell (var) : " \t\n"; - if (ifs_chars == 0) /* XXX */ - ifs_chars = ""; /* XXX */ + ifs_chars = getifs (); + if (ifs_chars == 0) /* XXX - shouldn't happen */ + ifs_chars = ""; - input_string = (char *)xmalloc (size = 128); + input_string = (char *)xmalloc (size = 112); /* XXX was 128 */ + + /* $TMOUT, if set, is the default timeout for read. */ + if (have_timeout == 0 && (e = get_string_value ("TMOUT"))) + { + code = legal_number (e, &intval); + if (code == 0 || intval < 0 || intval != (unsigned int)intval) + tmout = 0; + else + tmout = intval; + } begin_unwind_frame ("read_builtin"); -#if defined (READLINE) - add_unwind_protect (xfree, rlbuf); -#endif - input_is_tty = isatty (0); + input_is_tty = isatty (fd); if (input_is_tty == 0) #ifndef __CYGWIN__ input_is_pipe = (lseek (0, 0L, SEEK_CUR) < 0) && (errno == ESPIPE); @@ -262,6 +287,11 @@ read_builtin (list) edit = silent = 0; } +#if defined (READLINE) + if (edit) + add_unwind_protect (xfree, rlbuf); +#endif + if (prompt && edit == 0) { fprintf (stderr, "%s", prompt); @@ -275,7 +305,7 @@ read_builtin (list) { /* Turn off the timeout if stdin is a regular file (e.g. from input redirection). */ - if ((fstat (0, &tsb) < 0) || S_ISREG (tsb.st_mode)) + if ((fstat (fd, &tsb) < 0) || S_ISREG (tsb.st_mode)) tmout = 0; } @@ -341,7 +371,7 @@ read_builtin (list) setmode (0, O_TEXT); #endif - for (eof = 0;;) + for (eof = retval = 0;;) { #if defined (READLINE) if (edit) @@ -368,9 +398,9 @@ read_builtin (list) #endif if (unbuffered_read) - retval = zread (0, &c, 1); + retval = zread (fd, &c, 1); else - retval = zreadc (0, &c); + retval = zreadc (fd, &c); if (retval <= 0) { @@ -425,6 +455,14 @@ read_builtin (list) } input_string[i] = '\0'; +#if 1 + if (retval < 0) + { + builtin_error ("read error: %d: %s", fd, strerror (errno)); + return (EXECUTION_FAILURE); + } +#endif + if (tmout > 0) reset_alarm (); @@ -447,7 +485,7 @@ read_builtin (list) ttrestore (); if (unbuffered_read == 0) - zsyncfd (0); + zsyncfd (fd); interrupt_immediately--; discard_unwind_frame ("read_builtin"); @@ -462,7 +500,7 @@ read_builtin (list) var = find_or_make_array_variable (arrayname, 1); if (var == 0) return EXECUTION_FAILURE; /* readonly or noassign */ - empty_array (array_cell (var)); + array_flush (array_cell (var)); alist = list_string (input_string, ifs_chars, 0); if (alist) @@ -487,7 +525,7 @@ read_builtin (list) { #if 0 orig_input_string = input_string; - for (t = input_string; ifs_chars && *ifs_chars && spctabnl(*t) && issep(*t); t++) + for (t = input_string; ifs_chars && *ifs_chars && spctabnl(*t) && isifs(*t); t++) ; input_string = t; input_string = strip_trailing_ifs_whitespace (input_string, ifs_chars, saw_escape); @@ -513,7 +551,7 @@ read_builtin (list) /* Remove IFS white space at the beginning of the input string. If $IFS is null, no field splitting is performed. */ - for (t = input_string; ifs_chars && *ifs_chars && spctabnl(*t) && issep(*t); t++) + for (t = input_string; ifs_chars && *ifs_chars && spctabnl(*t) && isifs(*t); t++) ; input_string = t; @@ -526,7 +564,7 @@ read_builtin (list) if (legal_identifier (varname) == 0) #endif { - builtin_error ("`%s': not a valid identifier", varname); + sh_invalidid (varname); xfree (orig_input_string); return (EXECUTION_FAILURE); } @@ -574,7 +612,7 @@ read_builtin (list) if (legal_identifier (list->word->word) == 0) #endif { - builtin_error ("`%s': not a valid identifier", list->word->word); + sh_invalidid (list->word->word); xfree (orig_input_string); return (EXECUTION_FAILURE); } @@ -615,6 +653,8 @@ bind_read_variable (name, value) } #if defined (READLINE) +static rl_completion_func_t *old_attempted_completion_function; + static char * edit_line (p) char *p; @@ -624,7 +664,10 @@ edit_line (p) if (!bash_readline_initialized) initialize_readline (); + old_attempted_completion_function = rl_attempted_completion_function; + rl_attempted_completion_function = (rl_completion_func_t *)NULL; ret = readline (p); + rl_attempted_completion_function = old_attempted_completion_function; if (ret == 0) return ret; len = strlen (ret); |