10a314654bebe448faa9871a1af04401e160f8d4
[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, 1989, 1991 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 $PRODUCES declare.c
23
24 $BUILTIN declare
25 $FUNCTION declare_builtin
26 $SHORT_DOC declare [-afFrxi] [-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 without definitions
36   -r    to make NAMEs readonly
37   -x    to make NAMEs export
38   -i    to make NAMEs have the `integer' attribute set
39
40 Variables with the integer attribute have arithmetic evaluation (see
41 `let') done when the variable is assigned to.
42
43 When displaying values of variables, -f displays a function's name
44 and definition.  The -F option restricts the display to function
45 name only.
46
47 Using `+' instead of `-' turns off the given attribute instead.  When
48 used in a function, makes NAMEs local, as with the `local' command.
49 $END
50
51 $BUILTIN typeset
52 $FUNCTION declare_builtin
53 $SHORT_DOC typeset [-afFrxi] [-p] name[=value] ...
54 Obsolete.  See `declare'.
55 $END
56
57 #include <config.h>
58
59 #if defined (HAVE_UNISTD_H)
60 #  include <unistd.h>
61 #endif
62
63 #include <stdio.h>
64
65 #include "../bashansi.h"
66
67 #include "../shell.h"
68 #include "common.h"
69 #include "builtext.h"
70
71 extern int variable_context, array_needs_making;
72
73 static int declare_internal ();
74
75 /* Declare or change variable attributes. */
76 int
77 declare_builtin (list)
78      register WORD_LIST *list;
79 {
80   return (declare_internal (list, 0));
81 }
82
83 $BUILTIN local
84 $FUNCTION local_builtin
85 $SHORT_DOC local name[=value] ...
86 Create a local variable called NAME, and give it VALUE.  LOCAL
87 can only be used within a function; it makes the variable NAME
88 have a visible scope restricted to that function and its children.
89 $END
90 int
91 local_builtin (list)
92      register WORD_LIST *list;
93 {
94   if (variable_context)
95     return (declare_internal (list, 1));
96   else
97     {
98       builtin_error ("can only be used in a function");
99       return (EXECUTION_FAILURE);
100     }
101 }
102
103 /* The workhorse function. */
104 static int
105 declare_internal (list, local_var)
106      register WORD_LIST *list;
107      int local_var;
108 {
109   int flags_on, flags_off, *flags, any_failed, assign_error, pflag, nodefs;
110   char *t;
111   SHELL_VAR *var;
112
113   flags_on = flags_off = any_failed = assign_error = pflag = nodefs = 0;
114   while (list)
115     {
116       t = list->word->word;
117       if (t[0] == '-' && t[1] == '-' && t[2] == '\0')
118         {
119           list = list->next;
120           break;
121         }
122
123       if (*t != '+' && *t != '-')
124         break;
125
126       flags = (*t++ == '+') ? &flags_off : &flags_on;
127
128       while (*t)
129         {
130           if (*t == 'p' && local_var == 0)
131             pflag++, t++;
132           else if (*t == 'F')
133             {
134               nodefs++;
135               *flags |= att_function; t++;
136             }
137           else if (*t == 'f')
138             *flags |= att_function, t++;
139           else if (*t == 'x')
140             *flags |= att_exported, t++, array_needs_making = 1;
141           else if (*t == 'r')
142             *flags |= att_readonly, t++;
143           else if (*t == 'i')
144             *flags |= att_integer, t++;
145 #if defined (ARRAY_VARS)
146           else if (*t == 'a')
147             *flags |= att_array, t++;
148 #endif
149           else
150             {
151               builtin_error ("unknown option: `-%c'", *t);
152               builtin_usage ();
153               return (EX_USAGE);
154             }
155         }
156
157       list = list->next;
158     }
159
160   /* If there are no more arguments left, then we just want to show
161      some variables. */
162   if (list == 0)        /* declare -[afFirx] */
163     {
164       /* Show local variables defined at this context level if this is
165          the `local' builtin. */
166       if (local_var)
167         {
168           register SHELL_VAR **vlist;
169           register int i;
170
171           vlist = map_over (variable_in_context, shell_variables);
172
173           if (vlist)
174             {
175               for (i = 0; vlist[i]; i++)
176                 print_assignment (vlist[i]);
177
178               free (vlist);
179             }
180         }
181       else
182         {
183           if (flags_on == 0)
184             set_builtin ((WORD_LIST *)NULL);
185           else
186             set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs);
187         }
188
189       fflush (stdout);
190       return (EXECUTION_SUCCESS);
191     }
192
193   if (pflag)    /* declare -p [-afFirx] name [name...] */
194     {
195       for (any_failed = 0; list; list = list->next)
196         {
197           pflag = show_name_attributes (list->word->word, nodefs);
198           if (pflag)
199             {
200               builtin_error ("%s: not found", list->word->word);
201               any_failed++;
202             }
203         }
204       return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
205     }
206
207 #define NEXT_VARIABLE() free (name); list = list->next; continue
208
209   /* There are arguments left, so we are making variables. */
210   while (list)          /* declare [-afFirx] name [name ...] */
211     {
212       char *value, *name;
213       int offset;
214 #if defined (ARRAY_VARS)
215       int making_array_special, assigning_array_special;
216 #endif
217
218       name = savestring (list->word->word);
219       offset = assignment (name);
220
221       if (offset)       /* declare [-afFirx] name=value */
222         {
223           name[offset] = '\0';
224           value = name + offset + 1;
225         }
226       else
227         value = "";
228
229 #if defined (ARRAY_VARS)
230       assigning_array_special = 0;
231       if (t = strchr (name, '['))
232         {
233           *t = '\0';
234           making_array_special = 1;
235         }
236       else
237         making_array_special = 0;
238 #endif
239         
240       if (legal_identifier (name) == 0)
241         {
242           builtin_error ("`%s': not a valid identifier", name);
243           assign_error++;
244           NEXT_VARIABLE ();
245         }
246
247       /* If VARIABLE_CONTEXT has a non-zero value, then we are executing
248          inside of a function.  This means we should make local variables,
249          not global ones. */
250
251       if (variable_context)
252         {
253 #if defined (ARRAY_VARS)
254           if ((flags_on & att_array) || making_array_special)
255             make_local_array_variable (name);
256           else
257 #endif
258           make_local_variable (name);
259         }
260
261       /* If we are declaring a function, then complain about it in some way.
262          We don't let people make functions by saying `typeset -f foo=bar'. */
263
264       /* There should be a way, however, to let people look at a particular
265          function definition by saying `typeset -f foo'. */
266
267       if (flags_on & att_function)
268         {
269           if (offset)   /* declare -f [-rix] foo=bar */
270             {
271               builtin_error ("cannot use `-f' to make functions");
272               free (name);
273               return (EXECUTION_FAILURE);
274             }
275           else          /* declare -f [-rx] name [name...] */
276             {
277               var = find_function (name);
278
279               if (var)
280                 {
281                   if (readonly_p (var) && (flags_off & att_readonly))
282                     {
283                       builtin_error ("%s: readonly function", name);
284                       any_failed++;
285                       NEXT_VARIABLE ();
286                     }
287
288                   /* declare -[Ff] name [name...] */
289                   if (flags_on == att_function && flags_off == 0)
290                     {
291                       t = nodefs ? var->name
292                                  : named_function_string (name, function_cell (var), 1);
293                       printf ("%s\n", t);
294                     }
295                   else          /* declare -[fF] -[rx] name [name...] */
296                     {
297                       var->attributes |= flags_on;
298                       var->attributes &= ~flags_off;
299                     }
300                 }
301               else
302                 any_failed++;
303               NEXT_VARIABLE ();
304             }
305         }
306       else              /* declare -[airx] name [name...] */
307         {
308           var = find_variable (name);
309
310           if (var == 0)
311             {
312 #if defined (ARRAY_VARS)
313               if ((flags_on & att_array) || making_array_special)
314                 var = make_new_array_variable (name);
315               else
316 #endif
317               var = bind_variable (name, "");
318             }
319
320           /* Cannot use declare +r to turn off readonly attribute. */ 
321           if (readonly_p (var) && (flags_off & att_readonly))
322             {
323               builtin_error ("%s: readonly variable", name);
324               any_failed++;
325               NEXT_VARIABLE ();
326             }
327
328           /* Cannot use declare to assign value to readonly variable. */
329           if (readonly_p (var) && offset)
330             {
331               builtin_error ("%s: readonly variable", name);
332               assign_error++;
333               NEXT_VARIABLE ();
334             }
335
336 #if defined (ARRAY_VARS)
337           /* declare -a name=value does not work; declare name=value when
338              name is already an array does not work. */
339           if ((making_array_special || (flags_on & att_array) || array_p (var)) && offset)
340             {
341               if (value[0] == '(' && strchr (value, ')'))
342                 assigning_array_special = 1;
343               else
344                 {
345                   builtin_error ("%s: cannot assign to array variables in this way", name);
346                   assign_error++;
347                   NEXT_VARIABLE ();
348                 }
349             }
350
351           /* Cannot use declare +a name to remove an array variable. */
352           if ((flags_off & att_array) && array_p (var))
353             {
354               builtin_error ("%s: cannot destroy array variables in this way", name);
355               any_failed++;
356               NEXT_VARIABLE ();
357             }
358
359           /* declare -a name makes name an array variable. */
360           if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0)
361             var = convert_var_to_array (var);
362 #endif /* ARRAY_VARS */
363
364           var->attributes |= flags_on;
365           var->attributes &= ~flags_off;
366
367 #if defined (ARRAY_VARS)
368           if (offset && assigning_array_special)
369             assign_array_var_from_string (var, value);
370           else
371 #endif
372           if (offset)
373             {
374               t = make_variable_value (var, value);
375               FREE (var->value);
376               var->value = t;
377             }
378         }
379
380       stupidly_hack_special_variables (name);
381
382       NEXT_VARIABLE ();
383     }
384
385   return (assign_error ? EX_BADASSIGN
386                        : ((any_failed == 0) ? EXECUTION_SUCCESS
387                                             : EXECUTION_FAILURE));
388 }