summaryrefslogtreecommitdiff
path: root/builtins/declare.def
diff options
context:
space:
mode:
authorChet Ramey <chet.ramey@case.edu>2019-01-07 09:27:52 -0500
committerChet Ramey <chet.ramey@case.edu>2019-01-07 09:27:52 -0500
commitd233b485e83c3a784b803fb894280773f16f2deb (patch)
tree16d51f3ccca2d4ad2d8f2da564d68ca848de595b /builtins/declare.def
parent64447609994bfddeef1061948022c074093e9a9f (diff)
downloadbash-d233b485e83c3a784b803fb894280773f16f2deb.tar.gz
bash-5.0 distribution sources and documentationbash-5.0
Diffstat (limited to 'builtins/declare.def')
-rw-r--r--builtins/declare.def143
1 files changed, 110 insertions, 33 deletions
diff --git a/builtins/declare.def b/builtins/declare.def
index f4819b42..7eac6f58 100644
--- a/builtins/declare.def
+++ b/builtins/declare.def
@@ -40,11 +40,11 @@ Options which set attributes:
-a to make NAMEs indexed arrays (if supported)
-A to make NAMEs associative arrays (if supported)
-i to make NAMEs have the `integer' attribute
- -l to convert NAMEs to lower case on assignment
+ -l to convert the value of each NAME to lower case on assignment
-n make NAME a reference to the variable named by its value
-r to make NAMEs readonly
-t to make NAMEs have the `trace' attribute
- -u to convert NAMEs to upper case on assignment
+ -u to convert the value of each NAME to upper case on assignment
-x to make NAMEs export
Using `+' instead of `-' turns off the given attribute.
@@ -88,9 +88,7 @@ $END
#include "builtext.h"
#include "bashgetopt.h"
-extern int array_needs_making;
-extern int posixly_correct;
-
+static SHELL_VAR *declare_find_variable __P((const char *, int, int));
static int declare_internal __P((register WORD_LIST *, int));
/* Declare or change variable attributes. */
@@ -120,6 +118,13 @@ int
local_builtin (list)
register WORD_LIST *list;
{
+ /* Catch a straight `local --help' before checking function context */
+ if (list && list->word && STREQ (list->word->word, "--help"))
+ {
+ builtin_help ();
+ return (EX_USAGE);
+ }
+
if (variable_context)
return (declare_internal (list, 1));
else
@@ -130,11 +135,31 @@ local_builtin (list)
}
#if defined (ARRAY_VARS)
-# define DECLARE_OPTS "+acfgilnprtuxAF"
+# define DECLARE_OPTS "+acfgilnprtuxAFG"
#else
-# define DECLARE_OPTS "+cfgilnprtuxF"
+# define DECLARE_OPTS "+cfgilnprtuxFG"
#endif
+static SHELL_VAR *
+declare_find_variable (name, mkglobal, chklocal)
+ const char *name;
+ int mkglobal, chklocal;
+{
+ SHELL_VAR *var;
+
+ if (mkglobal == 0)
+ return (find_variable (name));
+ else if (chklocal)
+ {
+ var = find_variable (name);
+ if (var && local_p (var) && var->context == variable_context)
+ return var;
+ return (find_global_variable (name));
+ }
+ else
+ return (find_global_variable (name));
+}
+
/* The workhorse function. */
static int
declare_internal (list, local_var)
@@ -142,12 +167,14 @@ declare_internal (list, local_var)
int local_var;
{
int flags_on, flags_off, *flags;
- int any_failed, assign_error, pflag, nodefs, opt, mkglobal, onref, offref;
+ int any_failed, assign_error, pflag, nodefs, opt, onref, offref;
+ int mkglobal, chklocal;
char *t, *subscript_start;
SHELL_VAR *var, *refvar, *v;
FUNCTION_DEF *shell_fn;
- flags_on = flags_off = any_failed = assign_error = pflag = nodefs = mkglobal = 0;
+ flags_on = flags_off = any_failed = assign_error = pflag = nodefs = 0;
+ mkglobal = chklocal = 0;
refvar = (SHELL_VAR *)NULL;
reset_internal_getopt ();
while ((opt = internal_getopt (list, DECLARE_OPTS)) != -1)
@@ -185,6 +212,10 @@ declare_internal (list, local_var)
case 'f':
*flags |= att_function;
break;
+ case 'G':
+ if (flags == &flags_on)
+ chklocal = 1;
+ /*FALLTHROUGH*/
case 'g':
if (flags == &flags_on)
mkglobal = 1;
@@ -288,6 +319,7 @@ declare_internal (list, local_var)
{
char *value, *name, *oldname;
int offset, aflags, wflags, created_var, namelen;
+ int assoc_noexpand;
#if defined (ARRAY_VARS)
int making_array_special, compound_array_assign, simple_array_assign;
int var_exists, array_exists, creating_array, array_subscript_assignment;
@@ -295,13 +327,18 @@ declare_internal (list, local_var)
name = savestring (list->word->word);
wflags = list->word->flags;
- offset = assignment (name, 0);
+#if defined (ARRAY_VARS)
+ assoc_noexpand = assoc_expand_once && (wflags & W_ASSIGNMENT);
+#else
+ assoc_noexpand = 0;
+#endif
+ offset = assignment (name, assoc_noexpand ? 2 : 0);
aflags = 0;
created_var = 0;
if (local_var && variable_context && STREQ (name, "-"))
{
- var = make_local_variable ("-");
+ var = make_local_variable ("-", 0);
FREE (value_cell (var)); /* just in case */
value = get_current_options ();
var_setvalue (var, value);
@@ -363,7 +400,7 @@ restart_new_var_name:
compound_array_assign = simple_array_assign = 0;
array_subscript_assignment = 0;
subscript_start = (char *)NULL;
- if (t = strchr (name, '[')) /* ] */
+ if ((t = strchr (name, '[')) && (flags_on & att_function) == 0) /* ] */
{
/* If offset != 0 we have already validated any array reference
because assignment() calls skipsubscript() */
@@ -403,19 +440,38 @@ restart_new_var_name:
refvar = (SHELL_VAR *)NULL;
if (variable_context && mkglobal == 0 && ((flags_on & att_function) == 0))
{
+ char *newname;
+
/* check name for validity here? */
+ var = find_variable (name);
+ if (var == 0)
+ newname = nameref_transform_name (name, ASS_MKLOCAL);
+ else if ((flags_on & att_nameref) == 0 && (flags_off & att_nameref) == 0)
+ {
+ /* Ok, we're following namerefs here, so let's make sure that if
+ we followed one, it was at the same context (see below for
+ more details). */
+ refvar = find_variable_last_nameref (name, 1);
+ newname = (refvar && refvar->context != variable_context) ? name : var->name;
+ refvar = (SHELL_VAR *)NULL;
+ }
+ else
+ newname = name; /* dealing with nameref attribute */
+
#if defined (ARRAY_VARS)
+ /* Pass 1 as second argument to make_local_{assoc,array}_variable
+ return an existing {array,assoc} variable to be flagged as an
+ error below. */
if (flags_on & att_assoc)
- var = make_local_assoc_variable (name);
+ var = make_local_assoc_variable (newname, 1);
else if ((flags_on & att_array) || making_array_special)
- var = make_local_array_variable (name, making_array_special);
+ var = make_local_array_variable (newname, 1);
else
#endif
if (offset == 0 && (flags_on & att_nameref))
{
/* First look for refvar at current scope */
refvar = find_variable_last_nameref (name, 1);
- var = find_variable (name);
/* VARIABLE_CONTEXT != 0, so we are attempting to create or modify
the attributes for a local variable at the same scope. If we've
used a reference from a previous context to resolve VAR, we
@@ -423,18 +479,19 @@ restart_new_var_name:
if (refvar && refvar->context != variable_context)
{
refvar = 0;
- var = make_local_variable (name);
+ var = make_local_variable (name, 0);
}
else if (refvar && refvar->context == variable_context)
var = refvar;
/* Maybe we just want to create a new local variable */
else if (var == 0 || var->context != variable_context)
- var = make_local_variable (name);
+ var = make_local_variable (name, 0);
/* otherwise we have a var at the right context */
}
else
/* XXX - check name for validity here with valid_nameref_value */
- var = make_local_variable (name); /* sets att_invisible for new vars */
+ var = make_local_variable ((flags_on & att_nameref) ? name : newname, 0); /* sets att_invisible for new vars */
+
if (var == 0)
{
any_failed++;
@@ -528,21 +585,17 @@ restart_new_var_name:
#endif
if (var == 0 && (flags_on & att_nameref))
{
-#if 0
- /* See if we are trying to modify an existing nameref variable */
- var = mkglobal ? find_global_variable_last_nameref (name, 1) : find_variable_last_nameref (name, 1);
-#else
/* See if we are trying to modify an existing nameref variable,
but don't follow the nameref chain. */
var = mkglobal ? find_global_variable_noref (name) : find_variable_noref (name);
-#endif
if (var && nameref_p (var) == 0)
var = 0;
}
/* However, if we're turning off the nameref attribute on an existing
nameref variable, we first follow the nameref chain to the end,
- modify the value of the variable this nameref variable references,
- *CHANGING ITS VALUE AS A SIDE EFFECT* then turn off the nameref
+ modify the value of the variable this nameref variable references
+ if there is an assignment statement argument,
+ *CHANGING ITS VALUE AS A SIDE EFFECT*, then turn off the nameref
flag *LEAVING THE NAMEREF VARIABLE'S VALUE UNCHANGED* */
else if (var == 0 && (flags_off & att_nameref))
{
@@ -560,7 +613,18 @@ restart_new_var_name:
any_failed++;
NEXT_VARIABLE ();
}
+
+ /* If all we're doing is turning off the nameref attribute, don't
+ bother with VAR at all, whether it exists or not. Just turn it
+ off and go on. */
+ if (refvar && flags_on == 0 && offset == 0 && (flags_off & ~att_nameref) == 0)
+ {
+ VUNSETATTR (refvar, att_nameref);
+ NEXT_VARIABLE ();
+ }
+
if (refvar)
+ /* XXX - use declare_find_variable here? */
var = mkglobal ? find_global_variable (nameref_cell (refvar)) : find_variable (nameref_cell (refvar));
}
#if defined (ARRAY_VARS)
@@ -579,19 +643,20 @@ restart_new_var_name:
}
#endif
- /* See if we are trying to set flags or value for an existing nameref
- that points to a non-existent variable: e.g.,
+ /* See if we are trying to set flags or value (or create) for an
+ existing nameref that points to a non-existent variable: e.g.,
declare -n foo=bar
unset foo # unsets bar
declare -i foo
foo=4+4
declare -p foo */
- if (var == 0 && (flags_on || flags_off || offset))
+ if (var == 0 && (mkglobal || flags_on || flags_off || offset))
{
refvar = mkglobal ? find_global_variable_last_nameref (name, 0) : find_variable_last_nameref (name, 0);
if (refvar && nameref_p (refvar) == 0)
refvar = 0;
if (refvar)
+ /* XXX - use declare_find_variable here? */
var = mkglobal ? find_global_variable (nameref_cell (refvar)) : find_variable (nameref_cell (refvar));
if (refvar && var == 0)
{
@@ -637,12 +702,18 @@ restart_new_var_name:
value = name + namelen;
}
free (oldname);
+
+ /* OK, let's turn off the nameref attribute.
+ Now everything else applies to VAR. */
+ if (flags_off & att_nameref)
+ VUNSETATTR (refvar, att_nameref);
+
goto restart_new_var_name;
/* NOTREACHED */
}
}
if (var == 0)
- var = mkglobal ? find_global_variable (name) : find_variable (name);
+ var = declare_find_variable (name, mkglobal, chklocal);
#if defined (ARRAY_VARS)
var_exists = var != 0;
@@ -821,10 +892,13 @@ restart_new_var_name:
assign_array_var_from_string (var, value, aflags|ASS_FORCE);
else if (simple_array_assign && subscript_start)
{
+ int local_aflags;
/* declare [-aA] name[N]=value */
*subscript_start = '['; /* ] */
/* XXX - problem here with appending */
- var = assign_array_element (name, value, aflags&ASS_APPEND); /* XXX - not aflags */
+ local_aflags = aflags&ASS_APPEND;
+ local_aflags |= assoc_noexpand ? ASS_NOEXPAND : 0;
+ var = assign_array_element (name, value, local_aflags); /* XXX - not aflags */
*subscript_start = '\0';
if (var == 0) /* some kind of assignment error */
{
@@ -885,9 +959,12 @@ restart_new_var_name:
{
tvalue = var_isset (var) ? savestring (value_cell (var)) : savestring ("");
tv = bind_variable (var->name, tvalue, 0);
- tv->attributes |= var->attributes & ~att_tempvar;
- if (tv->context > 0)
- VSETATTR (tv, att_propagate);
+ if (tv)
+ {
+ tv->attributes |= var->attributes & ~att_tempvar;
+ if (tv->context > 0)
+ VSETATTR (tv, att_propagate);
+ }
free (tvalue);
}
VSETATTR (var, att_propagate);