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