Imported from ../bash-2.04.tar.gz.
This commit is contained in:
parent
b72432fdcc
commit
bb70624e96
387 changed files with 28522 additions and 9334 deletions
|
@ -7,7 +7,7 @@ This file is part of GNU Bash, the Bourne Again SHell.
|
|||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
|
@ -17,44 +17,53 @@ for more details.
|
|||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES read.c
|
||||
|
||||
$BUILTIN read
|
||||
$FUNCTION read_builtin
|
||||
$SHORT_DOC read [-r] [-p prompt] [-a array] [-e] [name ...]
|
||||
$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. The return code is
|
||||
zero, unless end-of-file is encountered. 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. If
|
||||
the `-p' option is supplied, the string supplied as an argument 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.
|
||||
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.
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "bashtypes.h"
|
||||
#include "posixstat.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../shell.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#include <shtty.h>
|
||||
|
||||
#if defined (READLINE)
|
||||
#include "../bashline.h"
|
||||
#include <readline/readline.h>
|
||||
|
@ -70,9 +79,29 @@ extern int interrupt_immediately;
|
|||
|
||||
#if defined (READLINE)
|
||||
static char *edit_line ();
|
||||
static void set_eol_delim ();
|
||||
static void reset_eol_delim ();
|
||||
#endif
|
||||
static SHELL_VAR *bind_read_variable ();
|
||||
|
||||
static procenv_t alrmbuf;
|
||||
static SigHandler *old_alrm;
|
||||
static int delim;
|
||||
|
||||
static sighandler
|
||||
sigalrm (s)
|
||||
int s;
|
||||
{
|
||||
longjmp (alrmbuf, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
reset_alarm ()
|
||||
{
|
||||
set_signal_handler (SIGALRM, old_alrm);
|
||||
alarm (0);
|
||||
}
|
||||
|
||||
/* Read the value of the shell variables whose names follow.
|
||||
The reading is done from the current input stream, whatever
|
||||
that may be. Successive words of the input line are assigned
|
||||
|
@ -84,10 +113,14 @@ read_builtin (list)
|
|||
WORD_LIST *list;
|
||||
{
|
||||
register char *varname;
|
||||
int size, i, raw, pass_next, saw_escape, eof, opt, retval, edit;
|
||||
int size, i, pass_next, saw_escape, eof, opt, retval, code;
|
||||
int input_is_tty, input_is_pipe, unbuffered_read;
|
||||
int raw, edit, tmout, nchars, silent;
|
||||
long timeoutval, ncharsval;
|
||||
char c;
|
||||
char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname;
|
||||
char *e, *t, *t1;
|
||||
struct stat tsb;
|
||||
SHELL_VAR *var;
|
||||
#if defined (ARRAY_VARS)
|
||||
WORD_LIST *alist;
|
||||
|
@ -99,6 +132,7 @@ read_builtin (list)
|
|||
|
||||
i = 0; /* Index into the string that we are reading. */
|
||||
raw = edit = 0; /* Not reading raw input by default. */
|
||||
silent = 0;
|
||||
arrayname = prompt = (char *)NULL;
|
||||
|
||||
#if defined (READLINE)
|
||||
|
@ -106,8 +140,12 @@ read_builtin (list)
|
|||
rlind = 0;
|
||||
#endif
|
||||
|
||||
tmout = -1; /* no timeout */
|
||||
nchars = input_is_tty = input_is_pipe = unbuffered_read = 0;
|
||||
delim = '\n'; /* read until newline */
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "erp:a:")) != -1)
|
||||
while ((opt = internal_getopt (list, "erp:a:d:t:n:s")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
|
@ -117,6 +155,9 @@ read_builtin (list)
|
|||
case 'p':
|
||||
prompt = list_optarg;
|
||||
break;
|
||||
case 's':
|
||||
silent = 1;
|
||||
break;
|
||||
case 'e':
|
||||
#if defined (READLINE)
|
||||
edit = 1;
|
||||
|
@ -127,6 +168,29 @@ read_builtin (list)
|
|||
arrayname = list_optarg;
|
||||
break;
|
||||
#endif
|
||||
case 't':
|
||||
code = legal_number (list_optarg, &timeoutval);
|
||||
if (code == 0 || timeoutval < 0)
|
||||
{
|
||||
builtin_error ("%s: invalid timeout specification", list_optarg);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
tmout = timeoutval;
|
||||
break;
|
||||
case 'n':
|
||||
code = legal_number (list_optarg, &ncharsval);
|
||||
if (code == 0 || ncharsval < 0)
|
||||
{
|
||||
builtin_error ("%s: invalid number specification", list_optarg);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
nchars = ncharsval;
|
||||
break;
|
||||
case 'd':
|
||||
delim = *list_optarg;
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
|
@ -134,6 +198,10 @@ read_builtin (list)
|
|||
}
|
||||
list = loptend;
|
||||
|
||||
/* `read -t 0 var' returns failure immediately. */
|
||||
if (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";
|
||||
|
@ -149,12 +217,20 @@ read_builtin (list)
|
|||
#endif
|
||||
interrupt_immediately++;
|
||||
|
||||
/* If the -p or -e flags were given, but input is not coming from the
|
||||
input_is_tty = isatty (0);
|
||||
if (input_is_tty == 0)
|
||||
#ifndef __CYGWIN32__
|
||||
input_is_pipe = (lseek (0, 0L, SEEK_CUR) < 0) && (errno == ESPIPE);
|
||||
#else
|
||||
input_is_pipe = 1;
|
||||
#endif
|
||||
|
||||
/* If the -p, -e or -s flags were given, but input is not coming from the
|
||||
terminal, turn them off. */
|
||||
if ((prompt || edit) && (isatty (0) == 0))
|
||||
if ((prompt || edit || silent) && input_is_tty == 0)
|
||||
{
|
||||
prompt = (char *)NULL;
|
||||
edit = 0;
|
||||
edit = silent = 0;
|
||||
}
|
||||
|
||||
if (prompt && edit == 0)
|
||||
|
@ -166,6 +242,67 @@ read_builtin (list)
|
|||
pass_next = 0; /* Non-zero signifies last char was backslash. */
|
||||
saw_escape = 0; /* Non-zero signifies that we saw an escape char */
|
||||
|
||||
if (tmout > 0)
|
||||
{
|
||||
/* 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))
|
||||
tmout = -1;
|
||||
}
|
||||
|
||||
if (tmout > 0)
|
||||
{
|
||||
code = setjmp (alrmbuf);
|
||||
if (code)
|
||||
{
|
||||
run_unwind_frame ("read_builtin");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
old_alrm = set_signal_handler (SIGALRM, sigalrm);
|
||||
add_unwind_protect (reset_alarm, (char *)NULL);
|
||||
alarm (tmout);
|
||||
}
|
||||
|
||||
/* If we've been asked to read only NCHARS chars, or we're using some
|
||||
character other than newline to terminate the line, do the right
|
||||
thing to readline or the tty. */
|
||||
if (nchars > 0 || delim != '\n')
|
||||
{
|
||||
#if defined (READLINE)
|
||||
if (edit)
|
||||
{
|
||||
if (nchars > 0)
|
||||
{
|
||||
unwind_protect_int (rl_num_chars_to_read);
|
||||
rl_num_chars_to_read = nchars;
|
||||
}
|
||||
if (delim != '\n')
|
||||
{
|
||||
set_eol_delim (delim);
|
||||
add_unwind_protect (reset_eol_delim, (char *)NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
#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);
|
||||
}
|
||||
|
||||
unbuffered_read = (nchars > 0) || (delim != '\n') || input_is_pipe;
|
||||
|
||||
for (eof = 0;;)
|
||||
{
|
||||
#if defined (READLINE)
|
||||
|
@ -192,8 +329,11 @@ read_builtin (list)
|
|||
{
|
||||
#endif
|
||||
|
||||
while (((retval = read (0, &c, 1)) < 0) && errno == EINTR)
|
||||
;
|
||||
if (unbuffered_read)
|
||||
retval = zread (0, &c, 1);
|
||||
else
|
||||
retval = zreadc (0, &c);
|
||||
|
||||
if (retval <= 0)
|
||||
{
|
||||
eof = 1;
|
||||
|
@ -227,7 +367,7 @@ read_builtin (list)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (c == '\n')
|
||||
if (c == delim)
|
||||
break;
|
||||
|
||||
if (c == CTLESC || c == CTLNUL)
|
||||
|
@ -237,9 +377,36 @@ read_builtin (list)
|
|||
}
|
||||
|
||||
input_string[i++] = c;
|
||||
|
||||
if (nchars > 0 && i >= nchars)
|
||||
break;
|
||||
}
|
||||
input_string[i] = '\0';
|
||||
|
||||
if (tmout > 0)
|
||||
reset_alarm ();
|
||||
|
||||
if (nchars > 0 || delim != '\n')
|
||||
{
|
||||
#if defined (READLINE)
|
||||
if (edit)
|
||||
{
|
||||
if (nchars > 0)
|
||||
rl_num_chars_to_read = 0;
|
||||
if (delim != '\n')
|
||||
reset_eol_delim ();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (input_is_tty)
|
||||
ttrestore ();
|
||||
}
|
||||
else if (silent)
|
||||
ttrestore ();
|
||||
|
||||
if (unbuffered_read == 0)
|
||||
zsyncfd (0);
|
||||
|
||||
interrupt_immediately--;
|
||||
discard_unwind_frame ("read_builtin");
|
||||
|
||||
|
@ -294,7 +461,7 @@ read_builtin (list)
|
|||
}
|
||||
else
|
||||
var = bind_variable ("REPLY", input_string);
|
||||
var->attributes &= ~att_invisible;
|
||||
VUNSETATTR (var, att_invisible);
|
||||
#if 0
|
||||
free (orig_input_string);
|
||||
#else
|
||||
|
@ -360,7 +527,7 @@ read_builtin (list)
|
|||
}
|
||||
|
||||
stupidly_hack_special_variables (varname);
|
||||
var->attributes &= ~att_invisible;
|
||||
VUNSETATTR (var, att_invisible);
|
||||
}
|
||||
|
||||
/* Now assign the rest of the line to the last variable argument. */
|
||||
|
@ -390,7 +557,7 @@ read_builtin (list)
|
|||
var = bind_read_variable (list->word->word, input_string);
|
||||
stupidly_hack_special_variables (list->word->word);
|
||||
if (var)
|
||||
var->attributes &= ~att_invisible;
|
||||
VUNSETATTR (var, att_invisible);
|
||||
free (orig_input_string);
|
||||
|
||||
return (retval);
|
||||
|
@ -434,8 +601,55 @@ edit_line (p)
|
|||
return ret;
|
||||
len = strlen (ret);
|
||||
ret = xrealloc (ret, len + 2);
|
||||
ret[len++] = '\n';
|
||||
ret[len++] = delim;
|
||||
ret[len] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int old_delim_ctype;
|
||||
static Function *old_delim_func;
|
||||
static int old_newline_ctype;
|
||||
static Function *old_newline_func;
|
||||
|
||||
static int delim_char;
|
||||
|
||||
static void
|
||||
set_eol_delim (c)
|
||||
int c;
|
||||
{
|
||||
Keymap cmap;
|
||||
|
||||
if (bash_readline_initialized == 0)
|
||||
initialize_readline ();
|
||||
cmap = rl_get_keymap ();
|
||||
|
||||
/* Change newline to self-insert */
|
||||
old_newline_ctype = cmap[RETURN].type;
|
||||
old_newline_func = cmap[RETURN].function;
|
||||
cmap[RETURN].type = ISFUNC;
|
||||
cmap[RETURN].function = rl_insert;
|
||||
|
||||
/* Bind the delimiter character to accept-line. */
|
||||
old_delim_ctype = cmap[c].type;
|
||||
old_delim_func = cmap[c].function;
|
||||
cmap[c].type = ISFUNC;
|
||||
cmap[c].function = rl_newline;
|
||||
|
||||
delim_char = c;
|
||||
}
|
||||
|
||||
static void
|
||||
reset_eol_delim (c)
|
||||
int c;
|
||||
{
|
||||
Keymap cmap;
|
||||
|
||||
cmap = rl_get_keymap ();
|
||||
|
||||
cmap[RETURN].type = old_newline_ctype;
|
||||
cmap[RETURN].function = old_newline_func;
|
||||
|
||||
cmap[delim_char].type = old_delim_ctype;
|
||||
cmap[delim_char].function = old_delim_func;
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue