Imported from ../bash-3.0.tar.gz.
[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-2003 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 it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
12
13 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with Bash; see the file COPYING.  If not, write to the Free Software
20 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
21
22 $PRODUCES declare.c
23
24 $BUILTIN declare
25 $FUNCTION declare_builtin
26 $SHORT_DOC declare [-afFirtx] [-p] [name[=value] ...]
27 Declare variables and/or give them attributes.  If no NAMEs are
28 given, then display the values of variables instead.  The -p option
29 will display the attributes and values of each NAME.
30
31 The flags are:
32
33   -a    to make NAMEs arrays (if supported)
34   -f    to select from among function names only
35   -F    to display function names (and line number and source file name if
36         debugging) without definitions 
37   -i    to make NAMEs have the `integer' attribute
38   -r    to make NAMEs readonly
39   -t    to make NAMEs have the `trace' attribute
40   -x    to make NAMEs export
41
42 Variables with the integer attribute have arithmetic evaluation (see
43 `let') done when the variable is assigned to.
44
45 When displaying values of variables, -f displays a function's name
46 and definition.  The -F option restricts the display to function
47 name only.
48
49 Using `+' instead of `-' turns off the given attribute instead.  When
50 used in a function, makes NAMEs local, as with the `local' command.
51 $END
52
53 $BUILTIN typeset
54 $FUNCTION declare_builtin
55 $SHORT_DOC typeset [-afFirtx] [-p] name[=value] ...
56 Obsolete.  See `declare'.
57 $END
58
59 #include <config.h>
60
61 #if defined (HAVE_UNISTD_H)
62 #  ifdef _MINIX
63 #    include <sys/types.h>
64 #  endif
65 #  include <unistd.h>
66 #endif
67
68 #include <stdio.h>
69
70 #include "../bashansi.h"
71 #include "../bashintl.h"
72
73 #include "../shell.h"
74 #include "common.h"
75 #include "builtext.h"
76 #include "bashgetopt.h"
77
78 extern int array_needs_making;
79
80 static int declare_internal __P((register WORD_LIST *, int));
81
82 /* Declare or change variable attributes. */
83 int
84 declare_builtin (list)
85      register WORD_LIST *list;
86 {
87   return (declare_internal (list, 0));
88 }
89
90 $BUILTIN local
91 $FUNCTION local_builtin
92 $SHORT_DOC local name[=value] ...
93 Create a local variable called NAME, and give it VALUE.  LOCAL
94 can only be used within a function; it makes the variable NAME
95 have a visible scope restricted to that function and its children.
96 $END
97 int
98 local_builtin (list)
99      register WORD_LIST *list;
100 {
101   if (variable_context)
102     return (declare_internal (list, 1));
103   else
104     {
105       builtin_error (_("can only be used in a function"));
106       return (EXECUTION_FAILURE);
107     }
108 }
109
110 #if defined (ARRAY_VARS)
111 #  define DECLARE_OPTS  "+afiprtxF"
112 #else
113 #  define DECLARE_OPTS  "+fiprtxF"
114 #endif
115
116 /* The workhorse function. */
117 static int
118 declare_internal (list, local_var)
119      register WORD_LIST *list;
120      int local_var;
121 {
122   int flags_on, flags_off, *flags, any_failed, assign_error, pflag, nodefs, opt;
123   char *t, *subscript_start;
124   SHELL_VAR *var;
125   FUNCTION_DEF *shell_fn;
126
127   flags_on = flags_off = any_failed = assign_error = pflag = nodefs = 0;
128   reset_internal_getopt ();
129   while ((opt = internal_getopt (list, DECLARE_OPTS)) != EOF)
130     {
131       flags = list_opttype == '+' ? &flags_off : &flags_on;
132
133       switch (opt)
134         {
135         case 'a':
136 #if defined (ARRAY_VARS)
137           *flags |= att_array;
138 #endif
139           break;
140         case 'p':
141           if (local_var == 0)
142             pflag++;
143           break;
144         case 'F':
145           nodefs++;
146           *flags |= att_function;
147           break;
148         case 'f':
149           *flags |= att_function;
150           break;
151         case 'i':
152           *flags |= att_integer;
153           break;
154         case 'r':
155           *flags |= att_readonly;
156           break;
157         case 't':
158           *flags |= att_trace;
159           break;
160         case 'x':
161           *flags |= att_exported;
162           array_needs_making = 1;
163           break;
164         default:
165           builtin_usage ();
166           return (EX_USAGE);
167         }
168     }
169
170   list = loptend;
171
172   /* If there are no more arguments left, then we just want to show
173      some variables. */
174   if (list == 0)        /* declare -[afFirtx] */
175     {
176       /* Show local variables defined at this context level if this is
177          the `local' builtin. */
178       if (local_var)
179         {
180           register SHELL_VAR **vlist;
181           register int i;
182
183           vlist = all_local_variables ();
184
185           if (vlist)
186             {
187               for (i = 0; vlist[i]; i++)
188                 print_assignment (vlist[i]);
189
190               free (vlist);
191             }
192         }
193       else
194         {
195           if (flags_on == 0)
196             set_builtin ((WORD_LIST *)NULL);
197           else
198             set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs);
199         }
200
201       fflush (stdout);
202       return (EXECUTION_SUCCESS);
203     }
204
205   if (pflag)    /* declare -p [-afFirtx] name [name...] */
206     {
207       for (any_failed = 0; list; list = list->next)
208         {
209           pflag = show_name_attributes (list->word->word, nodefs);
210           if (pflag)
211             {
212               sh_notfound (list->word->word);
213               any_failed++;
214             }
215         }
216       return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
217     }
218
219 #define NEXT_VARIABLE() free (name); list = list->next; continue
220
221   /* There are arguments left, so we are making variables. */
222   while (list)          /* declare [-afFirx] name [name ...] */
223     {
224       char *value, *name;
225       int offset;
226 #if defined (ARRAY_VARS)
227       int making_array_special, compound_array_assign, simple_array_assign;
228 #endif
229
230       name = savestring (list->word->word);
231       offset = assignment (name, 0);
232
233       if (offset)       /* declare [-afFirx] name=value */
234         {
235           name[offset] = '\0';
236           value = name + offset + 1;
237         }
238       else
239         value = "";
240
241 #if defined (ARRAY_VARS)
242       compound_array_assign = simple_array_assign = 0;
243       subscript_start = (char *)NULL;
244       if (t = strchr (name, '['))       /* ] */
245         {
246           subscript_start = t;
247           *t = '\0';
248           making_array_special = 1;
249         }
250       else
251         making_array_special = 0;
252 #endif
253         
254       if (legal_identifier (name) == 0)
255         {
256           sh_invalidid (name);
257           assign_error++;
258           NEXT_VARIABLE ();
259         }
260
261       /* If VARIABLE_CONTEXT has a non-zero value, then we are executing
262          inside of a function.  This means we should make local variables,
263          not global ones. */
264
265       /* XXX - this has consequences when we're making a local copy of a
266                variable that was in the temporary environment.  Watch out
267                for this. */
268       if (variable_context && ((flags_on & att_function) == 0))
269         {
270 #if defined (ARRAY_VARS)
271           if ((flags_on & att_array) || making_array_special)
272             var = make_local_array_variable (name);
273           else
274 #endif
275           var = make_local_variable (name);
276           if (var == 0)
277             {
278               any_failed++;
279               NEXT_VARIABLE ();
280             }
281         }
282       else
283         var = (SHELL_VAR *)NULL;
284
285       /* If we are declaring a function, then complain about it in some way.
286          We don't let people make functions by saying `typeset -f foo=bar'. */
287
288       /* There should be a way, however, to let people look at a particular
289          function definition by saying `typeset -f foo'. */
290
291       if (flags_on & att_function)
292         {
293           if (offset)   /* declare -f [-rix] foo=bar */
294             {
295               builtin_error (_("cannot use `-f' to make functions"));
296               free (name);
297               return (EXECUTION_FAILURE);
298             }
299           else          /* declare -f [-rx] name [name...] */
300             {
301               var = find_function (name);
302
303               if (var)
304                 {
305                   if (readonly_p (var) && (flags_off & att_readonly))
306                     {
307                       builtin_error (_("%s: readonly function"), name);
308                       any_failed++;
309                       NEXT_VARIABLE ();
310                     }
311
312                   /* declare -[Ff] name [name...] */
313                   if (flags_on == att_function && flags_off == 0)
314                     {
315 #if defined (DEBUGGER)
316                       if (nodefs && debugging_mode)
317                         {
318                           shell_fn = find_function_def (var->name);
319                           if (shell_fn)
320                             printf ("%s %d %s\n", var->name, shell_fn->line, shell_fn->source_file);
321                           else
322                             printf ("%s\n", var->name);
323                         }
324                       else
325 #endif /* DEBUGGER */
326                         {       
327                           t = nodefs ? var->name
328                                      : named_function_string (name, function_cell (var), 1);
329                           printf ("%s\n", t);
330                         }
331                     }
332                   else          /* declare -[fF] -[rx] name [name...] */
333                     {
334                       VSETATTR (var, flags_on);
335                       VUNSETATTR (var, flags_off);
336                     }
337                 }
338               else
339                 any_failed++;
340               NEXT_VARIABLE ();
341             }
342         }
343       else              /* declare -[airx] name [name...] */
344         {
345           /* Non-null if we just created or fetched a local variable. */
346           if (var == 0)
347             var = find_variable (name);
348
349           if (var == 0)
350             {
351 #if defined (ARRAY_VARS)
352               if ((flags_on & att_array) || making_array_special)
353                 var = make_new_array_variable (name);
354               else
355 #endif
356               var = bind_variable (name, "");
357             }
358
359           /* Cannot use declare +r to turn off readonly attribute. */ 
360           if (readonly_p (var) && (flags_off & att_readonly))
361             {
362               sh_readonly (name);
363               any_failed++;
364               NEXT_VARIABLE ();
365             }
366
367           /* Cannot use declare to assign value to readonly or noassign
368              variable. */
369           if ((readonly_p (var) || noassign_p (var)) && offset)
370             {
371               if (readonly_p (var))
372                 sh_readonly (name);
373               assign_error++;
374               NEXT_VARIABLE ();
375             }
376
377 #if defined (ARRAY_VARS)
378           if ((making_array_special || (flags_on & att_array) || array_p (var)) && offset)
379             {
380               if (value[0] == '(' && strchr (value, ')'))
381                 compound_array_assign = 1;
382               else
383                 simple_array_assign = 1;
384             }
385
386           /* Cannot use declare +a name to remove an array variable. */
387           if ((flags_off & att_array) && array_p (var))
388             {
389               builtin_error (_("%s: cannot destroy array variables in this way"), name);
390               any_failed++;
391               NEXT_VARIABLE ();
392             }
393
394           /* declare -a name makes name an array variable. */
395           if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0)
396             var = convert_var_to_array (var);
397 #endif /* ARRAY_VARS */
398
399           VSETATTR (var, flags_on);
400           VUNSETATTR (var, flags_off);
401
402 #if defined (ARRAY_VARS)
403           if (offset && compound_array_assign)
404             assign_array_var_from_string (var, value);
405           else if (simple_array_assign && subscript_start)
406             {
407               /* declare [-a] name[N]=value */
408               *subscript_start = '[';   /* ] */
409               var = assign_array_element (name, value);
410               *subscript_start = '\0';
411             }
412           else if (simple_array_assign)
413             /* let bind_array_variable take care of this. */
414             bind_array_variable (name, 0, value);
415           else
416 #endif
417           /* bind_variable_value duplicates the essential internals of
418              bind_variable() */
419           if (offset)
420             bind_variable_value (var, value);
421
422           /* If we found this variable in the temporary environment, as with
423              `var=value declare -x var', make sure it is treated identically
424              to `var=value export var'.  Do the same for `declare -r' and
425              `readonly'.  Preserve the attributes, except for att_tempvar. */
426           /* XXX -- should this create a variable in the global scope, or
427              modify the local variable flags?  ksh93 has it modify the
428              global scope.
429              Need to handle case like in set_var_attribute where a temporary
430              variable is in the same table as the function local vars. */
431           if ((flags_on & (att_exported|att_readonly)) && tempvar_p (var))
432             {
433               SHELL_VAR *tv;
434               char *tvalue;
435
436               tv = find_tempenv_variable (var->name);
437               if (tv)
438                 {
439                   tvalue = var_isset (var) ? savestring (value_cell (var)) : savestring ("");
440                   tv = bind_variable (var->name, tvalue);
441                   tv->attributes |= var->attributes & ~att_tempvar;
442                   if (tv->context > 0)
443                     VSETATTR (tv, att_propagate);
444                   free (tvalue);
445                 }
446               VSETATTR (var, att_propagate);
447             }
448         }
449
450       stupidly_hack_special_variables (name);
451
452       NEXT_VARIABLE ();
453     }
454
455   return (assign_error ? EX_BADASSIGN
456                        : ((any_failed == 0) ? EXECUTION_SUCCESS
457                                             : EXECUTION_FAILURE));
458 }