]> git.ipfire.org Git - thirdparty/bash.git/blob - builtins/declare.def
Bash-5.2 patch 26: fix typo when specifying readline's custom color prefix
[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-2016 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 [-aAfFgilnrtux] [-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 -p display the attributes and value of each NAME
38
39 Options which set attributes:
40 -a to make NAMEs indexed arrays (if supported)
41 -A to make NAMEs associative arrays (if supported)
42 -i to make NAMEs have the `integer' attribute
43 -l to convert the value of each NAME to lower case on assignment
44 -n make NAME a reference to the variable named by its value
45 -r to make NAMEs readonly
46 -t to make NAMEs have the `trace' attribute
47 -u to convert the value of each NAME to upper case on assignment
48 -x to make NAMEs export
49
50 Using `+' instead of `-' turns off the given attribute.
51
52 Variables with the integer attribute have arithmetic evaluation (see
53 the `let' command) performed when the variable is assigned a value.
54
55 When used in a function, `declare' makes NAMEs local, as with the `local'
56 command. The `-g' option suppresses this behavior.
57
58 Exit Status:
59 Returns success unless an invalid option is supplied or a variable
60 assignment error occurs.
61 $END
62
63 $BUILTIN typeset
64 $FUNCTION declare_builtin
65 $SHORT_DOC typeset [-aAfFgilnrtux] [-p] name[=value] ...
66 Set variable values and attributes.
67
68 A synonym for `declare'. See `help declare'.
69 $END
70
71 #include <config.h>
72
73 #if defined (HAVE_UNISTD_H)
74 # ifdef _MINIX
75 # include <sys/types.h>
76 # endif
77 # include <unistd.h>
78 #endif
79
80 #include <stdio.h>
81
82 #include "../bashansi.h"
83 #include "../bashintl.h"
84
85 #include "../shell.h"
86 #include "../flags.h"
87 #include "common.h"
88 #include "builtext.h"
89 #include "bashgetopt.h"
90
91 static SHELL_VAR *declare_find_variable __P((const char *, int, int));
92 static int declare_internal __P((register WORD_LIST *, int));
93
94 /* Declare or change variable attributes. */
95 int
96 declare_builtin (list)
97 register WORD_LIST *list;
98 {
99 return (declare_internal (list, 0));
100 }
101
102 $BUILTIN local
103 $FUNCTION local_builtin
104 $SHORT_DOC local [option] name[=value] ...
105 Define local variables.
106
107 Create a local variable called NAME, and give it VALUE. OPTION can
108 be any option accepted by `declare'.
109
110 Local variables can only be used within a function; they are visible
111 only to the function where they are defined and its children.
112
113 Exit Status:
114 Returns success unless an invalid option is supplied, a variable
115 assignment error occurs, or the shell is not executing a function.
116 $END
117 int
118 local_builtin (list)
119 register WORD_LIST *list;
120 {
121 /* Catch a straight `local --help' before checking function context */
122 if (list && list->word && STREQ (list->word->word, "--help"))
123 {
124 builtin_help ();
125 return (EX_USAGE);
126 }
127
128 if (variable_context)
129 return (declare_internal (list, 1));
130 else
131 {
132 builtin_error (_("can only be used in a function"));
133 return (EXECUTION_FAILURE);
134 }
135 }
136
137 #if defined (ARRAY_VARS)
138 # define DECLARE_OPTS "+acfgilnprtuxAFG"
139 #else
140 # define DECLARE_OPTS "+cfgilnprtuxFG"
141 #endif
142
143 static SHELL_VAR *
144 declare_find_variable (name, mkglobal, chklocal)
145 const char *name;
146 int mkglobal, chklocal;
147 {
148 SHELL_VAR *var;
149
150 if (mkglobal == 0)
151 return (find_variable (name));
152 else if (chklocal)
153 {
154 var = find_variable (name);
155 if (var && local_p (var) && var->context == variable_context)
156 return var;
157 return (find_global_variable (name));
158 }
159 else
160 return (find_global_variable (name));
161 }
162
163 /* The workhorse function. */
164 static int
165 declare_internal (list, local_var)
166 register WORD_LIST *list;
167 int local_var;
168 {
169 int flags_on, flags_off, *flags;
170 int any_failed, assign_error, pflag, nodefs, opt, onref, offref;
171 int mkglobal, chklocal;
172 char *t, *subscript_start;
173 SHELL_VAR *var, *refvar, *v;
174 FUNCTION_DEF *shell_fn;
175
176 flags_on = flags_off = any_failed = assign_error = pflag = nodefs = 0;
177 mkglobal = chklocal = 0;
178 refvar = (SHELL_VAR *)NULL;
179 reset_internal_getopt ();
180 while ((opt = internal_getopt (list, DECLARE_OPTS)) != -1)
181 {
182 flags = list_opttype == '+' ? &flags_off : &flags_on;
183
184 /* If you add options here, see whether or not they need to be added to
185 the loop in subst.c:shell_expand_word_list() */
186 switch (opt)
187 {
188 case 'a':
189 #if defined (ARRAY_VARS)
190 *flags |= att_array;
191 break;
192 #else
193 builtin_usage ();
194 return (EX_USAGE);
195 #endif
196 case 'A':
197 #if defined (ARRAY_VARS)
198 *flags |= att_assoc;
199 break;
200 #else
201 builtin_usage ();
202 return (EX_USAGE);
203 #endif
204 case 'p':
205 if (local_var == 0)
206 pflag++;
207 break;
208 case 'F':
209 nodefs++;
210 *flags |= att_function;
211 break;
212 case 'f':
213 *flags |= att_function;
214 break;
215 case 'G':
216 if (flags == &flags_on)
217 chklocal = 1;
218 /*FALLTHROUGH*/
219 case 'g':
220 if (flags == &flags_on)
221 mkglobal = 1;
222 break;
223 case 'i':
224 *flags |= att_integer;
225 break;
226 case 'n':
227 *flags |= att_nameref;
228 break;
229 case 'r':
230 *flags |= att_readonly;
231 break;
232 case 't':
233 *flags |= att_trace;
234 break;
235 case 'x':
236 *flags |= att_exported;
237 array_needs_making = 1;
238 break;
239 #if defined (CASEMOD_ATTRS)
240 # if defined (CASEMOD_CAPCASE)
241 case 'c':
242 *flags |= att_capcase;
243 if (flags == &flags_on)
244 flags_off |= att_uppercase|att_lowercase;
245 break;
246 # endif
247 case 'l':
248 *flags |= att_lowercase;
249 if (flags == &flags_on)
250 flags_off |= att_capcase|att_uppercase;
251 break;
252 case 'u':
253 *flags |= att_uppercase;
254 if (flags == &flags_on)
255 flags_off |= att_capcase|att_lowercase;
256 break;
257 #endif /* CASEMOD_ATTRS */
258 CASE_HELPOPT;
259 default:
260 builtin_usage ();
261 return (EX_USAGE);
262 }
263 }
264
265 list = loptend;
266
267 /* If there are no more arguments left, then we just want to show
268 some variables. */
269 if (list == 0) /* declare -[aAfFirtx] */
270 {
271 /* Show local variables defined at this context level if this is
272 the `local' builtin. */
273 if (local_var)
274 {
275 register SHELL_VAR **vlist;
276 register int i;
277
278 vlist = all_local_variables ();
279
280 if (vlist)
281 {
282 for (i = 0; vlist[i]; i++)
283 print_assignment (vlist[i]);
284
285 free (vlist);
286 }
287 }
288 else if (pflag && (flags_on == 0 || flags_on == att_function))
289 show_all_var_attributes (flags_on == 0, nodefs);
290 else if (flags_on == 0)
291 return (set_builtin ((WORD_LIST *)NULL));
292 else
293 set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs);
294
295 return (sh_chkwrite (EXECUTION_SUCCESS));
296 }
297
298 if (pflag) /* declare -p [-aAfFirtx] name [name...] */
299 {
300 for (any_failed = 0; list; list = list->next)
301 {
302 if (flags_on & att_function)
303 pflag = show_func_attributes (list->word->word, nodefs);
304 else
305 pflag = show_name_attributes (list->word->word, nodefs);
306 if (pflag)
307 {
308 sh_notfound (list->word->word);
309 any_failed++;
310 }
311 }
312 return (sh_chkwrite (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS));
313 }
314
315 #define NEXT_VARIABLE() free (name); list = list->next; continue
316
317 /* There are arguments left, so we are making variables. */
318 while (list) /* declare [-aAfFirx] name [name ...] */
319 {
320 char *value, *name, *oldname;
321 int offset, aflags, wflags, created_var, namelen;
322 int assoc_noexpand;
323 #if defined (ARRAY_VARS)
324 int making_array_special, compound_array_assign, simple_array_assign;
325 int var_exists, array_exists, creating_array, array_subscript_assignment;
326 #endif
327
328 name = savestring (list->word->word);
329 wflags = list->word->flags;
330 #if defined (ARRAY_VARS)
331 assoc_noexpand = assoc_expand_once && (wflags & W_ASSIGNMENT);
332 #else
333 assoc_noexpand = 0;
334 #endif
335 offset = assignment (name, assoc_noexpand ? 2 : 0);
336 aflags = 0;
337 created_var = 0;
338
339 if (local_var && variable_context && STREQ (name, "-"))
340 {
341 var = make_local_variable ("-", 0);
342 FREE (value_cell (var)); /* just in case */
343 value = get_current_options ();
344 var_setvalue (var, value);
345 VSETATTR (var, att_invisible);
346 NEXT_VARIABLE ();
347 }
348
349 if (offset) /* declare [-aAfFirx] name=value */
350 {
351 name[offset] = '\0';
352 value = name + offset + 1;
353 if (name[offset - 1] == '+')
354 {
355 aflags |= ASS_APPEND;
356 name[offset - 1] = '\0';
357 }
358 }
359 else
360 value = "";
361
362 /* Do some lexical error checking on the LHS and RHS of the assignment
363 that is specific to nameref variables. */
364 if (flags_on & att_nameref)
365 {
366 #if defined (ARRAY_VARS)
367 if (valid_array_reference (name, 0))
368 {
369 builtin_error (_("%s: reference variable cannot be an array"), name);
370 assign_error++;
371 NEXT_VARIABLE ();
372 }
373 else
374 #endif
375 /* disallow self references at global scope, warn at function scope */
376 if (check_selfref (name, value, 0))
377 {
378 if (variable_context == 0)
379 {
380 builtin_error (_("%s: nameref variable self references not allowed"), name);
381 assign_error++;
382 NEXT_VARIABLE ();
383 }
384 else
385 builtin_warning (_("%s: circular name reference"), name);
386 }
387 #if 1
388 if (value && *value && (aflags & ASS_APPEND) == 0 && valid_nameref_value (value, 1) == 0)
389 {
390 builtin_error (_("`%s': invalid variable name for name reference"), value);
391 assign_error++;
392 NEXT_VARIABLE ();
393 }
394 #endif
395 }
396
397 restart_new_var_name:
398 #if defined (ARRAY_VARS)
399 var_exists = array_exists = creating_array = 0;
400 compound_array_assign = simple_array_assign = 0;
401 array_subscript_assignment = 0;
402 subscript_start = (char *)NULL;
403 if ((t = strchr (name, '[')) && (flags_on & att_function) == 0) /* ] */
404 {
405 /* If offset != 0 we have already validated any array reference
406 because assignment() calls skipsubscript() */
407 if (offset == 0 && valid_array_reference (name, 0) == 0)
408 {
409 sh_invalidid (name);
410 assign_error++;
411 NEXT_VARIABLE ();
412 }
413 subscript_start = t;
414 *t = '\0';
415 making_array_special = 1; /* XXX - should this check offset? */
416 array_subscript_assignment = offset != 0;
417 }
418 else
419 making_array_special = 0;
420 #endif
421
422 /* If we're in posix mode or not looking for a shell function (since
423 shell function names don't have to be valid identifiers when the
424 shell's not in posix mode), check whether or not the argument is a
425 valid, well-formed shell identifier. */
426 if ((posixly_correct || (flags_on & att_function) == 0) && legal_identifier (name) == 0)
427 {
428 sh_invalidid (name);
429 assign_error++;
430 NEXT_VARIABLE ();
431 }
432
433 /* If VARIABLE_CONTEXT has a non-zero value, then we are executing
434 inside of a function. This means we should make local variables,
435 not global ones. */
436
437 /* XXX - this has consequences when we're making a local copy of a
438 variable that was in the temporary environment. Watch out
439 for this. */
440 refvar = (SHELL_VAR *)NULL;
441 if (variable_context && mkglobal == 0 && ((flags_on & att_function) == 0))
442 {
443 char *newname;
444
445 /* check name for validity here? */
446 var = find_variable (name);
447 if (var == 0)
448 newname = nameref_transform_name (name, ASS_MKLOCAL);
449 else if ((flags_on & att_nameref) == 0 && (flags_off & att_nameref) == 0)
450 {
451 /* Ok, we're following namerefs here, so let's make sure that if
452 we followed one, it was at the same context (see below for
453 more details). */
454 refvar = find_variable_last_nameref (name, 1);
455 newname = (refvar && refvar->context != variable_context) ? name : var->name;
456 refvar = (SHELL_VAR *)NULL;
457 }
458 else
459 newname = name; /* dealing with nameref attribute */
460
461 #if defined (ARRAY_VARS)
462 /* Pass 1 as second argument to make_local_{assoc,array}_variable
463 return an existing {array,assoc} variable to be flagged as an
464 error below. */
465 if (flags_on & att_assoc)
466 var = make_local_assoc_variable (newname, 1);
467 else if ((flags_on & att_array) || making_array_special)
468 var = make_local_array_variable (newname, 1);
469 else
470 #endif
471 if (offset == 0 && (flags_on & att_nameref))
472 {
473 /* First look for refvar at current scope */
474 refvar = find_variable_last_nameref (name, 1);
475 /* VARIABLE_CONTEXT != 0, so we are attempting to create or modify
476 the attributes for a local variable at the same scope. If we've
477 used a reference from a previous context to resolve VAR, we
478 want to throw REFVAR and VAR away and create a new local var. */
479 if (refvar && refvar->context != variable_context)
480 {
481 refvar = 0;
482 var = make_local_variable (name, 0);
483 }
484 else if (refvar && refvar->context == variable_context)
485 var = refvar;
486 /* Maybe we just want to create a new local variable */
487 else if (var == 0 || var->context != variable_context)
488 var = make_local_variable (name, 0);
489 /* otherwise we have a var at the right context */
490 }
491 else
492 /* XXX - check name for validity here with valid_nameref_value */
493 var = make_local_variable ((flags_on & att_nameref) ? name : newname, 0); /* sets att_invisible for new vars */
494
495 if (var == 0)
496 {
497 any_failed++;
498 NEXT_VARIABLE ();
499 }
500 if (var && nameref_p (var) && readonly_p (var) && nameref_cell (var) && (flags_off & att_nameref))
501 {
502 sh_readonly (name);
503 any_failed++;
504 NEXT_VARIABLE ();
505 }
506 }
507 else
508 var = (SHELL_VAR *)NULL;
509
510 /* If we are declaring a function, then complain about it in some way.
511 We don't let people make functions by saying `typeset -f foo=bar'. */
512
513 /* There should be a way, however, to let people look at a particular
514 function definition by saying `typeset -f foo'. */
515
516 if (flags_on & att_function)
517 {
518 if (offset) /* declare -f [-rix] foo=bar */
519 {
520 builtin_error (_("cannot use `-f' to make functions"));
521 free (name);
522 return (EXECUTION_FAILURE);
523 }
524 else /* declare -f [-rx] name [name...] */
525 {
526 var = find_function (name);
527
528 if (var)
529 {
530 if (readonly_p (var) && (flags_off & att_readonly))
531 {
532 builtin_error (_("%s: readonly function"), name);
533 any_failed++;
534 NEXT_VARIABLE ();
535 }
536
537 /* declare -[Ff] name [name...] */
538 if (flags_on == att_function && flags_off == 0)
539 {
540 #if defined (DEBUGGER)
541 if (nodefs && debugging_mode)
542 {
543 shell_fn = find_function_def (var->name);
544 if (shell_fn)
545 printf ("%s %d %s\n", var->name, shell_fn->line, shell_fn->source_file);
546 else
547 printf ("%s\n", var->name);
548 }
549 else
550 #endif /* DEBUGGER */
551 {
552 t = nodefs ? var->name
553 : named_function_string (name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL);
554 printf ("%s\n", t);
555 any_failed = sh_chkwrite (any_failed);
556 }
557 }
558 else /* declare -[fF] -[rx] name [name...] */
559 {
560 VSETATTR (var, flags_on);
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 && no_invisible_vars == 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 && no_invisible_vars == 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 && no_invisible_vars == 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 }