mailarchive of the ptxdist mailing list
 help / color / mirror / Atom feed
From: Christian Melki <christian.melki@t2data.com>
To: ptxdist@pengutronix.de
Subject: [ptxdist] [PATCH] bash: Version bump. 4.3.30 (+patches-33) -> 5.1.8 (patches-12).
Date: Wed, 22 Dec 2021 14:02:42 +0100	[thread overview]
Message-ID: <20211222130304.2549154-1-christian.melki@t2data.com> (raw)

Upgrade bash to 5.1.8 plus patches to patchlevel 12.
Roll up patches as in previous series.

Fixes CVE-2019-18276 and CVE-2019-9924 with a new baseline, without patches.
Fixes loads of bugs in bash.

Signed-off-by: Christian Melki <christian.melki@t2data.com>
---
 .../bash-4.3.30/0001-Bash-4.3-patch-31.patch  | 5467 -----------------
 .../bash-4.3.30/0002-Bash-4.3-patch-32.patch  | 5409 ----------------
 .../bash-4.3.30/0003-Bash-4.3-patch-33.patch  |  204 -
 patches/bash-4.3.30/series                    |    6 -
 .../bash-5.1.8/0001-Bash-5.1-patch-12.patch   |  262 +
 patches/bash-5.1.8/series                     |    1 +
 rules/bash.make                               |    4 +-
 7 files changed, 265 insertions(+), 11088 deletions(-)
 delete mode 100644 patches/bash-4.3.30/0001-Bash-4.3-patch-31.patch
 delete mode 100644 patches/bash-4.3.30/0002-Bash-4.3-patch-32.patch
 delete mode 100644 patches/bash-4.3.30/0003-Bash-4.3-patch-33.patch
 delete mode 100644 patches/bash-4.3.30/series
 create mode 100644 patches/bash-5.1.8/0001-Bash-5.1-patch-12.patch
 create mode 100644 patches/bash-5.1.8/series

diff --git a/patches/bash-4.3.30/0001-Bash-4.3-patch-31.patch b/patches/bash-4.3.30/0001-Bash-4.3-patch-31.patch
deleted file mode 100644
index d9a187dcb..000000000
--- a/patches/bash-4.3.30/0001-Bash-4.3-patch-31.patch
+++ /dev/null
@@ -1,5467 +0,0 @@
-From: Chet Ramey <chet.ramey@case.edu>
-Date: Thu, 15 Jan 2015 10:20:04 -0500
-Subject: [PATCH] Bash-4.3 patch 31
-
----
- patchlevel.h     |    2 +-
- subst.h          |    1 +
- variables.c      |   32 +-
- variables.c.orig | 5365 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 4 files changed, 5397 insertions(+), 3 deletions(-)
- create mode 100644 variables.c.orig
-
-diff --git a/patchlevel.h b/patchlevel.h
-index e5dde5245275..0ad46aafbdd9 100644
---- a/patchlevel.h
-+++ b/patchlevel.h
-@@ -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 30
-+#define PATCHLEVEL 31
- 
- #endif /* _PATCHLEVEL_H_ */
-diff --git a/subst.h b/subst.h
-index cedaf8b6b444..1c300ab96b04 100644
---- a/subst.h
-+++ b/subst.h
-@@ -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 */
-diff --git a/variables.c b/variables.c
-index 7c82710e0f0b..81b7877e32e8 100644
---- a/variables.c
-+++ b/variables.c
-@@ -2516,10 +2516,27 @@ bind_variable_internal (name, value, table, hflags, aflags)
-      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)
-     {
-@@ -2550,6 +2567,16 @@ bind_variable_internal (name, value, table, hflags, aflags)
-       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);
-@@ -2670,7 +2697,8 @@ bind_variable (name, value, flags)
- 			 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;
-diff --git a/variables.c.orig b/variables.c.orig
-new file mode 100644
-index 000000000000..7c82710e0f0b
---- /dev/null
-+++ b/variables.c.orig
-@@ -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 --git a/patches/bash-4.3.30/0002-Bash-4.3-patch-32.patch b/patches/bash-4.3.30/0002-Bash-4.3-patch-32.patch
deleted file mode 100644
index 801b4a609..000000000
--- a/patches/bash-4.3.30/0002-Bash-4.3-patch-32.patch
+++ /dev/null
@@ -1,5409 +0,0 @@
-From: Chet Ramey <chet.ramey@case.edu>
-Date: Thu, 15 Jan 2015 10:20:45 -0500
-Subject: [PATCH] Bash-4.3 patch 32
-
----
- jobs.c           |    4 +-
- patchlevel.h     |    2 +-
- variables.c.orig | 5365 ------------------------------------------------------
- 3 files changed, 4 insertions(+), 5367 deletions(-)
- delete mode 100644 variables.c.orig
-
-diff --git a/jobs.c b/jobs.c
-index f38b0c3f4446..b6e59eba0de8 100644
---- a/jobs.c
-+++ b/jobs.c
-@@ -3339,7 +3339,9 @@ itrace("waitchld: waitpid returns %d block = %d", pid, block);
-       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  */
-diff --git a/patchlevel.h b/patchlevel.h
-index 0ad46aafbdd9..b8bf38704ed2 100644
---- a/patchlevel.h
-+++ b/patchlevel.h
-@@ -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 31
-+#define PATCHLEVEL 32
- 
- #endif /* _PATCHLEVEL_H_ */
-diff --git a/variables.c.orig b/variables.c.orig
-deleted file mode 100644
-index 7c82710e0f0b..000000000000
---- a/variables.c.orig
-+++ /dev/null
-@@ -1,5365 +0,0 @@
--/* 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 --git a/patches/bash-4.3.30/0003-Bash-4.3-patch-33.patch b/patches/bash-4.3.30/0003-Bash-4.3-patch-33.patch
deleted file mode 100644
index cda179735..000000000
--- a/patches/bash-4.3.30/0003-Bash-4.3-patch-33.patch
+++ /dev/null
@@ -1,204 +0,0 @@
-From: Chet Ramey <chet.ramey@case.edu>
-Date: Thu, 15 Jan 2015 10:21:08 -0500
-Subject: [PATCH] Bash-4.3 patch 33
-
----
- bashline.c        |  6 ++++--
- builtins/common.h |  4 ++++
- builtins/read.def | 31 ++++++++++++++++++++++++++++---
- patchlevel.h      |  2 +-
- shell.c           |  9 +++++++++
- sig.c             |  6 ++++--
- 6 files changed, 50 insertions(+), 8 deletions(-)
-
-diff --git a/bashline.c b/bashline.c
-index 77ca033f2cc8..c87415171a4a 100644
---- a/bashline.c
-+++ b/bashline.c
-@@ -202,6 +202,7 @@ extern int current_command_line_count, saved_command_line_count;
- 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;
-@@ -4208,8 +4209,9 @@ bash_event_hook ()
- {
-   /* 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 --git a/builtins/common.h b/builtins/common.h
-index cae16b10fb65..a1298cb9c84a 100644
---- a/builtins/common.h
-+++ b/builtins/common.h
-@@ -122,6 +122,10 @@ extern void bash_logout __P((void));
- /* 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 --git a/builtins/read.def b/builtins/read.def
-index 43971544d081..56c23010bbe8 100644
---- a/builtins/read.def
-+++ b/builtins/read.def
-@@ -140,10 +140,12 @@ static void reset_alarm __P((void));
- 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 @@ read_builtin (list)
-   struct stat tsb;
-   SHELL_VAR *var;
-   TTYSTRUCT ttattrs, ttset;
--  struct ttsave termsave;
- #if defined (ARRAY_VARS)
-   WORD_LIST *alist;
- #endif
-@@ -221,7 +222,7 @@ read_builtin (list)
-   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,6 +439,8 @@ read_builtin (list)
- 	  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)
-@@ -482,7 +485,10 @@ read_builtin (list)
- 	  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 */
-@@ -497,7 +503,10 @@ read_builtin (list)
-       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
-@@ -588,6 +597,8 @@ read_builtin (list)
- 	    }
- 	  else
- 	    lastsig = 0;
-+	  if (terminating_signal && tty_modified)
-+	    ttyrestore (&termsave);	/* fix terminal before exiting */
- 	  CHECK_TERMSIG;
- 	  eof = 1;
- 	  break;
-@@ -978,6 +989,20 @@ ttyrestore (ttp)
-      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)
-diff --git a/patchlevel.h b/patchlevel.h
-index b8bf38704ed2..cefe6bdd3a13 100644
---- a/patchlevel.h
-+++ b/patchlevel.h
-@@ -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 32
-+#define PATCHLEVEL 33
- 
- #endif /* _PATCHLEVEL_H_ */
-diff --git a/shell.c b/shell.c
-index bbc8a66cc2eb..2fd8179ba10d 100644
---- a/shell.c
-+++ b/shell.c
-@@ -73,6 +73,7 @@
- #endif
- 
- #if defined (READLINE)
-+#  include <readline/readline.h>
- #  include "bashline.h"
- #endif
- 
-@@ -909,6 +910,14 @@ exit_shell (s)
-   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 --git a/sig.c b/sig.c
-index 3b62ea5d7c5d..8bc45c17f478 100644
---- a/sig.c
-+++ b/sig.c
-@@ -532,8 +532,10 @@ termsig_sighandler (sig)
- #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 --git a/patches/bash-4.3.30/series b/patches/bash-4.3.30/series
deleted file mode 100644
index 2e1fdf17f..000000000
--- a/patches/bash-4.3.30/series
+++ /dev/null
@@ -1,6 +0,0 @@
-# generated by git-ptx-patches
-#tag:base --start-number 1
-0001-Bash-4.3-patch-31.patch
-0002-Bash-4.3-patch-32.patch
-0003-Bash-4.3-patch-33.patch
-# 602897f584d96d29536a2fa60f8d5e23  - git-ptx-patches magic
diff --git a/patches/bash-5.1.8/0001-Bash-5.1-patch-12.patch b/patches/bash-5.1.8/0001-Bash-5.1-patch-12.patch
new file mode 100644
index 000000000..ef8b6ae7f
--- /dev/null
+++ b/patches/bash-5.1.8/0001-Bash-5.1-patch-12.patch
@@ -0,0 +1,262 @@
+diff -urN bash-5.1.8.orig/builtins/wait.def bash-5.1.8/builtins/wait.def
+--- bash-5.1.8.orig/builtins/wait.def	2021-12-21 12:57:08.083139502 +0100
++++ bash-5.1.8/builtins/wait.def	2021-12-21 12:58:24.304849937 +0100
+@@ -111,7 +111,8 @@
+ wait_builtin (list)
+      WORD_LIST *list;
+ {
+-  int status, code, opt, nflag, wflags;
++  int status, code, opt, nflag;
++  volatile int wflags;
+   char *vname;
+   SHELL_VAR *pidvar;
+   struct procstat pstat;
+@@ -180,6 +181,8 @@
+       last_command_exit_signal = wait_signal_received;
+       status = 128 + wait_signal_received;
+       wait_sigint_cleanup ();
++      if (wflags & JWAIT_WAITING)
++	unset_waitlist ();
+       WAIT_RETURN (status);
+     }
+ 
+diff -urN bash-5.1.8.orig/command.h bash-5.1.8/command.h
+--- bash-5.1.8.orig/command.h	2021-12-21 12:57:08.099139862 +0100
++++ bash-5.1.8/command.h	2021-12-21 12:58:27.760927380 +0100
+@@ -124,6 +124,7 @@
+ #define SUBSHELL_PROCSUB 0x20	/* subshell caused by <(command) or >(command) */
+ #define SUBSHELL_COPROC	0x40	/* subshell from a coproc pipeline */
+ #define SUBSHELL_RESETTRAP 0x80	/* subshell needs to reset trap strings on first call to trap */
++#define SUBSHELL_IGNTRAP 0x100  /* subshell should reset trapped signals from trap_handler */
+ 
+ /* A structure which represents a word. */
+ typedef struct word_desc {
+diff -urN bash-5.1.8.orig/execute_cmd.c bash-5.1.8/execute_cmd.c
+--- bash-5.1.8.orig/execute_cmd.c	2021-12-21 12:57:08.091139683 +0100
++++ bash-5.1.8/execute_cmd.c	2021-12-21 12:58:27.764927470 +0100
+@@ -1547,6 +1547,9 @@
+   clear_pending_traps ();
+   reset_signal_handlers ();
+   subshell_environment |= SUBSHELL_RESETTRAP;
++  /* Note that signal handlers have been reset, so we should no longer
++    reset the handler and resend trapped signals to ourselves. */
++  subshell_environment &= ~SUBSHELL_IGNTRAP;
+ 
+   /* We are in a subshell, so forget that we are running a trap handler or
+      that the signal handler has changed (we haven't changed it!) */
+@@ -4320,7 +4323,8 @@
+ 	  already_forked = 1;
+ 	  cmdflags |= CMD_NO_FORK;
+ 
+-	  subshell_environment = SUBSHELL_FORK;		/* XXX */
++	  /* We redo some of what make_child() does with SUBSHELL_IGNTRAP */
++	  subshell_environment = SUBSHELL_FORK|SUBSHELL_IGNTRAP;	/* XXX */
+ 	  if (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
+ 	    subshell_environment |= SUBSHELL_PIPE;
+ 	  if (async)
+@@ -4574,6 +4578,7 @@
+ 	     trap strings if we run trap to change a signal disposition. */
+ 	  reset_signal_handlers ();
+ 	  subshell_environment |= SUBSHELL_RESETTRAP;
++	  subshell_environment &= ~SUBSHELL_IGNTRAP;
+ 
+ 	  if (async)
+ 	    {
+@@ -5514,6 +5519,7 @@
+       reset_terminating_signals ();	/* XXX */
+       /* Cancel traps, in trap.c. */
+       restore_original_signals ();
++      subshell_environment &= ~SUBSHELL_IGNTRAP;
+ 
+ #if defined (JOB_CONTROL)
+       FREE (p);
+diff -urN bash-5.1.8.orig/jobs.c bash-5.1.8/jobs.c
+--- bash-5.1.8.orig/jobs.c	2021-12-21 12:57:08.091139683 +0100
++++ bash-5.1.8/jobs.c	2021-12-21 12:58:27.764927470 +0100
+@@ -2217,6 +2217,8 @@
+ 	 signals to the default state for a new process. */
+       pid_t mypid;
+ 
++      subshell_environment |= SUBSHELL_IGNTRAP;
++
+       /* If this ends up being changed to modify or use `command' in the
+ 	 child process, go back and change callers who free `command' in
+ 	 the child process when this returns. */
+diff -urN bash-5.1.8.orig/lib/malloc/malloc.c bash-5.1.8/lib/malloc/malloc.c
+--- bash-5.1.8.orig/lib/malloc/malloc.c	2021-12-21 12:57:08.095139773 +0100
++++ bash-5.1.8/lib/malloc/malloc.c	2021-12-21 12:58:22.200802784 +0100
+@@ -1286,13 +1286,12 @@
+       p = (union mhead *) ap - 1;
+     }
+ 
+-  /* XXX - should we return 0 if ISFREE? */
+-  maxbytes = binsize(p->mh_index);
+-
+-  /* So the usable size is the maximum number of bytes in the bin less the
+-     malloc overhead */
+-  maxbytes -= MOVERHEAD + MSLOP;
+-  return (maxbytes);
++  /* return 0 if ISFREE */
++  if (p->mh_alloc == ISFREE)
++    return 0;
++  
++  /* Since we use bounds checking, the usable size is the last requested size. */
++  return (p->mh_nbytes);
+ }
+ 
+ #if !defined (NO_VALLOC)
+diff -urN bash-5.1.8.orig/nojobs.c bash-5.1.8/nojobs.c
+--- bash-5.1.8.orig/nojobs.c	2021-12-21 12:57:08.091139683 +0100
++++ bash-5.1.8/nojobs.c	2021-12-21 12:58:27.764927470 +0100
+@@ -575,6 +575,8 @@
+ 	last_asynchronous_pid = getpid ();
+ #endif
+ 
++      subshell_environment |= SUBSHELL_IGNTRAP;
++
+       default_tty_job_signals ();
+     }
+   else
+diff -urN bash-5.1.8.orig/parse.y bash-5.1.8/parse.y
+--- bash-5.1.8.orig/parse.y	2021-12-21 12:57:08.099139862 +0100
++++ bash-5.1.8/parse.y	2021-12-21 12:58:26.112890455 +0100
+@@ -6493,10 +6493,8 @@
+   old_expand_aliases = expand_aliases;
+ 
+   push_stream (1);
+-#if 0 /* TAG: bash-5.2 Alex fxmbsw7 Ratchev <fxmbsw7@gmail.com> 11/17/2020 */
+   if (ea = expanding_alias ())
+     parser_save_alias ();
+-#endif
+   last_read_token = WORD;		/* WORD to allow reserved words here */
+   current_command_line_count = 0;
+   echo_input_at_read = expand_aliases = 0;
+@@ -6531,10 +6529,8 @@
+   last_read_token = '\n';
+   pop_stream ();
+ 
+-#if 0 /* TAG: bash-5.2 */
+   if (ea)
+     parser_restore_alias ();
+-#endif
+ 
+ #if defined (HISTORY)
+   remember_on_history = old_remember_on_history;
+diff -urN bash-5.1.8.orig/patchlevel.h bash-5.1.8/patchlevel.h
+--- bash-5.1.8.orig/patchlevel.h	2021-12-21 12:57:08.075139321 +0100
++++ bash-5.1.8/patchlevel.h	2021-12-21 12:58:27.764927470 +0100
+@@ -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 8
++#define PATCHLEVEL 12
+ 
+ #endif /* _PATCHLEVEL_H_ */
+diff -urN bash-5.1.8.orig/sig.c bash-5.1.8/sig.c
+--- bash-5.1.8.orig/sig.c	2021-12-21 12:57:08.071139231 +0100
++++ bash-5.1.8/sig.c	2021-12-21 12:58:27.764927470 +0100
+@@ -55,7 +55,8 @@
+ #  include "bashhist.h"
+ #endif
+ 
+-extern void initialize_siglist ();
++extern void initialize_siglist PARAMS((void));
++extern void set_original_signal PARAMS((int, SigHandler *));
+ 
+ #if !defined (JOB_CONTROL)
+ extern void initialize_job_signals PARAMS((void));
+@@ -255,6 +256,13 @@
+       sigaction (XSIG (i), &act, &oact);
+       XHANDLER(i) = oact.sa_handler;
+       XSAFLAGS(i) = oact.sa_flags;
++
++#if 0
++      set_original_signal (XSIG(i), XHANDLER(i));	/* optimization */
++#else
++      set_original_signal (XSIG(i), act.sa_handler);	/* optimization */
++#endif
++
+       /* Don't do anything with signals that are ignored at shell entry
+ 	 if the shell is not interactive. */
+       /* XXX - should we do this for interactive shells, too? */
+diff -urN bash-5.1.8.orig/subst.c bash-5.1.8/subst.c
+--- bash-5.1.8.orig/subst.c	2021-12-21 12:57:08.099139862 +0100
++++ bash-5.1.8/subst.c	2021-12-21 12:58:27.764927470 +0100
+@@ -5951,6 +5951,7 @@
+       free_pushed_string_input ();
+       /* Cancel traps, in trap.c. */
+       restore_original_signals ();	/* XXX - what about special builtins? bash-4.2 */
++      subshell_environment &= ~SUBSHELL_IGNTRAP;
+       QUIT;	/* catch any interrupts we got post-fork */
+       setup_async_signals ();
+ #if 0
+@@ -6382,6 +6383,7 @@
+ 	}	
+       QUIT;	/* catch any interrupts we got post-fork */
+       subshell_environment |= SUBSHELL_RESETTRAP;
++      subshell_environment &= ~SUBSHELL_IGNTRAP;
+     }
+ 
+ #if defined (JOB_CONTROL)
+diff -urN bash-5.1.8.orig/trap.c bash-5.1.8/trap.c
+--- bash-5.1.8.orig/trap.c	2021-12-21 12:57:08.083139502 +0100
++++ bash-5.1.8/trap.c	2021-12-21 12:58:27.764927470 +0100
+@@ -481,6 +481,32 @@
+       SIGRETURN (0);
+     }
+ 
++  /* This means we're in a subshell, but have not yet reset the handler for
++     trapped signals. We're not supposed to execute the trap in this situation;
++     we should restore the original signal and resend the signal to ourselves
++     to preserve the Posix "signal traps that are not being ignored shall be
++     set to the default action" semantics. */
++  if ((subshell_environment & SUBSHELL_IGNTRAP) && trap_list[sig] != (char *)IGNORE_SIG)
++    {
++      sigset_t mask;
++
++      /* Paranoia */
++      if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER)
++	original_signals[sig] = SIG_DFL;
++
++      restore_signal (sig);
++
++      /* Make sure we let the signal we just caught through */
++      sigemptyset (&mask);
++      sigprocmask (SIG_SETMASK, (sigset_t *)NULL, &mask);
++      sigdelset (&mask, sig);
++      sigprocmask (SIG_SETMASK, &mask, (sigset_t *)NULL);
++
++      kill (getpid (), sig);
++
++      SIGRETURN (0);
++    }
++
+   if ((sig >= NSIG) ||
+       (trap_list[sig] == (char *)DEFAULT_SIG) ||
+       (trap_list[sig] == (char *)IGNORE_SIG))
+diff -urN bash-5.1.8.orig/y.tab.c bash-5.1.8/y.tab.c
+--- bash-5.1.8.orig/y.tab.c	2021-12-21 12:57:08.075139321 +0100
++++ bash-5.1.8/y.tab.c	2021-12-21 12:58:26.116890545 +0100
+@@ -8787,10 +8787,8 @@
+   old_expand_aliases = expand_aliases;
+ 
+   push_stream (1);
+-#if 0 /* TAG: bash-5.2 Alex fxmbsw7 Ratchev <fxmbsw7@gmail.com> 11/17/2020 */
+   if (ea = expanding_alias ())
+     parser_save_alias ();
+-#endif
+   last_read_token = WORD;		/* WORD to allow reserved words here */
+   current_command_line_count = 0;
+   echo_input_at_read = expand_aliases = 0;
+@@ -8825,10 +8823,8 @@
+   last_read_token = '\n';
+   pop_stream ();
+ 
+-#if 0 /* TAG: bash-5.2 */
+   if (ea)
+     parser_restore_alias ();
+-#endif
+ 
+ #if defined (HISTORY)
+   remember_on_history = old_remember_on_history;
diff --git a/patches/bash-5.1.8/series b/patches/bash-5.1.8/series
new file mode 100644
index 000000000..0e53e492a
--- /dev/null
+++ b/patches/bash-5.1.8/series
@@ -0,0 +1 @@
+0001-Bash-5.1-patch-12.patch
diff --git a/rules/bash.make b/rules/bash.make
index bed121586..c46196f7f 100644
--- a/rules/bash.make
+++ b/rules/bash.make
@@ -13,8 +13,8 @@ PACKAGES-$(PTXCONF_BASH) += bash
 #
 # Paths and names
 #
-BASH_VERSION	:= 4.3.30
-BASH_MD5	:= a27b3ee9be83bd3ba448c0ff52b28447
+BASH_VERSION	:= 5.1.8
+BASH_MD5	:= 23eee6195b47318b9fd878e590ccb38c
 BASH		:= bash-$(BASH_VERSION)
 BASH_SUFFIX	:= tar.gz
 BASH_URL	:= $(call ptx/mirror, GNU, bash/$(BASH).$(BASH_SUFFIX))
-- 
2.30.2


_______________________________________________
ptxdist mailing list
ptxdist@pengutronix.de
To unsubscribe, send a mail with subject "unsubscribe" to ptxdist-request@pengutronix.de


             reply	other threads:[~2021-12-22 13:07 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-12-22 13:02 Christian Melki [this message]
2021-12-22 13:02 ` [ptxdist] [PATCH] bridge-utils: Version bump. 1.6 -> 1.7.1 Christian Melki
2022-01-21  7:18   ` [ptxdist] [APPLIED] " Michael Olbrich
2021-12-22 13:02 ` [ptxdist] [PATCH] curl: Version bump 7.77.0 -> 7.80.0 Christian Melki
2022-01-21  7:19   ` [ptxdist] [APPLIED] " Michael Olbrich
2021-12-22 13:02 ` [ptxdist] [PATCH] e2fsprogs: Version bump 1.46.2 -> 1.46.4 Christian Melki
2022-01-21  7:19   ` [ptxdist] [APPLIED] " Michael Olbrich
2021-12-22 13:02 ` [ptxdist] [PATCH] ethtool: Version bump. 5.13 -> 5.15 Christian Melki
2022-01-21  7:19   ` [ptxdist] [APPLIED] " Michael Olbrich
2021-12-22 13:02 ` [ptxdist] [PATCH] expat: Version bump 2.4.1 -> 2.4.2 Christian Melki
2022-01-21  7:19   ` [ptxdist] [APPLIED] " Michael Olbrich
2021-12-22 13:02 ` [ptxdist] [PATCH] host-libcap: BUILD_GPERF is reserved Christian Melki
2022-01-05 12:18   ` Michael Olbrich
2021-12-22 13:02 ` [ptxdist] [PATCH] iptables: Version bump 1.8.3 -> 1.8.7 Christian Melki
2022-01-06  7:10   ` Michael Olbrich
2022-01-21  7:19   ` [ptxdist] [APPLIED] " Michael Olbrich
2021-12-22 13:02 ` [ptxdist] [PATCH] jimtcl: Verison bump 0.80 -> 0.81 Christian Melki
2022-01-21  7:19   ` [ptxdist] [APPLIED] " Michael Olbrich
2021-12-22 13:02 ` [ptxdist] [PATCH] libcap-ng: Version bump 0.7.10 -> 0.8.2 Christian Melki
2022-01-21  7:19   ` [ptxdist] [APPLIED] " Michael Olbrich
2021-12-22 13:02 ` [ptxdist] [PATCH] libcap: Version bump 2.51 -> 2.62 Christian Melki
2022-01-05 12:21   ` Michael Olbrich
2022-01-05 12:32     ` Christian Melki
2022-01-05 12:46       ` Michael Olbrich
2021-12-22 13:02 ` [ptxdist] [PATCH] libffi: Version bump 3.3 -> 3.4.2 Christian Melki
2022-01-21  7:19   ` [ptxdist] [APPLIED] " Michael Olbrich
2021-12-22 13:02 ` [ptxdist] [PATCH] libjpeg: Version bump 2.1.0 -> 2.1.2 Christian Melki
2022-01-21  7:19   ` [ptxdist] [APPLIED] " Michael Olbrich
2021-12-22 13:02 ` [ptxdist] [PATCH] libmbim: Version bump 1.24.2 -> 1.26.2 Christian Melki
2022-01-21  7:19   ` [ptxdist] [APPLIED] " Michael Olbrich
2021-12-22 13:02 ` [ptxdist] [PATCH] libseccomp: Version bump 2.5.1 -> 2.5.3 Christian Melki
2022-01-06 10:56   ` Michael Olbrich
2021-12-22 13:02 ` [ptxdist] [PATCH] libunwind: Version bump 1.5.0 -> 1.6.2 Christian Melki
2022-01-21  7:19   ` [ptxdist] [APPLIED] " Michael Olbrich
2021-12-22 13:02 ` [ptxdist] [PATCH] openssh: Version bump 8.6p1 -> 8.8p1 Christian Melki
2022-01-21  7:19   ` [ptxdist] [APPLIED] " Michael Olbrich
2021-12-22 13:02 ` [ptxdist] [PATCH] screen: Version bump 4.5.0 -> 4.8.0 Christian Melki
2022-01-06 10:55   ` Michael Olbrich
2022-01-07  9:58     ` Christian Melki
2022-01-07 11:05       ` Michael Olbrich
2022-01-21  7:19   ` [ptxdist] [APPLIED] " Michael Olbrich
2021-12-22 13:03 ` [ptxdist] [PATCH] strace: Version bump 5.9 -> 5.15 Christian Melki
2022-01-05 12:53   ` Michael Olbrich
2021-12-22 13:03 ` [ptxdist] [PATCH] tcpdump: Version bump 4.93 -> 4.99.1 Christian Melki
2022-01-06  7:22   ` Michael Olbrich
2021-12-22 13:03 ` [ptxdist] [WIP: PATCH] usbutils: Version bump 007 -> 014 Christian Melki
2022-01-05 12:38   ` Michael Olbrich
2022-01-06 21:52     ` Christian Melki
2022-01-07  8:09       ` Michael Olbrich
2021-12-22 13:03 ` [ptxdist] [PATCH] util-linux-ng: Version bump 2.37 -> 2.37.2 Christian Melki
2022-01-21  7:19   ` [ptxdist] [APPLIED] " Michael Olbrich
2021-12-22 13:03 ` [ptxdist] [PATCH] zstd: Version bump 1.5.0 -> 1.5.1 Christian Melki
2022-01-21  7:19   ` [ptxdist] [APPLIED] " Michael Olbrich
2022-01-05 13:00 ` [ptxdist] [PATCH] bash: Version bump. 4.3.30 (+patches-33) -> 5.1.8 (patches-12) Michael Olbrich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211222130304.2549154-1-christian.melki@t2data.com \
    --to=christian.melki@t2data.com \
    --cc=ptxdist@pengutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox