Index: BOOK/introduction/common/changelog.xml
===================================================================
--- BOOK/introduction/common/changelog.xml	(revision a602073e7302a4cb1173e9b5305ed1cd76d21ac3)
+++ BOOK/introduction/common/changelog.xml	(revision e6b4db2ff5cd411b279ff0e60c0bfcef5b528ca8)
@@ -36,4 +36,13 @@
     </listitem>
 -->
+
+    <listitem>
+      <para>April 9, 2009</para>
+      <itemizedlist>
+        <listitem>
+          <para>[Jim] - Updated Bash Branch Update Patch to -4.</para>
+        </listitem>
+      </itemizedlist>
+    </listitem>
 
     <listitem>
Index: BOOK/patches.ent
===================================================================
--- BOOK/patches.ent	(revision a602073e7302a4cb1173e9b5305ed1cd76d21ac3)
+++ BOOK/patches.ent	(revision e6b4db2ff5cd411b279ff0e60c0bfcef5b528ca8)
@@ -5,7 +5,7 @@
 <!-- Start of Common Patches -->
 
-<!ENTITY bash-branch_update-patch "bash-&bash-version;-branch_update-3.patch">
-<!ENTITY bash-branch_update-patch-md5 "1121b5d966599721aaf6dffb03f13d8c">
-<!ENTITY bash-branch_update-patch-size "14 KB">
+<!ENTITY bash-branch_update-patch "bash-&bash-version;-branch_update-4.patch">
+<!ENTITY bash-branch_update-patch-md5 "25ff4f245e33902252f7dc97ae04c119">
+<!ENTITY bash-branch_update-patch-size "24 KB">
 
 <!ENTITY binutils-branch_update-patch "binutils-&binutils-version;-branch_update-1.patch">
Index: tches/bash-4.0-branch_update-3.patch
===================================================================
--- patches/bash-4.0-branch_update-3.patch	(revision a602073e7302a4cb1173e9b5305ed1cd76d21ac3)
+++ 	(revision )
@@ -1,497 +1,0 @@
-Submitted By: Jim Gifford (jim at cross-lfs dot org)
-Date: 03-09-2009
-Initial Package Version: 4.0
-Origin: Upstream
-Upstream Status: Applied
-Description: Contains all upstream patches up to 4.0-010
-
-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-03-09 15:07:05.270012850 -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-03-09 15:07:02.561839362 -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-03-09 15:07:01.245754993 -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/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-03-09 15:07:07.890180751 -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/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-03-09 15:07:09.194264282 -0700
-@@ -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];
- }
- 
- /*
-@@ -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 \<newline> 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 \<newline> 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-03-09 15:07:09.194264282 -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 10
- 
- #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-03-09 15:06:58.589584858 -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/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-03-09 15:07:05.274015365 -0700
-@@ -222,6 +222,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));
- 
-@@ -1374,6 +1375,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
Index: patches/bash-4.0-branch_update-4.patch
===================================================================
--- patches/bash-4.0-branch_update-4.patch	(revision e6b4db2ff5cd411b279ff0e60c0bfcef5b528ca8)
+++ patches/bash-4.0-branch_update-4.patch	(revision e6b4db2ff5cd411b279ff0e60c0bfcef5b528ca8)
@@ -0,0 +1,794 @@
+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 \<newline> 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 \<newline> 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);
Index: scripts/patch/binutils-patch.sh
===================================================================
--- scripts/patch/binutils-patch.sh	(revision a602073e7302a4cb1173e9b5305ed1cd76d21ac3)
+++ scripts/patch/binutils-patch.sh	(revision e6b4db2ff5cd411b279ff0e60c0bfcef5b528ca8)
@@ -28,5 +28,5 @@
 cd /usr/src
 wget http://svn.cross-lfs.org/svn/repos/cross-lfs/trunk/patches/ --no-remove-listing
-PATCH_NUM=$(cat index.html | grep binutils | grep "${VERSION}" | grep branch_update | cut -f2 -d'"' | cut -f1 -d'"'| cut -f4 -d- | cut -f1 -d. | tail -n 1)
+PATCH_NUM=$(cat index.html | grep binutils | grep "${SOURCEVERSION}" | grep branch_update | cut -f2 -d'"' | cut -f1 -d'"'| cut -f4 -d- | cut -f1 -d. | tail -n 1)
 PATCH_NUM=$(expr ${PATCH_NUM} + 1)
 rm -f index.html
