]> git.ipfire.org Git - thirdparty/bash.git/blob - builtins/declare.def
bash-5.2 distribution sources and documentation
[thirdparty/bash.git] / builtins / declare.def
1 This file is declare.def, from which is created declare.c.
2 It implements the builtins "declare" and "local" in Bash.
3
4 Copyright (C) 1987-2021 Free Software Foundation, Inc.
5
6 This file is part of GNU Bash, the Bourne Again SHell.
7
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.
12
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.
17
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/>.
20
21 $PRODUCES declare.c
22
23 $BUILTIN declare
24 $FUNCTION declare_builtin
25 $SHORT_DOC declare [-aAfFgiIlnrtux] [name[=value] ...] or declare -p [-aAfFilnrtux] [name ...]
26 Set variable values and attributes.
27
28 Declare variables and give them attributes. If no NAMEs are given,
29 display the attributes and values of all variables.
30
31 Options:
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
36 ignored
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
40
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
51
52 Using `+' instead of `-' turns off the given attribute.
53
54 Variables with the integer attribute have arithmetic evaluation (see
55 the `let' command) performed when the variable is assigned a value.
56
57 When used in a function, `declare' makes NAMEs local, as with the `local'
58 command. The `-g' option suppresses this behavior.
59
60 Exit Status:
61 Returns success unless an invalid option is supplied or a variable
62 assignment error occurs.
63 $END
64
65 $BUILTIN typeset
66 $FUNCTION declare_builtin
67 $SHORT_DOC typeset [-aAfFgiIlnrtux] name[=value] ... or typeset -p [-aAfFilnrtux] [name ...]
68 Set variable values and attributes.
69
70 A synonym for `declare'. See `help declare'.
71 $END
72
73 #include <config.h>
74
75 #if defined (HAVE_UNISTD_H)
76 # ifdef _MINIX
77 # include <sys/types.h>
78 # endif
79 # include <unistd.h>
80 #endif
81
82 #include <stdio.h>
83
84 #include "../bashansi.h"
85 #include "../bashintl.h"
86
87 #include "../shell.h"
88 #include "../flags.h"
89 #include "common.h"
90 #include "builtext.h"
91 #include "bashgetopt.h"
92
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));
96
97 static int declare_internal PARAMS((register WORD_LIST *, int));
98
99 /* Declare or change variable attributes. */
100 int
101 declare_builtin (list)
102 register WORD_LIST *list;
103 {
104 return (declare_internal (list, 0));
105 }
106
107 $BUILTIN local
108 $FUNCTION local_builtin
109 $SHORT_DOC local [option] name[=value] ...
110 Define local variables.
111
112 Create a local variable called NAME, and give it VALUE. OPTION can
113 be any option accepted by `declare'.
114
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.
117
118 Exit Status:
119 Returns success unless an invalid option is supplied, a variable
120 assignment error occurs, or the shell is not executing a function.
121 $END
122 int
123 local_builtin (list)
124 register WORD_LIST *list;
125 {
126 /* Catch a straight `local --help' before checking function context */
127 if (list && list->word && STREQ (list->word->word, "--help"))
128 {
129 builtin_help ();
130 return (EX_USAGE);
131 }
132
133 if (variable_context)
134 return (declare_internal (list, 1));
135 else
136 {
137 builtin_error (_("can only be used in a function"));
138 return (EXECUTION_FAILURE);
139 }
140 }
141
142 #if defined (ARRAY_VARS)
143 # define DECLARE_OPTS "+acfgilnprtuxAFGI"
144 #else
145 # define DECLARE_OPTS "+cfgilnprtuxFGI"
146 #endif
147
148 static SHELL_VAR *
149 declare_find_variable (name, mkglobal, chklocal)
150 const char *name;
151 int mkglobal, chklocal;
152 {
153 SHELL_VAR *var;
154
155 if (mkglobal == 0)
156 return (find_variable (name));
157 else if (chklocal)
158 {
159 var = find_variable (name);
160 if (var && local_p (var) && var->context == variable_context)
161 return var;
162 return (find_global_variable (name));
163 }
164 else
165 return (find_global_variable (name));
166 }
167
168 /* Build a new string
169 NAME[SUBSCRIPT][[+]=VALUE]
170 from expanding a nameref into NAME */
171 static char *
172 declare_build_newname (name, subscript_start, offset, value, aflags)
173 char *name, *subscript_start;
174 int offset;
175 char *value;
176 int aflags;
177 {
178 size_t namelen, savelen;
179 char *ret;
180
181 savelen = namelen = strlen (name);
182 if (subscript_start)
183 {
184 *subscript_start = '['; /* ] */
185 namelen += strlen (subscript_start);
186 }
187 ret = xmalloc (namelen + 2 + strlen (value) + 1);
188 strcpy (ret, name);
189 if (subscript_start)
190 strcpy (ret + savelen, subscript_start);
191 if (offset)
192 {
193 if (aflags & ASS_APPEND)
194 ret[namelen++] = '+';
195 ret[namelen++] = '=';
196 if (value && *value)
197 strcpy (ret + namelen, value);
198 else
199 ret[namelen] = '\0';
200 }
201
202 return (ret);
203 }
204
205 static char *
206 declare_transform_name (name, flags_on, flags_off)
207 char *name;
208 int flags_on, flags_off;
209 {
210 SHELL_VAR *var, *v;
211 char *newname;
212
213 var = find_variable (name);
214 if (var == 0)
215 newname = nameref_transform_name (name, ASS_MKLOCAL);
216 else if ((flags_on & att_nameref) == 0 && (flags_off & att_nameref) == 0)
217 {
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
220 more details). */
221 v = find_variable_last_nameref (name, 1);
222 newname = (v && v->context != variable_context) ? name : name_cell (var);
223 }
224 else
225 newname = name; /* dealing with nameref attribute */
226
227 return (newname);
228 }
229
230 /* The workhorse function. */
231 static int
232 declare_internal (list, local_var)
233 register WORD_LIST *list;
234 int local_var;
235 {
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;
242
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)
248 {
249 flags = list_opttype == '+' ? &flags_off : &flags_on;
250
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() */
253 switch (opt)
254 {
255 case 'a':
256 #if defined (ARRAY_VARS)
257 *flags |= att_array;
258 break;
259 #else
260 builtin_usage ();
261 return (EX_USAGE);
262 #endif
263 case 'A':
264 #if defined (ARRAY_VARS)
265 *flags |= att_assoc;
266 break;
267 #else
268 builtin_usage ();
269 return (EX_USAGE);
270 #endif
271 case 'p':
272 pflag++;
273 break;
274 case 'F':
275 nodefs++;
276 *flags |= att_function;
277 break;
278 case 'f':
279 *flags |= att_function;
280 break;
281 case 'G':
282 if (flags == &flags_on)
283 chklocal = 1;
284 /*FALLTHROUGH*/
285 case 'g':
286 if (flags == &flags_on)
287 mkglobal = 1;
288 break;
289 case 'i':
290 *flags |= att_integer;
291 break;
292 case 'n':
293 *flags |= att_nameref;
294 break;
295 case 'r':
296 *flags |= att_readonly;
297 break;
298 case 't':
299 *flags |= att_trace;
300 break;
301 case 'x':
302 *flags |= att_exported;
303 array_needs_making = 1;
304 break;
305 #if defined (CASEMOD_ATTRS)
306 # if defined (CASEMOD_CAPCASE)
307 case 'c':
308 *flags |= att_capcase;
309 if (flags == &flags_on)
310 flags_off |= att_uppercase|att_lowercase;
311 break;
312 # endif
313 case 'l':
314 *flags |= att_lowercase;
315 if (flags == &flags_on)
316 flags_off |= att_capcase|att_uppercase;
317 break;
318 case 'u':
319 *flags |= att_uppercase;
320 if (flags == &flags_on)
321 flags_off |= att_capcase|att_lowercase;
322 break;
323 #endif /* CASEMOD_ATTRS */
324 case 'I':
325 inherit_flag = MKLOC_INHERIT;
326 break;
327 CASE_HELPOPT;
328 default:
329 builtin_usage ();
330 return (EX_USAGE);
331 }
332 }
333
334 list = loptend;
335
336 /* If there are no more arguments left, then we just want to show
337 some variables. */
338 if (list == 0) /* declare -[aAfFilnrtux] */
339 {
340 /* Show local variables defined at this context level if this is
341 the `local' builtin. */
342 if (local_var)
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));
348 else
349 set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs);
350
351 return (sh_chkwrite (EXECUTION_SUCCESS));
352 }
353
354 if (pflag) /* declare -p [-aAfFilnrtux] [name ...] */
355 {
356 for (any_failed = 0; list; list = list->next)
357 {
358 if (flags_on & att_function)
359 pflag = show_func_attributes (list->word->word, nodefs);
360 else if (local_var)
361 pflag = show_localname_attributes (list->word->word, nodefs);
362 else
363 pflag = show_name_attributes (list->word->word, nodefs);
364 if (pflag)
365 {
366 sh_notfound (list->word->word);
367 any_failed++;
368 }
369 }
370 return (sh_chkwrite (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS));
371 }
372
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)))
375 {
376 char *optchar;
377
378 if (flags_on & att_nameref)
379 optchar = "-n";
380 else if (flags_on & att_integer)
381 optchar = "-i";
382 else if (flags_on & att_assoc)
383 optchar = "-A";
384 else if (flags_on & att_array)
385 optchar = "-a";
386
387 sh_invalidopt (optchar);
388 return (EXECUTION_FAILURE);
389 }
390
391 #define NEXT_VARIABLE() free (name); list = list->next; continue
392
393 /* There are arguments left, so we are making variables. */
394 while (list) /* declare [-aAfFilnrtux] name[=value] [name[=value] ...] */
395 {
396 char *value, *name, *newname;
397 int offset, aflags, wflags, created_var;
398 int assoc_noexpand;
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;
402 #endif
403
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);
408 #else
409 assoc_noexpand = 0;
410 #endif
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);
418 aflags = 0;
419 created_var = 0;
420
421 if (local_var && variable_context && STREQ (name, "-"))
422 {
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);
428 NEXT_VARIABLE ();
429 }
430
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'. */
433
434 /* Can't define functions using assignment statements */
435 if (offset && (flags_on & att_function)) /* declare -f [-rix] foo=bar */
436 {
437 builtin_error (_("cannot use `-f' to make functions"));
438 free (name);
439 return (EXECUTION_FAILURE);
440 }
441
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. */
445
446 if (flags_on & att_function)
447 {
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)
452 {
453 sh_invalidid (name);
454 assign_error++;
455 NEXT_VARIABLE ();
456 }
457
458 var = find_function (name);
459
460 if (var)
461 {
462 if (readonly_p (var) && (flags_off & att_readonly))
463 {
464 builtin_error (_("%s: readonly function"), name);
465 any_failed++;
466 NEXT_VARIABLE ();
467 }
468 /* declare -[Ff] name [name...] */
469 if (flags_on == att_function && flags_off == 0)
470 {
471 #if defined (DEBUGGER)
472 if (nodefs && debugging_mode)
473 {
474 shell_fn = find_function_def (name_cell (var));
475 if (shell_fn)
476 printf ("%s %d %s\n", name_cell (var), shell_fn->line, shell_fn->source_file);
477 else
478 printf ("%s\n", name_cell (var));
479 }
480 else
481 #endif /* DEBUGGER */
482 {
483 t = nodefs ? name_cell (var) : named_function_string (name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL);
484 printf ("%s\n", t);
485 any_failed = sh_chkwrite (any_failed);
486 }
487 }
488 else /* declare -[fF] -[rx] name [name...] */
489 {
490 VSETATTR (var, flags_on);
491 flags_off &= ~att_function; /* makes no sense */
492 VUNSETATTR (var, flags_off);
493 }
494 }
495 else
496 any_failed++;
497
498 NEXT_VARIABLE ();
499 }
500
501 if (offset) /* declare [-aAfFirx] name=value */
502 {
503 name[offset] = '\0';
504 value = name + offset + 1;
505 if (name[offset - 1] == '+')
506 {
507 aflags |= ASS_APPEND;
508 name[offset - 1] = '\0';
509 }
510 }
511 else
512 value = "";
513
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)
517 {
518 #if defined (ARRAY_VARS)
519 if (valid_array_reference (name, 0))
520 {
521 builtin_error (_("%s: reference variable cannot be an array"), name);
522 any_failed++;
523 NEXT_VARIABLE ();
524 }
525 else
526 #endif
527 /* disallow self references at global scope, warn at function scope */
528 if (check_selfref (name, value, 0))
529 {
530 if (variable_context == 0)
531 {
532 builtin_error (_("%s: nameref variable self references not allowed"), name);
533 assign_error++; /* XXX any_failed++ instead? */
534 NEXT_VARIABLE ();
535 }
536 else
537 builtin_warning (_("%s: circular name reference"), name);
538 }
539 if (value && *value && (aflags & ASS_APPEND) == 0 && valid_nameref_value (value, 1) == 0)
540 {
541 builtin_error (_("`%s': invalid variable name for name reference"), value);
542 assign_error++;
543 NEXT_VARIABLE ();
544 }
545 }
546
547 restart_new_var_name:
548
549 /* The rest of the loop body deals with declare -[aAlinrtux] name [name...]
550 where each NAME can be an assignment statement. */
551
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, '[')) /* ] */
559 {
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)
563 {
564 sh_invalidid (name);
565 assign_error++;
566 NEXT_VARIABLE ();
567 }
568 subscript_start = t;
569 *t = '\0';
570 making_array_special = 1; /* XXX - should this check offset? */
571 array_subscript_assignment = offset != 0;
572 }
573 else
574 making_array_special = 0;
575 #endif
576
577 /* Ensure the argument is a valid, well-formed shell identifier. */
578 if (legal_identifier (name) == 0)
579 {
580 sh_invalidid (name);
581 assign_error++;
582 NEXT_VARIABLE ();
583 }
584
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,
587 not global ones. */
588
589 /* XXX - this has consequences when we're making a local copy of a
590 variable that was in the temporary environment. Watch out
591 for this. */
592 refvar = (SHELL_VAR *)NULL;
593 if (variable_context && mkglobal == 0)
594 {
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
597 cause problems. */
598 newname = declare_transform_name (name, flags_on, flags_off);
599
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
603 error below. */
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);
608 else
609 #endif
610 if (offset == 0 && (flags_on & att_nameref))
611 {
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)
619 {
620 refvar = 0;
621 var = make_local_variable (name, inherit_flag);
622 }
623 else if (refvar && refvar->context == variable_context)
624 var = refvar;
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 */
629 }
630 else
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 */
633
634 if (var == 0)
635 {
636 any_failed++;
637 NEXT_VARIABLE ();
638 }
639 if (var && nameref_p (var) && readonly_p (var) && nameref_cell (var) && (flags_off & att_nameref))
640 {
641 sh_readonly (name);
642 any_failed++;
643 NEXT_VARIABLE ();
644 }
645 }
646 else
647 var = (SHELL_VAR *)NULL;
648
649 /* VAR is non-null if we just created or fetched a local variable. */
650
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))
657 {
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)
662 var = 0;
663 }
664
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))
672 {
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)
676 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))
682 {
683 sh_readonly (name);
684 any_failed++;
685 NEXT_VARIABLE ();
686 }
687
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
690 off and go on. */
691 if (refvar && flags_on == 0 && offset == 0 && flags_off == att_nameref)
692 {
693 VUNSETATTR (refvar, att_nameref);
694 NEXT_VARIABLE ();
695 }
696
697 if (refvar)
698 var = declare_find_variable (nameref_cell (refvar), mkglobal, 0);
699 }
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)
705 {
706 var = mkglobal ? find_global_variable_noref (name) : find_variable_noref (name);
707 if (var && nameref_p (var))
708 {
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);
713 }
714 }
715 #endif
716
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.,
719 declare -n foo=bar
720 unset foo # unsets bar
721 declare -i foo
722 foo=4+4
723 declare -p foo
724 */
725 if (var == 0 && (mkglobal || flags_on || flags_off || offset))
726 {
727 refvar = mkglobal ? find_global_variable_last_nameref (name, 0) : find_variable_last_nameref (name, 0);
728 if (refvar && nameref_p (refvar) == 0)
729 refvar = 0;
730 if (refvar)
731 var = declare_find_variable (nameref_cell (refvar), mkglobal, 0);
732 if (refvar && var == 0)
733 {
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);
738 free (name);
739 name = newname;
740
741 if (offset)
742 {
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 */
747 if (offset == 0)
748 {
749 sh_invalidid (name);
750 assign_error++;
751 NEXT_VARIABLE ();
752 }
753 name[(aflags & ASS_APPEND) ? offset - 1 : offset] = '\0';
754 value = name + offset + 1;
755 }
756
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);
761
762 goto restart_new_var_name;
763 /* NOTREACHED */
764 }
765 }
766 if (var == 0)
767 var = declare_find_variable (name, mkglobal, chklocal);
768
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);
775 #endif
776
777 /* Make a new variable if we need to. */
778 if (var == 0)
779 {
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);
785 else
786 #endif
787 var = mkglobal ? bind_global_variable (name, (char *)NULL, ASS_FORCE) : bind_variable (name, (char *)NULL, ASS_FORCE);
788
789 if (var == 0)
790 {
791 /* Has to appear in brackets */
792 NEXT_VARIABLE ();
793 }
794 if (offset == 0)
795 VSETATTR (var, att_invisible);
796 created_var = 1;
797 }
798
799 /* Nameref variable error checking. */
800
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))
803 {
804 builtin_error (_("%s: reference variable cannot be an array"), name);
805 any_failed++;
806 NEXT_VARIABLE ();
807 }
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)
810 {
811 builtin_error (_("`%s': invalid variable name for name reference"), value);
812 any_failed++;
813 NEXT_VARIABLE ();
814 }
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)
819 {
820 builtin_error (_("`%s': invalid variable name for name reference"), value_cell (var));
821 any_failed++;
822 NEXT_VARIABLE ();
823 }
824 /* Can't make an existing readonly variable a nameref. */
825 else if ((flags_on & att_nameref) && readonly_p (var))
826 {
827 sh_readonly (name);
828 any_failed++;
829 NEXT_VARIABLE ();
830 }
831
832 /* Readonly variable error checking. */
833
834 /* Cannot use declare +r to turn off readonly attribute. */
835 if (readonly_p (var) && (flags_off & att_readonly))
836 {
837 sh_readonly (name_cell (var));
838 any_failed++;
839 NEXT_VARIABLE ();
840 }
841 /* Cannot use declare to assign value to readonly or noassign variable. */
842 else if ((readonly_p (var) || noassign_p (var)) && offset)
843 {
844 if (readonly_p (var))
845 sh_readonly (name);
846 assign_error++;
847 NEXT_VARIABLE ();
848 }
849
850 #if defined (ARRAY_VARS)
851 /* Array variable error checking. */
852
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)))
855 {
856 builtin_error (_("%s: cannot destroy array variables in this way"), name);
857 any_failed++;
858 NEXT_VARIABLE ();
859 }
860 else if ((flags_on & att_array) && assoc_p (var))
861 {
862 builtin_error (_("%s: cannot convert associative to indexed array"), name);
863 any_failed++;
864 NEXT_VARIABLE ();
865 }
866 else if ((flags_on & att_assoc) && array_p (var))
867 {
868 builtin_error (_("%s: cannot convert indexed to associative array"), name);
869 any_failed++;
870 NEXT_VARIABLE ();
871 }
872
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)
878 {
879 int vlen;
880 vlen = STRLEN (value);
881 /*itrace("declare_builtin: name = %s value = %s flags = %d", name, value, wflags);*/
882
883 if (shell_compatibility_level > 43 && (wflags & W_COMPASSIGN) == 0 &&
884 value[0] == '(' && value[vlen-1] == ')')
885 {
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;
894 }
895 else if (value[0] == '(' && value[vlen-1] == ')' && (shell_compatibility_level < 44 || (wflags & W_COMPASSIGN)))
896 compound_array_assign = 1;
897 else
898 simple_array_assign = 1;
899 }
900
901 /* declare -A name[[n]] makes name an associative array variable. */
902 if (flags_on & att_assoc)
903 {
904 if (assoc_p (var) == 0)
905 var = convert_var_to_assoc (var);
906 }
907 /* declare -a name[[n]] or declare name[n] makes NAME an indexed
908 array variable. */
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 */
912
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);
916
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)
929 onref = 0;
930 #endif
931
932 /* ksh93 seems to do this */
933 offref = (flags_off & att_nameref);
934 flags_off &= ~att_nameref;
935
936 VSETATTR (var, flags_on);
937 VUNSETATTR (var, flags_off);
938
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)
943 {
944 int local_aflags;
945
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 */
955 {
956 assign_error++;
957 flags_on |= onref;
958 flags_off |= offref;
959 NEXT_VARIABLE ();
960 }
961 }
962 else if (simple_array_assign)
963 {
964 /* let bind_{array,assoc}_variable take care of this. */
965 if (assoc_p (var))
966 bind_assoc_variable (var, name, savestring ("0"), value, aflags|ASS_FORCE);
967 else
968 bind_array_variable (name, 0, value, aflags|ASS_FORCE);
969 }
970 else
971 #endif
972 /* XXX - no ASS_FORCE here */
973 /* bind_variable_value duplicates the essential internals of bind_variable() */
974 if (offset)
975 {
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)))
980 {
981 if (valid_nameref_value (value, 1) == 0)
982 sh_invalidid (value);
983 assign_error++;
984 /* XXX - unset this variable? or leave it as normal var? */
985 if (created_var)
986 delete_var (name_cell (var), mkglobal ? global_variables : shell_variables);
987 flags_on |= onref; /* undo change from above */
988 flags_off |= offref;
989 NEXT_VARIABLE ();
990 }
991 }
992
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
999 global scope.
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))
1003 {
1004 SHELL_VAR *tv;
1005 char *tvalue;
1006
1007 tv = find_tempenv_variable (name_cell (var));
1008 if (tv)
1009 {
1010 tvalue = var_isset (var) ? savestring (value_cell (var)) : savestring ("");
1011 tv = bind_variable (name_cell (var), tvalue, 0);
1012 if (tv)
1013 {
1014 tv->attributes |= var->attributes & ~att_tempvar;
1015 if (tv->context > 0)
1016 VSETATTR (tv, att_propagate);
1017 }
1018 free (tvalue);
1019 }
1020 VSETATTR (var, att_propagate);
1021 }
1022
1023 /* Turn on nameref attribute we deferred above. */
1024 VSETATTR (var, onref);
1025 flags_on |= onref;
1026 VUNSETATTR (var, offref);
1027 flags_off |= offref;
1028
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. */
1033 if (refvar)
1034 {
1035 if (flags_off & att_readonly)
1036 flags_off &= ~att_readonly;
1037 VUNSETATTR (refvar, flags_off);
1038 }
1039
1040 stupidly_hack_special_variables (name);
1041
1042 NEXT_VARIABLE ();
1043 }
1044
1045 return (assign_error ? EX_BADASSIGN
1046 : ((any_failed == 0) ? EXECUTION_SUCCESS
1047 : EXECUTION_FAILURE));
1048 }