]> git.ipfire.org Git - thirdparty/bash.git/blob - builtins/declare.def
Bash-4.3 patch 39
[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-2012 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 NAMEs 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 NAMEs 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 [-aAfFgilrtux] [-p] name[=value] ...
66 Set variable values and attributes.
67
68 Obsolete. 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 "common.h"
87 #include "builtext.h"
88 #include "bashgetopt.h"
89
90 extern int array_needs_making;
91 extern int posixly_correct;
92
93 static int declare_internal __P((register WORD_LIST *, int));
94
95 /* Declare or change variable attributes. */
96 int
97 declare_builtin (list)
98 register WORD_LIST *list;
99 {
100 return (declare_internal (list, 0));
101 }
102
103 $BUILTIN local
104 $FUNCTION local_builtin
105 $SHORT_DOC local [option] name[=value] ...
106 Define local variables.
107
108 Create a local variable called NAME, and give it VALUE. OPTION can
109 be any option accepted by `declare'.
110
111 Local variables can only be used within a function; they are visible
112 only to the function where they are defined and its children.
113
114 Exit Status:
115 Returns success unless an invalid option is supplied, a variable
116 assignment error occurs, or the shell is not executing a function.
117 $END
118 int
119 local_builtin (list)
120 register WORD_LIST *list;
121 {
122 if (variable_context)
123 return (declare_internal (list, 1));
124 else
125 {
126 builtin_error (_("can only be used in a function"));
127 return (EXECUTION_FAILURE);
128 }
129 }
130
131 #if defined (ARRAY_VARS)
132 # define DECLARE_OPTS "+acfgilnprtuxAF"
133 #else
134 # define DECLARE_OPTS "+cfgilnprtuxF"
135 #endif
136
137 /* The workhorse function. */
138 static int
139 declare_internal (list, local_var)
140 register WORD_LIST *list;
141 int local_var;
142 {
143 int flags_on, flags_off, *flags;
144 int any_failed, assign_error, pflag, nodefs, opt, mkglobal, onref, offref;
145 char *t, *subscript_start;
146 SHELL_VAR *var, *refvar, *v;
147 FUNCTION_DEF *shell_fn;
148
149 flags_on = flags_off = any_failed = assign_error = pflag = nodefs = mkglobal = 0;
150 refvar = (SHELL_VAR *)NULL;
151 reset_internal_getopt ();
152 while ((opt = internal_getopt (list, DECLARE_OPTS)) != EOF)
153 {
154 flags = list_opttype == '+' ? &flags_off : &flags_on;
155
156 switch (opt)
157 {
158 case 'a':
159 #if defined (ARRAY_VARS)
160 *flags |= att_array;
161 break;
162 #else
163 builtin_usage ();
164 return (EX_USAGE);
165 #endif
166 case 'A':
167 #if defined (ARRAY_VARS)
168 *flags |= att_assoc;
169 break;
170 #else
171 builtin_usage ();
172 return (EX_USAGE);
173 #endif
174 case 'p':
175 if (local_var == 0)
176 pflag++;
177 break;
178 case 'F':
179 nodefs++;
180 *flags |= att_function;
181 break;
182 case 'f':
183 *flags |= att_function;
184 break;
185 case 'g':
186 if (flags == &flags_on)
187 mkglobal = 1;
188 break;
189 case 'i':
190 *flags |= att_integer;
191 break;
192 case 'n':
193 *flags |= att_nameref;
194 break;
195 case 'r':
196 *flags |= att_readonly;
197 break;
198 case 't':
199 *flags |= att_trace;
200 break;
201 case 'x':
202 *flags |= att_exported;
203 array_needs_making = 1;
204 break;
205 #if defined (CASEMOD_ATTRS)
206 # if defined (CASEMOD_CAPCASE)
207 case 'c':
208 *flags |= att_capcase;
209 if (flags == &flags_on)
210 flags_off |= att_uppercase|att_lowercase;
211 break;
212 # endif
213 case 'l':
214 *flags |= att_lowercase;
215 if (flags == &flags_on)
216 flags_off |= att_capcase|att_uppercase;
217 break;
218 case 'u':
219 *flags |= att_uppercase;
220 if (flags == &flags_on)
221 flags_off |= att_capcase|att_lowercase;
222 break;
223 #endif /* CASEMOD_ATTRS */
224 default:
225 builtin_usage ();
226 return (EX_USAGE);
227 }
228 }
229
230 list = loptend;
231
232 /* If there are no more arguments left, then we just want to show
233 some variables. */
234 if (list == 0) /* declare -[aAfFirtx] */
235 {
236 /* Show local variables defined at this context level if this is
237 the `local' builtin. */
238 if (local_var)
239 {
240 register SHELL_VAR **vlist;
241 register int i;
242
243 vlist = all_local_variables ();
244
245 if (vlist)
246 {
247 for (i = 0; vlist[i]; i++)
248 print_assignment (vlist[i]);
249
250 free (vlist);
251 }
252 }
253 else if (pflag && (flags_on == 0 || flags_on == att_function))
254 show_all_var_attributes (flags_on == 0, nodefs);
255 else if (flags_on == 0)
256 return (set_builtin ((WORD_LIST *)NULL));
257 else
258 set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs);
259
260 return (sh_chkwrite (EXECUTION_SUCCESS));
261 }
262
263 if (pflag) /* declare -p [-aAfFirtx] name [name...] */
264 {
265 for (any_failed = 0; list; list = list->next)
266 {
267 if (flags_on & att_function)
268 pflag = show_func_attributes (list->word->word, nodefs);
269 else
270 pflag = show_name_attributes (list->word->word, nodefs);
271 if (pflag)
272 {
273 sh_notfound (list->word->word);
274 any_failed++;
275 }
276 }
277 return (sh_chkwrite (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS));
278 }
279
280 #define NEXT_VARIABLE() free (name); list = list->next; continue
281
282 /* There are arguments left, so we are making variables. */
283 while (list) /* declare [-aAfFirx] name [name ...] */
284 {
285 char *value, *name;
286 int offset, aflags;
287 #if defined (ARRAY_VARS)
288 int making_array_special, compound_array_assign, simple_array_assign;
289 #endif
290
291 name = savestring (list->word->word);
292 offset = assignment (name, 0);
293 aflags = 0;
294
295 if (offset) /* declare [-aAfFirx] name=value */
296 {
297 name[offset] = '\0';
298 value = name + offset + 1;
299 if (name[offset - 1] == '+')
300 {
301 aflags |= ASS_APPEND;
302 name[offset - 1] = '\0';
303 }
304 }
305 else
306 value = "";
307
308 /* Do some lexical error checking on the LHS and RHS of the assignment
309 that is specific to nameref variables. */
310 if (flags_on & att_nameref)
311 {
312 #if defined (ARRAY_VARIABLES)
313 if (valid_array_reference (name))
314 {
315 builtin_error (_("%s: reference variable cannot be an array"), name);
316 assign_error++;
317 NEXT_VARIABLE ();
318 }
319 else
320 #endif
321 /* disallow self references at global scope */
322 if (STREQ (name, value) && variable_context == 0)
323 {
324 builtin_error (_("%s: nameref variable self references not allowed"), name);
325 assign_error++;
326 NEXT_VARIABLE ();
327 }
328 }
329
330 #if defined (ARRAY_VARS)
331 compound_array_assign = simple_array_assign = 0;
332 subscript_start = (char *)NULL;
333 if (t = strchr (name, '[')) /* ] */
334 {
335 /* If offset != 0 we have already validated any array reference */
336 if (offset == 0 && valid_array_reference (name) == 0)
337 {
338 sh_invalidid (name);
339 assign_error++;
340 NEXT_VARIABLE ();
341 }
342 subscript_start = t;
343 *t = '\0';
344 making_array_special = 1;
345 }
346 else
347 making_array_special = 0;
348 #endif
349
350 /* If we're in posix mode or not looking for a shell function (since
351 shell function names don't have to be valid identifiers when the
352 shell's not in posix mode), check whether or not the argument is a
353 valid, well-formed shell identifier. */
354 if ((posixly_correct || (flags_on & att_function) == 0) && legal_identifier (name) == 0)
355 {
356 sh_invalidid (name);
357 assign_error++;
358 NEXT_VARIABLE ();
359 }
360
361 /* If VARIABLE_CONTEXT has a non-zero value, then we are executing
362 inside of a function. This means we should make local variables,
363 not global ones. */
364
365 /* XXX - this has consequences when we're making a local copy of a
366 variable that was in the temporary environment. Watch out
367 for this. */
368 refvar = (SHELL_VAR *)NULL;
369 if (variable_context && mkglobal == 0 && ((flags_on & att_function) == 0))
370 {
371 #if defined (ARRAY_VARS)
372 if (flags_on & att_assoc)
373 var = make_local_assoc_variable (name);
374 else if ((flags_on & att_array) || making_array_special)
375 var = make_local_array_variable (name, making_array_special);
376 else
377 #endif
378 var = make_local_variable (name); /* sets att_invisible for new vars */
379 if (var == 0)
380 {
381 any_failed++;
382 NEXT_VARIABLE ();
383 }
384 }
385 else
386 var = (SHELL_VAR *)NULL;
387
388 /* If we are declaring a function, then complain about it in some way.
389 We don't let people make functions by saying `typeset -f foo=bar'. */
390
391 /* There should be a way, however, to let people look at a particular
392 function definition by saying `typeset -f foo'. */
393
394 if (flags_on & att_function)
395 {
396 if (offset) /* declare -f [-rix] foo=bar */
397 {
398 builtin_error (_("cannot use `-f' to make functions"));
399 free (name);
400 return (EXECUTION_FAILURE);
401 }
402 else /* declare -f [-rx] name [name...] */
403 {
404 var = find_function (name);
405
406 if (var)
407 {
408 if (readonly_p (var) && (flags_off & att_readonly))
409 {
410 builtin_error (_("%s: readonly function"), name);
411 any_failed++;
412 NEXT_VARIABLE ();
413 }
414
415 /* declare -[Ff] name [name...] */
416 if (flags_on == att_function && flags_off == 0)
417 {
418 #if defined (DEBUGGER)
419 if (nodefs && debugging_mode)
420 {
421 shell_fn = find_function_def (var->name);
422 if (shell_fn)
423 printf ("%s %d %s\n", var->name, shell_fn->line, shell_fn->source_file);
424 else
425 printf ("%s\n", var->name);
426 }
427 else
428 #endif /* DEBUGGER */
429 {
430 t = nodefs ? var->name
431 : named_function_string (name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL);
432 printf ("%s\n", t);
433 any_failed = sh_chkwrite (any_failed);
434 }
435 }
436 else /* declare -[fF] -[rx] name [name...] */
437 {
438 VSETATTR (var, flags_on);
439 VUNSETATTR (var, flags_off);
440 }
441 }
442 else
443 any_failed++;
444 NEXT_VARIABLE ();
445 }
446 }
447 else /* declare -[aAirx] name [name...] */
448 {
449 /* Non-null if we just created or fetched a local variable. */
450 /* Here's what ksh93 seems to do. If we are modifying an existing
451 nameref variable, we don't follow the nameref chain past the last
452 nameref, and we set the nameref variable's value so future
453 references to that variable will return the value of the variable
454 we're assigning right now. */
455 if (var == 0 && (flags_on & att_nameref))
456 {
457 /* See if we are trying to modify an existing nameref variable */
458 var = mkglobal ? find_global_variable_last_nameref (name) : find_variable_last_nameref (name);
459 if (var && nameref_p (var) == 0)
460 var = 0;
461 }
462 /* However, if we're turning off the nameref attribute on an existing
463 nameref variable, we first follow the nameref chain to the end,
464 modify the value of the variable this nameref variable references,
465 *CHANGING ITS VALUE AS A SIDE EFFECT* then turn off the nameref
466 flag *LEAVING THE NAMEREF VARIABLE'S VALUE UNCHANGED* */
467 else if (var == 0 && (flags_off & att_nameref))
468 {
469 /* See if we are trying to modify an existing nameref variable */
470 refvar = mkglobal ? find_global_variable_last_nameref (name) : find_variable_last_nameref (name);
471 if (refvar && nameref_p (refvar) == 0)
472 refvar = 0;
473 if (refvar)
474 var = mkglobal ? find_global_variable (nameref_cell (refvar)) : find_variable (nameref_cell (refvar));
475 }
476
477 if (var == 0)
478 var = mkglobal ? find_global_variable (name) : find_variable (name);
479
480 if (var == 0)
481 {
482 #if defined (ARRAY_VARS)
483 if (flags_on & att_assoc)
484 {
485 var = make_new_assoc_variable (name);
486 if (offset == 0)
487 VSETATTR (var, att_invisible);
488 }
489 else if ((flags_on & att_array) || making_array_special)
490 {
491 var = make_new_array_variable (name);
492 if (offset == 0)
493 VSETATTR (var, att_invisible);
494 }
495 else
496 #endif
497
498 if (offset)
499 var = mkglobal ? bind_global_variable (name, "", 0) : bind_variable (name, "", 0);
500 else
501 {
502 var = mkglobal ? bind_global_variable (name, (char *)NULL, 0) : bind_variable (name, (char *)NULL, 0);
503 VSETATTR (var, att_invisible);
504 }
505 }
506 /* Can't take an existing array variable and make it a nameref */
507 else if ((array_p (var) || assoc_p (var)) && (flags_on & att_nameref))
508 {
509 builtin_error (_("%s: reference variable cannot be an array"), name);
510 assign_error++;
511 NEXT_VARIABLE ();
512 }
513 else if (flags_on & att_nameref)
514 {
515 /* ksh93 compat: turning on nameref attribute turns off -ilu */
516 VUNSETATTR (var, att_integer|att_uppercase|att_lowercase|att_capcase);
517 }
518
519 /* Cannot use declare +r to turn off readonly attribute. */
520 if (readonly_p (var) && (flags_off & att_readonly))
521 {
522 sh_readonly (name);
523 any_failed++;
524 NEXT_VARIABLE ();
525 }
526
527 /* Cannot use declare to assign value to readonly or noassign
528 variable. */
529 if ((readonly_p (var) || noassign_p (var)) && offset)
530 {
531 if (readonly_p (var))
532 sh_readonly (name);
533 assign_error++;
534 NEXT_VARIABLE ();
535 }
536
537 #if defined (ARRAY_VARS)
538 if ((making_array_special || (flags_on & (att_array|att_assoc)) || array_p (var) || assoc_p (var)) && offset)
539 {
540 int vlen;
541 vlen = STRLEN (value);
542
543 if (value[0] == '(' && value[vlen-1] == ')')
544 compound_array_assign = 1;
545 else
546 simple_array_assign = 1;
547 }
548
549 /* Cannot use declare +a name or declare +A name to remove an
550 array variable. */
551 if (((flags_off & att_array) && array_p (var)) || ((flags_off & att_assoc) && assoc_p (var)))
552 {
553 builtin_error (_("%s: cannot destroy array variables in this way"), name);
554 any_failed++;
555 NEXT_VARIABLE ();
556 }
557
558 if ((flags_on & att_array) && assoc_p (var))
559 {
560 builtin_error (_("%s: cannot convert associative to indexed array"), name);
561 any_failed++;
562 NEXT_VARIABLE ();
563 }
564 if ((flags_on & att_assoc) && array_p (var))
565 {
566 builtin_error (_("%s: cannot convert indexed to associative array"), name);
567 any_failed++;
568 NEXT_VARIABLE ();
569 }
570
571 /* declare -A name[[n]] makes name an associative array variable. */
572 if (flags_on & att_assoc)
573 {
574 if (assoc_p (var) == 0)
575 var = convert_var_to_assoc (var);
576 }
577 /* declare -a name[[n]] or declare name[n] makes name an indexed
578 array variable. */
579 else if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0 && assoc_p (var) == 0)
580 var = convert_var_to_array (var);
581 #endif /* ARRAY_VARS */
582
583 /* XXX - we note that we are turning on nameref attribute and defer
584 setting it until the assignment has been made so we don't do an
585 inadvertent nameref lookup. Might have to do the same thing for
586 flags_off&att_nameref. */
587 /* XXX - ksh93 makes it an error to set a readonly nameref variable
588 using a single typeset command. */
589 onref = (flags_on & att_nameref);
590 flags_on &= ~att_nameref;
591 #if defined (ARRAY_VARS)
592 if (array_p (var) || assoc_p (var)
593 || (offset && compound_array_assign)
594 || simple_array_assign)
595 onref = 0; /* array variables may not be namerefs */
596 #endif
597
598 /* ksh93 seems to do this */
599 offref = (flags_off & att_nameref);
600 flags_off &= ~att_nameref;
601
602 VSETATTR (var, flags_on);
603 VUNSETATTR (var, flags_off);
604
605 #if defined (ARRAY_VARS)
606 if (offset && compound_array_assign)
607 assign_array_var_from_string (var, value, aflags);
608 else if (simple_array_assign && subscript_start)
609 {
610 /* declare [-aA] name[N]=value */
611 *subscript_start = '['; /* ] */
612 var = assign_array_element (name, value, 0); /* XXX - not aflags */
613 *subscript_start = '\0';
614 if (var == 0) /* some kind of assignment error */
615 {
616 assign_error++;
617 flags_on |= onref;
618 flags_off |= offref;
619 NEXT_VARIABLE ();
620 }
621 }
622 else if (simple_array_assign)
623 {
624 /* let bind_{array,assoc}_variable take care of this. */
625 if (assoc_p (var))
626 bind_assoc_variable (var, name, savestring ("0"), value, aflags);
627 else
628 bind_array_variable (name, 0, value, aflags);
629 }
630 else
631 #endif
632 /* bind_variable_value duplicates the essential internals of
633 bind_variable() */
634 if (offset)
635 {
636 if (onref)
637 aflags |= ASS_NAMEREF;
638 v = bind_variable_value (var, value, aflags);
639 if (v == 0 && onref)
640 {
641 sh_invalidid (value);
642 assign_error++;
643 /* XXX - unset this variable? or leave it as normal var? */
644 delete_var (var->name, mkglobal ? global_variables : shell_variables);
645 NEXT_VARIABLE ();
646 }
647 }
648
649 /* If we found this variable in the temporary environment, as with
650 `var=value declare -x var', make sure it is treated identically
651 to `var=value export var'. Do the same for `declare -r' and
652 `readonly'. Preserve the attributes, except for att_tempvar. */
653 /* XXX -- should this create a variable in the global scope, or
654 modify the local variable flags? ksh93 has it modify the
655 global scope.
656 Need to handle case like in set_var_attribute where a temporary
657 variable is in the same table as the function local vars. */
658 if ((flags_on & (att_exported|att_readonly)) && tempvar_p (var))
659 {
660 SHELL_VAR *tv;
661 char *tvalue;
662
663 tv = find_tempenv_variable (var->name);
664 if (tv)
665 {
666 tvalue = var_isset (var) ? savestring (value_cell (var)) : savestring ("");
667 tv = bind_variable (var->name, tvalue, 0);
668 tv->attributes |= var->attributes & ~att_tempvar;
669 if (tv->context > 0)
670 VSETATTR (tv, att_propagate);
671 free (tvalue);
672 }
673 VSETATTR (var, att_propagate);
674 }
675 }
676
677 /* Turn on nameref attribute we deferred above. */
678 /* XXX - should we turn on the noassign attribute for consistency with
679 ksh93 when we turn on the nameref attribute? */
680 VSETATTR (var, onref);
681 flags_on |= onref;
682 VUNSETATTR (var, offref);
683 flags_off |= offref;
684 /* Yuck. ksh93 compatibility */
685 if (refvar)
686 VUNSETATTR (refvar, flags_off);
687
688 stupidly_hack_special_variables (name);
689
690 NEXT_VARIABLE ();
691 }
692
693 return (assign_error ? EX_BADASSIGN
694 : ((any_failed == 0) ? EXECUTION_SUCCESS
695 : EXECUTION_FAILURE));
696 }