mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-28 07:59:50 +02:00
442 lines
12 KiB
Plaintext
442 lines
12 KiB
Plaintext
*** ../bash-3.2-patched/builtins/read.def 2007-08-25 13:47:07.000000000 -0400
|
|
--- builtins/read.def 2008-02-09 16:34:39.000000000 -0500
|
|
***************
|
|
*** 1,7 ****
|
|
This file is read.def, from which is created read.c.
|
|
It implements the builtin "read" in Bash.
|
|
|
|
! Copyright (C) 1987-2005 Free Software Foundation, Inc.
|
|
|
|
This file is part of GNU Bash, the Bourne Again SHell.
|
|
|
|
--- 1,7 ----
|
|
This file is read.def, from which is created read.c.
|
|
It implements the builtin "read" in Bash.
|
|
|
|
! Copyright (C) 1987-2008 Free Software Foundation, Inc.
|
|
|
|
This file is part of GNU Bash, the Bourne Again SHell.
|
|
|
|
***************
|
|
*** 23,50 ****
|
|
|
|
$BUILTIN read
|
|
$FUNCTION read_builtin
|
|
! $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. 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>
|
|
--- 23,57 ----
|
|
|
|
$BUILTIN read
|
|
$FUNCTION read_builtin
|
|
! $SHORT_DOC read [-ers] [-a array] [-d delim] [-n nchars] [-p prompt] [-t timeout] [-u fd] [name ...]
|
|
! Reads a single line from the standard input, or from file descriptor FD
|
|
! if the -u option is supplied. The line is split into fields as with word
|
|
! splitting, and the first word is assigned to the first NAME, the second
|
|
! word to the second NAME, and so on, with any 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.
|
|
!
|
|
! Options:
|
|
! -a array assign the words read to sequential indices of the array
|
|
! variable ARRAY, starting at zero
|
|
! -d delim continue until the first character of DELIM is read, rather
|
|
! than newline
|
|
! -e use Readline to obtain the line in an interactive shell
|
|
! -n nchars return after reading NCHARS characters rather than waiting
|
|
! for a newline
|
|
! -p prompt output the string PROMPT without a trailing newline before
|
|
! attempting to read
|
|
! -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
|
|
! variable is the default timeout.
|
|
! -u fd read from file descriptor FD instead of the standard input
|
|
!
|
|
! 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>
|
|
***************
|
|
*** 87,92 ****
|
|
--- 94,105 ----
|
|
extern int errno;
|
|
#endif
|
|
|
|
+ struct ttsave
|
|
+ {
|
|
+ int fd;
|
|
+ TTYSTRUCT *attrs;
|
|
+ };
|
|
+
|
|
#if defined (READLINE)
|
|
static void reset_attempted_completion_function __P((char *));
|
|
static char *edit_line __P((char *));
|
|
***************
|
|
*** 94,99 ****
|
|
--- 107,116 ----
|
|
static void reset_eol_delim __P((char *));
|
|
#endif
|
|
static SHELL_VAR *bind_read_variable __P((char *, char *));
|
|
+ #if defined (HANDLE_MULTIBYTE)
|
|
+ static int read_mbchar __P((int, char *, int, int, int));
|
|
+ #endif
|
|
+ static void ttyrestore __P((struct ttsave *));
|
|
|
|
static sighandler sigalrm __P((int));
|
|
static void reset_alarm __P((void));
|
|
***************
|
|
*** 134,142 ****
|
|
intmax_t intval;
|
|
char c;
|
|
char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname;
|
|
! char *e, *t, *t1, *ps2;
|
|
struct stat tsb;
|
|
SHELL_VAR *var;
|
|
#if defined (ARRAY_VARS)
|
|
WORD_LIST *alist;
|
|
#endif
|
|
--- 151,161 ----
|
|
intmax_t intval;
|
|
char c;
|
|
char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname;
|
|
! char *e, *t, *t1, *ps2, *tofree;
|
|
struct stat tsb;
|
|
SHELL_VAR *var;
|
|
+ TTYSTRUCT ttattrs, ttset;
|
|
+ struct ttsave termsave;
|
|
#if defined (ARRAY_VARS)
|
|
WORD_LIST *alist;
|
|
#endif
|
|
***************
|
|
*** 263,268 ****
|
|
--- 282,289 ----
|
|
ifs_chars = getifs ();
|
|
if (ifs_chars == 0) /* XXX - shouldn't happen */
|
|
ifs_chars = "";
|
|
+ for (skip_ctlesc = skip_ctlnul = 0, e = ifs_chars; *e; e++)
|
|
+ skip_ctlesc |= *e == CTLESC, skip_ctlnul |= *e == CTLNUL;
|
|
|
|
input_string = (char *)xmalloc (size = 112); /* XXX was 128 */
|
|
|
|
***************
|
|
*** 326,333 ****
|
|
--- 347,359 ----
|
|
code = setjmp (alrmbuf);
|
|
if (code)
|
|
{
|
|
+ #if 0
|
|
run_unwind_frame ("read_builtin");
|
|
return (EXECUTION_FAILURE);
|
|
+ #else
|
|
+ retval = EXECUTION_FAILURE;
|
|
+ goto assign_vars;
|
|
+ #endif
|
|
}
|
|
old_alrm = set_signal_handler (SIGALRM, sigalrm);
|
|
add_unwind_protect (reset_alarm, (char *)NULL);
|
|
***************
|
|
*** 361,379 ****
|
|
#endif
|
|
if (input_is_tty)
|
|
{
|
|
! ttsave ();
|
|
if (silent)
|
|
! ttcbreak ();
|
|
else
|
|
! ttonechar ();
|
|
! add_unwind_protect ((Function *)ttrestore, (char *)NULL);
|
|
}
|
|
}
|
|
else if (silent) /* turn off echo but leave term in canonical mode */
|
|
{
|
|
! ttsave ();
|
|
! ttnoecho ();
|
|
! add_unwind_protect ((Function *)ttrestore, (char *)NULL);
|
|
}
|
|
|
|
/* This *must* be the top unwind-protect on the stack, so the manipulation
|
|
--- 387,416 ----
|
|
#endif
|
|
if (input_is_tty)
|
|
{
|
|
! /* ttsave() */
|
|
! termsave.fd = fd;
|
|
! ttgetattr (fd, &ttattrs);
|
|
! termsave.attrs = &ttattrs;
|
|
!
|
|
! ttset = ttattrs;
|
|
if (silent)
|
|
! ttfd_cbreak (fd, &ttset); /* ttcbreak () */
|
|
else
|
|
! ttfd_onechar (fd, &ttset); /* ttonechar () */
|
|
! add_unwind_protect ((Function *)ttyrestore, (char *)&termsave);
|
|
}
|
|
}
|
|
else if (silent) /* turn off echo but leave term in canonical mode */
|
|
{
|
|
! /* ttsave (); */
|
|
! termsave.fd = fd;
|
|
! ttgetattr (fd, &ttattrs);
|
|
! termsave.attrs = &ttattrs;
|
|
!
|
|
! ttset = ttattrs;
|
|
! ttfd_noecho (fd, &ttset); /* ttnoecho (); */
|
|
!
|
|
! add_unwind_protect ((Function *)ttyrestore, (char *)&termsave);
|
|
}
|
|
|
|
/* This *must* be the top unwind-protect on the stack, so the manipulation
|
|
***************
|
|
*** 439,445 ****
|
|
}
|
|
#endif
|
|
|
|
! if (i + 2 >= size)
|
|
{
|
|
input_string = (char *)xrealloc (input_string, size += 128);
|
|
remove_unwind_protect ();
|
|
--- 476,482 ----
|
|
}
|
|
#endif
|
|
|
|
! 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 ();
|
|
***************
|
|
*** 462,479 ****
|
|
continue;
|
|
}
|
|
|
|
if (c == '\\' && raw == 0)
|
|
{
|
|
pass_next++;
|
|
! saw_escape++;
|
|
! input_string[i++] = CTLESC;
|
|
continue;
|
|
}
|
|
|
|
if ((unsigned char)c == delim)
|
|
break;
|
|
|
|
! if (c == CTLESC || c == CTLNUL)
|
|
{
|
|
saw_escape++;
|
|
input_string[i++] = CTLESC;
|
|
--- 499,520 ----
|
|
continue;
|
|
}
|
|
|
|
+ /* This may cause problems if IFS contains CTLESC */
|
|
if (c == '\\' && raw == 0)
|
|
{
|
|
pass_next++;
|
|
! if (skip_ctlesc == 0)
|
|
! {
|
|
! saw_escape++;
|
|
! input_string[i++] = CTLESC;
|
|
! }
|
|
continue;
|
|
}
|
|
|
|
if ((unsigned char)c == delim)
|
|
break;
|
|
|
|
! if ((skip_ctlesc == 0 && c == CTLESC) || (skip_ctlnul == 0 && c == CTLNUL))
|
|
{
|
|
saw_escape++;
|
|
input_string[i++] = CTLESC;
|
|
***************
|
|
*** 481,486 ****
|
|
--- 522,536 ----
|
|
|
|
add_char:
|
|
input_string[i++] = c;
|
|
+
|
|
+ #if defined (HANDLE_MULTIBYTE)
|
|
+ if (nchars > 0 && MB_CUR_MAX > 1)
|
|
+ {
|
|
+ input_string[i] = '\0'; /* for simplicity and debugging */
|
|
+ i += read_mbchar (fd, input_string, i, c, unbuffered_read);
|
|
+ }
|
|
+ #endif
|
|
+
|
|
nr++;
|
|
|
|
if (nchars > 0 && nr >= nchars)
|
|
***************
|
|
*** 513,522 ****
|
|
else
|
|
#endif
|
|
if (input_is_tty)
|
|
! ttrestore ();
|
|
}
|
|
else if (silent)
|
|
! ttrestore ();
|
|
|
|
if (unbuffered_read == 0)
|
|
zsyncfd (fd);
|
|
--- 563,572 ----
|
|
else
|
|
#endif
|
|
if (input_is_tty)
|
|
! ttyrestore (&termsave);
|
|
}
|
|
else if (silent)
|
|
! ttyrestore (&termsave);
|
|
|
|
if (unbuffered_read == 0)
|
|
zsyncfd (fd);
|
|
***************
|
|
*** 527,532 ****
|
|
--- 577,584 ----
|
|
|
|
retval = eof ? EXECUTION_FAILURE : EXECUTION_SUCCESS;
|
|
|
|
+ assign_vars:
|
|
+
|
|
#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. */
|
|
***************
|
|
*** 603,609 ****
|
|
for (t = input_string; ifs_chars && *ifs_chars && spctabnl(*t) && isifs(*t); t++)
|
|
;
|
|
input_string = t;
|
|
-
|
|
for (; list->next; list = list->next)
|
|
{
|
|
varname = list->word->word;
|
|
--- 655,660 ----
|
|
***************
|
|
*** 674,685 ****
|
|
#else
|
|
/* Check whether or not the number of fields is exactly the same as the
|
|
number of variables. */
|
|
if (*input_string)
|
|
{
|
|
t1 = input_string;
|
|
t = get_word_from_string (&input_string, ifs_chars, &e);
|
|
if (*input_string == 0)
|
|
! input_string = t;
|
|
else
|
|
input_string = strip_trailing_ifs_whitespace (t1, ifs_chars, saw_escape);
|
|
}
|
|
--- 725,737 ----
|
|
#else
|
|
/* Check whether or not the number of fields is exactly the same as the
|
|
number of variables. */
|
|
+ tofree = NULL;
|
|
if (*input_string)
|
|
{
|
|
t1 = input_string;
|
|
t = get_word_from_string (&input_string, ifs_chars, &e);
|
|
if (*input_string == 0)
|
|
! tofree = input_string = t;
|
|
else
|
|
input_string = strip_trailing_ifs_whitespace (t1, ifs_chars, saw_escape);
|
|
}
|
|
***************
|
|
*** 694,699 ****
|
|
--- 746,753 ----
|
|
else
|
|
var = bind_read_variable (list->word->word, input_string);
|
|
stupidly_hack_special_variables (list->word->word);
|
|
+ FREE (tofree);
|
|
+
|
|
if (var)
|
|
VUNSETATTR (var, att_invisible);
|
|
xfree (orig_input_string);
|
|
***************
|
|
*** 715,720 ****
|
|
--- 769,830 ----
|
|
#endif /* !ARRAY_VARS */
|
|
}
|
|
|
|
+ #if defined (HANDLE_MULTIBYTE)
|
|
+ static int
|
|
+ read_mbchar (fd, string, ind, ch, unbuffered)
|
|
+ int fd;
|
|
+ char *string;
|
|
+ int ind, ch, unbuffered;
|
|
+ {
|
|
+ char mbchar[MB_LEN_MAX + 1];
|
|
+ int i, n, r;
|
|
+ char c;
|
|
+ size_t ret;
|
|
+ mbstate_t ps, ps_back;
|
|
+ wchar_t wc;
|
|
+
|
|
+ memset (&ps, '\0', sizeof (mbstate_t));
|
|
+ memset (&ps_back, '\0', sizeof (mbstate_t));
|
|
+
|
|
+ mbchar[0] = ch;
|
|
+ i = 1;
|
|
+ for (n = 0; n <= MB_LEN_MAX; n++)
|
|
+ {
|
|
+ ps_back = ps;
|
|
+ ret = mbrtowc (&wc, mbchar, i, &ps);
|
|
+ if (ret == (size_t)-2)
|
|
+ {
|
|
+ ps = ps_back;
|
|
+ if (unbuffered)
|
|
+ r = zread (fd, &c, 1);
|
|
+ else
|
|
+ r = zreadc (fd, &c);
|
|
+ if (r < 0)
|
|
+ goto mbchar_return;
|
|
+ mbchar[i++] = c;
|
|
+ continue;
|
|
+ }
|
|
+ else if (ret == (size_t)-1 || ret == (size_t)0 || ret > (size_t)0)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ mbchar_return:
|
|
+ if (i > 1) /* read a multibyte char */
|
|
+ /* mbchar[0] is already string[ind-1] */
|
|
+ for (r = 1; r < i; r++)
|
|
+ string[ind+r-1] = mbchar[r];
|
|
+ return i - 1;
|
|
+ }
|
|
+ #endif
|
|
+
|
|
+
|
|
+ static void
|
|
+ ttyrestore (ttp)
|
|
+ struct ttsave *ttp;
|
|
+ {
|
|
+ ttsetattr (ttp->fd, ttp->attrs);
|
|
+ }
|
|
+
|
|
#if defined (READLINE)
|
|
static rl_completion_func_t *old_attempted_completion_function = 0;
|
|
|