From mboxrd@z Thu Jan 1 00:00:00 1970 Delivery-date: Wed, 05 Jan 2022 14:00:43 +0100 Received: from metis.ext.pengutronix.de ([2001:67c:670:201:290:27ff:fe1d:cc33]) by lore.white.stw.pengutronix.de with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1n55uF-00Bm9w-5M for lore@lore.pengutronix.de; Wed, 05 Jan 2022 14:00:43 +0100 Received: from localhost ([127.0.0.1] helo=metis.ext.pengutronix.de) by metis.ext.pengutronix.de with esmtp (Exim 4.92) (envelope-from ) id 1n55uE-0002PX-8k; Wed, 05 Jan 2022 14:00:42 +0100 Received: from drehscheibe.grey.stw.pengutronix.de ([2a0a:edc0:0:c01:1d::a2]) by metis.ext.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1n55tz-0002P9-CS; Wed, 05 Jan 2022 14:00:27 +0100 Received: from [2a0a:edc0:0:1101:1d::39] (helo=dude03.red.stw.pengutronix.de) by drehscheibe.grey.stw.pengutronix.de with esmtp (Exim 4.94.2) (envelope-from ) id 1n55tz-008bLf-6I; Wed, 05 Jan 2022 14:00:26 +0100 Received: from mol by dude03.red.stw.pengutronix.de with local (Exim 4.94.2) (envelope-from ) id 1n55tx-005Obs-Je; Wed, 05 Jan 2022 14:00:25 +0100 Date: Wed, 5 Jan 2022 14:00:25 +0100 From: Michael Olbrich To: Christian Melki Message-ID: Mail-Followup-To: Christian Melki , ptxdist@pengutronix.de References: <20211222130304.2549154-1-christian.melki@t2data.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20211222130304.2549154-1-christian.melki@t2data.com> X-Sent-From: Pengutronix Hildesheim X-URL: http://www.pengutronix.de/ X-IRC: #ptxdist @freenode X-Accept-Language: de,en X-Accept-Content-Type: text/plain Subject: Re: [ptxdist] [PATCH] bash: Version bump. 4.3.30 (+patches-33) -> 5.1.8 (patches-12). X-BeenThere: ptxdist@pengutronix.de X-Mailman-Version: 2.1.29 Precedence: list List-Id: PTXdist Development Mailing List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: ptxdist@pengutronix.de Cc: ptxdist@pengutronix.de Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "ptxdist" X-SA-Exim-Connect-IP: 127.0.0.1 X-SA-Exim-Mail-From: ptxdist-bounces@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false On Wed, Dec 22, 2021 at 02:02:42PM +0100, Christian Melki wrote: > 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. License file changed. Please check & update. "ptxdist licensecheck " is your friend :-). Michael > Signed-off-by: Christian Melki > --- > .../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 > -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 . > -+*/ > -+ > -+#include "config.h" > -+ > -+#include "bashtypes.h" > -+#include "posixstat.h" > -+#include "posixtime.h" > -+ > -+#if defined (__QNX__) > -+# if defined (__QNXNTO__) > -+# include > -+# else > -+# include > -+# endif /* !__QNXNTO__ */ > -+#endif /* __QNX__ */ > -+ > -+#if defined (HAVE_UNISTD_H) > -+# include > -+#endif > -+ > -+#include > -+#include "chartypes.h" > -+#if defined (HAVE_PWD_H) > -+# include > -+#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 > -+#else > -+# include > -+#endif > -+ > -+#if defined (HISTORY) > -+# include "bashhist.h" > -+# include > -+#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 > -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 . > --*/ > -- > --#include "config.h" > -- > --#include "bashtypes.h" > --#include "posixstat.h" > --#include "posixtime.h" > -- > --#if defined (__QNX__) > --# if defined (__QNXNTO__) > --# include > --# else > --# include > --# endif /* !__QNXNTO__ */ > --#endif /* __QNX__ */ > -- > --#if defined (HAVE_UNISTD_H) > --# include > --#endif > -- > --#include > --#include "chartypes.h" > --#if defined (HAVE_PWD_H) > --# include > --#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 > --#else > --# include > --#endif > -- > --#if defined (HISTORY) > --# include "bashhist.h" > --# include > --#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 > -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 > - # 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 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 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 > -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ ptxdist mailing list ptxdist@pengutronix.de To unsubscribe, send a mail with subject "unsubscribe" to ptxdist-request@pengutronix.de