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