This file is read.def, from which is created read.c.
It implements the builtin "read" in Bash.
-Copyright (C) 1987-2009 Free Software Foundation, Inc.
+Copyright (C) 1987-2010 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
$BUILTIN read
$FUNCTION read_builtin
-$SHORT_DOC read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-p prompt] [-t timeout] [-u fd] [name ...]
+$SHORT_DOC read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]
Read a line from the standard input and split it into fields.
Reads a single line from the standard input, or from file descriptor FD
-e use Readline to obtain the line in an interactive shell
-i text Use TEXT as the initial text for Readline
-n nchars return after reading NCHARS characters rather than waiting
- for a newline
+ for a newline, but honor a delimiter if fewer than NCHARS
+ characters are read before the delimiter
+ -N nchars return only after reading exactly NCHARS characters, unless
+ EOF is encountered or read times out, ignoring any delimiter
-p prompt output the string PROMPT without a trailing newline before
attempting to read
-r do not allow backslashes to escape any characters
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, fd;
+ int raw, edit, nchars, silent, have_timeout, ignore_delim, fd;
unsigned int tmsec, tmusec;
long ival, uval;
intmax_t intval;
tmsec = tmusec = 0; /* no timeout */
nr = nchars = input_is_tty = input_is_pipe = unbuffered_read = have_timeout = 0;
delim = '\n'; /* read until newline */
+ ignore_delim = 0;
reset_internal_getopt ();
- while ((opt = internal_getopt (list, "ersa:d:i:n:p:t:u:")) != -1)
+ while ((opt = internal_getopt (list, "ersa:d:i:n:p:t:u:N:")) != -1)
{
switch (opt)
{
tmusec = uval;
}
break;
+ case 'N':
+ ignore_delim = 1;
+ delim = -1;
case 'n':
code = legal_number (list_optarg, &intval);
if (code == 0 || intval < 0 || intval != (int)intval)
}
list = loptend;
- /* `read -t 0 var' returns failure immediately. XXX - should it test
- whether input is available with select/FIONREAD, and fail if those
- are unavailable? */
+ /* `read -t 0 var' tests whether input is available with select/FIONREAD,
+ and fails if those are unavailable */
if (have_timeout && tmsec == 0 && tmusec == 0)
#if 0
return (EXECUTION_FAILURE);
return (input_avail (fd) ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
#endif
+ /* If we're asked to ignore the delimiter, make sure we do. */
+ if (ignore_delim)
+ delim = -1;
+
/* IF IFS is unset, we use the default of " \t\n". */
ifs_chars = getifs ();
if (ifs_chars == 0) /* XXX - shouldn't happen */
ifs_chars = "";
+ /* If we want to read exactly NCHARS chars, don't split on IFS */
+ if (ignore_delim)
+ ifs_chars = "";
for (skip_ctlesc = skip_ctlnul = 0, e = ifs_chars; *e; e++)
skip_ctlesc |= *e == CTLESC, skip_ctlnul |= *e == CTLNUL;
code = setjmp (alrmbuf);
if (code)
{
-#if 0
- run_unwind_frame ("read_builtin");
- return (EXECUTION_FAILURE);
-#else
+ /* 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. */
+
input_string[i] = '\0'; /* make sure it's terminated */
- retval = 128+SIGALRM;;
+ if (i == 0)
+ {
+ t = (char *)xmalloc (1);
+ t[0] = 0;
+ }
+ else
+ t = savestring (input_string);
+
+ run_unwind_frame ("read_builtin");
+ input_string = t;
+ retval = 128+SIGALRM;
goto assign_vars;
-#endif
}
old_alrm = set_signal_handler (SIGALRM, sigalrm);
add_unwind_protect (reset_alarm, (char *)NULL);
termsave.attrs = &ttattrs;
ttset = ttattrs;
- if (silent)
- ttfd_cbreak (fd, &ttset); /* ttcbreak () */
- else
- ttfd_onechar (fd, &ttset); /* ttonechar () */
+ i = silent ? ttfd_cbreak (fd, &ttset) : ttfd_onechar (fd, &ttset);
+ if (i < 0)
+ sh_ttyerror (1);
add_unwind_protect ((Function *)ttyrestore, (char *)&termsave);
}
}
termsave.attrs = &ttattrs;
ttset = ttattrs;
- ttfd_noecho (fd, &ttset); /* ttnoecho (); */
+ i = ttfd_noecho (fd, &ttset); /* ttnoecho (); */
+ if (i < 0)
+ sh_ttyerror (1);
add_unwind_protect ((Function *)ttyrestore, (char *)&termsave);
}
if (unbuffered_read == 0)
zsyncfd (fd);
- interrupt_immediately--;
- terminate_immediately--;
discard_unwind_frame ("read_builtin");
retval = eof ? EXECUTION_FAILURE : EXECUTION_SUCCESS;
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. */
xfree (input_string);
return EXECUTION_FAILURE; /* readonly or noassign */
}
+ if (assoc_p (var))
+ {
+ builtin_error (_("%s: cannot convert associative to indexed array"), arrayname);
+ xfree (input_string);
+ return EXECUTION_FAILURE; /* existing associative array */
+ }
array_flush (array_cell (var));
alist = list_string (input_string, ifs_chars, 0);
xfree (t1);
}
else
- var = bind_read_variable (varname, t);
+ var = bind_read_variable (varname, t ? t : "");
}
else
{
if (*input_string == 0)
tofree = input_string = t;
else
- input_string = strip_trailing_ifs_whitespace (t1, ifs_chars, saw_escape);
+ {
+ input_string = strip_trailing_ifs_whitespace (t1, ifs_chars, saw_escape);
+ tofree = t;
+ }
}
#endif
- if (saw_escape)
+ if (saw_escape && input_string && *input_string)
{
t = dequote_string (input_string);
var = bind_read_variable (list->word->word, t);
xfree (t);
}
else
- var = bind_read_variable (list->word->word, input_string);
- stupidly_hack_special_variables (list->word->word);
- FREE (tofree);
+ var = bind_read_variable (list->word->word, input_string ? input_string : "");
if (var)
- VUNSETATTR (var, att_invisible);
+ {
+ stupidly_hack_special_variables (list->word->word);
+ VUNSETATTR (var, att_invisible);
+ }
+ else
+ retval = EXECUTION_FAILURE;
+
+ FREE (tofree);
xfree (orig_input_string);
return (retval);
bind_read_variable (name, value)
char *name, *value;
{
+ SHELL_VAR *v;
#if defined (ARRAY_VARS)
if (valid_array_reference (name) == 0)
- return (bind_variable (name, value, 0));
+ v = bind_variable (name, value, 0);
else
- return (assign_array_element (name, value, 0));
+ v = assign_array_element (name, value, 0);
#else /* !ARRAY_VARS */
- return bind_variable (name, value, 0);
+ v = bind_variable (name, value, 0);
#endif /* !ARRAY_VARS */
+ return (v == 0 ? v
+ : ((readonly_p (v) || noassign_p (v)) ? (SHELL_VAR *)NULL : v));
}
#if defined (HANDLE_MULTIBYTE)