diff options
author | Chet Ramey <chet.ramey@case.edu> | 2019-01-07 09:27:52 -0500 |
---|---|---|
committer | Chet Ramey <chet.ramey@case.edu> | 2019-01-07 09:27:52 -0500 |
commit | d233b485e83c3a784b803fb894280773f16f2deb (patch) | |
tree | 16d51f3ccca2d4ad2d8f2da564d68ca848de595b /builtins/declare.def | |
parent | 64447609994bfddeef1061948022c074093e9a9f (diff) | |
download | bash-d233b485e83c3a784b803fb894280773f16f2deb.tar.gz |
bash-5.0 distribution sources and documentationbash-5.0
Diffstat (limited to 'builtins/declare.def')
-rw-r--r-- | builtins/declare.def | 143 |
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); |