/* variables.c -- Functions for hacking shell variables. */
-/* Copyright (C) 1987-2018 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2022 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
#endif
#include "bashansi.h"
#include "bashintl.h"
+#include "filecntl.h"
#define NEED_XTRACE_SET_DECL
#define BASHFUNC_SUFFIX "%%"
#define BASHFUNC_SUFFLEN 2 /* == strlen(BASHFUNC_SUFFIX) */
+#if ARRAY_EXPORT
+#define BASHARRAY_PREFIX "BASH_ARRAY_"
+#define BASHARRAY_PREFLEN 11
+#define BASHARRAY_SUFFIX "%%"
+#define BASHARRAY_SUFFLEN 2
+
+#define BASHASSOC_PREFIX "BASH_ASSOC_"
+#define BASHASSOC_PREFLEN 11
+#define BASHASSOC_SUFFIX "%%" /* needs to be the same as BASHARRAY_SUFFIX */
+#define BASHASSOC_SUFFLEN 2
+#endif
+
/* flags for find_variable_internal */
#define FV_FORCETEMPENV 0x01
#define FV_SKIPINVISIBLE 0x02
+#define FV_NODYNAMIC 0x04
extern char **environ;
/* Variables used here and defined in other files. */
extern time_t shell_start_time;
+extern struct timeval shellstart;
/* The list of shell variables that the user has created at the global
scope, or that came from the environment. */
"$*", "$1", and all the cruft is kept. */
char *dollar_vars[10];
WORD_LIST *rest_of_args = (WORD_LIST *)NULL;
+int posparam_count = 0;
/* The value of $$. */
pid_t dollar_dollar_pid;
static VAR_CONTEXT *last_context_searched;
/* 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));
+static void create_variable_tables PARAMS((void));
+
+static void set_machine_vars PARAMS((void));
+static void set_home_var PARAMS((void));
+static void set_shell_var PARAMS((void));
+static char *get_bash_name PARAMS((void));
+static void initialize_shell_level PARAMS((void));
+static void uidset PARAMS((void));
#if defined (ARRAY_VARS)
-static void make_vers_array __P((void));
+static void make_vers_array PARAMS((void));
#endif
-static SHELL_VAR *null_assign __P((SHELL_VAR *, char *, arrayind_t, char *));
+static SHELL_VAR *null_assign PARAMS((SHELL_VAR *, char *, arrayind_t, char *));
#if defined (ARRAY_VARS)
-static SHELL_VAR *null_array_assign __P((SHELL_VAR *, char *, arrayind_t, char *));
+static SHELL_VAR *null_array_assign PARAMS((SHELL_VAR *, char *, arrayind_t, char *));
#endif
-static SHELL_VAR *get_self __P((SHELL_VAR *));
+static SHELL_VAR *get_self PARAMS((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));
+static SHELL_VAR *init_dynamic_array_var PARAMS((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int));
+static SHELL_VAR *init_dynamic_assoc_var PARAMS((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 inline SHELL_VAR *set_int_value (SHELL_VAR *, intmax_t, int);
+static inline SHELL_VAR *set_string_value (SHELL_VAR *, const char *, int);
+
+static SHELL_VAR *assign_seconds PARAMS((SHELL_VAR *, char *, arrayind_t, char *));
+static SHELL_VAR *get_seconds PARAMS((SHELL_VAR *));
+static SHELL_VAR *init_seconds_var PARAMS((void));
+
+static SHELL_VAR *assign_random PARAMS((SHELL_VAR *, char *, arrayind_t, char *));
+static SHELL_VAR *get_random PARAMS((SHELL_VAR *));
+
+static SHELL_VAR *get_urandom PARAMS((SHELL_VAR *));
-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 PARAMS((SHELL_VAR *, char *, arrayind_t, char *));
+static SHELL_VAR *get_lineno PARAMS((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 PARAMS((SHELL_VAR *, char *, arrayind_t, char *));
+static SHELL_VAR *get_subshell PARAMS((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_epochseconds PARAMS((SHELL_VAR *));
+static SHELL_VAR *get_epochrealtime PARAMS((SHELL_VAR *));
-static SHELL_VAR *get_epochseconds __P((SHELL_VAR *));
-static SHELL_VAR *get_epochrealtime __P((SHELL_VAR *));
+static SHELL_VAR *get_bashpid PARAMS((SHELL_VAR *));
-static SHELL_VAR *get_bashpid __P((SHELL_VAR *));
+static SHELL_VAR *get_bash_argv0 PARAMS((SHELL_VAR *));
+static SHELL_VAR *assign_bash_argv0 PARAMS((SHELL_VAR *, char *, arrayind_t, char *));
+static void set_argv0 PARAMS((void));
#if defined (HISTORY)
-static SHELL_VAR *get_histcmd __P((SHELL_VAR *));
+static SHELL_VAR *get_histcmd PARAMS((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 *));
+static SHELL_VAR *get_comp_wordbreaks PARAMS((SHELL_VAR *));
+static SHELL_VAR *assign_comp_wordbreaks PARAMS((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 *));
+static SHELL_VAR *assign_dirstack PARAMS((SHELL_VAR *, char *, arrayind_t, char *));
+static SHELL_VAR *get_dirstack PARAMS((SHELL_VAR *));
#endif
#if defined (ARRAY_VARS)
-static SHELL_VAR *get_groupset __P((SHELL_VAR *));
+static SHELL_VAR *get_groupset PARAMS((SHELL_VAR *));
# if defined (DEBUGGER)
-static SHELL_VAR *get_bashargcv __P((SHELL_VAR *));
+static SHELL_VAR *get_bashargcv PARAMS((SHELL_VAR *));
# endif
-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 *));
+static SHELL_VAR *build_hashcmd PARAMS((SHELL_VAR *));
+static SHELL_VAR *get_hashcmd PARAMS((SHELL_VAR *));
+static SHELL_VAR *assign_hashcmd PARAMS((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 *));
+static SHELL_VAR *build_aliasvar PARAMS((SHELL_VAR *));
+static SHELL_VAR *get_aliasvar PARAMS((SHELL_VAR *));
+static SHELL_VAR *assign_aliasvar PARAMS((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 SHELL_VAR *get_funcname PARAMS((SHELL_VAR *));
+static SHELL_VAR *init_funcname_var PARAMS((void));
-static void initialize_dynamic_variables __P((void));
+static void initialize_dynamic_variables PARAMS((void));
-static SHELL_VAR *bind_invalid_envvar __P((const char *, char *, int));
+static SHELL_VAR *bind_invalid_envvar PARAMS((const char *, char *, int));
-static int var_sametype __P((SHELL_VAR *, SHELL_VAR *));
+static int var_sametype PARAMS((SHELL_VAR *, SHELL_VAR *));
-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 SHELL_VAR *hash_lookup PARAMS((const char *, HASH_TABLE *));
+static SHELL_VAR *new_shell_variable PARAMS((const char *));
+static SHELL_VAR *make_new_variable PARAMS((const char *, HASH_TABLE *));
+static SHELL_VAR *bind_variable_internal PARAMS((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 void dispose_variable_value PARAMS((SHELL_VAR *));
+static void free_variable_hash_data PARAMS((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 VARLIST *vlist_alloc PARAMS((int));
+static VARLIST *vlist_realloc PARAMS((VARLIST *, int));
+static void vlist_add PARAMS((VARLIST *, SHELL_VAR *, int));
-static void flatten __P((HASH_TABLE *, sh_var_map_func_t *, VARLIST *, int));
+static void flatten PARAMS((HASH_TABLE *, sh_var_map_func_t *, VARLIST *, int));
-static int qsort_var_comp __P((SHELL_VAR **, SHELL_VAR **));
+static int qsort_var_comp PARAMS((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 SHELL_VAR **vapply PARAMS((sh_var_map_func_t *));
+static SHELL_VAR **fapply PARAMS((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 *));
+static int visible_var PARAMS((SHELL_VAR *));
+static int visible_and_exported PARAMS((SHELL_VAR *));
+static int export_environment_candidate PARAMS((SHELL_VAR *));
+static int local_and_exported PARAMS((SHELL_VAR *));
+static int visible_variable_in_context PARAMS((SHELL_VAR *));
+static int variable_in_context PARAMS((SHELL_VAR *));
#if defined (ARRAY_VARS)
-static int visible_array_vars __P((SHELL_VAR *));
+static int visible_array_vars PARAMS((SHELL_VAR *));
#endif
-static SHELL_VAR *find_variable_internal __P((const char *, int));
+static SHELL_VAR *find_variable_internal PARAMS((const char *, int));
-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 *find_nameref_at_context PARAMS((SHELL_VAR *, VAR_CONTEXT *));
+static SHELL_VAR *find_variable_nameref_context PARAMS((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **));
+static SHELL_VAR *find_variable_last_nameref_context PARAMS((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **));
-static SHELL_VAR *bind_tempenv_variable __P((const char *, char *));
-static void push_posix_temp_var __P((PTR_T));
-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 SHELL_VAR *bind_tempenv_variable PARAMS((const char *, char *));
+static void push_posix_temp_var PARAMS((PTR_T));
+static void push_temp_var PARAMS((PTR_T));
+static void propagate_temp_var PARAMS((PTR_T));
+static void dispose_temporary_env PARAMS((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 inline char *mk_env_string PARAMS((const char *, const char *, int));
+static char **make_env_array_from_var_list PARAMS((SHELL_VAR **));
+static char **make_var_export_array PARAMS((VAR_CONTEXT *));
+static char **make_func_export_array PARAMS((void));
+static void add_temp_array_to_env PARAMS((char **, int, int));
-static int n_shell_variables __P((void));
-static int set_context __P((SHELL_VAR *));
+static int n_shell_variables PARAMS((void));
+static int set_context PARAMS((SHELL_VAR *));
-static void push_func_var __P((PTR_T));
-static void push_builtin_var __P((PTR_T));
-static void push_exported_var __P((PTR_T));
+static void push_func_var PARAMS((PTR_T));
+static void push_builtin_var PARAMS((PTR_T));
+static void push_exported_var PARAMS((PTR_T));
-static inline void push_posix_tempvar_internal __P((SHELL_VAR *, int));
+static void delete_local_contexts PARAMS((VAR_CONTEXT *));
-static inline int find_special_var __P((const char *));
+/* This needs to be looked at again. */
+static inline void push_posix_tempvar_internal PARAMS((SHELL_VAR *, int));
+
+static inline int find_special_var PARAMS((const char *));
static void
create_variable_tables ()
VSETATTR (temp_var, (att_exported | att_imported | att_invisible));
array_needs_making = 1;
}
- last_command_exit_value = 1;
+ last_command_exit_value = EXECUTION_FAILURE;
report_error (_("error importing function definition for `%s'"), tname);
}
#if defined (ARRAY_VARS)
# if ARRAY_EXPORT
/* Array variables may not yet be exported. */
- if (*string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')')
+ if (STREQN (BASHARRAY_PREFIX, name, BASHARRAY_PREFLEN) &&
+ STREQN (BASHARRAY_SUFFIX, name + char_index - BASHARRAY_SUFFLEN, BASHARRAY_SUFFLEN) &&
+ *string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')')
{
+ size_t namelen;
+ char *tname; /* desired imported array variable name */
+
+ namelen = char_index - BASHARRAY_PREFLEN - BASHARRAY_SUFFLEN;
+
+ tname = name + BASHARRAY_PREFLEN; /* start of variable name */
+ tname[namelen] = '\0'; /* now tname == varname */
+
string_length = 1;
temp_string = extract_array_assignment_list (string, &string_length);
- temp_var = assign_array_from_string (name, temp_string, 0);
+ temp_var = assign_array_from_string (tname, temp_string, 0);
+ FREE (temp_string);
+ if (temp_var)
+ {
+ VSETATTR (temp_var, (att_exported | att_imported));
+ array_needs_making = 1;
+ }
+ }
+ else if (STREQN (BASHASSOC_PREFIX, name, BASHASSOC_PREFLEN) &&
+ STREQN (BASHASSOC_SUFFIX, name + char_index - BASHASSOC_SUFFLEN, BASHASSOC_SUFFLEN) &&
+ *string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')')
+ {
+ size_t namelen;
+ char *tname; /* desired imported assoc variable name */
+
+ namelen = char_index - BASHASSOC_PREFLEN - BASHASSOC_SUFFLEN;
+
+ tname = name + BASHASSOC_PREFLEN; /* start of variable name */
+ tname[namelen] = '\0'; /* now tname == varname */
+
+ /* need to make sure it exists as an associative array first */
+ temp_var = find_or_make_array_variable (tname, 2);
+ if (temp_var)
+ {
+ string_length = 1;
+ temp_string = extract_array_assignment_list (string, &string_length);
+ temp_var = assign_array_var_from_string (temp_var, temp_string, 0);
+ }
FREE (temp_string);
- VSETATTR (temp_var, (att_exported | att_imported));
- array_needs_making = 1;
+ if (temp_var)
+ {
+ VSETATTR (temp_var, (att_exported | att_imported));
+ array_needs_making = 1;
+ }
}
else
# endif /* ARRAY_EXPORT */
set_ppid ();
+ set_argv0 ();
+
/* Initialize the `getopts' stuff. */
temp_var = bind_variable ("OPTIND", "1", 0);
VSETATTR (temp_var, att_integer);
}
#endif /* HISTORY */
- /* Seed the random number generator. */
+ /* Seed the random number generators. */
seedrand ();
+ seedrand32 ();
/* Handle some "special" variables that we may have inherited from a
parent shell. */
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 = set_if_not ("BASH_LOADABLES_PATH", DEFAULT_LOADABLE_BUILTINS_PATH);
+
temp_var = find_variable ("BASH_XTRACEFD");
if (temp_var && imported_p (temp_var))
sv_xtracefd (temp_var->name);
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,
+ value for the specified dynamic variable. 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);
}
#endif
+/* Set the string value of VAR to the string representation of VALUE.
+ Right now this takes an INTMAX_T because that's what itos needs. If
+ FLAGS&1, we force the integer attribute on. */
+static inline SHELL_VAR *
+set_int_value (SHELL_VAR *var, intmax_t value, int flags)
+{
+ char *p;
+
+ p = itos (value);
+ FREE (value_cell (var));
+ var_setvalue (var, p);
+ if (flags & 1)
+ VSETATTR (var, att_integer);
+ return (var);
+}
+
+static inline SHELL_VAR *
+set_string_value (SHELL_VAR *var, const char *value, int flags)
+{
+ char *p;
+
+ if (value && *value)
+ p = savestring (value);
+ else
+ {
+ p = (char *)xmalloc (1);
+ p[0] = '\0';
+ }
+ FREE (value_cell (var));
+ var_setvalue (var, p);
+ return (var);
+}
+
/* 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. */
arrayind_t unused;
char *key;
{
- if (legal_number (value, &seconds_value_assigned) == 0)
- seconds_value_assigned = 0;
- shell_start_time = NOW;
- return (self);
+ intmax_t nval;
+ int expok;
+
+ if (integer_p (self))
+ nval = evalexp (value, 0, &expok);
+ else
+ expok = legal_number (value, &nval);
+ seconds_value_assigned = expok ? nval : 0;
+ gettimeofday (&shellstart, NULL);
+ shell_start_time = shellstart.tv_sec;
+ return (set_int_value (self, nval, integer_p (self) != 0));
}
static SHELL_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));
+ struct timeval tv;
- VSETATTR (var, att_integer);
- var_setvalue (var, p);
- return (var);
+ gettimeofday(&tv, NULL);
+ time_since_start = tv.tv_sec - shell_start_time;
+ return (set_int_value (var, seconds_value_assigned + time_since_start, 1));
}
static SHELL_VAR *
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 u_bits32_t rseed = 1;
-static int last_random_value;
-static int seeded_subshell = 0;
-
-#define BASH_RANDOM_16 1
-
-#if BASH_RANDOM_16
-# define BASH_RAND_MAX 32767 /* 0x7fff - 16 bits */
-#else
-# define BASH_RAND_MAX 0x7fffffff /* 32 bits */
-#endif
-
-/* Returns a pseudo-random number between 0 and 32767. */
-static int
-brand ()
-{
- /* Minimal Standard generator 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.
-
- x(n+1) = 16807 * x(n) mod (2**31 - 1).
-
- We split up the calculations to avoid overflow.
-
- h = rseed / q; l = x - h * q; t = a * l - h * r
- m = 2147483647, a = 16807, q = 127773, r = 2836
-
- There are lots of other combinations of constants to use; look at
- https://www.gnu.org/software/gsl/manual/html_node/Other-random-number-generators.html#Other-random-number-generators */
-
- bits32_t h, l, t;
-
- /* Can't seed with 0. */
- if (rseed == 0)
- rseed = 123459876;
- h = rseed / 127773;
- l = rseed - (127773 * h);
- t = 16807 * l - 2836 * h;
- rseed = (t < 0) ? t + 0x7fffffff : t;
-
- return ((unsigned int)(rseed & BASH_RAND_MAX)); /* was % BASH_RAND_MAX+1 */
-}
-/* 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;
- SHELL_VAR *v;
+/* Functions for $RANDOM and $SRANDOM */
- gettimeofday (&tv, NULL);
-#if 0
- v = find_variable ("BASH_VERSION");
- sbrand (tv.tv_sec ^ tv.tv_usec ^ getpid () ^ ((u_bits32_t)&v & 0x7fffffff));
-#else
- sbrand (tv.tv_sec ^ tv.tv_usec ^ getpid ());
-#endif
-}
+int last_random_value;
+static int seeded_subshell = 0;
static SHELL_VAR *
assign_random (self, value, unused, key)
arrayind_t unused;
char *key;
{
- sbrand (strtoul (value, (char **)NULL, 10));
+ intmax_t seedval;
+ int expok;
+
+ if (integer_p (self))
+ seedval = evalexp (value, 0, &expok);
+ else
+ expok = legal_number (value, &seedval);
+ if (expok == 0)
+ return (self);
+ sbrand (seedval);
if (subshell_environment)
seeded_subshell = getpid ();
- return (self);
+ return (set_int_value (self, seedval, integer_p (self) != 0));
}
int
do
rv = brand ();
while (rv == last_random_value);
- return rv;
+
+ return (last_random_value = rv);
}
static SHELL_VAR *
SHELL_VAR *var;
{
int rv;
- char *p;
rv = get_random_number ();
- last_random_value = rv;
- p = itos (rv);
+ return (set_int_value (var, rv, 1));
+}
- FREE (value_cell (var));
+static SHELL_VAR *
+get_urandom (var)
+ SHELL_VAR *var;
+{
+ u_bits32_t rv;
- VSETATTR (var, att_integer);
- var_setvalue (var, p);
- return (var);
+ rv = get_urandom32 ();
+ return (set_int_value (var, rv, 1));
}
static SHELL_VAR *
if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0)
new_value = 0;
line_number = line_number_base = new_value;
- return var;
+ return (set_int_value (var, line_number, integer_p (var) != 0));
}
/* Function which returns the current line number. */
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);
+ return (set_int_value (var, ln, 0));
}
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);
+ return (set_int_value (var, subshell_level, 0));
}
static SHELL_VAR *
SHELL_VAR *var;
{
intmax_t now;
- char *p;
now = NOW;
- p = itos (now);
-
- FREE (value_cell (var));
- var_setvalue (var, p);
- return (var);
+ return (set_int_value (var, now, 0));
}
static SHELL_VAR *
SHELL_VAR *var;
{
char buf[32];
- char *p;
struct timeval tv;
gettimeofday (&tv, NULL);
locale_decpoint (),
(unsigned)tv.tv_usec);
- p = savestring (buf);
- FREE (value_cell (var));
- var_setvalue (var, p);
- return (var);
+ return (set_string_value (var, buf, 0));
}
static SHELL_VAR *
SHELL_VAR *var;
{
int pid;
- char *p;
pid = getpid ();
- p = itos (pid);
-
- FREE (value_cell (var));
- VSETATTR (var, att_integer); /* XXX - was also att_readonly */
- var_setvalue (var, p);
- return (var);
+ return (set_int_value (var, pid, 1));
}
static SHELL_VAR *
get_bash_argv0 (var)
SHELL_VAR *var;
{
- char *p;
-
- p = savestring (dollar_vars[0]);
- FREE (value_cell (var));
- var_setvalue (var, p);
- return var;
+ return (set_string_value (var, dollar_vars[0], 0));
}
static char *static_shell_name = 0;
shell_name = static_shell_name;
return var;
}
+
+static void
+set_argv0 ()
+{
+ SHELL_VAR *v;
+
+ v = find_variable ("BASH_ARGV0");
+ if (v && imported_p (v))
+ assign_bash_argv0 (v, value_cell (v), 0, 0);
+}
static SHELL_VAR *
get_bash_command (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);
+ p = the_printed_command_except_trap ? the_printed_command_except_trap : "";
+ return (set_string_value (var, p, 0));
}
#if defined (HISTORY)
get_histcmd (var)
SHELL_VAR *var;
{
- char *p;
+ int n;
- p = itos (history_number ());
- FREE (value_cell (var));
- var_setvalue (var, p);
- return (var);
+ /* Do the same adjustment here we do in parse.y:prompt_history_number,
+ assuming that we are in one of two states: decoding this as part of
+ the prompt string, in which case we do not want to assume that the
+ command has been saved to the history and the history number incremented,
+ or the expansion is part of the current command being executed and has
+ already been saved to history and the history number incremented.
+ Right now we use EXECUTING as the determinant. */
+ n = history_number () - executing;
+ return (set_int_value (var, n, 0));
}
#endif
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);
+ return (set_string_value (var, rl_completer_word_break_characters, 0));
}
/* When this function returns, rl_completer_word_break_characters points to
{
if (rl_completer_word_break_characters &&
rl_completer_word_break_characters != rl_basic_word_break_characters)
- free (rl_completer_word_break_characters);
+ free ((void *)rl_completer_word_break_characters);
rl_completer_word_break_characters = savestring (value);
return 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);
- }
+ return (set_string_value (self, this_shell_function->name, 0));
#endif
return (self);
}
INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random);
VSETATTR (v, att_integer);
+ INIT_DYNAMIC_VAR ("SRANDOM", (char *)NULL, get_urandom, (sh_var_assign_func_t *)NULL);
+ VSETATTR (v, att_integer);
INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno);
- VSETATTR (v, att_integer|att_regenerate);
+ VSETATTR (v, att_regenerate);
INIT_DYNAMIC_VAR ("BASHPID", (char *)NULL, get_bashpid, null_assign);
VSETATTR (v, att_integer);
/* */
/* **************************************************************** */
+#if 0 /* not yet */
+int
+var_isset (var)
+ SHELL_VAR *var;
+{
+ return (var->value != 0);
+}
+
+int
+var_isunset (var)
+ SHELL_VAR *var;
+{
+ return (var->value == 0);
+}
+#endif
+
/* 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). */
{
v = find_variable_last_nameref (name, 1);
/* If we're making local variables, only follow namerefs that point to
- non-existant variables at the same variable context. */
+ non-existent variables at the same variable context. */
if (v && v->context != variable_context)
v = 0;
}
var = var_lookup (name, global_variables);
if (var && nameref_p (var))
- var = find_variable_nameref (var);
+ var = find_variable_nameref (var); /* XXX - find_global_variable_noref? */
if (var == 0)
return ((SHELL_VAR *)NULL);
/* 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, but doesn't
- leak in practice. Since functions and variables have separate name
+ leak in practice. Since functions and variables have separate name
spaces, returns NULL if var_name is a shell function only. */
char *
get_string_value (var_name)
if (was_tmpvar && old_var->context == variable_context && last_table_searched != temporary_env)
{
VUNSETATTR (old_var, att_invisible); /* XXX */
-#if 0 /* TAG:bash-5.1 */
/* We still want to flag this variable as local, though, and set things
up so that it gets treated as a local variable. */
new_var = old_var;
if (vc_isfuncenv (vc) && vc->scope == variable_context)
break;
goto set_local_var_flags;
-#endif
+
return (old_var);
}
/* value_cell will be 0 if localvar_inherit == 0 or there was no old variable
with the same name or the old variable was invisible */
- if (was_tmpvar == 0 && no_invisible_vars == 0 && value_cell (new_var) == 0)
+ if (was_tmpvar == 0 && value_cell (new_var) == 0)
VSETATTR (new_var, att_invisible); /* XXX */
return (new_var);
}
}
SHELL_VAR *
-make_local_array_variable (name, assoc_ok)
+make_local_array_variable (name, flags)
char *name;
- int assoc_ok;
+ int flags;
{
SHELL_VAR *var;
ARRAY *array;
+ int assoc_ok;
- var = make_local_variable (name, 0); /* XXX for now */
+ assoc_ok = flags & MKLOC_ASSOCOK;
+
+ var = make_local_variable (name, flags & MKLOC_INHERIT); /* XXX for now */
/* If ASSOC_OK is non-zero, assume that we are ok with letting an assoc
variable return to the caller without converting it. The caller will
either flag an error or do the conversion itself. */
return var;
/* Validate any value we inherited from a variable instance at a previous
- scope and disard anything that's invalid. */
+ scope and discard anything that's invalid. */
if (localvar_inherit && assoc_p (var))
{
- internal_warning ("%s: cannot inherit value from incompatible type", name);
+ internal_warning (_("%s: cannot inherit value from incompatible type"), name);
VUNSETATTR (var, att_assoc);
dispose_variable_value (var);
array = array_create ();
HASH_TABLE *hash;
entry = make_new_variable (name, global_variables->table);
- hash = assoc_create (0);
+ hash = assoc_create (ASSOC_HASH_BUCKETS);
var_setassoc (entry, hash);
VSETATTR (entry, att_assoc);
}
SHELL_VAR *
-make_local_assoc_variable (name, array_ok)
+make_local_assoc_variable (name, flags)
char *name;
- int array_ok;
+ int flags;
{
SHELL_VAR *var;
HASH_TABLE *hash;
+ int array_ok;
+
+ array_ok = flags & MKLOC_ARRAYOK;
- var = make_local_variable (name, 0); /* XXX for now */
+ var = make_local_variable (name, flags & MKLOC_INHERIT); /* XXX for now */
/* If ARRAY_OK is non-zero, assume that we are ok with letting an array
variable return to the caller without converting it. The caller will
either flag an error or do the conversion itself. */
return var;
/* Validate any value we inherited from a variable instance at a previous
- scope and disard anything that's invalid. */
+ scope and discard anything that's invalid. */
if (localvar_inherit && array_p (var))
{
- internal_warning ("%s: cannot inherit value from incompatible type", name);
+ internal_warning (_("%s: cannot inherit value from incompatible type"), name);
VUNSETATTR (var, att_array);
dispose_variable_value (var);
- hash = assoc_create (0);
+ hash = assoc_create (ASSOC_HASH_BUCKETS);
var_setassoc (var, hash);
}
else if (localvar_inherit)
else
{
dispose_variable_value (var);
- hash = assoc_create (0);
+ hash = assoc_create (ASSOC_HASH_BUCKETS);
var_setassoc (var, hash);
}
VUNSETATTR (tentry, att_nameref);
}
free (tname);
- /* XXX - should it be aflags? */
- entry = assign_array_element (newval, make_variable_value (entry, value, aflags), aflags|ASS_NAMEREF);
+
+ /* entry == nameref variable; tentry == array variable;
+ newval == x[2]; value = bar
+ We don't need to call make_variable_value here, since
+ assign_array_element will eventually do it itself based on
+ newval and aflags. */
+
+ entry = assign_array_element (newval, value, aflags|ASS_NAMEREF, (array_eltstate_t *)0);
if (entry == 0)
return entry;
}
}
else if (entry->assign_func) /* array vars have assign functions now */
{
+ if ((readonly_p (entry) && (aflags & ASS_FORCE) == 0) || noassign_p (entry))
+ {
+ if (readonly_p (entry))
+ err_readonly (name_cell (entry));
+ return (entry);
+ }
+
INVALIDATE_EXPORTSTR (entry);
newval = (aflags & ASS_APPEND) ? make_variable_value (entry, value, aflags) : value;
if (assoc_p (entry))
return (bind_variable_internal (nv->name, value, nvc->table, 0, flags));
#if defined (ARRAY_VARS)
else if (valid_array_reference (nameref_cell (nv), 0))
- return (assign_array_element (nameref_cell (nv), value, flags));
+ return (assign_array_element (nameref_cell (nv), value, flags, (array_eltstate_t *)0));
else
#endif
return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags));
else if (nv == &nameref_maxloop_value)
{
internal_warning (_("%s: circular name reference"), v->name);
-#if 1
- /* TAG:bash-5.1 */
return (bind_global_variable (v->name, value, flags));
-#else
- v = 0; /* backwards compat */
-#endif
}
else
v = nv;
else if (nv == &nameref_maxloop_value)
{
internal_warning (_("%s: circular name reference"), v->name);
-#if 1
- /* TAG:bash-5.1 */
return (bind_global_variable (v->name, value, flags));
-#else
- v = 0; /* backwards compat */
-#endif
}
else
v = nv;
int flags;
{
register SHELL_VAR *v;
- int isint, isarr, implicitarray;
+ int isint, isarr, implicitarray, vflags, avflags;
isint = isarr = implicitarray = 0;
#if defined (ARRAY_VARS)
- if (valid_array_reference (lhs, (flags & ASS_NOEXPAND) != 0))
+ /* Don't rely on VA_NOEXPAND being 1, set it explicitly */
+ vflags = (flags & ASS_NOEXPAND) ? VA_NOEXPAND : 0;
+ if (flags & ASS_ONEWORD)
+ vflags |= VA_ONEWORD;
+ if (valid_array_reference (lhs, vflags))
{
isarr = 1;
- v = array_variable_part (lhs, (flags & ASS_NOEXPAND) != 0, (char **)0, (int *)0);
+ avflags = 0;
+ /* Common code to translate between assignment and reference flags. */
+ if (flags & ASS_NOEXPAND)
+ avflags |= AV_NOEXPAND;
+ if (flags & ASS_ONEWORD)
+ avflags |= AV_ONEWORD;
+ v = array_variable_part (lhs, avflags, (char **)0, (int *)0);
}
else if (legal_identifier (lhs) == 0)
{
#if defined (ARRAY_VARS)
if (isarr)
- v = assign_array_element (lhs, rhs, flags);
+ v = assign_array_element (lhs, rhs, flags, (array_eltstate_t *)0);
else if (implicitarray)
v = bind_array_variable (lhs, 0, rhs, 0); /* XXX - check on flags */
else
}
SHELL_VAR *
-bind_var_to_int (var, val)
+bind_var_to_int (var, val, flags)
char *var;
intmax_t val;
+ int flags;
{
char ibuf[INT_STRLEN_BOUND (intmax_t) + 1], *p;
p = fmtulong (val, 10, ibuf, sizeof (ibuf), 0);
- return (bind_int_variable (var, p, 0));
+ return (bind_int_variable (var, p, flags));
}
/* Do a function binding to a variable. You pass the name and
if (legal_identifier (name) == 0)
{
sh_invalidid (name);
+ free (name);
return (0);
}
array_needs_making = 1;
if (flags)
- stupidly_hack_special_variables (newname);
+ {
+ if (STREQ (newname, "POSIXLY_CORRECT") || STREQ (newname, "POSIX_PEDANDTIC"))
+ save_posix_options (); /* XXX one level of saving right now */
+ stupidly_hack_special_variables (newname);
+ }
if (echo_command_at_execute)
/* The Korn shell prints the `+ ' in front of assignment statements,
return 0;
}
+int
+unbind_global_variable (name)
+ const char *name;
+{
+ SHELL_VAR *v, *nv;
+ int r;
+
+ v = var_lookup (name, global_variables);
+ /* This starts at the current scope, just like find_global_variable; should we
+ use find_global_variable_nameref here? */
+ nv = (v && nameref_p (v)) ? find_variable_nameref (v) : (SHELL_VAR *)NULL;
+
+ r = nv ? makunbound (nv->name, shell_variables) : makunbound (name, global_variables);
+ return r;
+}
+
+int
+unbind_global_variable_noref (name)
+ const char *name;
+{
+ SHELL_VAR *v;
+
+ v = var_lookup (name, global_variables);
+ if (v)
+ return makunbound (name, global_variables);
+ return 0;
+}
+
int
check_unbind_variable (name)
const char *name;
if (v && readonly_p (v))
{
internal_error (_("%s: cannot unset: readonly %s"), name, "variable");
- return -1;
+ return -2;
+ }
+ else if (v && non_unsettable_p (v))
+ {
+ internal_error (_("%s: cannot unset"), name);
+ return -2;
}
return (unbind_variable (name));
}
if (!entry) \
{ \
entry = bind_variable (name, "", 0); \
- if (!no_invisible_vars && entry) entry->attributes |= att_invisible; \
+ if (entry) entry->attributes |= att_invisible; \
} \
} \
while (0)
static int
variable_in_context (var)
SHELL_VAR *var;
+{
+ return (local_p (var) && var->context == variable_context);
+}
+
+static int
+visible_variable_in_context (var)
+ SHELL_VAR *var;
{
return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context);
}
SHELL_VAR **
-all_local_variables ()
+all_local_variables (visible_only)
+ int visible_only;
{
VARLIST *vlist;
SHELL_VAR **ret;
vlist = vlist_alloc (HASH_ENTRIES (vc->table));
- flatten (vc->table, variable_in_context, vlist, 0);
+ if (visible_only)
+ flatten (vc->table, visible_variable_in_context, vlist, 0);
+ else
+ flatten (vc->table, variable_in_context, vlist, 0);
ret = vlist->list;
free (vlist);
int tvlist_ind;
/* Take a variable from an assignment statement preceding a posix special
- builtin (including `return') and create a variable from it as if a
- standalone assignment statement had been performed. This is called from
- merge_temporary_env, which is only called when in posix mode. */
+ builtin (including `return') and create a global variable from it. This
+ is called from merge_temporary_env, which is only called when in posix
+ mode. */
static void
push_posix_temp_var (data)
PTR_T data;
"current execution environment." */
v = bind_variable (var->name, value_cell (var), ASS_FORCE|ASS_NOLONGJMP);
+ /* XXX - do we need to worry about array variables here? */
+
/* If this modifies an existing local variable, v->context will be non-zero.
If it comes back with v->context == 0, we bound at the global context.
Set binding_table appropriately. It doesn't matter whether it's correct
binding_table = v->context ? shell_variables->table : global_variables->table;
/* global variables are no longer temporary and don't need propagating. */
- if (binding_table == global_variables->table)
+ if (v->context == 0)
var->attributes &= ~(att_tempvar|att_propagate);
if (v)
{
- v->attributes |= var->attributes;
- v->attributes &= ~att_tempvar; /* not a temp var now */
+ v->attributes |= var->attributes; /* preserve tempvar attribute if appropriate */
+ /* If we don't bind a local variable, propagate the value. If we bind a
+ local variable (the "current execution environment"), keep it as local
+ and don't propagate it to the calling environment. */
+ if (v->context > 0 && local_p (v) == 0)
+ v->attributes |= att_propagate;
+ else
+ v->attributes &= ~att_propagate;
}
if (find_special_var (var->name) >= 0)
var->attributes &= ~(att_tempvar|att_propagate);
else
{
- var->attributes |= att_propagate;
+ var->attributes |= att_propagate; /* XXX - propagate more than once? */
if (binding_table == shell_variables->table)
shell_variables->flags |= VC_HASTMPVAR;
}
dispose_temporary_env (posixly_correct ? push_posix_temp_var : push_temp_var);
}
+/* Temporary function to use if we want to separate function and special
+ builtin behavior. */
+void
+merge_function_temporary_env ()
+{
+ if (temporary_env)
+ dispose_temporary_env (push_temp_var);
+}
+
void
flush_temporary_env ()
{
/* **************************************************************** */
static inline char *
-mk_env_string (name, value, isfunc)
+mk_env_string (name, value, attributes)
const char *name, *value;
- int isfunc;
+ int attributes;
{
size_t name_len, value_len;
char *p, *q, *t;
+ int isfunc, isarray;
name_len = strlen (name);
value_len = STRLEN (value);
+ isfunc = attributes & att_function;
+#if defined (ARRAY_VARS) && defined (ARRAY_EXPORT)
+ isarray = attributes & (att_array|att_assoc);
+#endif
+
/* If we are exporting a shell function, construct the encoded function
name. */
if (isfunc && value)
memcpy (q, BASHFUNC_SUFFIX, BASHFUNC_SUFFLEN);
q += BASHFUNC_SUFFLEN;
}
+#if defined (ARRAY_VARS) && defined (ARRAY_EXPORT)
+ else if (isarray && value)
+ {
+ if (attributes & att_assoc)
+ p = (char *)xmalloc (BASHASSOC_PREFLEN + name_len + BASHASSOC_SUFFLEN + value_len + 2);
+ else
+ p = (char *)xmalloc (BASHARRAY_PREFLEN + name_len + BASHARRAY_SUFFLEN + value_len + 2);
+ q = p;
+ if (attributes & att_assoc)
+ {
+ memcpy (q, BASHASSOC_PREFIX, BASHASSOC_PREFLEN);
+ q += BASHASSOC_PREFLEN;
+ }
+ else
+ {
+ memcpy (q, BASHARRAY_PREFIX, BASHARRAY_PREFLEN);
+ q += BASHARRAY_PREFLEN;
+ }
+ memcpy (q, name, name_len);
+ q += name_len;
+ /* These are actually the same currently */
+ if (attributes & att_assoc)
+ {
+ memcpy (q, BASHASSOC_SUFFIX, BASHASSOC_SUFFLEN);
+ q += BASHARRAY_SUFFLEN;
+ }
+ else
+ {
+ memcpy (q, BASHARRAY_SUFFIX, BASHARRAY_SUFFLEN);
+ q += BASHARRAY_SUFFLEN;
+ }
+ }
+#endif
else
{
p = (char *)xmalloc (2 + name_len + value_len);
}
#endif
+#if defined (ARRAY_VARS)
+# define USE_EXPORTSTR (value == var->exportstr && array_p (var) == 0 && assoc_p (var) == 0)
+#else
+# define USE_EXPORTSTR (value == var->exportstr)
+#endif
+
static char **
make_env_array_from_var_list (vars)
SHELL_VAR **vars;
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__)
continue; /* XXX array vars cannot yet be exported */
# endif /* ARRAY_EXPORT */
else if (assoc_p (var))
-# if 0
+# if ARRAY_EXPORT
value = assoc_to_assign (assoc_cell (var), 0);
# else
continue; /* XXX associative array vars cannot yet be exported */
-# endif
+# endif /* ARRAY_EXPORT */
#endif
else
value = value_cell (var);
/* 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));
+ : mk_env_string (var->name, value, var->attributes);
if (USE_EXPORTSTR == 0)
SAVE_EXPORTSTR (var, list[list_index]);
list_index++;
#undef USE_EXPORTSTR
-#if 0 /* not yet */
-#if defined (ARRAY_VARS)
+#if defined (ARRAY_VARS) && defined (ARRAY_EXPORT)
if (array_p (var) || assoc_p (var))
free (value);
-#endif
#endif
}
}
export_env[export_env_index] = (char *)NULL; \
} while (0)
-/* Add ASSIGN to EXPORT_ENV, or supercede a previous assignment in the
+/* Add ASSIGN to EXPORT_ENV, or supersede 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)
functions no longer behave like assignment statements preceding
special builtins, and do not persist in the current shell environment.
This is austin group interp #654, though nobody implements it yet. */
-#if 0 /* XXX - TAG: bash-5.1 */
posix_func_behavior = 0;
-#else
- posix_func_behavior = posixly_correct;
-#endif
vc = new_var_context (name, flags);
/* Posix interp 1009, temporary assignments preceding function calls modify
vc->table = tempvars;
/* Have to do this because the temp environment was created before
variable_context was incremented. */
+ /* XXX - only need to do it if flags&VC_FUNCENV */
flatten (tempvars, set_context, (VARLIST *)NULL, 0);
vc->flags |= VC_HASTMPVAR;
}
/* This can be called from one of two code paths:
1. pop_scope, which implements the posix rules for propagating variable
assignments preceding special builtins to the surrounding scope
- (push_builtin_var);
+ (push_builtin_var -- isbltin == 1);
2. pop_var_context, which is called from pop_context and implements the
posix rules for propagating variable assignments preceding function
- calls to the surrounding scope (push_func_var).
+ calls to the surrounding scope (push_func_var -- isbltin == 0)
It takes variables out of a temporary environment hash table. We take the
variable in data.
functions no longer behave like assignment statements preceding
special builtins, and do not persist in the current shell environment.
This is austin group interp #654, though nobody implements it yet. */
-#if 0 /* XXX - TAG: bash-5.1 */
posix_var_behavior = posixly_correct && isbltin;
-#else
- posix_var_behavior = posixly_correct;
-#endif
+ v = 0;
if (local_p (var) && STREQ (var->name, "-"))
- set_current_options (value_cell (var));
- else if (tempvar_p (var) && (posix_var_behavior || (var->attributes & att_propagate)))
+ {
+ set_current_options (value_cell (var));
+ set_shellopts ();
+ }
+ /* This takes variable assignments preceding special builtins that can execute
+ multiple commands (source, eval, etc.) and performs the equivalent of
+ an assignment statement to modify the closest enclosing variable (the
+ posix "current execution environment"). This makes the behavior the same
+ as push_posix_temp_var; but the circumstances of calling are slightly
+ different. */
+ else if (tempvar_p (var) && posix_var_behavior)
+ {
+ /* similar to push_posix_temp_var */
+ v = bind_variable (var->name, value_cell (var), ASS_FORCE|ASS_NOLONGJMP);
+ if (v)
+ {
+ v->attributes |= var->attributes;
+ if (v->context == 0)
+ v->attributes &= ~(att_tempvar|att_propagate);
+ /* XXX - set att_propagate here if v->context > 0? */
+ }
+ }
+ else if (tempvar_p (var) && propagate_p (var))
{
/* 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
/* XXX - should we set v->context here? */
if (v)
v->context = shell_variables->scope;
-#if defined (ARRAY_VARS)
- if (v && (array_p (var) || assoc_p (var)))
- {
- FREE (value_cell (v));
- if (array_p (var))
- var_setarray (v, array_copy (array_cell (var)));
- else
- var_setassoc (v, assoc_copy (assoc_cell (var)));
- }
-#endif
if (shell_variables == global_variables)
var->attributes &= ~(att_tempvar|att_propagate);
else
else
stupidly_hack_special_variables (var->name); /* XXX */
+#if defined (ARRAY_VARS)
+ if (v && (array_p (var) || assoc_p (var)))
+ {
+ FREE (value_cell (v));
+ if (array_p (var))
+ var_setarray (v, array_copy (array_cell (var)));
+ else
+ var_setassoc (v, assoc_copy (assoc_cell (var)));
+ }
+#endif
+
dispose_variable (var);
}
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)
+static void
+delete_local_contexts (vcxt)
VAR_CONTEXT *vcxt;
{
VAR_CONTEXT *v, *t;
{
t = v->down;
dispose_var_context (v);
- }
+ }
+}
+/* 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;
+{
+ delete_local_contexts (vcxt);
delete_all_variables (global_variables->table);
shell_variables = global_variables;
}
+/* Reset the context so we are not executing in a shell function. Only call
+ this if you are getting ready to exit the shell. */
+void
+reset_local_contexts ()
+{
+ delete_local_contexts (shell_variables);
+ shell_variables = global_variables;
+ variable_context = 0;
+}
+
/* **************************************************************** */
/* */
/* Pushing and Popping temporary variable scopes */
struct saved_dollar_vars {
char **first_ten;
WORD_LIST *rest;
+ int count;
};
static struct saved_dollar_vars *dollar_arg_stack = (struct saved_dollar_vars *)NULL;
FREE (args[i]);
}
+/* Do what remember_args (xxx, 1) would have done. */
+void
+clear_dollar_vars ()
+{
+ free_dollar_vars ();
+ dispose_words (rest_of_args);
+
+ rest_of_args = (WORD_LIST *)NULL;
+ posparam_count = 0;
+}
+
/* XXX - should always be followed by remember_args () */
void
push_context (name, is_subshell, tempvars)
xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10)
* sizeof (struct saved_dollar_vars));
}
-
+
+ dollar_arg_stack[dollar_arg_stack_index].count = posparam_count;
dollar_arg_stack[dollar_arg_stack_index].first_ten = save_dollar_vars ();
dollar_arg_stack[dollar_arg_stack_index++].rest = rest_of_args;
rest_of_args = (WORD_LIST *)NULL;
+ posparam_count = 0;
dollar_arg_stack[dollar_arg_stack_index].first_ten = (char **)NULL;
dollar_arg_stack[dollar_arg_stack_index].rest = (WORD_LIST *)NULL;
if (dollar_arg_stack == 0 || dollar_arg_stack_index == 0)
return;
- /* Do what remember_args (xxx, 1) would have done. */
- free_dollar_vars ();
- dispose_words (rest_of_args);
-
+ /* Wipe out current values */
+ clear_dollar_vars ();
+
rest_of_args = dollar_arg_stack[--dollar_arg_stack_index].rest;
restore_dollar_vars (dollar_arg_stack[dollar_arg_stack_index].first_ten);
free (dollar_arg_stack[dollar_arg_stack_index].first_ten);
+ posparam_count = dollar_arg_stack[dollar_arg_stack_index].count;
dollar_arg_stack[dollar_arg_stack_index].first_ten = (char **)NULL;
dollar_arg_stack[dollar_arg_stack_index].rest = (WORD_LIST *)NULL;
-
+ dollar_arg_stack[dollar_arg_stack_index].count = 0;
+
set_dollar_vars_unchanged ();
invalidate_cached_quoted_dollar_at ();
}
dollar_arg_stack[dollar_arg_stack_index].first_ten = (char **)NULL;
dollar_arg_stack[dollar_arg_stack_index].rest = (WORD_LIST *)NULL;
+ dollar_arg_stack[dollar_arg_stack_index].count = 0;
}
/* Initialize BASH_ARGV and BASH_ARGC after turning on extdebug after the
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);
+ ce = array_unshift_element (bash_argc_a);
if (ce == 0 || legal_number (element_value (ce), &i) == 0)
i = 0;
sv_tz (name)
char *name;
{
- if (chkexport (name))
- tzset ();
+ SHELL_VAR *v;
+
+ v = find_variable (name);
+ if (v && exported_p (v))
+ array_needs_making = 1;
+ else if (v == 0)
+ array_needs_making = 1;
+
+ if (array_needs_making)
+ {
+ maybe_make_export_env ();
+ tzset ();
+ }
}
#endif
#if 1
if (r == 0 && posixly_correct)
- last_command_exit_value = 1;
+ set_exit_status (EXECUTION_FAILURE);
#endif
}
/* Fast case */
if (array_num_elements (a) == nproc && nproc == 1)
{
+#ifndef ALT_ARRAY_IMPLEMENTATION
ae = element_forw (a->head);
- free (element_value (ae));
- set_element_value (ae, itos (ps[0]));
+#else
+ ae = a->elements[0];
+#endif
+ ARRAY_ELEMENT_REPLACE (ae, itos (ps[0]));
}
else if (array_num_elements (a) <= nproc)
{
/* modify in array_num_elements members in place, then add */
+#ifndef ALT_ARRAY_IMPLEMENTATION
ae = a->head;
+#endif
for (i = 0; i < array_num_elements (a); i++)
{
+#ifndef ALT_ARRAY_IMPLEMENTATION
ae = element_forw (ae);
- free (element_value (ae));
- set_element_value (ae, itos (ps[i]));
+#else
+ ae = a->elements[i];
+#endif
+ ARRAY_ELEMENT_REPLACE (ae, itos (ps[i]));
}
/* add any more */
for ( ; i < nproc; i++)
}
else
{
+#ifndef ALT_ARRAY_IMPLEMENTATION
/* deleting elements. it's faster to rebuild the array. */
array_flush (a);
- for (i = 0; ps[i] != -1; i++)
+ for (i = 0; i < nproc; i++)
{
t = inttostr (ps[i], tbuf, sizeof (tbuf));
array_insert (a, i, t);
}
+#else
+ /* deleting elements. replace the first NPROC, free the rest */
+ for (i = 0; i < nproc; i++)
+ {
+ ae = a->elements[i];
+ ARRAY_ELEMENT_REPLACE (ae, itos (ps[i]));
+ }
+ for ( ; i <= array_max_index (a); i++)
+ {
+ array_dispose_element (a->elements[i]);
+ a->elements[i] = (ARRAY_ELEMENT *)NULL;
+ }
+
+ /* bookkeeping usually taken care of by array_insert */
+ set_max_index (a, nproc - 1);
+ set_first_index (a, 0);
+ set_num_elements (a, nproc);
+#endif /* ALT_ARRAY_IMPLEMENTATION */
}
}