1 This file is declare.def, from which is created declare.c.
2 It implements the builtins "declare" and "local" in Bash.
4 Copyright (C) 1987-2021 Free Software Foundation, Inc.
6 This file is part of GNU Bash, the Bourne Again SHell.
8 Bash is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 Bash is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Bash. If not, see <http://www.gnu.org/licenses/>.
24 $FUNCTION declare_builtin
25 $SHORT_DOC declare [-aAfFgiIlnrtux] [name[=value] ...] or declare -p [-aAfFilnrtux] [name ...]
26 Set variable values and attributes.
28 Declare variables and give them attributes. If no NAMEs are given,
29 display the attributes and values of all variables.
32 -f restrict action or display to function names and definitions
33 -F restrict display to function names only (plus line number and
34 source file when debugging)
35 -g create global variables when used in a shell function; otherwise
37 -I if creating a local variable, inherit the attributes and value
38 of a variable with the same name at a previous scope
39 -p display the attributes and value of each NAME
41 Options which set attributes:
42 -a to make NAMEs indexed arrays (if supported)
43 -A to make NAMEs associative arrays (if supported)
44 -i to make NAMEs have the `integer' attribute
45 -l to convert the value of each NAME to lower case on assignment
46 -n make NAME a reference to the variable named by its value
47 -r to make NAMEs readonly
48 -t to make NAMEs have the `trace' attribute
49 -u to convert the value of each NAME to upper case on assignment
50 -x to make NAMEs export
52 Using `+' instead of `-' turns off the given attribute.
54 Variables with the integer attribute have arithmetic evaluation (see
55 the `let' command) performed when the variable is assigned a value.
57 When used in a function, `declare' makes NAMEs local, as with the `local'
58 command. The `-g' option suppresses this behavior.
61 Returns success unless an invalid option is supplied or a variable
62 assignment error occurs.
66 $FUNCTION declare_builtin
67 $SHORT_DOC typeset [-aAfFgiIlnrtux] name[=value] ... or typeset -p [-aAfFilnrtux] [name ...]
68 Set variable values and attributes.
70 A synonym for `declare'. See `help declare'.
75 #if defined (HAVE_UNISTD_H)
77 # include <sys/types.h>
84 #include "../bashansi.h"
85 #include "../bashintl.h"
91 #include "bashgetopt.h"
93 static SHELL_VAR *declare_find_variable PARAMS((const char *, int, int));
94 static char *declare_build_newname PARAMS((char *, char *, int, char *, int));
95 static char *declare_transform_name PARAMS((char *, int, int));
97 static int declare_internal PARAMS((register WORD_LIST *, int));
99 /* Declare or change variable attributes. */
101 declare_builtin (list)
102 register WORD_LIST *list;
104 return (declare_internal (list, 0));
108 $FUNCTION local_builtin
109 $SHORT_DOC local [option] name[=value] ...
110 Define local variables.
112 Create a local variable called NAME, and give it VALUE. OPTION can
113 be any option accepted by `declare'.
115 Local variables can only be used within a function; they are visible
116 only to the function where they are defined and its children.
119 Returns success unless an invalid option is supplied, a variable
120 assignment error occurs, or the shell is not executing a function.
124 register WORD_LIST *list;
126 /* Catch a straight `local --help' before checking function context */
127 if (list && list->word && STREQ (list->word->word, "--help"))
133 if (variable_context)
134 return (declare_internal (list, 1));
137 builtin_error (_("can only be used in a function"));
138 return (EXECUTION_FAILURE);
142 #if defined (ARRAY_VARS)
143 # define DECLARE_OPTS "+acfgilnprtuxAFGI"
145 # define DECLARE_OPTS "+cfgilnprtuxFGI"
149 declare_find_variable (name, mkglobal, chklocal)
151 int mkglobal, chklocal;
156 return (find_variable (name));
159 var = find_variable (name);
160 if (var && local_p (var) && var->context == variable_context)
162 return (find_global_variable (name));
165 return (find_global_variable (name));
168 /* Build a new string
169 NAME[SUBSCRIPT][[+]=VALUE]
170 from expanding a nameref into NAME */
172 declare_build_newname (name, subscript_start, offset, value, aflags)
173 char *name, *subscript_start;
178 size_t namelen, savelen;
181 savelen = namelen = strlen (name);
184 *subscript_start = '['; /* ] */
185 namelen += strlen (subscript_start);
187 ret = xmalloc (namelen + 2 + strlen (value) + 1);
190 strcpy (ret + savelen, subscript_start);
193 if (aflags & ASS_APPEND)
194 ret[namelen++] = '+';
195 ret[namelen++] = '=';
197 strcpy (ret + namelen, value);
206 declare_transform_name (name, flags_on, flags_off)
208 int flags_on, flags_off;
213 var = find_variable (name);
215 newname = nameref_transform_name (name, ASS_MKLOCAL);
216 else if ((flags_on & att_nameref) == 0 && (flags_off & att_nameref) == 0)
218 /* Ok, we're following namerefs here, so let's make sure that if
219 we followed one, it was at the same context (see below for
221 v = find_variable_last_nameref (name, 1);
222 newname = (v && v->context != variable_context) ? name : name_cell (var);
225 newname = name; /* dealing with nameref attribute */
230 /* The workhorse function. */
232 declare_internal (list, local_var)
233 register WORD_LIST *list;
236 int flags_on, flags_off, *flags;
237 int any_failed, assign_error, pflag, nodefs, opt, onref, offref;
238 int mkglobal, chklocal, inherit_flag;
239 char *t, *subscript_start;
240 SHELL_VAR *var, *refvar, *v;
241 FUNCTION_DEF *shell_fn;
243 flags_on = flags_off = any_failed = assign_error = pflag = nodefs = 0;
244 mkglobal = chklocal = inherit_flag = 0;
245 refvar = (SHELL_VAR *)NULL;
246 reset_internal_getopt ();
247 while ((opt = internal_getopt (list, DECLARE_OPTS)) != -1)
249 flags = list_opttype == '+' ? &flags_off : &flags_on;
251 /* If you add options here, see whether or not they need to be added to
252 the loop in subst.c:shell_expand_word_list() */
256 #if defined (ARRAY_VARS)
264 #if defined (ARRAY_VARS)
276 *flags |= att_function;
279 *flags |= att_function;
282 if (flags == &flags_on)
286 if (flags == &flags_on)
290 *flags |= att_integer;
293 *flags |= att_nameref;
296 *flags |= att_readonly;
302 *flags |= att_exported;
303 array_needs_making = 1;
305 #if defined (CASEMOD_ATTRS)
306 # if defined (CASEMOD_CAPCASE)
308 *flags |= att_capcase;
309 if (flags == &flags_on)
310 flags_off |= att_uppercase|att_lowercase;
314 *flags |= att_lowercase;
315 if (flags == &flags_on)
316 flags_off |= att_capcase|att_uppercase;
319 *flags |= att_uppercase;
320 if (flags == &flags_on)
321 flags_off |= att_capcase|att_lowercase;
323 #endif /* CASEMOD_ATTRS */
325 inherit_flag = MKLOC_INHERIT;
336 /* If there are no more arguments left, then we just want to show
338 if (list == 0) /* declare -[aAfFilnrtux] */
340 /* Show local variables defined at this context level if this is
341 the `local' builtin. */
343 show_local_var_attributes (0, nodefs); /* XXX - fix up args later */
344 else if (pflag && (flags_on == 0 || flags_on == att_function))
345 show_all_var_attributes (flags_on == 0, nodefs);
346 else if (flags_on == 0)
347 return (set_builtin ((WORD_LIST *)NULL));
349 set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs);
351 return (sh_chkwrite (EXECUTION_SUCCESS));
354 if (pflag) /* declare -p [-aAfFilnrtux] [name ...] */
356 for (any_failed = 0; list; list = list->next)
358 if (flags_on & att_function)
359 pflag = show_func_attributes (list->word->word, nodefs);
361 pflag = show_localname_attributes (list->word->word, nodefs);
363 pflag = show_name_attributes (list->word->word, nodefs);
366 sh_notfound (list->word->word);
370 return (sh_chkwrite (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS));
373 /* Some option combinations that don't make any sense */
374 if ((flags_on & att_function) && (flags_on & (att_array|att_assoc|att_integer|att_nameref)))
378 if (flags_on & att_nameref)
380 else if (flags_on & att_integer)
382 else if (flags_on & att_assoc)
384 else if (flags_on & att_array)
387 sh_invalidopt (optchar);
388 return (EXECUTION_FAILURE);
391 #define NEXT_VARIABLE() free (name); list = list->next; continue
393 /* There are arguments left, so we are making variables. */
394 while (list) /* declare [-aAfFilnrtux] name[=value] [name[=value] ...] */
396 char *value, *name, *newname;
397 int offset, aflags, wflags, created_var;
399 #if defined (ARRAY_VARS)
400 int making_array_special, compound_array_assign, simple_array_assign;
401 int var_exists, array_exists, creating_array, array_subscript_assignment;
404 name = savestring (list->word->word);
405 wflags = list->word->flags;
406 #if defined (ARRAY_VARS)
407 assoc_noexpand = assoc_expand_once && (wflags & W_ASSIGNMENT);
411 /* XXX - we allow unbalanced brackets if assoc_noexpand is set, we count
412 brackets and make sure they match if assoc_noexpand is not set. So we
413 need to make sure we're checking assoc_noexpand and expand_once_flag
414 for backwards compatibility. We also use assoc_noexpand below when
415 we call assign_array_element, so we need to make sure they're
416 consistent in how they count brackets. */
417 offset = assignment (name, assoc_noexpand ? 2 : 0);
421 if (local_var && variable_context && STREQ (name, "-"))
423 var = make_local_variable ("-", 0);
424 FREE (value_cell (var)); /* just in case */
425 value = get_current_options ();
426 var_setvalue (var, value);
427 VSETATTR (var, att_invisible);
431 /* If we are declaring a function, then complain about it in some way.
432 We don't let people make functions by saying `typeset -f foo=bar'. */
434 /* Can't define functions using assignment statements */
435 if (offset && (flags_on & att_function)) /* declare -f [-rix] foo=bar */
437 builtin_error (_("cannot use `-f' to make functions"));
439 return (EXECUTION_FAILURE);
442 /* There should be a way, however, to let people look at a particular
443 function definition by saying `typeset -f foo'. This is the only
444 place in this builtin where we deal with functions. */
446 if (flags_on & att_function)
448 /* Should we restrict this when the shell is in posix mode even if
449 the function was created before the shell entered posix mode?
450 Previous versions of the shell enforced the restriction. */
451 if (posixly_correct && legal_identifier (name) == 0)
458 var = find_function (name);
462 if (readonly_p (var) && (flags_off & att_readonly))
464 builtin_error (_("%s: readonly function"), name);
468 /* declare -[Ff] name [name...] */
469 if (flags_on == att_function && flags_off == 0)
471 #if defined (DEBUGGER)
472 if (nodefs && debugging_mode)
474 shell_fn = find_function_def (name_cell (var));
476 printf ("%s %d %s\n", name_cell (var), shell_fn->line, shell_fn->source_file);
478 printf ("%s\n", name_cell (var));
481 #endif /* DEBUGGER */
483 t = nodefs ? name_cell (var) : named_function_string (name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL);
485 any_failed = sh_chkwrite (any_failed);
488 else /* declare -[fF] -[rx] name [name...] */
490 VSETATTR (var, flags_on);
491 flags_off &= ~att_function; /* makes no sense */
492 VUNSETATTR (var, flags_off);
501 if (offset) /* declare [-aAfFirx] name=value */
504 value = name + offset + 1;
505 if (name[offset - 1] == '+')
507 aflags |= ASS_APPEND;
508 name[offset - 1] = '\0';
514 /* Do some lexical error checking on the LHS and RHS of the assignment
515 that is specific to nameref variables. */
516 if (flags_on & att_nameref)
518 #if defined (ARRAY_VARS)
519 if (valid_array_reference (name, 0))
521 builtin_error (_("%s: reference variable cannot be an array"), name);
527 /* disallow self references at global scope, warn at function scope */
528 if (check_selfref (name, value, 0))
530 if (variable_context == 0)
532 builtin_error (_("%s: nameref variable self references not allowed"), name);
533 assign_error++; /* XXX any_failed++ instead? */
537 builtin_warning (_("%s: circular name reference"), name);
539 if (value && *value && (aflags & ASS_APPEND) == 0 && valid_nameref_value (value, 1) == 0)
541 builtin_error (_("`%s': invalid variable name for name reference"), value);
547 restart_new_var_name:
549 /* The rest of the loop body deals with declare -[aAlinrtux] name [name...]
550 where each NAME can be an assignment statement. */
552 subscript_start = (char *)NULL; /* used below */
553 #if defined (ARRAY_VARS)
554 /* Determine whether we are creating or assigning an array variable */
555 var_exists = array_exists = creating_array = 0;
556 compound_array_assign = simple_array_assign = 0;
557 array_subscript_assignment = 0;
558 if (t = strchr (name, '[')) /* ] */
560 /* If offset != 0 we have already validated any array reference
561 because assignment() calls skipsubscript() */
562 if (offset == 0 && valid_array_reference (name, 0) == 0)
570 making_array_special = 1; /* XXX - should this check offset? */
571 array_subscript_assignment = offset != 0;
574 making_array_special = 0;
577 /* Ensure the argument is a valid, well-formed shell identifier. */
578 if (legal_identifier (name) == 0)
585 /* If VARIABLE_CONTEXT has a non-zero value, then we are executing
586 inside of a function. This means we should make local variables,
589 /* XXX - this has consequences when we're making a local copy of a
590 variable that was in the temporary environment. Watch out
592 refvar = (SHELL_VAR *)NULL;
593 if (variable_context && mkglobal == 0)
595 /* We don't check newname for validity here. We should not have an
596 invalid name assigned as the value of a nameref, but this could
598 newname = declare_transform_name (name, flags_on, flags_off);
600 #if defined (ARRAY_VARS)
601 /* Pass 1 as second argument to make_local_{assoc,array}_variable
602 return an existing {array,assoc} variable to be flagged as an
604 if (flags_on & att_assoc)
605 var = make_local_assoc_variable (newname, MKLOC_ARRAYOK|inherit_flag);
606 else if ((flags_on & att_array) || making_array_special)
607 var = make_local_array_variable (newname, MKLOC_ASSOCOK|inherit_flag);
610 if (offset == 0 && (flags_on & att_nameref))
612 /* First look for refvar at current scope */
613 refvar = find_variable_last_nameref (name, 1);
614 /* VARIABLE_CONTEXT != 0, so we are attempting to create or modify
615 the attributes for a local variable at the same scope. If we've
616 used a reference from a previous context to resolve VAR, we
617 want to throw REFVAR and VAR away and create a new local var. */
618 if (refvar && refvar->context != variable_context)
621 var = make_local_variable (name, inherit_flag);
623 else if (refvar && refvar->context == variable_context)
625 /* Maybe we just want to create a new local variable */
626 else if ((var = find_variable (name)) == 0 || var->context != variable_context)
627 var = make_local_variable (name, inherit_flag);
628 /* otherwise we have a var at the right context */
631 /* XXX - check name for validity here with valid_nameref_value? */
632 var = make_local_variable ((flags_on & att_nameref) ? name : newname, inherit_flag); /* sets att_invisible for new vars */
639 if (var && nameref_p (var) && readonly_p (var) && nameref_cell (var) && (flags_off & att_nameref))
647 var = (SHELL_VAR *)NULL;
649 /* VAR is non-null if we just created or fetched a local variable. */
651 /* Here's what ksh93 seems to do as of the 2012 version: if we are
652 using declare -n to modify the value of an existing nameref
653 variable, don't follow the nameref chain at all and just search
654 for a nameref at the current context. If we have a nameref,
655 modify its value (changing which variable it references). */
656 if (var == 0 && (flags_on & att_nameref))
658 /* See if we are trying to modify an existing nameref variable,
659 but don't follow the nameref chain. */
660 var = mkglobal ? find_global_variable_noref (name) : find_variable_noref (name);
661 if (var && nameref_p (var) == 0)
665 /* However, if we're turning off the nameref attribute on an existing
666 nameref variable, we first follow the nameref chain to the end,
667 modify the value of the variable this nameref variable references
668 if there is an assignment statement argument,
669 *CHANGING ITS VALUE AS A SIDE EFFECT*, then turn off the nameref
670 flag *LEAVING THE NAMEREF VARIABLE'S VALUE UNCHANGED* */
671 else if (var == 0 && (flags_off & att_nameref))
673 /* See if we are trying to modify an existing nameref variable */
674 refvar = mkglobal ? find_global_variable_last_nameref (name, 0) : find_variable_last_nameref (name, 0);
675 if (refvar && nameref_p (refvar) == 0)
677 /* If the nameref is readonly but doesn't have a value, ksh93
678 allows the nameref attribute to be removed. If it's readonly
679 and has a value, even if the value doesn't reference an
680 existing variable, we disallow the modification */
681 if (refvar && nameref_cell (refvar) && readonly_p (refvar))
688 /* If all we're doing is turning off the nameref attribute, don't
689 bother with VAR at all, whether it exists or not. Just turn it
691 if (refvar && flags_on == 0 && offset == 0 && flags_off == att_nameref)
693 VUNSETATTR (refvar, att_nameref);
698 var = declare_find_variable (nameref_cell (refvar), mkglobal, 0);
700 #if defined (ARRAY_VARS)
701 /* If we have an array assignment to a nameref, remove the nameref
702 attribute and go on. This handles
703 declare -n xref[=value]; declare [-a] xref[1]=one */
704 else if (var == 0 && offset && array_subscript_assignment)
706 var = mkglobal ? find_global_variable_noref (name) : find_variable_noref (name);
707 if (var && nameref_p (var))
709 internal_warning (_("%s: removing nameref attribute"), name);
710 FREE (value_cell (var)); /* XXX - bash-4.3 compat */
711 var_setvalue (var, (char *)NULL);
712 VUNSETATTR (var, att_nameref);
717 /* See if we are trying to set flags or value (or create) for an
718 existing nameref that points to a non-existent variable: e.g.,
720 unset foo # unsets bar
725 if (var == 0 && (mkglobal || flags_on || flags_off || offset))
727 refvar = mkglobal ? find_global_variable_last_nameref (name, 0) : find_variable_last_nameref (name, 0);
728 if (refvar && nameref_p (refvar) == 0)
731 var = declare_find_variable (nameref_cell (refvar), mkglobal, 0);
732 if (refvar && var == 0)
734 /* I'm not sure subscript_start is ever non-null here. In any
735 event, build a new name from the nameref value, including any
736 subscript, and add the [[+]=value] if offset != 0 */
737 newname = declare_build_newname (nameref_cell (refvar), subscript_start, offset, value, aflags);
743 offset = assignment (name, 0);
744 /* If offset was valid previously, but substituting the
745 the nameref value results in an invalid assignment,
746 throw an invalid identifier error */
753 name[(aflags & ASS_APPEND) ? offset - 1 : offset] = '\0';
754 value = name + offset + 1;
757 /* OK, let's turn off the nameref attribute.
758 Now everything else applies to VAR. */
759 if (flags_off & att_nameref)
760 VUNSETATTR (refvar, att_nameref);
762 goto restart_new_var_name;
767 var = declare_find_variable (name, mkglobal, chklocal);
769 /* At this point, VAR is the variable we are dealing with; REFVAR is the
770 nameref variable we dereferenced to get VAR, if any. */
771 #if defined (ARRAY_VARS)
772 var_exists = var != 0;
773 array_exists = var && (array_p (var) || assoc_p (var));
774 creating_array = flags_on & (att_array|att_assoc);
777 /* Make a new variable if we need to. */
780 #if defined (ARRAY_VARS)
781 if (flags_on & att_assoc)
782 var = make_new_assoc_variable (name);
783 else if ((flags_on & att_array) || making_array_special)
784 var = make_new_array_variable (name);
787 var = mkglobal ? bind_global_variable (name, (char *)NULL, ASS_FORCE) : bind_variable (name, (char *)NULL, ASS_FORCE);
791 /* Has to appear in brackets */
795 VSETATTR (var, att_invisible);
799 /* Nameref variable error checking. */
801 /* Can't take an existing array variable and make it a nameref */
802 else if ((array_p (var) || assoc_p (var)) && (flags_on & att_nameref))
804 builtin_error (_("%s: reference variable cannot be an array"), name);
808 /* Can't have an invalid identifier as nameref value */
809 else if (nameref_p (var) && (flags_on & att_nameref) == 0 && (flags_off & att_nameref) == 0 && offset && valid_nameref_value (value, 1) == 0)
811 builtin_error (_("`%s': invalid variable name for name reference"), value);
815 /* Can't make an existing variable a nameref if its current value is not
816 a valid identifier. Check of offset is to allow an assignment to a
817 nameref var as part of the declare word to override existing value. */
818 else if ((flags_on & att_nameref) && nameref_p (var) == 0 && var_isset (var) && offset == 0 && valid_nameref_value (value_cell (var), 0) == 0)
820 builtin_error (_("`%s': invalid variable name for name reference"), value_cell (var));
824 /* Can't make an existing readonly variable a nameref. */
825 else if ((flags_on & att_nameref) && readonly_p (var))
832 /* Readonly variable error checking. */
834 /* Cannot use declare +r to turn off readonly attribute. */
835 if (readonly_p (var) && (flags_off & att_readonly))
837 sh_readonly (name_cell (var));
841 /* Cannot use declare to assign value to readonly or noassign variable. */
842 else if ((readonly_p (var) || noassign_p (var)) && offset)
844 if (readonly_p (var))
850 #if defined (ARRAY_VARS)
851 /* Array variable error checking. */
853 /* Cannot use declare +a name or declare +A name to remove an array variable. */
854 if (((flags_off & att_array) && array_p (var)) || ((flags_off & att_assoc) && assoc_p (var)))
856 builtin_error (_("%s: cannot destroy array variables in this way"), name);
860 else if ((flags_on & att_array) && assoc_p (var))
862 builtin_error (_("%s: cannot convert associative to indexed array"), name);
866 else if ((flags_on & att_assoc) && array_p (var))
868 builtin_error (_("%s: cannot convert indexed to associative array"), name);
873 /* make declare A[2]=foo as similar to A[2]=foo as possible if A is
874 already an array or assoc variable. */
875 if (array_subscript_assignment && array_exists && creating_array == 0)
876 simple_array_assign = 1;
877 else if ((making_array_special || creating_array || array_exists) && offset)
880 vlen = STRLEN (value);
881 /*itrace("declare_builtin: name = %s value = %s flags = %d", name, value, wflags);*/
883 if (shell_compatibility_level > 43 && (wflags & W_COMPASSIGN) == 0 &&
884 value[0] == '(' && value[vlen-1] == ')')
886 /* I don't believe this warning is printed any more.
887 We use creating_array to allow things like
888 declare -a foo$bar='(abc)'
889 to work as they have in the past. */
890 if (array_exists == 0 && creating_array == 0)
891 internal_warning (_("%s: quoted compound array assignment deprecated"), list->word->word);
892 compound_array_assign = array_exists || creating_array;
893 simple_array_assign = making_array_special;
895 else if (value[0] == '(' && value[vlen-1] == ')' && (shell_compatibility_level < 44 || (wflags & W_COMPASSIGN)))
896 compound_array_assign = 1;
898 simple_array_assign = 1;
901 /* declare -A name[[n]] makes name an associative array variable. */
902 if (flags_on & att_assoc)
904 if (assoc_p (var) == 0)
905 var = convert_var_to_assoc (var);
907 /* declare -a name[[n]] or declare name[n] makes NAME an indexed
909 else if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0 && assoc_p (var) == 0)
910 var = convert_var_to_array (var);
911 #endif /* ARRAY_VARS */
913 /* ksh93 compat: turning on nameref attribute turns off -ilu */
914 if (flags_on & att_nameref)
915 VUNSETATTR (var, att_integer|att_uppercase|att_lowercase|att_capcase);
917 /* XXX - we note that we are turning on nameref attribute and defer
918 setting it until the assignment has been made so we don't do an
919 inadvertent nameref lookup. Might have to do the same thing for
920 flags_off&att_nameref. */
921 /* XXX - ksh93 makes it an error to set a readonly nameref variable
922 using a single typeset command. */
923 onref = (flags_on & att_nameref);
924 flags_on &= ~att_nameref;
925 #if defined (ARRAY_VARS)
926 /* I don't believe this condition ever tests true, but array variables
927 may not be namerefs */
928 if (array_p (var) || assoc_p (var) || compound_array_assign || simple_array_assign)
932 /* ksh93 seems to do this */
933 offref = (flags_off & att_nameref);
934 flags_off &= ~att_nameref;
936 VSETATTR (var, flags_on);
937 VUNSETATTR (var, flags_off);
939 #if defined (ARRAY_VARS)
940 if (offset && compound_array_assign)
941 assign_array_var_from_string (var, value, aflags|ASS_FORCE);
942 else if (simple_array_assign && subscript_start)
946 /* declare [-aA] name[N]=value */
947 *subscript_start = '['; /* ] */
948 /* XXX - problem here with appending */
949 local_aflags = aflags&ASS_APPEND;
950 local_aflags |= assoc_noexpand ? ASS_NOEXPAND : 0;
951 local_aflags |= ASS_ALLOWALLSUB; /* allow declare a[@]=at */
952 var = assign_array_element (name, value, local_aflags, (array_eltstate_t *)0); /* XXX - not aflags */
953 *subscript_start = '\0';
954 if (var == 0) /* some kind of assignment error */
962 else if (simple_array_assign)
964 /* let bind_{array,assoc}_variable take care of this. */
966 bind_assoc_variable (var, name, savestring ("0"), value, aflags|ASS_FORCE);
968 bind_array_variable (name, 0, value, aflags|ASS_FORCE);
972 /* XXX - no ASS_FORCE here */
973 /* bind_variable_value duplicates the essential internals of bind_variable() */
976 if (onref || nameref_p (var))
977 aflags |= ASS_NAMEREF;
978 v = bind_variable_value (var, value, aflags);
979 if (v == 0 && (onref || nameref_p (var)))
981 if (valid_nameref_value (value, 1) == 0)
982 sh_invalidid (value);
984 /* XXX - unset this variable? or leave it as normal var? */
986 delete_var (name_cell (var), mkglobal ? global_variables : shell_variables);
987 flags_on |= onref; /* undo change from above */
993 /* If we found this variable in the temporary environment, as with
994 `var=value declare -x var', make sure it is treated identically
995 to `var=value export var'. Do the same for `declare -r' and
996 `readonly'. Preserve the attributes, except for att_tempvar. */
997 /* XXX -- should this create a variable in the global scope, or
998 modify the local variable flags? ksh93 has it modify the
1000 Need to handle case like in set_var_attribute where a temporary
1001 variable is in the same table as the function local vars. */
1002 if ((flags_on & (att_exported|att_readonly)) && tempvar_p (var))
1007 tv = find_tempenv_variable (name_cell (var));
1010 tvalue = var_isset (var) ? savestring (value_cell (var)) : savestring ("");
1011 tv = bind_variable (name_cell (var), tvalue, 0);
1014 tv->attributes |= var->attributes & ~att_tempvar;
1015 if (tv->context > 0)
1016 VSETATTR (tv, att_propagate);
1020 VSETATTR (var, att_propagate);
1023 /* Turn on nameref attribute we deferred above. */
1024 VSETATTR (var, onref);
1026 VUNSETATTR (var, offref);
1027 flags_off |= offref;
1029 /* Yuck. ksh93 compatibility. XXX - need to investigate more but
1030 definitely happens when turning off nameref attribute on nameref
1031 (see comments above). Under no circumstances allow this to turn
1032 off readonly attribute on readonly nameref variable. */
1035 if (flags_off & att_readonly)
1036 flags_off &= ~att_readonly;
1037 VUNSETATTR (refvar, flags_off);
1040 stupidly_hack_special_variables (name);
1045 return (assign_error ? EX_BADASSIGN
1046 : ((any_failed == 0) ? EXECUTION_SUCCESS
1047 : EXECUTION_FAILURE));