This patch documents two implemented and classical command
line options "-v" and "-x". It is derived from Debian GNU/Linux.

Index: doc/bash.1
--- doc/bash.1.orig	2004-07-12 17:27:08 +0200
+++ doc/bash.1	2004-07-27 19:47:10 +0200
@@ -113,6 +113,12 @@
 This option allows the positional parameters to be set
 when invoking an interactive shell.
 .TP
+.B \-v
+Print shell input lines as they are read.
+.TP
+.B \-x
+Print commands and their arguments as they are executed.
+.TP
 .B \-D
 A list of all double-quoted strings preceded by \fB$\fP
 is printed on the standard ouput.

-----------------------------------------------------------------------------

This patch adds an explicit recognition for terminal sequence "kD" to be
"Delete" key. This is derived from Debian GNU/Linux and SuSE Linux.

Index: lib/readline/terminal.c
--- lib/readline/terminal.c.orig	2003-09-18 17:03:42 +0200
+++ lib/readline/terminal.c	2004-07-27 20:03:17 +0200
@@ -145,6 +145,9 @@
 static char *_rl_term_kH;
 static char *_rl_term_at7;	/* @7 */
 
+/* The key sequence sent by the Delete key, if any. */
+static char *_rl_term_kD;
+
 /* Insert key */
 static char *_rl_term_kI;
 
@@ -313,6 +316,7 @@
   { "ei", &_rl_term_ei },
   { "ic", &_rl_term_ic },
   { "im", &_rl_term_im },
+  { "kD", &_rl_term_kD },	/* delete */
   { "kH", &_rl_term_kH },	/* home down ?? */
   { "kI", &_rl_term_kI },	/* insert */
   { "kd", &_rl_term_kd },
@@ -492,6 +496,7 @@
 
   rl_bind_keyseq_if_unbound (_rl_term_kh, rl_beg_of_line);	/* Home */
   rl_bind_keyseq_if_unbound (_rl_term_at7, rl_end_of_line);	/* End */
+  rl_bind_keyseq_if_unbound (_rl_term_kD, rl_delete);		/* Delete */
 
   _rl_keymap = xkeymap;
 }

-----------------------------------------------------------------------------

This patch makes sure a signal state variable is declared "volatile" so
it is consistent throughout signal handling. This patch is derived from
SuSE Linux.

Index: quit.h
--- quit.h.orig	2001-09-10 16:08:33 +0200
+++ quit.h	2004-07-27 19:47:10 +0200
@@ -22,7 +22,7 @@
 #define _QUIT_H_
 
 /* Non-zero means SIGINT has already ocurred. */
-extern int interrupt_state;
+extern volatile int interrupt_state;
 
 /* Macro to call a great deal.  SIGINT just sets above variable.  When
    it is safe, put QUIT in the code, and the "interrupt" will take place. */
Index: sig.c
--- sig.c.orig	2003-12-19 22:11:35 +0100
+++ sig.c	2004-07-27 19:47:10 +0200
@@ -59,7 +59,7 @@
 extern int parse_and_execute_level, shell_initialized;
 
 /* Non-zero after SIGINT. */
-int interrupt_state;
+volatile int interrupt_state = 0;
 
 /* The environment at the top-level R-E loop.  We use this in
    the case of error return. */
@@ -71,7 +71,7 @@
 #endif /* JOB_CONTROL */
 
 /* When non-zero, we throw_to_top_level (). */
-int interrupt_immediately = 0;
+volatile int interrupt_immediately = 0;
 
 static void initialize_shell_signals __P((void));
 
-----------------------------------------------------------------------------

Port to HP-UX 11i and similar less smart platforms.

Index: configure
--- configure.orig	2004-07-21 22:18:56 +0200
+++ configure	2004-07-27 19:47:10 +0200
@@ -1479,6 +1479,7 @@
 *-beos*)	opt_bash_malloc=no ;;	# they say it's suitable
 *-cygwin*)	opt_bash_malloc=no ;;	# Cygnus's CYGWIN environment
 *-opennt*|*-interix*)	opt_bash_malloc=no ;;	# Interix, now owned by Microsoft
+*-hpux*)	opt_bash_malloc=no ;;	# HP HP-UX
 esac
 
 # memory scrambling on free()
@@ -1624,7 +1625,7 @@
 
 else
 	MALLOC_LIB=
-	MALLOC_LIBRARY=
+	MALLOC_LIBRARY=dummy
 	MALLOC_LDFLAGS=
 	MALLOC_DEP=
 fi
Index: syntax.h
--- syntax.h.orig	2004-04-15 05:19:36 +0200
+++ syntax.h	2004-07-27 19:47:10 +0200
@@ -21,6 +21,8 @@
 #ifndef _SYNTAX_H_
 #define _SYNTAX_H_
 
+#include "config.h"
+
 /* Defines for use by mksyntax.c */
 
 #define slashify_in_quotes "\\`$\"\n"

-----------------------------------------------------------------------------

This adds the OpenPKG packaging brand.

Index: version.c
--- version.c.orig	2003-12-19 22:34:02 +0100
+++ version.c	2004-07-27 19:47:10 +0200
@@ -77,7 +77,7 @@
 show_shell_version (extended)
      int extended;
 {
-  printf ("GNU bash, version %s (%s)\n", shell_version_string (), MACHTYPE);
+  printf ("GNU bash, version %s (%s) [@l_openpkg_release@]\n", shell_version_string (), MACHTYPE);
   if (extended)
     printf (_("Copyright (C) 2004 Free Software Foundation, Inc.\n"));
 }

-----------------------------------------------------------------------------

Fix timezone handling for HPUX

Index: lib/sh/strftime.c
--- lib/sh/strftime.c.orig	2004-03-04 04:13:23 +0100
+++ lib/sh/strftime.c	2004-08-06 12:40:06 +0200
@@ -97,6 +97,8 @@
 extern int daylight;
 #if defined(SOLARIS) || defined(mips) || defined (M_UNIX)
 extern long int timezone, altzone;
+#elif defined(HPUX)
+extern long int timezone;
 #else
 extern int timezone, altzone;
 #endif
@@ -480,7 +482,11 @@
 			 * Systems with tzname[] probably have timezone as
 			 * secs west of GMT.  Convert to mins east of GMT.
 			 */
+#if defined(HPUX)
+			off = -(timezone / 60);
+#else
 			off = -(daylight ? timezone : altzone) / 60;
+#endif /* HPUX */
 #else /* !HAVE_TZNAME */
 			off = -zone.tz_minuteswest;
 #endif /* !HAVE_TZNAME */

-----------------------------------------------------------------------------

These are the accumulated official GNU bash 3.0 patches 001 to 014.

Index: array.c
--- array.c.orig	2004-05-06 14:24:13 +0200
+++ array.c	2004-10-24 18:48:43 +0200
@@ -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);
Index: arrayfunc.c
--- arrayfunc.c.orig	2003-12-19 06:03:09 +0100
+++ arrayfunc.c	2004-10-24 18:48:43 +0200
@@ -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
Index: bashline.c
--- bashline.c.orig	2004-07-06 05:22:12 +0200
+++ bashline.c	2004-10-24 18:48:43 +0200
@@ -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))
Index: braces.c
--- braces.c.orig	2003-12-04 17:09:52 +0100
+++ braces.c	2004-10-24 18:48:43 +0200
@@ -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
Index: builtins/trap.def
--- builtins/trap.def.orig	2004-05-28 04:26:19 +0200
+++ builtins/trap.def	2004-10-24 18:48:43 +0200
@@ -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;
Index: include/shmbutil.h
--- include/shmbutil.h.orig	2004-04-19 15:59:42 +0200
+++ include/shmbutil.h	2004-10-24 18:48:43 +0200
@@ -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
Index: jobs.c
--- jobs.c.orig	2004-04-23 22:28:25 +0200
+++ jobs.c	2004-10-24 18:48:43 +0200
@@ -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;
     }
 
Index: lib/readline/display.c
--- lib/readline/display.c.orig	2004-05-28 04:57:51 +0200
+++ lib/readline/display.c	2004-10-24 18:48:43 +0200
@@ -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;
Index: lib/readline/mbutil.c
--- lib/readline/mbutil.c.orig	2004-01-14 15:44:52 +0100
+++ lib/readline/mbutil.c	2004-10-24 18:48:43 +0200
@@ -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;
 	}
     }
Index: lib/readline/misc.c
--- lib/readline/misc.c.orig	2004-07-07 14:56:32 +0200
+++ lib/readline/misc.c	2004-10-24 18:48:43 +0200
@@ -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;
 }
Index: lib/readline/vi_mode.c
--- lib/readline/vi_mode.c.orig	2004-07-13 20:08:27 +0200
+++ lib/readline/vi_mode.c	2004-10-24 18:48:43 +0200
@@ -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
 	{
Index: patchlevel.h
--- patchlevel.h.orig	2001-08-22 14:05:39 +0200
+++ patchlevel.h	2004-10-24 18:48:43 +0200
@@ -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 14
 
 #endif /* _PATCHLEVEL_H_ */
Index: pcomplete.c
--- pcomplete.c.orig	2004-01-08 16:36:17 +0100
+++ pcomplete.c	2004-10-24 18:48:43 +0200
@@ -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;
Index: subst.c
--- subst.c.orig	2004-07-04 19:56:13 +0200
+++ subst.c	2004-10-24 18:48:43 +0200
@@ -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;
@@ -4891,7 +4911,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 +5002,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;
Index: variables.c
--- variables.c.orig	2004-07-04 19:57:26 +0200
+++ variables.c	2004-10-24 18:48:43 +0200
@@ -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)

-----------------------------------------------------------------------------

On brain-dead Linux platforms somewhere between glibc 2.3.3 (20040405)
and glibc 2.3.3 (20040917) (e.g. between SuSE 9.1 and SuSE 9.2 or
between Gentoo 1.4.x and 1.5.x) the system headers provide the
waitpid(2) option WCONTINUED although the underlying Linux kernels 2.4
and 2.6 still do not support this option and return EINVAL on waitpid(2)
using WCONTINUED.

As a side-effect the GNU Bash goes into an endless loop with waitpid(3)
calls after the first executed command terminated. The following
patch is derived from Gentoo Portage and workarounds this problems by
gracefully and efficiently degrading the options on waitpid(2) calls.

Well, it's just another great example of how good Linux provides
standardized APIs -- actually they are nothing more than Potemkin
villages. Ggrrrrr!

Index: jobs.c
--- jobs.c.orig	2004-11-04 10:29:23 +0100
+++ jobs.c	2004-11-04 10:32:47 +0100
@@ -2476,6 +2476,9 @@
   PROCESS *child;
   pid_t pid;
   int call_set_current, last_stopped_job, job, children_exited, waitpid_flags;
+#ifdef __linux__
+  static int wcontinued_not_supported = 0;
+#endif
 
   call_set_current = children_exited = 0;
   last_stopped_job = NO_JOB;
@@ -2489,7 +2492,18 @@
 			: 0;
       if (sigchld || block == 0)
 	waitpid_flags |= WNOHANG;
+#ifdef __linux__
+      retry:
+      if (wcontinued_not_supported)
+          waitpid_flags &= ~WCONTINUED;
+#endif
       pid = WAITPID (-1, &status, waitpid_flags);
+#ifdef __linux__
+      if (pid == -1 && errno == EINVAL) {
+          wcontinued_not_supported = 1;
+          goto retry;
+      }
+#endif
 
       /* The check for WNOHANG is to make sure we decrement sigchld only
 	 if it was non-zero before we called waitpid. */
