Submitted By: William Harrington (kb0iic at cross-lfs dot org)
Date: 08-15-2014
Initial Package Version: 4.3
Origin: Upstream
Upstream Status: Applied
Description: Contains all upstream patches up to 4.3-042

diff -Naur bash-4.3.orig/arrayfunc.c bash-4.3/arrayfunc.c
--- bash-4.3.orig/arrayfunc.c	2013-08-02 20:19:59.000000000 +0000
+++ bash-4.3/arrayfunc.c	2015-08-16 01:14:31.592942004 +0000
@@ -179,6 +179,7 @@
     array_insert (array_cell (entry), ind, newval);
   FREE (newval);
 
+  VUNSETATTR (entry, att_invisible);	/* no longer invisible */
   return (entry);
 }
 
@@ -403,6 +404,9 @@
       (*var->assign_func) (var, l->word->word, i, 0);
     else
       array_insert (a, i, l->word->word);
+
+  VUNSETATTR (var, att_invisible);	/* no longer invisible */
+
   return var;
 }
 
@@ -597,6 +601,11 @@
       if (assoc_p (var))
 	{
 	  val = expand_assignment_string_to_string (val, 0);
+	  if (val == 0)
+	    {
+	      val = (char *)xmalloc (1);
+	      val[0] = '\0';	/* like do_assignment_internal */
+	    }
 	  free_val = 1;
 	}
 
@@ -628,6 +637,10 @@
 
   if (nlist)
     dispose_words (nlist);
+
+  if (var)
+    VUNSETATTR (var, att_invisible);	/* no longer invisible */
+
   return (var);
 }
 
diff -Naur bash-4.3.orig/assoc.c bash-4.3/assoc.c
--- bash-4.3.orig/assoc.c	2011-11-05 20:39:05.000000000 +0000
+++ bash-4.3/assoc.c	2015-08-16 01:14:31.586275818 +0000
@@ -436,6 +436,8 @@
 #if 1
 	if (sh_contains_shell_metas (tlist->key))
 	  istr = sh_double_quote (tlist->key);
+	else if (ALL_ELEMENT_SUB (tlist->key[0]) && tlist->key[1] == '\0')
+	  istr = sh_double_quote (tlist->key);	
 	else
 	  istr = tlist->key;	
 #else
diff -Naur bash-4.3.orig/bashline.c bash-4.3/bashline.c
--- bash-4.3.orig/bashline.c	2014-02-10 00:56:58.000000000 +0000
+++ bash-4.3/bashline.c	2015-08-16 01:14:31.599608190 +0000
@@ -202,6 +202,7 @@
 extern int last_command_exit_value;
 extern int array_needs_making;
 extern int posixly_correct, no_symbolic_links;
+extern int sigalrm_seen;
 extern char *current_prompt_string, *ps1_prompt;
 extern STRING_INT_ALIST word_token_alist[];
 extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin;
@@ -1467,10 +1468,23 @@
 
       os = start;
       n = 0;
+      was_assignment = 0;
       s = find_cmd_start (os);
       e = find_cmd_end (end);
       do
 	{
+	  /* Don't read past the end of rl_line_buffer */
+	  if (s > rl_end)
+	    {
+	      s1 = s = e1;
+	      break;
+	    }
+	  /* Or past point if point is within an assignment statement */
+	  else if (was_assignment && s > rl_point)
+	    {
+	      s1 = s = e1;
+	      break;
+	    }
 	  /* Skip over assignment statements preceding a command name.  If we
 	     don't find a command name at all, we can perform command name
 	     completion.  If we find a partial command name, we should perform
@@ -4167,9 +4181,16 @@
   int qc;
 
   qc = rl_dispatching ? rl_completion_quote_character : 0;  
-  dfn = bash_dequote_filename ((char *)text, qc);
+  /* If rl_completion_found_quote != 0, rl_completion_matches will call the
+     filename dequoting function, causing the directory name to be dequoted
+     twice. */
+  if (rl_dispatching && rl_completion_found_quote == 0)
+    dfn = bash_dequote_filename ((char *)text, qc);
+  else
+    dfn = (char *)text;
   m1 = rl_completion_matches (dfn, rl_filename_completion_function);
-  free (dfn);
+  if (dfn != text)
+    free (dfn);
 
   if (m1 == 0 || m1[0] == 0)
     return m1;
@@ -4201,8 +4222,9 @@
 {
   /* If we're going to longjmp to top_level, make sure we clean up readline.
      check_signals will call QUIT, which will eventually longjmp to top_level,
-     calling run_interrupt_trap along the way. */
-  if (interrupt_state)
+     calling run_interrupt_trap along the way.  The check for sigalrm_seen is
+     to clean up the read builtin's state. */
+  if (terminating_signal || interrupt_state || sigalrm_seen)
     rl_cleanup_after_signal ();
   bashline_reset_event_hook ();
   check_signals_and_traps ();	/* XXX */
diff -Naur bash-4.3.orig/builtins/common.h bash-4.3/builtins/common.h
--- bash-4.3.orig/builtins/common.h	2013-07-08 20:54:47.000000000 +0000
+++ bash-4.3/builtins/common.h	2015-08-16 01:14:31.576276540 +0000
@@ -33,6 +33,8 @@
 #define SEVAL_RESETLINE	0x010
 #define SEVAL_PARSEONLY	0x020
 #define SEVAL_NOLONGJMP 0x040
+#define SEVAL_FUNCDEF	0x080		/* only allow function definitions */
+#define SEVAL_ONECMD	0x100		/* only allow a single command */
 
 /* Flags for describe_command, shared between type.def and command.def */
 #define CDESC_ALL		0x001	/* type -a */
@@ -120,6 +122,10 @@
 /* Functions from getopts.def */
 extern void getopts_reset __P((int));
 
+/* Functions from read.def */
+extern void read_tty_cleanup __P((void));
+extern int read_tty_modified __P((void));
+
 /* Functions from set.def */
 extern int minus_o_option_value __P((char *));
 extern void list_minus_o_opts __P((int, int));
diff -Naur bash-4.3.orig/builtins/evalstring.c bash-4.3/builtins/evalstring.c
--- bash-4.3.orig/builtins/evalstring.c	2014-02-11 14:42:10.000000000 +0000
+++ bash-4.3/builtins/evalstring.c	2015-08-16 01:14:31.539612516 +0000
@@ -308,6 +308,27 @@
 	    {
 	      struct fd_bitmap *bitmap;
 
+	      if (flags & SEVAL_FUNCDEF)
+		{
+		  char *x;
+
+		  /* If the command parses to something other than a straight
+		     function definition, or if we have not consumed the entire
+		     string, or if the parser has transformed the function
+		     name (as parsing will if it begins or ends with shell
+		     whitespace, for example), reject the attempt */
+		  if (command->type != cm_function_def ||
+		      ((x = parser_remaining_input ()) && *x) ||
+		      (STREQ (from_file, command->value.Function_def->name->word) == 0))
+		    {
+		      internal_warning (_("%s: ignoring function definition attempt"), from_file);
+		      should_jump_to_top_level = 0;
+		      last_result = last_command_exit_value = EX_BADUSAGE;
+		      reset_parser ();
+		      break;
+		    }
+		}
+
 	      bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
 	      begin_unwind_frame ("pe_dispose");
 	      add_unwind_protect (dispose_fd_bitmap, bitmap);
@@ -368,6 +389,12 @@
 	      dispose_command (command);
 	      dispose_fd_bitmap (bitmap);
 	      discard_unwind_frame ("pe_dispose");
+
+	      if (flags & SEVAL_ONECMD)
+		{
+		  reset_parser ();
+		  break;
+		}
 	    }
 	}
       else
diff -Naur bash-4.3.orig/builtins/read.def bash-4.3/builtins/read.def
--- bash-4.3.orig/builtins/read.def	2013-09-02 15:54:00.000000000 +0000
+++ bash-4.3/builtins/read.def	2015-08-16 01:14:31.576276540 +0000
@@ -140,10 +140,12 @@
 procenv_t alrmbuf;
 int sigalrm_seen;
 
-static int reading;
+static int reading, tty_modified;
 static SigHandler *old_alrm;
 static unsigned char delim;
 
+static struct ttsave termsave;
+
 /* In all cases, SIGALRM just sets a flag that we check periodically.  This
    avoids problems with the semi-tricky stuff we do with the xfree of
    input_string at the top of the unwind-protect list (see below). */
@@ -188,7 +190,6 @@
   struct stat tsb;
   SHELL_VAR *var;
   TTYSTRUCT ttattrs, ttset;
-  struct ttsave termsave;
 #if defined (ARRAY_VARS)
   WORD_LIST *alist;
 #endif
@@ -221,7 +222,7 @@
   USE_VAR(ps2);
   USE_VAR(lastsig);
 
-  sigalrm_seen = reading = 0;
+  sigalrm_seen = reading = tty_modified = 0;
 
   i = 0;		/* Index into the string that we are reading. */
   raw = edit = 0;	/* Not reading raw input by default. */
@@ -438,11 +439,16 @@
 	  retval = 128+SIGALRM;
 	  goto assign_vars;
 	}
+      if (interactive_shell == 0)
+	initialize_terminating_signals ();
       old_alrm = set_signal_handler (SIGALRM, sigalrm);
       add_unwind_protect (reset_alarm, (char *)NULL);
 #if defined (READLINE)
       if (edit)
-	add_unwind_protect (reset_attempted_completion_function, (char *)NULL);
+	{
+	  add_unwind_protect (reset_attempted_completion_function, (char *)NULL);
+	  add_unwind_protect (bashline_reset_event_hook, (char *)NULL);
+	}
 #endif
       falarm (tmsec, tmusec);
     }
@@ -479,7 +485,10 @@
 	  i = silent ? ttfd_cbreak (fd, &ttset) : ttfd_onechar (fd, &ttset);
 	  if (i < 0)
 	    sh_ttyerror (1);
+	  tty_modified = 1;
 	  add_unwind_protect ((Function *)ttyrestore, (char *)&termsave);
+	  if (interactive_shell == 0)
+	    initialize_terminating_signals ();
 	}
     }
   else if (silent)	/* turn off echo but leave term in canonical mode */
@@ -494,7 +503,10 @@
       if (i < 0)
 	sh_ttyerror (1);
 
+      tty_modified = 1;
       add_unwind_protect ((Function *)ttyrestore, (char *)&termsave);
+      if (interactive_shell == 0)
+	initialize_terminating_signals ();
     }
 
   /* This *must* be the top unwind-protect on the stack, so the manipulation
@@ -585,6 +597,8 @@
 	    }
 	  else
 	    lastsig = 0;
+	  if (terminating_signal && tty_modified)
+	    ttyrestore (&termsave);	/* fix terminal before exiting */
 	  CHECK_TERMSIG;
 	  eof = 1;
 	  break;
@@ -975,6 +989,20 @@
      struct ttsave *ttp;
 {
   ttsetattr (ttp->fd, ttp->attrs);
+  tty_modified = 0;
+}
+
+void
+read_tty_cleanup ()
+{
+  if (tty_modified)
+    ttyrestore (&termsave);
+}
+
+int
+read_tty_modified ()
+{
+  return (tty_modified);
 }
 
 #if defined (READLINE)
@@ -1021,6 +1049,7 @@
 
   old_attempted_completion_function = rl_attempted_completion_function;
   rl_attempted_completion_function = (rl_completion_func_t *)NULL;
+  bashline_set_event_hook ();
   if (itext)
     {
       old_startup_hook = rl_startup_hook;
@@ -1032,6 +1061,7 @@
 
   rl_attempted_completion_function = old_attempted_completion_function;
   old_attempted_completion_function = (rl_completion_func_t *)NULL;
+  bashline_reset_event_hook ();
 
   if (ret == 0)
     return ret;
diff -Naur bash-4.3.orig/builtins/set.def bash-4.3/builtins/set.def
--- bash-4.3.orig/builtins/set.def	2013-04-19 11:20:34.000000000 +0000
+++ bash-4.3/builtins/set.def	2015-08-16 01:14:31.579609632 +0000
@@ -751,9 +751,11 @@
   WORD_LIST *list;
 {
   int unset_function, unset_variable, unset_array, opt, nameref, any_failed;
+  int global_unset_func, global_unset_var;
   char *name;
 
   unset_function = unset_variable = unset_array = nameref = any_failed = 0;
+  global_unset_func = global_unset_var = 0;
 
   reset_internal_getopt ();
   while ((opt = internal_getopt (list, "fnv")) != -1)
@@ -761,10 +763,10 @@
       switch (opt)
 	{
 	case 'f':
-	  unset_function = 1;
+	  global_unset_func = 1;
 	  break;
 	case 'v':
-	  unset_variable = 1;
+	  global_unset_var = 1;
 	  break;
 	case 'n':
 	  nameref = 1;
@@ -777,7 +779,7 @@
 
   list = loptend;
 
-  if (unset_function && unset_variable)
+  if (global_unset_func && global_unset_var)
     {
       builtin_error (_("cannot simultaneously unset a function and a variable"));
       return (EXECUTION_FAILURE);
@@ -795,6 +797,9 @@
 
       name = list->word->word;
 
+      unset_function = global_unset_func;
+      unset_variable = global_unset_var;
+
 #if defined (ARRAY_VARS)
       unset_array = 0;
       if (!unset_function && valid_array_reference (name))
diff -Naur bash-4.3.orig/copy_cmd.c bash-4.3/copy_cmd.c
--- bash-4.3.orig/copy_cmd.c	2009-09-11 20:28:02.000000000 +0000
+++ bash-4.3/copy_cmd.c	2015-08-16 01:14:31.539612516 +0000
@@ -126,7 +126,7 @@
     {
     case r_reading_until:
     case r_deblank_reading_until:
-      new_redirect->here_doc_eof = savestring (redirect->here_doc_eof);
+      new_redirect->here_doc_eof = redirect->here_doc_eof ? savestring (redirect->here_doc_eof) : 0;
       /*FALLTHROUGH*/
     case r_reading_string:
     case r_appending_to:
diff -Naur bash-4.3.orig/execute_cmd.c bash-4.3/execute_cmd.c
--- bash-4.3.orig/execute_cmd.c	2014-01-31 15:54:52.000000000 +0000
+++ bash-4.3/execute_cmd.c	2015-08-16 01:14:31.476283749 +0000
@@ -2409,7 +2409,16 @@
 #endif
       lstdin = wait_for (lastpid);
 #if defined (JOB_CONTROL)
-      exec_result = job_exit_status (lastpipe_jid);
+      /* If wait_for removes the job from the jobs table, use result of last
+	 command as pipeline's exit status as usual.  The jobs list can get
+	 frozen and unfrozen at inconvenient times if there are multiple pipelines
+	 running simultaneously. */
+      if (INVALID_JOB (lastpipe_jid) == 0)
+	exec_result = job_exit_status (lastpipe_jid);
+      else if (pipefail_opt)
+	exec_result = exec_result | lstdin;	/* XXX */
+      /* otherwise we use exec_result */
+        
 #endif
       unfreeze_jobs_list ();
     }
diff -Naur bash-4.3.orig/externs.h bash-4.3/externs.h
--- bash-4.3.orig/externs.h	2014-01-02 19:58:20.000000000 +0000
+++ bash-4.3/externs.h	2015-08-16 01:14:31.366291680 +0000
@@ -324,6 +324,7 @@
 extern char *sh_backslash_quote __P((char *, const char *, int));
 extern char *sh_backslash_quote_for_double_quotes __P((char *));
 extern int sh_contains_shell_metas __P((char *));
+extern int sh_contains_quotes __P((char *));
 
 /* declarations for functions defined in lib/sh/spell.c */
 extern int spname __P((char *, char *));
diff -Naur bash-4.3.orig/jobs.c bash-4.3/jobs.c
--- bash-4.3.orig/jobs.c	2014-01-10 14:05:34.000000000 +0000
+++ bash-4.3/jobs.c	2015-08-16 01:14:31.569610353 +0000
@@ -3339,7 +3339,9 @@
       if (posixly_correct && this_shell_builtin && this_shell_builtin == wait_builtin)
 	{
 	  interrupt_immediately = 0;
-	  trap_handler (SIGCHLD);	/* set pending_traps[SIGCHLD] */
+	  /* This was trap_handler (SIGCHLD) but that can lose traps if
+	     children_exited > 1 */
+	  queue_sigchld_trap (children_exited);
 	  wait_signal_received = SIGCHLD;
 	  /* If we're in a signal handler, let CHECK_WAIT_INTR pick it up;
 	     run_pending_traps will call run_sigchld_trap later  */
@@ -3597,6 +3599,7 @@
   unwind_protect_int (jobs_list_frozen);
   unwind_protect_pointer (the_pipeline);
   unwind_protect_pointer (subst_assign_varlist);
+  unwind_protect_pointer (this_shell_builtin);
 
   /* We have to add the commands this way because they will be run
      in reverse order of adding.  We don't want maybe_set_sigchld_trap ()
@@ -4374,7 +4377,7 @@
 void
 end_job_control ()
 {
-  if (interactive_shell)		/* XXX - should it be interactive? */
+  if (interactive_shell || job_control)		/* XXX - should it be just job_control? */
     {
       terminate_stopped_jobs ();
 
diff -Naur bash-4.3.orig/lib/glob/glob.c bash-4.3/lib/glob/glob.c
--- bash-4.3.orig/lib/glob/glob.c	2014-02-01 02:43:51.000000000 +0000
+++ bash-4.3/lib/glob/glob.c	2015-08-16 01:14:31.439619726 +0000
@@ -123,6 +123,8 @@
 extern char *glob_patscan __P((char *, char *, int));
 extern wchar_t *glob_patscan_wc __P((wchar_t *, wchar_t *, int));
 
+extern char *glob_dirscan __P((char *, int));
+
 /* Compile `glob_loop.c' for single-byte characters. */
 #define CHAR	unsigned char
 #define INT	int
@@ -179,42 +181,53 @@
      char *pat, *dname;
      int flags;
 {
-  char *pp, *pe, *t;
-  int n, r;
+  char *pp, *pe, *t, *se;
+  int n, r, negate;
 
+  negate = *pat == '!';
   pp = pat + 2;
-  pe = pp + strlen (pp) - 1;	/*(*/
-  if (*pe != ')')
+  se = pp + strlen (pp) - 1;		/* end of string */
+  pe = glob_patscan (pp, se, 0);	/* end of extglob pattern (( */
+  /* we should check for invalid extglob pattern here */
+  if (pe == 0)
     return 0;
-  if ((t = strchr (pp, '|')) == 0)	/* easy case first */
+
+  /* if pe != se we have more of the pattern at the end of the extglob
+     pattern. Check the easy case first ( */
+  if (pe == se && *pe == ')' && (t = strchr (pp, '|')) == 0)
     {
       *pe = '\0';
+#if defined (HANDLE_MULTIBYTE)
+      r = mbskipname (pp, dname, flags);
+#else
       r = skipname (pp, dname, flags);	/*(*/
+#endif
       *pe = ')';
       return r;
     }
+
+  /* check every subpattern */
   while (t = glob_patscan (pp, pe, '|'))
     {
       n = t[-1];
       t[-1] = '\0';
+#if defined (HANDLE_MULTIBYTE)
+      r = mbskipname (pp, dname, flags);
+#else
       r = skipname (pp, dname, flags);
+#endif
       t[-1] = n;
       if (r == 0)	/* if any pattern says not skip, we don't skip */
         return r;
       pp = t;
     }	/*(*/
 
-  if (pp == pe)		/* glob_patscan might find end of pattern */
+  /* glob_patscan might find end of pattern */
+  if (pp == se)
     return r;
 
-  *pe = '\0';
-#  if defined (HANDLE_MULTIBYTE)
-  r = mbskipname (pp, dname, flags);	/*(*/
-#  else
-  r = skipname (pp, dname, flags);	/*(*/
-#  endif
-  *pe = ')';
-  return r;
+  /* but if it doesn't then we didn't match a leading dot */
+  return 0;
 }
 #endif
 
@@ -277,20 +290,23 @@
      int flags;
 {
 #if EXTENDED_GLOB
-  wchar_t *pp, *pe, *t, n;
-  int r;
+  wchar_t *pp, *pe, *t, n, *se;
+  int r, negate;
 
+  negate = *pat == L'!';
   pp = pat + 2;
-  pe = pp + wcslen (pp) - 1;	/*(*/
-  if (*pe != L')')
-    return 0;
-  if ((t = wcschr (pp, L'|')) == 0)
+  se = pp + wcslen (pp) - 1;	/*(*/
+  pe = glob_patscan_wc (pp, se, 0);
+
+  if (pe == se && *pe == ')' && (t = wcschr (pp, L'|')) == 0)
     {
       *pe = L'\0';
       r = wchkname (pp, dname); /*(*/
       *pe = L')';
       return r;
     }
+
+  /* check every subpattern */
   while (t = glob_patscan_wc (pp, pe, '|'))
     {
       n = t[-1];
@@ -305,10 +321,8 @@
   if (pp == pe)		/* glob_patscan_wc might find end of pattern */
     return r;
 
-  *pe = L'\0';
-  r = wchkname (pp, dname);	/*(*/
-  *pe = L')';
-  return r;
+  /* but if it doesn't then we didn't match a leading dot */
+  return 0;
 #else
   return (wchkname (pat, dname));
 #endif
@@ -1006,7 +1020,7 @@
 {
   char **result;
   unsigned int result_size;
-  char *directory_name, *filename, *dname;
+  char *directory_name, *filename, *dname, *fn;
   unsigned int directory_len;
   int free_dirname;			/* flag */
   int dflags;
@@ -1022,6 +1036,18 @@
 
   /* Find the filename.  */
   filename = strrchr (pathname, '/');
+#if defined (EXTENDED_GLOB)
+  if (filename && extended_glob)
+    {
+      fn = glob_dirscan (pathname, '/');
+#if DEBUG_MATCHING
+      if (fn != filename)
+	fprintf (stderr, "glob_filename: glob_dirscan: fn (%s) != filename (%s)\n", fn ? fn : "(null)", filename);
+#endif
+      filename = fn;
+    }
+#endif
+
   if (filename == NULL)
     {
       filename = pathname;
diff -Naur bash-4.3.orig/lib/glob/gmisc.c bash-4.3/lib/glob/gmisc.c
--- bash-4.3.orig/lib/glob/gmisc.c	2013-10-28 18:45:25.000000000 +0000
+++ bash-4.3/lib/glob/gmisc.c	2015-08-16 01:14:31.439619726 +0000
@@ -42,6 +42,8 @@
 #define WLPAREN         L'('
 #define WRPAREN         L')'
 
+extern char *glob_patscan __P((char *, char *, int));
+
 /* Return 1 of the first character of WSTRING could match the first
    character of pattern WPAT.  Wide character version. */
 int
@@ -210,6 +212,7 @@
     case '+':
     case '!':
     case '@':
+    case '?':
       return (pat[1] == LPAREN);
     default:
       return 0;
@@ -374,3 +377,34 @@
 
   return matlen;
 }
+
+/* Skip characters in PAT and return the final occurrence of DIRSEP.  This
+   is only called when extended_glob is set, so we have to skip over extglob
+   patterns x(...) */
+char *
+glob_dirscan (pat, dirsep)
+     char *pat;
+     int dirsep;
+{
+  char *p, *d, *pe, *se;
+
+  d = pe = se = 0;
+  for (p = pat; p && *p; p++)
+    {
+      if (extglob_pattern_p (p))
+	{
+	  if (se == 0)
+	    se = p + strlen (p) - 1;
+	  pe = glob_patscan (p + 2, se, 0);
+	  if (pe == 0)
+	    continue;
+	  else if (*pe == 0)
+	    break;
+	  p = pe - 1;	/* will do increment above */
+	  continue;
+	}
+      if (*p ==  dirsep)
+	d = p;
+    }
+  return d;
+}
diff -Naur bash-4.3.orig/lib/readline/complete.c bash-4.3/lib/readline/complete.c
--- bash-4.3.orig/lib/readline/complete.c	2013-10-14 13:27:10.000000000 +0000
+++ bash-4.3/lib/readline/complete.c	2015-08-16 01:14:31.599608190 +0000
@@ -689,6 +689,8 @@
 
   if (temp == 0 || *temp == '\0')
     return (pathname);
+  else if (temp[1] == 0 && temp == pathname)
+    return (pathname);
   /* If the basename is NULL, we might have a pathname like '/usr/src/'.
      Look for a previous slash and, if one is found, return the portion
      following that slash.  If there's no previous slash, just return the
diff -Naur bash-4.3.orig/lib/readline/display.c bash-4.3/lib/readline/display.c
--- bash-4.3.orig/lib/readline/display.c	2013-12-27 18:10:56.000000000 +0000
+++ bash-4.3/lib/readline/display.c	2015-08-16 01:14:31.382957145 +0000
@@ -1637,7 +1637,7 @@
   /* If we are changing the number of invisible characters in a line, and
      the spot of first difference is before the end of the invisible chars,
      lendiff needs to be adjusted. */
-  if (current_line == 0 && !_rl_horizontal_scroll_mode &&
+  if (current_line == 0 && /* !_rl_horizontal_scroll_mode && */
       current_invis_chars != visible_wrap_offset)
     {
       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
@@ -1825,8 +1825,13 @@
 	      else
 		_rl_last_c_pos += bytes_to_insert;
 
+	      /* XXX - we only want to do this if we are at the end of the line
+		 so we move there with _rl_move_cursor_relative */
 	      if (_rl_horizontal_scroll_mode && ((oe-old) > (ne-new)))
-		goto clear_rest_of_line;
+		{
+		  _rl_move_cursor_relative (ne-new, new);
+		  goto clear_rest_of_line;
+		}
 	    }
 	}
       /* Otherwise, print over the existing material. */
@@ -2677,7 +2682,8 @@
 {
   if (_rl_echoing_p)
     {
-      _rl_move_vert (_rl_vis_botlin);
+      if (_rl_vis_botlin > 0)	/* minor optimization plus bug fix */
+	_rl_move_vert (_rl_vis_botlin);
       _rl_vis_botlin = 0;
       fflush (rl_outstream);
       rl_restart_output (1, 0);
diff -Naur bash-4.3.orig/lib/readline/input.c bash-4.3/lib/readline/input.c
--- bash-4.3.orig/lib/readline/input.c	2014-01-10 20:07:08.000000000 +0000
+++ bash-4.3/lib/readline/input.c	2015-08-16 01:14:31.446285912 +0000
@@ -534,8 +534,16 @@
 	return (RL_ISSTATE (RL_STATE_READCMD) ? READERR : EOF);
       else if (_rl_caught_signal == SIGHUP || _rl_caught_signal == SIGTERM)
 	return (RL_ISSTATE (RL_STATE_READCMD) ? READERR : EOF);
+      /* keyboard-generated signals of interest */
       else if (_rl_caught_signal == SIGINT || _rl_caught_signal == SIGQUIT)
         RL_CHECK_SIGNALS ();
+      /* non-keyboard-generated signals of interest */
+      else if (_rl_caught_signal == SIGALRM
+#if defined (SIGVTALRM)
+		|| _rl_caught_signal == SIGVTALRM
+#endif
+	      )
+        RL_CHECK_SIGNALS ();
 
       if (rl_signal_event_hook)
 	(*rl_signal_event_hook) ();
diff -Naur bash-4.3.orig/lib/readline/misc.c bash-4.3/lib/readline/misc.c
--- bash-4.3.orig/lib/readline/misc.c	2012-09-01 22:03:11.000000000 +0000
+++ bash-4.3/lib/readline/misc.c	2015-08-16 01:14:31.456285191 +0000
@@ -461,6 +461,7 @@
 	    saved_undo_list = 0;
 	  /* Set up rl_line_buffer and other variables from history entry */
 	  rl_replace_from_history (entry, 0);	/* entry->line is now current */
+	  entry->data = 0;			/* entry->data is now current undo list */
 	  /* Undo all changes to this history entry */
 	  while (rl_undo_list)
 	    rl_do_undo ();
@@ -468,7 +469,6 @@
 	     the timestamp. */
 	  FREE (entry->line);
 	  entry->line = savestring (rl_line_buffer);
-	  entry->data = 0;
 	}
       entry = previous_history ();
     }
diff -Naur bash-4.3.orig/lib/readline/readline.c bash-4.3/lib/readline/readline.c
--- bash-4.3.orig/lib/readline/readline.c	2013-10-28 18:58:06.000000000 +0000
+++ bash-4.3/lib/readline/readline.c	2015-08-16 01:14:31.326294564 +0000
@@ -744,7 +744,8 @@
     r = _rl_subseq_result (r, cxt->oldmap, cxt->okey, (cxt->flags & KSEQ_SUBSEQ));
 
   RL_CHECK_SIGNALS ();
-  if (r == 0)			/* success! */
+  /* We only treat values < 0 specially to simulate recursion. */
+  if (r >= 0 || (r == -1 && (cxt->flags & KSEQ_SUBSEQ) == 0))	/* success! or failure! */
     {
       _rl_keyseq_chain_dispose ();
       RL_UNSETSTATE (RL_STATE_MULTIKEY);
@@ -964,7 +965,7 @@
 #if defined (VI_MODE)
   if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap &&
       key != ANYOTHERKEY &&
-      rl_key_sequence_length == 1 &&	/* XXX */
+      _rl_dispatching_keymap == vi_movement_keymap &&
       _rl_vi_textmod_command (key))
     _rl_vi_set_last (key, rl_numeric_arg, rl_arg_sign);
 #endif
diff -Naur bash-4.3.orig/lib/readline/readline.c.orig bash-4.3/lib/readline/readline.c.orig
--- bash-4.3.orig/lib/readline/readline.c.orig	1970-01-01 00:00:00.000000000 +0000
+++ bash-4.3/lib/readline/readline.c.orig	2015-08-16 01:14:31.296296728 +0000
@@ -0,0 +1,1364 @@
+/* readline.c -- a general facility for reading lines of input
+   with emacs style editing and completion. */
+
+/* Copyright (C) 1987-2013 Free Software Foundation, Inc.
+
+   This file is part of the GNU Readline Library (Readline), a library
+   for reading lines of text with interactive input and history editing.      
+
+   Readline is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   Readline is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with Readline.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+#  include <config.h>
+#endif
+
+#include <sys/types.h>
+#include "posixstat.h"
+#include <fcntl.h>
+#if defined (HAVE_SYS_FILE_H)
+#  include <sys/file.h>
+#endif /* HAVE_SYS_FILE_H */
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+#  include <stdlib.h>
+#else
+#  include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#if defined (HAVE_LOCALE_H)
+#  include <locale.h>
+#endif
+
+#include <stdio.h>
+#include "posixjmp.h"
+#include <errno.h>
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+#include "rlmbutil.h"
+
+#if defined (__EMX__)
+#  define INCL_DOSPROCESS
+#  include <os2.h>
+#endif /* __EMX__ */
+
+/* Some standard library routines. */
+#include "readline.h"
+#include "history.h"
+
+#include "rlprivate.h"
+#include "rlshell.h"
+#include "xmalloc.h"
+
+#ifndef RL_LIBRARY_VERSION
+#  define RL_LIBRARY_VERSION "5.1"
+#endif
+
+#ifndef RL_READLINE_VERSION
+#  define RL_READLINE_VERSION	0x0501
+#endif
+
+extern void _rl_free_history_entry PARAMS((HIST_ENTRY *));
+
+#if defined (COLOR_SUPPORT)
+extern void _rl_parse_colors PARAMS((void));		/* XXX */
+#endif
+
+
+/* Forward declarations used in this file. */
+static char *readline_internal PARAMS((void));
+static void readline_initialize_everything PARAMS((void));
+
+static void bind_arrow_keys_internal PARAMS((Keymap));
+static void bind_arrow_keys PARAMS((void));
+
+static void readline_default_bindings PARAMS((void));
+static void reset_default_bindings PARAMS((void));
+
+static int _rl_subseq_result PARAMS((int, Keymap, int, int));
+static int _rl_subseq_getchar PARAMS((int));
+
+/* **************************************************************** */
+/*								    */
+/*			Line editing input utility		    */
+/*								    */
+/* **************************************************************** */
+
+const char *rl_library_version = RL_LIBRARY_VERSION;
+
+int rl_readline_version = RL_READLINE_VERSION;
+
+/* True if this is `real' readline as opposed to some stub substitute. */
+int rl_gnu_readline_p = 1;
+
+/* A pointer to the keymap that is currently in use.
+   By default, it is the standard emacs keymap. */
+Keymap _rl_keymap = emacs_standard_keymap;
+
+/* The current style of editing. */
+int rl_editing_mode = emacs_mode;
+
+/* The current insert mode:  input (the default) or overwrite */
+int rl_insert_mode = RL_IM_DEFAULT;
+
+/* Non-zero if we called this function from _rl_dispatch().  It's present
+   so functions can find out whether they were called from a key binding
+   or directly from an application. */
+int rl_dispatching;
+
+/* Non-zero if the previous command was a kill command. */
+int _rl_last_command_was_kill = 0;
+
+/* The current value of the numeric argument specified by the user. */
+int rl_numeric_arg = 1;
+
+/* Non-zero if an argument was typed. */
+int rl_explicit_arg = 0;
+
+/* Temporary value used while generating the argument. */
+int rl_arg_sign = 1;
+
+/* Non-zero means we have been called at least once before. */
+static int rl_initialized;
+
+#if 0
+/* If non-zero, this program is running in an EMACS buffer. */
+static int running_in_emacs;
+#endif
+
+/* Flags word encapsulating the current readline state. */
+int rl_readline_state = RL_STATE_NONE;
+
+/* The current offset in the current input line. */
+int rl_point;
+
+/* Mark in the current input line. */
+int rl_mark;
+
+/* Length of the current input line. */
+int rl_end;
+
+/* Make this non-zero to return the current input_line. */
+int rl_done;
+
+/* The last function executed by readline. */
+rl_command_func_t *rl_last_func = (rl_command_func_t *)NULL;
+
+/* Top level environment for readline_internal (). */
+procenv_t _rl_top_level;
+
+/* The streams we interact with. */
+FILE *_rl_in_stream, *_rl_out_stream;
+
+/* The names of the streams that we do input and output to. */
+FILE *rl_instream = (FILE *)NULL;
+FILE *rl_outstream = (FILE *)NULL;
+
+/* Non-zero means echo characters as they are read.  Defaults to no echo;
+   set to 1 if there is a controlling terminal, we can get its attributes,
+   and the attributes include `echo'.  Look at rltty.c:prepare_terminal_settings
+   for the code that sets it. */
+int _rl_echoing_p = 0;
+
+/* Current prompt. */
+char *rl_prompt = (char *)NULL;
+int rl_visible_prompt_length = 0;
+
+/* Set to non-zero by calling application if it has already printed rl_prompt
+   and does not want readline to do it the first time. */
+int rl_already_prompted = 0;
+
+/* The number of characters read in order to type this complete command. */
+int rl_key_sequence_length = 0;
+
+/* If non-zero, then this is the address of a function to call just
+   before readline_internal_setup () prints the first prompt. */
+rl_hook_func_t *rl_startup_hook = (rl_hook_func_t *)NULL;
+
+/* If non-zero, this is the address of a function to call just before
+   readline_internal_setup () returns and readline_internal starts
+   reading input characters. */
+rl_hook_func_t *rl_pre_input_hook = (rl_hook_func_t *)NULL;
+
+/* What we use internally.  You should always refer to RL_LINE_BUFFER. */
+static char *the_line;
+
+/* The character that can generate an EOF.  Really read from
+   the terminal driver... just defaulted here. */
+int _rl_eof_char = CTRL ('D');
+
+/* Non-zero makes this the next keystroke to read. */
+int rl_pending_input = 0;
+
+/* Pointer to a useful terminal name. */
+const char *rl_terminal_name = (const char *)NULL;
+
+/* Non-zero means to always use horizontal scrolling in line display. */
+int _rl_horizontal_scroll_mode = 0;
+
+/* Non-zero means to display an asterisk at the starts of history lines
+   which have been modified. */
+int _rl_mark_modified_lines = 0;  
+
+/* The style of `bell' notification preferred.  This can be set to NO_BELL,
+   AUDIBLE_BELL, or VISIBLE_BELL. */
+int _rl_bell_preference = AUDIBLE_BELL;
+     
+/* String inserted into the line by rl_insert_comment (). */
+char *_rl_comment_begin;
+
+/* Keymap holding the function currently being executed. */
+Keymap rl_executing_keymap;
+
+/* Keymap we're currently using to dispatch. */
+Keymap _rl_dispatching_keymap;
+
+/* Non-zero means to erase entire line, including prompt, on empty input lines. */
+int rl_erase_empty_line = 0;
+
+/* Non-zero means to read only this many characters rather than up to a
+   character bound to accept-line. */
+int rl_num_chars_to_read;
+
+/* Line buffer and maintenance. */
+char *rl_line_buffer = (char *)NULL;
+int rl_line_buffer_len = 0;
+
+/* Key sequence `contexts' */
+_rl_keyseq_cxt *_rl_kscxt = 0;
+
+int rl_executing_key;
+char *rl_executing_keyseq = 0;
+int _rl_executing_keyseq_size = 0;
+
+/* Timeout (specified in milliseconds) when reading characters making up an
+   ambiguous multiple-key sequence */
+int _rl_keyseq_timeout = 500;
+
+#define RESIZE_KEYSEQ_BUFFER() \
+  do \
+    { \
+      if (rl_key_sequence_length + 2 >= _rl_executing_keyseq_size) \
+	{ \
+	  _rl_executing_keyseq_size += 16; \
+	  rl_executing_keyseq = xrealloc (rl_executing_keyseq, _rl_executing_keyseq_size); \
+	} \
+    } \
+  while (0);
+        
+/* Forward declarations used by the display, termcap, and history code. */
+
+/* **************************************************************** */
+/*								    */
+/*			`Forward' declarations  		    */
+/*								    */
+/* **************************************************************** */
+
+/* Non-zero means do not parse any lines other than comments and
+   parser directives. */
+unsigned char _rl_parsing_conditionalized_out = 0;
+
+/* Non-zero means to convert characters with the meta bit set to
+   escape-prefixed characters so we can indirect through
+   emacs_meta_keymap or vi_escape_keymap. */
+int _rl_convert_meta_chars_to_ascii = 1;
+
+/* Non-zero means to output characters with the meta bit set directly
+   rather than as a meta-prefixed escape sequence. */
+int _rl_output_meta_chars = 0;
+
+/* Non-zero means to look at the termios special characters and bind
+   them to equivalent readline functions at startup. */
+int _rl_bind_stty_chars = 1;
+
+/* Non-zero means to go through the history list at every newline (or
+   whenever rl_done is set and readline returns) and revert each line to
+   its initial state. */
+int _rl_revert_all_at_newline = 0;
+
+/* Non-zero means to honor the termios ECHOCTL bit and echo control
+   characters corresponding to keyboard-generated signals. */
+int _rl_echo_control_chars = 1;
+
+/* Non-zero means to prefix the displayed prompt with a character indicating
+   the editing mode: @ for emacs, : for vi-command, + for vi-insert. */
+int _rl_show_mode_in_prompt = 0;
+
+/* **************************************************************** */
+/*								    */
+/*			Top Level Functions			    */
+/*								    */
+/* **************************************************************** */
+
+/* Non-zero means treat 0200 bit in terminal input as Meta bit. */
+int _rl_meta_flag = 0;	/* Forward declaration */
+
+/* Set up the prompt and expand it.  Called from readline() and
+   rl_callback_handler_install (). */
+int
+rl_set_prompt (prompt)
+     const char *prompt;
+{
+  FREE (rl_prompt);
+  rl_prompt = prompt ? savestring (prompt) : (char *)NULL;
+  rl_display_prompt = rl_prompt ? rl_prompt : "";
+
+  rl_visible_prompt_length = rl_expand_prompt (rl_prompt);
+  return 0;
+}
+  
+/* Read a line of input.  Prompt with PROMPT.  An empty PROMPT means
+   none.  A return value of NULL means that EOF was encountered. */
+char *
+readline (prompt)
+     const char *prompt;
+{
+  char *value;
+#if 0
+  int in_callback;
+#endif
+
+  /* If we are at EOF return a NULL string. */
+  if (rl_pending_input == EOF)
+    {
+      rl_clear_pending_input ();
+      return ((char *)NULL);
+    }
+
+#if 0
+  /* If readline() is called after installing a callback handler, temporarily
+     turn off the callback state to avoid ensuing messiness.  Patch supplied
+     by the gdb folks.  XXX -- disabled.  This can be fooled and readline
+     left in a strange state by a poorly-timed longjmp. */
+  if (in_callback = RL_ISSTATE (RL_STATE_CALLBACK))
+    RL_UNSETSTATE (RL_STATE_CALLBACK);
+#endif
+
+  rl_set_prompt (prompt);
+
+  rl_initialize ();
+  if (rl_prep_term_function)
+    (*rl_prep_term_function) (_rl_meta_flag);
+
+#if defined (HANDLE_SIGNALS)
+  rl_set_signals ();
+#endif
+
+  value = readline_internal ();
+  if (rl_deprep_term_function)
+    (*rl_deprep_term_function) ();
+
+#if defined (HANDLE_SIGNALS)
+  rl_clear_signals ();
+#endif
+
+#if 0
+  if (in_callback)
+    RL_SETSTATE (RL_STATE_CALLBACK);
+#endif
+
+#if HAVE_DECL_AUDIT_TTY && defined (ENABLE_TTY_AUDIT_SUPPORT)
+  if (value)
+    _rl_audit_tty (value);
+#endif
+
+  return (value);
+}
+
+#if defined (READLINE_CALLBACKS)
+#  define STATIC_CALLBACK
+#else
+#  define STATIC_CALLBACK static
+#endif
+
+STATIC_CALLBACK void
+readline_internal_setup ()
+{
+  char *nprompt;
+
+  _rl_in_stream = rl_instream;
+  _rl_out_stream = rl_outstream;
+
+  /* Enable the meta key only for the duration of readline(), if this
+     terminal has one and the terminal has been initialized */
+  if (_rl_enable_meta & RL_ISSTATE (RL_STATE_TERMPREPPED))
+    _rl_enable_meta_key ();
+
+  if (rl_startup_hook)
+    (*rl_startup_hook) ();
+
+#if defined (VI_MODE)
+  if (rl_editing_mode == vi_mode)
+    rl_vi_insertion_mode (1, 'i');	/* don't want to reset last */
+#endif /* VI_MODE */
+
+  /* If we're not echoing, we still want to at least print a prompt, because
+     rl_redisplay will not do it for us.  If the calling application has a
+     custom redisplay function, though, let that function handle it. */
+  if (_rl_echoing_p == 0 && rl_redisplay_function == rl_redisplay)
+    {
+      if (rl_prompt && rl_already_prompted == 0)
+	{
+	  nprompt = _rl_strip_prompt (rl_prompt);
+	  fprintf (_rl_out_stream, "%s", nprompt);
+	  fflush (_rl_out_stream);
+	  xfree (nprompt);
+	}
+    }
+  else
+    {
+      if (rl_prompt && rl_already_prompted)
+	rl_on_new_line_with_prompt ();
+      else
+	rl_on_new_line ();
+      (*rl_redisplay_function) ();
+    }
+
+  if (rl_pre_input_hook)
+    (*rl_pre_input_hook) ();
+
+  RL_CHECK_SIGNALS ();
+}
+
+STATIC_CALLBACK char *
+readline_internal_teardown (eof)
+     int eof;
+{
+  char *temp;
+  HIST_ENTRY *entry;
+
+  RL_CHECK_SIGNALS ();
+
+  /* Restore the original of this history line, iff the line that we
+     are editing was originally in the history, AND the line has changed. */
+  entry = current_history ();
+
+  if (entry && rl_undo_list)
+    {
+      temp = savestring (the_line);
+      rl_revert_line (1, 0);
+      entry = replace_history_entry (where_history (), the_line, (histdata_t)NULL);
+      _rl_free_history_entry (entry);
+
+      strcpy (the_line, temp);
+      xfree (temp);
+    }
+
+  if (_rl_revert_all_at_newline)
+    _rl_revert_all_lines ();
+
+  /* At any rate, it is highly likely that this line has an undo list.  Get
+     rid of it now. */
+  if (rl_undo_list)
+    rl_free_undo_list ();
+
+  /* Disable the meta key, if this terminal has one and we were told to use it.
+     The check whether or not we sent the enable string is in
+     _rl_disable_meta_key(); the flag is set in _rl_enable_meta_key */
+  _rl_disable_meta_key ();
+
+  /* Restore normal cursor, if available. */
+  _rl_set_insert_mode (RL_IM_INSERT, 0);
+
+  return (eof ? (char *)NULL : savestring (the_line));
+}
+
+void
+_rl_internal_char_cleanup ()
+{
+#if defined (VI_MODE)
+  /* In vi mode, when you exit insert mode, the cursor moves back
+     over the previous character.  We explicitly check for that here. */
+  if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap)
+    rl_vi_check ();
+#endif /* VI_MODE */
+
+  if (rl_num_chars_to_read && rl_end >= rl_num_chars_to_read)
+    {
+      (*rl_redisplay_function) ();
+      _rl_want_redisplay = 0;
+      rl_newline (1, '\n');
+    }
+
+  if (rl_done == 0)
+    {
+      (*rl_redisplay_function) ();
+      _rl_want_redisplay = 0;
+    }
+
+  /* If the application writer has told us to erase the entire line if
+     the only character typed was something bound to rl_newline, do so. */
+  if (rl_erase_empty_line && rl_done && rl_last_func == rl_newline &&
+      rl_point == 0 && rl_end == 0)
+    _rl_erase_entire_line ();
+}
+
+STATIC_CALLBACK int
+#if defined (READLINE_CALLBACKS)
+readline_internal_char ()
+#else
+readline_internal_charloop ()
+#endif
+{
+  static int lastc, eof_found;
+  int c, code, lk;
+
+  lastc = -1;
+  eof_found = 0;
+
+#if !defined (READLINE_CALLBACKS)
+  while (rl_done == 0)
+    {
+#endif
+      lk = _rl_last_command_was_kill;
+
+#if defined (HAVE_POSIX_SIGSETJMP)
+      code = sigsetjmp (_rl_top_level, 0);
+#else
+      code = setjmp (_rl_top_level);
+#endif
+
+      if (code)
+	{
+	  (*rl_redisplay_function) ();
+	  _rl_want_redisplay = 0;
+	  /* If we get here, we're not being called from something dispatched
+	     from _rl_callback_read_char(), which sets up its own value of
+	     _rl_top_level (saving and restoring the old, of course), so
+	     we can just return here. */
+	  if (RL_ISSTATE (RL_STATE_CALLBACK))
+	    return (0);
+	}
+
+      if (rl_pending_input == 0)
+	{
+	  /* Then initialize the argument and number of keys read. */
+	  _rl_reset_argument ();
+	  rl_key_sequence_length = 0;
+	  rl_executing_keyseq[0] = 0;
+	}
+
+      RL_SETSTATE(RL_STATE_READCMD);
+      c = rl_read_key ();
+      RL_UNSETSTATE(RL_STATE_READCMD);
+
+      /* look at input.c:rl_getc() for the circumstances under which this will
+	 be returned; punt immediately on read error without converting it to
+	 a newline; assume that rl_read_key has already called the signal
+	 handler. */
+      if (c == READERR)
+	{
+#if defined (READLINE_CALLBACKS)
+	  RL_SETSTATE(RL_STATE_DONE);
+	  return (rl_done = 1);
+#else
+	  eof_found = 1;
+	  break;
+#endif
+	}
+
+      /* EOF typed to a non-blank line is a <NL>.  If we want to change this,
+	 to force any existing line to be ignored when read(2) reads EOF,
+	 for example, this is the place to change. */
+      if (c == EOF && rl_end)
+	c = NEWLINE;
+
+      /* The character _rl_eof_char typed to blank line, and not as the
+	 previous character is interpreted as EOF. */
+      if (((c == _rl_eof_char && lastc != c) || c == EOF) && !rl_end)
+	{
+#if defined (READLINE_CALLBACKS)
+	  RL_SETSTATE(RL_STATE_DONE);
+	  return (rl_done = 1);
+#else
+	  eof_found = 1;
+	  break;
+#endif
+	}
+
+      lastc = c;
+      _rl_dispatch ((unsigned char)c, _rl_keymap);
+      RL_CHECK_SIGNALS ();
+
+      /* If there was no change in _rl_last_command_was_kill, then no kill
+	 has taken place.  Note that if input is pending we are reading
+	 a prefix command, so nothing has changed yet. */
+      if (rl_pending_input == 0 && lk == _rl_last_command_was_kill)
+	_rl_last_command_was_kill = 0;
+
+      _rl_internal_char_cleanup ();
+
+#if defined (READLINE_CALLBACKS)
+      return 0;
+#else
+    }
+
+  return (eof_found);
+#endif
+}
+
+#if defined (READLINE_CALLBACKS)
+static int
+readline_internal_charloop ()
+{
+  int eof = 1;
+
+  while (rl_done == 0)
+    eof = readline_internal_char ();
+  return (eof);
+}
+#endif /* READLINE_CALLBACKS */
+
+/* Read a line of input from the global rl_instream, doing output on
+   the global rl_outstream.
+   If rl_prompt is non-null, then that is our prompt. */
+static char *
+readline_internal ()
+{
+  int eof;
+
+  readline_internal_setup ();
+  eof = readline_internal_charloop ();
+  return (readline_internal_teardown (eof));
+}
+
+void
+_rl_init_line_state ()
+{
+  rl_point = rl_end = rl_mark = 0;
+  the_line = rl_line_buffer;
+  the_line[0] = 0;
+}
+
+void
+_rl_set_the_line ()
+{
+  the_line = rl_line_buffer;
+}
+
+#if defined (READLINE_CALLBACKS)
+_rl_keyseq_cxt *
+_rl_keyseq_cxt_alloc ()
+{
+  _rl_keyseq_cxt *cxt;
+
+  cxt = (_rl_keyseq_cxt *)xmalloc (sizeof (_rl_keyseq_cxt));
+
+  cxt->flags = cxt->subseq_arg = cxt->subseq_retval = 0;
+
+  cxt->okey = 0;
+  cxt->ocxt = _rl_kscxt;
+  cxt->childval = 42;		/* sentinel value */
+
+  return cxt;
+}
+
+void
+_rl_keyseq_cxt_dispose (cxt)
+    _rl_keyseq_cxt *cxt;
+{
+  xfree (cxt);
+}
+
+void
+_rl_keyseq_chain_dispose ()
+{
+  _rl_keyseq_cxt *cxt;
+
+  while (_rl_kscxt)
+    {
+      cxt = _rl_kscxt;
+      _rl_kscxt = _rl_kscxt->ocxt;
+      _rl_keyseq_cxt_dispose (cxt);
+    }
+}
+#endif
+
+static int
+_rl_subseq_getchar (key)
+     int key;
+{
+  int k;
+
+  if (key == ESC)
+    RL_SETSTATE(RL_STATE_METANEXT);
+  RL_SETSTATE(RL_STATE_MOREINPUT);
+  k = rl_read_key ();
+  RL_UNSETSTATE(RL_STATE_MOREINPUT);
+  if (key == ESC)
+    RL_UNSETSTATE(RL_STATE_METANEXT);
+
+  return k;
+}
+
+#if defined (READLINE_CALLBACKS)
+int
+_rl_dispatch_callback (cxt)
+     _rl_keyseq_cxt *cxt;
+{
+  int nkey, r;
+
+  /* For now */
+  /* The first time this context is used, we want to read input and dispatch
+     on it.  When traversing the chain of contexts back `up', we want to use
+     the value from the next context down.  We're simulating recursion using
+     a chain of contexts. */
+  if ((cxt->flags & KSEQ_DISPATCHED) == 0)
+    {
+      nkey = _rl_subseq_getchar (cxt->okey);
+      if (nkey < 0)
+	{
+	  _rl_abort_internal ();
+	  return -1;
+	}
+      r = _rl_dispatch_subseq (nkey, cxt->dmap, cxt->subseq_arg);
+      cxt->flags |= KSEQ_DISPATCHED;
+    }
+  else
+    r = cxt->childval;
+
+  /* For now */
+  if (r != -3)	/* don't do this if we indicate there will be other matches */
+    r = _rl_subseq_result (r, cxt->oldmap, cxt->okey, (cxt->flags & KSEQ_SUBSEQ));
+
+  RL_CHECK_SIGNALS ();
+  /* We only treat values < 0 specially to simulate recursion. */
+  if (r >= 0 || (r == -1 && (cxt->flags & KSEQ_SUBSEQ) == 0))	/* success! or failure! */
+    {
+      _rl_keyseq_chain_dispose ();
+      RL_UNSETSTATE (RL_STATE_MULTIKEY);
+      return r;
+    }
+
+  if (r != -3)			/* magic value that says we added to the chain */
+    _rl_kscxt = cxt->ocxt;
+  if (_rl_kscxt)
+    _rl_kscxt->childval = r;
+  if (r != -3)
+    _rl_keyseq_cxt_dispose (cxt);
+
+  return r;
+}
+#endif /* READLINE_CALLBACKS */
+  
+/* Do the command associated with KEY in MAP.
+   If the associated command is really a keymap, then read
+   another key, and dispatch into that map. */
+int
+_rl_dispatch (key, map)
+     register int key;
+     Keymap map;
+{
+  _rl_dispatching_keymap = map;
+  return _rl_dispatch_subseq (key, map, 0);
+}
+
+int
+_rl_dispatch_subseq (key, map, got_subseq)
+     register int key;
+     Keymap map;
+     int got_subseq;
+{
+  int r, newkey;
+  char *macro;
+  rl_command_func_t *func;
+#if defined (READLINE_CALLBACKS)
+  _rl_keyseq_cxt *cxt;
+#endif
+
+  if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii)
+    {
+      if (map[ESC].type == ISKMAP)
+	{
+	  if (RL_ISSTATE (RL_STATE_MACRODEF))
+	    _rl_add_macro_char (ESC);
+	  RESIZE_KEYSEQ_BUFFER ();
+	  rl_executing_keyseq[rl_key_sequence_length++] = ESC;
+	  map = FUNCTION_TO_KEYMAP (map, ESC);
+	  key = UNMETA (key);
+	  return (_rl_dispatch (key, map));
+	}
+      else
+	rl_ding ();
+      return 0;
+    }
+
+  if (RL_ISSTATE (RL_STATE_MACRODEF))
+    _rl_add_macro_char (key);
+
+  r = 0;
+  switch (map[key].type)
+    {
+    case ISFUNC:
+      func = map[key].function;
+      if (func)
+	{
+	  /* Special case rl_do_lowercase_version (). */
+	  if (func == rl_do_lowercase_version)
+	    /* Should we do anything special if key == ANYOTHERKEY? */
+	    return (_rl_dispatch (_rl_to_lower (key), map));
+
+	  rl_executing_keymap = map;
+	  rl_executing_key = key;
+
+	  RESIZE_KEYSEQ_BUFFER();
+	  rl_executing_keyseq[rl_key_sequence_length++] = key;
+	  rl_executing_keyseq[rl_key_sequence_length] = '\0';
+
+	  rl_dispatching = 1;
+	  RL_SETSTATE(RL_STATE_DISPATCHING);
+	  r = (*func) (rl_numeric_arg * rl_arg_sign, key);
+	  RL_UNSETSTATE(RL_STATE_DISPATCHING);
+	  rl_dispatching = 0;
+
+	  /* If we have input pending, then the last command was a prefix
+	     command.  Don't change the state of rl_last_func.  Otherwise,
+	     remember the last command executed in this variable. */
+	  if (rl_pending_input == 0 && map[key].function != rl_digit_argument)
+	    rl_last_func = map[key].function;
+
+	  RL_CHECK_SIGNALS ();
+	}
+      else if (map[ANYOTHERKEY].function)
+	{
+	  /* OK, there's no function bound in this map, but there is a
+	     shadow function that was overridden when the current keymap
+	     was created.  Return -2 to note  that. */
+	  if (RL_ISSTATE (RL_STATE_MACROINPUT))
+	    _rl_prev_macro_key ();
+	  else
+	    _rl_unget_char  (key);
+	  return -2;
+	}
+      else if (got_subseq)
+	{
+	  /* Return -1 to note that we're in a subsequence, but  we don't
+	     have a matching key, nor was one overridden.  This means
+	     we need to back up the recursion chain and find the last
+	     subsequence that is bound to a function. */
+	  if (RL_ISSTATE (RL_STATE_MACROINPUT))
+	    _rl_prev_macro_key ();
+	  else
+	    _rl_unget_char (key);
+	  return -1;
+	}
+      else
+	{
+#if defined (READLINE_CALLBACKS)
+	  RL_UNSETSTATE (RL_STATE_MULTIKEY);
+	  _rl_keyseq_chain_dispose ();
+#endif
+	  _rl_abort_internal ();
+	  return -1;
+	}
+      break;
+
+    case ISKMAP:
+      if (map[key].function != 0)
+	{
+#if defined (VI_MODE)
+	  /* The only way this test will be true is if a subsequence has been
+	     bound starting with ESC, generally the arrow keys.  What we do is
+	     check whether there's input in the queue, which there generally
+	     will be if an arrow key has been pressed, and, if there's not,
+	     just dispatch to (what we assume is) rl_vi_movement_mode right
+	     away.  This is essentially an input test with a zero timeout (by
+	     default) or a timeout determined by the value of `keyseq-timeout' */
+	  /* _rl_keyseq_timeout specified in milliseconds; _rl_input_queued
+	     takes microseconds, so multiply by 1000 */
+	  if (rl_editing_mode == vi_mode && key == ESC && map == vi_insertion_keymap
+	      && _rl_input_queued ((_rl_keyseq_timeout > 0) ? _rl_keyseq_timeout*1000 : 0) == 0)
+	    return (_rl_dispatch (ANYOTHERKEY, FUNCTION_TO_KEYMAP (map, key)));
+#endif
+
+	  RESIZE_KEYSEQ_BUFFER ();
+	  rl_executing_keyseq[rl_key_sequence_length++] = key;
+	  _rl_dispatching_keymap = FUNCTION_TO_KEYMAP (map, key);
+
+	  /* Allocate new context here.  Use linked contexts (linked through
+	     cxt->ocxt) to simulate recursion */
+#if defined (READLINE_CALLBACKS)
+	  if (RL_ISSTATE (RL_STATE_CALLBACK))
+	    {
+	      /* Return 0 only the first time, to indicate success to
+		 _rl_callback_read_char.  The rest of the time, we're called
+		 from _rl_dispatch_callback, so we return -3 to indicate
+		 special handling is necessary. */
+	      r = RL_ISSTATE (RL_STATE_MULTIKEY) ? -3 : 0;
+	      cxt = _rl_keyseq_cxt_alloc ();
+
+	      if (got_subseq)
+		cxt->flags |= KSEQ_SUBSEQ;
+	      cxt->okey = key;
+	      cxt->oldmap = map;
+	      cxt->dmap = _rl_dispatching_keymap;
+	      cxt->subseq_arg = got_subseq || cxt->dmap[ANYOTHERKEY].function;
+
+	      RL_SETSTATE (RL_STATE_MULTIKEY);
+	      _rl_kscxt = cxt;
+
+	      return r;		/* don't indicate immediate success */
+	    }
+#endif
+
+	  /* Tentative inter-character timeout for potential multi-key
+	     sequences?  If no input within timeout, abort sequence and
+	     act as if we got non-matching input. */
+	  /* _rl_keyseq_timeout specified in milliseconds; _rl_input_queued
+	     takes microseconds, so multiply by 1000 */
+	  if (_rl_keyseq_timeout > 0 &&
+	  	(RL_ISSTATE (RL_STATE_INPUTPENDING|RL_STATE_MACROINPUT) == 0) &&
+	  	_rl_pushed_input_available () == 0 &&
+		_rl_dispatching_keymap[ANYOTHERKEY].function &&
+		_rl_input_queued (_rl_keyseq_timeout*1000) == 0)
+	    return (_rl_subseq_result (-2, map, key, got_subseq));
+
+	  newkey = _rl_subseq_getchar (key);
+	  if (newkey < 0)
+	    {
+	      _rl_abort_internal ();
+	      return -1;
+	    }
+
+	  r = _rl_dispatch_subseq (newkey, _rl_dispatching_keymap, got_subseq || map[ANYOTHERKEY].function);
+	  return _rl_subseq_result (r, map, key, got_subseq);
+	}
+      else
+	{
+	  _rl_abort_internal ();
+	  return -1;
+	}
+      break;
+
+    case ISMACR:
+      if (map[key].function != 0)
+	{
+	  rl_executing_keyseq[rl_key_sequence_length] = '\0';
+	  macro = savestring ((char *)map[key].function);
+	  _rl_with_macro_input (macro);
+	  return 0;
+	}
+      break;
+    }
+#if defined (VI_MODE)
+  if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap &&
+      key != ANYOTHERKEY &&
+      rl_key_sequence_length == 1 &&	/* XXX */
+      _rl_vi_textmod_command (key))
+    _rl_vi_set_last (key, rl_numeric_arg, rl_arg_sign);
+#endif
+
+  return (r);
+}
+
+static int
+_rl_subseq_result (r, map, key, got_subseq)
+     int r;
+     Keymap map;
+     int key, got_subseq;
+{
+  Keymap m;
+  int type, nt;
+  rl_command_func_t *func, *nf;
+
+  if (r == -2)
+    /* We didn't match anything, and the keymap we're indexed into
+       shadowed a function previously bound to that prefix.  Call
+       the function.  The recursive call to _rl_dispatch_subseq has
+       already taken care of pushing any necessary input back onto
+       the input queue with _rl_unget_char. */
+    {
+      m = _rl_dispatching_keymap;
+      type = m[ANYOTHERKEY].type;
+      func = m[ANYOTHERKEY].function;
+      if (type == ISFUNC && func == rl_do_lowercase_version)
+	r = _rl_dispatch (_rl_to_lower (key), map);
+      else if (type == ISFUNC && func == rl_insert)
+	{
+	  /* If the function that was shadowed was self-insert, we
+	     somehow need a keymap with map[key].func == self-insert.
+	     Let's use this one. */
+	  nt = m[key].type;
+	  nf = m[key].function;
+
+	  m[key].type = type;
+	  m[key].function = func;
+	  r = _rl_dispatch (key, m);
+	  m[key].type = nt;
+	  m[key].function = nf;
+	}
+      else
+	r = _rl_dispatch (ANYOTHERKEY, m);
+    }
+  else if (r && map[ANYOTHERKEY].function)
+    {
+      /* We didn't match (r is probably -1), so return something to
+	 tell the caller that it should try ANYOTHERKEY for an
+	 overridden function. */
+      if (RL_ISSTATE (RL_STATE_MACROINPUT))
+	_rl_prev_macro_key ();
+      else
+	_rl_unget_char (key);
+      _rl_dispatching_keymap = map;
+      return -2;
+    }
+  else if (r && got_subseq)
+    {
+      /* OK, back up the chain. */
+      if (RL_ISSTATE (RL_STATE_MACROINPUT))
+	_rl_prev_macro_key ();
+      else
+	_rl_unget_char (key);
+      _rl_dispatching_keymap = map;
+      return -1;
+    }
+
+  return r;
+}
+
+/* **************************************************************** */
+/*								    */
+/*			Initializations 			    */
+/*								    */
+/* **************************************************************** */
+
+/* Initialize readline (and terminal if not already). */
+int
+rl_initialize ()
+{
+  /* If we have never been called before, initialize the
+     terminal and data structures. */
+  if (!rl_initialized)
+    {
+      RL_SETSTATE(RL_STATE_INITIALIZING);
+      readline_initialize_everything ();
+      RL_UNSETSTATE(RL_STATE_INITIALIZING);
+      rl_initialized++;
+      RL_SETSTATE(RL_STATE_INITIALIZED);
+    }
+
+  /* Initialize the current line information. */
+  _rl_init_line_state ();
+
+  /* We aren't done yet.  We haven't even gotten started yet! */
+  rl_done = 0;
+  RL_UNSETSTATE(RL_STATE_DONE);
+
+  /* Tell the history routines what is going on. */
+  _rl_start_using_history ();
+
+  /* Make the display buffer match the state of the line. */
+  rl_reset_line_state ();
+
+  /* No such function typed yet. */
+  rl_last_func = (rl_command_func_t *)NULL;
+
+  /* Parsing of key-bindings begins in an enabled state. */
+  _rl_parsing_conditionalized_out = 0;
+
+#if defined (VI_MODE)
+  if (rl_editing_mode == vi_mode)
+    _rl_vi_initialize_line ();
+#endif
+
+  /* Each line starts in insert mode (the default). */
+  _rl_set_insert_mode (RL_IM_DEFAULT, 1);
+
+  return 0;
+}
+
+#if 0
+#if defined (__EMX__)
+static void
+_emx_build_environ ()
+{
+  TIB *tibp;
+  PIB *pibp;
+  char *t, **tp;
+  int c;
+
+  DosGetInfoBlocks (&tibp, &pibp);
+  t = pibp->pib_pchenv;
+  for (c = 1; *t; c++)
+    t += strlen (t) + 1;
+  tp = environ = (char **)xmalloc ((c + 1) * sizeof (char *));
+  t = pibp->pib_pchenv;
+  while (*t)
+    {
+      *tp++ = t;
+      t += strlen (t) + 1;
+    }
+  *tp = 0;
+}
+#endif /* __EMX__ */
+#endif
+
+/* Initialize the entire state of the world. */
+static void
+readline_initialize_everything ()
+{
+#if 0
+#if defined (__EMX__)
+  if (environ == 0)
+    _emx_build_environ ();
+#endif
+#endif
+
+#if 0
+  /* Find out if we are running in Emacs -- UNUSED. */
+  running_in_emacs = sh_get_env_value ("EMACS") != (char *)0;
+#endif
+
+  /* Set up input and output if they are not already set up. */
+  if (!rl_instream)
+    rl_instream = stdin;
+
+  if (!rl_outstream)
+    rl_outstream = stdout;
+
+  /* Bind _rl_in_stream and _rl_out_stream immediately.  These values
+     may change, but they may also be used before readline_internal ()
+     is called. */
+  _rl_in_stream = rl_instream;
+  _rl_out_stream = rl_outstream;
+
+  /* Allocate data structures. */
+  if (rl_line_buffer == 0)
+    rl_line_buffer = (char *)xmalloc (rl_line_buffer_len = DEFAULT_BUFFER_SIZE);
+
+  /* Initialize the terminal interface. */
+  if (rl_terminal_name == 0)
+    rl_terminal_name = sh_get_env_value ("TERM");
+  _rl_init_terminal_io (rl_terminal_name);
+
+  /* Bind tty characters to readline functions. */
+  readline_default_bindings ();
+
+  /* Initialize the function names. */
+  rl_initialize_funmap ();
+
+  /* Decide whether we should automatically go into eight-bit mode. */
+  _rl_init_eightbit ();
+      
+  /* Read in the init file. */
+  rl_read_init_file ((char *)NULL);
+
+  /* XXX */
+  if (_rl_horizontal_scroll_mode && _rl_term_autowrap)
+    {
+      _rl_screenwidth--;
+      _rl_screenchars -= _rl_screenheight;
+    }
+
+  /* Override the effect of any `set keymap' assignments in the
+     inputrc file. */
+  rl_set_keymap_from_edit_mode ();
+
+  /* Try to bind a common arrow key prefix, if not already bound. */
+  bind_arrow_keys ();
+
+  /* If the completion parser's default word break characters haven't
+     been set yet, then do so now. */
+  if (rl_completer_word_break_characters == (char *)NULL)
+    rl_completer_word_break_characters = (char *)rl_basic_word_break_characters;
+
+#if defined (COLOR_SUPPORT)
+  if (_rl_colored_stats)
+    _rl_parse_colors ();
+#endif
+
+  rl_executing_keyseq = malloc (_rl_executing_keyseq_size = 16);
+  if (rl_executing_keyseq)
+    rl_executing_keyseq[0] = '\0';
+}
+
+/* If this system allows us to look at the values of the regular
+   input editing characters, then bind them to their readline
+   equivalents, iff the characters are not bound to keymaps. */
+static void
+readline_default_bindings ()
+{
+  if (_rl_bind_stty_chars)
+    rl_tty_set_default_bindings (_rl_keymap);
+}
+
+/* Reset the default bindings for the terminal special characters we're
+   interested in back to rl_insert and read the new ones. */
+static void
+reset_default_bindings ()
+{
+  if (_rl_bind_stty_chars)
+    {
+      rl_tty_unset_default_bindings (_rl_keymap);
+      rl_tty_set_default_bindings (_rl_keymap);
+    }
+}
+
+/* Bind some common arrow key sequences in MAP. */
+static void
+bind_arrow_keys_internal (map)
+     Keymap map;
+{
+  Keymap xkeymap;
+
+  xkeymap = _rl_keymap;
+  _rl_keymap = map;
+
+#if defined (__MSDOS__)
+  rl_bind_keyseq_if_unbound ("\033[0A", rl_get_previous_history);
+  rl_bind_keyseq_if_unbound ("\033[0B", rl_backward_char);
+  rl_bind_keyseq_if_unbound ("\033[0C", rl_forward_char);
+  rl_bind_keyseq_if_unbound ("\033[0D", rl_get_next_history);
+#endif
+
+  rl_bind_keyseq_if_unbound ("\033[A", rl_get_previous_history);
+  rl_bind_keyseq_if_unbound ("\033[B", rl_get_next_history);
+  rl_bind_keyseq_if_unbound ("\033[C", rl_forward_char);
+  rl_bind_keyseq_if_unbound ("\033[D", rl_backward_char);
+  rl_bind_keyseq_if_unbound ("\033[H", rl_beg_of_line);
+  rl_bind_keyseq_if_unbound ("\033[F", rl_end_of_line);
+
+  rl_bind_keyseq_if_unbound ("\033OA", rl_get_previous_history);
+  rl_bind_keyseq_if_unbound ("\033OB", rl_get_next_history);
+  rl_bind_keyseq_if_unbound ("\033OC", rl_forward_char);
+  rl_bind_keyseq_if_unbound ("\033OD", rl_backward_char);
+  rl_bind_keyseq_if_unbound ("\033OH", rl_beg_of_line);
+  rl_bind_keyseq_if_unbound ("\033OF", rl_end_of_line);
+
+#if defined (__MINGW32__)
+  rl_bind_keyseq_if_unbound ("\340H", rl_get_previous_history);
+  rl_bind_keyseq_if_unbound ("\340P", rl_get_next_history);
+  rl_bind_keyseq_if_unbound ("\340M", rl_forward_char);
+  rl_bind_keyseq_if_unbound ("\340K", rl_backward_char);
+  rl_bind_keyseq_if_unbound ("\340G", rl_beg_of_line);
+  rl_bind_keyseq_if_unbound ("\340O", rl_end_of_line);
+  rl_bind_keyseq_if_unbound ("\340S", rl_delete);
+  rl_bind_keyseq_if_unbound ("\340R", rl_overwrite_mode);
+
+  /* These may or may not work because of the embedded NUL. */
+  rl_bind_keyseq_if_unbound ("\\000H", rl_get_previous_history);
+  rl_bind_keyseq_if_unbound ("\\000P", rl_get_next_history);
+  rl_bind_keyseq_if_unbound ("\\000M", rl_forward_char);
+  rl_bind_keyseq_if_unbound ("\\000K", rl_backward_char);
+  rl_bind_keyseq_if_unbound ("\\000G", rl_beg_of_line);
+  rl_bind_keyseq_if_unbound ("\\000O", rl_end_of_line);
+  rl_bind_keyseq_if_unbound ("\\000S", rl_delete);
+  rl_bind_keyseq_if_unbound ("\\000R", rl_overwrite_mode);
+#endif
+
+  _rl_keymap = xkeymap;
+}
+
+/* Try and bind the common arrow key prefixes after giving termcap and
+   the inputrc file a chance to bind them and create `real' keymaps
+   for the arrow key prefix. */
+static void
+bind_arrow_keys ()
+{
+  bind_arrow_keys_internal (emacs_standard_keymap);
+
+#if defined (VI_MODE)
+  bind_arrow_keys_internal (vi_movement_keymap);
+  /* Unbind vi_movement_keymap[ESC] to allow users to repeatedly hit ESC
+     in vi command mode while still allowing the arrow keys to work. */
+  if (vi_movement_keymap[ESC].type == ISKMAP)
+    rl_bind_keyseq_in_map ("\033", (rl_command_func_t *)NULL, vi_movement_keymap);
+  bind_arrow_keys_internal (vi_insertion_keymap);
+#endif
+}
+
+/* **************************************************************** */
+/*								    */
+/*		Saving and Restoring Readline's state		    */
+/*								    */
+/* **************************************************************** */
+
+int
+rl_save_state (sp)
+     struct readline_state *sp;
+{
+  if (sp == 0)
+    return -1;
+
+  sp->point = rl_point;
+  sp->end = rl_end;
+  sp->mark = rl_mark;
+  sp->buffer = rl_line_buffer;
+  sp->buflen = rl_line_buffer_len;
+  sp->ul = rl_undo_list;
+  sp->prompt = rl_prompt;
+
+  sp->rlstate = rl_readline_state;
+  sp->done = rl_done;
+  sp->kmap = _rl_keymap;
+
+  sp->lastfunc = rl_last_func;
+  sp->insmode = rl_insert_mode;
+  sp->edmode = rl_editing_mode;
+  sp->kseqlen = rl_key_sequence_length;
+  sp->inf = rl_instream;
+  sp->outf = rl_outstream;
+  sp->pendingin = rl_pending_input;
+  sp->macro = rl_executing_macro;
+
+  sp->catchsigs = rl_catch_signals;
+  sp->catchsigwinch = rl_catch_sigwinch;
+
+  return (0);
+}
+
+int
+rl_restore_state (sp)
+     struct readline_state *sp;
+{
+  if (sp == 0)
+    return -1;
+
+  rl_point = sp->point;
+  rl_end = sp->end;
+  rl_mark = sp->mark;
+  the_line = rl_line_buffer = sp->buffer;
+  rl_line_buffer_len = sp->buflen;
+  rl_undo_list = sp->ul;
+  rl_prompt = sp->prompt;
+
+  rl_readline_state = sp->rlstate;
+  rl_done = sp->done;
+  _rl_keymap = sp->kmap;
+
+  rl_last_func = sp->lastfunc;
+  rl_insert_mode = sp->insmode;
+  rl_editing_mode = sp->edmode;
+  rl_key_sequence_length = sp->kseqlen;
+  rl_instream = sp->inf;
+  rl_outstream = sp->outf;
+  rl_pending_input = sp->pendingin;
+  rl_executing_macro = sp->macro;
+
+  rl_catch_signals = sp->catchsigs;
+  rl_catch_sigwinch = sp->catchsigwinch;
+
+  return (0);
+}
diff -Naur bash-4.3.orig/lib/sh/shquote.c bash-4.3/lib/sh/shquote.c
--- bash-4.3.orig/lib/sh/shquote.c	2013-04-01 01:53:32.000000000 +0000
+++ bash-4.3/lib/sh/shquote.c	2015-08-16 01:14:31.366291680 +0000
@@ -311,3 +311,17 @@
 
   return (0);
 }
+
+int
+sh_contains_quotes (string)
+     char *string;
+{
+  char *s;
+
+  for (s = string; s && *s; s++)
+    {
+      if (*s == '\'' || *s == '"' || *s == '\\')
+	return 1;
+    }
+  return 0;
+}
diff -Naur bash-4.3.orig/lib/sh/unicode.c bash-4.3/lib/sh/unicode.c
--- bash-4.3.orig/lib/sh/unicode.c	2014-01-30 21:47:19.000000000 +0000
+++ bash-4.3/lib/sh/unicode.c	2015-08-16 01:14:31.582942725 +0000
@@ -78,13 +78,15 @@
   s = strrchr (locale, '.');
   if (s)
     {
-      strcpy (charsetbuf, s+1);
+      strncpy (charsetbuf, s+1, sizeof (charsetbuf) - 1);
+      charsetbuf[sizeof (charsetbuf) - 1] = '\0';
       t = strchr (charsetbuf, '@');
       if (t)
 	*t = 0;
       return charsetbuf;
     }
-  strcpy (charsetbuf, locale);
+  strncpy (charsetbuf, locale, sizeof (charsetbuf) - 1);
+  charsetbuf[sizeof (charsetbuf) - 1] = '\0';
   return charsetbuf;
 }
 #endif
diff -Naur bash-4.3.orig/make_cmd.c bash-4.3/make_cmd.c
--- bash-4.3.orig/make_cmd.c	2011-12-16 13:08:01.000000000 +0000
+++ bash-4.3/make_cmd.c	2015-08-16 01:14:31.539612516 +0000
@@ -692,6 +692,7 @@
   /* First do the common cases. */
   temp->redirector = source;
   temp->redirectee = dest_and_filename;
+  temp->here_doc_eof = 0;
   temp->instruction = instruction;
   temp->flags = 0;
   temp->rflags = flags;
diff -Naur bash-4.3.orig/parse.y bash-4.3/parse.y
--- bash-4.3.orig/parse.y	2014-02-11 14:42:10.000000000 +0000
+++ bash-4.3/parse.y	2015-08-16 01:14:31.602941283 +0000
@@ -168,6 +168,9 @@
 
 static int reserved_word_acceptable __P((int));
 static int yylex __P((void));
+
+static void push_heredoc __P((REDIRECT *));
+static char *mk_alexpansion __P((char *));
 static int alias_expand_token __P((char *));
 static int time_command_acceptable __P((void));
 static int special_case_tokens __P((char *));
@@ -265,7 +268,9 @@
 
 /* Variables to manage the task of reading here documents, because we need to
    defer the reading until after a complete command has been collected. */
-static REDIRECT *redir_stack[10];
+#define HEREDOC_MAX 16
+
+static REDIRECT *redir_stack[HEREDOC_MAX];
 int need_here_doc;
 
 /* Where shell input comes from.  History expansion is performed on each
@@ -307,7 +312,7 @@
    or `for WORD' begins.  This is a nested command maximum, since the array
    index is decremented after a case, select, or for command is parsed. */
 #define MAX_CASE_NEST	128
-static int word_lineno[MAX_CASE_NEST];
+static int word_lineno[MAX_CASE_NEST+1];
 static int word_top = -1;
 
 /* If non-zero, it is the token that we want read_token to return
@@ -520,42 +525,42 @@
 			  source.dest = 0;
 			  redir.filename = $2;
 			  $$ = make_redirection (source, r_reading_until, redir, 0);
-			  redir_stack[need_here_doc++] = $$;
+			  push_heredoc ($$);
 			}
 	|	NUMBER LESS_LESS WORD
 			{
 			  source.dest = $1;
 			  redir.filename = $3;
 			  $$ = make_redirection (source, r_reading_until, redir, 0);
-			  redir_stack[need_here_doc++] = $$;
+			  push_heredoc ($$);
 			}
 	|	REDIR_WORD LESS_LESS WORD
 			{
 			  source.filename = $1;
 			  redir.filename = $3;
 			  $$ = make_redirection (source, r_reading_until, redir, REDIR_VARASSIGN);
-			  redir_stack[need_here_doc++] = $$;
+			  push_heredoc ($$);
 			}
 	|	LESS_LESS_MINUS WORD
 			{
 			  source.dest = 0;
 			  redir.filename = $2;
 			  $$ = make_redirection (source, r_deblank_reading_until, redir, 0);
-			  redir_stack[need_here_doc++] = $$;
+			  push_heredoc ($$);
 			}
 	|	NUMBER LESS_LESS_MINUS WORD
 			{
 			  source.dest = $1;
 			  redir.filename = $3;
 			  $$ = make_redirection (source, r_deblank_reading_until, redir, 0);
-			  redir_stack[need_here_doc++] = $$;
+			  push_heredoc ($$);
 			}
 	|	REDIR_WORD  LESS_LESS_MINUS WORD
 			{
 			  source.filename = $1;
 			  redir.filename = $3;
 			  $$ = make_redirection (source, r_deblank_reading_until, redir, REDIR_VARASSIGN);
-			  redir_stack[need_here_doc++] = $$;
+			  push_heredoc ($$);
 			}
 	|	LESS_LESS_LESS WORD
 			{
@@ -2424,7 +2429,7 @@
 	 not already end in an EOF character.  */
       if (shell_input_line_terminator != EOF)
 	{
-	  if (shell_input_line_size < SIZE_MAX && shell_input_line_len > shell_input_line_size - 3)
+	  if (shell_input_line_size < SIZE_MAX-3 && (shell_input_line_len+3 > shell_input_line_size))
 	    shell_input_line = (char *)xrealloc (shell_input_line,
 					1 + (shell_input_line_size += 2));
 
@@ -2533,6 +2538,16 @@
     eol_ungetc_lookahead = c;
 }
 
+char *
+parser_remaining_input ()
+{
+  if (shell_input_line == 0)
+    return 0;
+  if (shell_input_line_index < 0 || shell_input_line_index >= shell_input_line_len)
+    return '\0';	/* XXX */
+  return (shell_input_line + shell_input_line_index);
+}
+
 #ifdef INCLUDE_UNUSED
 /* Back the input pointer up by one, effectively `ungetting' a character. */
 static void
@@ -2636,13 +2651,28 @@
    which allow ESAC to be the next one read. */
 static int esacs_needed_count;
 
+static void
+push_heredoc (r)
+     REDIRECT *r;
+{
+  if (need_here_doc >= HEREDOC_MAX)
+    {
+      last_command_exit_value = EX_BADUSAGE;
+      need_here_doc = 0;
+      report_syntax_error (_("maximum here-document count exceeded"));
+      reset_parser ();
+      exit_shell (last_command_exit_value);
+    }
+  redir_stack[need_here_doc++] = r;
+}
+
 void
 gather_here_documents ()
 {
   int r;
 
   r = 0;
-  while (need_here_doc)
+  while (need_here_doc > 0)
     {
       parser_state |= PST_HEREDOC;
       make_here_document (redir_stack[r++], line_number);
@@ -2788,11 +2818,16 @@
     case AND_AND:
     case OR_OR:
     case '&':
+    case WHILE:
     case DO:
+    case UNTIL:
+    case IF:
     case THEN:
+    case ELIF:
     case ELSE:
     case '{':		/* } */
-    case '(':		/* ) */
+    case '(':		/* )( */
+    case ')':		/* only valid in case statement */
     case BANG:		/* ! time pipeline */
     case TIME:		/* time time pipeline */
     case TIMEOPT:	/* time -p time pipeline */
@@ -2953,6 +2988,8 @@
   FREE (word_desc_to_read);
   word_desc_to_read = (WORD_DESC *)NULL;
 
+  eol_ungetc_lookahead = 0;
+
   current_token = '\n';		/* XXX */
   last_read_token = '\n';
   token_to_read = '\n';
@@ -3398,7 +3435,7 @@
          within a double-quoted ${...} construct "an even number of
          unescaped double-quotes or single-quotes, if any, shall occur." */
       /* This was changed in Austin Group Interp 221 */
-      if MBTEST(posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE && (flags & P_DQUOTE) && (flags & P_DOLBRACE) && ch == '\'')
+      if MBTEST(posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE && dolbrace_state != DOLBRACE_QUOTE2 && (flags & P_DQUOTE) && (flags & P_DOLBRACE) && ch == '\'')
 	continue;
 
       /* Could also check open == '`' if we want to parse grouping constructs
@@ -3671,6 +3708,8 @@
 /*itrace("parse_comsub:%d: lex_inword -> 1 ch = `%c' (%d)", line_number, ch, __LINE__);*/
 	      tflags |= LEX_INWORD;
 	      lex_wlen = 0;
+	      if (tflags & LEX_RESWDOK)
+		lex_rwlen = 0;
 	    }
 	}
 
@@ -4005,8 +4044,8 @@
   reset_parser ();
   /* reset_parser clears shell_input_line and associated variables */
   restore_input_line_state (&ls);
-  if (interactive)
-    token_to_read = 0;
+
+  token_to_read = 0;
 
   /* Need to find how many characters parse_and_execute consumed, update
      *indp, if flags != 0, copy the portion of the string parsed into RET
@@ -6075,6 +6114,7 @@
 
   ps->expand_aliases = expand_aliases;
   ps->echo_input_at_read = echo_input_at_read;
+  ps->need_here_doc = need_here_doc;
 
   ps->token = token;
   ps->token_buffer_size = token_buffer_size;
@@ -6123,6 +6163,7 @@
 
   expand_aliases = ps->expand_aliases;
   echo_input_at_read = ps->echo_input_at_read;
+  need_here_doc = ps->need_here_doc;
 
   FREE (token);
   token = ps->token;
diff -Naur bash-4.3.orig/patchlevel.h bash-4.3/patchlevel.h
--- bash-4.3.orig/patchlevel.h	2012-12-29 15:47:57.000000000 +0000
+++ bash-4.3/patchlevel.h	2015-08-16 01:14:31.606274377 +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 42
 
 #endif /* _PATCHLEVEL_H_ */
diff -Naur bash-4.3.orig/pcomplete.c bash-4.3/pcomplete.c
--- bash-4.3.orig/pcomplete.c	2013-08-26 19:23:45.000000000 +0000
+++ bash-4.3/pcomplete.c	2015-08-16 01:14:31.366291680 +0000
@@ -183,6 +183,7 @@
 
 COMPSPEC *pcomp_curcs;
 const char *pcomp_curcmd;
+const char *pcomp_curtxt;
 
 #ifdef DEBUG
 /* Debugging code */
@@ -753,6 +754,32 @@
 	     quoted strings. */
 	  dfn = (*rl_filename_dequoting_function) ((char *)text, rl_completion_quote_character);
 	}
+      /* Intended to solve a mismatched assumption by bash-completion.  If
+	 the text to be completed is empty, but bash-completion turns it into
+	 a quoted string ('') assuming that this code will dequote it before
+	 calling readline, do the dequoting. */
+      else if (iscompgen && iscompleting &&
+	       pcomp_curtxt && *pcomp_curtxt == 0 &&
+	       text && (*text == '\'' || *text == '"') && text[1] == text[0] && text[2] == 0 && 
+	       rl_filename_dequoting_function)
+	dfn = (*rl_filename_dequoting_function) ((char *)text, rl_completion_quote_character);
+      /* Another mismatched assumption by bash-completion.  If compgen is being
+      	 run as part of bash-completion, and the argument to compgen is not
+      	 the same as the word originally passed to the programmable completion
+      	 code, dequote the argument if it has quote characters.  It's an
+      	 attempt to detect when bash-completion is quoting its filename
+      	 argument before calling compgen. */
+      /* We could check whether gen_shell_function_matches is in the call
+	 stack by checking whether the gen-shell-function-matches tag is in
+	 the unwind-protect stack, but there's no function to do that yet.
+	 We could simply check whether we're executing in a function by
+	 checking variable_context, and may end up doing that. */
+      else if (iscompgen && iscompleting && rl_filename_dequoting_function &&
+	       pcomp_curtxt && text &&
+	       STREQ (pcomp_curtxt, text) == 0 &&
+	       variable_context &&
+	       sh_contains_quotes (text))	/* guess */
+	dfn = (*rl_filename_dequoting_function) ((char *)text, rl_completion_quote_character);
       else
 	dfn = savestring (text);
     }
@@ -1522,7 +1549,7 @@
      COMPSPEC **lastcs;
 {
   COMPSPEC *cs, *oldcs;
-  const char *oldcmd;
+  const char *oldcmd, *oldtxt;
   STRINGLIST *ret;
 
   cs = progcomp_search (ocmd);
@@ -1545,14 +1572,17 @@
 
   oldcs = pcomp_curcs;
   oldcmd = pcomp_curcmd;
+  oldtxt = pcomp_curtxt;
 
   pcomp_curcs = cs;
   pcomp_curcmd = cmd;
+  pcomp_curtxt = word;
 
   ret = gen_compspec_completions (cs, cmd, word, start, end, foundp);
 
   pcomp_curcs = oldcs;
   pcomp_curcmd = oldcmd;
+  pcomp_curtxt = oldtxt;
 
   /* We need to conditionally handle setting *retryp here */
   if (retryp)
diff -Naur bash-4.3.orig/shell.c bash-4.3/shell.c
--- bash-4.3.orig/shell.c	2014-01-14 13:04:32.000000000 +0000
+++ bash-4.3/shell.c	2015-08-16 01:14:31.576276540 +0000
@@ -73,6 +73,7 @@
 #endif
 
 #if defined (READLINE)
+#  include <readline/readline.h>
 #  include "bashline.h"
 #endif
 
@@ -909,6 +910,14 @@
   fflush (stdout);		/* XXX */
   fflush (stderr);
 
+  /* Clean up the terminal if we are in a state where it's been modified. */
+#if defined (READLINE)
+  if (RL_ISSTATE (RL_STATE_TERMPREPPED) && rl_deprep_term_function)
+    (*rl_deprep_term_function) ();
+#endif
+  if (read_tty_modified ())
+    read_tty_cleanup ();
+
   /* Do trap[0] if defined.  Allow it to override the exit status
      passed to us. */
   if (signal_is_trapped (0))
diff -Naur bash-4.3.orig/shell.h bash-4.3/shell.h
--- bash-4.3.orig/shell.h	2012-12-26 02:11:01.000000000 +0000
+++ bash-4.3/shell.h	2015-08-16 01:14:31.542945610 +0000
@@ -168,7 +168,8 @@
   /* flags state affecting the parser */
   int expand_aliases;
   int echo_input_at_read;
-  
+  int need_here_doc;
+
 } sh_parser_state_t;
 
 typedef struct _sh_input_line_state_t {
@@ -179,6 +180,8 @@
 } sh_input_line_state_t;
 
 /* Let's try declaring these here. */
+extern char *parser_remaining_input __P((void));
+
 extern sh_parser_state_t *save_parser_state __P((sh_parser_state_t *));
 extern void restore_parser_state __P((sh_parser_state_t *));
 
diff -Naur bash-4.3.orig/sig.c bash-4.3/sig.c
--- bash-4.3.orig/sig.c	2014-01-10 20:06:06.000000000 +0000
+++ bash-4.3/sig.c	2015-08-16 01:14:31.579609632 +0000
@@ -532,8 +532,10 @@
 #if defined (READLINE)
   /* Set the event hook so readline will call it after the signal handlers
      finish executing, so if this interrupted character input we can get
-     quick response. */
-  if (interactive_shell && interactive && no_line_editing == 0)
+     quick response.  If readline is active or has modified the terminal we
+     need to set this no matter what the signal is, though the check for
+     RL_STATE_TERMPREPPED is possibly redundant. */
+  if (RL_ISSTATE (RL_STATE_SIGHANDLER) || RL_ISSTATE (RL_STATE_TERMPREPPED))
     bashline_set_event_hook ();
 #endif
 
diff -Naur bash-4.3.orig/subst.c bash-4.3/subst.c
--- bash-4.3.orig/subst.c	2014-01-23 21:26:37.000000000 +0000
+++ bash-4.3/subst.c	2015-08-16 01:14:31.596275097 +0000
@@ -1192,12 +1192,18 @@
    Start extracting at (SINDEX) as if we had just seen "<(".
    Make (SINDEX) get the position of the matching ")". */ /*))*/
 char *
-extract_process_subst (string, starter, sindex)
+extract_process_subst (string, starter, sindex, xflags)
      char *string;
      char *starter;
      int *sindex;
+     int xflags;
 {
+#if 0
   return (extract_delimited_string (string, sindex, starter, "(", ")", SX_COMMAND));
+#else
+  xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0);
+  return (xparse_dolparen (string, string+*sindex, sindex, xflags));
+#endif
 }
 #endif /* PROCESS_SUBSTITUTION */
 
@@ -1785,7 +1791,7 @@
 	  si = i + 2;
 	  if (string[si] == '\0')
 	    CQ_RETURN(si);
-	  temp = extract_process_subst (string, (c == '<') ? "<(" : ">(", &si);
+	  temp = extract_process_subst (string, (c == '<') ? "<(" : ">(", &si, 0);
 	  free (temp);		/* no SX_ALLOC here */
 	  i = si;
 	  if (string[i] == '\0')
@@ -3248,8 +3254,10 @@
   if (w->word == 0 || w->word[0] == '\0')
     return ((char *)NULL);
 
+  expand_no_split_dollar_star = 1;
   w->flags |= W_NOSPLIT2;
   l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0);
+  expand_no_split_dollar_star = 0;
   if (l)
     {
       if (special == 0)			/* LHS */
@@ -5774,7 +5782,7 @@
       /* XXX - does this leak if name[@] or name[*]? */
       if (pflags & PF_ASSIGNRHS)
         {
-          temp = array_variable_name (name, &tt, (int *)0);
+          var = array_variable_part (name, &tt, (int *)0);
           if (ALL_ELEMENT_SUB (tt[0]) && tt[1] == ']')
 	    temp = array_value (name, quoted|Q_DOUBLE_QUOTES, 0, &atype, &ind);
 	  else
@@ -7366,7 +7374,13 @@
     }
 
   if (want_indir)
-    tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at);
+    {
+      tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at);
+      /* Turn off the W_ARRAYIND flag because there is no way for this function
+	 to return the index we're supposed to be using. */
+      if (tdesc && tdesc->flags)
+	tdesc->flags &= ~W_ARRAYIND;
+    }
   else
     tdesc = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND|(pflags&(PF_NOSPLIT2|PF_ASSIGNRHS)), &ind);
 
@@ -7847,6 +7861,10 @@
 	 We also want to make sure that splitting is done no matter what --
 	 according to POSIX.2, this expands to a list of the positional
 	 parameters no matter what IFS is set to. */
+      /* XXX - what to do when in a context where word splitting is not
+	 performed? Even when IFS is not the default, posix seems to imply
+	 that we behave like unquoted $* ?  Maybe we should use PF_NOSPLIT2
+	 here. */
       temp = string_list_dollar_at (list, (pflags & PF_ASSIGNRHS) ? (quoted|Q_DOUBLE_QUOTES) : quoted);
 
       tflag |= W_DOLLARAT;
@@ -8029,7 +8047,9 @@
 
 	  goto return0;
 	}
-      else if (var = find_variable_last_nameref (temp1))
+      else if (var && (invisible_p (var) || var_isset (var) == 0))
+	temp = (char *)NULL;
+      else if ((var = find_variable_last_nameref (temp1)) && var_isset (var) && invisible_p (var) == 0)
 	{
 	  temp = nameref_cell (var);
 #if defined (ARRAY_VARS)
@@ -8243,7 +8263,7 @@
 	    else
 	      t_index = sindex + 1; /* skip past both '<' and LPAREN */
 
-	    temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index); /*))*/
+	    temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index, 0); /*))*/
 	    sindex = t_index;
 
 	    /* If the process substitution specification is `<()', we want to
@@ -8816,6 +8836,7 @@
   else
     {
       char *ifs_chars;
+      char *tstring;
 
       ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL;
 
@@ -8830,11 +8851,36 @@
 	 regardless of what else has happened to IFS since the expansion. */
       if (split_on_spaces)
 	list = list_string (istring, " ", 1);	/* XXX quoted == 1? */
+      /* If we have $@ (has_dollar_at != 0) and we are in a context where we
+	 don't want to split the result (W_NOSPLIT2), and we are not quoted,
+	 we have already separated the arguments with the first character of
+	 $IFS.  In this case, we want to return a list with a single word
+	 with the separator possibly replaced with a space (it's what other
+	 shells seem to do).
+	 quoted_dollar_at is internal to this function and is set if we are
+	 passed an argument that is unquoted (quoted == 0) but we encounter a
+	 double-quoted $@ while expanding it. */
+      else if (has_dollar_at && quoted_dollar_at == 0 && ifs_chars && quoted == 0 && (word->flags & W_NOSPLIT2))
+	{
+	  /* Only split and rejoin if we have to */
+	  if (*ifs_chars && *ifs_chars != ' ')
+	    {
+	      list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
+	      tstring = string_list (list);
+	    }
+	  else
+	    tstring = istring;
+	  tword = make_bare_word (tstring);
+	  if (tstring != istring)
+	    free (tstring);
+	  goto set_word_flags;
+	}
       else if (has_dollar_at && ifs_chars)
 	list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
       else
 	{
 	  tword = make_bare_word (istring);
+set_word_flags:
 	  if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED))
 	    tword->flags |= W_QUOTED;
 	  if (word->flags & W_ASSIGNMENT)
diff -Naur bash-4.3.orig/subst.h bash-4.3/subst.h
--- bash-4.3.orig/subst.h	2014-01-12 02:02:27.000000000 +0000
+++ bash-4.3/subst.h	2015-08-16 01:14:31.552944888 +0000
@@ -47,6 +47,7 @@
 #define ASS_MKASSOC	0x0004
 #define ASS_MKGLOBAL	0x0008	/* force global assignment */
 #define ASS_NAMEREF	0x0010	/* assigning to nameref variable */
+#define ASS_FROMREF	0x0020	/* assigning from value of nameref variable */
 
 /* Flags for the string extraction functions. */
 #define SX_NOALLOC	0x0001	/* just skip; don't return substring */
@@ -82,7 +83,7 @@
 /* Extract the <( or >( construct in STRING, and return a new string.
    Start extracting at (SINDEX) as if we had just seen "<(".
    Make (SINDEX) get the position just after the matching ")". */
-extern char *extract_process_subst __P((char *, char *, int *));
+extern char *extract_process_subst __P((char *, char *, int *, int));
 #endif /* PROCESS_SUBSTITUTION */
 
 /* Extract the name of the variable to bind to from the assignment string. */
diff -Naur bash-4.3.orig/test.c bash-4.3/test.c
--- bash-4.3.orig/test.c	2014-02-04 21:52:58.000000000 +0000
+++ bash-4.3/test.c	2015-08-16 01:14:31.289630541 +0000
@@ -646,8 +646,8 @@
       return (v && invisible_p (v) == 0 && var_isset (v) ? TRUE : FALSE);
 
     case 'R':
-      v = find_variable (arg);
-      return (v && invisible_p (v) == 0 && var_isset (v) && nameref_p (v) ? TRUE : FALSE);
+      v = find_variable_noref (arg);
+      return ((v && invisible_p (v) == 0 && var_isset (v) && nameref_p (v)) ? TRUE : FALSE);
     }
 
   /* We can't actually get here, but this shuts up gcc. */
@@ -723,6 +723,7 @@
     case 'o': case 'p': case 'r': case 's': case 't':
     case 'u': case 'v': case 'w': case 'x': case 'z':
     case 'G': case 'L': case 'O': case 'S': case 'N':
+    case 'R':
       return (1);
     }
 
diff -Naur bash-4.3.orig/trap.c bash-4.3/trap.c
--- bash-4.3.orig/trap.c	2014-02-05 15:03:21.000000000 +0000
+++ bash-4.3/trap.c	2015-08-16 01:14:31.292963634 +0000
@@ -920,7 +920,8 @@
       subst_assign_varlist = 0;
 
 #if defined (JOB_CONTROL)
-      save_pipeline (1);	/* XXX only provides one save level */
+      if (sig != DEBUG_TRAP)	/* run_debug_trap does this */
+	save_pipeline (1);	/* XXX only provides one save level */
 #endif
 
       /* If we're in a function, make sure return longjmps come here, too. */
@@ -940,7 +941,8 @@
       trap_exit_value = last_command_exit_value;
 
 #if defined (JOB_CONTROL)
-      restore_pipeline (1);
+      if (sig != DEBUG_TRAP)	/* run_debug_trap does this */
+	restore_pipeline (1);
 #endif
 
       subst_assign_varlist = save_subst_varlist;
diff -Naur bash-4.3.orig/variables.c bash-4.3/variables.c
--- bash-4.3.orig/variables.c	2014-02-14 16:55:12.000000000 +0000
+++ bash-4.3/variables.c	2015-08-16 01:14:31.586275818 +0000
@@ -83,6 +83,11 @@
 
 #define ifsname(s)	((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0')
 
+#define BASHFUNC_PREFIX		"BASH_FUNC_"
+#define BASHFUNC_PREFLEN	10	/* == strlen(BASHFUNC_PREFIX */
+#define BASHFUNC_SUFFIX		"%%"
+#define BASHFUNC_SUFFLEN	2	/* == strlen(BASHFUNC_SUFFIX) */
+
 extern char **environ;
 
 /* Variables used here and defined in other files. */
@@ -279,7 +284,7 @@
 static void propagate_temp_var __P((PTR_T));
 static void dispose_temporary_env __P((sh_free_func_t *));     
 
-static inline char *mk_env_string __P((const char *, const char *));
+static inline char *mk_env_string __P((const char *, const char *, int));
 static char **make_env_array_from_var_list __P((SHELL_VAR **));
 static char **make_var_export_array __P((VAR_CONTEXT *));
 static char **make_func_export_array __P((void));
@@ -349,24 +354,33 @@
 
       /* If exported function, define it now.  Don't import functions from
 	 the environment in privileged mode. */
-      if (privmode == 0 && read_but_dont_execute == 0 && STREQN ("() {", string, 4))
+      if (privmode == 0 && read_but_dont_execute == 0 && 
+          STREQN (BASHFUNC_PREFIX, name, BASHFUNC_PREFLEN) &&
+          STREQ (BASHFUNC_SUFFIX, name + char_index - BASHFUNC_SUFFLEN) &&
+	  STREQN ("() {", string, 4))
 	{
-	  string_length = strlen (string);
-	  temp_string = (char *)xmalloc (3 + string_length + char_index);
+	  size_t namelen;
+	  char *tname;		/* desired imported function name */
 
-	  strcpy (temp_string, name);
-	  temp_string[char_index] = ' ';
-	  strcpy (temp_string + char_index + 1, string);
+	  namelen = char_index - BASHFUNC_PREFLEN - BASHFUNC_SUFFLEN;
 
-	  if (posixly_correct == 0 || legal_identifier (name))
-	    parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST);
+	  tname = name + BASHFUNC_PREFLEN;	/* start of func name */
+	  tname[namelen] = '\0';		/* now tname == func name */
+
+	  string_length = strlen (string);
+	  temp_string = (char *)xmalloc (namelen + string_length + 2);
 
-	  /* Ancient backwards compatibility.  Old versions of bash exported
-	     functions like name()=() {...} */
-	  if (name[char_index - 1] == ')' && name[char_index - 2] == '(')
-	    name[char_index - 2] = '\0';
+	  memcpy (temp_string, tname, namelen);
+	  temp_string[namelen] = ' ';
+	  memcpy (temp_string + namelen + 1, string, string_length + 1);
+
+	  /* Don't import function names that are invalid identifiers from the
+	     environment, though we still allow them to be defined as shell
+	     variables. */
+	  if (absolute_program (tname) == 0 && (posixly_correct == 0 || legal_identifier (tname)))
+	    parse_and_execute (temp_string, tname, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
 
-	  if (temp_var = find_function (name))
+	  if (temp_var = find_function (tname))
 	    {
 	      VSETATTR (temp_var, (att_exported|att_imported));
 	      array_needs_making = 1;
@@ -379,12 +393,11 @@
 		  array_needs_making = 1;
 		}
 	      last_command_exit_value = 1;
-	      report_error (_("error importing function definition for `%s'"), name);
+	      report_error (_("error importing function definition for `%s'"), tname);
 	    }
 
-	  /* ( */
-	  if (name[char_index - 1] == ')' && name[char_index - 2] == '\0')
-	    name[char_index - 2] = '(';		/* ) */
+	  /* Restore original suffix */
+	  tname[namelen] = BASHFUNC_SUFFIX[0];
 	}
 #if defined (ARRAY_VARS)
 #  if ARRAY_EXPORT
@@ -2197,10 +2210,7 @@
   /* 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)
-    {
-      VUNSETATTR (old_var, att_invisible);	/* XXX */
-      return (old_var);
-    }
+    return (old_var);
 
   was_tmpvar = old_var && tempvar_p (old_var);
   /* If we're making a local variable in a shell function, the temporary env
@@ -2506,10 +2516,27 @@
      HASH_TABLE *table;
      int hflags, aflags;
 {
-  char *newval;
+  char *newname, *newval;
   SHELL_VAR *entry;
+#if defined (ARRAY_VARS)
+  arrayind_t ind;
+  char *subp;
+  int sublen;
+#endif
 
+  newname = 0;
+#if defined (ARRAY_VARS)
+  if ((aflags & ASS_FROMREF) && (hflags & HASH_NOSRCH) == 0 && valid_array_reference (name))
+    {
+      newname = array_variable_name (name, &subp, &sublen);
+      if (newname == 0)
+	return (SHELL_VAR *)NULL;	/* XXX */
+      entry = hash_lookup (newname, table);
+    }
+  else
+#endif
   entry = (hflags & HASH_NOSRCH) ? (SHELL_VAR *)NULL : hash_lookup (name, table);
+
   /* Follow the nameref chain here if this is the global variables table */
   if (entry && nameref_p (entry) && (invisible_p (entry) == 0) && table == global_variables->table)
     {
@@ -2540,6 +2567,16 @@
       var_setvalue (entry, make_variable_value (entry, value, 0));
       }
     }
+#if defined (ARRAY_VARS)
+  else if (entry == 0 && newname)
+    {
+      entry = make_new_array_variable (newname);	/* indexed array by default */
+      if (entry == 0)
+	return entry;
+      ind = array_expand_index (name, subp, sublen);
+      bind_array_element (entry, ind, value, aflags);
+    }
+#endif
   else if (entry == 0)
     {
       entry = make_new_variable (name, table);
@@ -2660,7 +2697,8 @@
 			 normal. */
 		      if (nameref_cell (nv) == 0)
 			return (bind_variable_internal (nv->name, value, nvc->table, 0, flags));
-		      return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags));
+		      /* XXX - bug here with ref=array[index] */
+		      return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags|ASS_FROMREF));
 		    }
 		  else
 		    v = nv;
@@ -2795,10 +2833,12 @@
 #endif
     v = bind_variable (lhs, rhs, 0);
 
-  if (v && isint)
-    VSETATTR (v, att_integer);
-
-  VUNSETATTR (v, att_invisible);
+  if (v)
+    {
+      if (isint)
+	VSETATTR (v, att_integer);
+      VUNSETATTR (v, att_invisible);
+    }
 
   return (v);
 }
@@ -2963,7 +3003,7 @@
   var->context = variable_context;	/* XXX */
 
   INVALIDATE_EXPORTSTR (var);
-  var->exportstr = mk_env_string (name, value);
+  var->exportstr = mk_env_string (name, value, 0);
 
   array_needs_making = 1;
 
@@ -3861,21 +3901,42 @@
 /* **************************************************************** */
 
 static inline char *
-mk_env_string (name, value)
+mk_env_string (name, value, isfunc)
      const char *name, *value;
+     int isfunc;
 {
-  int name_len, value_len;
-  char	*p;
+  size_t name_len, value_len;
+  char	*p, *q;
 
   name_len = strlen (name);
   value_len = STRLEN (value);
-  p = (char *)xmalloc (2 + name_len + value_len);
-  strcpy (p, name);
-  p[name_len] = '=';
+
+  /* If we are exporting a shell function, construct the encoded function
+     name. */
+  if (isfunc && value)
+    {
+      p = (char *)xmalloc (BASHFUNC_PREFLEN + name_len + BASHFUNC_SUFFLEN + value_len + 2);
+      q = p;
+      memcpy (q, BASHFUNC_PREFIX, BASHFUNC_PREFLEN);
+      q += BASHFUNC_PREFLEN;
+      memcpy (q, name, name_len);
+      q += name_len;
+      memcpy (q, BASHFUNC_SUFFIX, BASHFUNC_SUFFLEN);
+      q += BASHFUNC_SUFFLEN;
+    }
+  else
+    {
+      p = (char *)xmalloc (2 + name_len + value_len);
+      memcpy (p, name, name_len);
+      q = p + name_len;
+    }
+
+  q[0] = '=';
   if (value && *value)
-    strcpy (p + name_len + 1, value);
+    memcpy (q + 1, value, value_len + 1);
   else
-    p[name_len + 1] = '\0';
+    q[1] = '\0';
+
   return (p);
 }
 
@@ -3961,7 +4022,7 @@
 	  /* Gee, I'd like to get away with not using savestring() if we're
 	     using the cached exportstr... */
 	  list[list_index] = USE_EXPORTSTR ? savestring (value)
-					   : mk_env_string (var->name, value);
+					   : mk_env_string (var->name, value, function_p (var));
 
 	  if (USE_EXPORTSTR == 0)
 	    SAVE_EXPORTSTR (var, list[list_index]);
diff -Naur bash-4.3.orig/variables.c.orig bash-4.3/variables.c.orig
--- bash-4.3.orig/variables.c.orig	1970-01-01 00:00:00.000000000 +0000
+++ bash-4.3/variables.c.orig	2015-08-16 01:14:31.509614679 +0000
@@ -0,0 +1,5365 @@
+/* variables.c -- Functions for hacking shell variables. */
+
+/* Copyright (C) 1987-2013 Free Software Foundation, Inc.
+
+   This file is part of GNU Bash, the Bourne Again SHell.
+
+   Bash is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   Bash is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with Bash.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "config.h"
+
+#include "bashtypes.h"
+#include "posixstat.h"
+#include "posixtime.h"
+
+#if defined (__QNX__)
+#  if defined (__QNXNTO__)
+#    include <sys/netmgr.h>
+#  else
+#    include <sys/vc.h>
+#  endif /* !__QNXNTO__ */
+#endif /* __QNX__ */
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include "chartypes.h"
+#if defined (HAVE_PWD_H)
+#  include <pwd.h>
+#endif
+#include "bashansi.h"
+#include "bashintl.h"
+
+#define NEED_XTRACE_SET_DECL
+
+#include "shell.h"
+#include "flags.h"
+#include "execute_cmd.h"
+#include "findcmd.h"
+#include "mailcheck.h"
+#include "input.h"
+#include "hashcmd.h"
+#include "pathexp.h"
+#include "alias.h"
+#include "jobs.h"
+
+#include "version.h"
+
+#include "builtins/getopt.h"
+#include "builtins/common.h"
+#include "builtins/builtext.h"
+
+#if defined (READLINE)
+#  include "bashline.h"
+#  include <readline/readline.h>
+#else
+#  include <tilde/tilde.h>
+#endif
+
+#if defined (HISTORY)
+#  include "bashhist.h"
+#  include <readline/history.h>
+#endif /* HISTORY */
+
+#if defined (PROGRAMMABLE_COMPLETION)
+#  include "pcomplete.h"
+#endif
+
+#define TEMPENV_HASH_BUCKETS	4	/* must be power of two */
+
+#define ifsname(s)	((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0')
+
+#define BASHFUNC_PREFIX		"BASH_FUNC_"
+#define BASHFUNC_PREFLEN	10	/* == strlen(BASHFUNC_PREFIX */
+#define BASHFUNC_SUFFIX		"%%"
+#define BASHFUNC_SUFFLEN	2	/* == strlen(BASHFUNC_SUFFIX) */
+
+extern char **environ;
+
+/* Variables used here and defined in other files. */
+extern int posixly_correct;
+extern int line_number, line_number_base;
+extern int subshell_environment, indirection_level, subshell_level;
+extern int build_version, patch_level;
+extern int expanding_redir;
+extern int last_command_exit_value;
+extern char *dist_version, *release_status;
+extern char *shell_name;
+extern char *primary_prompt, *secondary_prompt;
+extern char *current_host_name;
+extern sh_builtin_func_t *this_shell_builtin;
+extern SHELL_VAR *this_shell_function;
+extern char *the_printed_command_except_trap;
+extern char *this_command_name;
+extern char *command_execution_string;
+extern time_t shell_start_time;
+extern int assigning_in_environment;
+extern int executing_builtin;
+extern int funcnest_max;
+
+#if defined (READLINE)
+extern int no_line_editing;
+extern int perform_hostname_completion;
+#endif
+
+/* The list of shell variables that the user has created at the global
+   scope, or that came from the environment. */
+VAR_CONTEXT *global_variables = (VAR_CONTEXT *)NULL;
+
+/* The current list of shell variables, including function scopes */
+VAR_CONTEXT *shell_variables = (VAR_CONTEXT *)NULL;
+
+/* The list of shell functions that the user has created, or that came from
+   the environment. */
+HASH_TABLE *shell_functions = (HASH_TABLE *)NULL;
+
+#if defined (DEBUGGER)
+/* The table of shell function definitions that the user defined or that
+   came from the environment. */
+HASH_TABLE *shell_function_defs = (HASH_TABLE *)NULL;
+#endif
+
+/* The current variable context.  This is really a count of how deep into
+   executing functions we are. */
+int variable_context = 0;
+
+/* The set of shell assignments which are made only in the environment
+   for a single command. */
+HASH_TABLE *temporary_env = (HASH_TABLE *)NULL;
+
+/* Set to non-zero if an assignment error occurs while putting variables
+   into the temporary environment. */
+int tempenv_assign_error;
+
+/* Some funky variables which are known about specially.  Here is where
+   "$*", "$1", and all the cruft is kept. */
+char *dollar_vars[10];
+WORD_LIST *rest_of_args = (WORD_LIST *)NULL;
+
+/* The value of $$. */
+pid_t dollar_dollar_pid;
+
+/* Non-zero means that we have to remake EXPORT_ENV. */
+int array_needs_making = 1;
+
+/* The number of times BASH has been executed.  This is set
+   by initialize_variables (). */
+int shell_level = 0;
+
+/* An array which is passed to commands as their environment.  It is
+   manufactured from the union of the initial environment and the
+   shell variables that are marked for export. */
+char **export_env = (char **)NULL;
+static int export_env_index;
+static int export_env_size;
+
+#if defined (READLINE)
+static int winsize_assignment;		/* currently assigning to LINES or COLUMNS */
+#endif
+
+static HASH_TABLE *last_table_searched;	/* hash_lookup sets this */
+
+/* Some forward declarations. */
+static void create_variable_tables __P((void));
+
+static void set_machine_vars __P((void));
+static void set_home_var __P((void));
+static void set_shell_var __P((void));
+static char *get_bash_name __P((void));
+static void initialize_shell_level __P((void));
+static void uidset __P((void));
+#if defined (ARRAY_VARS)
+static void make_vers_array __P((void));
+#endif
+
+static SHELL_VAR *null_assign __P((SHELL_VAR *, char *, arrayind_t, char *));
+#if defined (ARRAY_VARS)
+static SHELL_VAR *null_array_assign __P((SHELL_VAR *, char *, arrayind_t, char *));
+#endif
+static SHELL_VAR *get_self __P((SHELL_VAR *));
+
+#if defined (ARRAY_VARS)
+static SHELL_VAR *init_dynamic_array_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int));
+static SHELL_VAR *init_dynamic_assoc_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int));
+#endif
+
+static SHELL_VAR *assign_seconds __P((SHELL_VAR *, char *, arrayind_t, char *));
+static SHELL_VAR *get_seconds __P((SHELL_VAR *));
+static SHELL_VAR *init_seconds_var __P((void));
+
+static int brand __P((void));
+static void sbrand __P((unsigned long));		/* set bash random number generator. */
+static void seedrand __P((void));			/* seed generator randomly */
+static SHELL_VAR *assign_random __P((SHELL_VAR *, char *, arrayind_t, char *));
+static SHELL_VAR *get_random __P((SHELL_VAR *));
+
+static SHELL_VAR *assign_lineno __P((SHELL_VAR *, char *, arrayind_t, char *));
+static SHELL_VAR *get_lineno __P((SHELL_VAR *));
+
+static SHELL_VAR *assign_subshell __P((SHELL_VAR *, char *, arrayind_t, char *));
+static SHELL_VAR *get_subshell __P((SHELL_VAR *));
+
+static SHELL_VAR *get_bashpid __P((SHELL_VAR *));
+
+#if defined (HISTORY)
+static SHELL_VAR *get_histcmd __P((SHELL_VAR *));
+#endif
+
+#if defined (READLINE)
+static SHELL_VAR *get_comp_wordbreaks __P((SHELL_VAR *));
+static SHELL_VAR *assign_comp_wordbreaks __P((SHELL_VAR *, char *, arrayind_t, char *));
+#endif
+
+#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
+static SHELL_VAR *assign_dirstack __P((SHELL_VAR *, char *, arrayind_t, char *));
+static SHELL_VAR *get_dirstack __P((SHELL_VAR *));
+#endif
+
+#if defined (ARRAY_VARS)
+static SHELL_VAR *get_groupset __P((SHELL_VAR *));
+
+static SHELL_VAR *build_hashcmd __P((SHELL_VAR *));
+static SHELL_VAR *get_hashcmd __P((SHELL_VAR *));
+static SHELL_VAR *assign_hashcmd __P((SHELL_VAR *,  char *, arrayind_t, char *));
+#  if defined (ALIAS)
+static SHELL_VAR *build_aliasvar __P((SHELL_VAR *));
+static SHELL_VAR *get_aliasvar __P((SHELL_VAR *));
+static SHELL_VAR *assign_aliasvar __P((SHELL_VAR *,  char *, arrayind_t, char *));
+#  endif
+#endif
+
+static SHELL_VAR *get_funcname __P((SHELL_VAR *));
+static SHELL_VAR *init_funcname_var __P((void));
+
+static void initialize_dynamic_variables __P((void));
+
+static SHELL_VAR *hash_lookup __P((const char *, HASH_TABLE *));
+static SHELL_VAR *new_shell_variable __P((const char *));
+static SHELL_VAR *make_new_variable __P((const char *, HASH_TABLE *));
+static SHELL_VAR *bind_variable_internal __P((const char *, char *, HASH_TABLE *, int, int));
+
+static void dispose_variable_value __P((SHELL_VAR *));
+static void free_variable_hash_data __P((PTR_T));
+
+static VARLIST *vlist_alloc __P((int));
+static VARLIST *vlist_realloc __P((VARLIST *, int));
+static void vlist_add __P((VARLIST *, SHELL_VAR *, int));
+
+static void flatten __P((HASH_TABLE *, sh_var_map_func_t *, VARLIST *, int));
+
+static int qsort_var_comp __P((SHELL_VAR **, SHELL_VAR **));
+
+static SHELL_VAR **vapply __P((sh_var_map_func_t *));
+static SHELL_VAR **fapply __P((sh_var_map_func_t *));
+
+static int visible_var __P((SHELL_VAR *));
+static int visible_and_exported __P((SHELL_VAR *));
+static int export_environment_candidate __P((SHELL_VAR *));
+static int local_and_exported __P((SHELL_VAR *));
+static int variable_in_context __P((SHELL_VAR *));
+#if defined (ARRAY_VARS)
+static int visible_array_vars __P((SHELL_VAR *));
+#endif
+
+static SHELL_VAR *find_nameref_at_context __P((SHELL_VAR *, VAR_CONTEXT *));
+static SHELL_VAR *find_variable_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **));
+static SHELL_VAR *find_variable_last_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **));
+
+static SHELL_VAR *bind_tempenv_variable __P((const char *, char *));
+static void push_temp_var __P((PTR_T));
+static void propagate_temp_var __P((PTR_T));
+static void dispose_temporary_env __P((sh_free_func_t *));     
+
+static inline char *mk_env_string __P((const char *, const char *, int));
+static char **make_env_array_from_var_list __P((SHELL_VAR **));
+static char **make_var_export_array __P((VAR_CONTEXT *));
+static char **make_func_export_array __P((void));
+static void add_temp_array_to_env __P((char **, int, int));
+
+static int n_shell_variables __P((void));
+static int set_context __P((SHELL_VAR *));
+
+static void push_func_var __P((PTR_T));
+static void push_exported_var __P((PTR_T));
+
+static inline int find_special_var __P((const char *));
+
+static void
+create_variable_tables ()
+{
+  if (shell_variables == 0)
+    {
+      shell_variables = global_variables = new_var_context ((char *)NULL, 0);
+      shell_variables->scope = 0;
+      shell_variables->table = hash_create (0);
+    }
+
+  if (shell_functions == 0)
+    shell_functions = hash_create (0);
+
+#if defined (DEBUGGER)
+  if (shell_function_defs == 0)
+    shell_function_defs = hash_create (0);
+#endif
+}
+
+/* Initialize the shell variables from the current environment.
+   If PRIVMODE is nonzero, don't import functions from ENV or
+   parse $SHELLOPTS. */
+void
+initialize_shell_variables (env, privmode)
+     char **env;
+     int privmode;
+{
+  char *name, *string, *temp_string;
+  int c, char_index, string_index, string_length, ro;
+  SHELL_VAR *temp_var;
+
+  create_variable_tables ();
+
+  for (string_index = 0; string = env[string_index++]; )
+    {
+      char_index = 0;
+      name = string;
+      while ((c = *string++) && c != '=')
+	;
+      if (string[-1] == '=')
+	char_index = string - name - 1;
+
+      /* If there are weird things in the environment, like `=xxx' or a
+	 string without an `=', just skip them. */
+      if (char_index == 0)
+	continue;
+
+      /* ASSERT(name[char_index] == '=') */
+      name[char_index] = '\0';
+      /* Now, name = env variable name, string = env variable value, and
+	 char_index == strlen (name) */
+
+      temp_var = (SHELL_VAR *)NULL;
+
+      /* If exported function, define it now.  Don't import functions from
+	 the environment in privileged mode. */
+      if (privmode == 0 && read_but_dont_execute == 0 && 
+          STREQN (BASHFUNC_PREFIX, name, BASHFUNC_PREFLEN) &&
+          STREQ (BASHFUNC_SUFFIX, name + char_index - BASHFUNC_SUFFLEN) &&
+	  STREQN ("() {", string, 4))
+	{
+	  size_t namelen;
+	  char *tname;		/* desired imported function name */
+
+	  namelen = char_index - BASHFUNC_PREFLEN - BASHFUNC_SUFFLEN;
+
+	  tname = name + BASHFUNC_PREFLEN;	/* start of func name */
+	  tname[namelen] = '\0';		/* now tname == func name */
+
+	  string_length = strlen (string);
+	  temp_string = (char *)xmalloc (namelen + string_length + 2);
+
+	  memcpy (temp_string, tname, namelen);
+	  temp_string[namelen] = ' ';
+	  memcpy (temp_string + namelen + 1, string, string_length + 1);
+
+	  /* Don't import function names that are invalid identifiers from the
+	     environment, though we still allow them to be defined as shell
+	     variables. */
+	  if (absolute_program (tname) == 0 && (posixly_correct == 0 || legal_identifier (tname)))
+	    parse_and_execute (temp_string, tname, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
+
+	  if (temp_var = find_function (tname))
+	    {
+	      VSETATTR (temp_var, (att_exported|att_imported));
+	      array_needs_making = 1;
+	    }
+	  else
+	    {
+	      if (temp_var = bind_variable (name, string, 0))
+		{
+		  VSETATTR (temp_var, (att_exported | att_imported | att_invisible));
+		  array_needs_making = 1;
+		}
+	      last_command_exit_value = 1;
+	      report_error (_("error importing function definition for `%s'"), tname);
+	    }
+
+	  /* Restore original suffix */
+	  tname[namelen] = BASHFUNC_SUFFIX[0];
+	}
+#if defined (ARRAY_VARS)
+#  if ARRAY_EXPORT
+      /* Array variables may not yet be exported. */
+      else if (*string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')')
+	{
+	  string_length = 1;
+	  temp_string = extract_array_assignment_list (string, &string_length);
+	  temp_var = assign_array_from_string (name, temp_string);
+	  FREE (temp_string);
+	  VSETATTR (temp_var, (att_exported | att_imported));
+	  array_needs_making = 1;
+	}
+#  endif /* ARRAY_EXPORT */
+#endif
+#if 0
+      else if (legal_identifier (name))
+#else
+      else
+#endif
+	{
+	  ro = 0;
+	  if (posixly_correct && STREQ (name, "SHELLOPTS"))
+	    {
+	      temp_var = find_variable ("SHELLOPTS");
+	      ro = temp_var && readonly_p (temp_var);
+	      if (temp_var)
+		VUNSETATTR (temp_var, att_readonly);
+	    }
+	  temp_var = bind_variable (name, string, 0);
+	  if (temp_var)
+	    {
+	      if (legal_identifier (name))
+		VSETATTR (temp_var, (att_exported | att_imported));
+	      else
+		VSETATTR (temp_var, (att_exported | att_imported | att_invisible));
+	      if (ro)
+		VSETATTR (temp_var, att_readonly);
+	      array_needs_making = 1;
+	    }
+	}
+
+      name[char_index] = '=';
+      /* temp_var can be NULL if it was an exported function with a syntax
+	 error (a different bug, but it still shouldn't dump core). */
+      if (temp_var && function_p (temp_var) == 0)	/* XXX not yet */
+	{
+	  CACHE_IMPORTSTR (temp_var, name);
+	}
+    }
+
+  set_pwd ();
+
+  /* Set up initial value of $_ */
+  temp_var = set_if_not ("_", dollar_vars[0]);
+
+  /* Remember this pid. */
+  dollar_dollar_pid = getpid ();
+
+  /* Now make our own defaults in case the vars that we think are
+     important are missing. */
+  temp_var = set_if_not ("PATH", DEFAULT_PATH_VALUE);
+#if 0
+  set_auto_export (temp_var);	/* XXX */
+#endif
+
+  temp_var = set_if_not ("TERM", "dumb");
+#if 0
+  set_auto_export (temp_var);	/* XXX */
+#endif
+
+#if defined (__QNX__)
+  /* set node id -- don't import it from the environment */
+  {
+    char node_name[22];
+#  if defined (__QNXNTO__)
+    netmgr_ndtostr(ND2S_LOCAL_STR, ND_LOCAL_NODE, node_name, sizeof(node_name));
+#  else
+    qnx_nidtostr (getnid (), node_name, sizeof (node_name));
+#  endif
+    temp_var = bind_variable ("NODE", node_name, 0);
+    set_auto_export (temp_var);
+  }
+#endif
+
+  /* set up the prompts. */
+  if (interactive_shell)
+    {
+#if defined (PROMPT_STRING_DECODE)
+      set_if_not ("PS1", primary_prompt);
+#else
+      if (current_user.uid == -1)
+	get_current_user_info ();
+      set_if_not ("PS1", current_user.euid == 0 ? "# " : primary_prompt);
+#endif
+      set_if_not ("PS2", secondary_prompt);
+    }
+  set_if_not ("PS4", "+ ");
+
+  /* Don't allow IFS to be imported from the environment. */
+  temp_var = bind_variable ("IFS", " \t\n", 0);
+  setifs (temp_var);
+
+  /* Magic machine types.  Pretty convenient. */
+  set_machine_vars ();
+
+  /* Default MAILCHECK for interactive shells.  Defer the creation of a
+     default MAILPATH until the startup files are read, because MAIL
+     names a mail file if MAILPATH is not set, and we should provide a
+     default only if neither is set. */
+  if (interactive_shell)
+    {
+      temp_var = set_if_not ("MAILCHECK", posixly_correct ? "600" : "60");
+      VSETATTR (temp_var, att_integer);
+    }
+
+  /* Do some things with shell level. */
+  initialize_shell_level ();
+
+  set_ppid ();
+
+  /* Initialize the `getopts' stuff. */
+  temp_var = bind_variable ("OPTIND", "1", 0);
+  VSETATTR (temp_var, att_integer);
+  getopts_reset (0);
+  bind_variable ("OPTERR", "1", 0);
+  sh_opterr = 1;
+
+  if (login_shell == 1 && posixly_correct == 0)
+    set_home_var ();
+
+  /* Get the full pathname to THIS shell, and set the BASH variable
+     to it. */
+  name = get_bash_name ();
+  temp_var = bind_variable ("BASH", name, 0);
+  free (name);
+
+  /* Make the exported environment variable SHELL be the user's login
+     shell.  Note that the `tset' command looks at this variable
+     to determine what style of commands to output; if it ends in "csh",
+     then C-shell commands are output, else Bourne shell commands. */
+  set_shell_var ();
+
+  /* Make a variable called BASH_VERSION which contains the version info. */
+  bind_variable ("BASH_VERSION", shell_version_string (), 0);
+#if defined (ARRAY_VARS)
+  make_vers_array ();
+#endif
+
+  if (command_execution_string)
+    bind_variable ("BASH_EXECUTION_STRING", command_execution_string, 0);
+
+  /* Find out if we're supposed to be in Posix.2 mode via an
+     environment variable. */
+  temp_var = find_variable ("POSIXLY_CORRECT");
+  if (!temp_var)
+    temp_var = find_variable ("POSIX_PEDANTIC");
+  if (temp_var && imported_p (temp_var))
+    sv_strict_posix (temp_var->name);
+
+#if defined (HISTORY)
+  /* Set history variables to defaults, and then do whatever we would
+     do if the variable had just been set.  Do this only in the case
+     that we are remembering commands on the history list. */
+  if (remember_on_history)
+    {
+      name = bash_tilde_expand (posixly_correct ? "~/.sh_history" : "~/.bash_history", 0);
+
+      set_if_not ("HISTFILE", name);
+      free (name);
+    }
+#endif /* HISTORY */
+
+  /* Seed the random number generator. */
+  seedrand ();
+
+  /* Handle some "special" variables that we may have inherited from a
+     parent shell. */
+  if (interactive_shell)
+    {
+      temp_var = find_variable ("IGNOREEOF");
+      if (!temp_var)
+	temp_var = find_variable ("ignoreeof");
+      if (temp_var && imported_p (temp_var))
+	sv_ignoreeof (temp_var->name);
+    }
+
+#if defined (HISTORY)
+  if (interactive_shell && remember_on_history)
+    {
+      sv_history_control ("HISTCONTROL");
+      sv_histignore ("HISTIGNORE");
+      sv_histtimefmt ("HISTTIMEFORMAT");
+    }
+#endif /* HISTORY */
+
+#if defined (READLINE) && defined (STRICT_POSIX)
+  /* POSIXLY_CORRECT will only be 1 here if the shell was compiled
+     -DSTRICT_POSIX */
+  if (interactive_shell && posixly_correct && no_line_editing == 0)
+    rl_prefer_env_winsize = 1;
+#endif /* READLINE && STRICT_POSIX */
+
+     /*
+      * 24 October 2001
+      *
+      * I'm tired of the arguing and bug reports.  Bash now leaves SSH_CLIENT
+      * and SSH2_CLIENT alone.  I'm going to rely on the shell_level check in
+      * isnetconn() to avoid running the startup files more often than wanted.
+      * That will, of course, only work if the user's login shell is bash, so
+      * I've made that behavior conditional on SSH_SOURCE_BASHRC being defined
+      * in config-top.h.
+      */
+#if 0
+  temp_var = find_variable ("SSH_CLIENT");
+  if (temp_var && imported_p (temp_var))
+    {
+      VUNSETATTR (temp_var, att_exported);
+      array_needs_making = 1;
+    }
+  temp_var = find_variable ("SSH2_CLIENT");
+  if (temp_var && imported_p (temp_var))
+    {
+      VUNSETATTR (temp_var, att_exported);
+      array_needs_making = 1;
+    }
+#endif
+
+  /* Get the user's real and effective user ids. */
+  uidset ();
+
+  temp_var = find_variable ("BASH_XTRACEFD");
+  if (temp_var && imported_p (temp_var))
+    sv_xtracefd (temp_var->name);
+
+  /* Initialize the dynamic variables, and seed their values. */
+  initialize_dynamic_variables ();
+}
+
+/* **************************************************************** */
+/*								    */
+/*	     Setting values for special shell variables		    */
+/*								    */
+/* **************************************************************** */
+
+static void
+set_machine_vars ()
+{
+  SHELL_VAR *temp_var;
+
+  temp_var = set_if_not ("HOSTTYPE", HOSTTYPE);
+  temp_var = set_if_not ("OSTYPE", OSTYPE);
+  temp_var = set_if_not ("MACHTYPE", MACHTYPE);
+
+  temp_var = set_if_not ("HOSTNAME", current_host_name);
+}
+
+/* Set $HOME to the information in the password file if we didn't get
+   it from the environment. */
+
+/* This function is not static so the tilde and readline libraries can
+   use it. */
+char *
+sh_get_home_dir ()
+{
+  if (current_user.home_dir == 0)
+    get_current_user_info ();
+  return current_user.home_dir;
+}
+
+static void
+set_home_var ()
+{
+  SHELL_VAR *temp_var;
+
+  temp_var = find_variable ("HOME");
+  if (temp_var == 0)
+    temp_var = bind_variable ("HOME", sh_get_home_dir (), 0);
+#if 0
+  VSETATTR (temp_var, att_exported);
+#endif
+}
+
+/* Set $SHELL to the user's login shell if it is not already set.  Call
+   get_current_user_info if we haven't already fetched the shell. */
+static void
+set_shell_var ()
+{
+  SHELL_VAR *temp_var;
+
+  temp_var = find_variable ("SHELL");
+  if (temp_var == 0)
+    {
+      if (current_user.shell == 0)
+	get_current_user_info ();
+      temp_var = bind_variable ("SHELL", current_user.shell, 0);
+    }
+#if 0
+  VSETATTR (temp_var, att_exported);
+#endif
+}
+
+static char *
+get_bash_name ()
+{
+  char *name;
+
+  if ((login_shell == 1) && RELPATH(shell_name))
+    {
+      if (current_user.shell == 0)
+	get_current_user_info ();
+      name = savestring (current_user.shell);
+    }
+  else if (ABSPATH(shell_name))
+    name = savestring (shell_name);
+  else if (shell_name[0] == '.' && shell_name[1] == '/')
+    {
+      /* Fast path for common case. */
+      char *cdir;
+      int len;
+
+      cdir = get_string_value ("PWD");
+      if (cdir)
+	{
+	  len = strlen (cdir);
+	  name = (char *)xmalloc (len + strlen (shell_name) + 1);
+	  strcpy (name, cdir);
+	  strcpy (name + len, shell_name + 1);
+	}
+      else
+	name = savestring (shell_name);
+    }
+  else
+    {
+      char *tname;
+      int s;
+
+      tname = find_user_command (shell_name);
+
+      if (tname == 0)
+	{
+	  /* Try the current directory.  If there is not an executable
+	     there, just punt and use the login shell. */
+	  s = file_status (shell_name);
+	  if (s & FS_EXECABLE)
+	    {
+	      tname = make_absolute (shell_name, get_string_value ("PWD"));
+	      if (*shell_name == '.')
+		{
+		  name = sh_canonpath (tname, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
+		  if (name == 0)
+		    name = tname;
+		  else
+		    free (tname);
+		}
+	     else
+		name = tname;
+	    }
+	  else
+	    {
+	      if (current_user.shell == 0)
+		get_current_user_info ();
+	      name = savestring (current_user.shell);
+	    }
+	}
+      else
+	{
+	  name = full_pathname (tname);
+	  free (tname);
+	}
+    }
+
+  return (name);
+}
+
+void
+adjust_shell_level (change)
+     int change;
+{
+  char new_level[5], *old_SHLVL;
+  intmax_t old_level;
+  SHELL_VAR *temp_var;
+
+  old_SHLVL = get_string_value ("SHLVL");
+  if (old_SHLVL == 0 || *old_SHLVL == '\0' || legal_number (old_SHLVL, &old_level) == 0)
+    old_level = 0;
+
+  shell_level = old_level + change;
+  if (shell_level < 0)
+    shell_level = 0;
+  else if (shell_level > 1000)
+    {
+      internal_warning (_("shell level (%d) too high, resetting to 1"), shell_level);
+      shell_level = 1;
+    }
+
+  /* We don't need the full generality of itos here. */
+  if (shell_level < 10)
+    {
+      new_level[0] = shell_level + '0';
+      new_level[1] = '\0';
+    }
+  else if (shell_level < 100)
+    {
+      new_level[0] = (shell_level / 10) + '0';
+      new_level[1] = (shell_level % 10) + '0';
+      new_level[2] = '\0';
+    }
+  else if (shell_level < 1000)
+    {
+      new_level[0] = (shell_level / 100) + '0';
+      old_level = shell_level % 100;
+      new_level[1] = (old_level / 10) + '0';
+      new_level[2] = (old_level % 10) + '0';
+      new_level[3] = '\0';
+    }
+
+  temp_var = bind_variable ("SHLVL", new_level, 0);
+  set_auto_export (temp_var);
+}
+
+static void
+initialize_shell_level ()
+{
+  adjust_shell_level (1);
+}
+
+/* If we got PWD from the environment, update our idea of the current
+   working directory.  In any case, make sure that PWD exists before
+   checking it.  It is possible for getcwd () to fail on shell startup,
+   and in that case, PWD would be undefined.  If this is an interactive
+   login shell, see if $HOME is the current working directory, and if
+   that's not the same string as $PWD, set PWD=$HOME. */
+
+void
+set_pwd ()
+{
+  SHELL_VAR *temp_var, *home_var;
+  char *temp_string, *home_string;
+
+  home_var = find_variable ("HOME");
+  home_string = home_var ? value_cell (home_var) : (char *)NULL;
+
+  temp_var = find_variable ("PWD");
+  if (temp_var && imported_p (temp_var) &&
+      (temp_string = value_cell (temp_var)) &&
+      same_file (temp_string, ".", (struct stat *)NULL, (struct stat *)NULL))
+    set_working_directory (temp_string);
+  else if (home_string && interactive_shell && login_shell &&
+	   same_file (home_string, ".", (struct stat *)NULL, (struct stat *)NULL))
+    {
+      set_working_directory (home_string);
+      temp_var = bind_variable ("PWD", home_string, 0);
+      set_auto_export (temp_var);
+    }
+  else
+    {
+      temp_string = get_working_directory ("shell-init");
+      if (temp_string)
+	{
+	  temp_var = bind_variable ("PWD", temp_string, 0);
+	  set_auto_export (temp_var);
+	  free (temp_string);
+	}
+    }
+
+  /* According to the Single Unix Specification, v2, $OLDPWD is an
+     `environment variable' and therefore should be auto-exported.
+     Make a dummy invisible variable for OLDPWD, and mark it as exported. */
+  temp_var = bind_variable ("OLDPWD", (char *)NULL, 0);
+  VSETATTR (temp_var, (att_exported | att_invisible));
+}
+
+/* Make a variable $PPID, which holds the pid of the shell's parent.  */
+void
+set_ppid ()
+{
+  char namebuf[INT_STRLEN_BOUND(pid_t) + 1], *name;
+  SHELL_VAR *temp_var;
+
+  name = inttostr (getppid (), namebuf, sizeof(namebuf));
+  temp_var = find_variable ("PPID");
+  if (temp_var)
+    VUNSETATTR (temp_var, (att_readonly | att_exported));
+  temp_var = bind_variable ("PPID", name, 0);
+  VSETATTR (temp_var, (att_readonly | att_integer));
+}
+
+static void
+uidset ()
+{
+  char buff[INT_STRLEN_BOUND(uid_t) + 1], *b;
+  register SHELL_VAR *v;
+
+  b = inttostr (current_user.uid, buff, sizeof (buff));
+  v = find_variable ("UID");
+  if (v == 0)
+    {
+      v = bind_variable ("UID", b, 0);
+      VSETATTR (v, (att_readonly | att_integer));
+    }
+
+  if (current_user.euid != current_user.uid)
+    b = inttostr (current_user.euid, buff, sizeof (buff));
+
+  v = find_variable ("EUID");
+  if (v == 0)
+    {
+      v = bind_variable ("EUID", b, 0);
+      VSETATTR (v, (att_readonly | att_integer));
+    }
+}
+
+#if defined (ARRAY_VARS)
+static void
+make_vers_array ()
+{
+  SHELL_VAR *vv;
+  ARRAY *av;
+  char *s, d[32], b[INT_STRLEN_BOUND(int) + 1];
+
+  unbind_variable ("BASH_VERSINFO");
+
+  vv = make_new_array_variable ("BASH_VERSINFO");
+  av = array_cell (vv);
+  strcpy (d, dist_version);
+  s = strchr (d, '.');
+  if (s)
+    *s++ = '\0';
+  array_insert (av, 0, d);
+  array_insert (av, 1, s);
+  s = inttostr (patch_level, b, sizeof (b));
+  array_insert (av, 2, s);
+  s = inttostr (build_version, b, sizeof (b));
+  array_insert (av, 3, s);
+  array_insert (av, 4, release_status);
+  array_insert (av, 5, MACHTYPE);
+
+  VSETATTR (vv, att_readonly);
+}
+#endif /* ARRAY_VARS */
+
+/* Set the environment variables $LINES and $COLUMNS in response to
+   a window size change. */
+void
+sh_set_lines_and_columns (lines, cols)
+     int lines, cols;
+{
+  char val[INT_STRLEN_BOUND(int) + 1], *v;
+
+#if defined (READLINE)
+  /* If we are currently assigning to LINES or COLUMNS, don't do anything. */
+  if (winsize_assignment)
+    return;
+#endif
+
+  v = inttostr (lines, val, sizeof (val));
+  bind_variable ("LINES", v, 0);
+
+  v = inttostr (cols, val, sizeof (val));
+  bind_variable ("COLUMNS", v, 0);
+}
+
+/* **************************************************************** */
+/*								    */
+/*		   Printing variables and values		    */
+/*								    */
+/* **************************************************************** */
+
+/* Print LIST (a list of shell variables) to stdout in such a way that
+   they can be read back in. */
+void
+print_var_list (list)
+     register SHELL_VAR **list;
+{
+  register int i;
+  register SHELL_VAR *var;
+
+  for (i = 0; list && (var = list[i]); i++)
+    if (invisible_p (var) == 0)
+      print_assignment (var);
+}
+
+/* Print LIST (a list of shell functions) to stdout in such a way that
+   they can be read back in. */
+void
+print_func_list (list)
+     register SHELL_VAR **list;
+{
+  register int i;
+  register SHELL_VAR *var;
+
+  for (i = 0; list && (var = list[i]); i++)
+    {
+      printf ("%s ", var->name);
+      print_var_function (var);
+      printf ("\n");
+    }
+}
+      
+/* Print the value of a single SHELL_VAR.  No newline is
+   output, but the variable is printed in such a way that
+   it can be read back in. */
+void
+print_assignment (var)
+     SHELL_VAR *var;
+{
+  if (var_isset (var) == 0)
+    return;
+
+  if (function_p (var))
+    {
+      printf ("%s", var->name);
+      print_var_function (var);
+      printf ("\n");
+    }
+#if defined (ARRAY_VARS)
+  else if (array_p (var))
+    print_array_assignment (var, 0);
+  else if (assoc_p (var))
+    print_assoc_assignment (var, 0);
+#endif /* ARRAY_VARS */
+  else
+    {
+      printf ("%s=", var->name);
+      print_var_value (var, 1);
+      printf ("\n");
+    }
+}
+
+/* Print the value cell of VAR, a shell variable.  Do not print
+   the name, nor leading/trailing newline.  If QUOTE is non-zero,
+   and the value contains shell metacharacters, quote the value
+   in such a way that it can be read back in. */
+void
+print_var_value (var, quote)
+     SHELL_VAR *var;
+     int quote;
+{
+  char *t;
+
+  if (var_isset (var) == 0)
+    return;
+
+  if (quote && posixly_correct == 0 && ansic_shouldquote (value_cell (var)))
+    {
+      t = ansic_quote (value_cell (var), 0, (int *)0);
+      printf ("%s", t);
+      free (t);
+    }
+  else if (quote && sh_contains_shell_metas (value_cell (var)))
+    {
+      t = sh_single_quote (value_cell (var));
+      printf ("%s", t);
+      free (t);
+    }
+  else
+    printf ("%s", value_cell (var));
+}
+
+/* Print the function cell of VAR, a shell variable.  Do not
+   print the name, nor leading/trailing newline. */
+void
+print_var_function (var)
+     SHELL_VAR *var;
+{
+  char *x;
+
+  if (function_p (var) && var_isset (var))
+    {
+      x = named_function_string ((char *)NULL, function_cell(var), FUNC_MULTILINE|FUNC_EXTERNAL);
+      printf ("%s", x);
+    }
+}
+
+/* **************************************************************** */
+/*								    */
+/*		 	Dynamic Variables			    */
+/*								    */
+/* **************************************************************** */
+
+/* DYNAMIC VARIABLES
+
+   These are variables whose values are generated anew each time they are
+   referenced.  These are implemented using a pair of function pointers
+   in the struct variable: assign_func, which is called from bind_variable
+   and, if arrays are compiled into the shell, some of the functions in
+   arrayfunc.c, and dynamic_value, which is called from find_variable.
+
+   assign_func is called from bind_variable_internal, if
+   bind_variable_internal discovers that the variable being assigned to
+   has such a function.  The function is called as
+	SHELL_VAR *temp = (*(entry->assign_func)) (entry, value, ind)
+   and the (SHELL_VAR *)temp is returned as the value of bind_variable.  It
+   is usually ENTRY (self).  IND is an index for an array variable, and
+   unused otherwise.
+
+   dynamic_value is called from find_variable_internal to return a `new'
+   value for the specified dynamic varible.  If this function is NULL,
+   the variable is treated as a `normal' shell variable.  If it is not,
+   however, then this function is called like this:
+	tempvar = (*(var->dynamic_value)) (var);
+
+   Sometimes `tempvar' will replace the value of `var'.  Other times, the
+   shell will simply use the string value.  Pretty object-oriented, huh?
+
+   Be warned, though: if you `unset' a special variable, it loses its
+   special meaning, even if you subsequently set it.
+
+   The special assignment code would probably have been better put in
+   subst.c: do_assignment_internal, in the same style as
+   stupidly_hack_special_variables, but I wanted the changes as
+   localized as possible.  */
+
+#define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \
+  do \
+    { \
+      v = bind_variable (var, (val), 0); \
+      v->dynamic_value = gfunc; \
+      v->assign_func = afunc; \
+    } \
+  while (0)
+
+#define INIT_DYNAMIC_ARRAY_VAR(var, gfunc, afunc) \
+  do \
+    { \
+      v = make_new_array_variable (var); \
+      v->dynamic_value = gfunc; \
+      v->assign_func = afunc; \
+    } \
+  while (0)
+
+#define INIT_DYNAMIC_ASSOC_VAR(var, gfunc, afunc) \
+  do \
+    { \
+      v = make_new_assoc_variable (var); \
+      v->dynamic_value = gfunc; \
+      v->assign_func = afunc; \
+    } \
+  while (0)
+
+static SHELL_VAR *
+null_assign (self, value, unused, key)
+     SHELL_VAR *self;
+     char *value;
+     arrayind_t unused;
+     char *key;
+{
+  return (self);
+}
+
+#if defined (ARRAY_VARS)
+static SHELL_VAR *
+null_array_assign (self, value, ind, key)
+     SHELL_VAR *self;
+     char *value;
+     arrayind_t ind;
+     char *key;
+{
+  return (self);
+}
+#endif
+
+/* Degenerate `dynamic_value' function; just returns what's passed without
+   manipulation. */
+static SHELL_VAR *
+get_self (self)
+     SHELL_VAR *self;
+{
+  return (self);
+}
+
+#if defined (ARRAY_VARS)
+/* A generic dynamic array variable initializer.  Initialize array variable
+   NAME with dynamic value function GETFUNC and assignment function SETFUNC. */
+static SHELL_VAR *
+init_dynamic_array_var (name, getfunc, setfunc, attrs)
+     char *name;
+     sh_var_value_func_t *getfunc;
+     sh_var_assign_func_t *setfunc;
+     int attrs;
+{
+  SHELL_VAR *v;
+
+  v = find_variable (name);
+  if (v)
+    return (v);
+  INIT_DYNAMIC_ARRAY_VAR (name, getfunc, setfunc);
+  if (attrs)
+    VSETATTR (v, attrs);
+  return v;
+}
+
+static SHELL_VAR *
+init_dynamic_assoc_var (name, getfunc, setfunc, attrs)
+     char *name;
+     sh_var_value_func_t *getfunc;
+     sh_var_assign_func_t *setfunc;
+     int attrs;
+{
+  SHELL_VAR *v;
+
+  v = find_variable (name);
+  if (v)
+    return (v);
+  INIT_DYNAMIC_ASSOC_VAR (name, getfunc, setfunc);
+  if (attrs)
+    VSETATTR (v, attrs);
+  return v;
+}
+#endif
+
+/* The value of $SECONDS.  This is the number of seconds since shell
+   invocation, or, the number of seconds since the last assignment + the
+   value of the last assignment. */
+static intmax_t seconds_value_assigned;
+
+static SHELL_VAR *
+assign_seconds (self, value, unused, key)
+     SHELL_VAR *self;
+     char *value;
+     arrayind_t unused;
+     char *key;
+{
+  if (legal_number (value, &seconds_value_assigned) == 0)
+    seconds_value_assigned = 0;
+  shell_start_time = NOW;
+  return (self);
+}
+
+static SHELL_VAR *
+get_seconds (var)
+     SHELL_VAR *var;
+{
+  time_t time_since_start;
+  char *p;
+
+  time_since_start = NOW - shell_start_time;
+  p = itos(seconds_value_assigned + time_since_start);
+
+  FREE (value_cell (var));
+
+  VSETATTR (var, att_integer);
+  var_setvalue (var, p);
+  return (var);
+}
+
+static SHELL_VAR *
+init_seconds_var ()
+{
+  SHELL_VAR *v;
+
+  v = find_variable ("SECONDS");
+  if (v)
+    {
+      if (legal_number (value_cell(v), &seconds_value_assigned) == 0)
+	seconds_value_assigned = 0;
+    }
+  INIT_DYNAMIC_VAR ("SECONDS", (v ? value_cell (v) : (char *)NULL), get_seconds, assign_seconds);
+  return v;      
+}
+     
+/* The random number seed.  You can change this by setting RANDOM. */
+static unsigned long rseed = 1;
+static int last_random_value;
+static int seeded_subshell = 0;
+
+/* A linear congruential random number generator based on the example
+   one in the ANSI C standard.  This one isn't very good, but a more
+   complicated one is overkill. */
+
+/* Returns a pseudo-random number between 0 and 32767. */
+static int
+brand ()
+{
+  /* From "Random number generators: good ones are hard to find",
+     Park and Miller, Communications of the ACM, vol. 31, no. 10,
+     October 1988, p. 1195. filtered through FreeBSD */
+  long h, l;
+
+  /* Can't seed with 0. */
+  if (rseed == 0)
+    rseed = 123459876;
+  h = rseed / 127773;
+  l = rseed % 127773;
+  rseed = 16807 * l - 2836 * h;
+#if 0
+  if (rseed < 0)
+    rseed += 0x7fffffff;
+#endif
+  return ((unsigned int)(rseed & 32767));	/* was % 32768 */
+}
+
+/* Set the random number generator seed to SEED. */
+static void
+sbrand (seed)
+     unsigned long seed;
+{
+  rseed = seed;
+  last_random_value = 0;
+}
+
+static void
+seedrand ()
+{
+  struct timeval tv;
+
+  gettimeofday (&tv, NULL);
+  sbrand (tv.tv_sec ^ tv.tv_usec ^ getpid ());
+}
+
+static SHELL_VAR *
+assign_random (self, value, unused, key)
+     SHELL_VAR *self;
+     char *value;
+     arrayind_t unused;
+     char *key;
+{
+  sbrand (strtoul (value, (char **)NULL, 10));
+  if (subshell_environment)
+    seeded_subshell = getpid ();
+  return (self);
+}
+
+int
+get_random_number ()
+{
+  int rv, pid;
+
+  /* Reset for command and process substitution. */
+  pid = getpid ();
+  if (subshell_environment && seeded_subshell != pid)
+    {
+      seedrand ();
+      seeded_subshell = pid;
+    }
+
+  do
+    rv = brand ();
+  while (rv == last_random_value);
+  return rv;
+}
+
+static SHELL_VAR *
+get_random (var)
+     SHELL_VAR *var;
+{
+  int rv;
+  char *p;
+
+  rv = get_random_number ();
+  last_random_value = rv;
+  p = itos (rv);
+
+  FREE (value_cell (var));
+
+  VSETATTR (var, att_integer);
+  var_setvalue (var, p);
+  return (var);
+}
+
+static SHELL_VAR *
+assign_lineno (var, value, unused, key)
+     SHELL_VAR *var;
+     char *value;
+     arrayind_t unused;
+     char *key;
+{
+  intmax_t new_value;
+
+  if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0)
+    new_value = 0;
+  line_number = line_number_base = new_value;
+  return var;
+}
+
+/* Function which returns the current line number. */
+static SHELL_VAR *
+get_lineno (var)
+     SHELL_VAR *var;
+{
+  char *p;
+  int ln;
+
+  ln = executing_line_number ();
+  p = itos (ln);
+  FREE (value_cell (var));
+  var_setvalue (var, p);
+  return (var);
+}
+
+static SHELL_VAR *
+assign_subshell (var, value, unused, key)
+     SHELL_VAR *var;
+     char *value;
+     arrayind_t unused;
+     char *key;
+{
+  intmax_t new_value;
+
+  if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0)
+    new_value = 0;
+  subshell_level = new_value;
+  return var;
+}
+
+static SHELL_VAR *
+get_subshell (var)
+     SHELL_VAR *var;
+{
+  char *p;
+
+  p = itos (subshell_level);
+  FREE (value_cell (var));
+  var_setvalue (var, p);
+  return (var);
+}
+
+static SHELL_VAR *
+get_bashpid (var)
+     SHELL_VAR *var;
+{
+  int pid;
+  char *p;
+
+  pid = getpid ();
+  p = itos (pid);
+
+  FREE (value_cell (var));
+  VSETATTR (var, att_integer|att_readonly);
+  var_setvalue (var, p);
+  return (var);
+}
+
+static SHELL_VAR *
+get_bash_command (var)
+     SHELL_VAR *var;
+{
+  char *p;
+
+  if (the_printed_command_except_trap)
+    p = savestring (the_printed_command_except_trap);
+  else
+    {
+      p = (char *)xmalloc (1);
+      p[0] = '\0';
+    }
+  FREE (value_cell (var));
+  var_setvalue (var, p);
+  return (var);
+}
+
+#if defined (HISTORY)
+static SHELL_VAR *
+get_histcmd (var)
+     SHELL_VAR *var;
+{
+  char *p;
+
+  p = itos (history_number ());
+  FREE (value_cell (var));
+  var_setvalue (var, p);
+  return (var);
+}
+#endif
+
+#if defined (READLINE)
+/* When this function returns, VAR->value points to malloced memory. */
+static SHELL_VAR *
+get_comp_wordbreaks (var)
+     SHELL_VAR *var;
+{
+  /* If we don't have anything yet, assign a default value. */
+  if (rl_completer_word_break_characters == 0 && bash_readline_initialized == 0)
+    enable_hostname_completion (perform_hostname_completion);
+
+  FREE (value_cell (var));
+  var_setvalue (var, savestring (rl_completer_word_break_characters));
+
+  return (var);
+}
+
+/* When this function returns, rl_completer_word_break_characters points to
+   malloced memory. */
+static SHELL_VAR *
+assign_comp_wordbreaks (self, value, unused, key)
+     SHELL_VAR *self;
+     char *value;
+     arrayind_t unused;
+     char *key;
+{
+  if (rl_completer_word_break_characters &&
+      rl_completer_word_break_characters != rl_basic_word_break_characters)
+    free (rl_completer_word_break_characters);
+
+  rl_completer_word_break_characters = savestring (value);
+  return self;
+}
+#endif /* READLINE */
+
+#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
+static SHELL_VAR *
+assign_dirstack (self, value, ind, key)
+     SHELL_VAR *self;
+     char *value;
+     arrayind_t ind;
+     char *key;
+{
+  set_dirstack_element (ind, 1, value);
+  return self;
+}
+
+static SHELL_VAR *
+get_dirstack (self)
+     SHELL_VAR *self;
+{
+  ARRAY *a;
+  WORD_LIST *l;
+
+  l = get_directory_stack (0);
+  a = array_from_word_list (l);
+  array_dispose (array_cell (self));
+  dispose_words (l);
+  var_setarray (self, a);
+  return self;
+}
+#endif /* PUSHD AND POPD && ARRAY_VARS */
+
+#if defined (ARRAY_VARS)
+/* We don't want to initialize the group set with a call to getgroups()
+   unless we're asked to, but we only want to do it once. */
+static SHELL_VAR *
+get_groupset (self)
+     SHELL_VAR *self;
+{
+  register int i;
+  int ng;
+  ARRAY *a;
+  static char **group_set = (char **)NULL;
+
+  if (group_set == 0)
+    {
+      group_set = get_group_list (&ng);
+      a = array_cell (self);
+      for (i = 0; i < ng; i++)
+	array_insert (a, i, group_set[i]);
+    }
+  return (self);
+}
+
+static SHELL_VAR *
+build_hashcmd (self)
+     SHELL_VAR *self;
+{
+  HASH_TABLE *h;
+  int i;
+  char *k, *v;
+  BUCKET_CONTENTS *item;
+
+  h = assoc_cell (self);
+  if (h)
+    assoc_dispose (h);
+
+  if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0)
+    {
+      var_setvalue (self, (char *)NULL);
+      return self;
+    }
+
+  h = assoc_create (hashed_filenames->nbuckets);
+  for (i = 0; i < hashed_filenames->nbuckets; i++)
+    {
+      for (item = hash_items (i, hashed_filenames); item; item = item->next)
+	{
+	  k = savestring (item->key);
+	  v = pathdata(item)->path;
+	  assoc_insert (h, k, v);
+	}
+    }
+
+  var_setvalue (self, (char *)h);
+  return self;
+}
+
+static SHELL_VAR *
+get_hashcmd (self)
+     SHELL_VAR *self;
+{
+  build_hashcmd (self);
+  return (self);
+}
+
+static SHELL_VAR *
+assign_hashcmd (self, value, ind, key)
+     SHELL_VAR *self;
+     char *value;
+     arrayind_t ind;
+     char *key;
+{
+  phash_insert (key, value, 0, 0);
+  return (build_hashcmd (self));
+}
+
+#if defined (ALIAS)
+static SHELL_VAR *
+build_aliasvar (self)
+     SHELL_VAR *self;
+{
+  HASH_TABLE *h;
+  int i;
+  char *k, *v;
+  BUCKET_CONTENTS *item;
+
+  h = assoc_cell (self);
+  if (h)
+    assoc_dispose (h);
+
+  if (aliases == 0 || HASH_ENTRIES (aliases) == 0)
+    {
+      var_setvalue (self, (char *)NULL);
+      return self;
+    }
+
+  h = assoc_create (aliases->nbuckets);
+  for (i = 0; i < aliases->nbuckets; i++)
+    {
+      for (item = hash_items (i, aliases); item; item = item->next)
+	{
+	  k = savestring (item->key);
+	  v = ((alias_t *)(item->data))->value;
+	  assoc_insert (h, k, v);
+	}
+    }
+
+  var_setvalue (self, (char *)h);
+  return self;
+}
+
+static SHELL_VAR *
+get_aliasvar (self)
+     SHELL_VAR *self;
+{
+  build_aliasvar (self);
+  return (self);
+}
+
+static SHELL_VAR *
+assign_aliasvar (self, value, ind, key)
+     SHELL_VAR *self;
+     char *value;
+     arrayind_t ind;
+     char *key;
+{
+  add_alias (key, value);
+  return (build_aliasvar (self));
+}
+#endif /* ALIAS */
+
+#endif /* ARRAY_VARS */
+
+/* If ARRAY_VARS is not defined, this just returns the name of any
+   currently-executing function.  If we have arrays, it's a call stack. */
+static SHELL_VAR *
+get_funcname (self)
+     SHELL_VAR *self;
+{
+#if ! defined (ARRAY_VARS)
+  char *t;
+  if (variable_context && this_shell_function)
+    {
+      FREE (value_cell (self));
+      t = savestring (this_shell_function->name);
+      var_setvalue (self, t);
+    }
+#endif
+  return (self);
+}
+
+void
+make_funcname_visible (on_or_off)
+     int on_or_off;
+{
+  SHELL_VAR *v;
+
+  v = find_variable ("FUNCNAME");
+  if (v == 0 || v->dynamic_value == 0)
+    return;
+
+  if (on_or_off)
+    VUNSETATTR (v, att_invisible);
+  else
+    VSETATTR (v, att_invisible);
+}
+
+static SHELL_VAR *
+init_funcname_var ()
+{
+  SHELL_VAR *v;
+
+  v = find_variable ("FUNCNAME");
+  if (v)
+    return v;
+#if defined (ARRAY_VARS)
+  INIT_DYNAMIC_ARRAY_VAR ("FUNCNAME", get_funcname, null_array_assign);
+#else
+  INIT_DYNAMIC_VAR ("FUNCNAME", (char *)NULL, get_funcname, null_assign);
+#endif
+  VSETATTR (v, att_invisible|att_noassign);
+  return v;
+}
+
+static void
+initialize_dynamic_variables ()
+{
+  SHELL_VAR *v;
+
+  v = init_seconds_var ();
+
+  INIT_DYNAMIC_VAR ("BASH_COMMAND", (char *)NULL, get_bash_command, (sh_var_assign_func_t *)NULL);
+  INIT_DYNAMIC_VAR ("BASH_SUBSHELL", (char *)NULL, get_subshell, assign_subshell);
+
+  INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random);
+  VSETATTR (v, att_integer);
+  INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno);
+  VSETATTR (v, att_integer);
+
+  INIT_DYNAMIC_VAR ("BASHPID", (char *)NULL, get_bashpid, null_assign);
+  VSETATTR (v, att_integer|att_readonly);
+
+#if defined (HISTORY)
+  INIT_DYNAMIC_VAR ("HISTCMD", (char *)NULL, get_histcmd, (sh_var_assign_func_t *)NULL);
+  VSETATTR (v, att_integer);
+#endif
+
+#if defined (READLINE)
+  INIT_DYNAMIC_VAR ("COMP_WORDBREAKS", (char *)NULL, get_comp_wordbreaks, assign_comp_wordbreaks);
+#endif
+
+#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
+  v = init_dynamic_array_var ("DIRSTACK", get_dirstack, assign_dirstack, 0);
+#endif /* PUSHD_AND_POPD && ARRAY_VARS */
+
+#if defined (ARRAY_VARS)
+  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_noassign|att_nounset);
+  v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, att_noassign|att_nounset);
+#  endif /* DEBUGGER */
+  v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, att_noassign|att_nounset);
+  v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, att_noassign|att_nounset);
+
+  v = init_dynamic_assoc_var ("BASH_CMDS", get_hashcmd, assign_hashcmd, att_nofree);
+#  if defined (ALIAS)
+  v = init_dynamic_assoc_var ("BASH_ALIASES", get_aliasvar, assign_aliasvar, att_nofree);
+#  endif
+#endif
+
+  v = init_funcname_var ();
+}
+
+/* **************************************************************** */
+/*								    */
+/*		Retrieving variables and values			    */
+/*								    */
+/* **************************************************************** */
+
+/* How to get a pointer to the shell variable or function named NAME.
+   HASHED_VARS is a pointer to the hash table containing the list
+   of interest (either variables or functions). */
+
+static SHELL_VAR *
+hash_lookup (name, hashed_vars)
+     const char *name;
+     HASH_TABLE *hashed_vars;
+{
+  BUCKET_CONTENTS *bucket;
+
+  bucket = hash_search (name, hashed_vars, 0);
+  /* If we find the name in HASHED_VARS, set LAST_TABLE_SEARCHED to that
+     table. */
+  if (bucket)
+    last_table_searched = hashed_vars;
+  return (bucket ? (SHELL_VAR *)bucket->data : (SHELL_VAR *)NULL);
+}
+
+SHELL_VAR *
+var_lookup (name, vcontext)
+     const char *name;
+     VAR_CONTEXT *vcontext;
+{
+  VAR_CONTEXT *vc;
+  SHELL_VAR *v;
+
+  v = (SHELL_VAR *)NULL;
+  for (vc = vcontext; vc; vc = vc->down)
+    if (v = hash_lookup (name, vc->table))
+      break;
+
+  return v;
+}
+
+/* Look up the variable entry named NAME.  If SEARCH_TEMPENV is non-zero,
+   then also search the temporarily built list of exported variables.
+   The lookup order is:
+	temporary_env
+	shell_variables list
+*/
+
+SHELL_VAR *
+find_variable_internal (name, force_tempenv)
+     const char *name;
+     int force_tempenv;
+{
+  SHELL_VAR *var;
+  int search_tempenv;
+  VAR_CONTEXT *vc;
+
+  var = (SHELL_VAR *)NULL;
+
+  /* If explicitly requested, first look in the temporary environment for
+     the variable.  This allows constructs such as "foo=x eval 'echo $foo'"
+     to get the `exported' value of $foo.  This happens if we are executing
+     a function or builtin, or if we are looking up a variable in a
+     "subshell environment". */
+  search_tempenv = force_tempenv || (expanding_redir == 0 && subshell_environment);
+
+  if (search_tempenv && temporary_env)		
+    var = hash_lookup (name, temporary_env);
+
+  vc = shell_variables;
+#if 0
+if (search_tempenv == 0 && /* (subshell_environment & SUBSHELL_COMSUB) && */
+    expanding_redir &&
+    (this_shell_builtin == eval_builtin || this_shell_builtin == command_builtin))
+  {
+  itrace("find_variable_internal: search_tempenv == 0: skipping VC_BLTNENV");
+  while (vc && (vc->flags & VC_BLTNENV))
+    vc = vc->down;
+  if (vc == 0)
+    vc = shell_variables;
+  }
+#endif
+
+  if (var == 0)
+    var = var_lookup (name, vc);
+
+  if (var == 0)
+    return ((SHELL_VAR *)NULL);
+
+  return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
+}
+
+/* Look up and resolve the chain of nameref variables starting at V all the
+   way to NULL or non-nameref. */
+SHELL_VAR *
+find_variable_nameref (v)
+     SHELL_VAR *v;
+{
+  int level;
+  char *newname;
+  SHELL_VAR *orig, *oldv;
+
+  level = 0;
+  orig = v;
+  while (v && nameref_p (v))
+    {
+      level++;
+      if (level > NAMEREF_MAX)
+	return ((SHELL_VAR *)0);	/* error message here? */
+      newname = nameref_cell (v);
+      if (newname == 0 || *newname == '\0')
+	return ((SHELL_VAR *)0);
+      oldv = v;
+      v = find_variable_internal (newname, (expanding_redir == 0 && (assigning_in_environment || executing_builtin)));
+      if (v == orig || v == oldv)
+	{
+	  internal_warning (_("%s: circular name reference"), orig->name);
+	  return ((SHELL_VAR *)0);
+	}
+    }
+  return v;
+}
+
+/* Resolve the chain of nameref variables for NAME.  XXX - could change later */
+SHELL_VAR *
+find_variable_last_nameref (name)
+     const char *name;
+{
+  SHELL_VAR *v, *nv;
+  char *newname;
+  int level;
+
+  nv = v = find_variable_noref (name);
+  level = 0;
+  while (v && nameref_p (v))
+    {
+      level++;
+      if (level > NAMEREF_MAX)
+        return ((SHELL_VAR *)0);	/* error message here? */
+      newname = nameref_cell (v);
+      if (newname == 0 || *newname == '\0')
+	return ((SHELL_VAR *)0);
+      nv = v;
+      v = find_variable_internal (newname, (expanding_redir == 0 && (assigning_in_environment || executing_builtin)));
+    }
+  return nv;
+}
+
+/* Resolve the chain of nameref variables for NAME.  XXX - could change later */
+SHELL_VAR *
+find_global_variable_last_nameref (name)
+     const char *name;
+{
+  SHELL_VAR *v, *nv;
+  char *newname;
+  int level;
+
+  nv = v = find_global_variable_noref (name);
+  level = 0;
+  while (v && nameref_p (v))
+    {
+      level++;
+      if (level > NAMEREF_MAX)
+        return ((SHELL_VAR *)0);	/* error message here? */
+      newname = nameref_cell (v);
+      if (newname == 0 || *newname == '\0')
+	return ((SHELL_VAR *)0);
+      nv = v;
+      v = find_global_variable_noref (newname);
+    }
+  return nv;
+}
+
+static SHELL_VAR *
+find_nameref_at_context (v, vc)
+     SHELL_VAR *v;
+     VAR_CONTEXT *vc;
+{
+  SHELL_VAR *nv, *nv2;
+  VAR_CONTEXT *nvc;
+  char *newname;
+  int level;
+
+  nv = v;
+  level = 1;
+  while (nv && nameref_p (nv))
+    {
+      level++;
+      if (level > NAMEREF_MAX)
+        return ((SHELL_VAR *)NULL);
+      newname = nameref_cell (nv);
+      if (newname == 0 || *newname == '\0')
+        return ((SHELL_VAR *)NULL);      
+      nv2 = hash_lookup (newname, vc->table);
+      if (nv2 == 0)
+        break;
+      nv = nv2;
+    }
+  return nv;
+}
+
+/* Do nameref resolution from the VC, which is the local context for some
+   function or builtin, `up' the chain to the global variables context.  If
+   NVCP is not NULL, return the variable context where we finally ended the
+   nameref resolution (so the bind_variable_internal can use the correct
+   variable context and hash table). */
+static SHELL_VAR *
+find_variable_nameref_context (v, vc, nvcp)
+     SHELL_VAR *v;
+     VAR_CONTEXT *vc;
+     VAR_CONTEXT **nvcp;
+{
+  SHELL_VAR *nv, *nv2;
+  VAR_CONTEXT *nvc;
+
+  /* Look starting at the current context all the way `up' */
+  for (nv = v, nvc = vc; nvc; nvc = nvc->down)
+    {
+      nv2 = find_nameref_at_context (nv, nvc);
+      if (nv2 == 0)
+        continue;
+      nv = nv2;
+      if (*nvcp)
+        *nvcp = nvc;
+      if (nameref_p (nv) == 0)
+        break;
+    }
+  return (nameref_p (nv) ? (SHELL_VAR *)NULL : nv);
+}
+
+/* Do nameref resolution from the VC, which is the local context for some
+   function or builtin, `up' the chain to the global variables context.  If
+   NVCP is not NULL, return the variable context where we finally ended the
+   nameref resolution (so the bind_variable_internal can use the correct
+   variable context and hash table). */
+static SHELL_VAR *
+find_variable_last_nameref_context (v, vc, nvcp)
+     SHELL_VAR *v;
+     VAR_CONTEXT *vc;
+     VAR_CONTEXT **nvcp;
+{
+  SHELL_VAR *nv, *nv2;
+  VAR_CONTEXT *nvc;
+
+  /* Look starting at the current context all the way `up' */
+  for (nv = v, nvc = vc; nvc; nvc = nvc->down)
+    {
+      nv2 = find_nameref_at_context (nv, nvc);
+      if (nv2 == 0)
+	continue;
+      nv = nv2;
+      if (*nvcp)
+        *nvcp = nvc;
+    }
+  return (nameref_p (nv) ? nv : (SHELL_VAR *)NULL);
+}
+
+/* Find a variable, forcing a search of the temporary environment first */
+SHELL_VAR *
+find_variable_tempenv (name)
+     const char *name;
+{
+  SHELL_VAR *var;
+
+  var = find_variable_internal (name, 1);
+  if (var && nameref_p (var))
+    var = find_variable_nameref (var);
+  return (var);
+}
+
+/* Find a variable, not forcing a search of the temporary environment first */
+SHELL_VAR *
+find_variable_notempenv (name)
+     const char *name;
+{
+  SHELL_VAR *var;
+
+  var = find_variable_internal (name, 0);
+  if (var && nameref_p (var))
+    var = find_variable_nameref (var);
+  return (var);
+}
+
+SHELL_VAR *
+find_global_variable (name)
+     const char *name;
+{
+  SHELL_VAR *var;
+
+  var = var_lookup (name, global_variables);
+  if (var && nameref_p (var))
+    var = find_variable_nameref (var);
+
+  if (var == 0)
+    return ((SHELL_VAR *)NULL);
+
+  return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
+}
+
+SHELL_VAR *
+find_global_variable_noref (name)
+     const char *name;
+{
+  SHELL_VAR *var;
+
+  var = var_lookup (name, global_variables);
+
+  if (var == 0)
+    return ((SHELL_VAR *)NULL);
+
+  return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
+}
+
+SHELL_VAR *
+find_shell_variable (name)
+     const char *name;
+{
+  SHELL_VAR *var;
+
+  var = var_lookup (name, shell_variables);
+  if (var && nameref_p (var))
+    var = find_variable_nameref (var);
+
+  if (var == 0)
+    return ((SHELL_VAR *)NULL);
+
+  return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
+}
+
+/* Look up the variable entry named NAME.  Returns the entry or NULL. */
+SHELL_VAR *
+find_variable (name)
+     const char *name;
+{
+  SHELL_VAR *v;
+
+  last_table_searched = 0;
+  v = find_variable_internal (name, (expanding_redir == 0 && (assigning_in_environment || executing_builtin)));
+  if (v && nameref_p (v))
+    v = find_variable_nameref (v);
+  return v;
+}
+
+SHELL_VAR *
+find_variable_noref (name)
+     const char *name;
+{
+  SHELL_VAR *v;
+
+  v = find_variable_internal (name, (expanding_redir == 0 && (assigning_in_environment || executing_builtin)));
+  return v;
+}
+
+/* Look up the function entry whose name matches STRING.
+   Returns the entry or NULL. */
+SHELL_VAR *
+find_function (name)
+     const char *name;
+{
+  return (hash_lookup (name, shell_functions));
+}
+
+/* Find the function definition for the shell function named NAME.  Returns
+   the entry or NULL. */
+FUNCTION_DEF *
+find_function_def (name)
+     const char *name;
+{
+#if defined (DEBUGGER)
+  return ((FUNCTION_DEF *)hash_lookup (name, shell_function_defs));
+#else
+  return ((FUNCTION_DEF *)0);
+#endif
+}
+
+/* Return the value of VAR.  VAR is assumed to have been the result of a
+   lookup without any subscript, if arrays are compiled into the shell. */
+char *
+get_variable_value (var)
+     SHELL_VAR *var;
+{
+  if (var == 0)
+    return ((char *)NULL);
+#if defined (ARRAY_VARS)
+  else if (array_p (var))
+    return (array_reference (array_cell (var), 0));
+  else if (assoc_p (var))
+    return (assoc_reference (assoc_cell (var), "0"));
+#endif
+  else
+    return (value_cell (var));
+}
+
+/* Return the string value of a variable.  Return NULL if the variable
+   doesn't exist.  Don't cons a new string.  This is a potential memory
+   leak if the variable is found in the temporary environment.  Since
+   functions and variables have separate name spaces, returns NULL if
+   var_name is a shell function only. */
+char *
+get_string_value (var_name)
+     const char *var_name;
+{
+  SHELL_VAR *var;
+
+  var = find_variable (var_name);
+  return ((var) ? get_variable_value (var) : (char *)NULL);
+}
+
+/* This is present for use by the tilde and readline libraries. */
+char *
+sh_get_env_value (v)
+     const char *v;
+{
+  return get_string_value (v);
+}
+
+/* **************************************************************** */
+/*								    */
+/*		  Creating and setting variables		    */
+/*								    */
+/* **************************************************************** */
+
+/* Set NAME to VALUE if NAME has no value. */
+SHELL_VAR *
+set_if_not (name, value)
+     char *name, *value;
+{
+  SHELL_VAR *v;
+
+  if (shell_variables == 0)
+    create_variable_tables ();
+
+  v = find_variable (name);
+  if (v == 0)
+    v = bind_variable_internal (name, value, global_variables->table, HASH_NOSRCH, 0);
+  return (v);
+}
+
+/* Create a local variable referenced by NAME. */
+SHELL_VAR *
+make_local_variable (name)
+     const char *name;
+{
+  SHELL_VAR *new_var, *old_var;
+  VAR_CONTEXT *vc;
+  int was_tmpvar;
+  char *tmp_value;
+
+  /* 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);
+
+  was_tmpvar = old_var && tempvar_p (old_var);
+  /* If we're making a local variable in a shell function, the temporary env
+     has already been merged into the function's variable context stack.  We
+     can assume that a temporary var in the same context appears in the same
+     VAR_CONTEXT and can safely be returned without creating a new variable
+     (which results in duplicate names in the same VAR_CONTEXT->table */
+  /* We can't just test tmpvar_p because variables in the temporary env given
+     to a shell function appear in the function's local variable VAR_CONTEXT
+     but retain their tempvar attribute.  We want temporary variables that are
+     found in temporary_env, hence the test for last_table_searched, which is
+     set in hash_lookup and only (so far) checked here. */
+  if (was_tmpvar && old_var->context == variable_context && last_table_searched != temporary_env)
+    {
+      VUNSETATTR (old_var, att_invisible);
+      return (old_var);
+    }
+  if (was_tmpvar)
+    tmp_value = value_cell (old_var);
+
+  for (vc = shell_variables; vc; vc = vc->down)
+    if (vc_isfuncenv (vc) && vc->scope == variable_context)
+      break;
+
+  if (vc == 0)
+    {
+      internal_error (_("make_local_variable: no function context at current scope"));
+      return ((SHELL_VAR *)NULL);
+    }
+  else if (vc->table == 0)
+    vc->table = hash_create (TEMPENV_HASH_BUCKETS);
+
+  /* Since this is called only from the local/declare/typeset code, we can
+     call builtin_error here without worry (of course, it will also work
+     for anything that sets this_command_name).  Variables with the `noassign'
+     attribute may not be made local.  The test against old_var's context
+     level is to disallow local copies of readonly global variables (since I
+     believe that this could be a security hole).  Readonly copies of calling
+     function local variables are OK. */
+  if (old_var && (noassign_p (old_var) ||
+		 (readonly_p (old_var) && old_var->context == 0)))
+    {
+      if (readonly_p (old_var))
+	sh_readonly (name);
+      else if (noassign_p (old_var))
+	builtin_error (_("%s: variable may not be assigned value"), name);
+#if 0
+      /* Let noassign variables through with a warning */
+      if (readonly_p (old_var))
+#endif
+	return ((SHELL_VAR *)NULL);
+    }
+
+  if (old_var == 0)
+    new_var = make_new_variable (name, vc->table);
+  else
+    {
+      new_var = make_new_variable (name, vc->table);
+
+      /* If we found this variable in one of the temporary environments,
+	 inherit its value.  Watch to see if this causes problems with
+	 things like `x=4 local x'. XXX - see above for temporary env
+	 variables with the same context level as variable_context */
+      /* XXX - we should only do this if the variable is not an array. */
+      if (was_tmpvar)
+	var_setvalue (new_var, savestring (tmp_value));
+
+      new_var->attributes = exported_p (old_var) ? att_exported : 0;
+    }
+
+  vc->flags |= VC_HASLOCAL;
+
+  new_var->context = variable_context;
+  VSETATTR (new_var, att_local);
+
+  if (ifsname (name))
+    setifs (new_var);
+
+  if (was_tmpvar == 0)
+    VSETATTR (new_var, att_invisible);	/* XXX */
+  return (new_var);
+}
+
+/* Create a new shell variable with name NAME. */
+static SHELL_VAR *
+new_shell_variable (name)
+     const char *name;
+{
+  SHELL_VAR *entry;
+
+  entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
+
+  entry->name = savestring (name);
+  var_setvalue (entry, (char *)NULL);
+  CLEAR_EXPORTSTR (entry);
+
+  entry->dynamic_value = (sh_var_value_func_t *)NULL;
+  entry->assign_func = (sh_var_assign_func_t *)NULL;
+
+  entry->attributes = 0;
+
+  /* Always assume variables are to be made at toplevel!
+     make_local_variable has the responsibility of changing the
+     variable context. */
+  entry->context = 0;
+
+  return (entry);
+}
+
+/* Create a new shell variable with name NAME and add it to the hash table
+   TABLE. */
+static SHELL_VAR *
+make_new_variable (name, table)
+     const char *name;
+     HASH_TABLE *table;
+{
+  SHELL_VAR *entry;
+  BUCKET_CONTENTS *elt;
+
+  entry = new_shell_variable (name);
+
+  /* Make sure we have a shell_variables hash table to add to. */
+  if (shell_variables == 0)
+    create_variable_tables ();
+
+  elt = hash_insert (savestring (name), table, HASH_NOSRCH);
+  elt->data = (PTR_T)entry;
+
+  return entry;
+}
+
+#if defined (ARRAY_VARS)
+SHELL_VAR *
+make_new_array_variable (name)
+     char *name;
+{
+  SHELL_VAR *entry;
+  ARRAY *array;
+
+  entry = make_new_variable (name, global_variables->table);
+  array = array_create ();
+
+  var_setarray (entry, array);
+  VSETATTR (entry, att_array);
+  return entry;
+}
+
+SHELL_VAR *
+make_local_array_variable (name, assoc_ok)
+     char *name;
+     int assoc_ok;
+{
+  SHELL_VAR *var;
+  ARRAY *array;
+
+  var = make_local_variable (name);
+  if (var == 0 || array_p (var) || (assoc_ok && assoc_p (var)))
+    return var;
+
+  array = array_create ();
+
+  dispose_variable_value (var);
+  var_setarray (var, array);
+  VSETATTR (var, att_array);
+  return var;
+}
+
+SHELL_VAR *
+make_new_assoc_variable (name)
+     char *name;
+{
+  SHELL_VAR *entry;
+  HASH_TABLE *hash;
+
+  entry = make_new_variable (name, global_variables->table);
+  hash = assoc_create (0);
+
+  var_setassoc (entry, hash);
+  VSETATTR (entry, att_assoc);
+  return entry;
+}
+
+SHELL_VAR *
+make_local_assoc_variable (name)
+     char *name;
+{
+  SHELL_VAR *var;
+  HASH_TABLE *hash;
+
+  var = make_local_variable (name);
+  if (var == 0 || assoc_p (var))
+    return var;
+
+  dispose_variable_value (var);
+  hash = assoc_create (0);
+
+  var_setassoc (var, hash);
+  VSETATTR (var, att_assoc);
+  return var;
+}
+#endif
+
+char *
+make_variable_value (var, value, flags)
+     SHELL_VAR *var;
+     char *value;
+     int flags;
+{
+  char *retval, *oval;
+  intmax_t lval, rval;
+  int expok, olen, op;
+
+  /* If this variable has had its type set to integer (via `declare -i'),
+     then do expression evaluation on it and store the result.  The
+     functions in expr.c (evalexp()) and bind_int_variable() are responsible
+     for turning off the integer flag if they don't want further
+     evaluation done. */
+  if (integer_p (var))
+    {
+      if (flags & ASS_APPEND)
+	{
+	  oval = value_cell (var);
+	  lval = evalexp (oval, &expok);	/* ksh93 seems to do this */
+	  if (expok == 0)
+	    {
+	      top_level_cleanup ();
+	      jump_to_top_level (DISCARD);
+	    }
+	}
+      rval = evalexp (value, &expok);
+      if (expok == 0)
+	{
+	  top_level_cleanup ();
+	  jump_to_top_level (DISCARD);
+	}
+      /* This can be fooled if the variable's value changes while evaluating
+	 `rval'.  We can change it if we move the evaluation of lval to here. */
+      if (flags & ASS_APPEND)
+	rval += lval;
+      retval = itos (rval);
+    }
+#if defined (CASEMOD_ATTRS)
+  else if (capcase_p (var) || uppercase_p (var) || lowercase_p (var))
+    {
+      if (flags & ASS_APPEND)
+	{
+	  oval = get_variable_value (var);
+	  if (oval == 0)	/* paranoia */
+	    oval = "";
+	  olen = STRLEN (oval);
+	  retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1);
+	  strcpy (retval, oval);
+	  if (value)
+	    strcpy (retval+olen, value);
+	}
+      else if (*value)
+	retval = savestring (value);
+      else
+	{
+	  retval = (char *)xmalloc (1);
+	  retval[0] = '\0';
+	}
+      op = capcase_p (var) ? CASE_CAPITALIZE
+			 : (uppercase_p (var) ? CASE_UPPER : CASE_LOWER);
+      oval = sh_modcase (retval, (char *)0, op);
+      free (retval);
+      retval = oval;
+    }
+#endif /* CASEMOD_ATTRS */
+  else if (value)
+    {
+      if (flags & ASS_APPEND)
+	{
+	  oval = get_variable_value (var);
+	  if (oval == 0)	/* paranoia */
+	    oval = "";
+	  olen = STRLEN (oval);
+	  retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1);
+	  strcpy (retval, oval);
+	  if (value)
+	    strcpy (retval+olen, value);
+	}
+      else if (*value)
+	retval = savestring (value);
+      else
+	{
+	  retval = (char *)xmalloc (1);
+	  retval[0] = '\0';
+	}
+    }
+  else
+    retval = (char *)NULL;
+
+  return retval;
+}
+
+/* Bind a variable NAME to VALUE in the HASH_TABLE TABLE, which may be the
+   temporary environment (but usually is not). */
+static SHELL_VAR *
+bind_variable_internal (name, value, table, hflags, aflags)
+     const char *name;
+     char *value;
+     HASH_TABLE *table;
+     int hflags, aflags;
+{
+  char *newval;
+  SHELL_VAR *entry;
+
+  entry = (hflags & HASH_NOSRCH) ? (SHELL_VAR *)NULL : hash_lookup (name, table);
+  /* Follow the nameref chain here if this is the global variables table */
+  if (entry && nameref_p (entry) && (invisible_p (entry) == 0) && table == global_variables->table)
+    {
+      entry = find_global_variable (entry->name);
+      /* Let's see if we have a nameref referencing a variable that hasn't yet
+	 been created. */
+      if (entry == 0)
+	entry = find_variable_last_nameref (name);	/* XXX */
+      if (entry == 0)					/* just in case */
+        return (entry);
+    }
+
+  /* The first clause handles `declare -n ref; ref=x;' */
+  if (entry && invisible_p (entry) && nameref_p (entry))
+    goto assign_value;
+  else if (entry && nameref_p (entry))
+    {
+      newval = nameref_cell (entry);
+#if defined (ARRAY_VARS)
+      /* declare -n foo=x[2] */
+      if (valid_array_reference (newval))
+        /* XXX - should it be aflags? */
+	entry = assign_array_element (newval, make_variable_value (entry, value, 0), aflags);
+      else
+#endif
+      {
+      entry = make_new_variable (newval, table);
+      var_setvalue (entry, make_variable_value (entry, value, 0));
+      }
+    }
+  else if (entry == 0)
+    {
+      entry = make_new_variable (name, table);
+      var_setvalue (entry, make_variable_value (entry, value, 0)); /* XXX */
+    }
+  else if (entry->assign_func)	/* array vars have assign functions now */
+    {
+      INVALIDATE_EXPORTSTR (entry);
+      newval = (aflags & ASS_APPEND) ? make_variable_value (entry, value, aflags) : value;
+      if (assoc_p (entry))
+	entry = (*(entry->assign_func)) (entry, newval, -1, savestring ("0"));
+      else if (array_p (entry))
+	entry = (*(entry->assign_func)) (entry, newval, 0, 0);
+      else
+	entry = (*(entry->assign_func)) (entry, newval, -1, 0);
+      if (newval != value)
+	free (newval);
+      return (entry);
+    }
+  else
+    {
+assign_value:
+      if (readonly_p (entry) || noassign_p (entry))
+	{
+	  if (readonly_p (entry))
+	    err_readonly (name);
+	  return (entry);
+	}
+
+      /* Variables which are bound are visible. */
+      VUNSETATTR (entry, att_invisible);
+
+#if defined (ARRAY_VARS)
+      if (assoc_p (entry) || array_p (entry))
+        newval = make_array_variable_value (entry, 0, "0", value, aflags);
+      else
+#endif
+
+      newval = make_variable_value (entry, value, aflags);	/* XXX */
+
+      /* Invalidate any cached export string */
+      INVALIDATE_EXPORTSTR (entry);
+
+#if defined (ARRAY_VARS)
+      /* XXX -- this bears looking at again -- XXX */
+      /* If an existing array variable x is being assigned to with x=b or
+	 `read x' or something of that nature, silently convert it to
+	 x[0]=b or `read x[0]'. */
+      if (assoc_p (entry))
+	{
+	  assoc_insert (assoc_cell (entry), savestring ("0"), newval);
+	  free (newval);
+	}
+      else if (array_p (entry))
+	{
+	  array_insert (array_cell (entry), 0, newval);
+	  free (newval);
+	}
+      else
+#endif
+	{
+	  FREE (value_cell (entry));
+	  var_setvalue (entry, newval);
+	}
+    }
+
+  if (mark_modified_vars)
+    VSETATTR (entry, att_exported);
+
+  if (exported_p (entry))
+    array_needs_making = 1;
+
+  return (entry);
+}
+	
+/* Bind a variable NAME to VALUE.  This conses up the name
+   and value strings.  If we have a temporary environment, we bind there
+   first, then we bind into shell_variables. */
+
+SHELL_VAR *
+bind_variable (name, value, flags)
+     const char *name;
+     char *value;
+     int flags;
+{
+  SHELL_VAR *v, *nv;
+  VAR_CONTEXT *vc, *nvc;
+  int level;
+
+  if (shell_variables == 0)
+    create_variable_tables ();
+
+  /* If we have a temporary environment, look there first for the variable,
+     and, if found, modify the value there before modifying it in the
+     shell_variables table.  This allows sourced scripts to modify values
+     given to them in a temporary environment while modifying the variable
+     value that the caller sees. */
+  if (temporary_env)
+    bind_tempenv_variable (name, value);
+
+  /* XXX -- handle local variables here. */
+  for (vc = shell_variables; vc; vc = vc->down)
+    {
+      if (vc_isfuncenv (vc) || vc_isbltnenv (vc))
+	{
+	  v = hash_lookup (name, vc->table);
+	  nvc = vc;
+	  if (v && nameref_p (v))
+	    {
+	      nv = find_variable_nameref_context (v, vc, &nvc);
+	      if (nv == 0)
+		{
+		  nv = find_variable_last_nameref_context (v, vc, &nvc);
+		  if (nv && nameref_p (nv))
+		    {
+		      /* If this nameref variable doesn't have a value yet,
+			 set the value.  Otherwise, assign using the value as
+			 normal. */
+		      if (nameref_cell (nv) == 0)
+			return (bind_variable_internal (nv->name, value, nvc->table, 0, flags));
+		      return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags));
+		    }
+		  else
+		    v = nv;
+		}
+	      else
+	        v = nv;
+	    }
+	  if (v)
+	    return (bind_variable_internal (v->name, value, nvc->table, 0, flags));
+	}
+    }
+  /* bind_variable_internal will handle nameref resolution in this case */
+  return (bind_variable_internal (name, value, global_variables->table, 0, flags));
+}
+
+SHELL_VAR *
+bind_global_variable (name, value, flags)
+     const char *name;
+     char *value;
+     int flags;
+{
+  SHELL_VAR *v, *nv;
+  VAR_CONTEXT *vc, *nvc;
+  int level;
+
+  if (shell_variables == 0)
+    create_variable_tables ();
+
+  /* bind_variable_internal will handle nameref resolution in this case */
+  return (bind_variable_internal (name, value, global_variables->table, 0, flags));
+}
+
+/* Make VAR, a simple shell variable, have value VALUE.  Once assigned a
+   value, variables are no longer invisible.  This is a duplicate of part
+   of the internals of bind_variable.  If the variable is exported, or
+   all modified variables should be exported, mark the variable for export
+   and note that the export environment needs to be recreated. */
+SHELL_VAR *
+bind_variable_value (var, value, aflags)
+     SHELL_VAR *var;
+     char *value;
+     int aflags;
+{
+  char *t;
+  int invis;
+
+  invis = invisible_p (var);
+  VUNSETATTR (var, att_invisible);
+
+  if (var->assign_func)
+    {
+      /* If we're appending, we need the old value, so use
+	 make_variable_value */
+      t = (aflags & ASS_APPEND) ? make_variable_value (var, value, aflags) : value;
+      (*(var->assign_func)) (var, t, -1, 0);
+      if (t != value && t)
+	free (t);      
+    }
+  else
+    {
+      t = make_variable_value (var, value, aflags);
+#if defined (ARRAY_VARS)
+      if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || (legal_identifier (t) == 0 && valid_array_reference (t) == 0)))
+#else
+      if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || legal_identifier (t) == 0))
+#endif
+	{
+	  free (t);
+	  if (invis)
+	    VSETATTR (var, att_invisible);	/* XXX */
+	  return ((SHELL_VAR *)NULL);
+	}
+      FREE (value_cell (var));
+      var_setvalue (var, t);
+    }
+
+  INVALIDATE_EXPORTSTR (var);
+
+  if (mark_modified_vars)
+    VSETATTR (var, att_exported);
+
+  if (exported_p (var))
+    array_needs_making = 1;
+
+  return (var);
+}
+
+/* Bind/create a shell variable with the name LHS to the RHS.
+   This creates or modifies a variable such that it is an integer.
+
+   This used to be in expr.c, but it is here so that all of the
+   variable binding stuff is localized.  Since we don't want any
+   recursive evaluation from bind_variable() (possible without this code,
+   since bind_variable() calls the evaluator for variables with the integer
+   attribute set), we temporarily turn off the integer attribute for each
+   variable we set here, then turn it back on after binding as necessary. */
+
+SHELL_VAR *
+bind_int_variable (lhs, rhs)
+     char *lhs, *rhs;
+{
+  register SHELL_VAR *v;
+  int isint, isarr, implicitarray;
+
+  isint = isarr = implicitarray = 0;
+#if defined (ARRAY_VARS)
+  if (valid_array_reference (lhs))
+    {
+      isarr = 1;
+      v = array_variable_part (lhs, (char **)0, (int *)0);
+    }
+  else
+#endif
+    v = find_variable (lhs);
+
+  if (v)
+    {
+      isint = integer_p (v);
+      VUNSETATTR (v, att_integer);
+#if defined (ARRAY_VARS)
+      if (array_p (v) && isarr == 0)
+	implicitarray = 1;
+#endif
+    }
+
+#if defined (ARRAY_VARS)
+  if (isarr)
+    v = assign_array_element (lhs, rhs, 0);
+  else if (implicitarray)
+    v = bind_array_variable (lhs, 0, rhs, 0);
+  else
+#endif
+    v = bind_variable (lhs, rhs, 0);
+
+  if (v && isint)
+    VSETATTR (v, att_integer);
+
+  VUNSETATTR (v, att_invisible);
+
+  return (v);
+}
+
+SHELL_VAR *
+bind_var_to_int (var, val)
+     char *var;
+     intmax_t val;
+{
+  char ibuf[INT_STRLEN_BOUND (intmax_t) + 1], *p;
+
+  p = fmtulong (val, 10, ibuf, sizeof (ibuf), 0);
+  return (bind_int_variable (var, p));
+}
+
+/* Do a function binding to a variable.  You pass the name and
+   the command to bind to.  This conses the name and command. */
+SHELL_VAR *
+bind_function (name, value)
+     const char *name;
+     COMMAND *value;
+{
+  SHELL_VAR *entry;
+
+  entry = find_function (name);
+  if (entry == 0)
+    {
+      BUCKET_CONTENTS *elt;
+
+      elt = hash_insert (savestring (name), shell_functions, HASH_NOSRCH);
+      entry = new_shell_variable (name);
+      elt->data = (PTR_T)entry;
+    }
+  else
+    INVALIDATE_EXPORTSTR (entry);
+
+  if (var_isset (entry))
+    dispose_command (function_cell (entry));
+
+  if (value)
+    var_setfunc (entry, copy_command (value));
+  else
+    var_setfunc (entry, 0);
+
+  VSETATTR (entry, att_function);
+
+  if (mark_modified_vars)
+    VSETATTR (entry, att_exported);
+
+  VUNSETATTR (entry, att_invisible);		/* Just to be sure */
+
+  if (exported_p (entry))
+    array_needs_making = 1;
+
+#if defined (PROGRAMMABLE_COMPLETION)
+  set_itemlist_dirty (&it_functions);
+#endif
+
+  return (entry);
+}
+
+#if defined (DEBUGGER)
+/* Bind a function definition, which includes source file and line number
+   information in addition to the command, into the FUNCTION_DEF hash table.*/
+void
+bind_function_def (name, value)
+     const char *name;
+     FUNCTION_DEF *value;
+{
+  FUNCTION_DEF *entry;
+  BUCKET_CONTENTS *elt;
+  COMMAND *cmd;
+
+  entry = find_function_def (name);
+  if (entry)
+    {
+      dispose_function_def_contents (entry);
+      entry = copy_function_def_contents (value, entry);
+    }
+  else
+    {
+      cmd = value->command;
+      value->command = 0;
+      entry = copy_function_def (value);
+      value->command = cmd;
+
+      elt = hash_insert (savestring (name), shell_function_defs, HASH_NOSRCH);
+      elt->data = (PTR_T *)entry;
+    }
+}
+#endif /* DEBUGGER */
+
+/* Add STRING, which is of the form foo=bar, to the temporary environment
+   HASH_TABLE (temporary_env).  The functions in execute_cmd.c are
+   responsible for moving the main temporary env to one of the other
+   temporary environments.  The expansion code in subst.c calls this. */
+int
+assign_in_env (word, flags)
+     WORD_DESC *word;
+     int flags;
+{
+  int offset, aflags;
+  char *name, *temp, *value;
+  SHELL_VAR *var;
+  const char *string;
+
+  string = word->word;
+
+  aflags = 0;
+  offset = assignment (string, 0);
+  name = savestring (string);
+  value = (char *)NULL;
+
+  if (name[offset] == '=')
+    {
+      name[offset] = 0;
+
+      /* don't ignore the `+' when assigning temporary environment */
+      if (name[offset - 1] == '+')
+	{
+	  name[offset - 1] = '\0';
+	  aflags |= ASS_APPEND;
+	}
+
+      var = find_variable (name);
+      if (var && (readonly_p (var) || noassign_p (var)))
+	{
+	  if (readonly_p (var))
+	    err_readonly (name);
+	  free (name);
+  	  return (0);
+	}
+
+      temp = name + offset + 1;
+      value = expand_assignment_string_to_string (temp, 0);
+
+      if (var && (aflags & ASS_APPEND))
+	{
+	  temp = make_variable_value (var, value, aflags);
+	  FREE (value);
+	  value = temp;
+	}
+    }
+
+  if (temporary_env == 0)
+    temporary_env = hash_create (TEMPENV_HASH_BUCKETS);
+
+  var = hash_lookup (name, temporary_env);
+  if (var == 0)
+    var = make_new_variable (name, temporary_env);
+  else
+    FREE (value_cell (var));
+
+  if (value == 0)
+    {
+      value = (char *)xmalloc (1);	/* like do_assignment_internal */
+      value[0] = '\0';
+    }
+
+  var_setvalue (var, value);
+  var->attributes |= (att_exported|att_tempvar);
+  var->context = variable_context;	/* XXX */
+
+  INVALIDATE_EXPORTSTR (var);
+  var->exportstr = mk_env_string (name, value, 0);
+
+  array_needs_making = 1;
+
+  if (flags)
+    stupidly_hack_special_variables (name);
+
+  if (echo_command_at_execute)
+    /* The Korn shell prints the `+ ' in front of assignment statements,
+	so we do too. */
+    xtrace_print_assignment (name, value, 0, 1);
+
+  free (name);
+  return 1;
+}
+
+/* **************************************************************** */
+/*								    */
+/*			Copying variables			    */
+/*								    */
+/* **************************************************************** */
+
+#ifdef INCLUDE_UNUSED
+/* Copy VAR to a new data structure and return that structure. */
+SHELL_VAR *
+copy_variable (var)
+     SHELL_VAR *var;
+{
+  SHELL_VAR *copy = (SHELL_VAR *)NULL;
+
+  if (var)
+    {
+      copy = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
+
+      copy->attributes = var->attributes;
+      copy->name = savestring (var->name);
+
+      if (function_p (var))
+	var_setfunc (copy, copy_command (function_cell (var)));
+#if defined (ARRAY_VARS)
+      else if (array_p (var))
+	var_setarray (copy, array_copy (array_cell (var)));
+      else if (assoc_p (var))
+	var_setassoc (copy, assoc_copy (assoc_cell (var)));
+#endif
+      else if (nameref_cell (var))	/* XXX - nameref */
+	var_setref (copy, savestring (nameref_cell (var)));
+      else if (value_cell (var))	/* XXX - nameref */
+	var_setvalue (copy, savestring (value_cell (var)));
+      else
+	var_setvalue (copy, (char *)NULL);
+
+      copy->dynamic_value = var->dynamic_value;
+      copy->assign_func = var->assign_func;
+
+      copy->exportstr = COPY_EXPORTSTR (var);
+
+      copy->context = var->context;
+    }
+  return (copy);
+}
+#endif
+
+/* **************************************************************** */
+/*								    */
+/*		  Deleting and unsetting variables		    */
+/*								    */
+/* **************************************************************** */
+
+/* Dispose of the information attached to VAR. */
+static void
+dispose_variable_value (var)
+     SHELL_VAR *var;
+{
+  if (function_p (var))
+    dispose_command (function_cell (var));
+#if defined (ARRAY_VARS)
+  else if (array_p (var))
+    array_dispose (array_cell (var));
+  else if (assoc_p (var))
+    assoc_dispose (assoc_cell (var));
+#endif
+  else if (nameref_p (var))
+    FREE (nameref_cell (var));
+  else
+    FREE (value_cell (var));
+}
+
+void
+dispose_variable (var)
+     SHELL_VAR *var;
+{
+  if (var == 0)
+    return;
+
+  if (nofree_p (var) == 0)
+    dispose_variable_value (var);
+
+  FREE_EXPORTSTR (var);
+
+  free (var->name);
+
+  if (exported_p (var))
+    array_needs_making = 1;
+
+  free (var);
+}
+
+/* Unset the shell variable referenced by NAME.  Unsetting a nameref variable
+   unsets the variable it resolves to but leaves the nameref alone. */
+int
+unbind_variable (name)
+     const char *name;
+{
+  SHELL_VAR *v, *nv;
+  int r;
+
+  v = var_lookup (name, shell_variables);
+  nv = (v && nameref_p (v)) ? find_variable_nameref (v) : (SHELL_VAR *)NULL;
+
+  r = nv ? makunbound (nv->name, shell_variables) : makunbound (name, shell_variables);
+  return r;
+}
+
+/* Unbind NAME, where NAME is assumed to be a nameref variable */
+int
+unbind_nameref (name)
+     const char *name;
+{
+  SHELL_VAR *v;
+
+  v = var_lookup (name, shell_variables);
+  if (v && nameref_p (v))
+    return makunbound (name, shell_variables);
+  return 0;
+}
+
+/* Unset the shell function named NAME. */
+int
+unbind_func (name)
+     const char *name;
+{
+  BUCKET_CONTENTS *elt;
+  SHELL_VAR *func;
+
+  elt = hash_remove (name, shell_functions, 0);
+
+  if (elt == 0)
+    return -1;
+
+#if defined (PROGRAMMABLE_COMPLETION)
+  set_itemlist_dirty (&it_functions);
+#endif
+
+  func = (SHELL_VAR *)elt->data;
+  if (func)
+    {
+      if (exported_p (func))
+	array_needs_making++;
+      dispose_variable (func);
+    }
+
+  free (elt->key);
+  free (elt);
+
+  return 0;  
+}
+
+#if defined (DEBUGGER)
+int
+unbind_function_def (name)
+     const char *name;
+{
+  BUCKET_CONTENTS *elt;
+  FUNCTION_DEF *funcdef;
+
+  elt = hash_remove (name, shell_function_defs, 0);
+
+  if (elt == 0)
+    return -1;
+
+  funcdef = (FUNCTION_DEF *)elt->data;
+  if (funcdef)
+    dispose_function_def (funcdef);
+
+  free (elt->key);
+  free (elt);
+
+  return 0;  
+}
+#endif /* DEBUGGER */
+
+int
+delete_var (name, vc)
+     const char *name;
+     VAR_CONTEXT *vc;
+{
+  BUCKET_CONTENTS *elt;
+  SHELL_VAR *old_var;
+  VAR_CONTEXT *v;
+
+  for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down)
+    if (elt = hash_remove (name, v->table, 0))
+      break;
+
+  if (elt == 0)
+    return (-1);
+
+  old_var = (SHELL_VAR *)elt->data;
+  free (elt->key);
+  free (elt);
+
+  dispose_variable (old_var);
+  return (0);
+}
+
+/* Make the variable associated with NAME go away.  HASH_LIST is the
+   hash table from which this variable should be deleted (either
+   shell_variables or shell_functions).
+   Returns non-zero if the variable couldn't be found. */
+int
+makunbound (name, vc)
+     const char *name;
+     VAR_CONTEXT *vc;
+{
+  BUCKET_CONTENTS *elt, *new_elt;
+  SHELL_VAR *old_var;
+  VAR_CONTEXT *v;
+  char *t;
+
+  for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down)
+    if (elt = hash_remove (name, v->table, 0))
+      break;
+
+  if (elt == 0)
+    return (-1);
+
+  old_var = (SHELL_VAR *)elt->data;
+
+  if (old_var && exported_p (old_var))
+    array_needs_making++;
+
+  /* If we're unsetting a local variable and we're still executing inside
+     the function, just mark the variable as invisible.  The function
+     eventually called by pop_var_context() will clean it up later.  This
+     must be done so that if the variable is subsequently assigned a new
+     value inside the function, the `local' attribute is still present.
+     We also need to add it back into the correct hash table. */
+  if (old_var && local_p (old_var) && variable_context == old_var->context)
+    {
+      if (nofree_p (old_var))
+	var_setvalue (old_var, (char *)NULL);
+#if defined (ARRAY_VARS)
+      else if (array_p (old_var))
+	array_dispose (array_cell (old_var));
+      else if (assoc_p (old_var))
+	assoc_dispose (assoc_cell (old_var));
+#endif
+      else if (nameref_p (old_var))
+	FREE (nameref_cell (old_var));
+      else
+	FREE (value_cell (old_var));
+      /* Reset the attributes.  Preserve the export attribute if the variable
+	 came from a temporary environment.  Make sure it stays local, and
+	 make it invisible. */ 
+      old_var->attributes = (exported_p (old_var) && tempvar_p (old_var)) ? att_exported : 0;
+      VSETATTR (old_var, att_local);
+      VSETATTR (old_var, att_invisible);
+      var_setvalue (old_var, (char *)NULL);
+      INVALIDATE_EXPORTSTR (old_var);
+
+      new_elt = hash_insert (savestring (old_var->name), v->table, 0);
+      new_elt->data = (PTR_T)old_var;
+      stupidly_hack_special_variables (old_var->name);
+
+      free (elt->key);
+      free (elt);
+      return (0);
+    }
+
+  /* Have to save a copy of name here, because it might refer to
+     old_var->name.  If so, stupidly_hack_special_variables will
+     reference freed memory. */
+  t = savestring (name);
+
+  free (elt->key);
+  free (elt);
+
+  dispose_variable (old_var);
+  stupidly_hack_special_variables (t);
+  free (t);
+
+  return (0);
+}
+
+/* Get rid of all of the variables in the current context. */
+void
+kill_all_local_variables ()
+{
+  VAR_CONTEXT *vc;
+
+  for (vc = shell_variables; vc; vc = vc->down)
+    if (vc_isfuncenv (vc) && vc->scope == variable_context)
+      break;
+  if (vc == 0)
+    return;		/* XXX */
+
+  if (vc->table && vc_haslocals (vc))
+    {
+      delete_all_variables (vc->table);
+      hash_dispose (vc->table);
+    }
+  vc->table = (HASH_TABLE *)NULL;
+}
+
+static void
+free_variable_hash_data (data)
+     PTR_T data;
+{
+  SHELL_VAR *var;
+
+  var = (SHELL_VAR *)data;
+  dispose_variable (var);
+}
+
+/* Delete the entire contents of the hash table. */
+void
+delete_all_variables (hashed_vars)
+     HASH_TABLE *hashed_vars;
+{
+  hash_flush (hashed_vars, free_variable_hash_data);
+}
+
+/* **************************************************************** */
+/*								    */
+/*		     Setting variable attributes		    */
+/*								    */
+/* **************************************************************** */
+
+#define FIND_OR_MAKE_VARIABLE(name, entry) \
+  do \
+    { \
+      entry = find_variable (name); \
+      if (!entry) \
+	{ \
+	  entry = bind_variable (name, "", 0); \
+	  if (!no_invisible_vars && entry) entry->attributes |= att_invisible; \
+	} \
+    } \
+  while (0)
+
+/* Make the variable associated with NAME be readonly.
+   If NAME does not exist yet, create it. */
+void
+set_var_read_only (name)
+     char *name;
+{
+  SHELL_VAR *entry;
+
+  FIND_OR_MAKE_VARIABLE (name, entry);
+  VSETATTR (entry, att_readonly);
+}
+
+#ifdef INCLUDE_UNUSED
+/* Make the function associated with NAME be readonly.
+   If NAME does not exist, we just punt, like auto_export code below. */
+void
+set_func_read_only (name)
+     const char *name;
+{
+  SHELL_VAR *entry;
+
+  entry = find_function (name);
+  if (entry)
+    VSETATTR (entry, att_readonly);
+}
+
+/* Make the variable associated with NAME be auto-exported.
+   If NAME does not exist yet, create it. */
+void
+set_var_auto_export (name)
+     char *name;
+{
+  SHELL_VAR *entry;
+
+  FIND_OR_MAKE_VARIABLE (name, entry);
+  set_auto_export (entry);
+}
+
+/* Make the function associated with NAME be auto-exported. */
+void
+set_func_auto_export (name)
+     const char *name;
+{
+  SHELL_VAR *entry;
+
+  entry = find_function (name);
+  if (entry)
+    set_auto_export (entry);
+}
+#endif
+
+/* **************************************************************** */
+/*								    */
+/*		     Creating lists of variables		    */
+/*								    */
+/* **************************************************************** */
+
+static VARLIST *
+vlist_alloc (nentries)
+     int nentries;
+{
+  VARLIST  *vlist;
+
+  vlist = (VARLIST *)xmalloc (sizeof (VARLIST));
+  vlist->list = (SHELL_VAR **)xmalloc ((nentries + 1) * sizeof (SHELL_VAR *));
+  vlist->list_size = nentries;
+  vlist->list_len = 0;
+  vlist->list[0] = (SHELL_VAR *)NULL;
+
+  return vlist;
+}
+
+static VARLIST *
+vlist_realloc (vlist, n)
+     VARLIST *vlist;
+     int n;
+{
+  if (vlist == 0)
+    return (vlist = vlist_alloc (n));
+  if (n > vlist->list_size)
+    {
+      vlist->list_size = n;
+      vlist->list = (SHELL_VAR **)xrealloc (vlist->list, (vlist->list_size + 1) * sizeof (SHELL_VAR *));
+    }
+  return vlist;
+}
+
+static void
+vlist_add (vlist, var, flags)
+     VARLIST *vlist;
+     SHELL_VAR *var;
+     int flags;
+{
+  register int i;
+
+  for (i = 0; i < vlist->list_len; i++)
+    if (STREQ (var->name, vlist->list[i]->name))
+      break;
+  if (i < vlist->list_len)
+    return;
+
+  if (i >= vlist->list_size)
+    vlist = vlist_realloc (vlist, vlist->list_size + 16);
+
+  vlist->list[vlist->list_len++] = var;
+  vlist->list[vlist->list_len] = (SHELL_VAR *)NULL;
+}
+
+/* Map FUNCTION over the variables in VAR_HASH_TABLE.  Return an array of the
+   variables for which FUNCTION returns a non-zero value.  A NULL value
+   for FUNCTION means to use all variables. */
+SHELL_VAR **
+map_over (function, vc)
+     sh_var_map_func_t *function;
+     VAR_CONTEXT *vc;
+{
+  VAR_CONTEXT *v;
+  VARLIST *vlist;
+  SHELL_VAR **ret;
+  int nentries;
+
+  for (nentries = 0, v = vc; v; v = v->down)
+    nentries += HASH_ENTRIES (v->table);
+
+  if (nentries == 0)
+    return (SHELL_VAR **)NULL;
+
+  vlist = vlist_alloc (nentries);
+
+  for (v = vc; v; v = v->down)
+    flatten (v->table, function, vlist, 0);
+
+  ret = vlist->list;
+  free (vlist);
+  return ret;
+}
+
+SHELL_VAR **
+map_over_funcs (function)
+     sh_var_map_func_t *function;
+{
+  VARLIST *vlist;
+  SHELL_VAR **ret;
+
+  if (shell_functions == 0 || HASH_ENTRIES (shell_functions) == 0)
+    return ((SHELL_VAR **)NULL);
+
+  vlist = vlist_alloc (HASH_ENTRIES (shell_functions));
+
+  flatten (shell_functions, function, vlist, 0);
+
+  ret = vlist->list;
+  free (vlist);
+  return ret;
+}
+
+/* Flatten VAR_HASH_TABLE, applying FUNC to each member and adding those
+   elements for which FUNC succeeds to VLIST->list.  FLAGS is reserved
+   for future use.  Only unique names are added to VLIST.  If FUNC is
+   NULL, each variable in VAR_HASH_TABLE is added to VLIST.  If VLIST is
+   NULL, FUNC is applied to each SHELL_VAR in VAR_HASH_TABLE.  If VLIST
+   and FUNC are both NULL, nothing happens. */
+static void
+flatten (var_hash_table, func, vlist, flags)
+     HASH_TABLE *var_hash_table;
+     sh_var_map_func_t *func;
+     VARLIST *vlist;
+     int flags;
+{
+  register int i;
+  register BUCKET_CONTENTS *tlist;
+  int r;
+  SHELL_VAR *var;
+
+  if (var_hash_table == 0 || (HASH_ENTRIES (var_hash_table) == 0) || (vlist == 0 && func == 0))
+    return;
+
+  for (i = 0; i < var_hash_table->nbuckets; i++)
+    {
+      for (tlist = hash_items (i, var_hash_table); tlist; tlist = tlist->next)
+	{
+	  var = (SHELL_VAR *)tlist->data;
+
+	  r = func ? (*func) (var) : 1;
+	  if (r && vlist)
+	    vlist_add (vlist, var, flags);
+	}
+    }
+}
+
+void
+sort_variables (array)
+     SHELL_VAR **array;
+{
+  qsort (array, strvec_len ((char **)array), sizeof (SHELL_VAR *), (QSFUNC *)qsort_var_comp);
+}
+
+static int
+qsort_var_comp (var1, var2)
+     SHELL_VAR **var1, **var2;
+{
+  int result;
+
+  if ((result = (*var1)->name[0] - (*var2)->name[0]) == 0)
+    result = strcmp ((*var1)->name, (*var2)->name);
+
+  return (result);
+}
+
+/* Apply FUNC to each variable in SHELL_VARIABLES, adding each one for
+   which FUNC succeeds to an array of SHELL_VAR *s.  Returns the array. */
+static SHELL_VAR **
+vapply (func)
+     sh_var_map_func_t *func;
+{
+  SHELL_VAR **list;
+
+  list = map_over (func, shell_variables);
+  if (list /* && posixly_correct */)
+    sort_variables (list);
+  return (list);
+}
+
+/* Apply FUNC to each variable in SHELL_FUNCTIONS, adding each one for
+   which FUNC succeeds to an array of SHELL_VAR *s.  Returns the array. */
+static SHELL_VAR **
+fapply (func)
+     sh_var_map_func_t *func;
+{
+  SHELL_VAR **list;
+
+  list = map_over_funcs (func);
+  if (list /* && posixly_correct */)
+    sort_variables (list);
+  return (list);
+}
+
+/* Create a NULL terminated array of all the shell variables. */
+SHELL_VAR **
+all_shell_variables ()
+{
+  return (vapply ((sh_var_map_func_t *)NULL));
+}
+
+/* Create a NULL terminated array of all the shell functions. */
+SHELL_VAR **
+all_shell_functions ()
+{
+  return (fapply ((sh_var_map_func_t *)NULL));
+}
+
+static int
+visible_var (var)
+     SHELL_VAR *var;
+{
+  return (invisible_p (var) == 0);
+}
+
+SHELL_VAR **
+all_visible_functions ()
+{
+  return (fapply (visible_var));
+}
+
+SHELL_VAR **
+all_visible_variables ()
+{
+  return (vapply (visible_var));
+}
+
+/* Return non-zero if the variable VAR is visible and exported.  Array
+   variables cannot be exported. */
+static int
+visible_and_exported (var)
+     SHELL_VAR *var;
+{
+  return (invisible_p (var) == 0 && exported_p (var));
+}
+
+/* Candidate variables for the export environment are either valid variables
+   with the export attribute or invalid variables inherited from the initial
+   environment and simply passed through. */
+static int
+export_environment_candidate (var)
+     SHELL_VAR *var;
+{
+  return (exported_p (var) && (invisible_p (var) == 0 || imported_p (var)));
+}
+
+/* Return non-zero if VAR is a local variable in the current context and
+   is exported. */
+static int
+local_and_exported (var)
+     SHELL_VAR *var;
+{
+  return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context && exported_p (var));
+}
+
+SHELL_VAR **
+all_exported_variables ()
+{
+  return (vapply (visible_and_exported));
+}
+
+SHELL_VAR **
+local_exported_variables ()
+{
+  return (vapply (local_and_exported));
+}
+
+static int
+variable_in_context (var)
+     SHELL_VAR *var;
+{
+  return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context);
+}
+
+SHELL_VAR **
+all_local_variables ()
+{
+  VARLIST *vlist;
+  SHELL_VAR **ret;
+  VAR_CONTEXT *vc;
+
+  vc = shell_variables;
+  for (vc = shell_variables; vc; vc = vc->down)
+    if (vc_isfuncenv (vc) && vc->scope == variable_context)
+      break;
+
+  if (vc == 0)
+    {
+      internal_error (_("all_local_variables: no function context at current scope"));
+      return (SHELL_VAR **)NULL;
+    }
+  if (vc->table == 0 || HASH_ENTRIES (vc->table) == 0 || vc_haslocals (vc) == 0)
+    return (SHELL_VAR **)NULL;
+    
+  vlist = vlist_alloc (HASH_ENTRIES (vc->table));
+
+  flatten (vc->table, variable_in_context, vlist, 0);
+
+  ret = vlist->list;
+  free (vlist);
+  if (ret)
+    sort_variables (ret);
+  return ret;
+}
+
+#if defined (ARRAY_VARS)
+/* Return non-zero if the variable VAR is visible and an array. */
+static int
+visible_array_vars (var)
+     SHELL_VAR *var;
+{
+  return (invisible_p (var) == 0 && array_p (var));
+}
+
+SHELL_VAR **
+all_array_variables ()
+{
+  return (vapply (visible_array_vars));
+}
+#endif /* ARRAY_VARS */
+
+char **
+all_variables_matching_prefix (prefix)
+     const char *prefix;
+{
+  SHELL_VAR **varlist;
+  char **rlist;
+  int vind, rind, plen;
+
+  plen = STRLEN (prefix);
+  varlist = all_visible_variables ();
+  for (vind = 0; varlist && varlist[vind]; vind++)
+    ;
+  if (varlist == 0 || vind == 0)
+    return ((char **)NULL);
+  rlist = strvec_create (vind + 1);
+  for (vind = rind = 0; varlist[vind]; vind++)
+    {
+      if (plen == 0 || STREQN (prefix, varlist[vind]->name, plen))
+	rlist[rind++] = savestring (varlist[vind]->name);
+    }
+  rlist[rind] = (char *)0;
+  free (varlist);
+
+  return rlist;
+}
+
+/* **************************************************************** */
+/*								    */
+/*		 Managing temporary variable scopes		    */
+/*								    */
+/* **************************************************************** */
+
+/* Make variable NAME have VALUE in the temporary environment. */
+static SHELL_VAR *
+bind_tempenv_variable (name, value)
+     const char *name;
+     char *value;
+{
+  SHELL_VAR *var;
+
+  var = temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL;
+
+  if (var)
+    {
+      FREE (value_cell (var));
+      var_setvalue (var, savestring (value));
+      INVALIDATE_EXPORTSTR (var);
+    }
+
+  return (var);
+}
+
+/* Find a variable in the temporary environment that is named NAME.
+   Return the SHELL_VAR *, or NULL if not found. */
+SHELL_VAR *
+find_tempenv_variable (name)
+     const char *name;
+{
+  return (temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL);
+}
+
+char **tempvar_list;
+int tvlist_ind;
+
+/* Push the variable described by (SHELL_VAR *)DATA down to the next
+   variable context from the temporary environment. */
+static void
+push_temp_var (data)
+     PTR_T data;
+{
+  SHELL_VAR *var, *v;
+  HASH_TABLE *binding_table;
+
+  var = (SHELL_VAR *)data;
+
+  binding_table = shell_variables->table;
+  if (binding_table == 0)
+    {
+      if (shell_variables == global_variables)
+	/* shouldn't happen */
+	binding_table = shell_variables->table = global_variables->table = hash_create (0);
+      else
+	binding_table = shell_variables->table = hash_create (TEMPENV_HASH_BUCKETS);
+    }
+
+  v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, 0);
+
+  /* XXX - should we set the context here?  It shouldn't matter because of how
+     assign_in_env works, but might want to check. */
+  if (binding_table == global_variables->table)		/* XXX */
+    var->attributes &= ~(att_tempvar|att_propagate);
+  else
+    {
+      var->attributes |= att_propagate;
+      if  (binding_table == shell_variables->table)
+	shell_variables->flags |= VC_HASTMPVAR;
+    }
+  v->attributes |= var->attributes;
+
+  if (find_special_var (var->name) >= 0)
+    tempvar_list[tvlist_ind++] = savestring (var->name);
+
+  dispose_variable (var);
+}
+
+static void
+propagate_temp_var (data)
+     PTR_T data;
+{
+  SHELL_VAR *var;
+
+  var = (SHELL_VAR *)data;
+  if (tempvar_p (var) && (var->attributes & att_propagate))
+    push_temp_var (data);
+  else
+    {
+      if (find_special_var (var->name) >= 0)
+	tempvar_list[tvlist_ind++] = savestring (var->name);
+      dispose_variable (var);
+    }
+}
+
+/* Free the storage used in the hash table for temporary
+   environment variables.  PUSHF is a function to be called
+   to free each hash table entry.  It takes care of pushing variables
+   to previous scopes if appropriate.  PUSHF stores names of variables
+   that require special handling (e.g., IFS) on tempvar_list, so this
+   function can call stupidly_hack_special_variables on all the
+   variables in the list when the temporary hash table is destroyed. */
+static void
+dispose_temporary_env (pushf)
+     sh_free_func_t *pushf;
+{
+  int i;
+
+  tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1);
+  tempvar_list[tvlist_ind = 0] = 0;
+    
+  hash_flush (temporary_env, pushf);
+  hash_dispose (temporary_env);
+  temporary_env = (HASH_TABLE *)NULL;
+
+  tempvar_list[tvlist_ind] = 0;
+
+  array_needs_making = 1;
+
+#if 0
+  sv_ifs ("IFS");		/* XXX here for now -- check setifs in assign_in_env */  
+#endif
+  for (i = 0; i < tvlist_ind; i++)
+    stupidly_hack_special_variables (tempvar_list[i]);
+
+  strvec_dispose (tempvar_list);
+  tempvar_list = 0;
+  tvlist_ind = 0;
+}
+
+void
+dispose_used_env_vars ()
+{
+  if (temporary_env)
+    {
+      dispose_temporary_env (propagate_temp_var);
+      maybe_make_export_env ();
+    }
+}
+
+/* Take all of the shell variables in the temporary environment HASH_TABLE
+   and make shell variables from them at the current variable context. */
+void
+merge_temporary_env ()
+{
+  if (temporary_env)
+    dispose_temporary_env (push_temp_var);
+}
+
+/* **************************************************************** */
+/*								    */
+/*	     Creating and manipulating the environment		    */
+/*								    */
+/* **************************************************************** */
+
+static inline char *
+mk_env_string (name, value, isfunc)
+     const char *name, *value;
+     int isfunc;
+{
+  size_t name_len, value_len;
+  char	*p, *q;
+
+  name_len = strlen (name);
+  value_len = STRLEN (value);
+
+  /* If we are exporting a shell function, construct the encoded function
+     name. */
+  if (isfunc && value)
+    {
+      p = (char *)xmalloc (BASHFUNC_PREFLEN + name_len + BASHFUNC_SUFFLEN + value_len + 2);
+      q = p;
+      memcpy (q, BASHFUNC_PREFIX, BASHFUNC_PREFLEN);
+      q += BASHFUNC_PREFLEN;
+      memcpy (q, name, name_len);
+      q += name_len;
+      memcpy (q, BASHFUNC_SUFFIX, BASHFUNC_SUFFLEN);
+      q += BASHFUNC_SUFFLEN;
+    }
+  else
+    {
+      p = (char *)xmalloc (2 + name_len + value_len);
+      memcpy (p, name, name_len);
+      q = p + name_len;
+    }
+
+  q[0] = '=';
+  if (value && *value)
+    memcpy (q + 1, value, value_len + 1);
+  else
+    q[1] = '\0';
+
+  return (p);
+}
+
+#ifdef DEBUG
+/* Debugging */
+static int
+valid_exportstr (v)
+     SHELL_VAR *v;
+{
+  char *s;
+
+  s = v->exportstr;
+  if (s == 0)
+    {
+      internal_error (_("%s has null exportstr"), v->name);
+      return (0);
+    }
+  if (legal_variable_starter ((unsigned char)*s) == 0)
+    {
+      internal_error (_("invalid character %d in exportstr for %s"), *s, v->name);
+      return (0);
+    }
+  for (s = v->exportstr + 1; s && *s; s++)
+    {
+      if (*s == '=')
+	break;
+      if (legal_variable_char ((unsigned char)*s) == 0)
+	{
+	  internal_error (_("invalid character %d in exportstr for %s"), *s, v->name);
+	  return (0);
+	}
+    }
+  if (*s != '=')
+    {
+      internal_error (_("no `=' in exportstr for %s"), v->name);
+      return (0);
+    }
+  return (1);
+}
+#endif
+
+static char **
+make_env_array_from_var_list (vars)
+     SHELL_VAR **vars;
+{
+  register int i, list_index;
+  register SHELL_VAR *var;
+  char **list, *value;
+
+  list = strvec_create ((1 + strvec_len ((char **)vars)));
+
+#define USE_EXPORTSTR (value == var->exportstr)
+
+  for (i = 0, list_index = 0; var = vars[i]; i++)
+    {
+#if defined (__CYGWIN__)
+      /* We don't use the exportstr stuff on Cygwin at all. */
+      INVALIDATE_EXPORTSTR (var);
+#endif
+      if (var->exportstr)
+	value = var->exportstr;
+      else if (function_p (var))
+	value = named_function_string ((char *)NULL, function_cell (var), 0);
+#if defined (ARRAY_VARS)
+      else if (array_p (var))
+#  if ARRAY_EXPORT
+	value = array_to_assignment_string (array_cell (var));
+#  else
+	continue;	/* XXX array vars cannot yet be exported */
+#  endif /* ARRAY_EXPORT */
+      else if (assoc_p (var))
+#  if 0
+	value = assoc_to_assignment_string (assoc_cell (var));
+#  else
+	continue;	/* XXX associative array vars cannot yet be exported */
+#  endif
+#endif
+      else
+	value = value_cell (var);
+
+      if (value)
+	{
+	  /* Gee, I'd like to get away with not using savestring() if we're
+	     using the cached exportstr... */
+	  list[list_index] = USE_EXPORTSTR ? savestring (value)
+					   : mk_env_string (var->name, value, function_p (var));
+
+	  if (USE_EXPORTSTR == 0)
+	    SAVE_EXPORTSTR (var, list[list_index]);
+
+	  list_index++;
+#undef USE_EXPORTSTR
+
+#if 0	/* not yet */
+#if defined (ARRAY_VARS)
+	  if (array_p (var) || assoc_p (var))
+	    free (value);
+#endif
+#endif
+	}
+    }
+
+  list[list_index] = (char *)NULL;
+  return (list);
+}
+
+/* Make an array of assignment statements from the hash table
+   HASHED_VARS which contains SHELL_VARs.  Only visible, exported
+   variables are eligible. */
+static char **
+make_var_export_array (vcxt)
+     VAR_CONTEXT *vcxt;
+{
+  char **list;
+  SHELL_VAR **vars;
+
+#if 0
+  vars = map_over (visible_and_exported, vcxt);
+#else
+  vars = map_over (export_environment_candidate, vcxt);
+#endif
+
+  if (vars == 0)
+    return (char **)NULL;
+
+  list = make_env_array_from_var_list (vars);
+
+  free (vars);
+  return (list);
+}
+
+static char **
+make_func_export_array ()
+{
+  char **list;
+  SHELL_VAR **vars;
+
+  vars = map_over_funcs (visible_and_exported);
+  if (vars == 0)
+    return (char **)NULL;
+
+  list = make_env_array_from_var_list (vars);
+
+  free (vars);
+  return (list);
+}
+
+/* Add ENVSTR to the end of the exported environment, EXPORT_ENV. */
+#define add_to_export_env(envstr,do_alloc) \
+do \
+  { \
+    if (export_env_index >= (export_env_size - 1)) \
+      { \
+	export_env_size += 16; \
+	export_env = strvec_resize (export_env, export_env_size); \
+	environ = export_env; \
+      } \
+    export_env[export_env_index++] = (do_alloc) ? savestring (envstr) : envstr; \
+    export_env[export_env_index] = (char *)NULL; \
+  } while (0)
+
+/* Add ASSIGN to EXPORT_ENV, or supercede a previous assignment in the
+   array with the same left-hand side.  Return the new EXPORT_ENV. */
+char **
+add_or_supercede_exported_var (assign, do_alloc)
+     char *assign;
+     int do_alloc;
+{
+  register int i;
+  int equal_offset;
+
+  equal_offset = assignment (assign, 0);
+  if (equal_offset == 0)
+    return (export_env);
+
+  /* If this is a function, then only supersede the function definition.
+     We do this by including the `=() {' in the comparison, like
+     initialize_shell_variables does. */
+  if (assign[equal_offset + 1] == '(' &&
+     strncmp (assign + equal_offset + 2, ") {", 3) == 0)		/* } */
+    equal_offset += 4;
+
+  for (i = 0; i < export_env_index; i++)
+    {
+      if (STREQN (assign, export_env[i], equal_offset + 1))
+	{
+	  free (export_env[i]);
+	  export_env[i] = do_alloc ? savestring (assign) : assign;
+	  return (export_env);
+	}
+    }
+  add_to_export_env (assign, do_alloc);
+  return (export_env);
+}
+
+static void
+add_temp_array_to_env (temp_array, do_alloc, do_supercede)
+     char **temp_array;
+     int do_alloc, do_supercede;
+{
+  register int i;
+
+  if (temp_array == 0)
+    return;
+
+  for (i = 0; temp_array[i]; i++)
+    {
+      if (do_supercede)
+	export_env = add_or_supercede_exported_var (temp_array[i], do_alloc);
+      else
+	add_to_export_env (temp_array[i], do_alloc);
+    }
+
+  free (temp_array);
+}
+
+/* Make the environment array for the command about to be executed, if the
+   array needs making.  Otherwise, do nothing.  If a shell action could
+   change the array that commands receive for their environment, then the
+   code should `array_needs_making++'.
+
+   The order to add to the array is:
+   	temporary_env
+   	list of var contexts whose head is shell_variables
+  	shell_functions
+
+  This is the shell variable lookup order.  We add only new variable
+  names at each step, which allows local variables and variables in
+  the temporary environments to shadow variables in the global (or
+  any previous) scope.
+*/
+
+static int
+n_shell_variables ()
+{
+  VAR_CONTEXT *vc;
+  int n;
+
+  for (n = 0, vc = shell_variables; vc; vc = vc->down)
+    n += HASH_ENTRIES (vc->table);
+  return n;
+}
+
+int
+chkexport (name)
+     char *name;
+{
+  SHELL_VAR *v;
+
+  v = find_variable (name);
+  if (v && exported_p (v))
+    {
+      array_needs_making = 1;
+      maybe_make_export_env ();
+      return 1;
+    }
+  return 0;
+}
+
+void
+maybe_make_export_env ()
+{
+  register char **temp_array;
+  int new_size;
+  VAR_CONTEXT *tcxt;
+
+  if (array_needs_making)
+    {
+      if (export_env)
+	strvec_flush (export_env);
+
+      /* Make a guess based on how many shell variables and functions we
+	 have.  Since there will always be array variables, and array
+	 variables are not (yet) exported, this will always be big enough
+	 for the exported variables and functions. */
+      new_size = n_shell_variables () + HASH_ENTRIES (shell_functions) + 1 +
+		 HASH_ENTRIES (temporary_env);
+      if (new_size > export_env_size)
+	{
+	  export_env_size = new_size;
+	  export_env = strvec_resize (export_env, export_env_size);
+	  environ = export_env;
+	}
+      export_env[export_env_index = 0] = (char *)NULL;
+
+      /* Make a dummy variable context from the temporary_env, stick it on
+	 the front of shell_variables, call make_var_export_array on the
+	 whole thing to flatten it, and convert the list of SHELL_VAR *s
+	 to the form needed by the environment. */
+      if (temporary_env)
+	{
+	  tcxt = new_var_context ((char *)NULL, 0);
+	  tcxt->table = temporary_env;
+	  tcxt->down = shell_variables;
+	}
+      else
+	tcxt = shell_variables;
+      
+      temp_array = make_var_export_array (tcxt);
+      if (temp_array)
+	add_temp_array_to_env (temp_array, 0, 0);
+
+      if (tcxt != shell_variables)
+	free (tcxt);
+
+#if defined (RESTRICTED_SHELL)
+      /* Restricted shells may not export shell functions. */
+      temp_array = restricted ? (char **)0 : make_func_export_array ();
+#else
+      temp_array = make_func_export_array ();
+#endif
+      if (temp_array)
+	add_temp_array_to_env (temp_array, 0, 0);
+
+      array_needs_making = 0;
+    }
+}
+
+/* This is an efficiency hack.  PWD and OLDPWD are auto-exported, so
+   we will need to remake the exported environment every time we
+   change directories.  `_' is always put into the environment for
+   every external command, so without special treatment it will always
+   cause the environment to be remade.
+
+   If there is no other reason to make the exported environment, we can
+   just update the variables in place and mark the exported environment
+   as no longer needing a remake. */
+void
+update_export_env_inplace (env_prefix, preflen, value)
+     char *env_prefix;
+     int preflen;
+     char *value;
+{
+  char *evar;
+
+  evar = (char *)xmalloc (STRLEN (value) + preflen + 1);
+  strcpy (evar, env_prefix);
+  if (value)
+    strcpy (evar + preflen, value);
+  export_env = add_or_supercede_exported_var (evar, 0);
+}
+
+/* We always put _ in the environment as the name of this command. */
+void
+put_command_name_into_env (command_name)
+     char *command_name;
+{
+  update_export_env_inplace ("_=", 2, command_name);
+}
+
+/* **************************************************************** */
+/*								    */
+/*		      Managing variable contexts		    */
+/*								    */
+/* **************************************************************** */
+
+/* Allocate and return a new variable context with NAME and FLAGS.
+   NAME can be NULL. */
+
+VAR_CONTEXT *
+new_var_context (name, flags)
+     char *name;
+     int flags;
+{
+  VAR_CONTEXT *vc;
+
+  vc = (VAR_CONTEXT *)xmalloc (sizeof (VAR_CONTEXT));
+  vc->name = name ? savestring (name) : (char *)NULL;
+  vc->scope = variable_context;
+  vc->flags = flags;
+
+  vc->up = vc->down = (VAR_CONTEXT *)NULL;
+  vc->table = (HASH_TABLE *)NULL;
+
+  return vc;
+}
+
+/* Free a variable context and its data, including the hash table.  Dispose
+   all of the variables. */
+void
+dispose_var_context (vc)
+     VAR_CONTEXT *vc;
+{
+  FREE (vc->name);
+
+  if (vc->table)
+    {
+      delete_all_variables (vc->table);
+      hash_dispose (vc->table);
+    }
+
+  free (vc);
+}
+
+/* Set VAR's scope level to the current variable context. */
+static int
+set_context (var)
+     SHELL_VAR *var;
+{
+  return (var->context = variable_context);
+}
+
+/* Make a new variable context with NAME and FLAGS and a HASH_TABLE of
+   temporary variables, and push it onto shell_variables.  This is
+   for shell functions. */
+VAR_CONTEXT *
+push_var_context (name, flags, tempvars)
+     char *name;
+     int flags;
+     HASH_TABLE *tempvars;
+{
+  VAR_CONTEXT *vc;
+
+  vc = new_var_context (name, flags);
+  vc->table = tempvars;
+  if (tempvars)
+    {
+      /* Have to do this because the temp environment was created before
+	 variable_context was incremented. */
+      flatten (tempvars, set_context, (VARLIST *)NULL, 0);
+      vc->flags |= VC_HASTMPVAR;
+    }
+  vc->down = shell_variables;
+  shell_variables->up = vc;
+
+  return (shell_variables = vc);
+}
+
+static void
+push_func_var (data)
+     PTR_T data;
+{
+  SHELL_VAR *var, *v;
+
+  var = (SHELL_VAR *)data;
+
+  if (tempvar_p (var) && (posixly_correct || (var->attributes & att_propagate)))
+    {
+      /* Make sure we have a hash table to store the variable in while it is
+	 being propagated down to the global variables table.  Create one if
+	 we have to */
+      if ((vc_isfuncenv (shell_variables) || vc_istempenv (shell_variables)) && shell_variables->table == 0)
+	shell_variables->table = hash_create (0);
+      /* XXX - should we set v->context here? */
+      v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);
+      if (shell_variables == global_variables)
+	var->attributes &= ~(att_tempvar|att_propagate);
+      else
+	shell_variables->flags |= VC_HASTMPVAR;
+      v->attributes |= var->attributes;
+    }
+  else
+    stupidly_hack_special_variables (var->name);	/* XXX */
+
+  dispose_variable (var);
+}
+
+/* Pop the top context off of VCXT and dispose of it, returning the rest of
+   the stack. */
+void
+pop_var_context ()
+{
+  VAR_CONTEXT *ret, *vcxt;
+
+  vcxt = shell_variables;
+  if (vc_isfuncenv (vcxt) == 0)
+    {
+      internal_error (_("pop_var_context: head of shell_variables not a function context"));
+      return;
+    }
+
+  if (ret = vcxt->down)
+    {
+      ret->up = (VAR_CONTEXT *)NULL;
+      shell_variables = ret;
+      if (vcxt->table)
+	hash_flush (vcxt->table, push_func_var);
+      dispose_var_context (vcxt);
+    }
+  else
+    internal_error (_("pop_var_context: no global_variables context"));
+}
+
+/* Delete the HASH_TABLEs for all variable contexts beginning at VCXT, and
+   all of the VAR_CONTEXTs except GLOBAL_VARIABLES. */
+void
+delete_all_contexts (vcxt)
+     VAR_CONTEXT *vcxt;
+{
+  VAR_CONTEXT *v, *t;
+
+  for (v = vcxt; v != global_variables; v = t)
+    {
+      t = v->down;
+      dispose_var_context (v);
+    }    
+
+  delete_all_variables (global_variables->table);
+  shell_variables = global_variables;
+}
+
+/* **************************************************************** */
+/*								    */
+/*	   Pushing and Popping temporary variable scopes	    */
+/*								    */
+/* **************************************************************** */
+
+VAR_CONTEXT *
+push_scope (flags, tmpvars)
+     int flags;
+     HASH_TABLE *tmpvars;
+{
+  return (push_var_context ((char *)NULL, flags, tmpvars));
+}
+
+static void
+push_exported_var (data)
+     PTR_T data;
+{
+  SHELL_VAR *var, *v;
+
+  var = (SHELL_VAR *)data;
+
+  /* If a temp var had its export attribute set, or it's marked to be
+     propagated, bind it in the previous scope before disposing it. */
+  /* XXX - This isn't exactly right, because all tempenv variables have the
+    export attribute set. */
+#if 0
+  if (exported_p (var) || (var->attributes & att_propagate))
+#else
+  if (tempvar_p (var) && exported_p (var) && (var->attributes & att_propagate))
+#endif
+    {
+      var->attributes &= ~att_tempvar;		/* XXX */
+      v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);
+      if (shell_variables == global_variables)
+	var->attributes &= ~att_propagate;
+      v->attributes |= var->attributes;
+    }
+  else
+    stupidly_hack_special_variables (var->name);	/* XXX */
+
+  dispose_variable (var);
+}
+
+void
+pop_scope (is_special)
+     int is_special;
+{
+  VAR_CONTEXT *vcxt, *ret;
+
+  vcxt = shell_variables;
+  if (vc_istempscope (vcxt) == 0)
+    {
+      internal_error (_("pop_scope: head of shell_variables not a temporary environment scope"));
+      return;
+    }
+
+  ret = vcxt->down;
+  if (ret)
+    ret->up = (VAR_CONTEXT *)NULL;
+
+  shell_variables = ret;
+
+  /* Now we can take care of merging variables in VCXT into set of scopes
+     whose head is RET (shell_variables). */
+  FREE (vcxt->name);
+  if (vcxt->table)
+    {
+      if (is_special)
+	hash_flush (vcxt->table, push_func_var);
+      else
+	hash_flush (vcxt->table, push_exported_var);
+      hash_dispose (vcxt->table);
+    }
+  free (vcxt);
+
+  sv_ifs ("IFS");	/* XXX here for now */
+}
+
+/* **************************************************************** */
+/*								    */
+/*		 Pushing and Popping function contexts		    */
+/*								    */
+/* **************************************************************** */
+
+static WORD_LIST **dollar_arg_stack = (WORD_LIST **)NULL;
+static int dollar_arg_stack_slots;
+static int dollar_arg_stack_index;
+
+/* XXX - we might want to consider pushing and popping the `getopts' state
+   when we modify the positional parameters. */
+void
+push_context (name, is_subshell, tempvars)
+     char *name;	/* function name */
+     int is_subshell;
+     HASH_TABLE *tempvars;
+{
+  if (is_subshell == 0)
+    push_dollar_vars ();
+  variable_context++;
+  push_var_context (name, VC_FUNCENV, tempvars);
+}
+
+/* Only called when subshell == 0, so we don't need to check, and can
+   unconditionally pop the dollar vars off the stack. */
+void
+pop_context ()
+{
+  pop_dollar_vars ();
+  variable_context--;
+  pop_var_context ();
+
+  sv_ifs ("IFS");		/* XXX here for now */
+}
+
+/* Save the existing positional parameters on a stack. */
+void
+push_dollar_vars ()
+{
+  if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots)
+    {
+      dollar_arg_stack = (WORD_LIST **)
+	xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10)
+		  * sizeof (WORD_LIST *));
+    }
+  dollar_arg_stack[dollar_arg_stack_index++] = list_rest_of_args ();
+  dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
+}
+
+/* Restore the positional parameters from our stack. */
+void
+pop_dollar_vars ()
+{
+  if (!dollar_arg_stack || dollar_arg_stack_index == 0)
+    return;
+
+  remember_args (dollar_arg_stack[--dollar_arg_stack_index], 1);
+  dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
+  dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
+  set_dollar_vars_unchanged ();
+}
+
+void
+dispose_saved_dollar_vars ()
+{
+  if (!dollar_arg_stack || dollar_arg_stack_index == 0)
+    return;
+
+  dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
+  dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
+}
+
+/* Manipulate the special BASH_ARGV and BASH_ARGC variables. */
+
+void
+push_args (list)
+     WORD_LIST *list;
+{
+#if defined (ARRAY_VARS) && defined (DEBUGGER)
+  SHELL_VAR *bash_argv_v, *bash_argc_v;
+  ARRAY *bash_argv_a, *bash_argc_a;
+  WORD_LIST *l;
+  arrayind_t i;
+  char *t;
+
+  GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
+  GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
+
+  for (l = list, i = 0; l; l = l->next, i++)
+    array_push (bash_argv_a, l->word->word);
+
+  t = itos (i);
+  array_push (bash_argc_a, t);
+  free (t);
+#endif /* ARRAY_VARS && DEBUGGER */
+}
+
+/* Remove arguments from BASH_ARGV array.  Pop top element off BASH_ARGC
+   array and use that value as the count of elements to remove from
+   BASH_ARGV. */
+void
+pop_args ()
+{
+#if defined (ARRAY_VARS) && defined (DEBUGGER)
+  SHELL_VAR *bash_argv_v, *bash_argc_v;
+  ARRAY *bash_argv_a, *bash_argc_a;
+  ARRAY_ELEMENT *ce;
+  intmax_t i;
+
+  GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
+  GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
+
+  ce = array_shift (bash_argc_a, 1, 0);
+  if (ce == 0 || legal_number (element_value (ce), &i) == 0)
+    i = 0;
+
+  for ( ; i > 0; i--)
+    array_pop (bash_argv_a);
+  array_dispose_element (ce);
+#endif /* ARRAY_VARS && DEBUGGER */
+}
+
+/*************************************************
+ *						 *
+ *	Functions to manage special variables	 *
+ *						 *
+ *************************************************/
+
+/* Extern declarations for variables this code has to manage. */
+extern int eof_encountered, eof_encountered_limit, ignoreeof;
+
+#if defined (READLINE)
+extern int hostname_list_initialized;
+#endif
+
+/* An alist of name.function for each special variable.  Most of the
+   functions don't do much, and in fact, this would be faster with a
+   switch statement, but by the end of this file, I am sick of switch
+   statements. */
+
+#define SET_INT_VAR(name, intvar)  intvar = find_variable (name) != 0
+
+/* This table will be sorted with qsort() the first time it's accessed. */
+struct name_and_function {
+  char *name;
+  sh_sv_func_t *function;
+};
+
+static struct name_and_function special_vars[] = {
+  { "BASH_COMPAT", sv_shcompat },
+  { "BASH_XTRACEFD", sv_xtracefd },
+
+#if defined (JOB_CONTROL)
+  { "CHILD_MAX", sv_childmax },
+#endif
+
+#if defined (READLINE)
+#  if defined (STRICT_POSIX)
+  { "COLUMNS", sv_winsize },
+#  endif
+  { "COMP_WORDBREAKS", sv_comp_wordbreaks },
+#endif
+
+  { "FUNCNEST", sv_funcnest },
+
+  { "GLOBIGNORE", sv_globignore },
+
+#if defined (HISTORY)
+  { "HISTCONTROL", sv_history_control },
+  { "HISTFILESIZE", sv_histsize },
+  { "HISTIGNORE", sv_histignore },
+  { "HISTSIZE", sv_histsize },
+  { "HISTTIMEFORMAT", sv_histtimefmt },
+#endif
+
+#if defined (__CYGWIN__)
+  { "HOME", sv_home },
+#endif
+
+#if defined (READLINE)
+  { "HOSTFILE", sv_hostfile },
+#endif
+
+  { "IFS", sv_ifs },
+  { "IGNOREEOF", sv_ignoreeof },
+
+  { "LANG", sv_locale },
+  { "LC_ALL", sv_locale },
+  { "LC_COLLATE", sv_locale },
+  { "LC_CTYPE", sv_locale },
+  { "LC_MESSAGES", sv_locale },
+  { "LC_NUMERIC", sv_locale },
+  { "LC_TIME", sv_locale },
+
+#if defined (READLINE) && defined (STRICT_POSIX)
+  { "LINES", sv_winsize },
+#endif
+
+  { "MAIL", sv_mail },
+  { "MAILCHECK", sv_mail },
+  { "MAILPATH", sv_mail },
+
+  { "OPTERR", sv_opterr },
+  { "OPTIND", sv_optind },
+
+  { "PATH", sv_path },
+  { "POSIXLY_CORRECT", sv_strict_posix },
+
+#if defined (READLINE)
+  { "TERM", sv_terminal },
+  { "TERMCAP", sv_terminal },
+  { "TERMINFO", sv_terminal },
+#endif /* READLINE */
+
+  { "TEXTDOMAIN", sv_locale },
+  { "TEXTDOMAINDIR", sv_locale },
+
+#if defined (HAVE_TZSET)
+  { "TZ", sv_tz },
+#endif
+
+#if defined (HISTORY) && defined (BANG_HISTORY)
+  { "histchars", sv_histchars },
+#endif /* HISTORY && BANG_HISTORY */
+
+  { "ignoreeof", sv_ignoreeof },
+
+  { (char *)0, (sh_sv_func_t *)0 }
+};
+
+#define N_SPECIAL_VARS	(sizeof (special_vars) / sizeof (special_vars[0]) - 1)
+
+static int
+sv_compare (sv1, sv2)
+     struct name_and_function *sv1, *sv2;
+{
+  int r;
+
+  if ((r = sv1->name[0] - sv2->name[0]) == 0)
+    r = strcmp (sv1->name, sv2->name);
+  return r;
+}
+
+static inline int
+find_special_var (name)
+     const char *name;
+{
+  register int i, r;
+
+  for (i = 0; special_vars[i].name; i++)
+    {
+      r = special_vars[i].name[0] - name[0];
+      if (r == 0)
+	r = strcmp (special_vars[i].name, name);
+      if (r == 0)
+	return i;
+      else if (r > 0)
+	/* Can't match any of rest of elements in sorted list.  Take this out
+	   if it causes problems in certain environments. */
+	break;
+    }
+  return -1;
+}
+
+/* The variable in NAME has just had its state changed.  Check to see if it
+   is one of the special ones where something special happens. */
+void
+stupidly_hack_special_variables (name)
+     char *name;
+{
+  static int sv_sorted = 0;
+  int i;
+
+  if (sv_sorted == 0)	/* shouldn't need, but it's fairly cheap. */
+    {
+      qsort (special_vars, N_SPECIAL_VARS, sizeof (special_vars[0]),
+		(QSFUNC *)sv_compare);
+      sv_sorted = 1;
+    }
+
+  i = find_special_var (name);
+  if (i != -1)
+    (*(special_vars[i].function)) (name);
+}
+
+/* Special variables that need hooks to be run when they are unset as part
+   of shell reinitialization should have their sv_ functions run here. */
+void
+reinit_special_variables ()
+{
+#if defined (READLINE)
+  sv_comp_wordbreaks ("COMP_WORDBREAKS");
+#endif
+  sv_globignore ("GLOBIGNORE");
+  sv_opterr ("OPTERR");
+}
+
+void
+sv_ifs (name)
+     char *name;
+{
+  SHELL_VAR *v;
+
+  v = find_variable ("IFS");
+  setifs (v);
+}
+
+/* What to do just after the PATH variable has changed. */
+void
+sv_path (name)
+     char *name;
+{
+  /* hash -r */
+  phash_flush ();
+}
+
+/* What to do just after one of the MAILxxxx variables has changed.  NAME
+   is the name of the variable.  This is called with NAME set to one of
+   MAIL, MAILCHECK, or MAILPATH.  */
+void
+sv_mail (name)
+     char *name;
+{
+  /* If the time interval for checking the files has changed, then
+     reset the mail timer.  Otherwise, one of the pathname vars
+     to the users mailbox has changed, so rebuild the array of
+     filenames. */
+  if (name[4] == 'C')  /* if (strcmp (name, "MAILCHECK") == 0) */
+    reset_mail_timer ();
+  else
+    {
+      free_mail_files ();
+      remember_mail_dates ();
+    }
+}
+
+void
+sv_funcnest (name)
+     char *name;
+{
+  SHELL_VAR *v;
+  intmax_t num;
+
+  v = find_variable (name);
+  if (v == 0)
+    funcnest_max = 0;
+  else if (legal_number (value_cell (v), &num) == 0)
+    funcnest_max = 0;
+  else
+    funcnest_max = num;
+}
+
+/* What to do when GLOBIGNORE changes. */
+void
+sv_globignore (name)
+     char *name;
+{
+  if (privileged_mode == 0)
+    setup_glob_ignore (name);
+}
+
+#if defined (READLINE)
+void
+sv_comp_wordbreaks (name)
+     char *name;
+{
+  SHELL_VAR *sv;
+
+  sv = find_variable (name);
+  if (sv == 0)
+    reset_completer_word_break_chars ();
+}
+
+/* What to do just after one of the TERMxxx variables has changed.
+   If we are an interactive shell, then try to reset the terminal
+   information in readline. */
+void
+sv_terminal (name)
+     char *name;
+{
+  if (interactive_shell && no_line_editing == 0)
+    rl_reset_terminal (get_string_value ("TERM"));
+}
+
+void
+sv_hostfile (name)
+     char *name;
+{
+  SHELL_VAR *v;
+
+  v = find_variable (name);
+  if (v == 0)
+    clear_hostname_list ();
+  else
+    hostname_list_initialized = 0;
+}
+
+#if defined (STRICT_POSIX)
+/* In strict posix mode, we allow assignments to LINES and COLUMNS (and values
+   found in the initial environment) to override the terminal size reported by
+   the kernel. */
+void
+sv_winsize (name)
+     char *name;
+{
+  SHELL_VAR *v;
+  intmax_t xd;
+  int d;
+
+  if (posixly_correct == 0 || interactive_shell == 0 || no_line_editing)
+    return;
+
+  v = find_variable (name);
+  if (v == 0 || var_isnull (v))
+    rl_reset_screen_size ();
+  else
+    {
+      if (legal_number (value_cell (v), &xd) == 0)
+	return;
+      winsize_assignment = 1;
+      d = xd;			/* truncate */
+      if (name[0] == 'L')	/* LINES */
+	rl_set_screen_size (d, -1);
+      else			/* COLUMNS */
+	rl_set_screen_size (-1, d);
+      winsize_assignment = 0;
+    }
+}
+#endif /* STRICT_POSIX */
+#endif /* READLINE */
+
+/* Update the value of HOME in the export environment so tilde expansion will
+   work on cygwin. */
+#if defined (__CYGWIN__)
+sv_home (name)
+     char *name;
+{
+  array_needs_making = 1;
+  maybe_make_export_env ();
+}
+#endif
+
+#if defined (HISTORY)
+/* What to do after the HISTSIZE or HISTFILESIZE variables change.
+   If there is a value for this HISTSIZE (and it is numeric), then stifle
+   the history.  Otherwise, if there is NO value for this variable,
+   unstifle the history.  If name is HISTFILESIZE, and its value is
+   numeric, truncate the history file to hold no more than that many
+   lines. */
+void
+sv_histsize (name)
+     char *name;
+{
+  char *temp;
+  intmax_t num;
+  int hmax;
+
+  temp = get_string_value (name);
+
+  if (temp && *temp)
+    {
+      if (legal_number (temp, &num))
+	{
+	  hmax = num;
+	  if (hmax < 0 && name[4] == 'S')
+	    unstifle_history ();	/* unstifle history if HISTSIZE < 0 */
+	  else if (name[4] == 'S')
+	    {
+	      stifle_history (hmax);
+	      hmax = where_history ();
+	      if (history_lines_this_session > hmax)
+		history_lines_this_session = hmax;
+	    }
+	  else if (hmax >= 0)	/* truncate HISTFILE if HISTFILESIZE >= 0 */
+	    {
+	      history_truncate_file (get_string_value ("HISTFILE"), hmax);
+	      if (hmax <= history_lines_in_file)
+		history_lines_in_file = hmax;
+	    }
+	}
+    }
+  else if (name[4] == 'S')
+    unstifle_history ();
+}
+
+/* What to do after the HISTIGNORE variable changes. */
+void
+sv_histignore (name)
+     char *name;
+{
+  setup_history_ignore (name);
+}
+
+/* What to do after the HISTCONTROL variable changes. */
+void
+sv_history_control (name)
+     char *name;
+{
+  char *temp;
+  char *val;
+  int tptr;
+
+  history_control = 0;
+  temp = get_string_value (name);
+
+  if (temp == 0 || *temp == 0)
+    return;
+
+  tptr = 0;
+  while (val = extract_colon_unit (temp, &tptr))
+    {
+      if (STREQ (val, "ignorespace"))
+	history_control |= HC_IGNSPACE;
+      else if (STREQ (val, "ignoredups"))
+	history_control |= HC_IGNDUPS;
+      else if (STREQ (val, "ignoreboth"))
+	history_control |= HC_IGNBOTH;
+      else if (STREQ (val, "erasedups"))
+	history_control |= HC_ERASEDUPS;
+
+      free (val);
+    }
+}
+
+#if defined (BANG_HISTORY)
+/* Setting/unsetting of the history expansion character. */
+void
+sv_histchars (name)
+     char *name;
+{
+  char *temp;
+
+  temp = get_string_value (name);
+  if (temp)
+    {
+      history_expansion_char = *temp;
+      if (temp[0] && temp[1])
+	{
+	  history_subst_char = temp[1];
+	  if (temp[2])
+	      history_comment_char = temp[2];
+	}
+    }
+  else
+    {
+      history_expansion_char = '!';
+      history_subst_char = '^';
+      history_comment_char = '#';
+    }
+}
+#endif /* BANG_HISTORY */
+
+void
+sv_histtimefmt (name)
+     char *name;
+{
+  SHELL_VAR *v;
+
+  if (v = find_variable (name))
+    {
+      if (history_comment_char == 0)
+	history_comment_char = '#';
+    }
+  history_write_timestamps = (v != 0);
+}
+#endif /* HISTORY */
+
+#if defined (HAVE_TZSET)
+void
+sv_tz (name)
+     char *name;
+{
+  if (chkexport (name))
+    tzset ();
+}
+#endif
+
+/* If the variable exists, then the value of it can be the number
+   of times we actually ignore the EOF.  The default is small,
+   (smaller than csh, anyway). */
+void
+sv_ignoreeof (name)
+     char *name;
+{
+  SHELL_VAR *tmp_var;
+  char *temp;
+
+  eof_encountered = 0;
+
+  tmp_var = find_variable (name);
+  ignoreeof = tmp_var != 0;
+  temp = tmp_var ? value_cell (tmp_var) : (char *)NULL;
+  if (temp)
+    eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10;
+  set_shellopts ();	/* make sure `ignoreeof' is/is not in $SHELLOPTS */
+}
+
+void
+sv_optind (name)
+     char *name;
+{
+  char *tt;
+  int s;
+
+  tt = get_string_value ("OPTIND");
+  if (tt && *tt)
+    {
+      s = atoi (tt);
+
+      /* According to POSIX, setting OPTIND=1 resets the internal state
+	 of getopt (). */
+      if (s < 0 || s == 1)
+	s = 0;
+    }
+  else
+    s = 0;
+  getopts_reset (s);
+}
+
+void
+sv_opterr (name)
+     char *name;
+{
+  char *tt;
+
+  tt = get_string_value ("OPTERR");
+  sh_opterr = (tt && *tt) ? atoi (tt) : 1;
+}
+
+void
+sv_strict_posix (name)
+     char *name;
+{
+  SET_INT_VAR (name, posixly_correct);
+  posix_initialize (posixly_correct);
+#if defined (READLINE)
+  if (interactive_shell)
+    posix_readline_initialize (posixly_correct);
+#endif /* READLINE */
+  set_shellopts ();	/* make sure `posix' is/is not in $SHELLOPTS */
+}
+
+void
+sv_locale (name)
+     char *name;
+{
+  char *v;
+  int r;
+
+  v = get_string_value (name);
+  if (name[0] == 'L' && name[1] == 'A')	/* LANG */
+    r = set_lang (name, v);
+  else
+    r = set_locale_var (name, v);		/* LC_*, TEXTDOMAIN* */
+
+#if 1
+  if (r == 0 && posixly_correct)
+    last_command_exit_value = 1;
+#endif
+}
+
+#if defined (ARRAY_VARS)
+void
+set_pipestatus_array (ps, nproc)
+     int *ps;
+     int nproc;
+{
+  SHELL_VAR *v;
+  ARRAY *a;
+  ARRAY_ELEMENT *ae;
+  register int i;
+  char *t, tbuf[INT_STRLEN_BOUND(int) + 1];
+
+  v = find_variable ("PIPESTATUS");
+  if (v == 0)
+    v = make_new_array_variable ("PIPESTATUS");
+  if (array_p (v) == 0)
+    return;		/* Do nothing if not an array variable. */
+  a = array_cell (v);
+
+  if (a == 0 || array_num_elements (a) == 0)
+    {
+      for (i = 0; i < nproc; i++)	/* was ps[i] != -1, not i < nproc */
+	{
+	  t = inttostr (ps[i], tbuf, sizeof (tbuf));
+	  array_insert (a, i, t);
+	}
+      return;
+    }
+
+  /* Fast case */
+  if (array_num_elements (a) == nproc && nproc == 1)
+    {
+      ae = element_forw (a->head);
+      free (element_value (ae));
+      ae->value = itos (ps[0]);
+    }
+  else if (array_num_elements (a) <= nproc)
+    {
+      /* modify in array_num_elements members in place, then add */
+      ae = a->head;
+      for (i = 0; i < array_num_elements (a); i++)
+	{
+	  ae = element_forw (ae);
+	  free (element_value (ae));
+	  ae->value = itos (ps[i]);
+	}
+      /* add any more */
+      for ( ; i < nproc; i++)
+	{
+	  t = inttostr (ps[i], tbuf, sizeof (tbuf));
+	  array_insert (a, i, t);
+	}
+    }
+  else
+    {
+      /* deleting elements.  it's faster to rebuild the array. */	  
+      array_flush (a);
+      for (i = 0; ps[i] != -1; i++)
+	{
+	  t = inttostr (ps[i], tbuf, sizeof (tbuf));
+	  array_insert (a, i, t);
+	}
+    }
+}
+
+ARRAY *
+save_pipestatus_array ()
+{
+  SHELL_VAR *v;
+  ARRAY *a, *a2;
+
+  v = find_variable ("PIPESTATUS");
+  if (v == 0 || array_p (v) == 0 || array_cell (v) == 0)
+    return ((ARRAY *)NULL);
+    
+  a = array_cell (v);
+  a2 = array_copy (array_cell (v));
+
+  return a2;
+}
+
+void
+restore_pipestatus_array (a)
+     ARRAY *a;
+{
+  SHELL_VAR *v;
+  ARRAY *a2;
+
+  v = find_variable ("PIPESTATUS");
+  /* XXX - should we still assign even if existing value is NULL? */
+  if (v == 0 || array_p (v) == 0 || array_cell (v) == 0)
+    return;
+
+  a2 = array_cell (v);
+  var_setarray (v, a); 
+
+  array_dispose (a2);
+}
+#endif
+
+void
+set_pipestatus_from_exit (s)
+     int s;
+{
+#if defined (ARRAY_VARS)
+  static int v[2] = { 0, -1 };
+
+  v[0] = s;
+  set_pipestatus_array (v, 1);
+#endif
+}
+
+void
+sv_xtracefd (name)
+     char *name;
+{
+  SHELL_VAR *v;
+  char *t, *e;
+  int fd;
+  FILE *fp;
+
+  v = find_variable (name);
+  if (v == 0)
+    {
+      xtrace_reset ();
+      return;
+    }
+
+  t = value_cell (v);
+  if (t == 0 || *t == 0)
+    xtrace_reset ();
+  else
+    {
+      fd = (int)strtol (t, &e, 10);
+      if (e != t && *e == '\0' && sh_validfd (fd))
+	{
+	  fp = fdopen (fd, "w");
+	  if (fp == 0)
+	    internal_error (_("%s: %s: cannot open as FILE"), name, value_cell (v));
+	  else
+	    xtrace_set (fd, fp);
+	}
+      else
+	internal_error (_("%s: %s: invalid value for trace file descriptor"), name, value_cell (v));
+    }
+}
+
+#define MIN_COMPAT_LEVEL 31
+
+void
+sv_shcompat (name)
+     char *name;
+{
+  SHELL_VAR *v;
+  char *val;
+  int tens, ones, compatval;
+
+  v = find_variable (name);
+  if (v == 0)
+    {
+      shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
+      set_compatibility_opts ();
+      return;
+    }
+  val = value_cell (v);
+  if (val == 0 || *val == '\0')
+    {
+      shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
+      set_compatibility_opts ();
+      return;
+    }
+  /* Handle decimal-like compatibility version specifications: 4.2 */
+  if (isdigit (val[0]) && val[1] == '.' && isdigit (val[2]) && val[3] == 0)
+    {
+      tens = val[0] - '0';
+      ones = val[2] - '0';
+      compatval = tens*10 + ones;
+    }
+  /* Handle integer-like compatibility version specifications: 42 */
+  else if (isdigit (val[0]) && isdigit (val[1]) && val[2] == 0)
+    {
+      tens = val[0] - '0';
+      ones = val[1] - '0';
+      compatval = tens*10 + ones;
+    }
+  else
+    {
+compat_error:
+      internal_error (_("%s: %s: compatibility value out of range"), name, val);
+      shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
+      set_compatibility_opts ();
+      return;
+    }
+
+  if (compatval < MIN_COMPAT_LEVEL || compatval > DEFAULT_COMPAT_LEVEL)
+    goto compat_error;
+
+  shell_compatibility_level = compatval;
+  set_compatibility_opts ();
+}
+
+#if defined (JOB_CONTROL)
+void
+sv_childmax (name)
+     char *name;
+{
+  char *tt;
+  int s;
+
+  tt = get_string_value (name);
+  s = (tt && *tt) ? atoi (tt) : 0;
+  set_maxchild (s);
+}
+#endif
diff -Naur bash-4.3.orig/y.tab.c bash-4.3/y.tab.c
--- bash-4.3.orig/y.tab.c	2014-02-11 15:57:47.000000000 +0000
+++ bash-4.3/y.tab.c	2015-08-16 01:14:31.602941283 +0000
@@ -168,7 +168,7 @@
 
 
 /* Copy the first part of user declarations.  */
-#line 21 "/usr/homes/chet/src/bash/src/parse.y"
+#line 21 "/usr/src/local/bash/bash-4.3-patched/parse.y"
 
 #include "config.h"
 
@@ -319,6 +319,9 @@
 
 static int reserved_word_acceptable __P((int));
 static int yylex __P((void));
+
+static void push_heredoc __P((REDIRECT *));
+static char *mk_alexpansion __P((char *));
 static int alias_expand_token __P((char *));
 static int time_command_acceptable __P((void));
 static int special_case_tokens __P((char *));
@@ -416,7 +419,9 @@
 
 /* Variables to manage the task of reading here documents, because we need to
    defer the reading until after a complete command has been collected. */
-static REDIRECT *redir_stack[10];
+#define HEREDOC_MAX 16
+
+static REDIRECT *redir_stack[HEREDOC_MAX];
 int need_here_doc;
 
 /* Where shell input comes from.  History expansion is performed on each
@@ -458,7 +463,7 @@
    or `for WORD' begins.  This is a nested command maximum, since the array
    index is decremented after a case, select, or for command is parsed. */
 #define MAX_CASE_NEST	128
-static int word_lineno[MAX_CASE_NEST];
+static int word_lineno[MAX_CASE_NEST+1];
 static int word_top = -1;
 
 /* If non-zero, it is the token that we want read_token to return
@@ -492,7 +497,7 @@
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 324 "/usr/homes/chet/src/bash/src/parse.y"
+#line 329 "/usr/src/local/bash/bash-4.3-patched/parse.y"
 {
   WORD_DESC *word;		/* the word that we read. */
   int number;			/* the number that we read. */
@@ -503,7 +508,7 @@
   PATTERN_LIST *pattern;
 }
 /* Line 193 of yacc.c.  */
-#line 507 "y.tab.c"
+#line 512 "y.tab.c"
 	YYSTYPE;
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
@@ -516,7 +521,7 @@
 
 
 /* Line 216 of yacc.c.  */
-#line 520 "y.tab.c"
+#line 525 "y.tab.c"
 
 #ifdef short
 # undef short
@@ -886,23 +891,23 @@
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   377,   377,   388,   397,   412,   422,   424,   428,   434,
-     440,   446,   452,   458,   464,   470,   476,   482,   488,   494,
-     500,   506,   512,   518,   525,   532,   539,   546,   553,   560,
-     566,   572,   578,   584,   590,   596,   602,   608,   614,   620,
-     626,   632,   638,   644,   650,   656,   662,   668,   674,   680,
-     686,   692,   700,   702,   704,   708,   712,   723,   725,   729,
-     731,   733,   749,   751,   755,   757,   759,   761,   763,   765,
-     767,   769,   771,   773,   775,   779,   784,   789,   794,   799,
-     804,   809,   814,   821,   826,   831,   836,   843,   848,   853,
-     858,   863,   868,   875,   880,   885,   892,   895,   898,   902,
-     904,   935,   942,   947,   964,   969,   986,   993,   995,   997,
-    1002,  1006,  1010,  1014,  1016,  1018,  1022,  1023,  1027,  1029,
-    1031,  1033,  1037,  1039,  1041,  1043,  1045,  1047,  1051,  1053,
-    1062,  1070,  1071,  1077,  1078,  1085,  1089,  1091,  1093,  1100,
-    1102,  1104,  1108,  1109,  1112,  1114,  1116,  1120,  1121,  1130,
-    1143,  1159,  1174,  1176,  1178,  1185,  1188,  1192,  1194,  1200,
-    1206,  1223,  1243,  1245,  1268,  1272,  1274,  1276
+       0,   382,   382,   393,   402,   417,   427,   429,   433,   439,
+     445,   451,   457,   463,   469,   475,   481,   487,   493,   499,
+     505,   511,   517,   523,   530,   537,   544,   551,   558,   565,
+     571,   577,   583,   589,   595,   601,   607,   613,   619,   625,
+     631,   637,   643,   649,   655,   661,   667,   673,   679,   685,
+     691,   697,   705,   707,   709,   713,   717,   728,   730,   734,
+     736,   738,   754,   756,   760,   762,   764,   766,   768,   770,
+     772,   774,   776,   778,   780,   784,   789,   794,   799,   804,
+     809,   814,   819,   826,   831,   836,   841,   848,   853,   858,
+     863,   868,   873,   880,   885,   890,   897,   900,   903,   907,
+     909,   940,   947,   952,   969,   974,   991,   998,  1000,  1002,
+    1007,  1011,  1015,  1019,  1021,  1023,  1027,  1028,  1032,  1034,
+    1036,  1038,  1042,  1044,  1046,  1048,  1050,  1052,  1056,  1058,
+    1067,  1075,  1076,  1082,  1083,  1090,  1094,  1096,  1098,  1105,
+    1107,  1109,  1113,  1114,  1117,  1119,  1121,  1125,  1126,  1135,
+    1148,  1164,  1179,  1181,  1183,  1190,  1193,  1197,  1199,  1205,
+    1211,  1228,  1248,  1250,  1273,  1277,  1279,  1281
 };
 #endif
 
@@ -2093,7 +2098,7 @@
   switch (yyn)
     {
         case 2:
-#line 378 "/usr/homes/chet/src/bash/src/parse.y"
+#line 383 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  /* Case of regular command.  Discard the error
 			     safety net,and return the command just parsed. */
@@ -2107,7 +2112,7 @@
     break;
 
   case 3:
-#line 389 "/usr/homes/chet/src/bash/src/parse.y"
+#line 394 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  /* Case of regular command, but not a very
 			     interesting one.  Return a NULL command. */
@@ -2119,7 +2124,7 @@
     break;
 
   case 4:
-#line 398 "/usr/homes/chet/src/bash/src/parse.y"
+#line 403 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  /* Error during parsing.  Return NULL command. */
 			  global_command = (COMMAND *)NULL;
@@ -2137,7 +2142,7 @@
     break;
 
   case 5:
-#line 413 "/usr/homes/chet/src/bash/src/parse.y"
+#line 418 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  /* Case of EOF seen by itself.  Do ignoreeof or
 			     not. */
@@ -2148,17 +2153,17 @@
     break;
 
   case 6:
-#line 423 "/usr/homes/chet/src/bash/src/parse.y"
+#line 428 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.word_list) = make_word_list ((yyvsp[(1) - (1)].word), (WORD_LIST *)NULL); }
     break;
 
   case 7:
-#line 425 "/usr/homes/chet/src/bash/src/parse.y"
+#line 430 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.word_list) = make_word_list ((yyvsp[(2) - (2)].word), (yyvsp[(1) - (2)].word_list)); }
     break;
 
   case 8:
-#line 429 "/usr/homes/chet/src/bash/src/parse.y"
+#line 434 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = 1;
 			  redir.filename = (yyvsp[(2) - (2)].word);
@@ -2167,7 +2172,7 @@
     break;
 
   case 9:
-#line 435 "/usr/homes/chet/src/bash/src/parse.y"
+#line 440 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = 0;
 			  redir.filename = (yyvsp[(2) - (2)].word);
@@ -2176,7 +2181,7 @@
     break;
 
   case 10:
-#line 441 "/usr/homes/chet/src/bash/src/parse.y"
+#line 446 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = (yyvsp[(1) - (3)].number);
 			  redir.filename = (yyvsp[(3) - (3)].word);
@@ -2185,7 +2190,7 @@
     break;
 
   case 11:
-#line 447 "/usr/homes/chet/src/bash/src/parse.y"
+#line 452 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = (yyvsp[(1) - (3)].number);
 			  redir.filename = (yyvsp[(3) - (3)].word);
@@ -2194,7 +2199,7 @@
     break;
 
   case 12:
-#line 453 "/usr/homes/chet/src/bash/src/parse.y"
+#line 458 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.filename = (yyvsp[(1) - (3)].word);
 			  redir.filename = (yyvsp[(3) - (3)].word);
@@ -2203,7 +2208,7 @@
     break;
 
   case 13:
-#line 459 "/usr/homes/chet/src/bash/src/parse.y"
+#line 464 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.filename = (yyvsp[(1) - (3)].word);
 			  redir.filename = (yyvsp[(3) - (3)].word);
@@ -2212,7 +2217,7 @@
     break;
 
   case 14:
-#line 465 "/usr/homes/chet/src/bash/src/parse.y"
+#line 470 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = 1;
 			  redir.filename = (yyvsp[(2) - (2)].word);
@@ -2221,7 +2226,7 @@
     break;
 
   case 15:
-#line 471 "/usr/homes/chet/src/bash/src/parse.y"
+#line 476 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = (yyvsp[(1) - (3)].number);
 			  redir.filename = (yyvsp[(3) - (3)].word);
@@ -2230,7 +2235,7 @@
     break;
 
   case 16:
-#line 477 "/usr/homes/chet/src/bash/src/parse.y"
+#line 482 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.filename = (yyvsp[(1) - (3)].word);
 			  redir.filename = (yyvsp[(3) - (3)].word);
@@ -2239,7 +2244,7 @@
     break;
 
   case 17:
-#line 483 "/usr/homes/chet/src/bash/src/parse.y"
+#line 488 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = 1;
 			  redir.filename = (yyvsp[(2) - (2)].word);
@@ -2248,7 +2253,7 @@
     break;
 
   case 18:
-#line 489 "/usr/homes/chet/src/bash/src/parse.y"
+#line 494 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = (yyvsp[(1) - (3)].number);
 			  redir.filename = (yyvsp[(3) - (3)].word);
@@ -2257,7 +2262,7 @@
     break;
 
   case 19:
-#line 495 "/usr/homes/chet/src/bash/src/parse.y"
+#line 500 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.filename = (yyvsp[(1) - (3)].word);
 			  redir.filename = (yyvsp[(3) - (3)].word);
@@ -2266,7 +2271,7 @@
     break;
 
   case 20:
-#line 501 "/usr/homes/chet/src/bash/src/parse.y"
+#line 506 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = 0;
 			  redir.filename = (yyvsp[(2) - (2)].word);
@@ -2275,7 +2280,7 @@
     break;
 
   case 21:
-#line 507 "/usr/homes/chet/src/bash/src/parse.y"
+#line 512 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = (yyvsp[(1) - (3)].number);
 			  redir.filename = (yyvsp[(3) - (3)].word);
@@ -2284,7 +2289,7 @@
     break;
 
   case 22:
-#line 513 "/usr/homes/chet/src/bash/src/parse.y"
+#line 518 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.filename = (yyvsp[(1) - (3)].word);
 			  redir.filename = (yyvsp[(3) - (3)].word);
@@ -2293,67 +2298,67 @@
     break;
 
   case 23:
-#line 519 "/usr/homes/chet/src/bash/src/parse.y"
+#line 524 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = 0;
 			  redir.filename = (yyvsp[(2) - (2)].word);
 			  (yyval.redirect) = make_redirection (source, r_reading_until, redir, 0);
-			  redir_stack[need_here_doc++] = (yyval.redirect);
+			  push_heredoc ((yyval.redirect));
 			}
     break;
 
   case 24:
-#line 526 "/usr/homes/chet/src/bash/src/parse.y"
+#line 531 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = (yyvsp[(1) - (3)].number);
 			  redir.filename = (yyvsp[(3) - (3)].word);
 			  (yyval.redirect) = make_redirection (source, r_reading_until, redir, 0);
-			  redir_stack[need_here_doc++] = (yyval.redirect);
+			  push_heredoc ((yyval.redirect));
 			}
     break;
 
   case 25:
-#line 533 "/usr/homes/chet/src/bash/src/parse.y"
+#line 538 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.filename = (yyvsp[(1) - (3)].word);
 			  redir.filename = (yyvsp[(3) - (3)].word);
 			  (yyval.redirect) = make_redirection (source, r_reading_until, redir, REDIR_VARASSIGN);
-			  redir_stack[need_here_doc++] = (yyval.redirect);
+			  push_heredoc ((yyval.redirect));
 			}
     break;
 
   case 26:
-#line 540 "/usr/homes/chet/src/bash/src/parse.y"
+#line 545 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = 0;
 			  redir.filename = (yyvsp[(2) - (2)].word);
 			  (yyval.redirect) = make_redirection (source, r_deblank_reading_until, redir, 0);
-			  redir_stack[need_here_doc++] = (yyval.redirect);
+			  push_heredoc ((yyval.redirect));
 			}
     break;
 
   case 27:
-#line 547 "/usr/homes/chet/src/bash/src/parse.y"
+#line 552 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = (yyvsp[(1) - (3)].number);
 			  redir.filename = (yyvsp[(3) - (3)].word);
 			  (yyval.redirect) = make_redirection (source, r_deblank_reading_until, redir, 0);
-			  redir_stack[need_here_doc++] = (yyval.redirect);
+			  push_heredoc ((yyval.redirect));
 			}
     break;
 
   case 28:
-#line 554 "/usr/homes/chet/src/bash/src/parse.y"
+#line 559 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.filename = (yyvsp[(1) - (3)].word);
 			  redir.filename = (yyvsp[(3) - (3)].word);
 			  (yyval.redirect) = make_redirection (source, r_deblank_reading_until, redir, REDIR_VARASSIGN);
-			  redir_stack[need_here_doc++] = (yyval.redirect);
+			  push_heredoc ((yyval.redirect));
 			}
     break;
 
   case 29:
-#line 561 "/usr/homes/chet/src/bash/src/parse.y"
+#line 566 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = 0;
 			  redir.filename = (yyvsp[(2) - (2)].word);
@@ -2362,7 +2367,7 @@
     break;
 
   case 30:
-#line 567 "/usr/homes/chet/src/bash/src/parse.y"
+#line 572 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = (yyvsp[(1) - (3)].number);
 			  redir.filename = (yyvsp[(3) - (3)].word);
@@ -2371,7 +2376,7 @@
     break;
 
   case 31:
-#line 573 "/usr/homes/chet/src/bash/src/parse.y"
+#line 578 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.filename = (yyvsp[(1) - (3)].word);
 			  redir.filename = (yyvsp[(3) - (3)].word);
@@ -2380,7 +2385,7 @@
     break;
 
   case 32:
-#line 579 "/usr/homes/chet/src/bash/src/parse.y"
+#line 584 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = 0;
 			  redir.dest = (yyvsp[(2) - (2)].number);
@@ -2389,7 +2394,7 @@
     break;
 
   case 33:
-#line 585 "/usr/homes/chet/src/bash/src/parse.y"
+#line 590 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = (yyvsp[(1) - (3)].number);
 			  redir.dest = (yyvsp[(3) - (3)].number);
@@ -2398,7 +2403,7 @@
     break;
 
   case 34:
-#line 591 "/usr/homes/chet/src/bash/src/parse.y"
+#line 596 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.filename = (yyvsp[(1) - (3)].word);
 			  redir.dest = (yyvsp[(3) - (3)].number);
@@ -2407,7 +2412,7 @@
     break;
 
   case 35:
-#line 597 "/usr/homes/chet/src/bash/src/parse.y"
+#line 602 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = 1;
 			  redir.dest = (yyvsp[(2) - (2)].number);
@@ -2416,7 +2421,7 @@
     break;
 
   case 36:
-#line 603 "/usr/homes/chet/src/bash/src/parse.y"
+#line 608 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = (yyvsp[(1) - (3)].number);
 			  redir.dest = (yyvsp[(3) - (3)].number);
@@ -2425,7 +2430,7 @@
     break;
 
   case 37:
-#line 609 "/usr/homes/chet/src/bash/src/parse.y"
+#line 614 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.filename = (yyvsp[(1) - (3)].word);
 			  redir.dest = (yyvsp[(3) - (3)].number);
@@ -2434,7 +2439,7 @@
     break;
 
   case 38:
-#line 615 "/usr/homes/chet/src/bash/src/parse.y"
+#line 620 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = 0;
 			  redir.filename = (yyvsp[(2) - (2)].word);
@@ -2443,7 +2448,7 @@
     break;
 
   case 39:
-#line 621 "/usr/homes/chet/src/bash/src/parse.y"
+#line 626 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = (yyvsp[(1) - (3)].number);
 			  redir.filename = (yyvsp[(3) - (3)].word);
@@ -2452,7 +2457,7 @@
     break;
 
   case 40:
-#line 627 "/usr/homes/chet/src/bash/src/parse.y"
+#line 632 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.filename = (yyvsp[(1) - (3)].word);
 			  redir.filename = (yyvsp[(3) - (3)].word);
@@ -2461,7 +2466,7 @@
     break;
 
   case 41:
-#line 633 "/usr/homes/chet/src/bash/src/parse.y"
+#line 638 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = 1;
 			  redir.filename = (yyvsp[(2) - (2)].word);
@@ -2470,7 +2475,7 @@
     break;
 
   case 42:
-#line 639 "/usr/homes/chet/src/bash/src/parse.y"
+#line 644 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = (yyvsp[(1) - (3)].number);
 			  redir.filename = (yyvsp[(3) - (3)].word);
@@ -2479,7 +2484,7 @@
     break;
 
   case 43:
-#line 645 "/usr/homes/chet/src/bash/src/parse.y"
+#line 650 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.filename = (yyvsp[(1) - (3)].word);
 			  redir.filename = (yyvsp[(3) - (3)].word);
@@ -2488,7 +2493,7 @@
     break;
 
   case 44:
-#line 651 "/usr/homes/chet/src/bash/src/parse.y"
+#line 656 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = 1;
 			  redir.dest = 0;
@@ -2497,7 +2502,7 @@
     break;
 
   case 45:
-#line 657 "/usr/homes/chet/src/bash/src/parse.y"
+#line 662 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = (yyvsp[(1) - (3)].number);
 			  redir.dest = 0;
@@ -2506,7 +2511,7 @@
     break;
 
   case 46:
-#line 663 "/usr/homes/chet/src/bash/src/parse.y"
+#line 668 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.filename = (yyvsp[(1) - (3)].word);
 			  redir.dest = 0;
@@ -2515,7 +2520,7 @@
     break;
 
   case 47:
-#line 669 "/usr/homes/chet/src/bash/src/parse.y"
+#line 674 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = 0;
 			  redir.dest = 0;
@@ -2524,7 +2529,7 @@
     break;
 
   case 48:
-#line 675 "/usr/homes/chet/src/bash/src/parse.y"
+#line 680 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = (yyvsp[(1) - (3)].number);
 			  redir.dest = 0;
@@ -2533,7 +2538,7 @@
     break;
 
   case 49:
-#line 681 "/usr/homes/chet/src/bash/src/parse.y"
+#line 686 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.filename = (yyvsp[(1) - (3)].word);
 			  redir.dest = 0;
@@ -2542,7 +2547,7 @@
     break;
 
   case 50:
-#line 687 "/usr/homes/chet/src/bash/src/parse.y"
+#line 692 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = 1;
 			  redir.filename = (yyvsp[(2) - (2)].word);
@@ -2551,7 +2556,7 @@
     break;
 
   case 51:
-#line 693 "/usr/homes/chet/src/bash/src/parse.y"
+#line 698 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  source.dest = 1;
 			  redir.filename = (yyvsp[(2) - (2)].word);
@@ -2560,29 +2565,29 @@
     break;
 
   case 52:
-#line 701 "/usr/homes/chet/src/bash/src/parse.y"
+#line 706 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.element).word = (yyvsp[(1) - (1)].word); (yyval.element).redirect = 0; }
     break;
 
   case 53:
-#line 703 "/usr/homes/chet/src/bash/src/parse.y"
+#line 708 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.element).word = (yyvsp[(1) - (1)].word); (yyval.element).redirect = 0; }
     break;
 
   case 54:
-#line 705 "/usr/homes/chet/src/bash/src/parse.y"
+#line 710 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.element).redirect = (yyvsp[(1) - (1)].redirect); (yyval.element).word = 0; }
     break;
 
   case 55:
-#line 709 "/usr/homes/chet/src/bash/src/parse.y"
+#line 714 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.redirect) = (yyvsp[(1) - (1)].redirect);
 			}
     break;
 
   case 56:
-#line 713 "/usr/homes/chet/src/bash/src/parse.y"
+#line 718 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  register REDIRECT *t;
 
@@ -2594,27 +2599,27 @@
     break;
 
   case 57:
-#line 724 "/usr/homes/chet/src/bash/src/parse.y"
+#line 729 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = make_simple_command ((yyvsp[(1) - (1)].element), (COMMAND *)NULL); }
     break;
 
   case 58:
-#line 726 "/usr/homes/chet/src/bash/src/parse.y"
+#line 731 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = make_simple_command ((yyvsp[(2) - (2)].element), (yyvsp[(1) - (2)].command)); }
     break;
 
   case 59:
-#line 730 "/usr/homes/chet/src/bash/src/parse.y"
+#line 735 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = clean_simple_command ((yyvsp[(1) - (1)].command)); }
     break;
 
   case 60:
-#line 732 "/usr/homes/chet/src/bash/src/parse.y"
+#line 737 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = (yyvsp[(1) - (1)].command); }
     break;
 
   case 61:
-#line 734 "/usr/homes/chet/src/bash/src/parse.y"
+#line 739 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  COMMAND *tc;
 
@@ -2633,72 +2638,72 @@
     break;
 
   case 62:
-#line 750 "/usr/homes/chet/src/bash/src/parse.y"
+#line 755 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = (yyvsp[(1) - (1)].command); }
     break;
 
   case 63:
-#line 752 "/usr/homes/chet/src/bash/src/parse.y"
+#line 757 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = (yyvsp[(1) - (1)].command); }
     break;
 
   case 64:
-#line 756 "/usr/homes/chet/src/bash/src/parse.y"
+#line 761 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = (yyvsp[(1) - (1)].command); }
     break;
 
   case 65:
-#line 758 "/usr/homes/chet/src/bash/src/parse.y"
+#line 763 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = (yyvsp[(1) - (1)].command); }
     break;
 
   case 66:
-#line 760 "/usr/homes/chet/src/bash/src/parse.y"
+#line 765 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = make_while_command ((yyvsp[(2) - (5)].command), (yyvsp[(4) - (5)].command)); }
     break;
 
   case 67:
-#line 762 "/usr/homes/chet/src/bash/src/parse.y"
+#line 767 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = make_until_command ((yyvsp[(2) - (5)].command), (yyvsp[(4) - (5)].command)); }
     break;
 
   case 68:
-#line 764 "/usr/homes/chet/src/bash/src/parse.y"
+#line 769 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = (yyvsp[(1) - (1)].command); }
     break;
 
   case 69:
-#line 766 "/usr/homes/chet/src/bash/src/parse.y"
+#line 771 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = (yyvsp[(1) - (1)].command); }
     break;
 
   case 70:
-#line 768 "/usr/homes/chet/src/bash/src/parse.y"
+#line 773 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = (yyvsp[(1) - (1)].command); }
     break;
 
   case 71:
-#line 770 "/usr/homes/chet/src/bash/src/parse.y"
+#line 775 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = (yyvsp[(1) - (1)].command); }
     break;
 
   case 72:
-#line 772 "/usr/homes/chet/src/bash/src/parse.y"
+#line 777 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = (yyvsp[(1) - (1)].command); }
     break;
 
   case 73:
-#line 774 "/usr/homes/chet/src/bash/src/parse.y"
+#line 779 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = (yyvsp[(1) - (1)].command); }
     break;
 
   case 74:
-#line 776 "/usr/homes/chet/src/bash/src/parse.y"
+#line 781 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = (yyvsp[(1) - (1)].command); }
     break;
 
   case 75:
-#line 780 "/usr/homes/chet/src/bash/src/parse.y"
+#line 785 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = make_for_command ((yyvsp[(2) - (6)].word), add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), (yyvsp[(5) - (6)].command), word_lineno[word_top]);
 			  if (word_top > 0) word_top--;
@@ -2706,7 +2711,7 @@
     break;
 
   case 76:
-#line 785 "/usr/homes/chet/src/bash/src/parse.y"
+#line 790 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = make_for_command ((yyvsp[(2) - (6)].word), add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), (yyvsp[(5) - (6)].command), word_lineno[word_top]);
 			  if (word_top > 0) word_top--;
@@ -2714,7 +2719,7 @@
     break;
 
   case 77:
-#line 790 "/usr/homes/chet/src/bash/src/parse.y"
+#line 795 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = make_for_command ((yyvsp[(2) - (7)].word), add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), (yyvsp[(6) - (7)].command), word_lineno[word_top]);
 			  if (word_top > 0) word_top--;
@@ -2722,7 +2727,7 @@
     break;
 
   case 78:
-#line 795 "/usr/homes/chet/src/bash/src/parse.y"
+#line 800 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = make_for_command ((yyvsp[(2) - (7)].word), add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), (yyvsp[(6) - (7)].command), word_lineno[word_top]);
 			  if (word_top > 0) word_top--;
@@ -2730,7 +2735,7 @@
     break;
 
   case 79:
-#line 800 "/usr/homes/chet/src/bash/src/parse.y"
+#line 805 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = make_for_command ((yyvsp[(2) - (10)].word), REVERSE_LIST ((yyvsp[(5) - (10)].word_list), WORD_LIST *), (yyvsp[(9) - (10)].command), word_lineno[word_top]);
 			  if (word_top > 0) word_top--;
@@ -2738,7 +2743,7 @@
     break;
 
   case 80:
-#line 805 "/usr/homes/chet/src/bash/src/parse.y"
+#line 810 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = make_for_command ((yyvsp[(2) - (10)].word), REVERSE_LIST ((yyvsp[(5) - (10)].word_list), WORD_LIST *), (yyvsp[(9) - (10)].command), word_lineno[word_top]);
 			  if (word_top > 0) word_top--;
@@ -2746,7 +2751,7 @@
     break;
 
   case 81:
-#line 810 "/usr/homes/chet/src/bash/src/parse.y"
+#line 815 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = make_for_command ((yyvsp[(2) - (9)].word), (WORD_LIST *)NULL, (yyvsp[(8) - (9)].command), word_lineno[word_top]);
 			  if (word_top > 0) word_top--;
@@ -2754,7 +2759,7 @@
     break;
 
   case 82:
-#line 815 "/usr/homes/chet/src/bash/src/parse.y"
+#line 820 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = make_for_command ((yyvsp[(2) - (9)].word), (WORD_LIST *)NULL, (yyvsp[(8) - (9)].command), word_lineno[word_top]);
 			  if (word_top > 0) word_top--;
@@ -2762,7 +2767,7 @@
     break;
 
   case 83:
-#line 822 "/usr/homes/chet/src/bash/src/parse.y"
+#line 827 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 				  (yyval.command) = make_arith_for_command ((yyvsp[(2) - (7)].word_list), (yyvsp[(6) - (7)].command), arith_for_lineno);
 				  if (word_top > 0) word_top--;
@@ -2770,7 +2775,7 @@
     break;
 
   case 84:
-#line 827 "/usr/homes/chet/src/bash/src/parse.y"
+#line 832 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 				  (yyval.command) = make_arith_for_command ((yyvsp[(2) - (7)].word_list), (yyvsp[(6) - (7)].command), arith_for_lineno);
 				  if (word_top > 0) word_top--;
@@ -2778,7 +2783,7 @@
     break;
 
   case 85:
-#line 832 "/usr/homes/chet/src/bash/src/parse.y"
+#line 837 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 				  (yyval.command) = make_arith_for_command ((yyvsp[(2) - (5)].word_list), (yyvsp[(4) - (5)].command), arith_for_lineno);
 				  if (word_top > 0) word_top--;
@@ -2786,7 +2791,7 @@
     break;
 
   case 86:
-#line 837 "/usr/homes/chet/src/bash/src/parse.y"
+#line 842 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 				  (yyval.command) = make_arith_for_command ((yyvsp[(2) - (5)].word_list), (yyvsp[(4) - (5)].command), arith_for_lineno);
 				  if (word_top > 0) word_top--;
@@ -2794,7 +2799,7 @@
     break;
 
   case 87:
-#line 844 "/usr/homes/chet/src/bash/src/parse.y"
+#line 849 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = make_select_command ((yyvsp[(2) - (6)].word), add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), (yyvsp[(5) - (6)].command), word_lineno[word_top]);
 			  if (word_top > 0) word_top--;
@@ -2802,7 +2807,7 @@
     break;
 
   case 88:
-#line 849 "/usr/homes/chet/src/bash/src/parse.y"
+#line 854 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = make_select_command ((yyvsp[(2) - (6)].word), add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), (yyvsp[(5) - (6)].command), word_lineno[word_top]);
 			  if (word_top > 0) word_top--;
@@ -2810,7 +2815,7 @@
     break;
 
   case 89:
-#line 854 "/usr/homes/chet/src/bash/src/parse.y"
+#line 859 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = make_select_command ((yyvsp[(2) - (7)].word), add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), (yyvsp[(6) - (7)].command), word_lineno[word_top]);
 			  if (word_top > 0) word_top--;
@@ -2818,7 +2823,7 @@
     break;
 
   case 90:
-#line 859 "/usr/homes/chet/src/bash/src/parse.y"
+#line 864 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = make_select_command ((yyvsp[(2) - (7)].word), add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), (yyvsp[(6) - (7)].command), word_lineno[word_top]);
 			  if (word_top > 0) word_top--;
@@ -2826,7 +2831,7 @@
     break;
 
   case 91:
-#line 864 "/usr/homes/chet/src/bash/src/parse.y"
+#line 869 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = make_select_command ((yyvsp[(2) - (10)].word), REVERSE_LIST ((yyvsp[(5) - (10)].word_list), WORD_LIST *), (yyvsp[(9) - (10)].command), word_lineno[word_top]);
 			  if (word_top > 0) word_top--;
@@ -2834,7 +2839,7 @@
     break;
 
   case 92:
-#line 869 "/usr/homes/chet/src/bash/src/parse.y"
+#line 874 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = make_select_command ((yyvsp[(2) - (10)].word), REVERSE_LIST ((yyvsp[(5) - (10)].word_list), WORD_LIST *), (yyvsp[(9) - (10)].command), word_lineno[word_top]);
 			  if (word_top > 0) word_top--;
@@ -2842,7 +2847,7 @@
     break;
 
   case 93:
-#line 876 "/usr/homes/chet/src/bash/src/parse.y"
+#line 881 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = make_case_command ((yyvsp[(2) - (6)].word), (PATTERN_LIST *)NULL, word_lineno[word_top]);
 			  if (word_top > 0) word_top--;
@@ -2850,7 +2855,7 @@
     break;
 
   case 94:
-#line 881 "/usr/homes/chet/src/bash/src/parse.y"
+#line 886 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = make_case_command ((yyvsp[(2) - (7)].word), (yyvsp[(5) - (7)].pattern), word_lineno[word_top]);
 			  if (word_top > 0) word_top--;
@@ -2858,7 +2863,7 @@
     break;
 
   case 95:
-#line 886 "/usr/homes/chet/src/bash/src/parse.y"
+#line 891 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = make_case_command ((yyvsp[(2) - (6)].word), (yyvsp[(5) - (6)].pattern), word_lineno[word_top]);
 			  if (word_top > 0) word_top--;
@@ -2866,27 +2871,27 @@
     break;
 
   case 96:
-#line 893 "/usr/homes/chet/src/bash/src/parse.y"
+#line 898 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = make_function_def ((yyvsp[(1) - (5)].word), (yyvsp[(5) - (5)].command), function_dstart, function_bstart); }
     break;
 
   case 97:
-#line 896 "/usr/homes/chet/src/bash/src/parse.y"
+#line 901 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = make_function_def ((yyvsp[(2) - (6)].word), (yyvsp[(6) - (6)].command), function_dstart, function_bstart); }
     break;
 
   case 98:
-#line 899 "/usr/homes/chet/src/bash/src/parse.y"
+#line 904 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = make_function_def ((yyvsp[(2) - (4)].word), (yyvsp[(4) - (4)].command), function_dstart, function_bstart); }
     break;
 
   case 99:
-#line 903 "/usr/homes/chet/src/bash/src/parse.y"
+#line 908 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = (yyvsp[(1) - (1)].command); }
     break;
 
   case 100:
-#line 905 "/usr/homes/chet/src/bash/src/parse.y"
+#line 910 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  COMMAND *tc;
 
@@ -2918,7 +2923,7 @@
     break;
 
   case 101:
-#line 936 "/usr/homes/chet/src/bash/src/parse.y"
+#line 941 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = make_subshell_command ((yyvsp[(2) - (3)].command));
 			  (yyval.command)->flags |= CMD_WANT_SUBSHELL;
@@ -2926,7 +2931,7 @@
     break;
 
   case 102:
-#line 943 "/usr/homes/chet/src/bash/src/parse.y"
+#line 948 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = make_coproc_command ("COPROC", (yyvsp[(2) - (2)].command));
 			  (yyval.command)->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL;
@@ -2934,7 +2939,7 @@
     break;
 
   case 103:
-#line 948 "/usr/homes/chet/src/bash/src/parse.y"
+#line 953 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  COMMAND *tc;
 
@@ -2954,7 +2959,7 @@
     break;
 
   case 104:
-#line 965 "/usr/homes/chet/src/bash/src/parse.y"
+#line 970 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = make_coproc_command ((yyvsp[(2) - (3)].word)->word, (yyvsp[(3) - (3)].command));
 			  (yyval.command)->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL;
@@ -2962,7 +2967,7 @@
     break;
 
   case 105:
-#line 970 "/usr/homes/chet/src/bash/src/parse.y"
+#line 975 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  COMMAND *tc;
 
@@ -2982,7 +2987,7 @@
     break;
 
   case 106:
-#line 987 "/usr/homes/chet/src/bash/src/parse.y"
+#line 992 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = make_coproc_command ("COPROC", clean_simple_command ((yyvsp[(2) - (2)].command)));
 			  (yyval.command)->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL;
@@ -2990,117 +2995,117 @@
     break;
 
   case 107:
-#line 994 "/usr/homes/chet/src/bash/src/parse.y"
+#line 999 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = make_if_command ((yyvsp[(2) - (5)].command), (yyvsp[(4) - (5)].command), (COMMAND *)NULL); }
     break;
 
   case 108:
-#line 996 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1001 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = make_if_command ((yyvsp[(2) - (7)].command), (yyvsp[(4) - (7)].command), (yyvsp[(6) - (7)].command)); }
     break;
 
   case 109:
-#line 998 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1003 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = make_if_command ((yyvsp[(2) - (6)].command), (yyvsp[(4) - (6)].command), (yyvsp[(5) - (6)].command)); }
     break;
 
   case 110:
-#line 1003 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1008 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = make_group_command ((yyvsp[(2) - (3)].command)); }
     break;
 
   case 111:
-#line 1007 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1012 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = make_arith_command ((yyvsp[(1) - (1)].word_list)); }
     break;
 
   case 112:
-#line 1011 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1016 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = (yyvsp[(2) - (3)].command); }
     break;
 
   case 113:
-#line 1015 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1020 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = make_if_command ((yyvsp[(2) - (4)].command), (yyvsp[(4) - (4)].command), (COMMAND *)NULL); }
     break;
 
   case 114:
-#line 1017 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1022 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = make_if_command ((yyvsp[(2) - (6)].command), (yyvsp[(4) - (6)].command), (yyvsp[(6) - (6)].command)); }
     break;
 
   case 115:
-#line 1019 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1024 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = make_if_command ((yyvsp[(2) - (5)].command), (yyvsp[(4) - (5)].command), (yyvsp[(5) - (5)].command)); }
     break;
 
   case 117:
-#line 1024 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1029 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyvsp[(2) - (2)].pattern)->next = (yyvsp[(1) - (2)].pattern); (yyval.pattern) = (yyvsp[(2) - (2)].pattern); }
     break;
 
   case 118:
-#line 1028 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1033 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.pattern) = make_pattern_list ((yyvsp[(2) - (4)].word_list), (yyvsp[(4) - (4)].command)); }
     break;
 
   case 119:
-#line 1030 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1035 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.pattern) = make_pattern_list ((yyvsp[(2) - (4)].word_list), (COMMAND *)NULL); }
     break;
 
   case 120:
-#line 1032 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1037 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.pattern) = make_pattern_list ((yyvsp[(3) - (5)].word_list), (yyvsp[(5) - (5)].command)); }
     break;
 
   case 121:
-#line 1034 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1039 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.pattern) = make_pattern_list ((yyvsp[(3) - (5)].word_list), (COMMAND *)NULL); }
     break;
 
   case 122:
-#line 1038 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1043 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.pattern) = (yyvsp[(1) - (2)].pattern); }
     break;
 
   case 123:
-#line 1040 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1045 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyvsp[(2) - (3)].pattern)->next = (yyvsp[(1) - (3)].pattern); (yyval.pattern) = (yyvsp[(2) - (3)].pattern); }
     break;
 
   case 124:
-#line 1042 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1047 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyvsp[(1) - (2)].pattern)->flags |= CASEPAT_FALLTHROUGH; (yyval.pattern) = (yyvsp[(1) - (2)].pattern); }
     break;
 
   case 125:
-#line 1044 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1049 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyvsp[(2) - (3)].pattern)->flags |= CASEPAT_FALLTHROUGH; (yyvsp[(2) - (3)].pattern)->next = (yyvsp[(1) - (3)].pattern); (yyval.pattern) = (yyvsp[(2) - (3)].pattern); }
     break;
 
   case 126:
-#line 1046 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1051 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyvsp[(1) - (2)].pattern)->flags |= CASEPAT_TESTNEXT; (yyval.pattern) = (yyvsp[(1) - (2)].pattern); }
     break;
 
   case 127:
-#line 1048 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1053 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyvsp[(2) - (3)].pattern)->flags |= CASEPAT_TESTNEXT; (yyvsp[(2) - (3)].pattern)->next = (yyvsp[(1) - (3)].pattern); (yyval.pattern) = (yyvsp[(2) - (3)].pattern); }
     break;
 
   case 128:
-#line 1052 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1057 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.word_list) = make_word_list ((yyvsp[(1) - (1)].word), (WORD_LIST *)NULL); }
     break;
 
   case 129:
-#line 1054 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1059 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.word_list) = make_word_list ((yyvsp[(3) - (3)].word), (yyvsp[(1) - (3)].word_list)); }
     break;
 
   case 130:
-#line 1063 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1068 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = (yyvsp[(2) - (2)].command);
 			  if (need_here_doc)
@@ -3109,14 +3114,14 @@
     break;
 
   case 132:
-#line 1072 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1077 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = (yyvsp[(2) - (2)].command);
 			}
     break;
 
   case 134:
-#line 1079 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1084 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  if ((yyvsp[(1) - (3)].command)->type == cm_connection)
 			    (yyval.command) = connect_async_list ((yyvsp[(1) - (3)].command), (COMMAND *)NULL, '&');
@@ -3126,17 +3131,17 @@
     break;
 
   case 136:
-#line 1090 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1095 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = command_connect ((yyvsp[(1) - (4)].command), (yyvsp[(4) - (4)].command), AND_AND); }
     break;
 
   case 137:
-#line 1092 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1097 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = command_connect ((yyvsp[(1) - (4)].command), (yyvsp[(4) - (4)].command), OR_OR); }
     break;
 
   case 138:
-#line 1094 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1099 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  if ((yyvsp[(1) - (4)].command)->type == cm_connection)
 			    (yyval.command) = connect_async_list ((yyvsp[(1) - (4)].command), (yyvsp[(4) - (4)].command), '&');
@@ -3146,37 +3151,37 @@
     break;
 
   case 139:
-#line 1101 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1106 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = command_connect ((yyvsp[(1) - (4)].command), (yyvsp[(4) - (4)].command), ';'); }
     break;
 
   case 140:
-#line 1103 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1108 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = command_connect ((yyvsp[(1) - (4)].command), (yyvsp[(4) - (4)].command), ';'); }
     break;
 
   case 141:
-#line 1105 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1110 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = (yyvsp[(1) - (1)].command); }
     break;
 
   case 144:
-#line 1113 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1118 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.number) = '\n'; }
     break;
 
   case 145:
-#line 1115 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1120 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.number) = ';'; }
     break;
 
   case 146:
-#line 1117 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1122 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.number) = yacc_EOF; }
     break;
 
   case 149:
-#line 1131 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1136 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = (yyvsp[(1) - (1)].command);
 			  if (need_here_doc)
@@ -3192,7 +3197,7 @@
     break;
 
   case 150:
-#line 1144 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1149 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  if ((yyvsp[(1) - (2)].command)->type == cm_connection)
 			    (yyval.command) = connect_async_list ((yyvsp[(1) - (2)].command), (COMMAND *)NULL, '&');
@@ -3211,7 +3216,7 @@
     break;
 
   case 151:
-#line 1160 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1165 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  (yyval.command) = (yyvsp[(1) - (2)].command);
 			  if (need_here_doc)
@@ -3227,17 +3232,17 @@
     break;
 
   case 152:
-#line 1175 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1180 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = command_connect ((yyvsp[(1) - (4)].command), (yyvsp[(4) - (4)].command), AND_AND); }
     break;
 
   case 153:
-#line 1177 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1182 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = command_connect ((yyvsp[(1) - (4)].command), (yyvsp[(4) - (4)].command), OR_OR); }
     break;
 
   case 154:
-#line 1179 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1184 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  if ((yyvsp[(1) - (3)].command)->type == cm_connection)
 			    (yyval.command) = connect_async_list ((yyvsp[(1) - (3)].command), (yyvsp[(3) - (3)].command), '&');
@@ -3247,22 +3252,22 @@
     break;
 
   case 155:
-#line 1186 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1191 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = command_connect ((yyvsp[(1) - (3)].command), (yyvsp[(3) - (3)].command), ';'); }
     break;
 
   case 156:
-#line 1189 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1194 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = (yyvsp[(1) - (1)].command); }
     break;
 
   case 157:
-#line 1193 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1198 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = (yyvsp[(1) - (1)].command); }
     break;
 
   case 158:
-#line 1195 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1200 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  if ((yyvsp[(2) - (2)].command))
 			    (yyvsp[(2) - (2)].command)->flags ^= CMD_INVERT_RETURN;	/* toggle */
@@ -3271,7 +3276,7 @@
     break;
 
   case 159:
-#line 1201 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1206 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  if ((yyvsp[(2) - (2)].command))
 			    (yyvsp[(2) - (2)].command)->flags |= (yyvsp[(1) - (2)].number);
@@ -3280,7 +3285,7 @@
     break;
 
   case 160:
-#line 1207 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1212 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  ELEMENT x;
 
@@ -3300,7 +3305,7 @@
     break;
 
   case 161:
-#line 1224 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1229 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  ELEMENT x;
 
@@ -3321,12 +3326,12 @@
     break;
 
   case 162:
-#line 1244 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1249 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = command_connect ((yyvsp[(1) - (4)].command), (yyvsp[(4) - (4)].command), '|'); }
     break;
 
   case 163:
-#line 1246 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1251 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     {
 			  /* Make cmd1 |& cmd2 equivalent to cmd1 2>&1 | cmd2 */
 			  COMMAND *tc;
@@ -3352,28 +3357,28 @@
     break;
 
   case 164:
-#line 1269 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1274 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.command) = (yyvsp[(1) - (1)].command); }
     break;
 
   case 165:
-#line 1273 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1278 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.number) = CMD_TIME_PIPELINE; }
     break;
 
   case 166:
-#line 1275 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1280 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.number) = CMD_TIME_PIPELINE|CMD_TIME_POSIX; }
     break;
 
   case 167:
-#line 1277 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1282 "/usr/src/local/bash/bash-4.3-patched/parse.y"
     { (yyval.number) = CMD_TIME_PIPELINE|CMD_TIME_POSIX; }
     break;
 
 
 /* Line 1267 of yacc.c.  */
-#line 3377 "y.tab.c"
+#line 3382 "y.tab.c"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -3587,7 +3592,7 @@
 }
 
 
-#line 1279 "/usr/homes/chet/src/bash/src/parse.y"
+#line 1284 "/usr/src/local/bash/bash-4.3-patched/parse.y"
 
 
 /* Initial size to allocate for tokens, and the
@@ -4736,7 +4741,7 @@
 	 not already end in an EOF character.  */
       if (shell_input_line_terminator != EOF)
 	{
-	  if (shell_input_line_size < SIZE_MAX && shell_input_line_len > shell_input_line_size - 3)
+	  if (shell_input_line_size < SIZE_MAX-3 && (shell_input_line_len+3 > shell_input_line_size))
 	    shell_input_line = (char *)xrealloc (shell_input_line,
 					1 + (shell_input_line_size += 2));
 
@@ -4845,6 +4850,16 @@
     eol_ungetc_lookahead = c;
 }
 
+char *
+parser_remaining_input ()
+{
+  if (shell_input_line == 0)
+    return 0;
+  if (shell_input_line_index < 0 || shell_input_line_index >= shell_input_line_len)
+    return '\0';	/* XXX */
+  return (shell_input_line + shell_input_line_index);
+}
+
 #ifdef INCLUDE_UNUSED
 /* Back the input pointer up by one, effectively `ungetting' a character. */
 static void
@@ -4948,13 +4963,28 @@
    which allow ESAC to be the next one read. */
 static int esacs_needed_count;
 
+static void
+push_heredoc (r)
+     REDIRECT *r;
+{
+  if (need_here_doc >= HEREDOC_MAX)
+    {
+      last_command_exit_value = EX_BADUSAGE;
+      need_here_doc = 0;
+      report_syntax_error (_("maximum here-document count exceeded"));
+      reset_parser ();
+      exit_shell (last_command_exit_value);
+    }
+  redir_stack[need_here_doc++] = r;
+}
+
 void
 gather_here_documents ()
 {
   int r;
 
   r = 0;
-  while (need_here_doc)
+  while (need_here_doc > 0)
     {
       parser_state |= PST_HEREDOC;
       make_here_document (redir_stack[r++], line_number);
@@ -5100,11 +5130,16 @@
     case AND_AND:
     case OR_OR:
     case '&':
+    case WHILE:
     case DO:
+    case UNTIL:
+    case IF:
     case THEN:
+    case ELIF:
     case ELSE:
     case '{':		/* } */
-    case '(':		/* ) */
+    case '(':		/* )( */
+    case ')':		/* only valid in case statement */
     case BANG:		/* ! time pipeline */
     case TIME:		/* time time pipeline */
     case TIMEOPT:	/* time -p time pipeline */
@@ -5265,6 +5300,8 @@
   FREE (word_desc_to_read);
   word_desc_to_read = (WORD_DESC *)NULL;
 
+  eol_ungetc_lookahead = 0;
+
   current_token = '\n';		/* XXX */
   last_read_token = '\n';
   token_to_read = '\n';
@@ -5710,7 +5747,7 @@
          within a double-quoted ${...} construct "an even number of
          unescaped double-quotes or single-quotes, if any, shall occur." */
       /* This was changed in Austin Group Interp 221 */
-      if MBTEST(posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE && (flags & P_DQUOTE) && (flags & P_DOLBRACE) && ch == '\'')
+      if MBTEST(posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE && dolbrace_state != DOLBRACE_QUOTE2 && (flags & P_DQUOTE) && (flags & P_DOLBRACE) && ch == '\'')
 	continue;
 
       /* Could also check open == '`' if we want to parse grouping constructs
@@ -5983,6 +6020,8 @@
 /*itrace("parse_comsub:%d: lex_inword -> 1 ch = `%c' (%d)", line_number, ch, __LINE__);*/
 	      tflags |= LEX_INWORD;
 	      lex_wlen = 0;
+	      if (tflags & LEX_RESWDOK)
+		lex_rwlen = 0;
 	    }
 	}
 
@@ -6317,8 +6356,8 @@
   reset_parser ();
   /* reset_parser clears shell_input_line and associated variables */
   restore_input_line_state (&ls);
-  if (interactive)
-    token_to_read = 0;
+
+  token_to_read = 0;
 
   /* Need to find how many characters parse_and_execute consumed, update
      *indp, if flags != 0, copy the portion of the string parsed into RET
@@ -8387,6 +8426,7 @@
 
   ps->expand_aliases = expand_aliases;
   ps->echo_input_at_read = echo_input_at_read;
+  ps->need_here_doc = need_here_doc;
 
   ps->token = token;
   ps->token_buffer_size = token_buffer_size;
@@ -8435,6 +8475,7 @@
 
   expand_aliases = ps->expand_aliases;
   echo_input_at_read = ps->echo_input_at_read;
+  need_here_doc = ps->need_here_doc;
 
   FREE (token);
   token = ps->token;
