diff options
Diffstat (limited to 'builtins/read.def')
-rw-r--r-- | builtins/read.def | 142 |
1 files changed, 112 insertions, 30 deletions
diff --git a/builtins/read.def b/builtins/read.def index d4078579..56945b95 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-2010 Free Software Foundation, Inc. +Copyright (C) 1987-2012 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -51,15 +51,17 @@ Options: -r do not allow backslashes to escape any characters -s do not echo input coming from a terminal -t timeout time out and return failure if a complete line of input is - not read withint TIMEOUT seconds. The value of the TMOUT + not read within TIMEOUT seconds. The value of the TMOUT variable is the default timeout. TIMEOUT may be a - fractional number. If TIMEOUT is 0, read returns success only - if input is available on the specified file descriptor. The + fractional number. If TIMEOUT is 0, read returns immediately, + without trying to read any data, returning success only if + input is available on the specified file descriptor. The exit status is greater than 128 if the timeout is exceeded -u fd read from file descriptor FD instead of the standard input Exit Status: -The return code is zero, unless end-of-file is encountered, read times out, +The return code is zero, unless end-of-file is encountered, read times out +(in which case it's greater than 128), a variable assignment error occurs, or an invalid file descriptor is supplied as the argument to -u. $END @@ -101,10 +103,17 @@ $END # include "input.h" #endif +#include "shmbutil.h" + #if !defined(errno) extern int errno; #endif +extern void run_pending_traps __P((void)); + +extern int posixly_correct; +extern int trapped_signal_received; + struct ttsave { int fd; @@ -127,15 +136,26 @@ static void ttyrestore __P((struct ttsave *)); static sighandler sigalrm __P((int)); static void reset_alarm __P((void)); -static procenv_t alrmbuf; +/* Try this to see what the rest of the shell can do with the information. */ +procenv_t alrmbuf; +int sigalrm_seen; + +static int reading; static SigHandler *old_alrm; static unsigned char delim; +/* In all cases, SIGALRM just sets a flag that we check periodically. This + avoids problems with the semi-tricky stuff we do with the xfree of + input_string at the top of the unwind-protect list (see below). */ + +/* Set a flag that CHECK_ALRM can check. This relies on zread calling + trap.c:check_signals_and_traps(), which knows about sigalrm_seen and + alrmbuf. */ static sighandler sigalrm (s) int s; { - longjmp (alrmbuf, 1); + sigalrm_seen = 1; } static void @@ -158,7 +178,7 @@ read_builtin (list) register char *varname; int size, i, nr, pass_next, saw_escape, eof, opt, retval, code, print_ps2; int input_is_tty, input_is_pipe, unbuffered_read, skip_ctlesc, skip_ctlnul; - int raw, edit, nchars, silent, have_timeout, ignore_delim, fd; + int raw, edit, nchars, silent, have_timeout, ignore_delim, fd, lastsig, t_errno; unsigned int tmsec, tmusec; long ival, uval; intmax_t intval; @@ -199,6 +219,9 @@ read_builtin (list) #endif USE_VAR(list); USE_VAR(ps2); + USE_VAR(lastsig); + + sigalrm_seen = reading = 0; i = 0; /* Index into the string that we are reading. */ raw = edit = 0; /* Not reading raw input by default. */ @@ -306,6 +329,18 @@ read_builtin (list) return (input_avail (fd) ? EXECUTION_SUCCESS : EXECUTION_FAILURE); #endif + /* Convenience: check early whether or not the first of possibly several + variable names is a valid identifier, and bail early if so. */ +#if defined (ARRAY_VARS) + if (list && legal_identifier (list->word->word) == 0 && valid_array_reference (list->word->word) == 0) +#else + if (list && legal_identifier (list->word->word) == 0) +#endif + { + sh_invalidid (list->word->word); + return (EXECUTION_FAILURE); + } + /* If we're asked to ignore the delimiter, make sure we do. */ if (ignore_delim) delim = -1; @@ -380,14 +415,15 @@ read_builtin (list) if (tmsec > 0 || tmusec > 0) { - code = setjmp (alrmbuf); + code = setjmp_nosigs (alrmbuf); if (code) { + sigalrm_seen = 0; /* Tricky. The top of the unwind-protect stack is the free of input_string. We want to run all the rest and use input_string, so we have to save input_string temporarily, run the unwind- - protects, then restore input_string so we can use it later. */ - + protects, then restore input_string so we can use it later */ + orig_input_string = 0; input_string[i] = '\0'; /* make sure it's terminated */ if (i == 0) { @@ -464,10 +500,12 @@ read_builtin (list) /* This *must* be the top unwind-protect on the stack, so the manipulation of the unwind-protect stack after the realloc() works right. */ add_unwind_protect (xfree, input_string); - interrupt_immediately++; - terminate_immediately++; - unbuffered_read = (nchars > 0) || (delim != '\n') || input_is_pipe; + CHECK_ALRM; + if ((nchars > 0) && (input_is_tty == 0) && ignore_delim) /* read -N */ + unbuffered_read = 2; + else if ((nchars > 0) || (delim != '\n') || input_is_pipe) + unbuffered_read = 1; if (prompt && edit == 0) { @@ -482,6 +520,8 @@ read_builtin (list) ps2 = 0; for (print_ps2 = eof = retval = 0;;) { + CHECK_ALRM; + #if defined (READLINE) if (edit) { @@ -492,7 +532,9 @@ read_builtin (list) } if (rlbuf == 0) { + reading = 1; rlbuf = edit_line (prompt ? prompt : "", itext); + reading = 0; rlind = 0; } if (rlbuf == 0) @@ -515,26 +557,58 @@ read_builtin (list) print_ps2 = 0; } - if (unbuffered_read) - retval = zread (fd, &c, 1); +#if 0 + if (posixly_correct == 0) + interrupt_immediately++; +#endif + reading = 1; + if (unbuffered_read == 2) + retval = posixly_correct ? zreadintr (fd, &c, 1) : zreadn (fd, &c, nchars - nr); + else if (unbuffered_read) + retval = posixly_correct ? zreadintr (fd, &c, 1) : zread (fd, &c, 1); else - retval = zreadc (fd, &c); + retval = posixly_correct ? zreadcintr (fd, &c) : zreadc (fd, &c); + reading = 0; +#if 0 + if (posixly_correct == 0) + interrupt_immediately--; +#endif if (retval <= 0) { + if (retval < 0 && errno == EINTR) + { + lastsig = LASTSIG(); + if (lastsig == 0) + lastsig = trapped_signal_received; + run_pending_traps (); /* because interrupt_immediately is not set */ + } + else + lastsig = 0; + CHECK_TERMSIG; eof = 1; break; } + CHECK_ALRM; + #if defined (READLINE) } #endif + CHECK_ALRM; if (i + 4 >= size) /* XXX was i + 2; use i + 4 for multibyte/read_mbchar */ { - input_string = (char *)xrealloc (input_string, size += 128); - remove_unwind_protect (); - add_unwind_protect (xfree, input_string); + char *t; + t = (char *)xrealloc (input_string, size += 128); + + /* Only need to change unwind-protect if input_string changes */ + if (t != input_string) + { + input_string = t; + remove_unwind_protect (); + add_unwind_protect (xfree, input_string); + } } /* If the next character is to be accepted verbatim, a backslash @@ -565,9 +639,12 @@ read_builtin (list) continue; } - if ((unsigned char)c == delim) + if (ignore_delim == 0 && (unsigned char)c == delim) break; + if (c == '\0' && delim != '\0') + continue; /* skip NUL bytes in input */ + if ((skip_ctlesc == 0 && c == CTLESC) || (skip_ctlnul == 0 && c == CTLNUL)) { saw_escape++; @@ -576,9 +653,10 @@ read_builtin (list) add_char: input_string[i++] = c; + CHECK_ALRM; #if defined (HANDLE_MULTIBYTE) - if (nchars > 0 && MB_CUR_MAX > 1) + if (nchars > 0 && MB_CUR_MAX > 1 && is_basic (c) == 0) { input_string[i] = '\0'; /* for simplicity and debugging */ i += read_mbchar (fd, input_string, i, c, unbuffered_read); @@ -591,15 +669,16 @@ add_char: break; } input_string[i] = '\0'; + CHECK_ALRM; -#if 1 if (retval < 0) { - builtin_error (_("read error: %d: %s"), fd, strerror (errno)); + t_errno = errno; + if (errno != EINTR) + builtin_error (_("read error: %d: %s"), fd, strerror (errno)); run_unwind_frame ("read_builtin"); - return (EXECUTION_FAILURE); + return ((t_errno != EINTR) ? EXECUTION_FAILURE : 128+lastsig); } -#endif if (tmsec > 0 || tmusec > 0) reset_alarm (); @@ -631,9 +710,6 @@ add_char: assign_vars: - interrupt_immediately--; - terminate_immediately--; - #if defined (ARRAY_VARS) /* If -a was given, take the string read, break it into a list of words, an assign them to `arrayname' in turn. */ @@ -658,6 +734,8 @@ assign_vars: xfree (input_string); return EXECUTION_FAILURE; /* existing associative array */ } + else if (invisible_p (var)) + VUNSETATTR (var, att_invisible); array_flush (array_cell (var)); alist = list_string (input_string, ifs_chars, 0); @@ -703,7 +781,7 @@ assign_vars: var = bind_variable ("REPLY", input_string, 0); VUNSETATTR (var, att_invisible); - free (input_string); + xfree (input_string); return (retval); } @@ -829,6 +907,7 @@ bind_read_variable (name, value) char *name, *value; { SHELL_VAR *v; + #if defined (ARRAY_VARS) if (valid_array_reference (name) == 0) v = bind_variable (name, value, 0); @@ -867,6 +946,7 @@ read_mbchar (fd, string, ind, ch, unbuffered) if (ret == (size_t)-2) { ps = ps_back; + /* We don't want to be interrupted during a multibyte char read */ if (unbuffered) r = zread (fd, &c, 1); else @@ -947,7 +1027,9 @@ edit_line (p, itext) rl_startup_hook = set_itext; deftext = itext; } + ret = readline (p); + rl_attempted_completion_function = old_attempted_completion_function; old_attempted_completion_function = (rl_completion_func_t *)NULL; |