improve of cmpl.
[bush.git] / builtins / declare.def
blob51b4653e05e8721048a4928dbca3b67384665eb5
1 This file is declare.def, from which is created declare.c.
2 It implements the builtins "declare" and "local" in Bush.
4 Copyright (C) 1987-2020 Free Software Foundation, Inc.
6 This file is part of GNU Bush, the Bourne Again SHell.
8 Bush is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 Bush is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Bush. If not, see <http://www.gnu.org/licenses/>.
21 $PRODUCES declare.c
23 $BUILTIN declare
24 $FUNCTION declare_builtin
25 $SHORT_DOC declare [-aAfFgiIlnrtux] [-p] [name[=value] ...]
26 Set variable values and attributes.
28 Declare variables and give them attributes. If no NAMEs are given,
29 display the attributes and values of all variables.
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
41 Options which set attributes:
42 -a to make NAMEs indexed arrays (if supported)
43 -A to make NAMEs associative arrays (if supported)
44 -i to make NAMEs have the `integer' attribute
45 -l to convert the value of each NAME to lower case on assignment
46 -n make NAME a reference to the variable named by its value
47 -r to make NAMEs readonly
48 -t to make NAMEs have the `trace' attribute
49 -u to convert the value of each NAME to upper case on assignment
50 -x to make NAMEs export
52 Using `+' instead of `-' turns off the given attribute.
54 Variables with the integer attribute have arithmetic evaluation (see
55 the `let' command) performed when the variable is assigned a value.
57 When used in a function, `declare' makes NAMEs local, as with the `local'
58 command. The `-g' option suppresses this behavior.
60 Exit Status:
61 Returns success unless an invalid option is supplied or a variable
62 assignment error occurs.
63 $END
65 $BUILTIN typeset
66 $FUNCTION declare_builtin
67 $SHORT_DOC typeset [-aAfFgiIlnrtux] [-p] name[=value] ...
68 Set variable values and attributes.
70 A synonym for `declare'. See `help declare'.
71 $END
73 #include <config.h>
75 #if defined (HAVE_UNISTD_H)
76 # ifdef _MINIX
77 # include <sys/types.h>
78 # endif
79 # include <unistd.h>
80 #endif
82 #include <stdio.h>
84 #include "../src/bushansi.h"
85 #include "../src/bushintl.h"
87 #include "../src/shell.h"
88 #include "../src/flags.h"
89 #include "common.h"
90 #include "builtext.h"
91 #include "bushgetopt.h"
93 static SHELL_VAR *declare_find_variable PARAMS((const char *, int, int));
94 static int declare_internal PARAMS((register WORD_LIST *, int));
96 /* Declare or change variable attributes. */
97 int
98 declare_builtin (list)
99 register WORD_LIST *list;
101 return (declare_internal (list, 0));
104 $BUILTIN local
105 $FUNCTION local_builtin
106 $SHORT_DOC local [option] name[=value] ...
107 Define local variables.
109 Create a local variable called NAME, and give it VALUE. OPTION can
110 be any option accepted by `declare'.
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.
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
120 local_builtin (list)
121 register WORD_LIST *list;
123 /* Catch a straight `local --help' before checking function context */
124 if (list && list->word && STREQ (list->word->word, "--help"))
126 builtin_help ();
127 return (EX_USAGE);
130 if (variable_context)
131 return (declare_internal (list, 1));
132 else
134 builtin_error (_("can only be used in a function"));
135 return (EXECUTION_FAILURE);
139 #if defined (ARRAY_VARS)
140 # define DECLARE_OPTS "+acfgilnprtuxAFGI"
141 #else
142 # define DECLARE_OPTS "+cfgilnprtuxFGI"
143 #endif
145 static SHELL_VAR *
146 declare_find_variable (name, mkglobal, chklocal)
147 const char *name;
148 int mkglobal, chklocal;
150 SHELL_VAR *var;
152 if (mkglobal == 0)
153 return (find_variable (name));
154 else if (chklocal)
156 var = find_variable (name);
157 if (var && local_p (var) && var->context == variable_context)
158 return var;
159 return (find_global_variable (name));
161 else
162 return (find_global_variable (name));
165 /* The workhorse function. */
166 static int
167 declare_internal (list, local_var)
168 register WORD_LIST *list;
169 int local_var;
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;
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 // printf("#############################################################\n");
184 while ((opt = internal_getopt (list, DECLARE_OPTS)) != -1)
186 flags = list_opttype == '+' ? &flags_off : &flags_on;
188 /* If you add options here, see whether or not they need to be added to
189 the loop in subst.c:shell_expand_word_list() */
190 switch (opt)
192 case 'a':
193 #if defined (ARRAY_VARS)
194 *flags |= att_array;
195 break;
196 #else
197 builtin_usage ();
198 return (EX_USAGE);
199 #endif
200 case 'A':
201 #if defined (ARRAY_VARS)
202 *flags |= att_assoc;
203 break;
204 #else
205 builtin_usage ();
206 return (EX_USAGE);
207 #endif
208 case 'p':
209 /* if (local_var == 0) */
210 pflag++;
211 break;
212 case 'F':
213 nodefs++;
214 *flags |= att_function;
215 break;
216 case 'f':
217 *flags |= att_function;
218 break;
219 case 'G':
220 if (flags == &flags_on)
221 chklocal = 1;
222 /*FALLTHROUGH*/
223 case 'g':
224 if (flags == &flags_on)
225 mkglobal = 1;
226 break;
227 case 'i':
228 *flags |= att_integer;
229 break;
230 case 'n':
231 *flags |= att_nameref;
232 break;
233 case 'r':
234 *flags |= att_readonly;
235 break;
236 case 't':
237 *flags |= att_trace;
238 break;
239 case 'x':
240 *flags |= att_exported;
241 array_needs_making = 1;
242 break;
243 #if defined (CASEMOD_ATTRS)
244 # if defined (CASEMOD_CAPCASE)
245 case 'c':
246 *flags |= att_capcase;
247 if (flags == &flags_on)
248 flags_off |= att_uppercase|att_lowercase;
249 break;
250 # endif
251 case 'l':
252 *flags |= att_lowercase;
253 if (flags == &flags_on)
254 flags_off |= att_capcase|att_uppercase;
255 break;
256 case 'u':
257 *flags |= att_uppercase;
258 if (flags == &flags_on)
259 flags_off |= att_capcase|att_lowercase;
260 break;
261 #endif /* CASEMOD_ATTRS */
262 case 'I':
263 inherit_flag = MKLOC_INHERIT;
264 break;
265 CASE_HELPOPT;
266 default:
267 builtin_usage ();
268 return (EX_USAGE);
272 list = loptend;
274 /* If there are no more arguments left, then we just want to show
275 some variables. */
276 if (list == 0) /* declare -[aAfFirtx] */
278 /* Show local variables defined at this context level if this is
279 the `local' builtin. */
280 if (local_var)
281 show_local_var_attributes (0, nodefs); /* XXX - fix up args later */
282 else if (pflag && (flags_on == 0 || flags_on == att_function))
283 show_all_var_attributes (flags_on == 0, nodefs);
284 else if (flags_on == 0)
285 return (set_builtin ((WORD_LIST *)NULL));
286 else
287 set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs);
289 return (sh_chkwrite (EXECUTION_SUCCESS));
292 if (pflag) /* declare -p [-aAfFirtx] name [name...] */
294 for (any_failed = 0; list; list = list->next)
296 if (flags_on & att_function)
297 pflag = show_func_attributes (list->word->word, nodefs);
298 else if (local_var)
299 pflag = show_localname_attributes (list->word->word, nodefs);
300 else
301 pflag = show_name_attributes (list->word->word, nodefs);
302 if (pflag)
304 sh_notfound (list->word->word);
305 any_failed++;
308 return (sh_chkwrite (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS));
311 #define NEXT_VARIABLE() free (name); list = list->next; continue
313 /* There are arguments left, so we are making variables. */
314 while (list) /* declare [-aAfFirx] name [name ...] */
316 char *value, *name, *oldname;
317 int offset, aflags, wflags, created_var, namelen;
318 int assoc_noexpand;
319 #if defined (ARRAY_VARS)
320 int making_array_special, compound_array_assign, simple_array_assign;
321 int var_exists, array_exists, creating_array, array_subscript_assignment;
322 #endif
324 // printf("list->word->word = %s\n", list->word->word);
325 name = savestring (list->word->word);
326 // printf("name = %s\n", name);
327 wflags = list->word->flags;
328 #if defined (ARRAY_VARS)
329 assoc_noexpand = assoc_expand_once && (wflags & W_ASSIGNMENT);
330 #else
331 assoc_noexpand = 0;
332 #endif
333 offset = assignment (name, assoc_noexpand ? 2 : 0);
334 // printf("offset = %d\n", offset);
335 // printf("name[offset] = %s\n", &name[offset]);
336 aflags = 0;
337 created_var = 0;
339 if (local_var && variable_context && STREQ (name, "-"))
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 ();
349 if (offset) /* declare [-aAfFirx] name=value */
351 name[offset] = '\0';
352 value = name + offset + 1;
353 if (name[offset - 1] == '+')
355 aflags |= ASS_APPEND;
356 name[offset - 1] = '\0';
359 else
360 value = "";
362 // printf("value = %s\n", value);
363 // printf("name = %s\n", name);
364 /* Do some lexical error checking on the LHS and RHS of the assignment
365 that is specific to nameref variables. */
366 if (flags_on & att_nameref)
368 #if defined (ARRAY_VARS)
369 if (valid_array_reference (name, 0))
371 builtin_error (_("%s: reference variable cannot be an array"), name);
372 assign_error++;
373 NEXT_VARIABLE ();
375 else
376 #endif
377 /* disallow self references at global scope, warn at function scope */
378 if (check_selfref (name, value, 0))
380 if (variable_context == 0)
382 builtin_error (_("%s: nameref variable self references not allowed"), name);
383 assign_error++;
384 NEXT_VARIABLE ();
386 else
387 builtin_warning (_("%s: circular name reference"), name);
389 #if 1
390 if (value && *value && (aflags & ASS_APPEND) == 0 && valid_nameref_value (value, 1) == 0)
392 builtin_error (_("`%s': invalid variable name for name reference"), value);
393 assign_error++;
394 NEXT_VARIABLE ();
396 #endif
399 restart_new_var_name:
400 #if defined (ARRAY_VARS)
401 var_exists = array_exists = creating_array = 0;
402 compound_array_assign = simple_array_assign = 0;
403 array_subscript_assignment = 0;
404 subscript_start = (char *)NULL;
405 if ((t = strchr (name, '[')) && (flags_on & att_function) == 0) /* ] */
407 /* If offset != 0 we have already validated any array reference
408 because assignment() calls skipsubscript() */
409 if (offset == 0 && valid_array_reference (name, 0) == 0)
411 sh_invalidid (name);
412 assign_error++;
413 NEXT_VARIABLE ();
415 subscript_start = t;
416 *t = '\0';
417 making_array_special = 1; /* XXX - should this check offset? */
418 array_subscript_assignment = offset != 0;
420 else
421 making_array_special = 0;
422 #endif
424 // printf("1111111111111111111111111111111111 value = %s\n", value);
426 /* If we're in posix mode or not looking for a shell function (since
427 shell function names don't have to be valid identifiers when the
428 shell's not in posix mode), check whether or not the argument is a
429 valid, well-formed shell identifier. */
430 if ((posixly_correct || (flags_on & att_function) == 0) && legal_identifier (name) == 0)
432 sh_invalidid (name);
433 assign_error++;
434 NEXT_VARIABLE ();
437 // printf("22222222222222222222222222222222222 value = %s\n", value);
439 /* If VARIABLE_CONTEXT has a non-zero value, then we are executing
440 inside of a function. This means we should make local variables,
441 not global ones. */
443 /* XXX - this has consequences when we're making a local copy of a
444 variable that was in the temporary environment. Watch out
445 for this. */
446 refvar = (SHELL_VAR *)NULL;
447 if (variable_context && mkglobal == 0 && ((flags_on & att_function) == 0))
449 char *newname;
451 /* check name for validity here? */
452 var = find_variable (name);
453 if (var == 0)
454 newname = nameref_transform_name (name, ASS_MKLOCAL);
455 else if ((flags_on & att_nameref) == 0 && (flags_off & att_nameref) == 0)
457 /* Ok, we're following namerefs here, so let's make sure that if
458 we followed one, it was at the same context (see below for
459 more details). */
460 refvar = find_variable_last_nameref (name, 1);
461 newname = (refvar && refvar->context != variable_context) ? name : var->name;
462 refvar = (SHELL_VAR *)NULL;
464 else
465 newname = name; /* dealing with nameref attribute */
467 #if defined (ARRAY_VARS)
468 /* Pass 1 as second argument to make_local_{assoc,array}_variable
469 return an existing {array,assoc} variable to be flagged as an
470 error below. */
471 if (flags_on & att_assoc)
472 var = make_local_assoc_variable (newname, MKLOC_ARRAYOK|inherit_flag);
473 else if ((flags_on & att_array) || making_array_special)
474 var = make_local_array_variable (newname, MKLOC_ASSOCOK|inherit_flag);
475 else
476 #endif
477 if (offset == 0 && (flags_on & att_nameref))
479 /* First look for refvar at current scope */
480 refvar = find_variable_last_nameref (name, 1);
481 /* VARIABLE_CONTEXT != 0, so we are attempting to create or modify
482 the attributes for a local variable at the same scope. If we've
483 used a reference from a previous context to resolve VAR, we
484 want to throw REFVAR and VAR away and create a new local var. */
485 if (refvar && refvar->context != variable_context)
487 refvar = 0;
488 var = make_local_variable (name, inherit_flag);
490 else if (refvar && refvar->context == variable_context)
491 var = refvar;
492 /* Maybe we just want to create a new local variable */
493 else if (var == 0 || var->context != variable_context)
494 var = make_local_variable (name, inherit_flag);
495 /* otherwise we have a var at the right context */
497 else
498 /* XXX - check name for validity here with valid_nameref_value */
499 var = make_local_variable ((flags_on & att_nameref) ? name : newname, inherit_flag); /* sets att_invisible for new vars */
501 if (var == 0)
503 any_failed++;
504 NEXT_VARIABLE ();
506 if (var && nameref_p (var) && readonly_p (var) && nameref_cell (var) && (flags_off & att_nameref))
508 sh_readonly (name);
509 any_failed++;
510 NEXT_VARIABLE ();
513 else
514 var = (SHELL_VAR *)NULL;
516 /* If we are declaring a function, then complain about it in some way.
517 We don't let people make functions by saying `typeset -f foo=bar'. */
519 /* There should be a way, however, to let people look at a particular
520 function definition by saying `typeset -f foo'. */
522 if (flags_on & att_function)
524 if (offset) /* declare -f [-rix] foo=bar */
526 builtin_error (_("cannot use `-f' to make functions"));
527 free (name);
528 return (EXECUTION_FAILURE);
530 else /* declare -f [-rx] name [name...] */
532 var = find_function (name);
534 if (var)
536 if (readonly_p (var) && (flags_off & att_readonly))
538 builtin_error (_("%s: readonly function"), name);
539 any_failed++;
540 NEXT_VARIABLE ();
542 else if (flags_on & (att_array|att_assoc))
544 sh_invalidopt ((flags_on & att_array) ? "-a" : "-A");
545 any_failed++;
546 NEXT_VARIABLE ();
548 /* declare -[Ff] name [name...] */
549 if (flags_on == att_function && flags_off == 0)
551 #if defined (DEBUGGER)
552 if (nodefs && debugging_mode)
554 shell_fn = find_function_def (var->name);
555 if (shell_fn)
556 printf ("%s %d %s\n", var->name, shell_fn->line, shell_fn->source_file);
557 else
558 printf ("%s\n", var->name);
560 else
561 #endif /* DEBUGGER */
563 t = nodefs ? var->name
564 : named_function_string (name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL);
565 printf ("%s\n", t);
566 any_failed = sh_chkwrite (any_failed);
569 else /* declare -[fF] -[rx] name [name...] */
571 VSETATTR (var, flags_on);
572 flags_off &= ~att_function; /* makes no sense */
573 VUNSETATTR (var, flags_off);
576 else
577 any_failed++;
578 NEXT_VARIABLE ();
581 else /* declare -[aAinrx] name [name...] */
583 /* Non-null if we just created or fetched a local variable. */
584 #if 0
585 /* This is bush-4.3 code. */
586 /* Here's what ksh93 seems to do. If we are modifying an existing
587 nameref variable, we don't follow the nameref chain past the last
588 nameref, and we set the nameref variable's value so future
589 references to that variable will return the value of the variable
590 we're assigning right now. */
591 #else
592 /* Here's what ksh93 seems to do as of the 2012 version: if we are
593 using declare -n to modify the value of an existing nameref
594 variable, don't follow the nameref chain at all and just search
595 for a nameref at the current context. If we have a nameref,
596 modify its value (changing which variable it references). */
597 #endif
598 if (var == 0 && (flags_on & att_nameref))
600 /* See if we are trying to modify an existing nameref variable,
601 but don't follow the nameref chain. */
602 var = mkglobal ? find_global_variable_noref (name) : find_variable_noref (name);
603 if (var && nameref_p (var) == 0)
604 var = 0;
606 /* However, if we're turning off the nameref attribute on an existing
607 nameref variable, we first follow the nameref chain to the end,
608 modify the value of the variable this nameref variable references
609 if there is an assignment statement argument,
610 *CHANGING ITS VALUE AS A SIDE EFFECT*, then turn off the nameref
611 flag *LEAVING THE NAMEREF VARIABLE'S VALUE UNCHANGED* */
612 else if (var == 0 && (flags_off & att_nameref))
614 /* See if we are trying to modify an existing nameref variable */
615 refvar = mkglobal ? find_global_variable_last_nameref (name, 0) : find_variable_last_nameref (name, 0);
616 if (refvar && nameref_p (refvar) == 0)
617 refvar = 0;
618 /* If the nameref is readonly but doesn't have a value, ksh93
619 allows the nameref attribute to be removed. If it's readonly
620 and has a value, even if the value doesn't reference an
621 existing variable, we disallow the modification */
622 if (refvar && nameref_cell (refvar) && readonly_p (refvar))
624 sh_readonly (name);
625 any_failed++;
626 NEXT_VARIABLE ();
629 /* If all we're doing is turning off the nameref attribute, don't
630 bother with VAR at all, whether it exists or not. Just turn it
631 off and go on. */
632 if (refvar && flags_on == 0 && offset == 0 && (flags_off & ~att_nameref) == 0)
634 VUNSETATTR (refvar, att_nameref);
635 NEXT_VARIABLE ();
638 if (refvar)
639 /* XXX - use declare_find_variable here? */
640 var = mkglobal ? find_global_variable (nameref_cell (refvar)) : find_variable (nameref_cell (refvar));
642 #if defined (ARRAY_VARS)
643 /* If we have an array assignment to a nameref, remove the nameref
644 attribute and go on. */
645 else if (var == 0 && offset && array_subscript_assignment)
647 var = mkglobal ? find_global_variable_noref (name) : find_variable_noref (name);
648 if (var && nameref_p (var))
650 internal_warning (_("%s: removing nameref attribute"), name);
651 FREE (value_cell (var)); /* XXX - bush-4.3 compat */
652 var_setvalue (var, (char *)NULL);
653 VUNSETATTR (var, att_nameref);
656 #endif
658 /* See if we are trying to set flags or value (or create) for an
659 existing nameref that points to a non-existent variable: e.g.,
660 declare -n foo=bar
661 unset foo # unsets bar
662 declare -i foo
663 foo=4+4
664 declare -p foo */
665 if (var == 0 && (mkglobal || flags_on || flags_off || offset))
667 refvar = mkglobal ? find_global_variable_last_nameref (name, 0) : find_variable_last_nameref (name, 0);
668 if (refvar && nameref_p (refvar) == 0)
669 refvar = 0;
670 if (refvar)
671 /* XXX - use declare_find_variable here? */
672 var = mkglobal ? find_global_variable (nameref_cell (refvar)) : find_variable (nameref_cell (refvar));
673 if (refvar && var == 0)
675 oldname = name; /* need to free this */
677 namelen = strlen (nameref_cell (refvar));
678 #if defined (ARRAY_VARS)
679 if (subscript_start)
681 *subscript_start = '['; /*]*/
682 namelen += strlen (subscript_start);
684 #endif
685 name = xmalloc (namelen + 2 + strlen (value) + 1);
686 strcpy (name, nameref_cell (refvar));
687 #if defined (ARRAY_VARS)
688 if (subscript_start)
689 strcpy (name + strlen (nameref_cell (refvar)), subscript_start);
690 #endif
691 /* We are committed to using the new name, so reset */
692 if (offset)
694 /* Rebuild assignment and restore offset and value */
695 if (aflags & ASS_APPEND)
696 name[namelen++] = '+';
697 name[namelen++] = '=';
698 if (value && *value)
699 strcpy (name + namelen, value);
700 else
701 name[namelen] = '\0';
702 offset = assignment (name, 0);
703 /* if offset was valid previously, but the substituting
704 of the nameref value results in an invalid assignment,
705 throw an invalid identifier error */
706 if (offset == 0)
708 free (oldname);
709 sh_invalidid (name);
710 assign_error++;
711 NEXT_VARIABLE ();
713 name[offset] = '\0';
714 value = name + namelen;
716 free (oldname);
718 /* OK, let's turn off the nameref attribute.
719 Now everything else applies to VAR. */
720 if (flags_off & att_nameref)
721 VUNSETATTR (refvar, att_nameref);
723 goto restart_new_var_name;
724 /* NOTREACHED */
727 if (var == 0)
728 var = declare_find_variable (name, mkglobal, chklocal);
730 #if defined (ARRAY_VARS)
731 var_exists = var != 0;
732 array_exists = var && (array_p (var) || assoc_p (var));
733 creating_array = flags_on & (att_array|att_assoc);
734 #endif
736 if (var == 0)
738 #if defined (ARRAY_VARS)
739 if (flags_on & att_assoc)
741 var = make_new_assoc_variable (name);
742 if (var && offset == 0)
743 VSETATTR (var, att_invisible);
745 else if ((flags_on & att_array) || making_array_special)
747 var = make_new_array_variable (name);
748 if (var && offset == 0)
749 VSETATTR (var, att_invisible);
751 else
752 #endif
754 var = mkglobal ? bind_global_variable (name, (char *)NULL, ASS_FORCE) : bind_variable (name, (char *)NULL, ASS_FORCE);
755 if (var && offset == 0)
756 VSETATTR (var, att_invisible);
758 if (var == 0)
760 /* Has to appear in brackets */
761 NEXT_VARIABLE ();
763 created_var = 1;
765 /* Can't take an existing array variable and make it a nameref */
766 else if ((array_p (var) || assoc_p (var)) && (flags_on & att_nameref))
768 builtin_error (_("%s: reference variable cannot be an array"), name);
769 assign_error++;
770 NEXT_VARIABLE ();
772 else if (nameref_p (var) && (flags_on & att_nameref) == 0 && (flags_off & att_nameref) == 0 && offset && valid_nameref_value (value, 1) == 0)
774 builtin_error (_("`%s': invalid variable name for name reference"), value);
775 any_failed++;
776 NEXT_VARIABLE ();
778 else if (flags_on & att_nameref)
780 #if 1
781 /* Check of offset is to allow an assignment to a nameref var as
782 part of the declare word to override existing value */
783 if (nameref_p (var) == 0 && var_isset (var) && offset == 0 && valid_nameref_value (value_cell (var), 0) == 0)
785 builtin_error (_("`%s': invalid variable name for name reference"), value_cell (var));
786 any_failed++;
787 NEXT_VARIABLE ();
789 #endif
790 if (readonly_p (var))
792 sh_readonly (name);
793 any_failed++;
794 NEXT_VARIABLE ();
796 /* ksh93 compat: turning on nameref attribute turns off -ilu */
797 VUNSETATTR (var, att_integer|att_uppercase|att_lowercase|att_capcase);
800 /* Cannot use declare +r to turn off readonly attribute. */
801 if (readonly_p (var) && (flags_off & att_readonly))
803 sh_readonly (name_cell (var));
804 any_failed++;
805 NEXT_VARIABLE ();
808 /* Cannot use declare to assign value to readonly or noassign
809 variable. */
810 if ((readonly_p (var) || noassign_p (var)) && offset)
812 if (readonly_p (var))
813 sh_readonly (name);
814 assign_error++;
815 NEXT_VARIABLE ();
818 #if defined (ARRAY_VARS)
819 /* make declare a[2]=foo as similar to a[2]=foo as possible if
820 a is already an array or assoc variable. */
821 if (array_subscript_assignment && array_exists && creating_array == 0)
822 simple_array_assign = 1;
823 else if ((making_array_special || creating_array || array_exists) && offset)
825 int vlen;
826 vlen = STRLEN (value);
827 /*itrace("declare_builtin: name = %s value = %s flags = %d", name, value, wflags);*/
828 if (shell_compatibility_level > 43 && (wflags & W_COMPASSIGN) == 0 &&
829 value[0] == '(' && value[vlen-1] == ')')
831 /* The warning is only printed when using compound assignment
832 to an array variable that doesn't already exist. We use
833 creating_array to allow things like
834 declare -a foo$bar='(abc)' to work. */
835 if (array_exists == 0 && creating_array == 0)
836 internal_warning (_("%s: quoted compound array assignment deprecated"), list->word->word);
837 compound_array_assign = array_exists || creating_array;
838 simple_array_assign = making_array_special;
840 else if (value[0] == '(' && value[vlen-1] == ')' && (shell_compatibility_level < 44 || (wflags & W_COMPASSIGN)))
841 compound_array_assign = 1;
842 else
843 simple_array_assign = 1;
846 /* Cannot use declare +a name or declare +A name to remove an
847 array variable. */
848 if (((flags_off & att_array) && array_p (var)) || ((flags_off & att_assoc) && assoc_p (var)))
850 builtin_error (_("%s: cannot destroy array variables in this way"), name);
851 any_failed++;
852 NEXT_VARIABLE ();
855 if ((flags_on & att_array) && assoc_p (var))
857 builtin_error (_("%s: cannot convert associative to indexed array"), name);
858 any_failed++;
859 NEXT_VARIABLE ();
861 if ((flags_on & att_assoc) && array_p (var))
863 builtin_error (_("%s: cannot convert indexed to associative array"), name);
864 any_failed++;
865 NEXT_VARIABLE ();
868 /* declare -A name[[n]] makes name an associative array variable. */
869 if (flags_on & att_assoc)
871 if (assoc_p (var) == 0)
872 var = convert_var_to_assoc (var);
874 /* declare -a name[[n]] or declare name[n] makes name an indexed
875 array variable. */
876 else if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0 && assoc_p (var) == 0)
877 var = convert_var_to_array (var);
878 #endif /* ARRAY_VARS */
880 /* XXX - we note that we are turning on nameref attribute and defer
881 setting it until the assignment has been made so we don't do an
882 inadvertent nameref lookup. Might have to do the same thing for
883 flags_off&att_nameref. */
884 /* XXX - ksh93 makes it an error to set a readonly nameref variable
885 using a single typeset command. */
886 onref = (flags_on & att_nameref);
887 flags_on &= ~att_nameref;
888 #if defined (ARRAY_VARS)
889 if (array_p (var) || assoc_p (var)
890 || (offset && compound_array_assign)
891 || simple_array_assign)
892 onref = 0; /* array variables may not be namerefs */
893 #endif
895 /* ksh93 seems to do this */
896 offref = (flags_off & att_nameref);
897 flags_off &= ~att_nameref;
899 VSETATTR (var, flags_on);
900 VUNSETATTR (var, flags_off);
902 #if defined (ARRAY_VARS)
903 if (offset && compound_array_assign)
904 assign_array_var_from_string (var, value, aflags|ASS_FORCE);
905 else if (simple_array_assign && subscript_start)
907 int local_aflags;
908 /* declare [-aA] name[N]=value */
909 *subscript_start = '['; /* ] */
910 /* XXX - problem here with appending */
911 local_aflags = aflags&ASS_APPEND;
912 local_aflags |= assoc_noexpand ? ASS_NOEXPAND : 0;
913 var = assign_array_element (name, value, local_aflags); /* XXX - not aflags */
914 *subscript_start = '\0';
915 if (var == 0) /* some kind of assignment error */
917 assign_error++;
918 flags_on |= onref;
919 flags_off |= offref;
920 NEXT_VARIABLE ();
923 else if (simple_array_assign)
925 /* let bind_{array,assoc}_variable take care of this. */
926 if (assoc_p (var))
927 bind_assoc_variable (var, name, savestring ("0"), value, aflags|ASS_FORCE);
928 else
929 bind_array_variable (name, 0, value, aflags|ASS_FORCE);
931 else
932 #endif
933 /* XXX - no ASS_FORCE here */
934 /* bind_variable_value duplicates the essential internals of
935 bind_variable() */
936 if (offset)
938 if (onref || nameref_p (var))
939 aflags |= ASS_NAMEREF;
940 v = bind_variable_value (var, value, aflags);
941 if (v == 0 && (onref || nameref_p (var)))
943 if (valid_nameref_value (value, 1) == 0)
944 sh_invalidid (value);
945 assign_error++;
946 /* XXX - unset this variable? or leave it as normal var? */
947 if (created_var)
948 delete_var (var->name, mkglobal ? global_variables : shell_variables);
949 flags_on |= onref; /* undo change from above */
950 flags_off |= offref;
951 NEXT_VARIABLE ();
955 /* If we found this variable in the temporary environment, as with
956 `var=value declare -x var', make sure it is treated identically
957 to `var=value export var'. Do the same for `declare -r' and
958 `readonly'. Preserve the attributes, except for att_tempvar. */
959 /* XXX -- should this create a variable in the global scope, or
960 modify the local variable flags? ksh93 has it modify the
961 global scope.
962 Need to handle case like in set_var_attribute where a temporary
963 variable is in the same table as the function local vars. */
964 if ((flags_on & (att_exported|att_readonly)) && tempvar_p (var))
966 SHELL_VAR *tv;
967 char *tvalue;
969 tv = find_tempenv_variable (var->name);
970 if (tv)
972 tvalue = var_isset (var) ? savestring (value_cell (var)) : savestring ("");
973 tv = bind_variable (var->name, tvalue, 0);
974 if (tv)
976 tv->attributes |= var->attributes & ~att_tempvar;
977 if (tv->context > 0)
978 VSETATTR (tv, att_propagate);
980 free (tvalue);
982 VSETATTR (var, att_propagate);
986 /* Turn on nameref attribute we deferred above. */
987 /* XXX - should we turn on the noassign attribute for consistency with
988 ksh93 when we turn on the nameref attribute? */
989 VSETATTR (var, onref);
990 flags_on |= onref;
991 VUNSETATTR (var, offref);
992 flags_off |= offref;
993 /* Yuck. ksh93 compatibility. XXX - need to investigate more but
994 definitely happens when turning off nameref attribute on nameref
995 (see comments above). Under no circumstances allow this to turn
996 off readonly attribute on readonly nameref variable. */
997 if (refvar)
999 if (flags_off & att_readonly)
1000 flags_off &= ~att_readonly;
1001 VUNSETATTR (refvar, flags_off);
1004 stupidly_hack_special_variables (name);
1006 NEXT_VARIABLE ();
1009 return (assign_error ? EX_BADASSIGN
1010 : ((any_failed == 0) ? EXECUTION_SUCCESS
1011 : EXECUTION_FAILURE));