From 011c1d1c0766c65517ebd495465c99e86edb63ec Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 11 Oct 2010 14:49:26 -0700 Subject: Update to bash-4.1 --- variables.c | 661 +++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 538 insertions(+), 123 deletions(-) (limited to 'variables.c') diff --git a/variables.c b/variables.c index 5fd9d0e..d1da8f6 100644 --- a/variables.c +++ b/variables.c @@ -1,22 +1,22 @@ /* variables.c -- Functions for hacking shell variables. */ -/* Copyright (C) 1987-2005 Free Software Foundation, Inc. +/* Copyright (C) 1987-2009 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 2, or (at your option) - any later version. + 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. + 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; see the file COPYING. If not, write to the Free - Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + along with Bash. If not, see . +*/ #include "config.h" @@ -24,13 +24,13 @@ #include "posixstat.h" #include "posixtime.h" -#if defined (qnx) -# if defined (qnx6) -# include +#if defined (__QNX__) +# if defined (__QNXNTO__) +# include # else # include -# endif /* !qnx6 */ -#endif /* qnx */ +# endif /* !__QNXNTO__ */ +#endif /* __QNX__ */ #if defined (HAVE_UNISTD_H) # include @@ -38,10 +38,14 @@ #include #include "chartypes.h" -#include +#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" @@ -50,6 +54,7 @@ #include "input.h" #include "hashcmd.h" #include "pathexp.h" +#include "alias.h" #include "builtins/getopt.h" #include "builtins/common.h" @@ -92,6 +97,8 @@ 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; #if defined (READLINE) extern int no_line_editing; @@ -135,6 +142,13 @@ 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. */ @@ -147,13 +161,6 @@ static int winsize_assignment; /* currently assigning to LINES or COLUMNS */ static int winsize_assigned; /* assigned to LINES or COLUMNS */ #endif -/* 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; - /* Some forward declarations. */ static void create_variable_tables __P((void)); @@ -167,42 +174,60 @@ static void uidset __P((void)); static void make_vers_array __P((void)); #endif -static SHELL_VAR *null_assign __P((SHELL_VAR *, char *, arrayind_t)); +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)); +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)); +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 SHELL_VAR *assign_random __P((SHELL_VAR *, char *, arrayind_t)); +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)); +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)); +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)); +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 *)); @@ -215,6 +240,7 @@ 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)); @@ -230,6 +256,7 @@ 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) @@ -307,6 +334,8 @@ initialize_shell_variables (env, privmode) /* 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 ("() {", string, 4)) @@ -351,10 +380,17 @@ initialize_shell_variables (env, privmode) } # endif #endif +#if 0 + else if (legal_identifier (name)) +#else else +#endif { temp_var = bind_variable (name, string, 0); - VSETATTR (temp_var, (att_exported | att_imported)); + if (legal_identifier (name)) + VSETATTR (temp_var, (att_exported | att_imported)); + else + VSETATTR (temp_var, (att_exported | att_imported | att_invisible)); array_needs_making = 1; } @@ -387,11 +423,11 @@ initialize_shell_variables (env, privmode) set_auto_export (temp_var); /* XXX */ #endif -#if defined (qnx) +#if defined (__QNX__) /* set node id -- don't import it from the environment */ { char node_name[22]; -# if defined (qnx6) +# 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)); @@ -495,7 +531,7 @@ initialize_shell_variables (env, privmode) #endif /* HISTORY */ /* Seed the random number generator. */ - sbrand (dollar_dollar_pid + shell_start_time); + seedrand (); /* Handle some "special" variables that we may have inherited from a parent shell. */ @@ -513,6 +549,7 @@ initialize_shell_variables (env, privmode) { sv_history_control ("HISTCONTROL"); sv_histignore ("HISTIGNORE"); + sv_histtimefmt ("HISTTIMEFORMAT"); } #endif /* HISTORY */ @@ -842,7 +879,7 @@ make_vers_array () vv = make_new_array_variable ("BASH_VERSINFO"); av = array_cell (vv); strcpy (d, dist_version); - s = xstrchr (d, '.'); + s = strchr (d, '.'); if (s) *s++ = '\0'; array_insert (av, 0, d); @@ -935,6 +972,8 @@ print_assignment (var) #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 { @@ -980,8 +1019,13 @@ void print_var_function (var) SHELL_VAR *var; { + char *x; + if (function_p (var) && var_isset (var)) - printf ("%s", named_function_string ((char *)NULL, function_cell(var), 1)); + { + x = named_function_string ((char *)NULL, function_cell(var), FUNC_MULTILINE|FUNC_EXTERNAL); + printf ("%s", x); + } } /* **************************************************************** */ @@ -1041,21 +1085,32 @@ print_var_function (var) } \ 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) +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) +null_array_assign (self, value, ind, key) SHELL_VAR *self; char *value; arrayind_t ind; + char *key; { return (self); } @@ -1090,8 +1145,25 @@ init_dynamic_array_var (name, getfunc, setfunc, attrs) VSETATTR (v, attrs); return v; } -#endif +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 @@ -1099,10 +1171,11 @@ init_dynamic_array_var (name, getfunc, setfunc, attrs) static intmax_t seconds_value_assigned; static SHELL_VAR * -assign_seconds (self, value, unused) +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; @@ -1155,8 +1228,26 @@ static int seeded_subshell = 0; static int brand () { +#if 0 rseed = rseed * 1103515245 + 12345; return ((unsigned int)((rseed >> 16) & 32767)); /* was % 32768 */ +#else + /* 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; + + if (rseed == 0) + seedrand (); + 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 */ +#endif } /* Set the random number generator seed to SEED. */ @@ -1168,28 +1259,39 @@ sbrand (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) +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 = 1; + seeded_subshell = getpid (); return (self); } int get_random_number () { - int rv; + int rv, pid; /* Reset for command and process substitution. */ - if (subshell_environment && seeded_subshell == 0) + pid = getpid (); + if (subshell_environment && seeded_subshell != pid) { - sbrand (rseed + getpid() + NOW); - seeded_subshell = 1; + seedrand (); + seeded_subshell = pid; } do @@ -1217,10 +1319,11 @@ get_random (var) } static SHELL_VAR * -assign_lineno (var, value, unused) +assign_lineno (var, value, unused, key) SHELL_VAR *var; char *value; arrayind_t unused; + char *key; { intmax_t new_value; @@ -1246,10 +1349,11 @@ get_lineno (var) } static SHELL_VAR * -assign_subshell (var, value, unused) +assign_subshell (var, value, unused, key) SHELL_VAR *var; char *value; arrayind_t unused; + char *key; { intmax_t new_value; @@ -1271,13 +1375,28 @@ get_subshell (var) 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 @@ -1314,7 +1433,8 @@ get_comp_wordbreaks (var) if (rl_completer_word_break_characters == 0 && bash_readline_initialized == 0) enable_hostname_completion (perform_hostname_completion); - var_setvalue (var, rl_completer_word_break_characters); + FREE (value_cell (var)); + var_setvalue (var, savestring (rl_completer_word_break_characters)); return (var); } @@ -1322,10 +1442,11 @@ get_comp_wordbreaks (var) /* When this function returns, rl_completer_word_break_characters points to malloced memory. */ static SHELL_VAR * -assign_comp_wordbreaks (self, value, unused) +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) @@ -1338,10 +1459,11 @@ assign_comp_wordbreaks (self, value, unused) #if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) static SHELL_VAR * -assign_dirstack (self, value, ind) +assign_dirstack (self, value, ind, key) SHELL_VAR *self; char *value; arrayind_t ind; + char *key; { set_dirstack_element (ind, 1, value); return self; @@ -1384,6 +1506,115 @@ get_groupset (self) } 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 @@ -1452,6 +1683,9 @@ initialize_dynamic_variables () 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); @@ -1474,6 +1708,11 @@ initialize_dynamic_variables () # 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 (); @@ -1520,7 +1759,7 @@ var_lookup (name, vcontext) then also search the temporarily built list of exported variables. The lookup order is: temporary_env - shell_variables list + shell_variables list */ SHELL_VAR * @@ -1557,7 +1796,7 @@ SHELL_VAR * find_variable (name) const char *name; { - return (find_variable_internal (name, (expanding_redir == 0 && this_shell_builtin != 0))); + return (find_variable_internal (name, (expanding_redir == 0 && (assigning_in_environment || executing_builtin)))); } /* Look up the function entry whose name matches STRING. @@ -1575,7 +1814,11 @@ 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 @@ -1589,6 +1832,8 @@ get_variable_value (var) #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)); @@ -1689,7 +1934,7 @@ make_local_variable (name) } if (old_var == 0) - new_var = bind_variable_internal (name, "", vc->table, HASH_NOSRCH, 0); + new_var = make_new_variable (name, vc->table); else { new_var = make_new_variable (name, vc->table); @@ -1698,7 +1943,7 @@ make_local_variable (name) inherit its value. Watch to see if this causes problems with things like `x=4 local x'. */ if (was_tmpvar) - var_setvalue (new_var, savestring (tmp_value)); + var_setvalue (new_var, savestring (tmp_value)); new_var->attributes = exported_p (old_var) ? att_exported : 0; } @@ -1714,27 +1959,6 @@ make_local_variable (name) return (new_var); } -#if defined (ARRAY_VARS) -SHELL_VAR * -make_local_array_variable (name) - char *name; -{ - SHELL_VAR *var; - ARRAY *array; - - var = make_local_variable (name); - if (var == 0 || array_p (var)) - return var; - - array = array_create (); - - FREE (value_cell(var)); - var_setarray (var, array); - VSETATTR (var, att_array); - return var; -} -#endif /* ARRAY_VARS */ - /* Create a new shell variable with name NAME. */ static SHELL_VAR * new_shell_variable (name) @@ -1793,10 +2017,64 @@ make_new_array_variable (name) 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) + char *name; +{ + SHELL_VAR *var; + ARRAY *array; + + var = make_local_variable (name); + if (var == 0 || array_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 * @@ -1807,7 +2085,7 @@ make_variable_value (var, value, flags) { char *retval, *oval; intmax_t lval, rval; - int expok, olen; + 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 @@ -1821,15 +2099,49 @@ make_variable_value (var, value, flags) oval = value_cell (var); lval = evalexp (oval, &expok); /* ksh93 seems to do this */ if (expok == 0) - jump_to_top_level (DISCARD); + { + top_level_cleanup (); + jump_to_top_level (DISCARD); + } } rval = evalexp (value, &expok); if (expok == 0) - jump_to_top_level (DISCARD); + { + top_level_cleanup (); + jump_to_top_level (DISCARD); + } 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) @@ -1880,9 +2192,14 @@ bind_variable_internal (name, value, table, hflags, aflags) { INVALIDATE_EXPORTSTR (entry); newval = (aflags & ASS_APPEND) ? make_variable_value (entry, value, aflags) : value; - entry = (*(entry->assign_func)) (entry, newval, -1); + 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); + free (newval); return (entry); } else @@ -1912,6 +2229,11 @@ bind_variable_internal (name, value, table, hflags, aflags) array_insert (array_cell (entry), 0, newval); free (newval); } + else if (assoc_p (entry)) + { + assoc_insert (assoc_cell (entry), savestring ("0"), newval); + free (newval); + } else #endif { @@ -1957,11 +2279,11 @@ bind_variable (name, value, flags) for (vc = shell_variables; vc; vc = vc->down) { if (vc_isfuncenv (vc) || vc_isbltnenv (vc)) - { - v = hash_lookup (name, vc->table); - if (v) + { + v = hash_lookup (name, vc->table); + if (v) return (bind_variable_internal (name, value, vc->table, 0, flags)); - } + } } return (bind_variable_internal (name, value, global_variables->table, 0, flags)); } @@ -1986,7 +2308,7 @@ bind_variable_value (var, value, aflags) /* 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); + (*(var->assign_func)) (var, t, -1, 0); if (t != value && t) free (t); } @@ -2112,6 +2434,7 @@ bind_function (name, value) 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 @@ -2140,6 +2463,7 @@ bind_function_def (name, value) 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 @@ -2178,13 +2502,7 @@ assign_in_env (word) } temp = name + offset + 1; -#if 0 - temp = (xstrchr (temp, '~') != 0) ? bash_tilde_expand (temp, 1) : savestring (temp); - value = expand_string_unsplit_to_string (temp, 0); - free (temp); -#else value = expand_assignment_string_to_string (temp, 0); -#endif } if (temporary_env == 0) @@ -2248,7 +2566,9 @@ copy_variable (var) var_setfunc (copy, copy_command (function_cell (var))); #if defined (ARRAY_VARS) else if (array_p (var)) - var_setarray (copy, dup_array (array_cell (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 (value_cell (var)) var_setvalue (copy, savestring (value_cell (var))); @@ -2273,21 +2593,31 @@ copy_variable (var) /* **************************************************************** */ /* Dispose of the information attached to VAR. */ -void -dispose_variable (var) +static void +dispose_variable_value (var) SHELL_VAR *var; { - if (var == 0) - return; - 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 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); @@ -2338,6 +2668,7 @@ unbind_func (name) return 0; } +#if defined (DEBUGGER) int unbind_function_def (name) const char *name; @@ -2359,6 +2690,7 @@ unbind_function_def (name) return 0; } +#endif /* DEBUGGER */ /* Make the variable associated with NAME go away. HASH_LIST is the hash table from which this variable should be deleted (either @@ -2394,15 +2726,19 @@ makunbound (name, vc) 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) - if (array_p (old_var)) + else if (array_p (old_var)) array_dispose (array_cell (old_var)); - else + else if (assoc_p (old_var)) + assoc_dispose (assoc_cell (old_var)); #endif + 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. */ + 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); @@ -2768,6 +3104,16 @@ visible_and_exported (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 @@ -2965,7 +3311,7 @@ dispose_temporary_env (pushf) { hash_flush (temporary_env, pushf); hash_dispose (temporary_env); - temporary_env = (HASH_TABLE *)NULL; + temporary_env = (HASH_TABLE *)NULL; array_needs_making = 1; @@ -3025,6 +3371,11 @@ valid_exportstr (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); @@ -3077,6 +3428,12 @@ make_env_array_from_var_list (vars) value = array_to_assignment_string (array_cell (var)); # else continue; /* XXX array vars cannot yet be exported */ +# endif + 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 @@ -3097,7 +3454,7 @@ make_env_array_from_var_list (vars) #if 0 /* not yet */ #if defined (ARRAY_VARS) - if (array_p (var)) + if (array_p (var) || assoc_p (var)) free (value); #endif #endif @@ -3118,7 +3475,11 @@ make_var_export_array (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; @@ -3251,7 +3612,7 @@ maybe_make_export_env () if (array_needs_making) { if (export_env) - strvec_flush (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 @@ -3267,25 +3628,25 @@ maybe_make_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. */ + /* 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; - } + { + tcxt = new_var_context ((char *)NULL, 0); + tcxt->table = temporary_env; + tcxt->down = shell_variables; + } else - tcxt = shell_variables; + 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); + free (tcxt); #if defined (RESTRICTED_SHELL) /* Restricted shells may not export shell functions. */ @@ -3452,9 +3813,11 @@ push_func_var (data) if (shell_variables == global_variables) var->attributes &= ~(att_tempvar|att_propagate); else - shell_variables->flags |= VC_HASTMPVAR; + shell_variables->flags |= VC_HASTMPVAR; v->attributes |= var->attributes; } + else + stupidly_hack_special_variables (var->name); /* XXX */ dispose_variable (var); } @@ -3497,7 +3860,7 @@ delete_all_contexts (vcxt) { t = v->down; dispose_var_context (v); - } + } delete_all_variables (global_variables->table); shell_variables = global_variables; @@ -3541,6 +3904,8 @@ push_exported_var (data) var->attributes &= ~att_propagate; v->attributes |= var->attributes; } + else + stupidly_hack_special_variables (var->name); /* XXX */ dispose_variable (var); } @@ -3730,6 +4095,8 @@ struct name_and_function { }; static struct name_and_function special_vars[] = { + { "BASH_XTRACEFD", sv_xtracefd }, + #if defined (READLINE) # if defined (STRICT_POSIX) { "COLUMNS", sv_winsize }, @@ -3831,7 +4198,7 @@ find_special_var (name) 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; + break; } return -1; } @@ -3857,6 +4224,18 @@ stupidly_hack_special_variables (name) (*(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; @@ -3901,7 +4280,8 @@ void sv_globignore (name) char *name; { - setup_glob_ignore (name); + if (privileged_mode == 0) + setup_glob_ignore (name); } #if defined (READLINE) @@ -3913,7 +4293,7 @@ sv_comp_wordbreaks (name) sv = find_variable (name); if (sv == 0) - rl_completer_word_break_characters = (char *)NULL; + reset_completer_word_break_chars (); } /* What to do just after one of the TERMxxx variables has changed. @@ -4268,3 +4648,38 @@ set_pipestatus_from_exit (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)); + } +} -- cgit v1.2.3