how `command' can cancel effects of special builtin exit properties
in the case of `dot file not found'
+ 10/13
+ -----
+lib/sh/strtrans.c
+ - pass \c through unchanged if not escaping for `echo -e' and they are
+ the final two characters in the string
+
+ 10/15
+ -----
+subst.c
+ - extract_dollar_brace_string: fix problem with single quotes
+ in unquoted ${...} for Posix compliance
+
+ 10/16
+ -----
+builtins/exec.def
+ - catch return value from shell_execve; don't print duplicate error
+ message if return value is EX_NOTFOUND. Make sure exit status
+ from exec is 127 if command is not found
+
+execute_cmd.c
+ - fix typo (`saved_redirects' should be `saved redirects') in
+ execute_function_or_builtin `command exec' case. Typo caused
+ too much of the unwind-protect stack to be discarded
+ - in same execute_function_or_builtin case, don't discard the
+ `saved redirects' frame unconditionally; only discard it if
+ saved_redirects is non-null in the `command exec' case. Fixes
+ sh -c 'command exec; exit 1' hanging bug uncovered by FreeBSD
+ sh test cases
+
+ 10/18
+ -----
+subst.c
+ - when in posix mode, shell should not exit if a variable assignment
+ error (e.g., assigning to readonly variable) occurs preceding a
+ command that is not a special builtin. Fixes bug uncovered by
+ FreeBSD sh test cases
+ - when in posix mode, the ${!?} and ${!#} expansions are not indirect
+ expansions, but posix word expansions involving the `!' variable
+
+parse.y
+ - fix parse_comsub so that it does not skip backslash-newline when
+ parsing a comment
+
+ 10/19
+ -----
+subst.c
+ - fix parameter_brace_expand so that an attempt to use the % or #
+ expansions on an unset variable with -u set will cause a non-
+ interactive shell to abort. Posix change
+ - fix parameter_brace_expand so that an attempt to use pattern
+ substitution or case modification expansions on an unset variable
+ with -u set will cause and unbound variable error and make a
+ non-interactive shell abort
+ - change parameter_brace_expand_length to return INTMAX_MIN if a
+ positional parameter is unset and -u is set
+ - if parameter_brace_expand_length returns INTMAX_MIN when -u is set,
+ treat it as an unbound variable error and make a non-interactive
+ shell abort. Posix change
+ - change parameter_brace_expand_length to return INTMAX_MIN if an
+ implicit reference to array[0] is made ${#array} and array[0] is
+ not set when -u is set
+
+ 10/20
+ -----
+builtins/cd.def
+ - Posix 2008 says that if no matching directories are found in $CDPATH,
+ use the directory name passed as an operand and go on. Posix change
+
+doc/bashref.texi
+ - change Posix mode section with latest additions and removals
- set executing_command_builtin in execute_builtin if the builtin is
command_builtin. Unwind-protected in execute_function_or_builtin
(like executing_builtin variable). Available for rest of shell
+
+builtins/{source.def,evalfile.c}
+ - make sure that non-interactive posix mode shells exit if the file
+ argument to `.' is not found only if they are not being executed
+ by the command builtin (executing_command_builtin == 0). This is
+ how `command' can cancel effects of special builtin exit properties
+ in the case of `dot file not found'
+
+ 10/13
+ -----
+lib/sh/strtrans.c
+ - pass \c through unchanged if not escaping for `echo -e' and they are
+ the final two characters in the string
+
+ 10/15
+ -----
+subst.c
+ - extract_dollar_brace_string: fix problem with single quotes
+ in unquoted ${...} for Posix compliance
+
+ 10/16
+ -----
+builtins/exec.def
+ - catch return value from shell_execve; don't print duplicate error
+ message if return value is EX_NOTFOUND. Make sure exit status
+ from exec is 127 if command is not found
+
+execute_cmd.c
+ - fix typo (`saved_redirects' should be `saved redirects') in
+ execute_function_or_builtin `command exec' case. Typo caused
+ too much of the unwind-protect stack to be discarded
+ - in same execute_function_or_builtin case, don't discard the
+ `saved redirects' frame unconditionally; only discard it if
+ saved_redirects is non-null in the `command exec' case. Fixes
+ sh -c 'command exec; exit 1' hanging bug uncovered by FreeBSD
+ sh test cases
+
+ 10/18
+ -----
+subst.c
+ - when in posix mode, shell should not exit if a variable assignment
+ error (e.g., assigning to readonly variable) occurs preceding a
+ command that is not a special builtin. Fixes bug uncovered by
+ FreeBSD sh test cases
+ - when in posix mode, the ${!?} and ${!#} expansions are not indirect
+ expansions, but posix word expansions involving the `!' variable
+
+parse.y
+ - fix parse_comsub so that it does not skip backslash-newline when
+ parsing a comment
+
+ 10/19
+ -----
+subst.c
+ - fix parameter_brace_expand so that an attempt to use the % or #
+ expansions on an unset variable with -u set will cause a non-
+ interactive shell to abort. Posix change
+ - fix parameter_brace_expand so that an attempt to use pattern
+ substitution or case modification expansions on an unset variable
+ with -u set will cause and unbound variable error and make a
+ non-interactive shell abort
+ - change parameter_brace_expand_length to return INTMAX_MIN if a
+ positional parameter is unset and -u is set
+ - if parameter_brace_expand_length returns INTMAX_MIN when -u is set,
+ treat it as an unbound variable error and make a non-interactive
+ shell abort. Posix change
+ - change parameter_brace_expand_length to return INTMAX_MIN if an
+ implicit reference to array[0] is made ${#array} and array[0] is
+ not set when -u is set
+
+ 10/20
+ -----
+builtins/cd.def
+ - Posix 2008 says that if no matching directories are found in $CDPATH,
+ use the directory name passed as an operand and go on. Posix change
free (temp);
}
+#if 0 /* changed for bash-4.2 Posix cd description steps 5-6 */
/* POSIX.2 says that if `.' does not appear in $CDPATH, we don't
try the current directory, so we just punt now with an error
message if POSIXLY_CORRECT is non-zero. The check for cdpath[0]
builtin_error ("%s: %s", dirname, strerror (ENOENT));
return (EXECUTION_FAILURE);
}
+#endif
}
else
dirname = list->word->word;
int cdable_vars;
+static int eflag; /* file scope so bindpwd() can see it */
+
$BUILTIN cd
$FUNCTION cd_builtin
$SHORT_DOC cd [-L|[-P [-e]]] [dir]
}
setpwd (dirname);
+ if (dirname == 0 && eflag)
+ r = EXECUTION_FAILURE;
if (dirname && dirname != the_current_working_directory)
free (dirname);
WORD_LIST *list;
{
char *dirname, *cdpath, *path, *temp;
- int path_index, no_symlinks, opt, lflag, eflag;
+ int path_index, no_symlinks, opt, lflag;
#if defined (RESTRICTED_SHELL)
if (restricted)
lflag = (cdable_vars ? LCD_DOVARS : 0) |
((interactive && cdspelling) ? LCD_DOSPELL : 0);
+ if (eflag && no_symlinks == 0)
+ eflag = 0;
if (list == 0)
{
specifying the current directory. */
if (posixly_correct && cdpath[0])
{
+#if 0
builtin_error ("%s: %s", dirname, strerror (ENOENT));
return (EXECUTION_FAILURE);
+#else /* changed for bash-4.2 Posix cd description steps 5-6 */
+ if (no_symlinks)
+ dirname = list->word->word;
+ else
+ dirname =
+#endif
}
}
else
/* evalstring.c - evaluate a string as one or more shell commands.
-/* Copyright (C) 1996-2009 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2010 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
begin_unwind_frame ("pe_dispose");
+itrace("begin_unwind_frame: pe_dispose");
add_unwind_protect (dispose_fd_bitmap, bitmap);
add_unwind_protect (dispose_command, command); /* XXX */
end_job_control ();
#endif /* JOB_CONTROL */
- shell_execve (command, args, env);
+ exit_value = shell_execve (command, args, env);
/* We have to set this to NULL because shell_execve has called realloc()
to stuff more items at the front of the array, which may have caused
if (cleanenv == 0)
adjust_shell_level (1);
- if (executable_file (command) == 0)
+ if (exit_value == EX_NOTFOUND) /* no duplicate error message */
+ goto failed_exec;
+ else if (executable_file (command) == 0)
{
builtin_error (_("%s: cannot execute: %s"), command, strerror (errno));
exit_value = EX_NOEXEC; /* As per Posix.2, 3.14.6 */
{
if (file_isdir (args[0]))
{
+#if defined (EISDIR)
+ builtin_error (_("%s: cannot execute: %s"), args[0], strerror (EISDIR));
+#else
builtin_error (_("%s: cannot execute: %s"), args[0], strerror (errno));
+#endif
exit_value = EX_NOEXEC;
}
else
end_job_control ();
#endif /* JOB_CONTROL */
- shell_execve (command, args, env);
+ exit_value = shell_execve (command, args, env);
/* We have to set this to NULL because shell_execve has called realloc()
to stuff more items at the front of the array, which may have caused
if (cleanenv == 0)
adjust_shell_level (1);
- if (executable_file (command) == 0)
+ if (exit_value == EX_NOTFOUND)
+ goto failed_exec;
+ else if (executable_file (command) == 0)
{
builtin_error (_("%s: cannot execute: %s"), command, strerror (errno));
exit_value = EX_NOEXEC; /* As per Posix.2, 3.14.6 */
shell and by the commands it invokes.
If a SIGNAL_SPEC is EXIT (0) ARG is executed on exit from the shell. If
-a SIGNAL_SPEC is DEBUG, ARG is executed before every simple command.
+a SIGNAL_SPEC is DEBUG, ARG is executed before every simple command. If
+a SIGNAL_SPEC is RETURN, ARG is executed each time a shell function or a
+script run by the . or source builtins finishes executing. A SIGNAL_SPEC
+of ERR means to execute ARG each time a command's failure would cause the
+shell to exit when the -e option is enabled.
If no arguments are supplied, trap prints the list of commands associated
with each signal.
This file is trap.def, from which is created trap.c.
It implements the builtin "trap" in Bash.
-Copyright (C) 1987-2009 Free Software Foundation, Inc.
+Copyright (C) 1987-2010 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
shell and by the commands it invokes.
If a SIGNAL_SPEC is EXIT (0) ARG is executed on exit from the shell. If
-a SIGNAL_SPEC is DEBUG, ARG is executed before every simple command.
+a SIGNAL_SPEC is DEBUG, ARG is executed before every simple command. If
+a SIGNAL_SPEC is RETURN, ARG is executed each time a shell function or a
+script run by the . or source builtins finishes executing.
If no arguments are supplied, trap prints the list of commands associated
with each signal.
.BR RETURN ,
the command
.I arg
-is executed each time a shell function or a script executed with the
-\fB.\fP or \fBsource\fP builtins finishes executing.
+is executed each time a shell function or a script executed with
+the \fB.\fP or \fBsource\fP builtins finishes executing.
.if t .sp 0.5
.if n .sp 1
If a
.\" Case Western Reserve University
.\" chet@po.cwru.edu
.\"
-.\" Last Change: Sat Aug 28 18:55:45 EDT 2010
+.\" Last Change: Mon Sep 6 22:07:38 EDT 2010
.\"
.\" bash_builtins, strip all but Built-Ins section
.if \n(zZ=1 .ig zZ
.if \n(zY=1 .ig zY
-.TH BASH 1 "2010 August 28" "GNU Bash-4.2"
+.TH BASH 1 "2010 September 6" "GNU Bash-4.2"
.\"
.\" There's some problem with having a `@'
.\" in a tagged paragraph with the BSD man macros.
redirection errors, variable assignment errors for assignments preceding
the command name, and so on.
-@item
-If @env{CDPATH} is set, the @code{cd} builtin will not implicitly
-append the current directory to it. This means that @code{cd} will
-fail if no valid directory name can be constructed from
-any of the entries in @env{$CDPATH}, even if the a directory with
-the same name as the name given as an argument to @code{cd} exists
-in the current directory.
-
@item
A non-interactive shell exits with an error status if a variable
assignment error occurs when no command name follows the assignment
A variable assignment error occurs, for example, when trying to assign
a value to a readonly variable.
+@item
+A non-interactive shell exists with an error status if a variable
+assignment error occurs in an assignment statement preceding a special
+builtin, but not with any other simple command.
+
@item
A non-interactive shell exits with an error status if the iteration
variable in a @code{for} statement or the selection variable in a
does not refer to an existing directory, @code{cd} will fail instead of
falling back to @var{physical} mode.
-@item
-When the @code{pwd} builtin is supplied the @option{-P} option, it resets
-@code{$PWD} to a pathname containing no symlinks.
-
@item
The @code{pwd} builtin verifies that the value it prints is the same as the
current directory, even if it is not asked to check the file system with the
The file descriptors can be utilized as arguments to shell commands
and redirections using standard word expansions.
-The process id of the shell spawned to execute the coprocess is
+The process ID of the shell spawned to execute the coprocess is
available as the value of the variable @var{NAME}_PID.
The @code{wait}
builtin command may be used to wait for the coprocess to terminate.
to a shell variable or array index (@pxref{Arrays}), the @samp{+=}
operator can be used to
append to or add to the variable's previous value.
-When @samp{+=} is applied to a variable for which the integer attribute
+When @samp{+=} is applied to a variable for which the @var{integer} attribute
has been set, @var{value} is evaluated as an arithmetic expression and
added to the variable's current value, which is also evaluated.
When @samp{+=} is applied to an array variable using compound assignment
expanded and that value is used in the rest of the substitution, rather
than the value of @var{parameter} itself.
This is known as @code{indirect expansion}.
-The exceptions to this are the expansions of $@{!@var{prefix*}@}
+The exceptions to this are the expansions of $@{!@var{prefix}@*}
and $@{!@var{name}[@@]@}
described below.
The exclamation point must immediately follow the left brace in order to
When the end of options is encountered, @code{getopts} exits with a
return value greater than zero.
@env{OPTIND} is set to the index of the first non-option argument,
-and @code{name} is set to @samp{?}.
+and @var{name} is set to @samp{?}.
@code{getopts}
normally parses the positional parameters, but if more arguments are
@item set
@btindex set
@example
-set [--abefhkmnptuvxBCEHPT] [-o @var{option}] [@var{argument} @dots{}]
-set [+abefhkmnptuvxBCEHPT] [+o @var{option}] [@var{argument} @dots{}]
+set [--abefhkmnptuvxBCEHPT] [-o @var{option-name}] [@var{argument} @dots{}]
+set [+abefhkmnptuvxBCEHPT] [+o @var{option-name}] [@var{argument} @dots{}]
@end example
If no options or arguments are supplied, @code{set} displays the names
@item compat31
If set, Bash
changes its behavior to that of version 3.1 with respect to quoted
-arguments to the conditional command's =~ operator.
+arguments to the conditional command's @samp{=~} operator.
@item compat32
If set, Bash
changes its behavior to that of version 3.2 with respect to locale-specific
-string comparison when using the conditional command's < and > operators.
+string comparison when using the conditional command's @samp{<} and @samp{>}
+operators.
@item compat40
If set, Bash
changes its behavior to that of version 4.0 with respect to locale-specific
-string comparison when using the conditional command's < and > operators
-and the effect of interrupting a command list.
+string comparison when using the conditional command's @samp{<} and @samp{>}
+operators and the effect of interrupting a command list.
@item compat41
If set, Bash, when in posix mode, treats a single quote in a double-quoted
reading any startup files. This variable is readonly.
@item BASHPID
-Expands to the process id of the current Bash process.
+Expands to the process ID of the current Bash process.
This differs from @code{$$} under certain circumstances, such as subshells
that do not require Bash to be re-initialized.
@item BASH_ALIASES
An associative array variable whose members correspond to the internal
-list of aliases as maintained by the @code{alias} builtin
+list of aliases as maintained by the @code{alias} builtin.
(@pxref{Bourne Shell Builtins}).
Elements added to this array appear in the alias list; unsetting array
elements cause aliases to be removed from the alias list.
@subsubheading Invoked by remote shell daemon
Bash attempts to determine when it is being run with its standard input
-connected to a network connection, as if by the remote shell
+connected to a network connection, as when executed by the remote shell
daemon, usually @code{rshd}, or the secure shell daemon @code{sshd}.
If Bash determines it is being run in
this fashion, it reads and executes commands from @file{~/.bashrc}, if that
when it is referenced, or when a variable which has been given the
@var{integer} attribute using @samp{declare -i} is assigned a value.
A null value evaluates to 0.
-A shell variable need not have its integer attribute turned on
+A shell variable need not have its @var{integer} attribute turned on
to be used in an expression.
Constants with a leading 0 are interpreted as octal numbers.
Copyright (C) 1988-2010 Free Software Foundation, Inc.
@end ignore
-@set LASTCHANGE Mon Sep 6 22:08:10 EDT 2010
+@set LASTCHANGE Wed Oct 20 21:37:22 EDT 2010
@set EDITION 4.2
@set VERSION 4.2
-@set UPDATED 6 September 2010
-@set UPDATED-MONTH September 2010
+@set UPDATED 20 October 2010
+@set UPDATED-MONTH October 2010
Copyright (C) 1988-2010 Free Software Foundation, Inc.
@end ignore
-@set LASTCHANGE Sat Aug 28 18:56:04 EDT 2010
+@set LASTCHANGE Mon Sep 6 22:08:10 EDT 2010
@set EDITION 4.2
@set VERSION 4.2
-@set UPDATED 28 August 2010
-@set UPDATED-MONTH August 2010
+@set UPDATED 6 September 2010
+@set UPDATED-MONTH September 2010
and preserve the redirections. */
if (builtin == command_builtin && this_shell_builtin == exec_builtin)
{
+ int discard;
+
+ discard = 0;
if (saved_undo_list)
- dispose_redirects (saved_undo_list);
+ {
+ dispose_redirects (saved_undo_list);
+ discard = 1;
+ }
redirection_undo_list = exec_redirection_undo_list;
saved_undo_list = exec_redirection_undo_list = (REDIRECT *)NULL;
- discard_unwind_frame ("saved_redirects");
+ if (discard)
+ discard_unwind_frame ("saved redirects");
}
if (saved_undo_list)
}
executing_builtin++;
- executing_command_builtin = builtin == command_builtin;
+ executing_command_builtin |= builtin == command_builtin;
result = ((*builtin) (words->next));
/* This shouldn't happen, but in case `return' comes back instead of
and preserve the redirections. */
if (builtin == command_builtin && this_shell_builtin == exec_builtin)
{
+ int discard;
+
+ discard = 0;
if (saved_undo_list)
- dispose_redirects (saved_undo_list);
+ {
+ dispose_redirects (saved_undo_list);
+ discard = 1;
+ }
redirection_undo_list = exec_redirection_undo_list;
saved_undo_list = exec_redirection_undo_list = (REDIRECT *)NULL;
- discard_unwind_frame ("saved_redirects");
+ if (discard)
+ discard_unwind_frame ("saved redirects");
}
if (saved_undo_list)
CHECK_TERMSIG;
SETOSTYPE (1);
+itrace("shell_execve: command = %s", command);
/* If we get to this point, then start checking out the file.
Maybe it is something we can hack ourselves. */
if (i != ENOEXEC)
#endif
#ifndef UNCTRL
/* control char to letter -- ASCII */
-# define UNCTRL(x) (TOUPPER((x) | 0x40))
+# define UNCTRL(x) (TOUPPER(x) ^ 0x40)
#endif
#endif /* _SH_CHARTYPES_H */
*rlen = r - ret;
return ret;
}
+ else if ((flags & 1) == 0 && *s == 0)
+ ; /* pass \c through */
else if ((flags & 1) == 0 && (c = *s))
{
s++;
/* The globally known line number. */
int line_number = 0;
+/* The line number offset set by assigning to LINENO. Not currently used. */
+int line_number_base = 0;
+
#if defined (COND_COMMAND)
static int cond_lineno;
static int cond_token;
start_lineno = line_number;
while (count)
{
- ch = shell_getc (qc != '\'' && (tflags & LEX_PASSNEXT) == 0);
+ ch = shell_getc (qc != '\'' && (tflags & (LEX_PASSNEXT)) == 0);
if (ch == EOF)
{
while (count)
{
comsub_readchar:
- ch = shell_getc (qc != '\'' && (tflags & LEX_PASSNEXT) == 0);
+ ch = shell_getc (qc != '\'' && (tflags & (LEX_INCOMMENT|LEX_PASSNEXT)) == 0);
if (ch == EOF)
{
/* The globally known line number. */
int line_number = 0;
+/* The line number offset set by assigning to LINENO. Not currently used. */
+int line_number_base = 0;
+
#if defined (COND_COMMAND)
static int cond_lineno;
static int cond_token;
start_lineno = line_number;
while (count)
{
- ch = shell_getc (qc != '\'' && (tflags & LEX_PASSNEXT) == 0);
+ ch = shell_getc (qc != '\'' && (tflags & (LEX_PASSNEXT)) == 0);
if (ch == EOF)
{
{
char *temp_prompt;
-itrace("prompt_again()");
if (interactive == 0 || expanding_alias ()) /* XXX */
return;
FREE (current_decoded_prompt);
current_decoded_prompt = temp_prompt;
}
-itrace("prompt_again: current_prompt_string = %s", current_prompt_string);
}
int
else
init_noninteractive ();
-#define CLOSE_FDS_AT_LOGIN
-#if defined (CLOSE_FDS_AT_LOGIN)
/*
* Some systems have the bad habit of starting login shells with lots of open
* file descriptors. For instance, most systems that have picked up the
* pre-4.0 Sun YP code leave a file descriptor open each time you call one
* of the getpw* functions, and it's set to be open across execs. That
- * means one for login, one for xterm, one for shelltool, etc.
+ * means one for login, one for xterm, one for shelltool, etc. There are
+ * also systems that open persistent FDs to other agents or files as part
+ * of process startup; these need to be set to be close-on-exec.
*/
if (login_shell && interactive_shell)
{
for (i = 3; i < 20; i++)
- close (i);
+ SET_CLOSE_ON_EXEC (i);
}
-#endif /* CLOSE_FDS_AT_LOGIN */
/* If we're in a strict Posix.2 mode, turn on interactive comments,
alias expansion in non-interactive shells, and other Posix.2 things. */
int code;
code = setjmp (top_level);
-
+itrace("run_one_command: setjmp: code = %d", code);
if (code != NOT_JUMPED)
{
#if defined (PROCESS_SUBSTITUTION)
unlink_fifo_list ();
#endif /* PROCESS_SUBSTITUTION */
+itrace("run_one_command: code = %d", code);
switch (code)
{
/* Some kind of throw to top_level has occured. */
/* Evaluates to 1 if C is one of the shell's special parameters for which an
indirect variable reference may be made. */
#define VALID_INDIR_PARAM(c) \
- ((c) == '#' || (c) == '?' || (c) == '@' || (c) == '*')
+ ((posixly_correct == 0 && (c) == '#') || (posixly_correct == 0 && (c) == '?') || (c) == '@' || (c) == '*')
/* Evaluates to 1 if C is one of the OP characters that follows the parameter
in ${parameter[:]OPword}. */
if (c == '\'')
{
/*itrace("extract_dollar_brace_string: c == single quote flags = %d quoted = %d dolbrace_state = %d", flags, quoted, dolbrace_state);*/
- if (posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE)
+ if (posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
ADVANCE_CHAR (string, slen, i);
else
{
break;
case '!':
if (last_asynchronous_pid == NO_PID)
- t = (char *)NULL;
+ t = (char *)NULL; /* XXX - error if set -u set? */
else
t = itos (last_asynchronous_pid);
break;
if (legal_number (name + 1, &arg_index)) /* ${#1} */
{
t = get_dollar_var_value (arg_index);
+ if (t == 0 && unbound_vars_is_error)
+ return INTMAX_MIN;
number = MB_STRLEN (t);
FREE (t);
}
t = assoc_reference (assoc_cell (var), "0");
else
t = array_reference (array_cell (var), 0);
+ if (t == 0 && unbound_vars_is_error)
+ return INTMAX_MIN;
number = MB_STRLEN (t);
}
#endif
/* If the name really consists of a special variable, then make sure
that we have the entire name. We don't allow indirect references
to special variables except `#', `?', `@' and `*'. */
- if ((sindex == t_index &&
- (string[t_index] == '-' ||
- string[t_index] == '?' ||
- string[t_index] == '#')) ||
- (sindex == t_index - 1 && string[sindex] == '!' &&
- (string[t_index] == '#' ||
- string[t_index] == '?' ||
- string[t_index] == '@' ||
- string[t_index] == '*')))
+ if ((sindex == t_index && VALID_SPECIAL_LENGTH_PARAM (string[t_index])) ||
+ (sindex == t_index - 1 && string[sindex] == '!' && VALID_INDIR_PARAM (string[t_index])))
{
t_index++;
free (name);
}
number = parameter_brace_expand_length (name);
+ if (number == INTMAX_MIN && unbound_vars_is_error)
+ {
+ last_command_exit_value = EXECUTION_FAILURE;
+ err_unboundvar (name+1);
+ free (name);
+ return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
+ }
free (name);
*indexp = sindex;
*indexp = sindex;
+ /* All the cases where an expansion can possibly generate an unbound
+ variable error. */
+ if (want_substring || want_patsub || want_casemod || c == '#' || c == '%' || c == RBRACE)
+ {
+ if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]))
+ {
+ last_command_exit_value = EXECUTION_FAILURE;
+ err_unboundvar (name);
+ FREE (value);
+ FREE (temp);
+ free (name);
+ return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
+ }
+ }
+
/* If this is a substring spec, process it and add the result. */
if (want_substring)
{
return &expand_wdesc_error;
case RBRACE:
- if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]))
- {
- last_command_exit_value = EXECUTION_FAILURE;
- err_unboundvar (name);
- FREE (value);
- FREE (temp);
- free (name);
- return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
- }
break;
case '#': /* ${param#[#]pattern} */
if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
{
sh_wassign_func_t *assign_func;
+ int is_special_builtin;
/* If the remainder of the words expand to nothing, Posix.2 requires
that the variable and environment assignments affect the shell's
assign_func = new_list ? assign_in_env : do_word_assignment;
tempenv_assign_error = 0;
+ /* Posix says that special builtins exit if a variable assignment error
+ occurs in an assignment preceding it. */
+ is_special_builtin = (posixly_correct && new_list && find_special_builtin (new_list->word->word));
+
for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
{
this_command_name = (char *)NULL;
if (assign_func == do_word_assignment)
{
last_command_exit_value = EXECUTION_FAILURE;
- if (interactive_shell == 0 && posixly_correct)
+ if (interactive_shell == 0 && posixly_correct && is_special_builtin)
exp_jump_to_top_level (FORCE_EOF);
else
exp_jump_to_top_level (DISCARD);
/* Evaluates to 1 if C is one of the shell's special parameters for which an
indirect variable reference may be made. */
#define VALID_INDIR_PARAM(c) \
- ((c) == '#' || (c) == '?' || (c) == '@' || (c) == '*')
+ ((posixly_correct == 0 && (c) == '#') || (posixly_correct == 0 && (c) == '?') || (c) == '@' || (c) == '*')
/* Evaluates to 1 if C is one of the OP characters that follows the parameter
in ${parameter[:]OPword}. */
if (c == '\'')
{
/*itrace("extract_dollar_brace_string: c == single quote flags = %d quoted = %d dolbrace_state = %d", flags, quoted, dolbrace_state);*/
- if (posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE)
+ if (posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
ADVANCE_CHAR (string, slen, i);
else
{
if (legal_number (name + 1, &arg_index)) /* ${#1} */
{
t = get_dollar_var_value (arg_index);
+ if (t == 0 && unbound_vars_is_error)
+ return INTMAX_MIN;
number = MB_STRLEN (t);
FREE (t);
}
t = assoc_reference (assoc_cell (var), "0");
else
t = array_reference (array_cell (var), 0);
+ if (t == 0 && unbound_vars_is_error)
+ return INTMAX_MIN;
number = MB_STRLEN (t);
}
#endif
/* If the name really consists of a special variable, then make sure
that we have the entire name. We don't allow indirect references
to special variables except `#', `?', `@' and `*'. */
- if ((sindex == t_index &&
- (string[t_index] == '-' ||
- string[t_index] == '?' ||
- string[t_index] == '#')) ||
- (sindex == t_index - 1 && string[sindex] == '!' &&
- (string[t_index] == '#' ||
- string[t_index] == '?' ||
- string[t_index] == '@' ||
- string[t_index] == '*')))
+ if ((sindex == t_index && VALID_SPECIAL_LENGTH_PARAM (string[t_index])) ||
+ (sindex == t_index - 1 && string[sindex] == '!' && VALID_INDIR_PARAM (string[t_index])))
{
t_index++;
free (name);
}
number = parameter_brace_expand_length (name);
+ if (number == INTMAX_MIN && unbound_vars_is_error)
+ {
+ last_command_exit_value = EXECUTION_FAILURE;
+ err_unboundvar (name+1);
+ free (name);
+ return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
+ }
free (name);
*indexp = sindex;
*indexp = sindex;
+ /* All the cases where an expansion can possibly generate an unbound
+ variable error. */
+ if (want_substring || want_patsub || want_casemod || c == '#' || c == '%' || c == RBRACE)
+ {
+ if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]))
+ {
+ last_command_exit_value = EXECUTION_FAILURE;
+ err_unboundvar (name);
+ FREE (value);
+ FREE (temp);
+ free (name);
+ return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
+ }
+ }
+
/* If this is a substring spec, process it and add the result. */
if (want_substring)
{
return &expand_wdesc_error;
case RBRACE:
- if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]))
- {
- last_command_exit_value = EXECUTION_FAILURE;
- err_unboundvar (name);
- FREE (value);
- FREE (temp);
- free (name);
- return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
- }
break;
case '#': /* ${param#[#]pattern} */
/* $? -- return value of the last synchronous command. */
case '?':
temp = itos (last_command_exit_value);
-itrace("last_command_exit_value = %d", last_command_exit_value);
break;
/* $- -- flags supplied to the shell on invocation or by `set'. */
if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
{
sh_wassign_func_t *assign_func;
+ int is_special_builtin;
/* If the remainder of the words expand to nothing, Posix.2 requires
that the variable and environment assignments affect the shell's
assign_func = new_list ? assign_in_env : do_word_assignment;
tempenv_assign_error = 0;
+ /* Posix says that special builtins exit if a variable assignment error
+ occurs in an assignment preceding it. */
+ is_special_builtin = (posixly_correct && new_list && find_special_builtin (new_list->word->word));
+
for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
{
this_command_name = (char *)NULL;
if (assign_func == do_word_assignment)
{
last_command_exit_value = EXECUTION_FAILURE;
- if (interactive_shell == 0 && posixly_correct)
+ if (interactive_shell == 0 && posixly_correct && is_special_builtin)
exp_jump_to_top_level (FORCE_EOF);
else
exp_jump_to_top_level (DISCARD);
-BUILD_DIR=/usr/local/build/chet/bash/bash-current
+BUILD_DIR=/usr/local/build/bash/bash-current
THIS_SH=$BUILD_DIR/bash
PATH=$PATH:$BUILD_DIR
127
/bin/sh: /bin/sh: cannot execute binary file
126
-./execscript: line 39: /: is a directory
+./execscript: line 39: /: Is a directory
126
/: /: is a directory
126
0
this is bashenv
./exec3.sub: line 3: /tmp/bash-notthere: No such file or directory
-./exec3.sub: line 3: exec: /tmp/bash-notthere: cannot execute: No such file or directory
-126
+127
./execscript: line 70: notthere: No such file or directory
127
./execscript: line 73: notthere: No such file or directory
true | `echo true` &
echo after
+
+# Problem with bash at least back to version 3.0
+${THIS_SH} -c 'VAR=0; VAR=1 command exec; exit ${VAR}'
--- /dev/null
+export LC_ALL=C
+export LANG=C
+
+if [ $UID -eq 0 ]; then
+ echo "execscript: the test suite should not be run as root" >&2
+fi
+
+set -- one two three
+echo before exec1.sub: "$@"
+echo calling exec1.sub
+./exec1.sub aa bb cc dd ee
+echo after exec1.sub with args: $?
+./exec1.sub
+echo after exec1.sub without args: $?
+
+# set up a fixed path so we know notthere will not be found
+PATH=/usr/bin:/bin:/usr/local/bin:
+export PATH
+
+notthere
+echo $?
+
+# this is iffy, since the error messages may vary from system to system
+# and /tmp might not exist
+ln -s ${THIS_SH} /tmp/bash 2>/dev/null
+if [ -f /tmp/bash ]; then
+ /tmp/bash notthere
+else
+ ${THIS_SH} notthere
+fi
+echo $?
+rm -f /tmp/bash
+
+# /bin/sh should be there on all systems
+${THIS_SH} /bin/sh
+echo $?
+
+# try executing a directory
+/
+echo $?
+
+${THIS_SH} /
+echo $?
+
+# try sourcing a directory
+. /
+echo $?
+
+# try sourcing a binary file -- post-2.04 versions don't do the binary file
+# check, and will probably fail with `command not found', or status 127
+# bash-4.1 and later check for 256 NUL characters and fail as binary files
+# if there are more than that, it's probably binary
+. ${THIS_SH} 2>/dev/null
+echo $?
+
+# post-bash-2.05 versions allow sourcing non-regular files
+. /dev/null
+echo $?
+
+# kill two birds with one test -- test out the BASH_ENV code
+echo echo this is bashenv > /tmp/bashenv
+export BASH_ENV=/tmp/bashenv
+${THIS_SH} ./exec3.sub
+rm -f /tmp/bashenv
+unset BASH_ENV
+
+# we're resetting the $PATH to empty, so this should be last
+PATH=
+
+notthere
+echo $?
+
+command notthere
+echo $?
+
+command -p notthere
+echo $?
+
+# but -p should guarantee that we find all the standard utilities, even
+# with an empty or unset $PATH
+command -p sh -c 'echo this is $0'
+unset PATH
+command -p sh -c 'echo this is $0'
+
+# a bug in bash before bash-2.01 caused PATH to be set to the empty string
+# when command -p was run with PATH unset
+echo ${PATH-unset}
+
+echo "echo ok" | ${THIS_SH} -t
+
+${THIS_SH} ./exec2.sub
+echo $?
+
+${THIS_SH} ./exec4.sub
+
+# try exec'ing a command that cannot be found in $PATH
+${THIS_SH} ./exec5.sub
+
+# this was a bug in bash versions before bash-2.04
+${THIS_SH} -c 'cat </dev/null | cat >/dev/null' >&-
+
+# checks for proper return values in subshell commands with inverted return
+# values
+
+${THIS_SH} ./exec6.sub
+
+# checks for properly deciding what constitutes an executable file
+${THIS_SH} ./exec7.sub
+
+${THIS_SH} -i ./exec8.sub
+
+true | `echo true` &
+
+echo after
+
+${THIS_SH} -c 'VAR=0; VAR=1 command exec; exit ${VAR}'
<x> <.> <w> <.> <x> <.> <w> <.>
argv[1] = <'bar>
argv[1] = <foo 'bar baz>
-argv[1] = <z}>
+argv[1] = <}z>
argv[1] = <''z}>
./posixexp.tests: line 68: unexpected EOF while looking for matching `}'
./posixexp.tests: line 69: syntax error: unexpected end of file
char *tag, *ignore;
{
UNWIND_ELT *elt;
+ int found;
+ found = 0;
while (elt = unwind_protect_list)
{
unwind_protect_list = unwind_protect_list->head.next;
if (elt->head.cleanup == 0 && (STREQ (elt->arg.v, tag)))
{
uwpfree (elt);
+ found = 1;
break;
}
else
uwpfree (elt);
}
+
+ if (found == 0)
+ internal_warning ("unwind_frame_discard: %s: frame not found", tag);
}
/* Restore the value of a variable, based on the contents of SV.
char *tag, *ignore;
{
UNWIND_ELT *elt;
+ int found;
+ found = 0;
while (elt = unwind_protect_list)
{
unwind_protect_list = elt->head.next;
/* If tag, then compare. */
- if (!elt->head.cleanup)
+ if (elt->head.cleanup == 0)
{
if (tag && STREQ (elt->arg.v, tag))
{
uwpfree (elt);
+ found = 1;
break;
}
}
uwpfree (elt);
}
+ if (tag && found == 0)
+ internal_warning ("unwind_frame_run: %s: frame not found", tag);
}
static void
{
without_interrupts (unwind_protect_mem_internal, var, (char *) &size);
}
+
+#if defined (DEBUG)
+void
+print_unwind_protect_tags ()
+{
+ UNWIND_ELT *elt;
+
+ elt = unwind_protect_list;
+ while (elt)
+ {
+ unwind_protect_list = unwind_protect_list->head.next;
+ if (elt->head.cleanup == 0)
+ fprintf(stderr, "tag: %s\n", elt->arg.v);
+ elt = unwind_protect_list;
+ }
+}
+#endif
--- /dev/null
+/* unwind_prot.c - a simple unwind-protect system for internal variables */
+
+/* I can't stand it anymore! Please can't we just write the
+ whole Unix system in lisp or something? */
+
+/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
+
+ This file is part of GNU Bash, the Bourne Again SHell.
+
+ Bash is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Bash is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Bash. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* **************************************************************** */
+/* */
+/* Unwind Protection Scheme for Bash */
+/* */
+/* **************************************************************** */
+#include "config.h"
+
+#include "bashtypes.h"
+#include "bashansi.h"
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#if STDC_HEADERS
+# include <stddef.h>
+#endif
+
+#ifndef offsetof
+# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#include "command.h"
+#include "general.h"
+#include "unwind_prot.h"
+#include "quit.h"
+#include "sig.h"
+
+/* Structure describing a saved variable and the value to restore it to. */
+typedef struct {
+ char *variable;
+ int size;
+ char desired_setting[1]; /* actual size is `size' */
+} SAVED_VAR;
+
+/* If HEAD.CLEANUP is null, then ARG.V contains a tag to throw back to.
+ If HEAD.CLEANUP is restore_variable, then SV.V contains the saved
+ variable. Otherwise, call HEAD.CLEANUP (ARG.V) to clean up. */
+typedef union uwp {
+ struct uwp_head {
+ union uwp *next;
+ Function *cleanup;
+ } head;
+ struct {
+ struct uwp_head uwp_head;
+ char *v;
+ } arg;
+ struct {
+ struct uwp_head uwp_head;
+ SAVED_VAR v;
+ } sv;
+} UNWIND_ELT;
+
+
+static void without_interrupts __P((VFunction *, char *, char *));
+static void unwind_frame_discard_internal __P((char *, char *));
+static void unwind_frame_run_internal __P((char *, char *));
+static void add_unwind_protect_internal __P((Function *, char *));
+static void remove_unwind_protect_internal __P((char *, char *));
+static void run_unwind_protects_internal __P((char *, char *));
+static void clear_unwind_protects_internal __P((char *, char *));
+static inline void restore_variable __P((SAVED_VAR *));
+static void unwind_protect_mem_internal __P((char *, char *));
+
+static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
+
+#define uwpalloc(elt) (elt) = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT))
+#define uwpfree(elt) free(elt)
+
+/* Run a function without interrupts. This relies on the fact that the
+ FUNCTION cannot change the value of interrupt_immediately. (I.e., does
+ not call QUIT (). */
+static void
+without_interrupts (function, arg1, arg2)
+ VFunction *function;
+ char *arg1, *arg2;
+{
+ int old_interrupt_immediately;
+
+ old_interrupt_immediately = interrupt_immediately;
+ interrupt_immediately = 0;
+
+ (*function)(arg1, arg2);
+
+ interrupt_immediately = old_interrupt_immediately;
+}
+
+/* Start the beginning of a region. */
+void
+begin_unwind_frame (tag)
+ char *tag;
+{
+ add_unwind_protect ((Function *)NULL, tag);
+}
+
+/* Discard the unwind protects back to TAG. */
+void
+discard_unwind_frame (tag)
+ char *tag;
+{
+ if (unwind_protect_list)
+ without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL);
+}
+
+/* Run the unwind protects back to TAG. */
+void
+run_unwind_frame (tag)
+ char *tag;
+{
+ if (unwind_protect_list)
+ without_interrupts (unwind_frame_run_internal, tag, (char *)NULL);
+}
+
+/* Add the function CLEANUP with ARG to the list of unwindable things. */
+void
+add_unwind_protect (cleanup, arg)
+ Function *cleanup;
+ char *arg;
+{
+ without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg);
+}
+
+/* Remove the top unwind protect from the list. */
+void
+remove_unwind_protect ()
+{
+ if (unwind_protect_list)
+ without_interrupts
+ (remove_unwind_protect_internal, (char *)NULL, (char *)NULL);
+}
+
+/* Run the list of cleanup functions in unwind_protect_list. */
+void
+run_unwind_protects ()
+{
+ if (unwind_protect_list)
+ without_interrupts
+ (run_unwind_protects_internal, (char *)NULL, (char *)NULL);
+}
+
+/* Erase the unwind-protect list. If flags is 1, free the elements. */
+void
+clear_unwind_protect_list (flags)
+ int flags;
+{
+ char *flag;
+
+ if (unwind_protect_list)
+ {
+ flag = flags ? "" : (char *)NULL;
+ without_interrupts
+ (clear_unwind_protects_internal, flag, (char *)NULL);
+ }
+}
+
+int
+have_unwind_protects ()
+{
+ return (unwind_protect_list != 0);
+}
+
+/* **************************************************************** */
+/* */
+/* The Actual Functions */
+/* */
+/* **************************************************************** */
+
+static void
+add_unwind_protect_internal (cleanup, arg)
+ Function *cleanup;
+ char *arg;
+{
+ UNWIND_ELT *elt;
+
+ uwpalloc (elt);
+ elt->head.next = unwind_protect_list;
+ elt->head.cleanup = cleanup;
+ elt->arg.v = arg;
+ unwind_protect_list = elt;
+}
+
+static void
+remove_unwind_protect_internal (ignore1, ignore2)
+ char *ignore1, *ignore2;
+{
+ UNWIND_ELT *elt;
+
+ elt = unwind_protect_list;
+ if (elt)
+ {
+ unwind_protect_list = unwind_protect_list->head.next;
+ uwpfree (elt);
+ }
+}
+
+static void
+run_unwind_protects_internal (ignore1, ignore2)
+ char *ignore1, *ignore2;
+{
+ unwind_frame_run_internal ((char *) NULL, (char *) NULL);
+}
+
+static void
+clear_unwind_protects_internal (flag, ignore)
+ char *flag, *ignore;
+{
+ if (flag)
+ {
+ while (unwind_protect_list)
+ remove_unwind_protect_internal ((char *)NULL, (char *)NULL);
+ }
+ unwind_protect_list = (UNWIND_ELT *)NULL;
+}
+
+static void
+unwind_frame_discard_internal (tag, ignore)
+ char *tag, *ignore;
+{
+ UNWIND_ELT *elt;
+ int found;
+
+ found = 0;
+ while (elt = unwind_protect_list)
+ {
+ unwind_protect_list = unwind_protect_list->head.next;
+ if (elt->head.cleanup == 0 && (STREQ (elt->arg.v, tag)))
+ {
+ uwpfree (elt);
+ found = 1;
+ break;
+ }
+ else
+ uwpfree (elt);
+ }
+
+ if (found == 0)
+ internal_warning ("unwind_frame_discard: %s: frame not found", tag);
+}
+
+/* Restore the value of a variable, based on the contents of SV.
+ sv->desired_setting is a block of memory SIZE bytes long holding the
+ value itself. This block of memory is copied back into the variable. */
+static inline void
+restore_variable (sv)
+ SAVED_VAR *sv;
+{
+ FASTCOPY (sv->desired_setting, sv->variable, sv->size);
+}
+
+static void
+unwind_frame_run_internal (tag, ignore)
+ char *tag, *ignore;
+{
+ UNWIND_ELT *elt;
+ int found;
+
+ found = 0;
+ while (elt = unwind_protect_list)
+ {
+ unwind_protect_list = elt->head.next;
+
+ /* If tag, then compare. */
+ if (elt->head.cleanup == 0)
+ {
+ if (tag && STREQ (elt->arg.v, tag))
+ {
+ uwpfree (elt);
+ found = 1;
+ break;
+ }
+ }
+ else
+ {
+ if (elt->head.cleanup == (Function *) restore_variable)
+ restore_variable (&elt->sv.v);
+ else
+ (*(elt->head.cleanup)) (elt->arg.v);
+ }
+
+ uwpfree (elt);
+ }
+ if (found == 0)
+ internal_warning ("unwind_frame_run: %s: frame not found", tag);
+}
+
+static void
+unwind_protect_mem_internal (var, psize)
+ char *var;
+ char *psize;
+{
+ int size, allocated;
+ UNWIND_ELT *elt;
+
+ size = *(int *) psize;
+ allocated = size + offsetof (UNWIND_ELT, sv.v.desired_setting[0]);
+ elt = (UNWIND_ELT *)xmalloc (allocated);
+ elt->head.next = unwind_protect_list;
+ elt->head.cleanup = (Function *) restore_variable;
+ elt->sv.v.variable = var;
+ elt->sv.v.size = size;
+ FASTCOPY (var, elt->sv.v.desired_setting, size);
+ unwind_protect_list = elt;
+}
+
+/* Save the value of a variable so it will be restored when unwind-protects
+ are run. VAR is a pointer to the variable. SIZE is the size in
+ bytes of VAR. */
+void
+unwind_protect_mem (var, size)
+ char *var;
+ int size;
+{
+ without_interrupts (unwind_protect_mem_internal, var, (char *) &size);
+}
+
+#if defined (DEBUG)
+void
+print_unwind_protect_tags ()
+{
+ UNWIND_ELT *elt;
+
+ elt = unwind_protect_list;
+ while (elt)
+ {
+ unwind_protect_list = unwind_protect_list->head.next;
+ if (elt->head.cleanup == 0)
+ fprintf(stderr, "tag: %s\n", elt->arg.v);
+ elt = unwind_protect_list;
+ }
+}
+#endif
/* Variables used here and defined in other files. */
extern int posixly_correct;
-extern int line_number;
+extern int line_number, line_number_base;
extern int subshell_environment, indirection_level, subshell_level;
extern int build_version, patch_level;
extern int expanding_redir;
if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0)
new_value = 0;
- line_number = new_value;
+ line_number = line_number_base = new_value;
return var;
}
#endif
{
temp_var = bind_variable (name, string, 0);
- if (legal_identifier (name))
- VSETATTR (temp_var, (att_exported | att_imported));
- else
- VSETATTR (temp_var, (att_exported | att_imported | att_invisible));
- array_needs_making = 1;
+ if (temp_var)
+ {
+ if (legal_identifier (name))
+ VSETATTR (temp_var, (att_exported | att_imported));
+ else
+ VSETATTR (temp_var, (att_exported | att_imported | att_invisible));
+ array_needs_making = 1;
+ }
}
name[char_index] = '=';
#endif
v = bind_variable (lhs, rhs, 0);
- if (isint)
+ if (v && isint)
VSETATTR (v, att_integer);
return (v);
if (!entry) \
{ \
entry = bind_variable (name, "", 0); \
- if (!no_invisible_vars) entry->attributes |= att_invisible; \
+ if (!no_invisible_vars && entry) entry->attributes |= att_invisible; \
} \
} \
while (0)
int fd;
FILE *fp;
-itrace("sv_xtracefd: %s", name);
v = find_variable (name);
if (v == 0)
{