--- /dev/null
+diff -Naur bash-3.0.orig/array.c bash-3.0/array.c
+--- bash-3.0.orig/array.c 2004-05-06 12:24:13.000000000 +0000
++++ bash-3.0/array.c 2005-01-08 05:40:02.059798512 +0000
+@@ -451,7 +451,7 @@
+ */
+ array_dispose_element(new);
+ free(element_value(ae));
+- ae->value = savestring(v);
++ ae->value = v ? savestring(v) : (char *)NULL;
+ return(0);
+ } else if (element_index(ae) > i) {
+ ADD_BEFORE(ae, new);
+diff -Naur bash-3.0.orig/arrayfunc.c bash-3.0/arrayfunc.c
+--- bash-3.0.orig/arrayfunc.c 2003-12-19 05:03:09.000000000 +0000
++++ bash-3.0/arrayfunc.c 2005-01-08 05:40:01.679856272 +0000
+@@ -611,7 +611,7 @@
+ var = find_variable (t);
+
+ free (t);
+- return var;
++ return (var == 0 || invisible_p (var)) ? (SHELL_VAR *)0 : var;
+ }
+
+ /* Return a string containing the elements in the array and subscript
+diff -Naur bash-3.0.orig/bashline.c bash-3.0/bashline.c
+--- bash-3.0.orig/bashline.c 2004-07-06 03:22:12.000000000 +0000
++++ bash-3.0/bashline.c 2005-01-08 05:40:42.016724136 +0000
+@@ -100,6 +100,7 @@
+ #endif
+
+ /* Helper functions for Readline. */
++static int bash_directory_expansion __P((char **));
+ static int bash_directory_completion_hook __P((char **));
+ static int filename_completion_ignore __P((char **));
+ static int bash_push_line __P((void));
+@@ -292,7 +293,7 @@
+ /* See if we have anything to do. */
+ at = strchr (rl_completer_word_break_characters, '@');
+ if ((at == 0 && on_or_off == 0) || (at != 0 && on_or_off != 0))
+- return;
++ return old_value;
+
+ /* We have something to do. Do it. */
+ nval = (char *)xmalloc (strlen (rl_completer_word_break_characters) + 1 + on_or_off);
+@@ -1406,10 +1407,19 @@
+ filename. */
+ if (*hint_text == '~')
+ {
+- int l, tl, vl;
++ int l, tl, vl, dl;
++ char *rd;
+ vl = strlen (val);
+ tl = strlen (hint_text);
++#if 0
+ l = vl - hint_len; /* # of chars added */
++#else
++ rd = savestring (filename_hint);
++ bash_directory_expansion (&rd);
++ dl = strlen (rd);
++ l = vl - dl; /* # of chars added */
++ free (rd);
++#endif
+ temp = (char *)xmalloc (l + 2 + tl);
+ strcpy (temp, hint_text);
+ strcpy (temp + tl, val + vl - l);
+@@ -2187,6 +2197,27 @@
+ return 0;
+ }
+
++/* Simulate the expansions that will be performed by
++ rl_filename_completion_function. This must be called with the address of
++ a pointer to malloc'd memory. */
++static int
++bash_directory_expansion (dirname)
++ char **dirname;
++{
++ char *d;
++
++ d = savestring (*dirname);
++
++ if (rl_directory_rewrite_hook)
++ (*rl_directory_rewrite_hook) (&d);
++
++ if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&d))
++ {
++ free (*dirname);
++ *dirname = d;
++ }
++}
++
+ /* Handle symbolic link references and other directory name
+ expansions while hacking completion. */
+ static int
+@@ -2513,7 +2544,7 @@
+ static char **matches = (char **)NULL;
+ static int ind;
+ int glen;
+- char *ret;
++ char *ret, *ttext;
+
+ if (state == 0)
+ {
+@@ -2523,17 +2554,22 @@
+ FREE (globorig);
+ FREE (globtext);
+
++ ttext = bash_tilde_expand (text, 0);
++
+ if (rl_explicit_arg)
+ {
+- globorig = savestring (text);
+- glen = strlen (text);
++ globorig = savestring (ttext);
++ glen = strlen (ttext);
+ globtext = (char *)xmalloc (glen + 2);
+- strcpy (globtext, text);
++ strcpy (globtext, ttext);
+ globtext[glen] = '*';
+ globtext[glen+1] = '\0';
+ }
+ else
+- globtext = globorig = savestring (text);
++ globtext = globorig = savestring (ttext);
++
++ if (ttext != text)
++ free (ttext);
+
+ matches = shell_glob_filename (globtext);
+ if (GLOB_FAILED (matches))
+diff -Naur bash-3.0.orig/braces.c bash-3.0/braces.c
+--- bash-3.0.orig/braces.c 2003-12-04 16:09:52.000000000 +0000
++++ bash-3.0/braces.c 2005-01-08 05:40:50.317462232 +0000
+@@ -340,8 +340,8 @@
+
+ if (lhs_t == ST_CHAR)
+ {
+- lhs_v = lhs[0];
+- rhs_v = rhs[0];
++ lhs_v = (unsigned char)lhs[0];
++ rhs_v = (unsigned char)rhs[0];
+ }
+ else
+ {
+@@ -402,6 +402,8 @@
+ {
+ pass_next = 1;
+ i++;
++ if (quoted == 0)
++ level++;
+ continue;
+ }
+ #endif
+diff -Naur bash-3.0.orig/builtins/trap.def bash-3.0/builtins/trap.def
+--- bash-3.0.orig/builtins/trap.def 2004-05-28 02:26:19.000000000 +0000
++++ bash-3.0/builtins/trap.def 2005-01-08 05:40:04.443436144 +0000
+@@ -23,7 +23,7 @@
+
+ $BUILTIN trap
+ $FUNCTION trap_builtin
+-$SHORT_DOC trap [-lp] [[arg] signal_spec ...]
++$SHORT_DOC trap [-lp] [arg signal_spec ...]
+ The command ARG is to be read and executed when the shell receives
+ signal(s) SIGNAL_SPEC. If ARG is absent (and a single SIGNAL_SPEC
+ is supplied) or `-', each specified signal is reset to its original
+@@ -87,7 +87,7 @@
+ trap_builtin (list)
+ WORD_LIST *list;
+ {
+- int list_signal_names, display, result, opt;
++ int list_signal_names, display, result, opt, first_signal;
+
+ list_signal_names = display = 0;
+ result = EXECUTION_SUCCESS;
+@@ -118,14 +118,19 @@
+ else
+ {
+ char *first_arg;
+- int operation, sig;
++ int operation, sig, first_signal;
+
+ operation = SET;
+ first_arg = list->word->word;
++ first_signal = first_arg && *first_arg && all_digits (first_arg) && signal_object_p (first_arg, opt);
++
++ /* Backwards compatibility */
++ if (first_signal)
++ operation = REVERT;
+ /* When in posix mode, the historical behavior of looking for a
+ missing first argument is disabled. To revert to the original
+ signal handling disposition, use `-' as the first argument. */
+- if (posixly_correct == 0 && first_arg && *first_arg &&
++ else if (posixly_correct == 0 && first_arg && *first_arg &&
+ (*first_arg != '-' || first_arg[1]) &&
+ signal_object_p (first_arg, opt) && list->next == 0)
+ operation = REVERT;
+diff -Naur bash-3.0.orig/doc/bashref.texi bash-3.0/doc/bashref.texi
+--- bash-3.0.orig/doc/bashref.texi 2004-06-26 18:26:07.000000000 +0000
++++ bash-3.0/doc/bashref.texi 2005-01-08 05:40:04.494428392 +0000
+@@ -5953,7 +5953,8 @@
+ @item
+ The @code{trap} builtin doesn't check the first argument for a possible
+ signal specification and revert the signal handling to the original
+-disposition if it is. If users want to reset the handler for a given
++disposition if it is, unless that argument consists solely of digits and
++is a valid signal number. If users want to reset the handler for a given
+ signal to the original disposition, they should use @samp{-} as the
+ first argument.
+
+diff -Naur bash-3.0.orig/general.c bash-3.0/general.c
+--- bash-3.0.orig/general.c 2004-04-15 03:20:13.000000000 +0000
++++ bash-3.0/general.c 2005-01-08 05:40:51.913219640 +0000
+@@ -267,7 +267,7 @@
+ c = string[indx = 0];
+
+ #if defined (ARRAY_VARS)
+- if ((legal_variable_starter (c) == 0) && (flags && c != '[')) /* ] */
++ if ((legal_variable_starter (c) == 0) && (flags == 0 || c != '[')) /* ] */
+ #else
+ if (legal_variable_starter (c) == 0)
+ #endif
+diff -Naur bash-3.0.orig/include/shmbutil.h bash-3.0/include/shmbutil.h
+--- bash-3.0.orig/include/shmbutil.h 2004-04-19 13:59:42.000000000 +0000
++++ bash-3.0/include/shmbutil.h 2005-01-08 05:40:05.724241432 +0000
+@@ -31,6 +31,8 @@
+ extern size_t xmbsrtowcs __P((wchar_t *, const char **, size_t, mbstate_t *));
+ extern size_t xdupmbstowcs __P((wchar_t **, char ***, const char *));
+
++extern size_t mbstrlen __P((const char *));
++
+ extern char *xstrchr __P((const char *, int));
+
+ #ifndef MB_INVALIDCH
+@@ -38,6 +40,9 @@
+ #define MB_NULLWCH(x) ((x) == 0)
+ #endif
+
++#define MBSLEN(s) (((s) && (s)[0]) ? ((s)[1] ? mbstrlen (s) : 1) : 0)
++#define MB_STRLEN(s) ((MB_CUR_MAX > 1) ? MBSLEN (s) : STRLEN (s))
++
+ #else /* !HANDLE_MULTIBYTE */
+
+ #undef MB_LEN_MAX
+@@ -54,6 +59,8 @@
+ #define MB_NULLWCH(x) (0)
+ #endif
+
++#define MB_STRLEN(s) (STRLEN(s))
++
+ #endif /* !HANDLE_MULTIBYTE */
+
+ /* Declare and initialize a multibyte state. Call must be terminated
+diff -Naur bash-3.0.orig/jobs.c bash-3.0/jobs.c
+--- bash-3.0.orig/jobs.c 2004-04-23 20:28:25.000000000 +0000
++++ bash-3.0/jobs.c 2005-01-08 05:40:40.567944384 +0000
+@@ -1778,8 +1778,13 @@
+ if (pipefail_opt)
+ {
+ fail = 0;
+- for (p = jobs[job]->pipe; p->next != jobs[job]->pipe; p = p->next)
+- if (p->status != EXECUTION_SUCCESS) fail = p->status;
++ p = jobs[job]->pipe;
++ do
++ {
++ if (p->status != EXECUTION_SUCCESS) fail = p->status;
++ p = p->next;
++ }
++ while (p != jobs[job]->pipe);
+ return fail;
+ }
+
+diff -Naur bash-3.0.orig/lib/readline/display.c bash-3.0/lib/readline/display.c
+--- bash-3.0.orig/lib/readline/display.c 2004-05-28 02:57:51.000000000 +0000
++++ bash-3.0/lib/readline/display.c 2005-01-08 05:40:08.574808080 +0000
+@@ -201,7 +201,7 @@
+ int *lp, *lip, *niflp, *vlp;
+ {
+ char *r, *ret, *p;
+- int l, rl, last, ignoring, ninvis, invfl, ind, pind, physchars;
++ int l, rl, last, ignoring, ninvis, invfl, invflset, ind, pind, physchars;
+
+ /* Short-circuit if we can. */
+ if ((MB_CUR_MAX <= 1 || rl_byte_oriented) && strchr (pmt, RL_PROMPT_START_IGNORE) == 0)
+@@ -222,6 +222,7 @@
+ r = ret = (char *)xmalloc (l + 1);
+
+ invfl = 0; /* invisible chars in first line of prompt */
++ invflset = 0; /* we only want to set invfl once */
+
+ for (rl = ignoring = last = ninvis = physchars = 0, p = pmt; p && *p; p++)
+ {
+@@ -249,7 +250,10 @@
+ while (l--)
+ *r++ = *p++;
+ if (!ignoring)
+- rl += ind - pind;
++ {
++ rl += ind - pind;
++ physchars += _rl_col_width (pmt, pind, ind);
++ }
+ else
+ ninvis += ind - pind;
+ p--; /* compensate for later increment */
+@@ -259,16 +263,19 @@
+ {
+ *r++ = *p;
+ if (!ignoring)
+- rl++; /* visible length byte counter */
++ {
++ rl++; /* visible length byte counter */
++ physchars++;
++ }
+ else
+ ninvis++; /* invisible chars byte counter */
+ }
+
+- if (rl >= _rl_screenwidth)
+- invfl = ninvis;
+-
+- if (ignoring == 0)
+- physchars++;
++ if (invflset == 0 && rl >= _rl_screenwidth)
++ {
++ invfl = ninvis;
++ invflset = 1;
++ }
+ }
+ }
+
+@@ -351,14 +358,14 @@
+ local_prompt = expand_prompt (p, &prompt_visible_length,
+ &prompt_last_invisible,
+ (int *)NULL,
+- (int *)NULL);
++ &prompt_physical_chars);
+ c = *t; *t = '\0';
+ /* The portion of the prompt string up to and including the
+ final newline is now null-terminated. */
+ local_prompt_prefix = expand_prompt (prompt, &prompt_prefix_length,
+ (int *)NULL,
+ &prompt_invis_chars_first_line,
+- &prompt_physical_chars);
++ (int *)NULL);
+ *t = c;
+ return (prompt_prefix_length);
+ }
+@@ -417,7 +424,7 @@
+ register int in, out, c, linenum, cursor_linenum;
+ register char *line;
+ int c_pos, inv_botlin, lb_botlin, lb_linenum;
+- int newlines, lpos, temp, modmark;
++ int newlines, lpos, temp, modmark, n0, num;
+ char *prompt_this_line;
+ #if defined (HANDLE_MULTIBYTE)
+ wchar_t wc;
+@@ -573,6 +580,7 @@
+
+ #if defined (HANDLE_MULTIBYTE)
+ memset (_rl_wrapped_line, 0, vis_lbsize);
++ num = 0;
+ #endif
+
+ /* prompt_invis_chars_first_line is the number of invisible characters in
+@@ -591,13 +599,32 @@
+ probably too much work for the benefit gained. How many people have
+ prompts that exceed two physical lines?
+ Additional logic fix from Edward Catmur <ed@catmur.co.uk> */
++#if defined (HANDLE_MULTIBYTE)
++ n0 = num;
++ temp = local_prompt ? strlen (local_prompt) : 0;
++ while (num < temp)
++ {
++ if (_rl_col_width (local_prompt, n0, num) > _rl_screenwidth)
++ {
++ num = _rl_find_prev_mbchar (local_prompt, num, MB_FIND_ANY);
++ break;
++ }
++ num++;
++ }
++ temp = num +
++#else
+ temp = ((newlines + 1) * _rl_screenwidth) +
++#endif /* !HANDLE_MULTIBYTE */
+ ((local_prompt_prefix == 0) ? ((newlines == 0) ? prompt_invis_chars_first_line
+ : ((newlines == 1) ? wrap_offset : 0))
+ : ((newlines == 0) ? wrap_offset :0));
+
+ inv_lbreaks[++newlines] = temp;
++#if defined (HANDLE_MULTIBYTE)
++ lpos -= _rl_col_width (local_prompt, n0, num);
++#else
+ lpos -= _rl_screenwidth;
++#endif
+ }
+
+ prompt_last_screen_line = newlines;
+diff -Naur bash-3.0.orig/lib/readline/mbutil.c bash-3.0/lib/readline/mbutil.c
+--- bash-3.0.orig/lib/readline/mbutil.c 2004-01-14 14:44:52.000000000 +0000
++++ bash-3.0/lib/readline/mbutil.c 2005-01-08 05:40:39.252144416 +0000
+@@ -126,11 +126,11 @@
+ if (find_non_zero)
+ {
+ tmp = mbrtowc (&wc, string + point, strlen (string + point), &ps);
+- while (wcwidth (wc) == 0)
++ while (tmp > 0 && wcwidth (wc) == 0)
+ {
+ point += tmp;
+ tmp = mbrtowc (&wc, string + point, strlen (string + point), &ps);
+- if (tmp == (size_t)(0) || tmp == (size_t)(-1) || tmp == (size_t)(-2))
++ if (MB_NULLWCH (tmp) || MB_INVALIDCH (tmp))
+ break;
+ }
+ }
+diff -Naur bash-3.0.orig/lib/readline/misc.c bash-3.0/lib/readline/misc.c
+--- bash-3.0.orig/lib/readline/misc.c 2004-07-07 12:56:32.000000000 +0000
++++ bash-3.0/lib/readline/misc.c 2005-01-08 05:40:07.040041400 +0000
+@@ -276,12 +276,6 @@
+ _rl_saved_line_for_history->line = savestring (rl_line_buffer);
+ _rl_saved_line_for_history->data = (char *)rl_undo_list;
+ }
+- else if (STREQ (rl_line_buffer, _rl_saved_line_for_history->line) == 0)
+- {
+- free (_rl_saved_line_for_history->line);
+- _rl_saved_line_for_history->line = savestring (rl_line_buffer);
+- _rl_saved_line_for_history->data = (char *)rl_undo_list; /* XXX possible memleak */
+- }
+
+ return 0;
+ }
+diff -Naur bash-3.0.orig/lib/readline/vi_mode.c bash-3.0/lib/readline/vi_mode.c
+--- bash-3.0.orig/lib/readline/vi_mode.c 2004-07-13 18:08:27.000000000 +0000
++++ bash-3.0/lib/readline/vi_mode.c 2005-01-08 05:40:25.349257976 +0000
+@@ -272,10 +272,12 @@
+ switch (key)
+ {
+ case '?':
++ _rl_free_saved_history_line ();
+ rl_noninc_forward_search (count, key);
+ break;
+
+ case '/':
++ _rl_free_saved_history_line ();
+ rl_noninc_reverse_search (count, key);
+ break;
+
+@@ -690,7 +692,7 @@
+ {
+ wchar_t wc;
+ char mb[MB_LEN_MAX+1];
+- int mblen;
++ int mblen, p;
+ mbstate_t ps;
+
+ memset (&ps, 0, sizeof (mbstate_t));
+@@ -713,11 +715,14 @@
+ /* Vi is kind of strange here. */
+ if (wc)
+ {
++ p = rl_point;
+ mblen = wcrtomb (mb, wc, &ps);
+ if (mblen >= 0)
+ mb[mblen] = '\0';
+ rl_begin_undo_group ();
+- rl_delete (1, 0);
++ rl_vi_delete (1, 0);
++ if (rl_point < p) /* Did we retreat at EOL? */
++ rl_point++; /* XXX - should we advance more than 1 for mbchar? */
+ rl_insert_text (mb);
+ rl_end_undo_group ();
+ rl_vi_check ();
+@@ -1310,12 +1315,16 @@
+ rl_vi_delete (1, c);
+ #if defined (HANDLE_MULTIBYTE)
+ if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+- while (_rl_insert_char (1, c))
+- {
+- RL_SETSTATE (RL_STATE_MOREINPUT);
+- c = rl_read_key ();
+- RL_UNSETSTATE (RL_STATE_MOREINPUT);
+- }
++ {
++ if (rl_point < p) /* Did we retreat at EOL? */
++ rl_point++;
++ while (_rl_insert_char (1, c))
++ {
++ RL_SETSTATE (RL_STATE_MOREINPUT);
++ c = rl_read_key ();
++ RL_UNSETSTATE (RL_STATE_MOREINPUT);
++ }
++ }
+ else
+ #endif
+ {
+diff -Naur bash-3.0.orig/patchlevel.h bash-3.0/patchlevel.h
+--- bash-3.0.orig/patchlevel.h 2001-08-22 12:05:39.000000000 +0000
++++ bash-3.0/patchlevel.h 2005-01-08 05:40:53.584965496 +0000
+@@ -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 16
+
+ #endif /* _PATCHLEVEL_H_ */
+diff -Naur bash-3.0.orig/pcomplete.c bash-3.0/pcomplete.c
+--- bash-3.0.orig/pcomplete.c 2004-01-08 15:36:17.000000000 +0000
++++ bash-3.0/pcomplete.c 2005-01-08 05:40:02.049800032 +0000
+@@ -863,6 +863,8 @@
+ if (array_p (v) == 0)
+ v = convert_var_to_array (v);
+ v = assign_array_var_from_word_list (v, lwords);
++
++ VUNSETATTR (v, att_invisible);
+ return v;
+ }
+ #endif /* ARRAY_VARS */
+@@ -1022,6 +1024,8 @@
+ if (array_p (v) == 0)
+ v = convert_var_to_array (v);
+
++ VUNSETATTR (v, att_invisible);
++
+ a = array_cell (v);
+ if (a == 0 || array_empty (a))
+ sl = (STRINGLIST *)NULL;
+diff -Naur bash-3.0.orig/subst.c bash-3.0/subst.c
+--- bash-3.0.orig/subst.c 2004-07-04 17:56:13.000000000 +0000
++++ bash-3.0/subst.c 2005-01-08 05:40:53.574967016 +0000
+@@ -4691,6 +4691,26 @@
+ legal_identifier (name + 1)); /* ${#PS1} */
+ }
+
++#if defined (HANDLE_MULTIBYTE)
++size_t
++mbstrlen (s)
++ const char *s;
++{
++ size_t clen, nc;
++ mbstate_t mbs;
++
++ nc = 0;
++ memset (&mbs, 0, sizeof (mbs));
++ while ((clen = mbrlen(s, MB_CUR_MAX, &mbs)) != 0 && (MB_INVALIDCH(clen) == 0))
++ {
++ s += clen;
++ nc++;
++ }
++ return nc;
++}
++#endif
++
++
+ /* Handle the parameter brace expansion that requires us to return the
+ length of a parameter. */
+ static intmax_t
+@@ -4746,14 +4766,14 @@
+ if (legal_number (name + 1, &arg_index)) /* ${#1} */
+ {
+ t = get_dollar_var_value (arg_index);
+- number = STRLEN (t);
++ number = MB_STRLEN (t);
+ FREE (t);
+ }
+ #if defined (ARRAY_VARS)
+- else if ((var = find_variable (name + 1)) && array_p (var))
++ else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && array_p (var))
+ {
+ t = array_reference (array_cell (var), 0);
+- number = STRLEN (t);
++ number = MB_STRLEN (t);
+ }
+ #endif
+ else /* ${#PS1} */
+@@ -4766,7 +4786,7 @@
+ if (list)
+ dispose_words (list);
+
+- number = STRLEN (t);
++ number = MB_STRLEN (t);
+ FREE (t);
+ }
+ }
+@@ -4871,7 +4891,7 @@
+ {
+ case VT_VARIABLE:
+ case VT_ARRAYMEMBER:
+- len = strlen (value);
++ len = MB_STRLEN (value);
+ break;
+ case VT_POSPARMS:
+ len = number_of_args () + 1;
+@@ -4879,8 +4899,9 @@
+ #if defined (ARRAY_VARS)
+ case VT_ARRAYVAR:
+ a = (ARRAY *)value;
+- /* For arrays, the first value deals with array indices. */
+- len = array_max_index (a); /* arrays index from 0 to n - 1 */
++ /* For arrays, the first value deals with array indices. Negative
++ offsets count from one past the array's maximum index. */
++ len = array_max_index (a) + (*e1p < 0); /* arrays index from 0 to n - 1 */
+ break;
+ #endif
+ }
+@@ -4891,7 +4912,7 @@
+ if (*e1p < 0) /* negative offsets count from end */
+ *e1p += len;
+
+- if (*e1p >= len || *e1p < 0)
++ if (*e1p > len || *e1p < 0)
+ return (-1);
+
+ #if defined (ARRAY_VARS)
+@@ -4982,7 +5003,7 @@
+ else
+ return -1;
+ }
+- else if ((v = find_variable (varname)) && array_p (v))
++ else if ((v = find_variable (varname)) && (invisible_p (v) == 0) && array_p (v))
+ {
+ vtype = VT_ARRAYMEMBER;
+ *varp = v;
+diff -Naur bash-3.0.orig/tests/array.right bash-3.0/tests/array.right
+--- bash-3.0.orig/tests/array.right 2003-10-05 03:25:10.000000000 +0000
++++ bash-3.0/tests/array.right 2005-01-08 05:40:53.582965800 +0000
+@@ -170,8 +170,8 @@
+ three five seven
+ positive offset - expect five seven
+ five seven
+-negative offset - expect five seven
+-five seven
++negative offset to unset element - expect seven
++seven
+ positive offset 2 - expect seven
+ seven
+ negative offset 2 - expect seven
+diff -Naur bash-3.0.orig/tests/array.tests bash-3.0/tests/array.tests
+--- bash-3.0.orig/tests/array.tests 2003-10-05 03:25:00.000000000 +0000
++++ bash-3.0/tests/array.tests 2005-01-08 05:40:53.580966104 +0000
+@@ -322,7 +322,7 @@
+
+ echo positive offset - expect five seven
+ echo ${av[@]:5:2}
+-echo negative offset - expect five seven
++echo negative offset to unset element - expect seven
+ echo ${av[@]: -2:2}
+
+ echo positive offset 2 - expect seven
+diff -Naur bash-3.0.orig/tests/dbg-support.tests bash-3.0/tests/dbg-support.tests
+--- bash-3.0.orig/tests/dbg-support.tests 2003-03-25 20:33:03.000000000 +0000
++++ bash-3.0/tests/dbg-support.tests 2005-01-08 05:40:02.065797600 +0000
+@@ -62,8 +62,8 @@
+ trap 'print_debug_trap $LINENO' DEBUG
+ trap 'print_return_trap $LINENO' RETURN
+
+-# Funcname is now an array. Vanilla Bash 2.05 doesn't have FUNCNAME array.
+-echo "FUNCNAME" ${FUNCNAME[0]}
++# Funcname is now an array, but you still can't see it outside a function
++echo "FUNCNAME" ${FUNCNAME[0]:-main}
+
+ # We should trace into the below.
+ # Start easy with a simple function.
+diff -Naur bash-3.0.orig/tests/errors.right bash-3.0/tests/errors.right
+--- bash-3.0.orig/tests/errors.right 2004-05-28 02:26:03.000000000 +0000
++++ bash-3.0/tests/errors.right 2005-01-08 05:40:04.502427176 +0000
+@@ -85,7 +85,7 @@
+ ./errors.tests: line 213: /bin/sh + 0: syntax error: operand expected (error token is "/bin/sh + 0")
+ ./errors.tests: line 216: trap: NOSIG: invalid signal specification
+ ./errors.tests: line 219: trap: -s: invalid option
+-trap: usage: trap [-lp] [[arg] signal_spec ...]
++trap: usage: trap [-lp] [arg signal_spec ...]
+ ./errors.tests: line 225: return: can only `return' from a function or sourced script
+ ./errors.tests: line 229: break: 0: loop count out of range
+ ./errors.tests: line 233: continue: 0: loop count out of range
+diff -Naur bash-3.0.orig/variables.c bash-3.0/variables.c
+--- bash-3.0.orig/variables.c 2004-07-04 17:57:26.000000000 +0000
++++ bash-3.0/variables.c 2005-01-08 05:40:01.842831496 +0000
+@@ -1419,11 +1419,11 @@
+ v = init_dynamic_array_var ("GROUPS", get_groupset, null_array_assign, att_noassign);
+
+ # if defined (DEBUGGER)
+- v = init_dynamic_array_var ("BASH_ARGC", get_self, null_array_assign, (att_invisible|att_noassign));
+- v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, (att_invisible|att_noassign));
++ v = init_dynamic_array_var ("BASH_ARGC", get_self, null_array_assign, att_noassign);
++ v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, att_noassign);
+ # endif /* DEBUGGER */
+- v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, (att_invisible|att_noassign));
+- v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, (att_invisible|att_noassign));
++ v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, att_noassign);
++ v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, att_noassign);
+ #endif
+
+ v = init_funcname_var ();
+@@ -1599,7 +1599,10 @@
+ /* local foo; local foo; is a no-op. */
+ old_var = find_variable (name);
+ if (old_var && local_p (old_var) && old_var->context == variable_context)
+- return (old_var);
++ {
++ VUNSETATTR (old_var, att_invisible);
++ return (old_var);
++ }
+
+ was_tmpvar = old_var && tempvar_p (old_var);
+ if (was_tmpvar)