commit bash-20080626 snapshot

This commit is contained in:
Chet Ramey
2011-12-07 09:25:06 -05:00
parent e33f22038c
commit fdf670eaa1
48 changed files with 4104 additions and 1876 deletions
+328 -80
View File
@@ -1,6 +1,6 @@
/* variables.c -- Functions for hacking shell variables. */
/* Copyright (C) 1987-2007 Free Software Foundation, Inc.
/* Copyright (C) 1987-2008 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -50,6 +50,7 @@
#include "input.h"
#include "hashcmd.h"
#include "pathexp.h"
#include "alias.h"
#include "builtins/getopt.h"
#include "builtins/common.h"
@@ -169,30 +170,31 @@ 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 void seedrand __P((void)); /* seed generator randomly */
static SHELL_VAR *assign_random __P((SHELL_VAR *, char *, arrayind_t));
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 *));
@@ -201,13 +203,25 @@ static SHELL_VAR *get_bashpid __P((SHELL_VAR *));
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 *));
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
static SHELL_VAR *get_funcname __P((SHELL_VAR *));
@@ -220,6 +234,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));
@@ -941,6 +956,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
{
@@ -1052,21 +1069,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);
}
@@ -1101,8 +1129,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
@@ -1110,10 +1155,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;
@@ -1205,10 +1251,11 @@ seedrand ()
}
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)
@@ -1254,10 +1301,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;
@@ -1283,10 +1331,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;
@@ -1329,7 +1378,7 @@ get_bash_command (var)
SHELL_VAR *var;
{
char *p;
if (the_printed_command_except_trap)
p = savestring (the_printed_command_except_trap);
else
@@ -1366,7 +1415,6 @@ get_comp_wordbreaks (var)
if (rl_completer_word_break_characters == 0 && bash_readline_initialized == 0)
enable_hostname_completion (perform_hostname_completion);
itrace("get: rl_completer_word_break_characters = `%s'", rl_completer_word_break_characters);
var_setvalue (var, rl_completer_word_break_characters);
return (var);
@@ -1375,27 +1423,28 @@ itrace("get: rl_completer_word_break_characters = `%s'", rl_completer_word_break
/* 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)
free (rl_completer_word_break_characters);
rl_completer_word_break_characters = savestring (value);
itrace("assign: rl_completer_word_break_characters = `%s'", rl_completer_word_break_characters);
return self;
}
#endif /* READLINE */
#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;
@@ -1438,6 +1487,112 @@ 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));
}
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 /* ARRAY_VARS */
/* If ARRAY_VARS is not defined, this just returns the name of any
@@ -1531,6 +1686,9 @@ 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);
v = init_dynamic_assoc_var ("BASH_ALIASES", get_aliasvar, assign_aliasvar, att_nofree);
#endif
v = init_funcname_var ();
@@ -1577,7 +1735,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 *
@@ -1650,6 +1808,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));
@@ -1759,7 +1919,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;
}
@@ -1775,27 +1935,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)
@@ -1854,10 +1993,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 *
@@ -1868,7 +2061,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
@@ -1897,6 +2090,34 @@ make_variable_value (var, value, flags)
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);
}
#endif /* CASEMOD_ATTRS */
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;
}
else if (value)
{
if (flags & ASS_APPEND)
@@ -1947,9 +2168,9 @@ 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);
entry = (*(entry->assign_func)) (entry, newval, -1, 0);
if (newval != value)
free (newval);
free (newval);
return (entry);
}
else
@@ -1979,6 +2200,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), "0", newval);
free (newval);
}
else
#endif
{
@@ -2024,11 +2250,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));
}
@@ -2053,7 +2279,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);
}
@@ -2311,7 +2537,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)));
@@ -2336,6 +2564,22 @@ copy_variable (var)
/* **************************************************************** */
/* 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
FREE (value_cell (var));
}
void
dispose_variable (var)
SHELL_VAR *var;
@@ -2343,14 +2587,8 @@ dispose_variable (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));
#endif
else
FREE (value_cell (var));
if (nofree_p (var) == 0)
dispose_variable_value (var);
FREE_EXPORTSTR (var);
@@ -2459,15 +2697,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);
@@ -3030,7 +3272,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;
@@ -3142,6 +3384,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
@@ -3162,7 +3410,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
@@ -3316,7 +3564,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
@@ -3333,24 +3581,24 @@ 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. */
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. */
@@ -3517,7 +3765,7 @@ 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
@@ -3564,7 +3812,7 @@ delete_all_contexts (vcxt)
{
t = v->down;
dispose_var_context (v);
}
}
delete_all_variables (global_variables->table);
shell_variables = global_variables;
@@ -3900,7 +4148,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;
}