Submitted By: Jim Gifford (jim at cross-lfs dot org) Date: 04-09-2009 Initial Package Version: 4.0 Origin: Upstream Upstream Status: Applied Description: Contains all upstream patches up to 4.0-017 diff -Naur bash-4.0.orig/arrayfunc.c bash-4.0/arrayfunc.c --- bash-4.0.orig/arrayfunc.c 2009-01-04 11:32:21.000000000 -0800 +++ bash-4.0/arrayfunc.c 2009-04-09 22:09:24.500045537 -0700 @@ -604,64 +604,7 @@ } } -/* This function assumes s[i] == '['; returns with s[ret] == ']' if - an array subscript is correctly parsed. */ -int -skipsubscript (s, i) - const char *s; - int i; -{ - int count, c; -#if defined (HANDLE_MULTIBYTE) - mbstate_t state, state_bak; - size_t slength, mblength; -#endif - -#if defined (HANDLE_MULTIBYTE) - memset (&state, '\0', sizeof (mbstate_t)); - slength = strlen (s + i); -#endif - - count = 1; - while (count) - { - /* Advance one (possibly multibyte) character in S starting at I. */ -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1) - { - state_bak = state; - mblength = mbrlen (s + i, slength, &state); - - if (MB_INVALIDCH (mblength)) - { - state = state_bak; - i++; - slength--; - } - else if (MB_NULLWCH (mblength)) - return i; - else - { - i += mblength; - slength -= mblength; - } - } - else -#endif - ++i; - - c = s[i]; - - if (c == 0) - break; - else if (c == '[') - count++; - else if (c == ']') - count--; - } - - return i; -} +/* skipsubscript moved to subst.c to use private functions. 2009/02/24. */ /* This function is called with SUB pointing to just after the beginning `[' of an array subscript and removes the array element to which SUB diff -Naur bash-4.0.orig/builtins/declare.def bash-4.0/builtins/declare.def --- bash-4.0.orig/builtins/declare.def 2009-01-04 11:32:22.000000000 -0800 +++ bash-4.0/builtins/declare.def 2009-04-09 22:09:21.747868696 -0700 @@ -295,6 +295,13 @@ subscript_start = (char *)NULL; if (t = strchr (name, '[')) /* ] */ { + /* If offset != 0 we have already validated any array reference */ + if (offset == 0 && valid_array_reference (name) == 0) + { + sh_invalidid (name); + assign_error++; + NEXT_VARIABLE (); + } subscript_start = t; *t = '\0'; making_array_special = 1; @@ -484,7 +491,7 @@ } /* declare -a name[[n]] or declare name[n] makes name an indexed array variable. */ - else if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0) + else if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0 && assoc_p (var) == 0) var = convert_var_to_array (var); #endif /* ARRAY_VARS */ diff -Naur bash-4.0.orig/builtins/exit.def bash-4.0/builtins/exit.def --- bash-4.0.orig/builtins/exit.def 2009-01-04 11:32:22.000000000 -0800 +++ bash-4.0/builtins/exit.def 2009-04-09 22:09:20.423784047 -0700 @@ -113,7 +113,7 @@ for (i = stopmsg = 0; i < js.j_jobslots; i++) if (jobs[i] && STOPPED (i)) stopmsg = JSTOPPED; - else if (check_jobs_at_exit && stopmsg == 0 && RUNNING (i)) + else if (check_jobs_at_exit && stopmsg == 0 && jobs[i] && RUNNING (i)) stopmsg = JRUNNING; if (stopmsg == JSTOPPED) diff -Naur bash-4.0.orig/builtins/fc.def bash-4.0/builtins/fc.def --- bash-4.0.orig/builtins/fc.def 2009-01-04 11:32:22.000000000 -0800 +++ bash-4.0/builtins/fc.def 2009-04-09 22:09:34.484684732 -0700 @@ -88,6 +88,7 @@ extern int current_command_line_count; extern int literal_history; extern int posixly_correct; +extern int subshell_environment, interactive_shell; extern int unlink __P((const char *)); @@ -172,7 +173,7 @@ register int i; register char *sep; int numbering, reverse, listing, execute; - int histbeg, histend, last_hist, retval, opt; + int histbeg, histend, last_hist, retval, opt, rh; FILE *stream; REPL *rlist, *rl; char *ename, *command, *newcom, *fcedit; @@ -275,6 +276,8 @@ fprintf (stderr, "%s\n", command); fc_replhist (command); /* replace `fc -s' with command */ + /* Posix says that the re-executed commands should be entered into the + history. */ return (parse_and_execute (command, "fc", SEVAL_NOHIST)); } @@ -293,7 +296,12 @@ line was actually added (HISTIGNORE may have caused it to not be), so we check hist_last_line_added. */ - last_hist = i - remember_on_history - hist_last_line_added; + /* Even though command substitution through parse_and_execute turns off + remember_on_history, command substitution in a shell when set -o history + has been enabled (interactive or not) should use it in the last_hist + calculation as if it were on. */ + rh = remember_on_history || ((subshell_environment & SUBSHELL_COMSUB) && enable_history_list); + last_hist = i - rh - hist_last_line_added; if (list) { @@ -456,7 +464,7 @@ char *command; HIST_ENTRY **hlist; { - int sign, n, clen; + int sign, n, clen, rh; register int i, j; register char *s; @@ -472,7 +480,12 @@ line was actually added (HISTIGNORE may have caused it to not be), so we check hist_last_line_added. This needs to agree with the calculation of last_hist in fc_builtin above. */ - i -= remember_on_history + hist_last_line_added; + /* Even though command substitution through parse_and_execute turns off + remember_on_history, command substitution in a shell when set -o history + has been enabled (interactive or not) should use it in the last_hist + calculation as if it were on. */ + rh = remember_on_history || ((subshell_environment & SUBSHELL_COMSUB) && enable_history_list); + i -= rh + hist_last_line_added; /* No specification defaults to most recent command. */ if (command == NULL) diff -Naur bash-4.0.orig/builtins/read.def bash-4.0/builtins/read.def --- bash-4.0.orig/builtins/read.def 2009-01-15 20:11:21.000000000 -0800 +++ bash-4.0/builtins/read.def 2009-04-09 22:09:27.380229641 -0700 @@ -369,14 +369,14 @@ code = setjmp (alrmbuf); if (code) { -#if 0 + /* Tricky. The top of the unwind-protect stack is the free of + input_string. We want to run all the rest and use input_string, + so we have to remove it from the stack. */ + remove_unwind_protect (); run_unwind_frame ("read_builtin"); - return (EXECUTION_FAILURE); -#else input_string[i] = '\0'; /* make sure it's terminated */ - retval = 128+SIGALRM;; + retval = 128+SIGALRM; goto assign_vars; -#endif } old_alrm = set_signal_handler (SIGALRM, sigalrm); add_unwind_protect (reset_alarm, (char *)NULL); diff -Naur bash-4.0.orig/execute_cmd.c bash-4.0/execute_cmd.c --- bash-4.0.orig/execute_cmd.c 2009-02-13 13:41:41.000000000 -0800 +++ bash-4.0/execute_cmd.c 2009-04-09 22:09:37.908905992 -0700 @@ -568,6 +568,7 @@ /* Fork a subshell, turn off the subshell bit, turn off job control and call execute_command () on the command again. */ + line_number_for_err_trap = line_number; paren_pid = make_child (savestring (make_command_string (command)), asynchronous); if (paren_pid == 0) @@ -610,7 +611,10 @@ if (user_subshell && was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS) { last_command_exit_value = exec_result; + save_line_number = line_number; + line_number = line_number_for_err_trap; run_error_trap (); + line_number = save_line_number; } if (user_subshell && ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS) @@ -766,7 +770,9 @@ if (was_error_trap && ignore_return == 0 && invert == 0 && pipe_in == NO_PIPE && pipe_out == NO_PIPE && exec_result != EXECUTION_SUCCESS) { last_command_exit_value = exec_result; + line_number = line_number_for_err_trap; run_error_trap (); + line_number = save_line_number; } if (ignore_return == 0 && invert == 0 && @@ -2105,6 +2111,7 @@ REDIRECT *rp; COMMAND *tc, *second; int ignore_return, exec_result, was_error_trap, invert; + volatile int save_line_number; ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; @@ -2174,12 +2181,16 @@ invert = (command->flags & CMD_INVERT_RETURN) != 0; ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; + line_number_for_err_trap = line_number; exec_result = execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close); if (was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS) { last_command_exit_value = exec_result; + save_line_number = line_number; + line_number = line_number_for_err_trap; run_error_trap (); + line_number = save_line_number; } if (ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS) @@ -2930,7 +2941,7 @@ retval = execute_command (clauses->action); } while ((clauses->flags & CASEPAT_FALLTHROUGH) && (clauses = clauses->next)); - if ((clauses->flags & CASEPAT_TESTNEXT) == 0) + if (clauses == 0 || (clauses->flags & CASEPAT_TESTNEXT) == 0) EXIT_CASE (); else break; diff -Naur bash-4.0.orig/parse.y bash-4.0/parse.y --- bash-4.0.orig/parse.y 2009-01-08 05:29:12.000000000 -0800 +++ bash-4.0/parse.y 2009-04-09 22:09:39.212989803 -0700 @@ -1122,7 +1122,7 @@ REDIRECTEE rd; REDIRECT *r; - tc = $1; + tc = $1->type == cm_simple ? (COMMAND *)$1->value.Simple : $1; rd.dest = 1; r = make_redirection (2, r_duplicating_output, rd); if (tc->redirects) @@ -1615,10 +1615,11 @@ { int *ret; - ret = (int *)xmalloc (3 * sizeof (int)); + ret = (int *)xmalloc (4 * sizeof (int)); ret[0] = last_read_token; ret[1] = token_before_that; ret[2] = two_tokens_ago; + ret[3] = current_token; return ret; } @@ -1631,6 +1632,7 @@ last_read_token = ts[0]; token_before_that = ts[1]; two_tokens_ago = ts[2]; + current_token = ts[3]; } /* @@ -1877,7 +1879,7 @@ prompt_again (); ret = read_a_line (remove_quoted_newline); #if defined (HISTORY) - if (remember_on_history && (parser_state & PST_HEREDOC)) + if (ret && remember_on_history && (parser_state & PST_HEREDOC)) { /* To make adding the the here-document body right, we need to rely on history_delimiting_chars() returning \n for the first line of @@ -2668,6 +2670,7 @@ FREE (word_desc_to_read); word_desc_to_read = (WORD_DESC *)NULL; + current_token = '\n'; /* XXX */ last_read_token = '\n'; token_to_read = '\n'; } @@ -2915,6 +2918,7 @@ #define P_DQUOTE 0x04 #define P_COMMAND 0x08 /* parsing a command, so look for comments */ #define P_BACKQUOTE 0x10 /* parsing a backquoted command substitution */ +#define P_ARRAYSUB 0x20 /* parsing a [...] array subscript for assignment */ /* Lexical state while parsing a grouping construct or $(...). */ #define LEX_WASDOL 0x001 @@ -2927,6 +2931,7 @@ #define LEX_INHEREDOC 0x080 #define LEX_HEREDELIM 0x100 /* reading here-doc delimiter */ #define LEX_STRIPDOC 0x200 /* <<- strip tabs from here doc delim */ +#define LEX_INWORD 0x400 #define COMSUB_META(ch) ((ch) == ';' || (ch) == '&' || (ch) == '|') @@ -3129,6 +3134,8 @@ APPEND_NESTRET (); FREE (nestret); } + else if ((flags & P_ARRAYSUB) && (tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */ + goto parse_dollar_word; } /* Parse an old-style command substitution within double quotes as a single word. */ @@ -3145,6 +3152,7 @@ else if MBTEST(open != '`' && (tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */ /* check for $(), $[], or ${} inside quoted string. */ { +parse_dollar_word: if (open == ch) /* undo previous increment */ count--; if (ch == '(') /* ) */ @@ -3179,7 +3187,7 @@ int open, close; int *lenp, flags; { - int count, ch, peekc, tflags, lex_rwlen, lex_firstind; + int count, ch, peekc, tflags, lex_rwlen, lex_wlen, lex_firstind; int nestlen, ttranslen, start_lineno; char *ret, *nestret, *ttrans, *heredelim; int retind, retsize, rflags, hdlen; @@ -3200,7 +3208,7 @@ retind = 0; start_lineno = line_number; - lex_rwlen = 0; + lex_rwlen = lex_wlen = 0; heredelim = 0; lex_firstind = -1; @@ -3267,6 +3275,46 @@ continue; } + if (tflags & LEX_PASSNEXT) /* last char was backslash */ + { +/*itrace("parse_comsub:%d: lex_passnext -> 0 ch = `%c' (%d)", line_number, ch, __LINE__);*/ + tflags &= ~LEX_PASSNEXT; + if (qc != '\'' && ch == '\n') /* double-quoted \ disappears. */ + { + if (retind > 0) + retind--; /* swallow previously-added backslash */ + continue; + } + + RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); + if MBTEST(ch == CTLESC || ch == CTLNUL) + ret[retind++] = CTLESC; + ret[retind++] = ch; + continue; + } + + /* If this is a shell break character, we are not in a word. If not, + we either start or continue a word. */ + if MBTEST(shellbreak (ch)) + { + tflags &= ~LEX_INWORD; +/*itrace("parse_comsub:%d: lex_inword -> 0 ch = `%c' (%d)", line_number, ch, __LINE__);*/ + } + else + { + if (tflags & LEX_INWORD) + { + lex_wlen++; +/*itrace("parse_comsub:%d: lex_inword == 1 ch = `%c' lex_wlen = %d (%d)", line_number, ch, lex_wlen, __LINE__);*/ + } + else + { +/*itrace("parse_comsub:%d: lex_inword -> 1 ch = `%c' (%d)", line_number, ch, __LINE__);*/ + tflags |= LEX_INWORD; + lex_wlen = 0; + } + } + /* Skip whitespace */ if MBTEST(shellblank (ch) && lex_rwlen == 0) { @@ -3364,9 +3412,21 @@ } tflags &= ~LEX_RESWDOK; } - else if (shellbreak (ch) == 0) + else if MBTEST((tflags & LEX_CKCOMMENT) && ch == '#' && (lex_rwlen == 0 || ((tflags & LEX_INWORD) && lex_wlen == 0))) + ; /* don't modify LEX_RESWDOK if we're starting a comment */ + else if MBTEST((tflags & LEX_INCASE) && ch != '\n') + /* If we can read a reserved word and we're in case, we're at the + point where we can read a new pattern list or an esac. We + handle the esac case above. If we read a newline, we want to + leave LEX_RESWDOK alone. If we read anything else, we want to + turn off LEX_RESWDOK, since we're going to read a pattern list. */ { - tflags &= ~LEX_RESWDOK; + tflags &= ~LEX_RESWDOK; +/*itrace("parse_comsub:%d: lex_incase == 1 found `%c', lex_reswordok -> 0", line_number, ch);*/ +} + else if MBTEST(shellbreak (ch) == 0) +{ + tflags &= ~LEX_RESWDOK; /*itrace("parse_comsub:%d: found `%c', lex_reswordok -> 0", line_number, ch);*/ } } @@ -3394,36 +3454,23 @@ } else shell_ungetc (peekc); - tflags |= LEX_HEREDELIM; - lex_firstind = -1; + if (peekc != '<') + { + tflags |= LEX_HEREDELIM; + lex_firstind = -1; + } continue; } else - ch = peekc; /* fall through and continue XXX - this skips comments if peekc == '#' */ + ch = peekc; /* fall through and continue XXX */ } - /* 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' || shellblank (ret[retind - 1]))) + else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (((tflags & LEX_RESWDOK) && lex_rwlen == 0) || ((tflags & LEX_INWORD) && lex_wlen == 0))) +{ +/*itrace("parse_comsub:%d: lex_incomment -> 1 (%d)", line_number, __LINE__);*/ tflags |= LEX_INCOMMENT; +} - if (tflags & LEX_PASSNEXT) /* last char was backslash */ - { - tflags &= ~LEX_PASSNEXT; - if (qc != '\'' && ch == '\n') /* double-quoted \ disappears. */ - { - if (retind > 0) - retind--; /* swallow previously-added backslash */ - continue; - } - - RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); - if MBTEST(ch == CTLESC || ch == CTLNUL) - ret[retind++] = CTLESC; - ret[retind++] = ch; - continue; - } - else if MBTEST(ch == CTLESC || ch == CTLNUL) /* special shell escapes */ + if MBTEST(ch == CTLESC || ch == CTLNUL) /* special shell escapes */ { RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); ret[retind++] = CTLESC; @@ -4248,7 +4295,7 @@ ((token_index > 0 && assignment_acceptable (last_read_token) && token_is_ident (token, token_index)) || (token_index == 0 && (parser_state&PST_COMPASSIGN)))) { - ttok = parse_matched_pair (cd, '[', ']', &ttoklen, 0); + ttok = parse_matched_pair (cd, '[', ']', &ttoklen, P_ARRAYSUB); if (ttok == &matched_pair_error) return -1; /* Bail immediately. */ RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, @@ -4449,6 +4496,7 @@ case '}': /* XXX */ case AND_AND: case BANG: + case BAR_AND: case DO: case DONE: case ELIF: diff -Naur bash-4.0.orig/patchlevel.h bash-4.0/patchlevel.h --- bash-4.0.orig/patchlevel.h 2009-01-04 11:32:40.000000000 -0800 +++ bash-4.0/patchlevel.h 2009-04-09 22:09:39.212989803 -0700 @@ -25,6 +25,6 @@ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh looks for to find the patch level (for the sccs version string). */ -#define PATCHLEVEL 0 +#define PATCHLEVEL 17 #endif /* _PATCHLEVEL_H_ */ diff -Naur bash-4.0.orig/pcomplete.c bash-4.0/pcomplete.c --- bash-4.0.orig/pcomplete.c 2009-02-01 14:12:31.000000000 -0800 +++ bash-4.0/pcomplete.c 2009-04-09 22:09:17.783614750 -0700 @@ -1032,6 +1032,7 @@ cmdlist = build_arg_list (funcname, text, lwords, cw); pps = &ps; + save_parser_state (pps); begin_unwind_frame ("gen-shell-function-matches"); add_unwind_protect (restore_parser_state, (char *)pps); add_unwind_protect (dispose_words, (char *)cmdlist); diff -Naur bash-4.0.orig/sig.c bash-4.0/sig.c --- bash-4.0.orig/sig.c 2009-01-04 11:32:41.000000000 -0800 +++ bash-4.0/sig.c 2009-04-09 22:09:36.612821343 -0700 @@ -448,6 +448,48 @@ termsig_sighandler (sig) int sig; { + /* If we get called twice with the same signal before handling it, + terminate right away. */ + if ( +#ifdef SIGHUP + sig != SIGHUP && +#endif +#ifdef SIGINT + sig != SIGINT && +#endif +#ifdef SIGDANGER + sig != SIGDANGER && +#endif +#ifdef SIGPIPE + sig != SIGPIPE && +#endif +#ifdef SIGALRM + sig != SIGALRM && +#endif +#ifdef SIGTERM + sig != SIGTERM && +#endif +#ifdef SIGXCPU + sig != SIGXCPU && +#endif +#ifdef SIGXFSZ + sig != SIGXFSZ && +#endif +#ifdef SIGVTALRM + sig != SIGVTALRM && +#endif +#ifdef SIGLOST + sig != SIGLOST && +#endif +#ifdef SIGUSR1 + sig != SIGUSR1 && +#endif +#ifdef SIGUSR2 + sig != SIGUSR2 && +#endif + sig == terminating_signal) + terminate_immediately = 1; + terminating_signal = sig; /* XXX - should this also trigger when interrupt_immediately is set? */ diff -Naur bash-4.0.orig/subst.c bash-4.0/subst.c --- bash-4.0.orig/subst.c 2009-01-28 11:34:12.000000000 -0800 +++ bash-4.0/subst.c 2009-04-09 22:09:33.024593378 -0700 @@ -85,6 +85,7 @@ /* Flags for the `pflags' argument to param_expand() */ #define PF_NOCOMSUB 0x01 /* Do not perform command substitution */ +#define PF_IGNUNBOUND 0x02 /* ignore unbound vars even if -u set */ /* These defs make it easier to use the editor. */ #define LBRACE '{' @@ -222,6 +223,7 @@ static int skip_double_quoted __P((char *, size_t, int)); static char *extract_delimited_string __P((char *, int *, char *, char *, char *, int)); static char *extract_dollar_brace_string __P((char *, int *, int, int)); +static int skip_matched_pair __P((const char *, int, int, int, int)); static char *pos_params __P((char *, int, int, int)); @@ -262,7 +264,7 @@ static int chk_atstar __P((char *, int, int *, int *)); static int chk_arithsub __P((const char *, int)); -static WORD_DESC *parameter_brace_expand_word __P((char *, int, int)); +static WORD_DESC *parameter_brace_expand_word __P((char *, int, int, int)); static WORD_DESC *parameter_brace_expand_indir __P((char *, int, int, int *, int *)); static WORD_DESC *parameter_brace_expand_rhs __P((char *, char *, int, int, int *, int *)); static void parameter_brace_expand_error __P((char *, char *)); @@ -1374,6 +1376,107 @@ #define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0) +/* This function assumes s[i] == open; returns with s[ret] == close; used to + parse array subscripts. FLAGS currently unused. */ +static int +skip_matched_pair (string, start, open, close, flags) + const char *string; + int start, open, close, flags; +{ + int i, pass_next, backq, si, c, count; + size_t slen; + char *temp, *ss; + DECLARE_MBSTATE; + + slen = strlen (string + start) + start; + no_longjmp_on_fatal_error = 1; + + i = start + 1; /* skip over leading bracket */ + count = 1; + pass_next = backq = 0; + ss = (char *)string; + 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 == open) + { + count++; + i++; + continue; + } + else if (c == close) + { + count--; + if (count == 0) + break; + i++; + continue; + } + else if (c == '\'' || c == '"') + { + i = (c == '\'') ? skip_single_quoted (ss, slen, ++i) + : skip_double_quoted (ss, 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 (ss, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */ + else + temp = extract_dollar_brace_string (ss, &si, 0, SX_NOALLOC); + i = si; + if (string[i] == '\0') /* don't increment i past EOS in loop */ + break; + i++; + continue; + } + else + ADVANCE_CHAR (string, slen, i); + } + + CQ_RETURN(i); +} + +#if defined (ARRAY_VARS) +int +skipsubscript (string, start) + const char *string; + int start; +{ + return (skip_matched_pair (string, start, '[', ']', 0)); +} +#endif + /* 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 @@ -5093,9 +5196,9 @@ the shell, e.g., "@", "$", "*", etc. QUOTED, if non-zero, means that NAME was found inside of a double-quoted expression. */ static WORD_DESC * -parameter_brace_expand_word (name, var_is_special, quoted) +parameter_brace_expand_word (name, var_is_special, quoted, pflags) char *name; - int var_is_special, quoted; + int var_is_special, quoted, pflags; { WORD_DESC *ret; char *temp, *tt; @@ -5127,7 +5230,7 @@ strcpy (tt + 1, name); ret = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL, - (int *)NULL, (int *)NULL, 0); + (int *)NULL, (int *)NULL, pflags); free (tt); } #if defined (ARRAY_VARS) @@ -5188,7 +5291,7 @@ char *temp, *t; WORD_DESC *w; - w = parameter_brace_expand_word (name, var_is_special, quoted); + w = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND); t = w->word; /* Have to dequote here if necessary */ if (t) @@ -5205,7 +5308,7 @@ if (t == 0) return (WORD_DESC *)NULL; - w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted); + w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, 0); free (t); return w; @@ -6556,7 +6659,7 @@ if (want_indir) tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at); else - tdesc = parameter_brace_expand_word (name, var_is_special, quoted); + tdesc = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND); if (tdesc) { @@ -6887,7 +6990,7 @@ case '*': /* `$*' */ list = list_rest_of_args (); - if (list == 0 && unbound_vars_is_error) + if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0) { uerror[0] = '$'; uerror[1] = '*'; @@ -6949,7 +7052,7 @@ case '@': /* `$@' */ list = list_rest_of_args (); - if (list == 0 && unbound_vars_is_error) + if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0) { uerror[0] = '$'; uerror[1] = '@'; diff -Naur bash-4.0.orig/trap.c bash-4.0/trap.c --- bash-4.0.orig/trap.c 2009-01-16 14:07:53.000000000 -0800 +++ bash-4.0/trap.c 2009-04-09 22:09:37.908905992 -0700 @@ -755,7 +755,7 @@ } flags = SEVAL_NONINT|SEVAL_NOHIST; - if (sig != DEBUG_TRAP && sig != RETURN_TRAP) + if (sig != DEBUG_TRAP && sig != RETURN_TRAP && sig != ERROR_TRAP) flags |= SEVAL_RESETLINE; if (function_code == 0) parse_and_execute (trap_command, tag, flags);