]> git.ipfire.org Git - thirdparty/bash.git/blame - builtins/declare.def
Bash-4.4 patch 19
[thirdparty/bash.git] / builtins / declare.def
CommitLineData
726f6388
JA
1This file is declare.def, from which is created declare.c.
2It implements the builtins "declare" and "local" in Bash.
3
a0c0a00f 4Copyright (C) 1987-2016 Free Software Foundation, Inc.
726f6388
JA
5
6This file is part of GNU Bash, the Bourne Again SHell.
7
3185942a
JA
8Bash is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
726f6388 12
3185942a
JA
13Bash is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
726f6388 17
3185942a
JA
18You should have received a copy of the GNU General Public License
19along with Bash. If not, see <http://www.gnu.org/licenses/>.
726f6388
JA
20
21$PRODUCES declare.c
22
23$BUILTIN declare
24$FUNCTION declare_builtin
ac50fbac 25$SHORT_DOC declare [-aAfFgilnrtux] [-p] [name[=value] ...]
3185942a 26Set variable values and attributes.
726f6388 27
3185942a
JA
28Declare variables and give them attributes. If no NAMEs are given,
29display the attributes and values of all variables.
726f6388 30
3185942a
JA
31Options:
32 -f restrict action or display to function names and definitions
33 -F restrict display to function names only (plus line number and
a0c0a00f 34 source file when debugging)
495aee44 35 -g create global variables when used in a shell function; otherwise
a0c0a00f 36 ignored
3185942a
JA
37 -p display the attributes and value of each NAME
38
39Options which set attributes:
40 -a to make NAMEs indexed arrays (if supported)
41 -A to make NAMEs associative arrays (if supported)
7117c2d2 42 -i to make NAMEs have the `integer' attribute
3185942a 43 -l to convert NAMEs to lower case on assignment
ac50fbac 44 -n make NAME a reference to the variable named by its value
ccc6cda3 45 -r to make NAMEs readonly
7117c2d2 46 -t to make NAMEs have the `trace' attribute
3185942a 47 -u to convert NAMEs to upper case on assignment
ccc6cda3 48 -x to make NAMEs export
726f6388 49
3185942a
JA
50Using `+' instead of `-' turns off the given attribute.
51
726f6388 52Variables with the integer attribute have arithmetic evaluation (see
3185942a 53the `let' command) performed when the variable is assigned a value.
726f6388 54
3185942a 55When used in a function, `declare' makes NAMEs local, as with the `local'
495aee44 56command. The `-g' option suppresses this behavior.
ccc6cda3 57
3185942a 58Exit Status:
ac50fbac
CR
59Returns success unless an invalid option is supplied or a variable
60assignment error occurs.
726f6388
JA
61$END
62
63$BUILTIN typeset
64$FUNCTION declare_builtin
a0c0a00f 65$SHORT_DOC typeset [-aAfFgilnrtux] [-p] name[=value] ...
3185942a
JA
66Set variable values and attributes.
67
a0c0a00f 68A synonym for `declare'. See `help declare'.
726f6388
JA
69$END
70
ccc6cda3
JA
71#include <config.h>
72
73#if defined (HAVE_UNISTD_H)
cce855bc
JA
74# ifdef _MINIX
75# include <sys/types.h>
76# endif
ccc6cda3
JA
77# include <unistd.h>
78#endif
79
726f6388
JA
80#include <stdio.h>
81
ccc6cda3 82#include "../bashansi.h"
b80f6443 83#include "../bashintl.h"
726f6388
JA
84
85#include "../shell.h"
a0c0a00f 86#include "../flags.h"
ccc6cda3
JA
87#include "common.h"
88#include "builtext.h"
7117c2d2 89#include "bashgetopt.h"
726f6388 90
f73dda09 91extern int array_needs_making;
0628567a 92extern int posixly_correct;
726f6388 93
f73dda09 94static int declare_internal __P((register WORD_LIST *, int));
726f6388
JA
95
96/* Declare or change variable attributes. */
97int
98declare_builtin (list)
99 register WORD_LIST *list;
100{
101 return (declare_internal (list, 0));
102}
103
104$BUILTIN local
105$FUNCTION local_builtin
3185942a
JA
106$SHORT_DOC local [option] name[=value] ...
107Define local variables.
108
109Create a local variable called NAME, and give it VALUE. OPTION can
110be any option accepted by `declare'.
111
112Local variables can only be used within a function; they are visible
113only to the function where they are defined and its children.
114
115Exit Status:
ac50fbac
CR
116Returns success unless an invalid option is supplied, a variable
117assignment error occurs, or the shell is not executing a function.
726f6388
JA
118$END
119int
120local_builtin (list)
121 register WORD_LIST *list;
122{
123 if (variable_context)
124 return (declare_internal (list, 1));
125 else
126 {
b80f6443 127 builtin_error (_("can only be used in a function"));
726f6388
JA
128 return (EXECUTION_FAILURE);
129 }
130}
131
7117c2d2 132#if defined (ARRAY_VARS)
ac50fbac 133# define DECLARE_OPTS "+acfgilnprtuxAF"
7117c2d2 134#else
ac50fbac 135# define DECLARE_OPTS "+cfgilnprtuxF"
7117c2d2
JA
136#endif
137
726f6388
JA
138/* The workhorse function. */
139static int
140declare_internal (list, local_var)
141 register WORD_LIST *list;
142 int local_var;
143{
3185942a 144 int flags_on, flags_off, *flags;
ac50fbac 145 int any_failed, assign_error, pflag, nodefs, opt, mkglobal, onref, offref;
f73dda09 146 char *t, *subscript_start;
ac50fbac 147 SHELL_VAR *var, *refvar, *v;
b80f6443 148 FUNCTION_DEF *shell_fn;
726f6388 149
495aee44 150 flags_on = flags_off = any_failed = assign_error = pflag = nodefs = mkglobal = 0;
ac50fbac 151 refvar = (SHELL_VAR *)NULL;
7117c2d2 152 reset_internal_getopt ();
a0c0a00f 153 while ((opt = internal_getopt (list, DECLARE_OPTS)) != -1)
726f6388 154 {
7117c2d2 155 flags = list_opttype == '+' ? &flags_off : &flags_on;
726f6388 156
a0c0a00f
CR
157 /* If you add options here, see whether or not they need to be added to
158 the loop in subst.c:shell_expand_word_list() */
7117c2d2 159 switch (opt)
726f6388 160 {
7117c2d2 161 case 'a':
ccc6cda3 162#if defined (ARRAY_VARS)
7117c2d2 163 *flags |= att_array;
3185942a
JA
164 break;
165#else
166 builtin_usage ();
167 return (EX_USAGE);
ccc6cda3 168#endif
3185942a
JA
169 case 'A':
170#if defined (ARRAY_VARS)
171 *flags |= att_assoc;
7117c2d2 172 break;
3185942a
JA
173#else
174 builtin_usage ();
175 return (EX_USAGE);
176#endif
7117c2d2
JA
177 case 'p':
178 if (local_var == 0)
179 pflag++;
180 break;
181 case 'F':
182 nodefs++;
183 *flags |= att_function;
184 break;
185 case 'f':
186 *flags |= att_function;
187 break;
495aee44
CR
188 case 'g':
189 if (flags == &flags_on)
190 mkglobal = 1;
191 break;
7117c2d2
JA
192 case 'i':
193 *flags |= att_integer;
194 break;
ac50fbac
CR
195 case 'n':
196 *flags |= att_nameref;
197 break;
7117c2d2
JA
198 case 'r':
199 *flags |= att_readonly;
200 break;
201 case 't':
202 *flags |= att_trace;
203 break;
204 case 'x':
205 *flags |= att_exported;
206 array_needs_making = 1;
207 break;
3185942a
JA
208#if defined (CASEMOD_ATTRS)
209# if defined (CASEMOD_CAPCASE)
210 case 'c':
211 *flags |= att_capcase;
212 if (flags == &flags_on)
213 flags_off |= att_uppercase|att_lowercase;
214 break;
215# endif
216 case 'l':
217 *flags |= att_lowercase;
218 if (flags == &flags_on)
219 flags_off |= att_capcase|att_uppercase;
220 break;
221 case 'u':
222 *flags |= att_uppercase;
223 if (flags == &flags_on)
224 flags_off |= att_capcase|att_lowercase;
225 break;
226#endif /* CASEMOD_ATTRS */
a0c0a00f 227 CASE_HELPOPT;
7117c2d2
JA
228 default:
229 builtin_usage ();
230 return (EX_USAGE);
726f6388 231 }
726f6388
JA
232 }
233
7117c2d2
JA
234 list = loptend;
235
726f6388
JA
236 /* If there are no more arguments left, then we just want to show
237 some variables. */
3185942a 238 if (list == 0) /* declare -[aAfFirtx] */
726f6388
JA
239 {
240 /* Show local variables defined at this context level if this is
241 the `local' builtin. */
242 if (local_var)
243 {
244 register SHELL_VAR **vlist;
245 register int i;
246
7117c2d2 247 vlist = all_local_variables ();
726f6388
JA
248
249 if (vlist)
250 {
251 for (i = 0; vlist[i]; i++)
252 print_assignment (vlist[i]);
253
254 free (vlist);
255 }
256 }
3185942a
JA
257 else if (pflag && (flags_on == 0 || flags_on == att_function))
258 show_all_var_attributes (flags_on == 0, nodefs);
259 else if (flags_on == 0)
260 return (set_builtin ((WORD_LIST *)NULL));
726f6388 261 else
3185942a 262 set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs);
726f6388 263
3185942a 264 return (sh_chkwrite (EXECUTION_SUCCESS));
726f6388
JA
265 }
266
3185942a 267 if (pflag) /* declare -p [-aAfFirtx] name [name...] */
ccc6cda3
JA
268 {
269 for (any_failed = 0; list; list = list->next)
270 {
ac50fbac
CR
271 if (flags_on & att_function)
272 pflag = show_func_attributes (list->word->word, nodefs);
273 else
274 pflag = show_name_attributes (list->word->word, nodefs);
ccc6cda3
JA
275 if (pflag)
276 {
7117c2d2 277 sh_notfound (list->word->word);
ccc6cda3
JA
278 any_failed++;
279 }
280 }
3185942a 281 return (sh_chkwrite (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS));
ccc6cda3
JA
282 }
283
726f6388
JA
284#define NEXT_VARIABLE() free (name); list = list->next; continue
285
286 /* There are arguments left, so we are making variables. */
3185942a 287 while (list) /* declare [-aAfFirx] name [name ...] */
726f6388 288 {
a0c0a00f
CR
289 char *value, *name, *oldname;
290 int offset, aflags, wflags, created_var, namelen;
ccc6cda3 291#if defined (ARRAY_VARS)
f73dda09 292 int making_array_special, compound_array_assign, simple_array_assign;
a0c0a00f 293 int var_exists, array_exists, creating_array, array_subscript_assignment;
ccc6cda3
JA
294#endif
295
296 name = savestring (list->word->word);
a0c0a00f 297 wflags = list->word->flags;
b80f6443 298 offset = assignment (name, 0);
95732b49 299 aflags = 0;
a0c0a00f
CR
300 created_var = 0;
301
302 if (local_var && variable_context && STREQ (name, "-"))
303 {
304 var = make_local_variable ("-");
305 FREE (value_cell (var)); /* just in case */
306 value = get_current_options ();
307 var_setvalue (var, value);
308 VSETATTR (var, att_invisible);
309 NEXT_VARIABLE ();
310 }
726f6388 311
3185942a 312 if (offset) /* declare [-aAfFirx] name=value */
726f6388
JA
313 {
314 name[offset] = '\0';
315 value = name + offset + 1;
95732b49
JA
316 if (name[offset - 1] == '+')
317 {
318 aflags |= ASS_APPEND;
319 name[offset - 1] = '\0';
320 }
726f6388
JA
321 }
322 else
323 value = "";
324
ac50fbac
CR
325 /* Do some lexical error checking on the LHS and RHS of the assignment
326 that is specific to nameref variables. */
327 if (flags_on & att_nameref)
328 {
a0c0a00f
CR
329#if defined (ARRAY_VARS)
330 if (valid_array_reference (name, 0))
ac50fbac
CR
331 {
332 builtin_error (_("%s: reference variable cannot be an array"), name);
333 assign_error++;
334 NEXT_VARIABLE ();
335 }
336 else
337#endif
a0c0a00f
CR
338 /* disallow self references at global scope, warn at function scope */
339 if (check_selfref (name, value, 0))
340 {
341 if (variable_context == 0)
342 {
343 builtin_error (_("%s: nameref variable self references not allowed"), name);
344 assign_error++;
345 NEXT_VARIABLE ();
346 }
347 else
348 builtin_warning (_("%s: circular name reference"), name);
349 }
350#if 1
351 if (value && *value && (aflags & ASS_APPEND) == 0 && valid_nameref_value (value, 1) == 0)
ac50fbac 352 {
a0c0a00f 353 builtin_error (_("`%s': invalid variable name for name reference"), value);
ac50fbac
CR
354 assign_error++;
355 NEXT_VARIABLE ();
356 }
a0c0a00f 357#endif
ac50fbac
CR
358 }
359
a0c0a00f 360restart_new_var_name:
ccc6cda3 361#if defined (ARRAY_VARS)
a0c0a00f 362 var_exists = array_exists = creating_array = 0;
f73dda09 363 compound_array_assign = simple_array_assign = 0;
a0c0a00f 364 array_subscript_assignment = 0;
f73dda09
JA
365 subscript_start = (char *)NULL;
366 if (t = strchr (name, '[')) /* ] */
ccc6cda3 367 {
a0c0a00f
CR
368 /* If offset != 0 we have already validated any array reference
369 because assignment() calls skipsubscript() */
370 if (offset == 0 && valid_array_reference (name, 0) == 0)
89a92869
CR
371 {
372 sh_invalidid (name);
373 assign_error++;
374 NEXT_VARIABLE ();
375 }
f73dda09 376 subscript_start = t;
ccc6cda3 377 *t = '\0';
a0c0a00f
CR
378 making_array_special = 1; /* XXX - should this check offset? */
379 array_subscript_assignment = offset != 0;
ccc6cda3
JA
380 }
381 else
382 making_array_special = 0;
383#endif
0628567a
JA
384
385 /* If we're in posix mode or not looking for a shell function (since
386 shell function names don't have to be valid identifiers when the
387 shell's not in posix mode), check whether or not the argument is a
388 valid, well-formed shell identifier. */
389 if ((posixly_correct || (flags_on & att_function) == 0) && legal_identifier (name) == 0)
726f6388 390 {
7117c2d2 391 sh_invalidid (name);
ccc6cda3 392 assign_error++;
726f6388
JA
393 NEXT_VARIABLE ();
394 }
395
396 /* If VARIABLE_CONTEXT has a non-zero value, then we are executing
397 inside of a function. This means we should make local variables,
398 not global ones. */
399
7117c2d2
JA
400 /* XXX - this has consequences when we're making a local copy of a
401 variable that was in the temporary environment. Watch out
402 for this. */
ac50fbac 403 refvar = (SHELL_VAR *)NULL;
495aee44 404 if (variable_context && mkglobal == 0 && ((flags_on & att_function) == 0))
ccc6cda3 405 {
a0c0a00f 406 /* check name for validity here? */
ccc6cda3 407#if defined (ARRAY_VARS)
3185942a
JA
408 if (flags_on & att_assoc)
409 var = make_local_assoc_variable (name);
410 else if ((flags_on & att_array) || making_array_special)
ac50fbac 411 var = make_local_array_variable (name, making_array_special);
ccc6cda3
JA
412 else
413#endif
a0c0a00f
CR
414 if (offset == 0 && (flags_on & att_nameref))
415 {
416 /* First look for refvar at current scope */
417 refvar = find_variable_last_nameref (name, 1);
418 var = find_variable (name);
419 /* VARIABLE_CONTEXT != 0, so we are attempting to create or modify
420 the attributes for a local variable at the same scope. If we've
421 used a reference from a previous context to resolve VAR, we
422 want to throw REFVAR and VAR away and create a new local var. */
423 if (refvar && refvar->context != variable_context)
424 {
425 refvar = 0;
426 var = make_local_variable (name);
427 }
428 else if (refvar && refvar->context == variable_context)
429 var = refvar;
430 /* Maybe we just want to create a new local variable */
431 else if (var == 0 || var->context != variable_context)
432 var = make_local_variable (name);
433 /* otherwise we have a var at the right context */
434 }
435 else
436 /* XXX - check name for validity here with valid_nameref_value */
ac50fbac 437 var = make_local_variable (name); /* sets att_invisible for new vars */
bb70624e
JA
438 if (var == 0)
439 {
440 any_failed++;
441 NEXT_VARIABLE ();
442 }
a0c0a00f
CR
443 if (var && nameref_p (var) && readonly_p (var) && nameref_cell (var) && (flags_off & att_nameref))
444 {
445 sh_readonly (name);
446 any_failed++;
447 NEXT_VARIABLE ();
448 }
ccc6cda3 449 }
7117c2d2
JA
450 else
451 var = (SHELL_VAR *)NULL;
726f6388
JA
452
453 /* If we are declaring a function, then complain about it in some way.
454 We don't let people make functions by saying `typeset -f foo=bar'. */
455
456 /* There should be a way, however, to let people look at a particular
457 function definition by saying `typeset -f foo'. */
458
459 if (flags_on & att_function)
460 {
ccc6cda3 461 if (offset) /* declare -f [-rix] foo=bar */
726f6388 462 {
b80f6443 463 builtin_error (_("cannot use `-f' to make functions"));
d166f048 464 free (name);
726f6388
JA
465 return (EXECUTION_FAILURE);
466 }
ccc6cda3 467 else /* declare -f [-rx] name [name...] */
726f6388 468 {
ccc6cda3 469 var = find_function (name);
726f6388 470
ccc6cda3 471 if (var)
726f6388 472 {
ccc6cda3 473 if (readonly_p (var) && (flags_off & att_readonly))
726f6388 474 {
b80f6443 475 builtin_error (_("%s: readonly function"), name);
726f6388
JA
476 any_failed++;
477 NEXT_VARIABLE ();
478 }
479
ccc6cda3 480 /* declare -[Ff] name [name...] */
726f6388
JA
481 if (flags_on == att_function && flags_off == 0)
482 {
b80f6443
JA
483#if defined (DEBUGGER)
484 if (nodefs && debugging_mode)
485 {
486 shell_fn = find_function_def (var->name);
487 if (shell_fn)
488 printf ("%s %d %s\n", var->name, shell_fn->line, shell_fn->source_file);
489 else
490 printf ("%s\n", var->name);
491 }
492 else
493#endif /* DEBUGGER */
494 {
495 t = nodefs ? var->name
3185942a 496 : named_function_string (name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL);
b80f6443 497 printf ("%s\n", t);
3185942a 498 any_failed = sh_chkwrite (any_failed);
b80f6443 499 }
726f6388 500 }
ccc6cda3 501 else /* declare -[fF] -[rx] name [name...] */
726f6388 502 {
bb70624e
JA
503 VSETATTR (var, flags_on);
504 VUNSETATTR (var, flags_off);
726f6388
JA
505 }
506 }
507 else
508 any_failed++;
509 NEXT_VARIABLE ();
510 }
511 }
a0c0a00f 512 else /* declare -[aAinrx] name [name...] */
726f6388 513 {
7117c2d2 514 /* Non-null if we just created or fetched a local variable. */
a0c0a00f
CR
515#if 0
516 /* This is bash-4.3 code. */
ac50fbac
CR
517 /* Here's what ksh93 seems to do. If we are modifying an existing
518 nameref variable, we don't follow the nameref chain past the last
519 nameref, and we set the nameref variable's value so future
520 references to that variable will return the value of the variable
521 we're assigning right now. */
a0c0a00f
CR
522#else
523 /* Here's what ksh93 seems to do as of the 2012 version: if we are
524 using declare -n to modify the value of an existing nameref
525 variable, don't follow the nameref chain at all and just search
526 for a nameref at the current context. If we have a nameref,
527 modify its value (changing which variable it references). */
528#endif
ac50fbac
CR
529 if (var == 0 && (flags_on & att_nameref))
530 {
a0c0a00f 531#if 0
ac50fbac 532 /* See if we are trying to modify an existing nameref variable */
a0c0a00f
CR
533 var = mkglobal ? find_global_variable_last_nameref (name, 1) : find_variable_last_nameref (name, 1);
534#else
535 /* See if we are trying to modify an existing nameref variable,
536 but don't follow the nameref chain. */
537 var = mkglobal ? find_global_variable_noref (name) : find_variable_noref (name);
538#endif
ac50fbac
CR
539 if (var && nameref_p (var) == 0)
540 var = 0;
541 }
542 /* However, if we're turning off the nameref attribute on an existing
543 nameref variable, we first follow the nameref chain to the end,
544 modify the value of the variable this nameref variable references,
545 *CHANGING ITS VALUE AS A SIDE EFFECT* then turn off the nameref
546 flag *LEAVING THE NAMEREF VARIABLE'S VALUE UNCHANGED* */
547 else if (var == 0 && (flags_off & att_nameref))
548 {
549 /* See if we are trying to modify an existing nameref variable */
a0c0a00f 550 refvar = mkglobal ? find_global_variable_last_nameref (name, 0) : find_variable_last_nameref (name, 0);
ac50fbac
CR
551 if (refvar && nameref_p (refvar) == 0)
552 refvar = 0;
a0c0a00f
CR
553 /* If the nameref is readonly but doesn't have a value, ksh93
554 allows the nameref attribute to be removed. If it's readonly
555 and has a value, even if the value doesn't reference an
556 existing variable, we disallow the modification */
557 if (refvar && nameref_cell (refvar) && readonly_p (refvar))
558 {
559 sh_readonly (name);
560 any_failed++;
561 NEXT_VARIABLE ();
562 }
ac50fbac
CR
563 if (refvar)
564 var = mkglobal ? find_global_variable (nameref_cell (refvar)) : find_variable (nameref_cell (refvar));
565 }
a0c0a00f
CR
566#if defined (ARRAY_VARS)
567 /* If we have an array assignment to a nameref, remove the nameref
568 attribute and go on. */
569 else if (var == 0 && offset && array_subscript_assignment)
570 {
571 var = mkglobal ? find_global_variable_noref (name) : find_variable_noref (name);
572 if (var && nameref_p (var))
573 {
574 internal_warning (_("%s: removing nameref attribute"), name);
575 FREE (value_cell (var)); /* XXX - bash-4.3 compat */
576 var_setvalue (var, (char *)NULL);
577 VUNSETATTR (var, att_nameref);
578 }
579 }
580#endif
581
582 /* See if we are trying to set flags or value for an existing nameref
583 that points to a non-existent variable: e.g.,
584 declare -n foo=bar
585 unset foo # unsets bar
586 declare -i foo
587 foo=4+4
588 declare -p foo */
589 if (var == 0 && (flags_on || flags_off || offset))
590 {
591 refvar = mkglobal ? find_global_variable_last_nameref (name, 0) : find_variable_last_nameref (name, 0);
592 if (refvar && nameref_p (refvar) == 0)
593 refvar = 0;
594 if (refvar)
595 var = mkglobal ? find_global_variable (nameref_cell (refvar)) : find_variable (nameref_cell (refvar));
596 if (refvar && var == 0)
597 {
598 oldname = name; /* need to free this */
599
600 namelen = strlen (nameref_cell (refvar));
601#if defined (ARRAY_VARS)
602 if (subscript_start)
603 {
604 *subscript_start = '['; /*]*/
605 namelen += strlen (subscript_start);
606 }
607#endif
608 name = xmalloc (namelen + 2 + strlen (value) + 1);
609 strcpy (name, nameref_cell (refvar));
610#if defined (ARRAY_VARS)
611 if (subscript_start)
612 strcpy (name + strlen (nameref_cell (refvar)), subscript_start);
613#endif
614 /* We are committed to using the new name, so reset */
615 if (offset)
616 {
617 /* Rebuild assignment and restore offset and value */
618 if (aflags & ASS_APPEND)
619 name[namelen++] = '+';
620 name[namelen++] = '=';
621 if (value && *value)
622 strcpy (name + namelen, value);
623 else
624 name[namelen] = '\0';
625 offset = assignment (name, 0);
626 /* if offset was valid previously, but the substituting
627 of the nameref value results in an invalid assignment,
628 throw an invalid identifier error */
629 if (offset == 0)
630 {
631 free (oldname);
632 sh_invalidid (name);
633 assign_error++;
634 NEXT_VARIABLE ();
635 }
636 name[offset] = '\0';
637 value = name + namelen;
638 }
639 free (oldname);
640 goto restart_new_var_name;
641 /* NOTREACHED */
642 }
643 }
7117c2d2 644 if (var == 0)
495aee44 645 var = mkglobal ? find_global_variable (name) : find_variable (name);
726f6388 646
a0c0a00f
CR
647#if defined (ARRAY_VARS)
648 var_exists = var != 0;
649 array_exists = var && (array_p (var) || assoc_p (var));
650 creating_array = flags_on & (att_array|att_assoc);
651#endif
652
ccc6cda3
JA
653 if (var == 0)
654 {
655#if defined (ARRAY_VARS)
3185942a 656 if (flags_on & att_assoc)
ac50fbac
CR
657 {
658 var = make_new_assoc_variable (name);
a0c0a00f 659 if (var && offset == 0 && no_invisible_vars == 0)
ac50fbac
CR
660 VSETATTR (var, att_invisible);
661 }
3185942a 662 else if ((flags_on & att_array) || making_array_special)
ac50fbac
CR
663 {
664 var = make_new_array_variable (name);
a0c0a00f 665 if (var && offset == 0 && no_invisible_vars == 0)
ac50fbac
CR
666 VSETATTR (var, att_invisible);
667 }
ccc6cda3
JA
668 else
669#endif
3185942a 670 {
a0c0a00f
CR
671 var = mkglobal ? bind_global_variable (name, (char *)NULL, ASS_FORCE) : bind_variable (name, (char *)NULL, ASS_FORCE);
672 if (var && offset == 0 && no_invisible_vars == 0)
673 VSETATTR (var, att_invisible);
674 }
675 if (var == 0)
676 {
677 /* Has to appear in brackets */
678 NEXT_VARIABLE ();
3185942a 679 }
a0c0a00f 680 created_var = 1;
ccc6cda3 681 }
ac50fbac
CR
682 /* Can't take an existing array variable and make it a nameref */
683 else if ((array_p (var) || assoc_p (var)) && (flags_on & att_nameref))
684 {
685 builtin_error (_("%s: reference variable cannot be an array"), name);
686 assign_error++;
687 NEXT_VARIABLE ();
688 }
a0c0a00f
CR
689 else if (nameref_p (var) && (flags_on & att_nameref) == 0 && (flags_off & att_nameref) == 0 && offset && valid_nameref_value (value, 1) == 0)
690 {
691 builtin_error (_("`%s': invalid variable name for name reference"), value);
692 any_failed++;
693 NEXT_VARIABLE ();
694 }
ac50fbac
CR
695 else if (flags_on & att_nameref)
696 {
a0c0a00f
CR
697#if 1
698 /* Check of offset is to allow an assignment to a nameref var as
699 part of the declare word to override existing value */
700 if (nameref_p (var) == 0 && var_isset (var) && offset == 0 && valid_nameref_value (value_cell (var), 0) == 0)
701 {
702 builtin_error (_("`%s': invalid variable name for name reference"), value_cell (var));
703 any_failed++;
704 NEXT_VARIABLE ();
705 }
706#endif
707 if (readonly_p (var))
708 {
709 sh_readonly (name);
710 any_failed++;
711 NEXT_VARIABLE ();
712 }
ac50fbac
CR
713 /* ksh93 compat: turning on nameref attribute turns off -ilu */
714 VUNSETATTR (var, att_integer|att_uppercase|att_lowercase|att_capcase);
715 }
726f6388 716
ccc6cda3 717 /* Cannot use declare +r to turn off readonly attribute. */
726f6388
JA
718 if (readonly_p (var) && (flags_off & att_readonly))
719 {
a0c0a00f 720 sh_readonly (name_cell (var));
726f6388
JA
721 any_failed++;
722 NEXT_VARIABLE ();
723 }
724
28ef6c31
JA
725 /* Cannot use declare to assign value to readonly or noassign
726 variable. */
727 if ((readonly_p (var) || noassign_p (var)) && offset)
ccc6cda3 728 {
28ef6c31 729 if (readonly_p (var))
7117c2d2 730 sh_readonly (name);
ccc6cda3
JA
731 assign_error++;
732 NEXT_VARIABLE ();
733 }
734
735#if defined (ARRAY_VARS)
a0c0a00f
CR
736 /* make declare a[2]=foo as similar to a[2]=foo as possible if
737 a is already an array or assoc variable. */
738 if (array_subscript_assignment && array_exists && creating_array == 0)
739 simple_array_assign = 1;
740 else if ((making_array_special || creating_array || array_exists) && offset)
ccc6cda3 741 {
95732b49
JA
742 int vlen;
743 vlen = STRLEN (value);
a0c0a00f
CR
744/*itrace("declare_builtin: name = %s value = %s flags = %d", name, value, wflags);*/
745 if (shell_compatibility_level > 43 && (wflags & W_COMPASSIGN) == 0 &&
746 value[0] == '(' && value[vlen-1] == ')')
747 {
748 /* The warning is only printed when using compound assignment
749 to an array variable that doesn't already exist. We use
750 creating_array to allow things like
751 declare -a foo$bar='(abc)' to work. */
752 if (array_exists == 0 && creating_array == 0)
753 internal_warning (_("%s: quoted compound array assignment deprecated"), list->word->word);
754 compound_array_assign = array_exists || creating_array;
755 simple_array_assign = making_array_special;
756 }
757 else if (value[0] == '(' && value[vlen-1] == ')' && (shell_compatibility_level < 44 || (wflags & W_COMPASSIGN)))
f73dda09 758 compound_array_assign = 1;
ccc6cda3 759 else
f73dda09 760 simple_array_assign = 1;
ccc6cda3
JA
761 }
762
3185942a
JA
763 /* Cannot use declare +a name or declare +A name to remove an
764 array variable. */
765 if (((flags_off & att_array) && array_p (var)) || ((flags_off & att_assoc) && assoc_p (var)))
ccc6cda3 766 {
b80f6443 767 builtin_error (_("%s: cannot destroy array variables in this way"), name);
ccc6cda3
JA
768 any_failed++;
769 NEXT_VARIABLE ();
770 }
771
3185942a
JA
772 if ((flags_on & att_array) && assoc_p (var))
773 {
774 builtin_error (_("%s: cannot convert associative to indexed array"), name);
775 any_failed++;
776 NEXT_VARIABLE ();
777 }
778 if ((flags_on & att_assoc) && array_p (var))
779 {
780 builtin_error (_("%s: cannot convert indexed to associative array"), name);
781 any_failed++;
782 NEXT_VARIABLE ();
783 }
784
785 /* declare -A name[[n]] makes name an associative array variable. */
786 if (flags_on & att_assoc)
787 {
788 if (assoc_p (var) == 0)
789 var = convert_var_to_assoc (var);
790 }
791 /* declare -a name[[n]] or declare name[n] makes name an indexed
792 array variable. */
89a92869 793 else if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0 && assoc_p (var) == 0)
ccc6cda3
JA
794 var = convert_var_to_array (var);
795#endif /* ARRAY_VARS */
796
ac50fbac
CR
797 /* XXX - we note that we are turning on nameref attribute and defer
798 setting it until the assignment has been made so we don't do an
799 inadvertent nameref lookup. Might have to do the same thing for
800 flags_off&att_nameref. */
801 /* XXX - ksh93 makes it an error to set a readonly nameref variable
802 using a single typeset command. */
803 onref = (flags_on & att_nameref);
804 flags_on &= ~att_nameref;
805#if defined (ARRAY_VARS)
806 if (array_p (var) || assoc_p (var)
807 || (offset && compound_array_assign)
808 || simple_array_assign)
809 onref = 0; /* array variables may not be namerefs */
810#endif
811
812 /* ksh93 seems to do this */
813 offref = (flags_off & att_nameref);
814 flags_off &= ~att_nameref;
815
bb70624e
JA
816 VSETATTR (var, flags_on);
817 VUNSETATTR (var, flags_off);
726f6388 818
ccc6cda3 819#if defined (ARRAY_VARS)
f73dda09 820 if (offset && compound_array_assign)
a0c0a00f 821 assign_array_var_from_string (var, value, aflags|ASS_FORCE);
f73dda09
JA
822 else if (simple_array_assign && subscript_start)
823 {
0001803f 824 /* declare [-aA] name[N]=value */
f73dda09 825 *subscript_start = '['; /* ] */
a0c0a00f
CR
826 /* XXX - problem here with appending */
827 var = assign_array_element (name, value, aflags&ASS_APPEND); /* XXX - not aflags */
f73dda09 828 *subscript_start = '\0';
307dbc7f
CR
829 if (var == 0) /* some kind of assignment error */
830 {
831 assign_error++;
ac50fbac
CR
832 flags_on |= onref;
833 flags_off |= offref;
307dbc7f
CR
834 NEXT_VARIABLE ();
835 }
f73dda09
JA
836 }
837 else if (simple_array_assign)
0001803f
CR
838 {
839 /* let bind_{array,assoc}_variable take care of this. */
840 if (assoc_p (var))
a0c0a00f 841 bind_assoc_variable (var, name, savestring ("0"), value, aflags|ASS_FORCE);
0001803f 842 else
a0c0a00f 843 bind_array_variable (name, 0, value, aflags|ASS_FORCE);
0001803f 844 }
ccc6cda3
JA
845 else
846#endif
a0c0a00f 847 /* XXX - no ASS_FORCE here */
bb70624e
JA
848 /* bind_variable_value duplicates the essential internals of
849 bind_variable() */
726f6388 850 if (offset)
ac50fbac 851 {
a0c0a00f 852 if (onref || nameref_p (var))
ac50fbac
CR
853 aflags |= ASS_NAMEREF;
854 v = bind_variable_value (var, value, aflags);
a0c0a00f 855 if (v == 0 && (onref || nameref_p (var)))
ac50fbac 856 {
a0c0a00f
CR
857 if (valid_nameref_value (value, 1) == 0)
858 sh_invalidid (value);
ac50fbac
CR
859 assign_error++;
860 /* XXX - unset this variable? or leave it as normal var? */
a0c0a00f
CR
861 if (created_var)
862 delete_var (var->name, mkglobal ? global_variables : shell_variables);
863 flags_on |= onref; /* undo change from above */
864 flags_off |= offref;
ac50fbac
CR
865 NEXT_VARIABLE ();
866 }
867 }
cce855bc
JA
868
869 /* If we found this variable in the temporary environment, as with
870 `var=value declare -x var', make sure it is treated identically
871 to `var=value export var'. Do the same for `declare -r' and
872 `readonly'. Preserve the attributes, except for att_tempvar. */
7117c2d2
JA
873 /* XXX -- should this create a variable in the global scope, or
874 modify the local variable flags? ksh93 has it modify the
875 global scope.
876 Need to handle case like in set_var_attribute where a temporary
877 variable is in the same table as the function local vars. */
cce855bc
JA
878 if ((flags_on & (att_exported|att_readonly)) && tempvar_p (var))
879 {
880 SHELL_VAR *tv;
7117c2d2
JA
881 char *tvalue;
882
883 tv = find_tempenv_variable (var->name);
884 if (tv)
885 {
886 tvalue = var_isset (var) ? savestring (value_cell (var)) : savestring ("");
95732b49 887 tv = bind_variable (var->name, tvalue, 0);
7117c2d2
JA
888 tv->attributes |= var->attributes & ~att_tempvar;
889 if (tv->context > 0)
890 VSETATTR (tv, att_propagate);
891 free (tvalue);
892 }
893 VSETATTR (var, att_propagate);
cce855bc 894 }
726f6388
JA
895 }
896
ac50fbac
CR
897 /* Turn on nameref attribute we deferred above. */
898 /* XXX - should we turn on the noassign attribute for consistency with
899 ksh93 when we turn on the nameref attribute? */
900 VSETATTR (var, onref);
901 flags_on |= onref;
902 VUNSETATTR (var, offref);
903 flags_off |= offref;
a0c0a00f
CR
904 /* Yuck. ksh93 compatibility. XXX - need to investigate more but
905 definitely happens when turning off nameref attribute on nameref
906 (see comments above). Under no circumstances allow this to turn
907 off readonly attribute on readonly nameref variable. */
ac50fbac 908 if (refvar)
a0c0a00f
CR
909 {
910 if (flags_off & att_readonly)
911 flags_off &= ~att_readonly;
912 VUNSETATTR (refvar, flags_off);
913 }
ac50fbac 914
726f6388
JA
915 stupidly_hack_special_variables (name);
916
917 NEXT_VARIABLE ();
918 }
ccc6cda3
JA
919
920 return (assign_error ? EX_BADASSIGN
921 : ((any_failed == 0) ? EXECUTION_SUCCESS
922 : EXECUTION_FAILURE));
726f6388 923}