]> git.ipfire.org Git - thirdparty/bash.git/blob - builtins/declare.def
bash-5.1 beta release
[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-2020 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] [-p] [name[=value] ...]
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] [-p] name[=value] ...
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 int declare_internal PARAMS((register WORD_LIST *, int));
95
96 /* Declare or change variable attributes. */
97 int
98 declare_builtin (list)
99 register WORD_LIST *list;
100 {
101 return (declare_internal (list, 0));
102 }
103
104 $BUILTIN local
105 $FUNCTION local_builtin
106 $SHORT_DOC local [option] name[=value] ...
107 Define local variables.
108
109 Create a local variable called NAME, and give it VALUE. OPTION can
110 be any option accepted by `declare'.
111
112 Local variables can only be used within a function; they are visible
113 only to the function where they are defined and its children.
114
115 Exit Status:
116 Returns success unless an invalid option is supplied, a variable
117 assignment error occurs, or the shell is not executing a function.
118 $END
119 int
120 local_builtin (list)
121 register WORD_LIST *list;
122 {
123 /* Catch a straight `local --help' before checking function context */
124 if (list && list->word && STREQ (list->word->word, "--help"))
125 {
126 builtin_help ();
127 return (EX_USAGE);
128 }
129
130 if (variable_context)
131 return (declare_internal (list, 1));
132 else
133 {
134 builtin_error (_("can only be used in a function"));
135 return (EXECUTION_FAILURE);
136 }
137 }
138
139 #if defined (ARRAY_VARS)
140 # define DECLARE_OPTS "+acfgilnprtuxAFGI"
141 #else
142 # define DECLARE_OPTS "+cfgilnprtuxFGI"
143 #endif
144
145 static SHELL_VAR *
146 declare_find_variable (name, mkglobal, chklocal)
147 const char *name;
148 int mkglobal, chklocal;
149 {
150 SHELL_VAR *var;
151
152 if (mkglobal == 0)
153 return (find_variable (name));
154 else if (chklocal)
155 {
156 var = find_variable (name);
157 if (var && local_p (var) && var->context == variable_context)
158 return var;
159 return (find_global_variable (name));
160 }
161 else
162 return (find_global_variable (name));
163 }
164
165 /* The workhorse function. */
166 static int
167 declare_internal (list, local_var)
168 register WORD_LIST *list;
169 int local_var;
170 {
171 int flags_on, flags_off, *flags;
172 int any_failed, assign_error, pflag, nodefs, opt, onref, offref;
173 int mkglobal, chklocal, inherit_flag;
174 char *t, *subscript_start;
175 SHELL_VAR *var, *refvar, *v;
176 FUNCTION_DEF *shell_fn;
177
178 flags_on = flags_off = any_failed = assign_error = pflag = nodefs = 0;
179 mkglobal = chklocal = inherit_flag = 0;
180 refvar = (SHELL_VAR *)NULL;
181 reset_internal_getopt ();
182 while ((opt = internal_getopt (list, DECLARE_OPTS)) != -1)
183 {
184 flags = list_opttype == '+' ? &flags_off : &flags_on;
185
186 /* If you add options here, see whether or not they need to be added to
187 the loop in subst.c:shell_expand_word_list() */
188 switch (opt)
189 {
190 case 'a':
191 #if defined (ARRAY_VARS)
192 *flags |= att_array;
193 break;
194 #else
195 builtin_usage ();
196 return (EX_USAGE);
197 #endif
198 case 'A':
199 #if defined (ARRAY_VARS)
200 *flags |= att_assoc;
201 break;
202 #else
203 builtin_usage ();
204 return (EX_USAGE);
205 #endif
206 case 'p':
207 /* if (local_var == 0) */
208 pflag++;
209 break;
210 case 'F':
211 nodefs++;
212 *flags |= att_function;
213 break;
214 case 'f':
215 *flags |= att_function;
216 break;
217 case 'G':
218 if (flags == &flags_on)
219 chklocal = 1;
220 /*FALLTHROUGH*/
221 case 'g':
222 if (flags == &flags_on)
223 mkglobal = 1;
224 break;
225 case 'i':
226 *flags |= att_integer;
227 break;
228 case 'n':
229 *flags |= att_nameref;
230 break;
231 case 'r':
232 *flags |= att_readonly;
233 break;
234 case 't':
235 *flags |= att_trace;
236 break;
237 case 'x':
238 *flags |= att_exported;
239 array_needs_making = 1;
240 break;
241 #if defined (CASEMOD_ATTRS)
242 # if defined (CASEMOD_CAPCASE)
243 case 'c':
244 *flags |= att_capcase;
245 if (flags == &flags_on)
246 flags_off |= att_uppercase|att_lowercase;
247 break;
248 # endif
249 case 'l':
250 *flags |= att_lowercase;
251 if (flags == &flags_on)
252 flags_off |= att_capcase|att_uppercase;
253 break;
254 case 'u':
255 *flags |= att_uppercase;
256 if (flags == &flags_on)
257 flags_off |= att_capcase|att_lowercase;
258 break;
259 #endif /* CASEMOD_ATTRS */
260 case 'I':
261 inherit_flag = MKLOC_INHERIT;
262 break;
263 CASE_HELPOPT;
264 default:
265 builtin_usage ();
266 return (EX_USAGE);
267 }
268 }
269
270 list = loptend;
271
272 /* If there are no more arguments left, then we just want to show
273 some variables. */
274 if (list == 0) /* declare -[aAfFirtx] */
275 {
276 /* Show local variables defined at this context level if this is
277 the `local' builtin. */
278 if (local_var)
279 show_local_var_attributes (0, nodefs); /* XXX - fix up args later */
280 else if (pflag && (flags_on == 0 || flags_on == att_function))
281 show_all_var_attributes (flags_on == 0, nodefs);
282 else if (flags_on == 0)
283 return (set_builtin ((WORD_LIST *)NULL));
284 else
285 set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs);
286
287 return (sh_chkwrite (EXECUTION_SUCCESS));
288 }
289
290 if (pflag) /* declare -p [-aAfFirtx] name [name...] */
291 {
292 for (any_failed = 0; list; list = list->next)
293 {
294 if (flags_on & att_function)
295 pflag = show_func_attributes (list->word->word, nodefs);
296 else if (local_var)
297 pflag = show_localname_attributes (list->word->word, nodefs);
298 else
299 pflag = show_name_attributes (list->word->word, nodefs);
300 if (pflag)
301 {
302 sh_notfound (list->word->word);
303 any_failed++;
304 }
305 }
306 return (sh_chkwrite (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS));
307 }
308
309 #define NEXT_VARIABLE() free (name); list = list->next; continue
310
311 /* There are arguments left, so we are making variables. */
312 while (list) /* declare [-aAfFirx] name [name ...] */
313 {
314 char *value, *name, *oldname;
315 int offset, aflags, wflags, created_var, namelen;
316 int assoc_noexpand;
317 #if defined (ARRAY_VARS)
318 int making_array_special, compound_array_assign, simple_array_assign;
319 int var_exists, array_exists, creating_array, array_subscript_assignment;
320 #endif
321
322 name = savestring (list->word->word);
323 wflags = list->word->flags;
324 #if defined (ARRAY_VARS)
325 assoc_noexpand = assoc_expand_once && (wflags & W_ASSIGNMENT);
326 #else
327 assoc_noexpand = 0;
328 #endif
329 offset = assignment (name, assoc_noexpand ? 2 : 0);
330 aflags = 0;
331 created_var = 0;
332
333 if (local_var && variable_context && STREQ (name, "-"))
334 {
335 var = make_local_variable ("-", 0);
336 FREE (value_cell (var)); /* just in case */
337 value = get_current_options ();
338 var_setvalue (var, value);
339 VSETATTR (var, att_invisible);
340 NEXT_VARIABLE ();
341 }
342
343 if (offset) /* declare [-aAfFirx] name=value */
344 {
345 name[offset] = '\0';
346 value = name + offset + 1;
347 if (name[offset - 1] == '+')
348 {
349 aflags |= ASS_APPEND;
350 name[offset - 1] = '\0';
351 }
352 }
353 else
354 value = "";
355
356 /* Do some lexical error checking on the LHS and RHS of the assignment
357 that is specific to nameref variables. */
358 if (flags_on & att_nameref)
359 {
360 #if defined (ARRAY_VARS)
361 if (valid_array_reference (name, 0))
362 {
363 builtin_error (_("%s: reference variable cannot be an array"), name);
364 assign_error++;
365 NEXT_VARIABLE ();
366 }
367 else
368 #endif
369 /* disallow self references at global scope, warn at function scope */
370 if (check_selfref (name, value, 0))
371 {
372 if (variable_context == 0)
373 {
374 builtin_error (_("%s: nameref variable self references not allowed"), name);
375 assign_error++;
376 NEXT_VARIABLE ();
377 }
378 else
379 builtin_warning (_("%s: circular name reference"), name);
380 }
381 #if 1
382 if (value && *value && (aflags & ASS_APPEND) == 0 && valid_nameref_value (value, 1) == 0)
383 {
384 builtin_error (_("`%s': invalid variable name for name reference"), value);
385 assign_error++;
386 NEXT_VARIABLE ();
387 }
388 #endif
389 }
390
391 restart_new_var_name:
392 #if defined (ARRAY_VARS)
393 var_exists = array_exists = creating_array = 0;
394 compound_array_assign = simple_array_assign = 0;
395 array_subscript_assignment = 0;
396 subscript_start = (char *)NULL;
397 if ((t = strchr (name, '[')) && (flags_on & att_function) == 0) /* ] */
398 {
399 /* If offset != 0 we have already validated any array reference
400 because assignment() calls skipsubscript() */
401 if (offset == 0 && valid_array_reference (name, 0) == 0)
402 {
403 sh_invalidid (name);
404 assign_error++;
405 NEXT_VARIABLE ();
406 }
407 subscript_start = t;
408 *t = '\0';
409 making_array_special = 1; /* XXX - should this check offset? */
410 array_subscript_assignment = offset != 0;
411 }
412 else
413 making_array_special = 0;
414 #endif
415
416 /* If we're in posix mode or not looking for a shell function (since
417 shell function names don't have to be valid identifiers when the
418 shell's not in posix mode), check whether or not the argument is a
419 valid, well-formed shell identifier. */
420 if ((posixly_correct || (flags_on & att_function) == 0) && legal_identifier (name) == 0)
421 {
422 sh_invalidid (name);
423 assign_error++;
424 NEXT_VARIABLE ();
425 }
426
427 /* If VARIABLE_CONTEXT has a non-zero value, then we are executing
428 inside of a function. This means we should make local variables,
429 not global ones. */
430
431 /* XXX - this has consequences when we're making a local copy of a
432 variable that was in the temporary environment. Watch out
433 for this. */
434 refvar = (SHELL_VAR *)NULL;
435 if (variable_context && mkglobal == 0 && ((flags_on & att_function) == 0))
436 {
437 char *newname;
438
439 /* check name for validity here? */
440 var = find_variable (name);
441 if (var == 0)
442 newname = nameref_transform_name (name, ASS_MKLOCAL);
443 else if ((flags_on & att_nameref) == 0 && (flags_off & att_nameref) == 0)
444 {
445 /* Ok, we're following namerefs here, so let's make sure that if
446 we followed one, it was at the same context (see below for
447 more details). */
448 refvar = find_variable_last_nameref (name, 1);
449 newname = (refvar && refvar->context != variable_context) ? name : var->name;
450 refvar = (SHELL_VAR *)NULL;
451 }
452 else
453 newname = name; /* dealing with nameref attribute */
454
455 #if defined (ARRAY_VARS)
456 /* Pass 1 as second argument to make_local_{assoc,array}_variable
457 return an existing {array,assoc} variable to be flagged as an
458 error below. */
459 if (flags_on & att_assoc)
460 var = make_local_assoc_variable (newname, MKLOC_ARRAYOK|inherit_flag);
461 else if ((flags_on & att_array) || making_array_special)
462 var = make_local_array_variable (newname, MKLOC_ASSOCOK|inherit_flag);
463 else
464 #endif
465 if (offset == 0 && (flags_on & att_nameref))
466 {
467 /* First look for refvar at current scope */
468 refvar = find_variable_last_nameref (name, 1);
469 /* VARIABLE_CONTEXT != 0, so we are attempting to create or modify
470 the attributes for a local variable at the same scope. If we've
471 used a reference from a previous context to resolve VAR, we
472 want to throw REFVAR and VAR away and create a new local var. */
473 if (refvar && refvar->context != variable_context)
474 {
475 refvar = 0;
476 var = make_local_variable (name, inherit_flag);
477 }
478 else if (refvar && refvar->context == variable_context)
479 var = refvar;
480 /* Maybe we just want to create a new local variable */
481 else if (var == 0 || var->context != variable_context)
482 var = make_local_variable (name, inherit_flag);
483 /* otherwise we have a var at the right context */
484 }
485 else
486 /* XXX - check name for validity here with valid_nameref_value */
487 var = make_local_variable ((flags_on & att_nameref) ? name : newname, inherit_flag); /* sets att_invisible for new vars */
488
489 if (var == 0)
490 {
491 any_failed++;
492 NEXT_VARIABLE ();
493 }
494 if (var && nameref_p (var) && readonly_p (var) && nameref_cell (var) && (flags_off & att_nameref))
495 {
496 sh_readonly (name);
497 any_failed++;
498 NEXT_VARIABLE ();
499 }
500 }
501 else
502 var = (SHELL_VAR *)NULL;
503
504 /* If we are declaring a function, then complain about it in some way.
505 We don't let people make functions by saying `typeset -f foo=bar'. */
506
507 /* There should be a way, however, to let people look at a particular
508 function definition by saying `typeset -f foo'. */
509
510 if (flags_on & att_function)
511 {
512 if (offset) /* declare -f [-rix] foo=bar */
513 {
514 builtin_error (_("cannot use `-f' to make functions"));
515 free (name);
516 return (EXECUTION_FAILURE);
517 }
518 else /* declare -f [-rx] name [name...] */
519 {
520 var = find_function (name);
521
522 if (var)
523 {
524 if (readonly_p (var) && (flags_off & att_readonly))
525 {
526 builtin_error (_("%s: readonly function"), name);
527 any_failed++;
528 NEXT_VARIABLE ();
529 }
530 else if (flags_on & (att_array|att_assoc))
531 {
532 sh_invalidopt ((flags_on & att_array) ? "-a" : "-A");
533 any_failed++;
534 NEXT_VARIABLE ();
535 }
536 /* declare -[Ff] name [name...] */
537 if (flags_on == att_function && flags_off == 0)
538 {
539 #if defined (DEBUGGER)
540 if (nodefs && debugging_mode)
541 {
542 shell_fn = find_function_def (var->name);
543 if (shell_fn)
544 printf ("%s %d %s\n", var->name, shell_fn->line, shell_fn->source_file);
545 else
546 printf ("%s\n", var->name);
547 }
548 else
549 #endif /* DEBUGGER */
550 {
551 t = nodefs ? var->name
552 : named_function_string (name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL);
553 printf ("%s\n", t);
554 any_failed = sh_chkwrite (any_failed);
555 }
556 }
557 else /* declare -[fF] -[rx] name [name...] */
558 {
559 VSETATTR (var, flags_on);
560 flags_off &= ~att_function; /* makes no sense */
561 VUNSETATTR (var, flags_off);
562 }
563 }
564 else
565 any_failed++;
566 NEXT_VARIABLE ();
567 }
568 }
569 else /* declare -[aAinrx] name [name...] */
570 {
571 /* Non-null if we just created or fetched a local variable. */
572 #if 0
573 /* This is bash-4.3 code. */
574 /* Here's what ksh93 seems to do. If we are modifying an existing
575 nameref variable, we don't follow the nameref chain past the last
576 nameref, and we set the nameref variable's value so future
577 references to that variable will return the value of the variable
578 we're assigning right now. */
579 #else
580 /* Here's what ksh93 seems to do as of the 2012 version: if we are
581 using declare -n to modify the value of an existing nameref
582 variable, don't follow the nameref chain at all and just search
583 for a nameref at the current context. If we have a nameref,
584 modify its value (changing which variable it references). */
585 #endif
586 if (var == 0 && (flags_on & att_nameref))
587 {
588 /* See if we are trying to modify an existing nameref variable,
589 but don't follow the nameref chain. */
590 var = mkglobal ? find_global_variable_noref (name) : find_variable_noref (name);
591 if (var && nameref_p (var) == 0)
592 var = 0;
593 }
594 /* However, if we're turning off the nameref attribute on an existing
595 nameref variable, we first follow the nameref chain to the end,
596 modify the value of the variable this nameref variable references
597 if there is an assignment statement argument,
598 *CHANGING ITS VALUE AS A SIDE EFFECT*, then turn off the nameref
599 flag *LEAVING THE NAMEREF VARIABLE'S VALUE UNCHANGED* */
600 else if (var == 0 && (flags_off & att_nameref))
601 {
602 /* See if we are trying to modify an existing nameref variable */
603 refvar = mkglobal ? find_global_variable_last_nameref (name, 0) : find_variable_last_nameref (name, 0);
604 if (refvar && nameref_p (refvar) == 0)
605 refvar = 0;
606 /* If the nameref is readonly but doesn't have a value, ksh93
607 allows the nameref attribute to be removed. If it's readonly
608 and has a value, even if the value doesn't reference an
609 existing variable, we disallow the modification */
610 if (refvar && nameref_cell (refvar) && readonly_p (refvar))
611 {
612 sh_readonly (name);
613 any_failed++;
614 NEXT_VARIABLE ();
615 }
616
617 /* If all we're doing is turning off the nameref attribute, don't
618 bother with VAR at all, whether it exists or not. Just turn it
619 off and go on. */
620 if (refvar && flags_on == 0 && offset == 0 && (flags_off & ~att_nameref) == 0)
621 {
622 VUNSETATTR (refvar, att_nameref);
623 NEXT_VARIABLE ();
624 }
625
626 if (refvar)
627 /* XXX - use declare_find_variable here? */
628 var = mkglobal ? find_global_variable (nameref_cell (refvar)) : find_variable (nameref_cell (refvar));
629 }
630 #if defined (ARRAY_VARS)
631 /* If we have an array assignment to a nameref, remove the nameref
632 attribute and go on. */
633 else if (var == 0 && offset && array_subscript_assignment)
634 {
635 var = mkglobal ? find_global_variable_noref (name) : find_variable_noref (name);
636 if (var && nameref_p (var))
637 {
638 internal_warning (_("%s: removing nameref attribute"), name);
639 FREE (value_cell (var)); /* XXX - bash-4.3 compat */
640 var_setvalue (var, (char *)NULL);
641 VUNSETATTR (var, att_nameref);
642 }
643 }
644 #endif
645
646 /* See if we are trying to set flags or value (or create) for an
647 existing nameref that points to a non-existent variable: e.g.,
648 declare -n foo=bar
649 unset foo # unsets bar
650 declare -i foo
651 foo=4+4
652 declare -p foo */
653 if (var == 0 && (mkglobal || flags_on || flags_off || offset))
654 {
655 refvar = mkglobal ? find_global_variable_last_nameref (name, 0) : find_variable_last_nameref (name, 0);
656 if (refvar && nameref_p (refvar) == 0)
657 refvar = 0;
658 if (refvar)
659 /* XXX - use declare_find_variable here? */
660 var = mkglobal ? find_global_variable (nameref_cell (refvar)) : find_variable (nameref_cell (refvar));
661 if (refvar && var == 0)
662 {
663 oldname = name; /* need to free this */
664
665 namelen = strlen (nameref_cell (refvar));
666 #if defined (ARRAY_VARS)
667 if (subscript_start)
668 {
669 *subscript_start = '['; /*]*/
670 namelen += strlen (subscript_start);
671 }
672 #endif
673 name = xmalloc (namelen + 2 + strlen (value) + 1);
674 strcpy (name, nameref_cell (refvar));
675 #if defined (ARRAY_VARS)
676 if (subscript_start)
677 strcpy (name + strlen (nameref_cell (refvar)), subscript_start);
678 #endif
679 /* We are committed to using the new name, so reset */
680 if (offset)
681 {
682 /* Rebuild assignment and restore offset and value */
683 if (aflags & ASS_APPEND)
684 name[namelen++] = '+';
685 name[namelen++] = '=';
686 if (value && *value)
687 strcpy (name + namelen, value);
688 else
689 name[namelen] = '\0';
690 offset = assignment (name, 0);
691 /* if offset was valid previously, but the substituting
692 of the nameref value results in an invalid assignment,
693 throw an invalid identifier error */
694 if (offset == 0)
695 {
696 free (oldname);
697 sh_invalidid (name);
698 assign_error++;
699 NEXT_VARIABLE ();
700 }
701 name[offset] = '\0';
702 value = name + namelen;
703 }
704 free (oldname);
705
706 /* OK, let's turn off the nameref attribute.
707 Now everything else applies to VAR. */
708 if (flags_off & att_nameref)
709 VUNSETATTR (refvar, att_nameref);
710
711 goto restart_new_var_name;
712 /* NOTREACHED */
713 }
714 }
715 if (var == 0)
716 var = declare_find_variable (name, mkglobal, chklocal);
717
718 #if defined (ARRAY_VARS)
719 var_exists = var != 0;
720 array_exists = var && (array_p (var) || assoc_p (var));
721 creating_array = flags_on & (att_array|att_assoc);
722 #endif
723
724 if (var == 0)
725 {
726 #if defined (ARRAY_VARS)
727 if (flags_on & att_assoc)
728 {
729 var = make_new_assoc_variable (name);
730 if (var && offset == 0)
731 VSETATTR (var, att_invisible);
732 }
733 else if ((flags_on & att_array) || making_array_special)
734 {
735 var = make_new_array_variable (name);
736 if (var && offset == 0)
737 VSETATTR (var, att_invisible);
738 }
739 else
740 #endif
741 {
742 var = mkglobal ? bind_global_variable (name, (char *)NULL, ASS_FORCE) : bind_variable (name, (char *)NULL, ASS_FORCE);
743 if (var && offset == 0)
744 VSETATTR (var, att_invisible);
745 }
746 if (var == 0)
747 {
748 /* Has to appear in brackets */
749 NEXT_VARIABLE ();
750 }
751 created_var = 1;
752 }
753 /* Can't take an existing array variable and make it a nameref */
754 else if ((array_p (var) || assoc_p (var)) && (flags_on & att_nameref))
755 {
756 builtin_error (_("%s: reference variable cannot be an array"), name);
757 assign_error++;
758 NEXT_VARIABLE ();
759 }
760 else if (nameref_p (var) && (flags_on & att_nameref) == 0 && (flags_off & att_nameref) == 0 && offset && valid_nameref_value (value, 1) == 0)
761 {
762 builtin_error (_("`%s': invalid variable name for name reference"), value);
763 any_failed++;
764 NEXT_VARIABLE ();
765 }
766 else if (flags_on & att_nameref)
767 {
768 #if 1
769 /* Check of offset is to allow an assignment to a nameref var as
770 part of the declare word to override existing value */
771 if (nameref_p (var) == 0 && var_isset (var) && offset == 0 && valid_nameref_value (value_cell (var), 0) == 0)
772 {
773 builtin_error (_("`%s': invalid variable name for name reference"), value_cell (var));
774 any_failed++;
775 NEXT_VARIABLE ();
776 }
777 #endif
778 if (readonly_p (var))
779 {
780 sh_readonly (name);
781 any_failed++;
782 NEXT_VARIABLE ();
783 }
784 /* ksh93 compat: turning on nameref attribute turns off -ilu */
785 VUNSETATTR (var, att_integer|att_uppercase|att_lowercase|att_capcase);
786 }
787
788 /* Cannot use declare +r to turn off readonly attribute. */
789 if (readonly_p (var) && (flags_off & att_readonly))
790 {
791 sh_readonly (name_cell (var));
792 any_failed++;
793 NEXT_VARIABLE ();
794 }
795
796 /* Cannot use declare to assign value to readonly or noassign
797 variable. */
798 if ((readonly_p (var) || noassign_p (var)) && offset)
799 {
800 if (readonly_p (var))
801 sh_readonly (name);
802 assign_error++;
803 NEXT_VARIABLE ();
804 }
805
806 #if defined (ARRAY_VARS)
807 /* make declare a[2]=foo as similar to a[2]=foo as possible if
808 a is already an array or assoc variable. */
809 if (array_subscript_assignment && array_exists && creating_array == 0)
810 simple_array_assign = 1;
811 else if ((making_array_special || creating_array || array_exists) && offset)
812 {
813 int vlen;
814 vlen = STRLEN (value);
815 /*itrace("declare_builtin: name = %s value = %s flags = %d", name, value, wflags);*/
816 if (shell_compatibility_level > 43 && (wflags & W_COMPASSIGN) == 0 &&
817 value[0] == '(' && value[vlen-1] == ')')
818 {
819 /* The warning is only printed when using compound assignment
820 to an array variable that doesn't already exist. We use
821 creating_array to allow things like
822 declare -a foo$bar='(abc)' to work. */
823 if (array_exists == 0 && creating_array == 0)
824 internal_warning (_("%s: quoted compound array assignment deprecated"), list->word->word);
825 compound_array_assign = array_exists || creating_array;
826 simple_array_assign = making_array_special;
827 }
828 else if (value[0] == '(' && value[vlen-1] == ')' && (shell_compatibility_level < 44 || (wflags & W_COMPASSIGN)))
829 compound_array_assign = 1;
830 else
831 simple_array_assign = 1;
832 }
833
834 /* Cannot use declare +a name or declare +A name to remove an
835 array variable. */
836 if (((flags_off & att_array) && array_p (var)) || ((flags_off & att_assoc) && assoc_p (var)))
837 {
838 builtin_error (_("%s: cannot destroy array variables in this way"), name);
839 any_failed++;
840 NEXT_VARIABLE ();
841 }
842
843 if ((flags_on & att_array) && assoc_p (var))
844 {
845 builtin_error (_("%s: cannot convert associative to indexed array"), name);
846 any_failed++;
847 NEXT_VARIABLE ();
848 }
849 if ((flags_on & att_assoc) && array_p (var))
850 {
851 builtin_error (_("%s: cannot convert indexed to associative array"), name);
852 any_failed++;
853 NEXT_VARIABLE ();
854 }
855
856 /* declare -A name[[n]] makes name an associative array variable. */
857 if (flags_on & att_assoc)
858 {
859 if (assoc_p (var) == 0)
860 var = convert_var_to_assoc (var);
861 }
862 /* declare -a name[[n]] or declare name[n] makes name an indexed
863 array variable. */
864 else if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0 && assoc_p (var) == 0)
865 var = convert_var_to_array (var);
866 #endif /* ARRAY_VARS */
867
868 /* XXX - we note that we are turning on nameref attribute and defer
869 setting it until the assignment has been made so we don't do an
870 inadvertent nameref lookup. Might have to do the same thing for
871 flags_off&att_nameref. */
872 /* XXX - ksh93 makes it an error to set a readonly nameref variable
873 using a single typeset command. */
874 onref = (flags_on & att_nameref);
875 flags_on &= ~att_nameref;
876 #if defined (ARRAY_VARS)
877 if (array_p (var) || assoc_p (var)
878 || (offset && compound_array_assign)
879 || simple_array_assign)
880 onref = 0; /* array variables may not be namerefs */
881 #endif
882
883 /* ksh93 seems to do this */
884 offref = (flags_off & att_nameref);
885 flags_off &= ~att_nameref;
886
887 VSETATTR (var, flags_on);
888 VUNSETATTR (var, flags_off);
889
890 #if defined (ARRAY_VARS)
891 if (offset && compound_array_assign)
892 assign_array_var_from_string (var, value, aflags|ASS_FORCE);
893 else if (simple_array_assign && subscript_start)
894 {
895 int local_aflags;
896 /* declare [-aA] name[N]=value */
897 *subscript_start = '['; /* ] */
898 /* XXX - problem here with appending */
899 local_aflags = aflags&ASS_APPEND;
900 local_aflags |= assoc_noexpand ? ASS_NOEXPAND : 0;
901 var = assign_array_element (name, value, local_aflags); /* XXX - not aflags */
902 *subscript_start = '\0';
903 if (var == 0) /* some kind of assignment error */
904 {
905 assign_error++;
906 flags_on |= onref;
907 flags_off |= offref;
908 NEXT_VARIABLE ();
909 }
910 }
911 else if (simple_array_assign)
912 {
913 /* let bind_{array,assoc}_variable take care of this. */
914 if (assoc_p (var))
915 bind_assoc_variable (var, name, savestring ("0"), value, aflags|ASS_FORCE);
916 else
917 bind_array_variable (name, 0, value, aflags|ASS_FORCE);
918 }
919 else
920 #endif
921 /* XXX - no ASS_FORCE here */
922 /* bind_variable_value duplicates the essential internals of
923 bind_variable() */
924 if (offset)
925 {
926 if (onref || nameref_p (var))
927 aflags |= ASS_NAMEREF;
928 v = bind_variable_value (var, value, aflags);
929 if (v == 0 && (onref || nameref_p (var)))
930 {
931 if (valid_nameref_value (value, 1) == 0)
932 sh_invalidid (value);
933 assign_error++;
934 /* XXX - unset this variable? or leave it as normal var? */
935 if (created_var)
936 delete_var (var->name, mkglobal ? global_variables : shell_variables);
937 flags_on |= onref; /* undo change from above */
938 flags_off |= offref;
939 NEXT_VARIABLE ();
940 }
941 }
942
943 /* If we found this variable in the temporary environment, as with
944 `var=value declare -x var', make sure it is treated identically
945 to `var=value export var'. Do the same for `declare -r' and
946 `readonly'. Preserve the attributes, except for att_tempvar. */
947 /* XXX -- should this create a variable in the global scope, or
948 modify the local variable flags? ksh93 has it modify the
949 global scope.
950 Need to handle case like in set_var_attribute where a temporary
951 variable is in the same table as the function local vars. */
952 if ((flags_on & (att_exported|att_readonly)) && tempvar_p (var))
953 {
954 SHELL_VAR *tv;
955 char *tvalue;
956
957 tv = find_tempenv_variable (var->name);
958 if (tv)
959 {
960 tvalue = var_isset (var) ? savestring (value_cell (var)) : savestring ("");
961 tv = bind_variable (var->name, tvalue, 0);
962 if (tv)
963 {
964 tv->attributes |= var->attributes & ~att_tempvar;
965 if (tv->context > 0)
966 VSETATTR (tv, att_propagate);
967 }
968 free (tvalue);
969 }
970 VSETATTR (var, att_propagate);
971 }
972 }
973
974 /* Turn on nameref attribute we deferred above. */
975 /* XXX - should we turn on the noassign attribute for consistency with
976 ksh93 when we turn on the nameref attribute? */
977 VSETATTR (var, onref);
978 flags_on |= onref;
979 VUNSETATTR (var, offref);
980 flags_off |= offref;
981 /* Yuck. ksh93 compatibility. XXX - need to investigate more but
982 definitely happens when turning off nameref attribute on nameref
983 (see comments above). Under no circumstances allow this to turn
984 off readonly attribute on readonly nameref variable. */
985 if (refvar)
986 {
987 if (flags_off & att_readonly)
988 flags_off &= ~att_readonly;
989 VUNSETATTR (refvar, flags_off);
990 }
991
992 stupidly_hack_special_variables (name);
993
994 NEXT_VARIABLE ();
995 }
996
997 return (assign_error ? EX_BADASSIGN
998 : ((any_failed == 0) ? EXECUTION_SUCCESS
999 : EXECUTION_FAILURE));
1000 }