summaryrefslogtreecommitdiff
path: root/builtins/read.def
diff options
context:
space:
mode:
Diffstat (limited to 'builtins/read.def')
-rw-r--r--builtins/read.def142
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;