commit bash-20080605 snapshot

This commit is contained in:
Chet Ramey
2011-12-07 09:24:46 -05:00
parent ed35cb4a63
commit e33f22038c
36 changed files with 7216 additions and 442 deletions
+79
View File
@@ -15989,3 +15989,82 @@ parse.y
doc/{bash.1,bashref.texi}
- document the effect of setting PROMPT_DIRTRIM
6/3
---
builtins/ulimit.def
- make the multiplier (block size) for -c and -f 512 bytes only if in
Posix mode and 1024 bytes otherwise (as in previous versions). Uses
POSIXBLK and BLOCK_SIZE defines to parameterize size based on value
of posixly_correct
doc/bashref.texi
- document this addition to posix mode
builtins/common.c
- change get_numeric_arg to have a calling sequence and return value
more closely mimicking general.c:legal_number(), with the addition
of a flags word
- add extra value for `fatal' argument to get_numeric_arg to force it
to return failure to the caller rather than longjmping
builtins/common.h
- change prototype declaration for get_numeric_arg
builtins/{break,shift}.def
- change calls to get_numeric_arg to deal with new semantics and calling
sequence
builtins/history.def
- display_history now returns an int
- change calling sequence for get_numeric_arg in display_history
- display_history now returns failure to the caller if get_numeric_arg
detects an invalid number, rather than jumping back to the top level
- use value returned by display_history as return status of history
builtin, filtered through sh_chkwrite
- history no longer aborts compound commands on invalid arguments.
fixes problem reported by Chu Li <chul@cn.fujitsu.com>
{braces,subst}.c
- extract_command_subst now takes a third flags argument; passed flags
are ORd into flags passed to other functions; changed callers
subst.h
- move SX_* defines here from subst.c so parse.y:xparse_dolparen can
see them and behave appropriately
- extract_command_subst now takes a third flags argument; change
prototype
subst.c
- change extract_command_subst to call xparse_dolparen when extracting
a $() construct
- change calls to extract_delimited_string to extract_command_subst
as appropriate
- if command_substitute returns a NULL word desc, don't call
dispose_word_desc on it
parse.y
- change xparse_dolparen to use the SX_* flags now in subst.h
6/16
----
subst.c
- in quote_list, set W_HASQUOTEDNULL flag in the word if quote_string
turns "" into CTLNUL
- in dequote_list, turn off W_HASQUOTEDNULL flag in the word if
dequote_string turns CTLNUL into ""
- new function, string_list_pos_params, encapsulates everything
needed to turn the positional parameters or an array indexed with
'@' or '*' into a string, including taking care of quoting and
using the first char of $IFS, when used in another expansion like
pattern removal or pattern substitution
- change list_remove_pattern, pos_params, pos_params_pat_subst to
call string_list_pos_params. Fixes problems reported by
Stephane Chazelas <stephane_chazelas@yahoo.fr>
6/22
----
variables.h
- include assoc.h for associative arrays
- defines for case-modifying expansions and associative array variables
- sh_var_assign_func_t functions now take an extra char * parameter
+82
View File
@@ -15979,3 +15979,85 @@ parse.y
substitution. From bash-4.0-devel branch
- changes to parse_matched_pair to combine most of the flag variables
(was_dollar, in_comment, and so on) into a local flags word
6/2
---
parse.y
- call trim_pathname, which retains only the last $PROMPT_DIRTRIM
directories and replaces the intervening characters with `...',
when expanding \w and \W
doc/{bash.1,bashref.texi}
- document the effect of setting PROMPT_DIRTRIM
6/3
---
builtins/ulimit.def
- make the multiplier (block size) for -c and -f 512 bytes only if in
Posix mode and 1024 bytes otherwise (as in previous versions). Uses
POSIXBLK and BLOCK_SIZE defines to parameterize size based on value
of posixly_correct
doc/bashref.texi
- document this addition to posix mode
builtins/common.c
- change get_numeric_arg to have a calling sequence and return value
more closely mimicking general.c:legal_number(), with the addition
of a flags word
- add extra value for `fatal' argument to get_numeric_arg to force it
to return failure to the caller rather than longjmping
builtins/common.h
- change prototype declaration for get_numeric_arg
builtins/{break,shift}.def
- change calls to get_numeric_arg to deal with new semantics and calling
sequence
builtins/history.def
- display_history now returns an int
- change calling sequence for get_numeric_arg in display_history
- display_history now returns failure to the caller if get_numeric_arg
detects an invalid number, rather than jumping back to the top level
- use value returned by display_history as return status of history
builtin, filtered through sh_chkwrite
- history no longer aborts compound commands on invalid arguments.
fixes problem reported by Chu Li <chul@cn.fujitsu.com>
{braces,subst}.c
- extract_command_subst now takes a third flags argument; passed flags
are ORd into flags passed to other functions; changed callers
subst.h
- move SX_* defines here from subst.c so parse.y:xparse_dolparen can
see them and behave appropriately
- extract_command_subst now takes a third flags argument; change
prototype
subst.c
- change extract_command_subst to call xparse_dolparen when extracting
a $() construct
- change calls to extract_delimited_string to extract_command_subst
as appropriate
- if command_substitute returns a NULL word desc, don't call
dispose_word_desc on it
parse.y
- change xparse_dolparen to use the SX_* flags now in subst.h
6/16
----
subst.c
- in quote_list, set W_HASQUOTEDNULL flag in the word if quote_string
turns "" into CTLNUL
- in dequote_list, turn off W_HASQUOTEDNULL flag in the word if
dequote_string turns CTLNUL into ""
- new function, string_list_pos_params, encapsulates everything
needed to turn the positional parameters or an array indexed with
'@' or '*' into a string, including taking care of quoting and
using the first char of $IFS, when used in another expansion like
pattern removal or pattern substitution
- change list_remove_pattern, pos_params, pos_params_pat_subst to
call string_list_pos_params. Fixes problems reported by
Stephane Chazelas <stephane_chazelas@yahoo.fr>
+4
View File
@@ -763,6 +763,9 @@ tests/case.tests f
tests/case.right f
tests/comsub.tests f
tests/comsub.right f
tests/comsub-posix.tests f
tests/comsub-posix.right f
tests/comsub-posix1.sub f
tests/cond.tests f
tests/cond.right f
tests/cond-regexp.sub f
@@ -925,6 +928,7 @@ tests/run-braces f
tests/run-builtins f
tests/run-case f
tests/run-comsub f
tests/run-comsub-posix f
tests/run-cond f
tests/run-cprint f
tests/run-dbg-support f
+6
View File
@@ -759,8 +759,12 @@ tests/source3.sub f
tests/source4.sub f
tests/source5.sub f
tests/source6.sub f
tests/case.tests f
tests/case.right f
tests/comsub.tests f
tests/comsub.right f
tests/comsub-posix.tests f
tests/comsub-posix.right f
tests/cond.tests f
tests/cond.right f
tests/cond-regexp.sub f
@@ -921,7 +925,9 @@ tests/run-array f
tests/run-array2 f
tests/run-braces f
tests/run-builtins f
tests/run-case f
tests/run-comsub f
tests/run-comsub-posix f
tests/run-cond f
tests/run-cprint f
tests/run-dbg-support f
+1 -1
View File
@@ -538,7 +538,7 @@ brace_gobbler (text, tlen, indx, satisfy)
if ((c == '$' || c == '<' || c == '>') && text[i+1] == '(') /* ) */
{
si = i + 2;
t = extract_command_subst (text, &si);
t = extract_command_subst (text, &si, 0);
i = si;
free (t);
i++;
+2 -2
View File
@@ -71,7 +71,7 @@ break_builtin (list)
if (check_loop_level () == 0)
return (EXECUTION_SUCCESS);
newbreak = get_numeric_arg (list, 1);
(void)get_numeric_arg (list, 1, &newbreak);
if (newbreak <= 0)
{
@@ -111,7 +111,7 @@ continue_builtin (list)
if (check_loop_level () == 0)
return (EXECUTION_SUCCESS);
newcont = get_numeric_arg (list, 1);
(void)get_numeric_arg (list, 1, &newcont);
if (newcont <= 0)
{
+18 -13
View File
@@ -399,30 +399,35 @@ set_dollar_vars_changed ()
/* Read a numeric arg for this_command_name, the name of the shell builtin
that wants it. LIST is the word list that the arg is to come from.
Accept only the numeric argument; report an error if other arguments
follow. If FATAL is true, call throw_to_top_level, which exits the
shell; if not, call jump_to_top_level (DISCARD), which aborts the
current command. */
intmax_t
get_numeric_arg (list, fatal)
follow. If FATAL is 1, call throw_to_top_level, which exits the
shell; if it's 2, call jump_to_top_level (DISCARD), which aborts the
current command; if FATAL is 0, return an indication of an invalid
number by setting *NUMOK == 0 and return -1. */
int
get_numeric_arg (list, fatal, count)
WORD_LIST *list;
int fatal;
intmax_t *count;
{
intmax_t count = 1;
char *arg;
if (count)
*count = 1;
if (list && list->word && ISOPTION (list->word->word, '-'))
list = list->next;
if (list)
{
register char *arg;
arg = list->word->word;
if (arg == 0 || (legal_number (arg, &count) == 0))
if (arg == 0 || (legal_number (arg, count) == 0))
{
sh_neednumarg (list->word->word);
if (fatal)
sh_neednumarg (list->word->word ? list->word->word : "`'");
if (fatal == 0)
return 0;
else if (fatal == 1) /* fatal == 1; abort */
throw_to_top_level ();
else
else /* fatal == 2; discard current command */
{
top_level_cleanup ();
jump_to_top_level (DISCARD);
@@ -431,7 +436,7 @@ get_numeric_arg (list, fatal)
no_args (list->next);
}
return (count);
return (1);
}
/* Get an eight-bit status value from LIST */
+1 -1
View File
@@ -89,7 +89,7 @@ extern int dollar_vars_changed __P((void));
extern void set_dollar_vars_unchanged __P((void));
extern void set_dollar_vars_changed __P((void));
extern intmax_t get_numeric_arg __P((WORD_LIST *, int));
extern int get_numeric_arg __P((WORD_LIST *, int, intmax_t *));
extern int get_exitstat __P((WORD_LIST *));
extern int read_octal __P((char *));
+9 -5
View File
@@ -88,7 +88,7 @@ extern int current_command_line_count;
extern int force_append_history; /* shopt -s histappend */
static char *histtime __P((HIST_ENTRY *, const char *));
static void display_history __P((WORD_LIST *));
static int display_history __P((WORD_LIST *));
static void push_history __P((WORD_LIST *));
static int expand_and_print_history __P((WORD_LIST *));
@@ -197,8 +197,8 @@ history_builtin (list)
}
else if ((flags & (AFLAG|RFLAG|NFLAG|WFLAG|CFLAG)) == 0)
{
display_history (list);
return (sh_chkwrite (EXECUTION_SUCCESS));
result = display_history (list);
return (sh_chkwrite (result));
}
filename = list ? list->word->word : get_string_value ("HISTFILE");
@@ -260,7 +260,7 @@ histtime (hlist, histtimefmt)
return timestr;
}
static void
static int
display_history (list)
WORD_LIST *list;
{
@@ -271,7 +271,9 @@ display_history (list)
if (list)
{
limit = get_numeric_arg (list, 0);
if (get_numeric_arg (list, 0, &limit) == 0)
return (EXECUTION_FAILURE);
if (limit < 0)
limit = -limit;
}
@@ -305,6 +307,8 @@ display_history (list)
i++;
}
}
return (EXECUTION_SUCCESS);
}
/* Remove the last entry in the history list and add each argument in
+3 -2
View File
@@ -51,7 +51,8 @@ Options:
-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. TIMEOUT may be a
fractional number.
fractional number. 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:
@@ -374,7 +375,7 @@ read_builtin (list)
return (EXECUTION_FAILURE);
#else
input_string[i] = '\0'; /* make sure it's terminated */
retval = EXECUTION_FAILURE;
retval = 128+SIGALRM;;
goto assign_vars;
#endif
}
+1 -1
View File
@@ -573,7 +573,7 @@ add_char:
if (tmsec > 0 || tmusec > 0)
reset_alarm ();
< if (nchars > 0 || delim != '\n')
if (nchars > 0 || delim != '\n')
{
#if defined (READLINE)
if (edit)
+2 -1
View File
@@ -62,7 +62,8 @@ shift_builtin (list)
register int count;
WORD_LIST *temp;
times = get_numeric_arg (list, 0);
if (get_numeric_arg (list, 0, &times) == 0)
return (EXECUTION_FAILURE);
if (times == 0)
return (EXECUTION_SUCCESS);
+12 -4
View File
@@ -179,6 +179,14 @@ extern int errno;
#define LIMIT_HARD 0x01
#define LIMIT_SOFT 0x02
/* "Blocks" are defined as 512 bytes when in Posix mode and 1024 bytes
otherwise. */
#define POSIXBLK -2
#define BLOCKSIZE(x) (((x) == POSIXBLK && posixly_correct) ? 512 : 1024)
extern int posixly_correct;
static int _findlim __P((int));
static int ulimit_internal __P((int, char *, int, int));
@@ -212,7 +220,7 @@ static RESOURCE_LIMITS limits[] = {
{ 'b', RLIMIT_SBSIZE, 1, "socket buffer size", "bytes" },
#endif
#ifdef RLIMIT_CORE
{ 'c', RLIMIT_CORE, 512, "core file size", "blocks" },
{ 'c', RLIMIT_CORE, POSIXBLK, "core file size", "blocks" },
#endif
#ifdef RLIMIT_DATA
{ 'd', RLIMIT_DATA, 1024, "data seg size", "kbytes" },
@@ -220,7 +228,7 @@ static RESOURCE_LIMITS limits[] = {
#ifdef RLIMIT_NICE
{ 'e', RLIMIT_NICE, 1, "scheduling priority", (char *)NULL },
#endif
{ 'f', RLIMIT_FILESIZE, 512, "file size", "blocks" },
{ 'f', RLIMIT_FILESIZE, POSIXBLK, "file size", "blocks" },
#ifdef RLIMIT_SIGPENDING
{ 'i', RLIMIT_SIGPENDING, 1, "pending signals", (char *)NULL },
#endif
@@ -438,7 +446,7 @@ ulimit_internal (cmd, cmdarg, mode, multiple)
else if (all_digits (cmdarg))
{
limit = string_to_rlimtype (cmdarg);
block_factor = limits[limind].block_factor;
block_factor = BLOCKSIZE(limits[limind].block_factor);
real_limit = limit * block_factor;
if ((real_limit / block_factor) != limit)
@@ -702,7 +710,7 @@ printone (limind, curlim, pdesc)
char unitstr[64];
int factor;
factor = limits[limind].block_factor;
factor = BLOCKSIZE(limits[limind].block_factor);
if (pdesc)
{
if (limits[limind].units)
+15 -4
View File
@@ -61,6 +61,9 @@ no option is given, then -f is assumed.
Values are in 1024-byte increments, except for -t, which is in seconds,
-p, which is in increments of 512 bytes, and -u, which is an unscaled
number of processes.
Exit Status:
Returns success unless an invalid option is supplied or an error occurs.
$END
#if !defined (_MINIX)
@@ -176,6 +179,14 @@ extern int errno;
#define LIMIT_HARD 0x01
#define LIMIT_SOFT 0x02
/* "Blocks" are defined as 512 bytes when in Posix mode and 1024 bytes
otherwise. */
#define POSIXBLK -2
#define BLOCKSIZE(x) (((x) == POSIXBLK && posixly_correct) ? 512 : (x))
extern int posixly_correct;
static int _findlim __P((int));
static int ulimit_internal __P((int, char *, int, int));
@@ -209,7 +220,7 @@ static RESOURCE_LIMITS limits[] = {
{ 'b', RLIMIT_SBSIZE, 1, "socket buffer size", "bytes" },
#endif
#ifdef RLIMIT_CORE
{ 'c', RLIMIT_CORE, 512, "core file size", "blocks" },
{ 'c', RLIMIT_CORE, POSIXBLK, "core file size", "blocks" },
#endif
#ifdef RLIMIT_DATA
{ 'd', RLIMIT_DATA, 1024, "data seg size", "kbytes" },
@@ -217,7 +228,7 @@ static RESOURCE_LIMITS limits[] = {
#ifdef RLIMIT_NICE
{ 'e', RLIMIT_NICE, 1, "scheduling priority", (char *)NULL },
#endif
{ 'f', RLIMIT_FILESIZE, 512, "file size", "blocks" },
{ 'f', RLIMIT_FILESIZE, POSIXBLK, "file size", "blocks" },
#ifdef RLIMIT_SIGPENDING
{ 'i', RLIMIT_SIGPENDING, 1, "pending signals", (char *)NULL },
#endif
@@ -435,7 +446,7 @@ ulimit_internal (cmd, cmdarg, mode, multiple)
else if (all_digits (cmdarg))
{
limit = string_to_rlimtype (cmdarg);
block_factor = limits[limind].block_factor;
block_factor = BLOCKSIZE(limits[limind].block_factor);
real_limit = limit * block_factor;
if ((real_limit / block_factor) != limit)
@@ -699,7 +710,7 @@ printone (limind, curlim, pdesc)
char unitstr[64];
int factor;
factor = limits[limind].block_factor;
factor = BLOCKSIZE(limits[limind].block_factor);
if (pdesc)
{
if (limits[limind].units)
+6 -2
View File
@@ -4242,6 +4242,8 @@ The
.I "previous job"
may be referenced using
.BR %\- .
If there is only a single job, \fB%+\fP and \fB%\-\fP can both be used
to refer to that job.
In output pertaining to jobs (e.g., the output of the
.B jobs
command), the current job is always flagged with a
@@ -7749,8 +7751,10 @@ Cause \fBread\fP to time out and return failure if a complete line of
input is not read within \fItimeout\fP seconds.
\fItimeout\fP may be a decimal number with a fractional portion following
the decimal point.
This option has no effect if \fBread\fP is not reading input from the
terminal or a pipe.
This option is only effective if \fBread\fP is reading input from a
terminal, pipe, or other special file; it has no effect when reading
from regular files.
The exit status is greater than 128 if the timeout is exceeded.
.TP
.B \-u \fIfd\fP
Read input from file descriptor \fIfd\fP.
+7 -4
View File
@@ -5,12 +5,12 @@
.\" Case Western Reserve University
.\" chet@po.cwru.edu
.\"
.\" Last Change: Sun May 25 10:41:29 EDT 2008
.\" Last Change: Mon Jun 2 20:32:53 EDT 2008
.\"
.\" bash_builtins, strip all but Built-Ins section
.if \n(zZ=1 .ig zZ
.if \n(zY=1 .ig zY
.TH BASH 1 "2008 May 25" "GNU Bash-4.0"
.TH BASH 1 "2008 June 2" "GNU Bash-4.0"
.\"
.\" There's some problem with having a `@'
.\" in a tagged paragraph with the BSD man macros.
@@ -4242,6 +4242,8 @@ The
.I "previous job"
may be referenced using
.BR %\- .
If there is only a single job, \fB%+\fP and \fB%\-\fP can both be used
to refer to that job.
In output pertaining to jobs (e.g., the output of the
.B jobs
command), the current job is always flagged with a
@@ -7749,8 +7751,9 @@ Cause \fBread\fP to time out and return failure if a complete line of
input is not read within \fItimeout\fP seconds.
\fItimeout\fP may be a decimal number with a fractional portion following
the decimal point.
This option has no effect if \fBread\fP is not reading input from the
terminal or a pipe.
This option is only effective if \fBread\fP is reading input from a
terminal, pipe, or other special file; it has no effect when reading
from regular files.
.TP
.B \-u \fIfd\fP
Read input from file descriptor \fIfd\fP.
+13 -5
View File
@@ -3661,8 +3661,10 @@ Cause @code{read} to time out and return failure if a complete line of
input is not read within @var{timeout} seconds.
@var{timeout} may be a decimal number with a fractional portion following
the decimal point.
This option has no effect if @code{read} is not reading input from the
terminal or a pipe.
This option is only effective if @code{read} is reading input from a
terminal, pipe, or other special file; it has no effect when reading
from regular files.
The exit status is greater than 128 if the timeout is exceeded.
@item -u @var{fd}
Read input from file descriptor @var{fd}.
@@ -6351,6 +6353,10 @@ When the @code{xpg_echo} option is enabled, Bash does not attempt to interpret
any arguments to @code{echo} as options. Each argument is displayed, after
escape characters are converted.
@item
The @code{ulimit} builtin uses a block size of 512 bytes for the @option{-c}
and @option{-f} options.
@end enumerate
There is other @sc{posix} behavior that Bash does not implement by
@@ -6454,9 +6460,11 @@ current job, which is the last job stopped while it was in the foreground
or started in the background.
A single @samp{%} (with no accompanying job specification) also refers
to the current job.
The previous job may be referenced using @samp{%-}. In output
pertaining to jobs (e.g., the output of the @code{jobs} command),
the current job is always flagged with a @samp{+}, and the
The previous job may be referenced using @samp{%-}.
If there is only a single job, @samp{%+} and @samp{%-} can both be used
to refer to that job.
In output pertaining to jobs (e.g., the output of the @code{jobs}
command), the current job is always flagged with a @samp{+}, and the
previous job with a @samp{-}.
A job may also be referred to
+14 -6
View File
@@ -3661,8 +3661,9 @@ Cause @code{read} to time out and return failure if a complete line of
input is not read within @var{timeout} seconds.
@var{timeout} may be a decimal number with a fractional portion following
the decimal point.
This option has no effect if @code{read} is not reading input from the
terminal or a pipe.
This option is only effective if @code{read} is reading input from a
terminal, pipe, or other special file; it has no effect when reading
from regular files.
@item -u @var{fd}
Read input from file descriptor @var{fd}.
@@ -6056,7 +6057,8 @@ The version of Bash (e.g., 2.00)
@item \V
The release of Bash, version + patchlevel (e.g., 2.00.0)
@item \w
The current working directory, with @env{$HOME} abbreviated with a tilde.
The current working directory, with @env{$HOME} abbreviated with a tilde
(uses the @env{$PROMPT_DIRTRIM} variable).
@item \W
The basename of @env{$PWD}, with @env{$HOME} abbreviated with a tilde.
@item \!
@@ -6350,6 +6352,10 @@ When the @code{xpg_echo} option is enabled, Bash does not attempt to interpret
any arguments to @code{echo} as options. Each argument is displayed, after
escape characters are converted.
@item
The @code{ulimit} builtin uses a block size of 512 bytes for the @option{-c}
and @option{-f} options.
@end enumerate
There is other @sc{posix} behavior that Bash does not implement by
@@ -6453,9 +6459,11 @@ current job, which is the last job stopped while it was in the foreground
or started in the background.
A single @samp{%} (with no accompanying job specification) also refers
to the current job.
The previous job may be referenced using @samp{%-}. In output
pertaining to jobs (e.g., the output of the @code{jobs} command),
the current job is always flagged with a @samp{+}, and the
The previous job may be referenced using @samp{%-}.
If there is only a single job, @samp{%+} and @samp{%-} can both be used
to refer to that job.
In output pertaining to jobs (e.g., the output of the @code{jobs}
command), the current job is always flagged with a @samp{+}, and the
previous job with a @samp{-}.
A job may also be referred to
+43 -8
View File
@@ -372,6 +372,8 @@ inputunit: simple_list simple_list_terminator
global_command = $1;
eof_encountered = 0;
/* discard_parser_constructs (0); */
if (parser_state & PST_CMDSUBST)
parser_state |= PST_EOFTOKEN;
YYACCEPT;
}
| '\n'
@@ -379,6 +381,8 @@ inputunit: simple_list simple_list_terminator
/* Case of regular command, but not a very
interesting one. Return a NULL command. */
global_command = (COMMAND *)NULL;
if (parser_state & PST_CMDSUBST)
parser_state |= PST_EOFTOKEN;
YYACCEPT;
}
| error '\n'
@@ -770,7 +774,6 @@ function_def: WORD '(' ')' newline_list function_body
{ $$ = make_function_def ($2, $4, function_dstart, function_bstart); }
;
function_body: shell_command
{ $$ = $1; }
| shell_command redirection_list
@@ -953,6 +956,13 @@ simple_list: simple_list1
$$ = $1;
if (need_here_doc)
gather_here_documents ();
if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token)
{
global_command = $1;
eof_encountered = 0;
rewind_input_string ();
YYACCEPT;
}
}
| simple_list1 '&'
{
@@ -962,12 +972,26 @@ simple_list: simple_list1
$$ = command_connect ($1, (COMMAND *)NULL, '&');
if (need_here_doc)
gather_here_documents ();
if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token)
{
global_command = $1;
eof_encountered = 0;
rewind_input_string ();
YYACCEPT;
}
}
| simple_list1 ';'
{
$$ = $1;
if (need_here_doc)
gather_here_documents ();
if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token)
{
global_command = $1;
eof_encountered = 0;
rewind_input_string ();
YYACCEPT;
}
}
;
@@ -2258,6 +2282,15 @@ yylex ()
token_before_that = last_read_token;
last_read_token = current_token;
current_token = read_token (READ);
if ((parser_state & PST_EOFTOKEN) && current_token == shell_eof_token)
{
current_token = yacc_EOF;
if (bash_input.type == st_string)
rewind_input_string ();
}
parser_state &= ~PST_EOFTOKEN;
return (current_token);
}
@@ -2686,6 +2719,7 @@ read_token (command)
#if defined (ALIAS)
parser_state &= ~PST_ALEXPNEXT;
#endif /* ALIAS */
peek_char = shell_getc (1);
if MBTEST(peek_char == '&')
return (SEMI_SEMI_AND);
@@ -2895,7 +2929,7 @@ parse_matched_pair (qc, open, close, lenp, flags)
/* Not exactly right yet, should handle shell metacharacters, too. If
any changes are made to this test, make analogous changes to subst.c:
extract_delimited_string(). */
else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || whitespace (ret[retind - 1])))
else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || shellblank (ret[retind - 1])))
tflags |= LEX_INCOMMENT;
if (tflags & LEX_PASSNEXT) /* last char was backslash */
@@ -3015,7 +3049,7 @@ parse_matched_pair (qc, open, close, lenp, flags)
if (open == ch) /* undo previous increment */
count--;
if (ch == '(') /* ) */
nestret = parse_matched_pair (0, '(', ')', &nestlen, rflags & ~P_DQUOTE);
nestret = parse_comsub (0, '(', ')', &nestlen, (rflags|P_COMMAND) & ~P_DQUOTE);
else if (ch == '{') /* } */
nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags);
else if (ch == '[') /* ] */
@@ -3414,7 +3448,7 @@ xparse_dolparen (base, string, indp, flags)
ostring = string;
sflags = SEVAL_NONINT|SEVAL_NOHIST|SEVAL_NOFREE;
if (flags & 0x010) /* EX_NOLONGJMP */
if (flags & SX_NOLONGJMP)
sflags |= SEVAL_NOLONGJMP;
save_parser_state (&ps);
@@ -3436,7 +3470,8 @@ xparse_dolparen (base, string, indp, flags)
if (ep[-1] != ')')
{
#if DEBUG
itrace("xparse_dolparen:%d: ep[-1] != RPAREN (%d), ep = `%s'", line_number, ep[-1], ep);
if (ep[-1] != '\n')
itrace("xparse_dolparen:%d: ep[-1] != RPAREN (%d), ep = `%s'", line_number, ep[-1], ep);
#endif
while (ep > ostring && ep[-1] == '\n') ep--;
}
@@ -3450,7 +3485,7 @@ xparse_dolparen (base, string, indp, flags)
itrace("xparse_dolparen:%d: base[%d] != RPAREN (%d), base = `%s'", line_number, *indp, base[*indp], base);
#endif
if (flags & 1)
if (flags & SX_NOALLOC)
return (char *)NULL;
if (nc == 0)
@@ -4017,7 +4052,7 @@ read_token_word (character)
history literally rather than causing a possibly-
incorrect `;' to be added. ) */
push_delimiter (dstack, peek_char);
ttok = parse_matched_pair (cd, '(', ')', &ttoklen, P_COMMAND);
ttok = parse_comsub (cd, '(', ')', &ttoklen, P_COMMAND);
pop_delimiter (dstack);
}
else
@@ -4424,7 +4459,7 @@ history_delimiting_chars ()
{
/* Tricky. `for i\nin ...' should not have a semicolon, but
`for i\ndo ...' should. We do what we can. */
for (i = shell_input_line_index; whitespace(shell_input_line[i]); i++)
for (i = shell_input_line_index; whitespace (shell_input_line[i]); i++)
;
if (shell_input_line[i] && shell_input_line[i] == 'i' && shell_input_line[i+1] == 'n')
return " ";
+5538
View File
File diff suppressed because it is too large Load Diff
+46 -11
View File
@@ -372,6 +372,8 @@ inputunit: simple_list simple_list_terminator
global_command = $1;
eof_encountered = 0;
/* discard_parser_constructs (0); */
if (parser_state & PST_CMDSUBST)
parser_state |= PST_EOFTOKEN;
YYACCEPT;
}
| '\n'
@@ -379,6 +381,8 @@ inputunit: simple_list simple_list_terminator
/* Case of regular command, but not a very
interesting one. Return a NULL command. */
global_command = (COMMAND *)NULL;
if (parser_state & PST_CMDSUBST)
parser_state |= PST_EOFTOKEN;
YYACCEPT;
}
| error '\n'
@@ -762,12 +766,10 @@ case_command: CASE WORD newline_list IN newline_list ESAC
function_def: WORD '(' ')' newline_list function_body
{ $$ = make_function_def ($1, $5, function_dstart, function_bstart); }
| FUNCTION WORD '(' ')' newline_list function_body
{ $$ = make_function_def ($2, $6, function_dstart, function_bstart); }
| FUNCTION WORD newline_list function_body
{ $$ = make_function_def ($2, $4, function_dstart, function_bstart); }
| FUNCTION WORD '(' ')' newline_list function_body
{ $$ = make_function_def ($2, $6, function_dstart, function_bstart); }
;
@@ -953,6 +955,13 @@ simple_list: simple_list1
$$ = $1;
if (need_here_doc)
gather_here_documents ();
if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token)
{
global_command = $1;
eof_encountered = 0;
rewind_input_string ();
YYACCEPT;
}
}
| simple_list1 '&'
{
@@ -962,12 +971,26 @@ simple_list: simple_list1
$$ = command_connect ($1, (COMMAND *)NULL, '&');
if (need_here_doc)
gather_here_documents ();
if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token)
{
global_command = $1;
eof_encountered = 0;
rewind_input_string ();
YYACCEPT;
}
}
| simple_list1 ';'
{
$$ = $1;
if (need_here_doc)
gather_here_documents ();
if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token)
{
global_command = $1;
eof_encountered = 0;
rewind_input_string ();
YYACCEPT;
}
}
;
@@ -2258,6 +2281,15 @@ yylex ()
token_before_that = last_read_token;
last_read_token = current_token;
current_token = read_token (READ);
if ((parser_state & PST_EOFTOKEN) && current_token == shell_eof_token)
{
current_token = yacc_EOF;
if (bash_input.type == st_string)
rewind_input_string ();
}
parser_state &= ~PST_EOFTOKEN;
return (current_token);
}
@@ -2686,6 +2718,7 @@ read_token (command)
#if defined (ALIAS)
parser_state &= ~PST_ALEXPNEXT;
#endif /* ALIAS */
peek_char = shell_getc (1);
if MBTEST(peek_char == '&')
return (SEMI_SEMI_AND);
@@ -2895,7 +2928,7 @@ parse_matched_pair (qc, open, close, lenp, flags)
/* Not exactly right yet, should handle shell metacharacters, too. If
any changes are made to this test, make analogous changes to subst.c:
extract_delimited_string(). */
else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || whitespace (ret[retind - 1])))
else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || shellblank (ret[retind - 1])))
tflags |= LEX_INCOMMENT;
if (tflags & LEX_PASSNEXT) /* last char was backslash */
@@ -3015,7 +3048,7 @@ parse_matched_pair (qc, open, close, lenp, flags)
if (open == ch) /* undo previous increment */
count--;
if (ch == '(') /* ) */
nestret = parse_matched_pair (0, '(', ')', &nestlen, rflags & ~P_DQUOTE);
nestret = parse_comsub (0, '(', ')', &nestlen, (rflags|P_COMMAND) & ~P_DQUOTE);
else if (ch == '{') /* } */
nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags);
else if (ch == '[') /* ] */
@@ -3414,7 +3447,7 @@ xparse_dolparen (base, string, indp, flags)
ostring = string;
sflags = SEVAL_NONINT|SEVAL_NOHIST|SEVAL_NOFREE;
if (flags & 0x010) /* EX_NOLONGJMP */
if (flags & SX_NOLONGJMP)
sflags |= SEVAL_NOLONGJMP;
save_parser_state (&ps);
@@ -3436,7 +3469,8 @@ xparse_dolparen (base, string, indp, flags)
if (ep[-1] != ')')
{
#if DEBUG
itrace("xparse_dolparen:%d: ep[-1] != RPAREN (%d), ep = `%s'", line_number, ep[-1], ep);
if (ep[-1] != '\n')
itrace("xparse_dolparen:%d: ep[-1] != RPAREN (%d), ep = `%s'", line_number, ep[-1], ep);
#endif
while (ep > ostring && ep[-1] == '\n') ep--;
}
@@ -3450,7 +3484,7 @@ xparse_dolparen (base, string, indp, flags)
itrace("xparse_dolparen:%d: base[%d] != RPAREN (%d), base = `%s'", line_number, *indp, base[*indp], base);
#endif
if (flags & 1)
if (flags & SX_NOALLOC)
return (char *)NULL;
if (nc == 0)
@@ -4017,7 +4051,7 @@ read_token_word (character)
history literally rather than causing a possibly-
incorrect `;' to be added. ) */
push_delimiter (dstack, peek_char);
ttok = parse_matched_pair (cd, '(', ')', &ttoklen, P_COMMAND);
ttok = parse_comsub (cd, '(', ')', &ttoklen, P_COMMAND);
pop_delimiter (dstack);
}
else
@@ -4424,7 +4458,7 @@ history_delimiting_chars ()
{
/* Tricky. `for i\nin ...' should not have a semicolon, but
`for i\ndo ...' should. We do what we can. */
for (i = shell_input_line_index; whitespace(shell_input_line[i]); i++)
for (i = shell_input_line_index; whitespace (shell_input_line[i]); i++)
;
if (shell_input_line[i] && shell_input_line[i] == 'i' && shell_input_line[i+1] == 'n')
return " ";
@@ -4752,6 +4786,7 @@ decode_prompt_string (string)
no longer than PATH_MAX - 1 characters. */
strcpy (t_string, polite_directory_format (t_string));
temp = trim_pathname (t_string, PATH_MAX - 1);
/* If we're going to be expanding the prompt string later,
quote the directory name. */
if (promptvars || posixly_correct)
+97 -39
View File
@@ -4,7 +4,7 @@
/* ``Have a little faith, there's magic in the night. You ain't a
beauty, but, hey, you're alright.'' */
/* Copyright (C) 1987-2007 Free Software Foundation, Inc.
/* Copyright (C) 1987-2008 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -69,6 +69,7 @@ extern int errno;
#define VT_POSPARMS 1
#define VT_ARRAYVAR 2
#define VT_ARRAYMEMBER 3
#define VT_ASSOCVAR 4
#define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */
@@ -78,14 +79,6 @@ extern int errno;
#define ST_SQUOTE 0x04 /* unused yet */
#define ST_DQUOTE 0x08 /* unused yet */
/* Flags for the string extraction functions. */
#define SX_NOALLOC 0x01 /* just skip; don't return substring */
#define SX_VARNAME 0x02 /* variable name; for string_extract () */
#define SX_REQMATCH 0x04 /* closing/matching delimiter required */
#define SX_COMMAND 0x08 /* extracting a shell script/command */
#define SX_NOCTLESC 0x10 /* don't honor CTLESC quoting */
#define SX_NOESCCTLNUL 0x20 /* don't let CTLESC quote CTLNUL */
/* Flags for the `pflags' argument to param_expand() */
#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */
@@ -715,7 +708,7 @@ add_one_character:
si = i + 2;
if (string[i + 1] == LPAREN)
ret = extract_delimited_string (string, &si, "$(", "(", ")", SX_COMMAND); /*)*/
ret = extract_command_subst (string, &si, 0);
else
ret = extract_dollar_brace_string (string, &si, 1, 0);
@@ -817,7 +810,7 @@ skip_double_quoted (string, slen, sind)
{
si = i + 2;
if (string[i + 1] == LPAREN)
ret = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
ret = extract_command_subst (string, &si, SX_NOALLOC);
else
ret = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
@@ -940,6 +933,7 @@ string_extract_verbatim (string, slen, sindex, charlist, flags)
i += 2;
continue;
}
#if defined (HANDLE_MULTIBYTE)
mblength = MBLEN (string + i, slen - i);
if (mblength > 1)
@@ -987,13 +981,21 @@ string_extract_verbatim (string, slen, sindex, charlist, flags)
/* Extract the $( construct in STRING, and return a new string.
Start extracting at (SINDEX) as if we had just seen "$(".
Make (SINDEX) get the position of the matching ")". ) */
Make (SINDEX) get the position of the matching ")". )
XFLAGS is additional flags to pass to other extraction functions, */
char *
extract_command_subst (string, sindex)
extract_command_subst (string, sindex, xflags)
char *string;
int *sindex;
int xflags;
{
return (extract_delimited_string (string, sindex, "$(", "(", ")", SX_COMMAND)); /*)*/
if (string[*sindex] == '(') /*)*/
return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/
else
{
xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0);
return (xparse_dolparen (string, string+*sindex, sindex, xflags));
}
}
/* Extract the $[ construct in STRING, and return a new string. (])
@@ -1100,7 +1102,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
/* Not exactly right yet; should handle shell metacharacters and
multibyte characters, too. */
if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || whitespace (string[i - 1])))
if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1])))
{
in_comment = 1;
ADVANCE_CHAR (string, slen, i);
@@ -1265,7 +1267,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
if (string[i] == '$' && string[i+1] == LPAREN)
{
si = i + 2;
t = extract_delimited_string (string, &si, "$(", "(", ")", flags|SX_NOALLOC|SX_COMMAND); /*)*/
t = extract_command_subst (string, &si, flags|SX_NOALLOC);
i = si + 1;
continue;
}
@@ -1953,6 +1955,55 @@ string_list_dollar_at (list, quoted)
return ret;
}
/* Turn the positional paramters into a string, understanding quoting and
the various subtleties of using the first character of $IFS as the
separator. Calls string_list_dollar_at, string_list_dollar_star, and
string_list as appropriate. */
char *
string_list_pos_params (pchar, list, quoted)
int pchar;
WORD_LIST *list;
int quoted;
{
char *ret;
WORD_LIST *tlist;
if (pchar == '*' && (quoted & Q_DOUBLE_QUOTES))
{
tlist = quote_list (list);
word_list_remove_quoted_nulls (tlist);
ret = string_list_dollar_star (tlist);
}
else if (pchar == '*' && (quoted & Q_HERE_DOCUMENT))
{
tlist = quote_list (list);
word_list_remove_quoted_nulls (tlist);
ret = string_list (tlist);
}
else if (pchar == '*')
{
/* Even when unquoted, string_list_dollar_star does the right thing
making sure that the first character of $IFS is used as the
separator. */
ret = string_list_dollar_star (list);
}
else if (pchar == '@' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
/* We use string_list_dollar_at, but only if the string is quoted, since
that quotes the escapes if it's not, which we don't want. We could
use string_list (the old code did), but that doesn't do the right
thing if the first character of $IFS is not a space. We use
string_list_dollar_star if the string is unquoted so we make sure that
the elements of $@ are separated by the first character of $IFS for
later splitting. */
ret = string_list_dollar_at (list, quoted);
else if (pchar == '@')
ret = string_list_dollar_star (list);
else
ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list);
return ret;
}
/* Return the list of words present in STRING. Separate the string into
words at any of the characters found in SEPARATORS. If QUOTED is
non-zero then word in the list will have its quoted flag set, otherwise
@@ -2578,17 +2629,9 @@ pos_params (string, start, end, quoted)
}
t->next = (WORD_LIST *)NULL;
if (string[0] == '*')
{
if (quoted & Q_DOUBLE_QUOTES)
ret = string_list_dollar_star (quote_list (h));
else if (quoted & Q_HERE_DOCUMENT)
ret = string_list (quote_list (h));
else
ret = string_list (h);
}
else
ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (h) : h);
ret = string_list_pos_params (string[0], h, quoted);
if (t != params)
t->next = params;
@@ -3226,9 +3269,10 @@ quote_list (list)
{
t = w->word->word;
w->word->word = quote_string (t);
free (t);
if (*t == 0)
w->word->flags |= W_HASQUOTEDNULL; /* XXX - turn on W_HASQUOTEDNULL here? */
w->word->flags |= W_QUOTED;
/* XXX - turn on W_HAVEQUOTEDNULL here? */
free (t);
}
return list;
}
@@ -3244,9 +3288,10 @@ dequote_list (list)
for (tlist = list; tlist; tlist = tlist->next)
{
s = dequote_string (tlist->word->word);
if (QUOTED_NULL (tlist->word->word))
tlist->word->flags &= ~W_HASQUOTEDNULL;
free (tlist->word->word);
tlist->word->word = s;
/* XXX - turn off W_HAVEQUOTEDNULL here? */
}
return list;
}
@@ -3983,12 +4028,9 @@ list_remove_pattern (list, pattern, patspec, itype, quoted)
}
l = REVERSE_LIST (new, WORD_LIST *);
if (itype == '*')
tword = (quoted & Q_DOUBLE_QUOTES) ? string_list_dollar_star (l) : string_list (l);
else
tword = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (l) : l);
tword = string_list_pos_params (itype, l, quoted);
dispose_words (l);
return (tword);
}
@@ -5813,6 +5855,7 @@ pos_params_pat_subst (string, pat, rep, mflags)
WORD_LIST *save, *params;
WORD_DESC *w;
char *ret;
int pchar, qflags;
save = params = list_rest_of_args ();
if (save == 0)
@@ -5827,10 +5870,22 @@ pos_params_pat_subst (string, pat, rep, mflags)
params->word = w;
}
pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
#if 0
if ((mflags & (MATCH_QUOTED|MATCH_STARSUB)) == (MATCH_QUOTED|MATCH_STARSUB))
ret = string_list_dollar_star (quote_list (save));
else if ((mflags & MATCH_STARSUB) == MATCH_STARSUB)
ret = string_list_dollar_star (save);
else if ((mflags & MATCH_QUOTED) == MATCH_QUOTED)
ret = string_list_dollar_at (save, qflags);
else
ret = string_list ((mflags & MATCH_QUOTED) ? quote_list (save) : save);
ret = string_list_dollar_star (save);
#else
ret = string_list_pos_params (pchar, save, qflags);
#endif
dispose_words (save);
return (ret);
@@ -6137,6 +6192,7 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll
temp = (char *)NULL;
goto bad_substitution;
}
/* Indirect expansion begins with a `!'. A valid indirect expansion is
either a variable name, one of the positional parameters or a special
variable that expands to one of the positional parameters. */
@@ -6676,7 +6732,7 @@ param_expand (string, sindex, quoted, expanded_something,
case LPAREN:
/* We have to extract the contents of this paren substitution. */
t_index = zindex + 1;
temp = extract_command_subst (string, &t_index);
temp = extract_command_subst (string, &t_index, 0);
zindex = t_index;
/* For Posix.2-style `$(( ))' arithmetic substitution,
@@ -6735,7 +6791,8 @@ comsub:
{
tdesc = command_substitute (temp, quoted);
temp1 = tdesc ? tdesc->word : (char *)NULL;
dispose_word_desc (tdesc);
if (tdesc)
dispose_word_desc (tdesc);
}
FREE (temp);
temp = temp1;
@@ -7153,7 +7210,8 @@ add_string:
de_backslash (temp);
tword = command_substitute (temp, quoted);
temp1 = tword ? tword->word : (char *)NULL;
dispose_word_desc (tword);
if (tword)
dispose_word_desc (tword);
}
FREE (temp);
temp = temp1;
+286 -136
View File
@@ -4,7 +4,7 @@
/* ``Have a little faith, there's magic in the night. You ain't a
beauty, but, hey, you're alright.'' */
/* Copyright (C) 1987-2007 Free Software Foundation, Inc.
/* Copyright (C) 1987-2008 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -69,6 +69,7 @@ extern int errno;
#define VT_POSPARMS 1
#define VT_ARRAYVAR 2
#define VT_ARRAYMEMBER 3
#define VT_ASSOCVAR 4
#define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */
@@ -78,13 +79,6 @@ extern int errno;
#define ST_SQUOTE 0x04 /* unused yet */
#define ST_DQUOTE 0x08 /* unused yet */
/* Flags for the string extraction functions. */
#define SX_NOALLOC 0x01 /* just skip; don't return substring */
#define SX_VARNAME 0x02 /* variable name; for string_extract () */
#define SX_REQMATCH 0x04 /* closing/matching delimiter required */
#define SX_COMMAND 0x08 /* extracting a shell script/command */
#define SX_NOCTLESC 0x10 /* don't honor CTLESC quoting */
/* Flags for the `pflags' argument to param_expand() */
#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */
@@ -135,6 +129,8 @@ size_t ifs_firstc_len;
unsigned char ifs_firstc;
#endif
int assigning_in_environment;
/* Extern functions and variables from different files. */
extern int last_command_exit_value, last_command_exit_signal;
extern int subshell_environment;
@@ -206,7 +202,6 @@ static WORD_LIST *list_quote_escapes __P((WORD_LIST *));
static char *dequote_escapes __P((char *));
static char *make_quoted_char __P((int));
static WORD_LIST *quote_list __P((WORD_LIST *));
static char *remove_quoted_escapes __P((char *));
static char *remove_quoted_nulls __P((char *));
static int unquoted_substring __P((char *, char *));
@@ -713,7 +708,7 @@ add_one_character:
si = i + 2;
if (string[i + 1] == LPAREN)
ret = extract_delimited_string (string, &si, "$(", "(", ")", SX_COMMAND); /*)*/
ret = extract_command_subst (string, &si, 0);
else
ret = extract_dollar_brace_string (string, &si, 1, 0);
@@ -815,7 +810,7 @@ skip_double_quoted (string, slen, sind)
{
si = i + 2;
if (string[i + 1] == LPAREN)
ret = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
ret = extract_command_subst (string, &si, SX_NOALLOC);
else
ret = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
@@ -930,6 +925,14 @@ string_extract_verbatim (string, slen, sindex, charlist, flags)
i += 2;
continue;
}
/* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL
through, to protect the CTLNULs from later calls to
remove_quoted_nulls. */
else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL)
{
i += 2;
continue;
}
#if defined (HANDLE_MULTIBYTE)
mblength = MBLEN (string + i, slen - i);
@@ -978,13 +981,21 @@ string_extract_verbatim (string, slen, sindex, charlist, flags)
/* Extract the $( construct in STRING, and return a new string.
Start extracting at (SINDEX) as if we had just seen "$(".
Make (SINDEX) get the position of the matching ")". ) */
Make (SINDEX) get the position of the matching ")". )
XFLAGS is additional flags to pass to other extraction functions, */
char *
extract_command_subst (string, sindex)
extract_command_subst (string, sindex, xflags)
char *string;
int *sindex;
int xflags;
{
return (extract_delimited_string (string, sindex, "$(", "(", ")", SX_COMMAND)); /*)*/
if (string[*sindex] == '(') /*)*/
return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/
else
{
xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0);
return (xparse_dolparen (string, string+*sindex, sindex, xflags));
}
}
/* Extract the $[ construct in STRING, and return a new string. (])
@@ -1091,7 +1102,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
/* Not exactly right yet; should handle shell metacharacters and
multibyte characters, too. */
if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || whitespace (string[i - 1])))
if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1])))
{
in_comment = 1;
ADVANCE_CHAR (string, slen, i);
@@ -1256,7 +1267,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
if (string[i] == '$' && string[i+1] == LPAREN)
{
si = i + 2;
t = extract_delimited_string (string, &si, "$(", "(", ")", flags|SX_NOALLOC|SX_COMMAND); /*)*/
t = extract_command_subst (string, &si, flags|SX_NOALLOC);
i = si + 1;
continue;
}
@@ -1353,6 +1364,91 @@ unquote_bang (string)
}
#endif
#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0)
/* Skip characters in STRING until we find a character in DELIMS, and return
the index of that character. START is the index into string at which we
begin. This is similar in spirit to strpbrk, but it returns an index into
STRING and takes a starting index. This little piece of code knows quite
a lot of shell syntax. It's very similar to skip_double_quoted and other
functions of that ilk. */
int
skip_to_delim (string, start, delims, flags)
char *string;
int start;
char *delims;
int flags;
{
int i, pass_next, backq, si, c;
size_t slen;
char *temp;
DECLARE_MBSTATE;
slen = strlen (string + start) + start;
if (flags & SD_NOJMP)
no_longjmp_on_fatal_error = 1;
i = start;
pass_next = backq = 0;
while (c = string[i])
{
if (pass_next)
{
pass_next = 0;
if (c == 0)
CQ_RETURN(i);
ADVANCE_CHAR (string, slen, i);
continue;
}
else if (c == '\\')
{
pass_next = 1;
i++;
continue;
}
else if (backq)
{
if (c == '`')
backq = 0;
ADVANCE_CHAR (string, slen, i);
continue;
}
else if (c == '`')
{
backq = 1;
i++;
continue;
}
else if (c == '\'' || c == '"')
{
i = (c == '\'') ? skip_single_quoted (string, slen, ++i)
: skip_double_quoted (string, slen, ++i);
/* no increment, the skip functions increment past the closing quote. */
}
else if (c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
{
si = i + 2;
if (string[si] == '\0')
CQ_RETURN(si);
if (string[i+1] == LPAREN)
temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
else
temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
i = si;
if (string[i] == '\0') /* don't increment i past EOS in loop */
break;
i++;
continue;
}
else if (member (c, delims))
break;
else
ADVANCE_CHAR (string, slen, i);
}
CQ_RETURN(i);
}
#if defined (READLINE)
/* Return 1 if the portion of STRING ending at EINDEX is quoted (there is
an unclosed quoted string), or if the character at EINDEX is quoted
@@ -1362,8 +1458,6 @@ unquote_bang (string)
recognizes need to be the same as the contents of
rl_completer_quote_characters. */
#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0)
int
char_is_quoted (string, eindex)
char *string;
@@ -1456,87 +1550,6 @@ unclosed_pair (string, eindex, openstr)
return (openc);
}
/* Skip characters in STRING until we find a character in DELIMS, and return
the index of that character. START is the index into string at which we
begin. This is similar in spirit to strpbrk, but it returns an index into
STRING and takes a starting index. This little piece of code knows quite
a lot of shell syntax. It's very similar to skip_double_quoted and other
functions of that ilk. */
int
skip_to_delim (string, start, delims)
char *string;
int start;
char *delims;
{
int i, pass_next, backq, si, c;
size_t slen;
char *temp;
DECLARE_MBSTATE;
slen = strlen (string + start) + start;
no_longjmp_on_fatal_error = 1;
i = start;
pass_next = backq = 0;
while (c = string[i])
{
if (pass_next)
{
pass_next = 0;
if (c == 0)
CQ_RETURN(i);
ADVANCE_CHAR (string, slen, i);
continue;
}
else if (c == '\\')
{
pass_next = 1;
i++;
continue;
}
else if (backq)
{
if (c == '`')
backq = 0;
ADVANCE_CHAR (string, slen, i);
continue;
}
else if (c == '`')
{
backq = 1;
i++;
continue;
}
else if (c == '\'' || c == '"')
{
i = (c == '\'') ? skip_single_quoted (string, slen, ++i)
: skip_double_quoted (string, slen, ++i);
/* no increment, the skip functions increment past the closing quote. */
}
else if (c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
{
si = i + 2;
if (string[si] == '\0')
CQ_RETURN(si);
if (string[i+1] == LPAREN)
temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
else
temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
i = si;
if (string[i] == '\0') /* don't increment i past EOS in loop */
break;
i++;
continue;
}
else if (member (c, delims))
break;
else
ADVANCE_CHAR (string, slen, i);
}
CQ_RETURN(i);
}
/* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the
individual words. If DELIMS is NULL, the current value of $IFS is used
to split the string, and the function follows the shell field splitting
@@ -1621,7 +1634,7 @@ split_at_delims (string, slen, delims, sentinel, nwp, cwp)
cw = -1;
while (1)
{
te = skip_to_delim (string, ts, d);
te = skip_to_delim (string, ts, d, SD_NOJMP);
/* If we have a non-whitespace delimiter character, use it to make a
separate field. This is just about what $IFS splitting does and
@@ -1787,6 +1800,42 @@ string_list (list)
return (string_list_internal (list, " "));
}
/* An external interface that can be used by the rest of the shell to
obtain a string containing the first character in $IFS. Handles all
the multibyte complications. If LENP is non-null, it is set to the
length of the returned string. */
char *
ifs_firstchar (lenp)
int *lenp;
{
char *ret;
int len;
ret = xmalloc (MB_LEN_MAX + 1);
#if defined (HANDLE_MULTIBYTE)
if (ifs_firstc_len == 1)
{
ret[0] = ifs_firstc[0];
ret[1] = '\0';
len = ret[0] ? 1 : 0;
}
else
{
memcpy (ret, ifs_firstc, ifs_firstc_len);
ret[len = ifs_firstc_len] = '\0';
}
#else
ret[0] = ifs_firstc;
ret[1] = '\0';
len = ret[0] ? 0 : 1;
#endif
if (lenp)
*lenp = len;
return ret;
}
/* Return a single string of all the words present in LIST, obeying the
quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the
expansion [of $*] appears within a double quoted string, it expands
@@ -1906,6 +1955,45 @@ string_list_dollar_at (list, quoted)
return ret;
}
/* Turn the positional paramters into a string, understanding quoting and
the various subtleties of using the first character of $IFS as the
separator. Calls string_list_dollar_at, string_list_dollar_star, and
string_list as appropriate. */
char *
string_list_pos_params (pchar, list, quoted)
int pchar;
WORD_LIST *list;
int quoted;
{
char *ret;
if (pchar == '*')
{
if (quoted & Q_DOUBLE_QUOTES)
ret = string_list_dollar_star (quote_list (list));
else if (quoted & Q_HERE_DOCUMENT)
ret = string_list (quote_list (list));
else
/* Even when unquoted, string_list_dollar_star does the right thing
making sure that the first character of $IFS is used as the
separator. */
ret = string_list_dollar_star (list);
}
else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
/* We use string_list_dollar_at, but only if the string is quoted, since
that quotes the escapes if it's not, which we don't want. We could
use string_list (the old code did), but that doesn't do the right
thing if the first character of $IFS is not a space. We use
string_list_dollar_star if the string is unquoted so we make sure that
the elements of $@ are separated by the first character of $IFS for
later splitting. */
ret = string_list_dollar_at (list, quoted);
else
ret = string_list_dollar_star (list);
return ret;
}
/* Return the list of words present in STRING. Separate the string into
words at any of the characters found in SEPARATORS. If QUOTED is
non-zero then word in the list will have its quoted flag set, otherwise
@@ -1957,7 +2045,10 @@ list_string (string, separators, quoted)
separators[2] == '\n' &&
separators[3] == '\0';
for (xflags = 0, s = ifs_value; s && *s; s++)
if (*s == CTLESC) xflags |= SX_NOCTLESC;
{
if (*s == CTLESC) xflags |= SX_NOCTLESC;
else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
}
slen = 0;
/* Remove sequences of whitespace at the beginning of STRING, as
@@ -2076,7 +2167,10 @@ get_word_from_string (stringp, separators, endptr)
separators[2] == '\n' &&
separators[3] == '\0';
for (xflags = 0, s = ifs_value; s && *s; s++)
if (*s == CTLESC) xflags |= SX_NOCTLESC;
{
if (*s == CTLESC) xflags |= SX_NOCTLESC;
if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
}
s = *stringp;
slen = 0;
@@ -2264,7 +2358,7 @@ do_assignment_internal (word, expand)
const WORD_DESC *word;
int expand;
{
int offset, tlen, appendop, assign_list, aflags;
int offset, tlen, appendop, assign_list, aflags, retval;
char *name, *value;
SHELL_VAR *entry;
#if defined (ARRAY_VARS)
@@ -2355,11 +2449,27 @@ do_assignment_internal (word, expand)
stupidly_hack_special_variables (name);
#if 1
/* Return 1 if the assignment seems to have been performed correctly. */
if (entry == 0 || readonly_p (entry))
retval = 0; /* assignment failure */
else if (noassign_p (entry))
{
last_command_exit_value = EXECUTION_FAILURE;
retval = 1; /* error status, but not assignment failure */
}
else
retval = 1;
ASSIGN_RETURN (retval);
if (entry && retval != 0)
VUNSETATTR (entry, att_invisible);
#else
if (entry)
VUNSETATTR (entry, att_invisible);
/* Return 1 if the assignment seems to have been performed correctly. */
ASSIGN_RETURN (entry ? ((readonly_p (entry) == 0) && noassign_p (entry) == 0) : 0);
#endif
}
/* Perform the assignment statement in STRING, and expand the
@@ -2509,17 +2619,9 @@ pos_params (string, start, end, quoted)
}
t->next = (WORD_LIST *)NULL;
if (string[0] == '*')
{
if (quoted & Q_DOUBLE_QUOTES)
ret = string_list_dollar_star (quote_list (h));
else if (quoted & Q_HERE_DOCUMENT)
ret = string_list (quote_list (h));
else
ret = string_list (h);
}
else
ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (h) : h);
ret = string_list_pos_params (string[0], h, quoted);
if (t != params)
t->next = params;
@@ -2825,9 +2927,10 @@ expand_string_assignment (string, quoted)
passed string when an error occurs. Might want to trap other calls
to jump_to_top_level here so we don't endlessly loop. */
WORD_LIST *
expand_prompt_string (string, quoted)
expand_prompt_string (string, quoted, wflags)
char *string;
int quoted;
int wflags;
{
WORD_LIST *value;
WORD_DESC td;
@@ -2835,7 +2938,7 @@ expand_prompt_string (string, quoted)
if (string == 0 || *string == 0)
return ((WORD_LIST *)NULL);
td.flags = 0;
td.flags = wflags;
td.word = savestring (string);
no_longjmp_on_fatal_error = 1;
@@ -2953,7 +3056,7 @@ quote_escapes (string)
register char *s, *t;
size_t slen;
char *result, *send;
int quote_spaces, skip_ctlesc;
int quote_spaces, skip_ctlesc, skip_ctlnul;
DECLARE_MBSTATE;
slen = strlen (string);
@@ -2961,15 +3064,15 @@ quote_escapes (string)
quote_spaces = (ifs_value && *ifs_value == 0);
for (skip_ctlesc = 0, s = ifs_value; s && *s; s++)
skip_ctlesc |= *s == CTLESC;
for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL;
t = result = (char *)xmalloc ((slen * 2) + 1);
s = string;
while (*s)
{
if ((skip_ctlesc == 0 && *s == CTLESC) || *s == CTLNUL || (quote_spaces && *s == ' '))
if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' '))
*t++ = CTLESC;
COPY_CHAR_P (t, s, send);
}
@@ -3183,7 +3286,7 @@ dequote_list (list)
/* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed
string. */
static char *
char *
remove_quoted_escapes (string)
char *string;
{
@@ -3992,7 +4095,11 @@ parameter_brace_remove_pattern (varname, value, patstr, rtype, quoted)
if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
patstr++;
pattern = getpattern (patstr, quoted, 1);
/* Need to pass getpattern newly-allocated memory in case of expansion --
the expansion code will free the passed string on an error. */
temp1 = savestring (patstr);
pattern = getpattern (temp1, quoted, 1);
free (temp1);
temp1 = (char *)NULL; /* shut up gcc */
switch (vtype)
@@ -4356,6 +4463,7 @@ process_substitute (string, open_for_read_in_child)
#if defined (JOB_CONTROL)
set_sigchld_handler ();
stop_making_children ();
/* XXX - should we only do this in the parent? (as in command subst) */
pipeline_pgrp = old_pipeline_pgrp;
#endif /* JOB_CONTROL */
@@ -4474,14 +4582,14 @@ read_comsub (fd, quoted, rflag)
int *rflag;
{
char *istring, buf[128], *bufp, *s;
int istring_index, istring_size, c, tflag, skip_ctlesc;
int istring_index, istring_size, c, tflag, skip_ctlesc, skip_ctlnul;
ssize_t bufn;
istring = (char *)NULL;
istring_index = istring_size = bufn = tflag = 0;
for (skip_ctlesc = 0, s = ifs_value; s && *s; s++)
skip_ctlesc |= *s == CTLESC;
for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL;
#ifdef __CYGWIN__
setmode (fd, O_TEXT); /* we don't want CR/LF, we want Unix-style */
@@ -4524,7 +4632,7 @@ read_comsub (fd, quoted, rflag)
tflag |= W_HASCTLESC;
istring[istring_index++] = CTLESC;
}
else if (c == CTLNUL || (c == ' ' && (ifs_value && *ifs_value == 0)))
else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0)))
istring[istring_index++] = CTLESC;
istring[istring_index++] = c;
@@ -4645,9 +4753,11 @@ command_substitute (string, quoted)
reset_signal_handlers ();
#if defined (JOB_CONTROL)
/* XXX DO THIS ONLY IN PARENT ? XXX */
set_sigchld_handler ();
stop_making_children ();
pipeline_pgrp = old_pipeline_pgrp;
if (pid != 0)
pipeline_pgrp = old_pipeline_pgrp;
#else
stop_making_children ();
#endif /* JOB_CONTROL */
@@ -4937,10 +5047,11 @@ parameter_brace_expand_word (name, var_is_special, quoted)
char *temp, *tt;
intmax_t arg_index;
SHELL_VAR *var;
int atype;
int atype, rflags;
ret = 0;
temp = 0;
rflags = 0;
/* Handle multiple digit arguments, as in ${11}. */
if (legal_number (name, &arg_index))
@@ -4973,6 +5084,8 @@ parameter_brace_expand_word (name, var_is_special, quoted)
temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
? quote_string (temp)
: quote_escapes (temp);
else if (atype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
rflags |= W_HASQUOTEDNULL;
}
#endif
else if (var = find_variable (name))
@@ -5000,6 +5113,7 @@ parameter_brace_expand_word (name, var_is_special, quoted)
{
ret = alloc_word_desc ();
ret->word = temp;
ret->flags |= rflags;
}
return ret;
}
@@ -5749,7 +5863,14 @@ pos_params_pat_subst (string, pat, rep, mflags)
if ((mflags & (MATCH_QUOTED|MATCH_STARSUB)) == (MATCH_QUOTED|MATCH_STARSUB))
ret = string_list_dollar_star (quote_list (save));
else
#if 0
ret = string_list ((mflags & MATCH_QUOTED) ? quote_list (save) : save);
#else
if ((mflags & MATCH_QUOTED) == MATCH_QUOTED)
ret = string_list_dollar_star (quote_list (save));
else
ret = string_list (save);
#endif
dispose_words (save);
return (ret);
@@ -5764,7 +5885,7 @@ parameter_brace_patsub (varname, value, patsub, quoted)
char *varname, *value, *patsub;
int quoted;
{
int vtype, mflags, starsub;
int vtype, mflags, starsub, delim;
char *val, *temp, *pat, *rep, *p, *lpatsub, *tt;
SHELL_VAR *v;
@@ -5799,10 +5920,21 @@ parameter_brace_patsub (varname, value, patsub, quoted)
/* If the pattern starts with a `/', make sure we skip over it when looking
for the replacement delimiter. */
#if 0
if (rep = quoted_strchr ((*patsub == '/') ? lpatsub+1 : lpatsub, '/', ST_BACKSL))
*rep++ = '\0';
else
rep = (char *)NULL;
#else
delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0);
if (lpatsub[delim] == '/')
{
lpatsub[delim] = 0;
rep = lpatsub + delim + 1;
}
else
rep = (char *)NULL;
#endif
if (rep && *rep == '\0')
rep = (char *)NULL;
@@ -5960,7 +6092,7 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll
int t_index, sindex, c, tflag;
intmax_t number;
value = (char *)NULL;
temp = temp1 = value = (char *)NULL;
var_is_set = var_is_null = var_is_special = check_nullness = 0;
want_substring = want_indir = want_patsub = 0;
@@ -6585,7 +6717,7 @@ param_expand (string, sindex, quoted, expanded_something,
case LPAREN:
/* We have to extract the contents of this paren substitution. */
t_index = zindex + 1;
temp = extract_command_subst (string, &t_index);
temp = extract_command_subst (string, &t_index, 0);
zindex = t_index;
/* For Posix.2-style `$(( ))' arithmetic substitution,
@@ -6644,7 +6776,8 @@ comsub:
{
tdesc = command_substitute (temp, quoted);
temp1 = tdesc ? tdesc->word : (char *)NULL;
dispose_word_desc (tdesc);
if (tdesc)
dispose_word_desc (tdesc);
}
FREE (temp);
temp = temp1;
@@ -6657,6 +6790,13 @@ comsub:
t_index = zindex + 1;
temp = extract_arithmetic_subst (string, &t_index);
zindex = t_index;
if (temp == 0)
{
temp = savestring (string);
if (expanded_something)
*expanded_something = 0;
goto return0;
}
/* Do initial variable expansion. */
temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES);
@@ -6986,7 +7126,7 @@ add_string:
free (temp);
temp = temp1;
sindex += t_index;
goto add_string;
goto add_quoted_string; /* XXX was add_string */
}
else
{
@@ -7055,7 +7195,8 @@ add_string:
de_backslash (temp);
tword = command_substitute (temp, quoted);
temp1 = tword ? tword->word : (char *)NULL;
dispose_word_desc (tword);
if (tword)
dispose_word_desc (tword);
}
FREE (temp);
temp = temp1;
@@ -7483,6 +7624,11 @@ string_quote_removal (string, quoted)
{
case '\\':
c = string[++sindex];
if (c == 0)
{
*r++ = '\\';
break;
}
if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0)
*r++ = '\\';
/* FALLTHROUGH */
@@ -7683,7 +7829,9 @@ exp_jump_to_top_level (v)
/* Cleanup code goes here. */
expand_no_split_dollar_star = 0; /* XXX */
expanding_redir = 0;
assigning_in_environment = 0;
top_level_cleanup (); /* from sig.c */
jump_to_top_level (v);
}
@@ -7901,7 +8049,7 @@ glob_expand_word_list (tlist, eflags)
else if (fail_glob_expansion != 0)
{
report_error (_("no match: %s"), tlist->word->word);
jump_to_top_level (DISCARD);
exp_jump_to_top_level (DISCARD);
}
else if (allow_null_glob_expansion == 0)
{
@@ -8183,7 +8331,9 @@ expand_word_list_internal (list, eflags)
for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
{
this_command_name = (char *)NULL;
assigning_in_environment = (assign_func == assign_in_env);
tint = (*assign_func) (temp_list->word);
assigning_in_environment = 0;
/* Variable assignment errors in non-interactive shells running
in Posix.2 mode cause the shell to exit. */
if (tint == 0)
+282 -143
View File
@@ -4,7 +4,7 @@
/* ``Have a little faith, there's magic in the night. You ain't a
beauty, but, hey, you're alright.'' */
/* Copyright (C) 1987-2007 Free Software Foundation, Inc.
/* Copyright (C) 1987-2008 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -69,6 +69,7 @@ extern int errno;
#define VT_POSPARMS 1
#define VT_ARRAYVAR 2
#define VT_ARRAYMEMBER 3
#define VT_ASSOCVAR 4
#define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */
@@ -78,13 +79,6 @@ extern int errno;
#define ST_SQUOTE 0x04 /* unused yet */
#define ST_DQUOTE 0x08 /* unused yet */
/* Flags for the string extraction functions. */
#define SX_NOALLOC 0x01 /* just skip; don't return substring */
#define SX_VARNAME 0x02 /* variable name; for string_extract () */
#define SX_REQMATCH 0x04 /* closing/matching delimiter required */
#define SX_COMMAND 0x08 /* extracting a shell script/command */
#define SX_NOCTLESC 0x10 /* don't honor CTLESC quoting */
/* Flags for the `pflags' argument to param_expand() */
#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */
@@ -135,6 +129,8 @@ size_t ifs_firstc_len;
unsigned char ifs_firstc;
#endif
int assigning_in_environment;
/* Extern functions and variables from different files. */
extern int last_command_exit_value, last_command_exit_signal;
extern int subshell_environment;
@@ -206,7 +202,6 @@ static WORD_LIST *list_quote_escapes __P((WORD_LIST *));
static char *dequote_escapes __P((char *));
static char *make_quoted_char __P((int));
static WORD_LIST *quote_list __P((WORD_LIST *));
static char *remove_quoted_escapes __P((char *));
static char *remove_quoted_nulls __P((char *));
static int unquoted_substring __P((char *, char *));
@@ -713,7 +708,7 @@ add_one_character:
si = i + 2;
if (string[i + 1] == LPAREN)
ret = extract_delimited_string (string, &si, "$(", "(", ")", SX_COMMAND); /*)*/
ret = extract_command_subst (string, &si, 0);
else
ret = extract_dollar_brace_string (string, &si, 1, 0);
@@ -815,7 +810,7 @@ skip_double_quoted (string, slen, sind)
{
si = i + 2;
if (string[i + 1] == LPAREN)
ret = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
ret = extract_command_subst (string, &si, SX_NOALLOC);
else
ret = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
@@ -933,11 +928,12 @@ string_extract_verbatim (string, slen, sindex, charlist, flags)
/* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL
through, to protect the CTLNULs from later calls to
remove_quoted_nulls. */
else if (c == CTLESC && string[i+1] == CTLNUL)
else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL)
{
i += 2;
continue;
}
#if defined (HANDLE_MULTIBYTE)
mblength = MBLEN (string + i, slen - i);
if (mblength > 1)
@@ -985,13 +981,21 @@ string_extract_verbatim (string, slen, sindex, charlist, flags)
/* Extract the $( construct in STRING, and return a new string.
Start extracting at (SINDEX) as if we had just seen "$(".
Make (SINDEX) get the position of the matching ")". ) */
Make (SINDEX) get the position of the matching ")". )
XFLAGS is additional flags to pass to other extraction functions, */
char *
extract_command_subst (string, sindex)
extract_command_subst (string, sindex, xflags)
char *string;
int *sindex;
int xflags;
{
return (extract_delimited_string (string, sindex, "$(", "(", ")", SX_COMMAND)); /*)*/
if (string[*sindex] == '(') /*)*/
return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/
else
{
xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0);
return (xparse_dolparen (string, string+*sindex, sindex, xflags));
}
}
/* Extract the $[ construct in STRING, and return a new string. (])
@@ -1098,7 +1102,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
/* Not exactly right yet; should handle shell metacharacters and
multibyte characters, too. */
if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || whitespace (string[i - 1])))
if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1])))
{
in_comment = 1;
ADVANCE_CHAR (string, slen, i);
@@ -1263,7 +1267,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
if (string[i] == '$' && string[i+1] == LPAREN)
{
si = i + 2;
t = extract_delimited_string (string, &si, "$(", "(", ")", flags|SX_NOALLOC|SX_COMMAND); /*)*/
t = extract_command_subst (string, &si, flags|SX_NOALLOC);
i = si + 1;
continue;
}
@@ -1360,6 +1364,91 @@ unquote_bang (string)
}
#endif
#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0)
/* Skip characters in STRING until we find a character in DELIMS, and return
the index of that character. START is the index into string at which we
begin. This is similar in spirit to strpbrk, but it returns an index into
STRING and takes a starting index. This little piece of code knows quite
a lot of shell syntax. It's very similar to skip_double_quoted and other
functions of that ilk. */
int
skip_to_delim (string, start, delims, flags)
char *string;
int start;
char *delims;
int flags;
{
int i, pass_next, backq, si, c;
size_t slen;
char *temp;
DECLARE_MBSTATE;
slen = strlen (string + start) + start;
if (flags & SD_NOJMP)
no_longjmp_on_fatal_error = 1;
i = start;
pass_next = backq = 0;
while (c = string[i])
{
if (pass_next)
{
pass_next = 0;
if (c == 0)
CQ_RETURN(i);
ADVANCE_CHAR (string, slen, i);
continue;
}
else if (c == '\\')
{
pass_next = 1;
i++;
continue;
}
else if (backq)
{
if (c == '`')
backq = 0;
ADVANCE_CHAR (string, slen, i);
continue;
}
else if (c == '`')
{
backq = 1;
i++;
continue;
}
else if (c == '\'' || c == '"')
{
i = (c == '\'') ? skip_single_quoted (string, slen, ++i)
: skip_double_quoted (string, slen, ++i);
/* no increment, the skip functions increment past the closing quote. */
}
else if (c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
{
si = i + 2;
if (string[si] == '\0')
CQ_RETURN(si);
if (string[i+1] == LPAREN)
temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
else
temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
i = si;
if (string[i] == '\0') /* don't increment i past EOS in loop */
break;
i++;
continue;
}
else if (member (c, delims))
break;
else
ADVANCE_CHAR (string, slen, i);
}
CQ_RETURN(i);
}
#if defined (READLINE)
/* Return 1 if the portion of STRING ending at EINDEX is quoted (there is
an unclosed quoted string), or if the character at EINDEX is quoted
@@ -1369,8 +1458,6 @@ unquote_bang (string)
recognizes need to be the same as the contents of
rl_completer_quote_characters. */
#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0)
int
char_is_quoted (string, eindex)
char *string;
@@ -1463,87 +1550,6 @@ unclosed_pair (string, eindex, openstr)
return (openc);
}
/* Skip characters in STRING until we find a character in DELIMS, and return
the index of that character. START is the index into string at which we
begin. This is similar in spirit to strpbrk, but it returns an index into
STRING and takes a starting index. This little piece of code knows quite
a lot of shell syntax. It's very similar to skip_double_quoted and other
functions of that ilk. */
int
skip_to_delim (string, start, delims)
char *string;
int start;
char *delims;
{
int i, pass_next, backq, si, c;
size_t slen;
char *temp;
DECLARE_MBSTATE;
slen = strlen (string + start) + start;
no_longjmp_on_fatal_error = 1;
i = start;
pass_next = backq = 0;
while (c = string[i])
{
if (pass_next)
{
pass_next = 0;
if (c == 0)
CQ_RETURN(i);
ADVANCE_CHAR (string, slen, i);
continue;
}
else if (c == '\\')
{
pass_next = 1;
i++;
continue;
}
else if (backq)
{
if (c == '`')
backq = 0;
ADVANCE_CHAR (string, slen, i);
continue;
}
else if (c == '`')
{
backq = 1;
i++;
continue;
}
else if (c == '\'' || c == '"')
{
i = (c == '\'') ? skip_single_quoted (string, slen, ++i)
: skip_double_quoted (string, slen, ++i);
/* no increment, the skip functions increment past the closing quote. */
}
else if (c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
{
si = i + 2;
if (string[si] == '\0')
CQ_RETURN(si);
if (string[i+1] == LPAREN)
temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
else
temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
i = si;
if (string[i] == '\0') /* don't increment i past EOS in loop */
break;
i++;
continue;
}
else if (member (c, delims))
break;
else
ADVANCE_CHAR (string, slen, i);
}
CQ_RETURN(i);
}
/* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the
individual words. If DELIMS is NULL, the current value of $IFS is used
to split the string, and the function follows the shell field splitting
@@ -1628,7 +1634,7 @@ split_at_delims (string, slen, delims, sentinel, nwp, cwp)
cw = -1;
while (1)
{
te = skip_to_delim (string, ts, d);
te = skip_to_delim (string, ts, d, SD_NOJMP);
/* If we have a non-whitespace delimiter character, use it to make a
separate field. This is just about what $IFS splitting does and
@@ -1794,6 +1800,42 @@ string_list (list)
return (string_list_internal (list, " "));
}
/* An external interface that can be used by the rest of the shell to
obtain a string containing the first character in $IFS. Handles all
the multibyte complications. If LENP is non-null, it is set to the
length of the returned string. */
char *
ifs_firstchar (lenp)
int *lenp;
{
char *ret;
int len;
ret = xmalloc (MB_LEN_MAX + 1);
#if defined (HANDLE_MULTIBYTE)
if (ifs_firstc_len == 1)
{
ret[0] = ifs_firstc[0];
ret[1] = '\0';
len = ret[0] ? 1 : 0;
}
else
{
memcpy (ret, ifs_firstc, ifs_firstc_len);
ret[len = ifs_firstc_len] = '\0';
}
#else
ret[0] = ifs_firstc;
ret[1] = '\0';
len = ret[0] ? 0 : 1;
#endif
if (lenp)
*lenp = len;
return ret;
}
/* Return a single string of all the words present in LIST, obeying the
quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the
expansion [of $*] appears within a double quoted string, it expands
@@ -1913,6 +1955,47 @@ string_list_dollar_at (list, quoted)
return ret;
}
/* Turn the positional paramters into a string, understanding quoting and
the various subtleties of using the first character of $IFS as the
separator. Calls string_list_dollar_at, string_list_dollar_star, and
string_list as appropriate. */
char *
string_list_pos_params (pchar, list, quoted)
int pchar;
WORD_LIST *list;
int quoted;
{
char *ret;
if (pchar == '*')
{
if (quoted & Q_DOUBLE_QUOTES)
ret = string_list_dollar_star (quote_list (list));
else if (quoted & Q_HERE_DOCUMENT)
ret = string_list (quote_list (list));
else
/* Even when unquoted, string_list_dollar_star does the right thing
making sure that the first character of $IFS is used as the
separator. */
ret = string_list_dollar_star (list);
}
else if (pchar == '@' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
/* We use string_list_dollar_at, but only if the string is quoted, since
that quotes the escapes if it's not, which we don't want. We could
use string_list (the old code did), but that doesn't do the right
thing if the first character of $IFS is not a space. We use
string_list_dollar_star if the string is unquoted so we make sure that
the elements of $@ are separated by the first character of $IFS for
later splitting. */
ret = string_list_dollar_at (list, quoted);
else if (pchar == '@')
ret = string_list_dollar_star (list);
else
ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list);
return ret;
}
/* Return the list of words present in STRING. Separate the string into
words at any of the characters found in SEPARATORS. If QUOTED is
non-zero then word in the list will have its quoted flag set, otherwise
@@ -1964,7 +2047,10 @@ list_string (string, separators, quoted)
separators[2] == '\n' &&
separators[3] == '\0';
for (xflags = 0, s = ifs_value; s && *s; s++)
if (*s == CTLESC) xflags |= SX_NOCTLESC;
{
if (*s == CTLESC) xflags |= SX_NOCTLESC;
else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
}
slen = 0;
/* Remove sequences of whitespace at the beginning of STRING, as
@@ -2083,7 +2169,10 @@ get_word_from_string (stringp, separators, endptr)
separators[2] == '\n' &&
separators[3] == '\0';
for (xflags = 0, s = ifs_value; s && *s; s++)
if (*s == CTLESC) xflags |= SX_NOCTLESC;
{
if (*s == CTLESC) xflags |= SX_NOCTLESC;
if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
}
s = *stringp;
slen = 0;
@@ -2271,7 +2360,7 @@ do_assignment_internal (word, expand)
const WORD_DESC *word;
int expand;
{
int offset, tlen, appendop, assign_list, aflags;
int offset, tlen, appendop, assign_list, aflags, retval;
char *name, *value;
SHELL_VAR *entry;
#if defined (ARRAY_VARS)
@@ -2362,11 +2451,27 @@ do_assignment_internal (word, expand)
stupidly_hack_special_variables (name);
#if 1
/* Return 1 if the assignment seems to have been performed correctly. */
if (entry == 0 || readonly_p (entry))
retval = 0; /* assignment failure */
else if (noassign_p (entry))
{
last_command_exit_value = EXECUTION_FAILURE;
retval = 1; /* error status, but not assignment failure */
}
else
retval = 1;
ASSIGN_RETURN (retval);
if (entry && retval != 0)
VUNSETATTR (entry, att_invisible);
#else
if (entry)
VUNSETATTR (entry, att_invisible);
/* Return 1 if the assignment seems to have been performed correctly. */
ASSIGN_RETURN (entry ? ((readonly_p (entry) == 0) && noassign_p (entry) == 0) : 0);
#endif
}
/* Perform the assignment statement in STRING, and expand the
@@ -2516,17 +2621,9 @@ pos_params (string, start, end, quoted)
}
t->next = (WORD_LIST *)NULL;
if (string[0] == '*')
{
if (quoted & Q_DOUBLE_QUOTES)
ret = string_list_dollar_star (quote_list (h));
else if (quoted & Q_HERE_DOCUMENT)
ret = string_list (quote_list (h));
else
ret = string_list (h);
}
else
ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (h) : h);
ret = string_list_pos_params (string[0], h, quoted);
if (t != params)
t->next = params;
@@ -2832,9 +2929,10 @@ expand_string_assignment (string, quoted)
passed string when an error occurs. Might want to trap other calls
to jump_to_top_level here so we don't endlessly loop. */
WORD_LIST *
expand_prompt_string (string, quoted)
expand_prompt_string (string, quoted, wflags)
char *string;
int quoted;
int wflags;
{
WORD_LIST *value;
WORD_DESC td;
@@ -2842,7 +2940,7 @@ expand_prompt_string (string, quoted)
if (string == 0 || *string == 0)
return ((WORD_LIST *)NULL);
td.flags = 0;
td.flags = wflags;
td.word = savestring (string);
no_longjmp_on_fatal_error = 1;
@@ -2960,7 +3058,7 @@ quote_escapes (string)
register char *s, *t;
size_t slen;
char *result, *send;
int quote_spaces, skip_ctlesc;
int quote_spaces, skip_ctlesc, skip_ctlnul;
DECLARE_MBSTATE;
slen = strlen (string);
@@ -2968,15 +3066,15 @@ quote_escapes (string)
quote_spaces = (ifs_value && *ifs_value == 0);
for (skip_ctlesc = 0, s = ifs_value; s && *s; s++)
skip_ctlesc |= *s == CTLESC;
for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL;
t = result = (char *)xmalloc ((slen * 2) + 1);
s = string;
while (*s)
{
if ((skip_ctlesc == 0 && *s == CTLESC) || *s == CTLNUL || (quote_spaces && *s == ' '))
if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' '))
*t++ = CTLESC;
COPY_CHAR_P (t, s, send);
}
@@ -3190,7 +3288,7 @@ dequote_list (list)
/* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed
string. */
static char *
char *
remove_quoted_escapes (string)
char *string;
{
@@ -3920,12 +4018,9 @@ list_remove_pattern (list, pattern, patspec, itype, quoted)
}
l = REVERSE_LIST (new, WORD_LIST *);
if (itype == '*')
tword = (quoted & Q_DOUBLE_QUOTES) ? string_list_dollar_star (l) : string_list (l);
else
tword = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (l) : l);
tword = string_list_pos_params (itype, l, quoted);
dispose_words (l);
return (tword);
}
@@ -3999,7 +4094,11 @@ parameter_brace_remove_pattern (varname, value, patstr, rtype, quoted)
if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
patstr++;
pattern = getpattern (patstr, quoted, 1);
/* Need to pass getpattern newly-allocated memory in case of expansion --
the expansion code will free the passed string on an error. */
temp1 = savestring (patstr);
pattern = getpattern (temp1, quoted, 1);
free (temp1);
temp1 = (char *)NULL; /* shut up gcc */
switch (vtype)
@@ -4363,6 +4462,7 @@ process_substitute (string, open_for_read_in_child)
#if defined (JOB_CONTROL)
set_sigchld_handler ();
stop_making_children ();
/* XXX - should we only do this in the parent? (as in command subst) */
pipeline_pgrp = old_pipeline_pgrp;
#endif /* JOB_CONTROL */
@@ -4481,14 +4581,14 @@ read_comsub (fd, quoted, rflag)
int *rflag;
{
char *istring, buf[128], *bufp, *s;
int istring_index, istring_size, c, tflag, skip_ctlesc;
int istring_index, istring_size, c, tflag, skip_ctlesc, skip_ctlnul;
ssize_t bufn;
istring = (char *)NULL;
istring_index = istring_size = bufn = tflag = 0;
for (skip_ctlesc = 0, s = ifs_value; s && *s; s++)
skip_ctlesc |= *s == CTLESC;
for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL;
#ifdef __CYGWIN__
setmode (fd, O_TEXT); /* we don't want CR/LF, we want Unix-style */
@@ -4531,7 +4631,7 @@ read_comsub (fd, quoted, rflag)
tflag |= W_HASCTLESC;
istring[istring_index++] = CTLESC;
}
else if (c == CTLNUL || (c == ' ' && (ifs_value && *ifs_value == 0)))
else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0)))
istring[istring_index++] = CTLESC;
istring[istring_index++] = c;
@@ -4652,9 +4752,11 @@ command_substitute (string, quoted)
reset_signal_handlers ();
#if defined (JOB_CONTROL)
/* XXX DO THIS ONLY IN PARENT ? XXX */
set_sigchld_handler ();
stop_making_children ();
pipeline_pgrp = old_pipeline_pgrp;
if (pid != 0)
pipeline_pgrp = old_pipeline_pgrp;
#else
stop_making_children ();
#endif /* JOB_CONTROL */
@@ -4944,10 +5046,11 @@ parameter_brace_expand_word (name, var_is_special, quoted)
char *temp, *tt;
intmax_t arg_index;
SHELL_VAR *var;
int atype;
int atype, rflags;
ret = 0;
temp = 0;
rflags = 0;
/* Handle multiple digit arguments, as in ${11}. */
if (legal_number (name, &arg_index))
@@ -4980,6 +5083,8 @@ parameter_brace_expand_word (name, var_is_special, quoted)
temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
? quote_string (temp)
: quote_escapes (temp);
else if (atype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
rflags |= W_HASQUOTEDNULL;
}
#endif
else if (var = find_variable (name))
@@ -5007,6 +5112,7 @@ parameter_brace_expand_word (name, var_is_special, quoted)
{
ret = alloc_word_desc ();
ret->word = temp;
ret->flags |= rflags;
}
return ret;
}
@@ -5739,6 +5845,7 @@ pos_params_pat_subst (string, pat, rep, mflags)
WORD_LIST *save, *params;
WORD_DESC *w;
char *ret;
int pchar;
save = params = list_rest_of_args ();
if (save == 0)
@@ -5755,8 +5862,11 @@ pos_params_pat_subst (string, pat, rep, mflags)
if ((mflags & (MATCH_QUOTED|MATCH_STARSUB)) == (MATCH_QUOTED|MATCH_STARSUB))
ret = string_list_dollar_star (quote_list (save));
else if ((mflags & MATCH_QUOTED) == MATCH_QUOTED)
ret = string_list_dollar_star (quote_list (save));
else
ret = string_list ((mflags & MATCH_QUOTED) ? quote_list (save) : save);
ret = string_list_dollar_star (save);
dispose_words (save);
return (ret);
@@ -5771,7 +5881,7 @@ parameter_brace_patsub (varname, value, patsub, quoted)
char *varname, *value, *patsub;
int quoted;
{
int vtype, mflags, starsub;
int vtype, mflags, starsub, delim;
char *val, *temp, *pat, *rep, *p, *lpatsub, *tt;
SHELL_VAR *v;
@@ -5806,10 +5916,21 @@ parameter_brace_patsub (varname, value, patsub, quoted)
/* If the pattern starts with a `/', make sure we skip over it when looking
for the replacement delimiter. */
#if 0
if (rep = quoted_strchr ((*patsub == '/') ? lpatsub+1 : lpatsub, '/', ST_BACKSL))
*rep++ = '\0';
else
rep = (char *)NULL;
#else
delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0);
if (lpatsub[delim] == '/')
{
lpatsub[delim] = 0;
rep = lpatsub + delim + 1;
}
else
rep = (char *)NULL;
#endif
if (rep && *rep == '\0')
rep = (char *)NULL;
@@ -5967,7 +6088,7 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll
int t_index, sindex, c, tflag;
intmax_t number;
value = (char *)NULL;
temp = temp1 = value = (char *)NULL;
var_is_set = var_is_null = var_is_special = check_nullness = 0;
want_substring = want_indir = want_patsub = 0;
@@ -6592,7 +6713,7 @@ param_expand (string, sindex, quoted, expanded_something,
case LPAREN:
/* We have to extract the contents of this paren substitution. */
t_index = zindex + 1;
temp = extract_command_subst (string, &t_index);
temp = extract_command_subst (string, &t_index, 0);
zindex = t_index;
/* For Posix.2-style `$(( ))' arithmetic substitution,
@@ -6651,7 +6772,8 @@ comsub:
{
tdesc = command_substitute (temp, quoted);
temp1 = tdesc ? tdesc->word : (char *)NULL;
dispose_word_desc (tdesc);
if (tdesc)
dispose_word_desc (tdesc);
}
FREE (temp);
temp = temp1;
@@ -6664,6 +6786,13 @@ comsub:
t_index = zindex + 1;
temp = extract_arithmetic_subst (string, &t_index);
zindex = t_index;
if (temp == 0)
{
temp = savestring (string);
if (expanded_something)
*expanded_something = 0;
goto return0;
}
/* Do initial variable expansion. */
temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES);
@@ -6993,7 +7122,7 @@ add_string:
free (temp);
temp = temp1;
sindex += t_index;
goto add_string;
goto add_quoted_string; /* XXX was add_string */
}
else
{
@@ -7062,7 +7191,8 @@ add_string:
de_backslash (temp);
tword = command_substitute (temp, quoted);
temp1 = tword ? tword->word : (char *)NULL;
dispose_word_desc (tword);
if (tword)
dispose_word_desc (tword);
}
FREE (temp);
temp = temp1;
@@ -7490,6 +7620,11 @@ string_quote_removal (string, quoted)
{
case '\\':
c = string[++sindex];
if (c == 0)
{
*r++ = '\\';
break;
}
if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0)
*r++ = '\\';
/* FALLTHROUGH */
@@ -7690,7 +7825,9 @@ exp_jump_to_top_level (v)
/* Cleanup code goes here. */
expand_no_split_dollar_star = 0; /* XXX */
expanding_redir = 0;
assigning_in_environment = 0;
top_level_cleanup (); /* from sig.c */
jump_to_top_level (v);
}
@@ -7908,7 +8045,7 @@ glob_expand_word_list (tlist, eflags)
else if (fail_glob_expansion != 0)
{
report_error (_("no match: %s"), tlist->word->word);
jump_to_top_level (DISCARD);
exp_jump_to_top_level (DISCARD);
}
else if (allow_null_glob_expansion == 0)
{
@@ -8190,7 +8327,9 @@ expand_word_list_internal (list, eflags)
for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
{
this_command_name = (char *)NULL;
assigning_in_environment = (assign_func == assign_in_env);
tint = (*assign_func) (temp_list->word);
assigning_in_environment = 0;
/* Variable assignment errors in non-interactive shells running
in Posix.2 mode cause the shell to exit. */
if (tint == 0)
+117 -40
View File
@@ -4,7 +4,7 @@
/* ``Have a little faith, there's magic in the night. You ain't a
beauty, but, hey, you're alright.'' */
/* Copyright (C) 1987-2007 Free Software Foundation, Inc.
/* Copyright (C) 1987-2008 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -69,6 +69,7 @@ extern int errno;
#define VT_POSPARMS 1
#define VT_ARRAYVAR 2
#define VT_ARRAYMEMBER 3
#define VT_ASSOCVAR 4
#define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */
@@ -78,14 +79,6 @@ extern int errno;
#define ST_SQUOTE 0x04 /* unused yet */
#define ST_DQUOTE 0x08 /* unused yet */
/* Flags for the string extraction functions. */
#define SX_NOALLOC 0x01 /* just skip; don't return substring */
#define SX_VARNAME 0x02 /* variable name; for string_extract () */
#define SX_REQMATCH 0x04 /* closing/matching delimiter required */
#define SX_COMMAND 0x08 /* extracting a shell script/command */
#define SX_NOCTLESC 0x10 /* don't honor CTLESC quoting */
#define SX_NOESCCTLNUL 0x20 /* don't let CTLESC quote CTLNUL */
/* Flags for the `pflags' argument to param_expand() */
#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */
@@ -715,7 +708,7 @@ add_one_character:
si = i + 2;
if (string[i + 1] == LPAREN)
ret = extract_delimited_string (string, &si, "$(", "(", ")", SX_COMMAND); /*)*/
ret = extract_command_subst (string, &si, 0);
else
ret = extract_dollar_brace_string (string, &si, 1, 0);
@@ -817,7 +810,7 @@ skip_double_quoted (string, slen, sind)
{
si = i + 2;
if (string[i + 1] == LPAREN)
ret = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
ret = extract_command_subst (string, &si, SX_NOALLOC);
else
ret = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
@@ -940,6 +933,7 @@ string_extract_verbatim (string, slen, sindex, charlist, flags)
i += 2;
continue;
}
#if defined (HANDLE_MULTIBYTE)
mblength = MBLEN (string + i, slen - i);
if (mblength > 1)
@@ -987,13 +981,21 @@ string_extract_verbatim (string, slen, sindex, charlist, flags)
/* Extract the $( construct in STRING, and return a new string.
Start extracting at (SINDEX) as if we had just seen "$(".
Make (SINDEX) get the position of the matching ")". ) */
Make (SINDEX) get the position of the matching ")". )
XFLAGS is additional flags to pass to other extraction functions, */
char *
extract_command_subst (string, sindex)
extract_command_subst (string, sindex, xflags)
char *string;
int *sindex;
int xflags;
{
return (extract_delimited_string (string, sindex, "$(", "(", ")", SX_COMMAND)); /*)*/
if (string[*sindex] == '(') /*)*/
return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/
else
{
xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0);
return (xparse_dolparen (string, string+*sindex, sindex, xflags));
}
}
/* Extract the $[ construct in STRING, and return a new string. (])
@@ -1100,7 +1102,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
/* Not exactly right yet; should handle shell metacharacters and
multibyte characters, too. */
if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || whitespace (string[i - 1])))
if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1])))
{
in_comment = 1;
ADVANCE_CHAR (string, slen, i);
@@ -1265,7 +1267,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
if (string[i] == '$' && string[i+1] == LPAREN)
{
si = i + 2;
t = extract_delimited_string (string, &si, "$(", "(", ")", flags|SX_NOALLOC|SX_COMMAND); /*)*/
t = extract_command_subst (string, &si, flags|SX_NOALLOC);
i = si + 1;
continue;
}
@@ -1953,6 +1955,55 @@ string_list_dollar_at (list, quoted)
return ret;
}
/* Turn the positional paramters into a string, understanding quoting and
the various subtleties of using the first character of $IFS as the
separator. Calls string_list_dollar_at, string_list_dollar_star, and
string_list as appropriate. */
char *
string_list_pos_params (pchar, list, quoted)
int pchar;
WORD_LIST *list;
int quoted;
{
char *ret;
WORD_LIST *tlist;
if (pchar == '*' && (quoted & Q_DOUBLE_QUOTES))
{
tlist = quote_list (list);
word_list_remove_quoted_nulls (tlist);
ret = string_list_dollar_star (tlist);
}
else if (pchar == '*' && (quoted & Q_HERE_DOCUMENT))
{
tlist = quote_list (list);
word_list_remove_quoted_nulls (tlist);
ret = string_list (tlist);
}
else if (pchar == '*')
{
/* Even when unquoted, string_list_dollar_star does the right thing
making sure that the first character of $IFS is used as the
separator. */
ret = string_list_dollar_star (list);
}
else if (pchar == '@' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
/* We use string_list_dollar_at, but only if the string is quoted, since
that quotes the escapes if it's not, which we don't want. We could
use string_list (the old code did), but that doesn't do the right
thing if the first character of $IFS is not a space. We use
string_list_dollar_star if the string is unquoted so we make sure that
the elements of $@ are separated by the first character of $IFS for
later splitting. */
ret = string_list_dollar_at (list, quoted);
else if (pchar == '@')
ret = string_list_dollar_star (list);
else
ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list);
return ret;
}
/* Return the list of words present in STRING. Separate the string into
words at any of the characters found in SEPARATORS. If QUOTED is
non-zero then word in the list will have its quoted flag set, otherwise
@@ -2578,17 +2629,9 @@ pos_params (string, start, end, quoted)
}
t->next = (WORD_LIST *)NULL;
if (string[0] == '*')
{
if (quoted & Q_DOUBLE_QUOTES)
ret = string_list_dollar_star (quote_list (h));
else if (quoted & Q_HERE_DOCUMENT)
ret = string_list (quote_list (h));
else
ret = string_list (h);
}
else
ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (h) : h);
ret = string_list_pos_params (string[0], h, quoted);
if (t != params)
t->next = params;
@@ -2894,9 +2937,10 @@ expand_string_assignment (string, quoted)
passed string when an error occurs. Might want to trap other calls
to jump_to_top_level here so we don't endlessly loop. */
WORD_LIST *
expand_prompt_string (string, quoted)
expand_prompt_string (string, quoted, wflags)
char *string;
int quoted;
int wflags;
{
WORD_LIST *value;
WORD_DESC td;
@@ -2904,7 +2948,7 @@ expand_prompt_string (string, quoted)
if (string == 0 || *string == 0)
return ((WORD_LIST *)NULL);
td.flags = 0;
td.flags = wflags;
td.word = savestring (string);
no_longjmp_on_fatal_error = 1;
@@ -3225,9 +3269,10 @@ quote_list (list)
{
t = w->word->word;
w->word->word = quote_string (t);
free (t);
if (*t == 0)
w->word->flags |= W_HASQUOTEDNULL; /* XXX - turn on W_HASQUOTEDNULL here? */
w->word->flags |= W_QUOTED;
/* XXX - turn on W_HAVEQUOTEDNULL here? */
free (t);
}
return list;
}
@@ -3243,9 +3288,10 @@ dequote_list (list)
for (tlist = list; tlist; tlist = tlist->next)
{
s = dequote_string (tlist->word->word);
if (QUOTED_NULL (tlist->word->word))
tlist->word->flags &= ~W_HASQUOTEDNULL;
free (tlist->word->word);
tlist->word->word = s;
/* XXX - turn off W_HAVEQUOTEDNULL here? */
}
return list;
}
@@ -3982,12 +4028,22 @@ list_remove_pattern (list, pattern, patspec, itype, quoted)
}
l = REVERSE_LIST (new, WORD_LIST *);
if (itype == '*')
tword = (quoted & Q_DOUBLE_QUOTES) ? string_list_dollar_star (l) : string_list (l);
#if 0
if (itype == '*' && (quoted & Q_DOUBLE_QUOTES))
tword = string_list_dollar_star (quote_list (l));
else if (itype == '*')
tword = string_list_dollar_star (l);
else if (itype == '@' && (quoted & Q_DOUBLE_QUOTES))
tword = string_list_dollar_at (l, quoted);
else if (itype == '@')
tword = string_list_dollar_star (l);
else
tword = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (l) : l);
tword = string_list (l);
#else
tword = string_list_pos_params (itype, l, quoted);
#endif
dispose_words (l);
return (tword);
}
@@ -5812,6 +5868,7 @@ pos_params_pat_subst (string, pat, rep, mflags)
WORD_LIST *save, *params;
WORD_DESC *w;
char *ret;
int pchar, qflags;
save = params = list_rest_of_args ();
if (save == 0)
@@ -5826,10 +5883,22 @@ pos_params_pat_subst (string, pat, rep, mflags)
params->word = w;
}
pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
#if 0
if ((mflags & (MATCH_QUOTED|MATCH_STARSUB)) == (MATCH_QUOTED|MATCH_STARSUB))
ret = string_list_dollar_star (quote_list (save));
else if ((mflags & MATCH_STARSUB) == MATCH_STARSUB)
ret = string_list_dollar_star (save);
else if ((mflags & MATCH_QUOTED) == MATCH_QUOTED)
ret = string_list_dollar_at (save, qflags);
else
ret = string_list ((mflags & MATCH_QUOTED) ? quote_list (save) : save);
ret = string_list_dollar_star (save);
#else
ret = string_list_pos_params (pchar, save, qflags);
#endif
dispose_words (save);
return (ret);
@@ -6136,6 +6205,7 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll
temp = (char *)NULL;
goto bad_substitution;
}
/* Indirect expansion begins with a `!'. A valid indirect expansion is
either a variable name, one of the positional parameters or a special
variable that expands to one of the positional parameters. */
@@ -6675,7 +6745,7 @@ param_expand (string, sindex, quoted, expanded_something,
case LPAREN:
/* We have to extract the contents of this paren substitution. */
t_index = zindex + 1;
temp = extract_command_subst (string, &t_index);
temp = extract_command_subst (string, &t_index, 0);
zindex = t_index;
/* For Posix.2-style `$(( ))' arithmetic substitution,
@@ -6734,7 +6804,8 @@ comsub:
{
tdesc = command_substitute (temp, quoted);
temp1 = tdesc ? tdesc->word : (char *)NULL;
dispose_word_desc (tdesc);
if (tdesc)
dispose_word_desc (tdesc);
}
FREE (temp);
temp = temp1;
@@ -7152,7 +7223,8 @@ add_string:
de_backslash (temp);
tword = command_substitute (temp, quoted);
temp1 = tword ? tword->word : (char *)NULL;
dispose_word_desc (tword);
if (tword)
dispose_word_desc (tword);
}
FREE (temp);
temp = temp1;
@@ -7580,6 +7652,11 @@ string_quote_removal (string, quoted)
{
case '\\':
c = string[++sindex];
if (c == 0)
{
*r++ = '\\';
break;
}
if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0)
*r++ = '\\';
/* FALLTHROUGH */
+18 -2
View File
@@ -43,6 +43,15 @@
#define ASS_APPEND 0x01
#define ASS_MKLOCAL 0x02
/* Flags for the string extraction functions. */
#define SX_NOALLOC 0x01 /* just skip; don't return substring */
#define SX_VARNAME 0x02 /* variable name; for string_extract () */
#define SX_REQMATCH 0x04 /* closing/matching delimiter required */
#define SX_COMMAND 0x08 /* extracting a shell script/command */
#define SX_NOCTLESC 0x10 /* don't honor CTLESC quoting */
#define SX_NOESCCTLNUL 0x20 /* don't let CTLESC quote CTLNUL */
#define SX_NOLONGJMP 0x40 /* don't longjmp on fatal error */
/* Remove backslashes which are quoting backquotes from STRING. Modifies
STRING, and returns a pointer to it. */
extern char * de_backslash __P((char *));
@@ -52,8 +61,9 @@ extern void unquote_bang __P((char *));
/* Extract the $( construct in STRING, and return a new string.
Start extracting at (SINDEX) as if we had just seen "$(".
Make (SINDEX) get the position just after the matching ")". */
extern char *extract_command_subst __P((char *, int *));
Make (SINDEX) get the position just after the matching ")".
XFLAGS is additional flags to pass to other extraction functions, */
extern char *extract_command_subst __P((char *, int *, int));
/* Extract the $[ construct in STRING, and return a new string.
Start extracting at (SINDEX) as if we had just seen "$[".
@@ -84,6 +94,12 @@ extern char *string_list_dollar_star __P((WORD_LIST *));
/* Expand $@ into a single string, obeying POSIX rules. */
extern char *string_list_dollar_at __P((WORD_LIST *, int));
/* Turn the positional paramters into a string, understanding quoting and
the various subtleties of using the first character of $IFS as the
separator. Calls string_list_dollar_at, string_list_dollar_star, and
string_list as appropriate. */
extern char *string_list_pos_params __P((int, WORD_LIST *, int));
/* Perform quoted null character removal on each element of LIST.
This modifies LIST. */
extern void word_list_remove_quoted_nulls __P((WORD_LIST *));
+13 -3
View File
@@ -43,6 +43,15 @@
#define ASS_APPEND 0x01
#define ASS_MKLOCAL 0x02
/* Flags for the string extraction functions. */
#define SX_NOALLOC 0x01 /* just skip; don't return substring */
#define SX_VARNAME 0x02 /* variable name; for string_extract () */
#define SX_REQMATCH 0x04 /* closing/matching delimiter required */
#define SX_COMMAND 0x08 /* extracting a shell script/command */
#define SX_NOCTLESC 0x10 /* don't honor CTLESC quoting */
#define SX_NOESCCTLNUL 0x20 /* don't let CTLESC quote CTLNUL */
#define SX_NOLONGJMP 0x40 /* don't longjmp on fatal error */
/* Remove backslashes which are quoting backquotes from STRING. Modifies
STRING, and returns a pointer to it. */
extern char * de_backslash __P((char *));
@@ -52,8 +61,9 @@ extern void unquote_bang __P((char *));
/* Extract the $( construct in STRING, and return a new string.
Start extracting at (SINDEX) as if we had just seen "$(".
Make (SINDEX) get the position just after the matching ")". */
extern char *extract_command_subst __P((char *, int *));
Make (SINDEX) get the position just after the matching ")".
XFLAGS is additional flags to pass to other extraction functions, */
extern char *extract_command_subst __P((char *, int *, int));
/* Extract the $[ construct in STRING, and return a new string.
Start extracting at (SINDEX) as if we had just seen "$[".
@@ -136,7 +146,7 @@ extern WORD_LIST *expand_string_unsplit __P((char *, int));
extern WORD_LIST *expand_string_assignment __P((char *, int));
/* Expand a prompt string. */
extern WORD_LIST *expand_prompt_string __P((char *, int));
extern WORD_LIST *expand_prompt_string __P((char *, int, int));
/* Expand STRING just as if you were expanding a word. This also returns
a list of words. Note that filename globbing is *NOT* done for word
+57
View File
@@ -0,0 +1,57 @@
abmnopyz
abmnopyz
ab
abcd
sh_352.26ax
sh_352.26ay
sh_352.25a sh_352.25b
sh_352.27 ) ) )
abc
here doc with )
)
bad' syntax
a
sh_352.26a
sh_352.26a
sh_352.26
sh_352.26
sh_352.26
1
sh_352.28 )
sh_352.28 )
k
abcd
ab
ab
abcde
argv[1] = <abcde^J >
abcdefoo
argv[1] = <abcde>
argv[2] = <foo>
argv[1] = <wxabcdeyz>
argv[1] = <abcde>
'
after 1
'
after 2
'
after 3
`
after 4
hello
after 5
'
after 6
x
x
quoted )
comment
here-doc with )
here-doc terminated with a parenthesis
' # or a single back- or doublequote
./comsub-posix1.sub: command substitution: line 2: syntax error near unexpected token `)'
./comsub-posix1.sub: command substitution: line 2: ` if x; then echo foo )'
after
+199
View File
@@ -0,0 +1,199 @@
# works right
echo ab$(echo mnop)yz
# works right
echo ab$(echo mnop
)yz
#
# works right
echo $(echo ab
)
# works right
echo $(
)
echo $()
echo ab$()cd
echo $(case a in (a) echo sh_352.26ax; esac )
echo $(case a in (a) echo sh_352.26ay; esac)
echo $((echo sh_352.25a);(echo sh_352.25b))
echo $(echo sh_352.27 ')' ")" \)
# ) comment
)
echo $(
echo abc # a comment with )
)
echo $(
cat <<eof
here doc with )
eof
)
echo $(
echo ')'
)
unset x
x=$(cat <<"EOF"
bad' syntax
EOF
)
echo "$x"
unset x
echo $(for f in \); do echo a; done )
echo $(case a in a) echo sh_352.26a; esac )
echo $(case a in a) echo sh_352.26a; esac)
echo $(case a in
(a) echo sh_352.26
;;
esac
)
echo $(case a in
a) echo sh_352.26
;;
esac
)
echo $(case a in
a) echo sh_352.26
;;
esac
)
echo $(( 4<(2+3) ? 1 : 32))
echo $(cat << end
sh_352.28 )
end
)
echo $(cat <<- end
sh_352.28 )
end
)
k=$(case x in x) echo k;; esac)
echo $k
x=$(
case $(ls) in
example) echo foobix;;
esac
)
echo $( echo ab\
cd)
echo `echo ab
cd`
echo `echo ab #xyz
cd`
echo "$(echo abcde)
"
recho "$(echo abcde)
"
echo $(echo abcde)\
foo
recho $(echo abcde)\
foo
recho "wx$(echo abcde)yz"
recho "$(echo abcde)"
echo $(cat <<eof
'
eof
)
echo after 1
echo $(cat <<\eof
'
eof
)
echo after 2
echo "$(cat <<\eof
'
eof
)"
echo after 3
echo "$(cat <<\eof
`
eof
)"
echo after 4
echo $(
cat << ')'
hello
)
)
echo after 5
echo $(cat <<'eof'
'
eof
)
echo after 6
echo $(
case x in x) echo x;; esac
)
echo $(
case x in (x) echo x;; esac
)
echo $(
echo 'quoted )'
)
echo $(
echo comment # with )
)
echo $(
cat <<\eof
here-doc with )
eof
)
echo $(
cat <<\)
here-doc terminated with a parenthesis
)
)
echo $(
cat <<\eof
' # or a single back- or doublequote
eof
)
${THIS_SH} ./comsub-posix1.sub
+197
View File
@@ -0,0 +1,197 @@
# works right
echo ab$(echo mnop)yz
# works right
echo ab$(echo mnop
)yz
#
# works right
echo $(echo ab
)
# works right
echo $(
)
echo $()
echo ab$()cd
echo $(case a in (a) echo sh_352.26ax; esac )
echo $(case a in (a) echo sh_352.26ay; esac)
echo $((echo sh_352.25a);(echo sh_352.25b))
echo $(echo sh_352.27 ')' ")" \)
# ) comment
)
echo $(
echo abc # a comment with )
)
echo $(
cat <<eof
here doc with )
eof
)
echo $(
echo ')'
)
unset x
x=$(cat <<"EOF"
bad' syntax
EOF
)
echo "$x"
unset x
echo $(for f in \); do echo a; done )
echo $(case a in a) echo sh_352.26a; esac )
echo $(case a in a) echo sh_352.26a; esac)
echo $(case a in
(a) echo sh_352.26
;;
esac
)
echo $(case a in
a) echo sh_352.26
;;
esac
)
echo $(case a in
a) echo sh_352.26
;;
esac
)
echo $(( 4<(2+3) ? 1 : 32))
echo $(cat << end
sh_352.28 )
end
)
echo $(cat <<- end
sh_352.28 )
end
)
k=$(case x in x) echo k;; esac)
echo $k
x=$(
case $(ls) in
example) echo foobix;;
esac
)
echo $( echo ab\
cd)
echo `echo ab
cd`
echo `echo ab #xyz
cd`
echo "$(echo abcde)
"
recho "$(echo abcde)
"
echo $(echo abcde)\
foo
recho $(echo abcde)\
foo
recho "wx$(echo abcde)yz"
recho "$(echo abcde)"
echo $(cat <<eof
'
eof
)
echo after 1
echo $(cat <<\eof
'
eof
)
echo after 2
echo "$(cat <<\eof
'
eof
)"
echo after 3
echo "$(cat <<\eof
`
eof
)"
echo after 4
echo $(
cat << ')'
hello
)
)
echo after 5
echo $(cat <<'eof'
'
eof
)
echo after 6
echo $(
case x in x) echo x;; esac
)
echo $(
case x in (x) echo x;; esac
)
echo $(
echo 'quoted )'
)
echo $(
echo comment # with )
)
echo $(
cat <<\eof
here-doc with )
eof
)
echo $(
cat <<\)
here-doc terminated with a parenthesis
)
)
echo $(
cat <<\eof
' # or a single back- or doublequote
eof
)
+3
View File
@@ -0,0 +1,3 @@
echo $( if x; then echo foo )
echo after
+4 -3
View File
@@ -53,9 +53,10 @@ umask: usage: umask [-p] [-S] [mode]
./errors.tests: line 159: declare: VAR: readonly variable
./errors.tests: line 161: declare: unset: not found
./errors.tests: line 164: VAR: readonly variable
./errors.tests: command substitution: line 168: syntax error: unexpected end of file
./errors.tests: command substitution: line 168: syntax error near unexpected token `done'
./errors.tests: command substitution: line 168: ` for z in 1 2 3; done '
./errors.tests: command substitution: line 168: syntax error near unexpected token `)'
./errors.tests: command substitution: line 168: ` for z in 1 2 3; do )'
./errors.tests: command substitution: line 169: syntax error near unexpected token `done'
./errors.tests: command substitution: line 169: ` for z in 1 2 3; done )'
./errors.tests: line 171: cd: HOME not set
./errors.tests: line 172: cd: /tmp/xyz.bash: No such file or directory
./errors.tests: line 174: cd: OLDPWD not set
+1
View File
@@ -54,4 +54,5 @@ exec 8<&0; cat <&8
exec 0<&7
exec 7<&-
rm -f infile
exit 0
+2
View File
@@ -0,0 +1,2 @@
${THIS_SH} ./comsub-posix.tests > /tmp/xx 2>&1
diff /tmp/xx comsub-posix.right && rm -f /tmp/xx
+17 -3
View File
@@ -1,6 +1,6 @@
/* variables.h -- data structures for shell variables. */
/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
/* Copyright (C) 1987-2008 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -23,6 +23,7 @@
#include "stdc.h"
#include "array.h"
#include "assoc.h"
/* Shell variables and functions are stored in hash tables. */
#include "hashlib.h"
@@ -61,7 +62,7 @@ typedef struct var_context {
/* What a shell variable looks like. */
typedef struct variable *sh_var_value_func_t __P((struct variable *));
typedef struct variable *sh_var_assign_func_t __P((struct variable *, char *, arrayind_t));
typedef struct variable *sh_var_assign_func_t __P((struct variable *, char *, arrayind_t, char *));
/* For the future */
union _value {
@@ -108,8 +109,11 @@ typedef struct _vlist {
#define att_local 0x0000020 /* variable is local to a function */
#define att_assoc 0x0000040 /* variable is an associative array */
#define att_trace 0x0000080 /* function is traced with DEBUG trap */
#define att_uppercase 0x0000100 /* word converted to uppercase on assignment */
#define att_lowercase 0x0000200 /* word converted to lowercase on assignment */
#define att_capcase 0x0000400 /* word capitalized on assignment */
#define user_attrs (att_exported|att_readonly|att_integer|att_local|att_trace)
#define user_attrs (att_exported|att_readonly|att_integer|att_local|att_trace|att_uppercase|att_lowercase|att_capcase)
#define attmask_user 0x0000fff
@@ -119,6 +123,7 @@ typedef struct _vlist {
#define att_noassign 0x0004000 /* assignment not allowed */
#define att_imported 0x0008000 /* came from environment */
#define att_special 0x0010000 /* requires special handling */
#define att_nofree 0x0020000 /* do not free value on unset */
#define attmask_int 0x00ff000
@@ -136,12 +141,16 @@ typedef struct _vlist {
#define local_p(var) ((((var)->attributes) & (att_local)))
#define assoc_p(var) ((((var)->attributes) & (att_assoc)))
#define trace_p(var) ((((var)->attributes) & (att_trace)))
#define uppercase_p(var) ((((var)->attributes) & (att_uppercase)))
#define lowercase_p(var) ((((var)->attributes) & (att_lowercase)))
#define capcase_p(var) ((((var)->attributes) & (att_capcase)))
#define invisible_p(var) ((((var)->attributes) & (att_invisible)))
#define non_unsettable_p(var) ((((var)->attributes) & (att_nounset)))
#define noassign_p(var) ((((var)->attributes) & (att_noassign)))
#define imported_p(var) ((((var)->attributes) & (att_imported)))
#define specialvar_p(var) ((((var)->attributes) & (att_special)))
#define nofree_p(var) ((((var)->attributes) & (att_nofree)))
#define tempvar_p(var) ((((var)->attributes) & (att_tempvar)))
@@ -149,6 +158,7 @@ typedef struct _vlist {
#define value_cell(var) ((var)->value)
#define function_cell(var) (COMMAND *)((var)->value)
#define array_cell(var) (ARRAY *)((var)->value)
#define assoc_cell(var) (HASH_TABLE *)((var)->value)
#define var_isnull(var) ((var)->value == 0)
#define var_isset(var) ((var)->value != 0)
@@ -157,6 +167,7 @@ typedef struct _vlist {
#define var_setvalue(var, str) ((var)->value = (str))
#define var_setfunc(var, func) ((var)->value = (char *)(func))
#define var_setarray(var, arr) ((var)->value = (char *)(arr))
#define var_setassoc(var, arr) ((var)->value = (char *)(arr))
/* Make VAR be auto-exported. */
#define set_auto_export(var) \
@@ -316,6 +327,9 @@ extern void print_var_function __P((SHELL_VAR *));
extern SHELL_VAR *make_new_array_variable __P((char *));
extern SHELL_VAR *make_local_array_variable __P((char *));
extern SHELL_VAR *make_new_assoc_variable __P((char *));
extern SHELL_VAR *make_local_assoc_variable __P((char *));
extern void set_pipestatus_array __P((int *, int));
#endif
+21 -3
View File
@@ -1,6 +1,6 @@
/* variables.h -- data structures for shell variables. */
/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
/* Copyright (C) 1987-2008 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -23,6 +23,7 @@
#include "stdc.h"
#include "array.h"
#include "assoc.h"
/* Shell variables and functions are stored in hash tables. */
#include "hashlib.h"
@@ -61,7 +62,7 @@ typedef struct var_context {
/* What a shell variable looks like. */
typedef struct variable *sh_var_value_func_t __P((struct variable *));
typedef struct variable *sh_var_assign_func_t __P((struct variable *, char *, arrayind_t));
typedef struct variable *sh_var_assign_func_t __P((struct variable *, char *, arrayind_t, char *));
/* For the future */
union _value {
@@ -108,8 +109,11 @@ typedef struct _vlist {
#define att_local 0x0000020 /* variable is local to a function */
#define att_assoc 0x0000040 /* variable is an associative array */
#define att_trace 0x0000080 /* function is traced with DEBUG trap */
#define att_uppercase 0x0000100 /* word converted to uppercase on assignment */
#define att_lowercase 0x0000200 /* word converted to lowercase on assignment */
#define att_capcase 0x0000400 /* word capitalized on assignment */
#define user_attrs (att_exported|att_readonly|att_integer|att_local|att_trace)
#define user_attrs (att_exported|att_readonly|att_integer|att_local|att_trace|att_uppercase|att_lowercase|att_capcase)
#define attmask_user 0x0000fff
@@ -119,6 +123,7 @@ typedef struct _vlist {
#define att_noassign 0x0004000 /* assignment not allowed */
#define att_imported 0x0008000 /* came from environment */
#define att_special 0x0010000 /* requires special handling */
#define att_nofree 0x0020000 /* do not free value on unset */
#define attmask_int 0x00ff000
@@ -136,12 +141,16 @@ typedef struct _vlist {
#define local_p(var) ((((var)->attributes) & (att_local)))
#define assoc_p(var) ((((var)->attributes) & (att_assoc)))
#define trace_p(var) ((((var)->attributes) & (att_trace)))
#define uppercase_p(var) ((((var)->attributes) & (att_uppercase)))
#define lowercase_p(var) ((((var)->attributes) & (att_lowercase)))
#define capcase_p(var) ((((var)->attributes) & (att_capcase)))
#define invisible_p(var) ((((var)->attributes) & (att_invisible)))
#define non_unsettable_p(var) ((((var)->attributes) & (att_nounset)))
#define noassign_p(var) ((((var)->attributes) & (att_noassign)))
#define imported_p(var) ((((var)->attributes) & (att_imported)))
#define specialvar_p(var) ((((var)->attributes) & (att_special)))
#define nofree_p(var) ((((var)->attributes) & (att_nofree)))
#define tempvar_p(var) ((((var)->attributes) & (att_tempvar)))
@@ -149,6 +158,7 @@ typedef struct _vlist {
#define value_cell(var) ((var)->value)
#define function_cell(var) (COMMAND *)((var)->value)
#define array_cell(var) (ARRAY *)((var)->value)
#define assoc_cell(var) (HASH_TABLE *)((var)->value)
#define var_isnull(var) ((var)->value == 0)
#define var_isset(var) ((var)->value != 0)
@@ -157,6 +167,7 @@ typedef struct _vlist {
#define var_setvalue(var, str) ((var)->value = (str))
#define var_setfunc(var, func) ((var)->value = (char *)(func))
#define var_setarray(var, arr) ((var)->value = (char *)(arr))
#define var_setassoc(var, arr) ((var)->value = (char *)(arr))
/* Make VAR be auto-exported. */
#define set_auto_export(var) \
@@ -316,6 +327,9 @@ extern void print_var_function __P((SHELL_VAR *));
extern SHELL_VAR *make_new_array_variable __P((char *));
extern SHELL_VAR *make_local_array_variable __P((char *));
extern SHELL_VAR *make_new_assoc_variable __P((char *));
extern SHELL_VAR *make_local_assoc_variable __P((char *));
extern void set_pipestatus_array __P((int *, int));
#endif
@@ -325,6 +339,10 @@ extern void set_pipestatus_from_exit __P((int));
is one of the special ones where something special happens. */
extern void stupidly_hack_special_variables __P((char *));
/* Reinitialize some special variables that have external effects upon unset
when the shell reinitializes itself. */
extern void reinit_special_variables __P((void));
extern int get_random_number __P((void));
/* The `special variable' functions that get called when a particular