bash-4.4 beta2 release

This commit is contained in:
Chet Ramey
2016-07-11 16:52:30 -04:00
parent 690150f9e5
commit a4eef1991c
205 changed files with 21194 additions and 15639 deletions
+234 -41
View File
@@ -1,6 +1,6 @@
/* variables.c -- Functions for hacking shell variables. */
/* Copyright (C) 1987-2015 Free Software Foundation, Inc.
/* Copyright (C) 1987-2016 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -83,8 +83,6 @@
#define FUNCTIONS_HASH_BUCKETS 512
#define TEMPENV_HASH_BUCKETS 4 /* must be power of two */
#define ifsname(s) ((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0')
#define BASHFUNC_PREFIX "BASH_FUNC_"
#define BASHFUNC_PREFLEN 10 /* == strlen(BASHFUNC_PREFIX */
#define BASHFUNC_SUFFIX "%%"
@@ -178,6 +176,9 @@ static int export_env_size;
static int winsize_assignment; /* currently assigning to LINES or COLUMNS */
#endif
SHELL_VAR nameref_invalid_value;
static SHELL_VAR nameref_maxloop_value;
static HASH_TABLE *last_table_searched; /* hash_lookup sets this */
/* Some forward declarations. */
@@ -282,6 +283,8 @@ static int variable_in_context __P((SHELL_VAR *));
static int visible_array_vars __P((SHELL_VAR *));
#endif
static SHELL_VAR *find_variable_internal __P((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 **));
@@ -487,7 +490,8 @@ initialize_shell_variables (env, privmode)
qnx_nidtostr (getnid (), node_name, sizeof (node_name));
# endif
temp_var = bind_variable ("NODE", node_name, 0);
set_auto_export (temp_var);
if (temp_var)
set_auto_export (temp_var);
}
#endif
@@ -505,7 +509,7 @@ initialize_shell_variables (env, privmode)
}
if (current_user.euid == 0)
bind_variable ("PS4", "+", 0);
bind_variable ("PS4", "+ ", 0);
else
set_if_not ("PS4", "+ ");
@@ -950,7 +954,7 @@ make_vers_array ()
ARRAY *av;
char *s, d[32], b[INT_STRLEN_BOUND(int) + 1];
unbind_variable ("BASH_VERSINFO");
unbind_variable_noref ("BASH_VERSINFO");
vv = make_new_array_variable ("BASH_VERSINFO");
av = array_cell (vv);
@@ -1628,6 +1632,13 @@ assign_hashcmd (self, value, ind, key)
arrayind_t ind;
char *key;
{
#if defined (RESTRICTED_SHELL)
if (restricted && strchr (value, '/'))
{
sh_restricted (value);
return (SHELL_VAR *)NULL;
}
#endif
phash_insert (key, value, 0, 0);
return (build_hashcmd (self));
}
@@ -1893,7 +1904,7 @@ find_variable_nameref (v)
SHELL_VAR *v;
{
int level, flags;
char *newname;
char *newname, *t;
SHELL_VAR *orig, *oldv;
level = 0;
@@ -1910,6 +1921,7 @@ find_variable_nameref (v)
flags = 0;
if (expanding_redir == 0 && (assigning_in_environment || executing_builtin))
flags |= FV_FORCETEMPENV;
/* We don't handle array subscripts here. */
v = find_variable_internal (newname, flags);
if (v == orig || v == oldv)
{
@@ -1922,8 +1934,9 @@ find_variable_nameref (v)
/* Resolve the chain of nameref variables for NAME. XXX - could change later */
SHELL_VAR *
find_variable_last_nameref (name)
find_variable_last_nameref (name, vflags)
const char *name;
int vflags;
{
SHELL_VAR *v, *nv;
char *newname;
@@ -1938,11 +1951,12 @@ find_variable_last_nameref (name)
return ((SHELL_VAR *)0); /* error message here? */
newname = nameref_cell (v);
if (newname == 0 || *newname == '\0')
return ((SHELL_VAR *)0);
return ((vflags && invisible_p (v)) ? v : (SHELL_VAR *)0);
nv = v;
flags = 0;
if (expanding_redir == 0 && (assigning_in_environment || executing_builtin))
flags |= FV_FORCETEMPENV;
/* We don't accommodate array subscripts here. */
v = find_variable_internal (newname, flags);
}
return nv;
@@ -1950,8 +1964,9 @@ find_variable_last_nameref (name)
/* Resolve the chain of nameref variables for NAME. XXX - could change later */
SHELL_VAR *
find_global_variable_last_nameref (name)
find_global_variable_last_nameref (name, vflags)
const char *name;
int vflags;
{
SHELL_VAR *v, *nv;
char *newname;
@@ -1966,8 +1981,9 @@ find_global_variable_last_nameref (name)
return ((SHELL_VAR *)0); /* error message here? */
newname = nameref_cell (v);
if (newname == 0 || *newname == '\0')
return ((SHELL_VAR *)0);
return ((vflags && invisible_p (v)) ? v : (SHELL_VAR *)0);
nv = v;
/* We don't accommodate array subscripts here. */
v = find_global_variable_noref (newname);
}
return nv;
@@ -1989,7 +2005,7 @@ find_nameref_at_context (v, vc)
{
level++;
if (level > NAMEREF_MAX)
return ((SHELL_VAR *)NULL);
return (&nameref_maxloop_value);
newname = nameref_cell (nv);
if (newname == 0 || *newname == '\0')
return ((SHELL_VAR *)NULL);
@@ -2019,6 +2035,8 @@ find_variable_nameref_context (v, vc, nvcp)
for (nv = v, nvc = vc; nvc; nvc = nvc->down)
{
nv2 = find_nameref_at_context (nv, nvc);
if (nv2 == &nameref_maxloop_value)
return (nv2); /* XXX */
if (nv2 == 0)
continue;
nv = nv2;
@@ -2048,6 +2066,8 @@ find_variable_last_nameref_context (v, vc, nvcp)
for (nv = v, nvc = vc; nvc; nvc = nvc->down)
{
nv2 = find_nameref_at_context (nv, nvc);
if (nv2 == &nameref_maxloop_value)
return (nv2); /* XXX */
if (nv2 == 0)
continue;
nv = nv2;
@@ -2057,6 +2077,58 @@ find_variable_last_nameref_context (v, vc, nvcp)
return (nameref_p (nv) ? nv : (SHELL_VAR *)NULL);
}
SHELL_VAR *
find_variable_nameref_for_create (name, flags)
const char *name;
int flags;
{
SHELL_VAR *var;
/* See if we have a nameref pointing to a variable that hasn't been
created yet. */
var = find_variable_last_nameref (name, 1);
if ((flags&1) && var && nameref_p (var) && invisible_p (var))
{
internal_warning (_("%s: removing nameref attribute"), name);
VUNSETATTR (var, att_nameref);
}
if (var && nameref_p (var))
{
if (legal_identifier (nameref_cell (var)) == 0)
{
sh_invalidid (nameref_cell (var) ? nameref_cell (var) : "");
return ((SHELL_VAR *)INVALID_NAMEREF_VALUE);
}
}
return (var);
}
SHELL_VAR *
find_variable_nameref_for_assignment (name, flags)
const char *name;
int flags;
{
SHELL_VAR *var;
/* See if we have a nameref pointing to a variable that hasn't been
created yet. */
var = find_variable_last_nameref (name, 1);
if (var && nameref_p (var) && invisible_p (var)) /* XXX - flags */
{
internal_warning (_("%s: removing nameref attribute"), name);
VUNSETATTR (var, att_nameref);
}
if (var && nameref_p (var))
{
if (valid_nameref_value (nameref_cell (var), 1) == 0)
{
sh_invalidid (nameref_cell (var) ? nameref_cell (var) : "");
return ((SHELL_VAR *)INVALID_NAMEREF_VALUE);
}
}
return (var);
}
/* Find a variable, forcing a search of the temporary environment first */
SHELL_VAR *
find_variable_tempenv (name)
@@ -2290,16 +2362,29 @@ SHELL_VAR *
make_local_variable (name)
const char *name;
{
SHELL_VAR *new_var, *old_var;
SHELL_VAR *new_var, *old_var, *old_ref;
VAR_CONTEXT *vc;
int was_tmpvar;
char *tmp_value;
/* We don't want to follow the nameref chain when making local variables; we
just want to create them. */
old_ref = find_variable_noref (name);
if (old_ref && nameref_p (old_ref) == 0)
old_ref = 0;
/* local foo; local foo; is a no-op. */
old_var = find_variable (name);
if (old_var && local_p (old_var) && old_var->context == variable_context)
if (old_ref == 0 && old_var && local_p (old_var) && old_var->context == variable_context)
return (old_var);
/* local -n foo; local -n foo; is a no-op. */
if (old_ref && local_p (old_ref) && old_ref->context == variable_context)
return (old_ref);
/* From here on, we want to use the refvar, not the variable it references */
if (old_ref)
old_var = old_ref;
was_tmpvar = old_var && tempvar_p (old_var);
/* If we're making a local variable in a shell function, the temporary env
has already been merged into the function's variable context stack. We
@@ -2604,8 +2689,8 @@ bind_variable_internal (name, value, table, hflags, aflags)
HASH_TABLE *table;
int hflags, aflags;
{
char *newval;
SHELL_VAR *entry;
char *newval, *tname;
SHELL_VAR *entry, *tentry;
entry = (hflags & HASH_NOSRCH) ? (SHELL_VAR *)NULL : hash_lookup (name, table);
/* Follow the nameref chain here if this is the global variables table */
@@ -2615,22 +2700,44 @@ bind_variable_internal (name, value, table, hflags, aflags)
/* Let's see if we have a nameref referencing a variable that hasn't yet
been created. */
if (entry == 0)
entry = find_variable_last_nameref (name); /* XXX */
entry = find_variable_last_nameref (name, 0); /* XXX */
if (entry == 0) /* just in case */
return (entry);
}
/* The first clause handles `declare -n ref; ref=x;' */
/* The first clause handles `declare -n ref; ref=x;' or `declare -n ref;
declare -n ref' */
if (entry && invisible_p (entry) && nameref_p (entry))
goto assign_value;
{
if ((aflags & ASS_FORCE) == 0 && value && valid_nameref_value (value, 0) == 0)
{
sh_invalidid (value);
return ((SHELL_VAR *)NULL);
}
goto assign_value;
}
else if (entry && nameref_p (entry))
{
newval = nameref_cell (entry);
#if defined (ARRAY_VARS)
/* declare -n foo=x[2] */
/* declare -n foo=x[2] ; foo=bar */
if (valid_array_reference (newval, 0))
/* XXX - should it be aflags? */
entry = assign_array_element (newval, make_variable_value (entry, value, 0), aflags);
{
tname = array_variable_name (newval, (char **)0, (int *)0);
if (tname && (tentry = find_variable_noref (tname)) && nameref_p (tentry))
{
/* nameref variables can't be arrays */
internal_warning (_("%s: removing nameref attribute"), name_cell (tentry));
FREE (value_cell (tentry)); /* XXX - bash-4.3 compat */
var_setvalue (tentry, (char *)NULL);
VUNSETATTR (tentry, att_nameref);
}
free (tname);
/* XXX - should it be aflags? */
entry = assign_array_element (newval, make_variable_value (entry, value, 0), aflags|ASS_NAMEREF);
if (entry == 0)
return entry;
}
else
#endif
{
@@ -2663,7 +2770,7 @@ assign_value:
if ((readonly_p (entry) && (aflags & ASS_FORCE) == 0) || noassign_p (entry))
{
if (readonly_p (entry))
err_readonly (name);
err_readonly (name_cell (entry));
return (entry);
}
@@ -2765,9 +2872,27 @@ bind_variable (name, value, flags)
#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 0
return (bind_variable_value (v, value, flags|ASS_NAMEREF));
#else
v = 0; /* backwards compat */
#endif
}
else
v = nv;
}
else if (nv == &nameref_maxloop_value)
{
internal_warning (_("%s: circular name reference"), v->name);
#if 0
return (bind_variable_value (v, value, flags|ASS_NAMEREF));
#else
v = 0; /* backwards compat */
#endif
}
else
v = nv;
}
@@ -2825,11 +2950,20 @@ bind_variable_value (var, value, aflags)
else
{
t = make_variable_value (var, value, aflags);
#if defined (ARRAY_VARS)
if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || (legal_identifier (t) == 0 && valid_array_reference (t, 0) == 0)))
#else
if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || legal_identifier (t) == 0))
#endif
if ((aflags & (ASS_NAMEREF|ASS_FORCE)) == ASS_NAMEREF && check_selfref (name_cell (var), t, 0))
{
if (variable_context)
internal_warning (_("%s: circular name reference"), name_cell (var));
else
{
internal_error (_("%s: nameref variable self references not allowed"), name_cell (var));
free (t);
if (invis)
VSETATTR (var, att_invisible); /* XXX */
return ((SHELL_VAR *)NULL);
}
}
if ((aflags & ASS_NAMEREF) && (valid_nameref_value (t, 0) == 0))
{
free (t);
if (invis)
@@ -2905,6 +3039,9 @@ bind_int_variable (lhs, rhs)
VUNSETATTR (v, att_invisible);
}
if (v && nameref_p (v))
internal_warning (_("%s: assigning integer to name reference"), lhs);
return (v);
}
@@ -3006,7 +3143,7 @@ assign_in_env (word, flags)
int flags;
{
int offset, aflags;
char *name, *temp, *value;
char *name, *temp, *value, *newname;
SHELL_VAR *var;
const char *string;
@@ -3014,7 +3151,7 @@ assign_in_env (word, flags)
aflags = 0;
offset = assignment (string, 0);
name = savestring (string);
newname = name = savestring (string);
value = (char *)NULL;
if (name[offset] == '=')
@@ -3029,6 +3166,23 @@ assign_in_env (word, flags)
}
var = find_variable (name);
if (var == 0)
{
var = find_variable_last_nameref (name, 1);
/* If we're assigning a value to a nameref variable in the temp
environment, and the value of the nameref is valid for assignment,
but the variable does not already exist, assign to the nameref
target and add the target to the temporary environment. This is
what ksh93 does */
if (var && nameref_p (var) && valid_nameref_value (nameref_cell (var), 1))
{
newname = nameref_cell (var);
var = 0; /* don't use it for append */
}
}
else
newname = name_cell (var); /* no-op if not nameref */
if (var && (readonly_p (var) || noassign_p (var)))
{
if (readonly_p (var))
@@ -3036,12 +3190,17 @@ assign_in_env (word, flags)
free (name);
return (0);
}
temp = name + offset + 1;
value = expand_assignment_string_to_string (temp, 0);
if (var && (aflags & ASS_APPEND))
{
if (value == 0)
{
value = (char *)xmalloc (1); /* like do_assignment_internal */
value[0] = '\0';
}
temp = make_variable_value (var, value, aflags);
FREE (value);
value = temp;
@@ -3051,15 +3210,15 @@ assign_in_env (word, flags)
if (temporary_env == 0)
temporary_env = hash_create (TEMPENV_HASH_BUCKETS);
var = hash_lookup (name, temporary_env);
var = hash_lookup (newname, temporary_env);
if (var == 0)
var = make_new_variable (name, temporary_env);
var = make_new_variable (newname, temporary_env);
else
FREE (value_cell (var));
if (value == 0)
{
value = (char *)xmalloc (1); /* like do_assignment_internal */
value = (char *)xmalloc (1); /* see above */
value[0] = '\0';
}
@@ -3068,12 +3227,12 @@ assign_in_env (word, flags)
var->context = variable_context; /* XXX */
INVALIDATE_EXPORTSTR (var);
var->exportstr = mk_env_string (name, value, 0);
var->exportstr = mk_env_string (newname, value, 0);
array_needs_making = 1;
if (flags)
stupidly_hack_special_variables (name);
stupidly_hack_special_variables (newname);
if (echo_command_at_execute)
/* The Korn shell prints the `+ ' in front of assignment statements,
@@ -3205,6 +3364,34 @@ unbind_nameref (name)
return 0;
}
/* Unbind the first instance of NAME, whether it's a nameref or not */
int
unbind_variable_noref (name)
const char *name;
{
SHELL_VAR *v;
v = var_lookup (name, shell_variables);
if (v)
return makunbound (name, shell_variables);
return 0;
}
int
check_unbind_variable (name)
const char *name;
{
SHELL_VAR *v;
v = find_variable (name);
if (v && readonly_p (v))
{
internal_error (_("%s: cannot unset: readonly %s"), name, "variable");
return -1;
}
return (unbind_variable (name));
}
/* Unset the shell function named NAME. */
int
unbind_func (name)
@@ -3880,7 +4067,8 @@ push_temp_var (data)
if (binding_table == shell_variables->table)
shell_variables->flags |= VC_HASTMPVAR;
}
v->attributes |= var->attributes;
if (v)
v->attributes |= var->attributes;
if (find_special_var (var->name) >= 0)
tempvar_list[tvlist_ind++] = savestring (var->name);
@@ -4474,7 +4662,8 @@ push_func_var (data)
var->attributes &= ~(att_tempvar|att_propagate);
else
shell_variables->flags |= VC_HASTMPVAR;
v->attributes |= var->attributes;
if (v)
v->attributes |= var->attributes;
}
else
stupidly_hack_special_variables (var->name); /* XXX */
@@ -4562,7 +4751,8 @@ push_exported_var (data)
v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);
if (shell_variables == global_variables)
var->attributes &= ~att_propagate;
v->attributes |= var->attributes;
if (v)
v->attributes |= var->attributes;
}
else
stupidly_hack_special_variables (var->name); /* XXX */
@@ -5208,7 +5398,7 @@ sv_ignoreeof (name)
eof_encountered = 0;
tmp_var = find_variable (name);
ignoreeof = tmp_var != 0;
ignoreeof = tmp_var && var_isset (tmp_var);
temp = tmp_var ? value_cell (tmp_var) : (char *)NULL;
if (temp)
eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10;
@@ -5257,7 +5447,10 @@ void
sv_strict_posix (name)
char *name;
{
SET_INT_VAR (name, posixly_correct);
SHELL_VAR *var;
var = find_variable (name);
posixly_correct = var && var_isset (var);
posix_initialize (posixly_correct);
#if defined (READLINE)
if (interactive_shell)