Imported from ../bash-2.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, 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 ("Can't use `-f' to make functions");
272               return (EXECUTION_FAILURE);
273             }
274           else          /* declare -f [-rx] name [name...] */
275             {
276               var = find_function (name);
277
278               if (var)
279                 {
280                   if (readonly_p (var) && (flags_off & att_readonly))
281                     {
282                       builtin_error ("%s: readonly function", name);
283                       any_failed++;
284                       NEXT_VARIABLE ();
285                     }
286
287                   /* declare -[Ff] name [name...] */
288                   if (flags_on == att_function && flags_off == 0)
289                     {
290                       t = nodefs ? var->name
291                                  : named_function_string (name, function_cell (var), 1);
292                       printf ("%s\n", t);
293                     }
294                   else          /* declare -[fF] -[rx] name [name...] */
295                     {
296                       var->attributes |= flags_on;
297                       var->attributes &= ~flags_off;
298                     }
299                 }
300               else
301                 any_failed++;
302               NEXT_VARIABLE ();
303             }
304         }
305       else              /* declare -[airx] name [name...] */
306         {
307           var = find_variable (name);
308
309           if (var == 0)
310             {
311 #if defined (ARRAY_VARS)
312               if ((flags_on & att_array) || making_array_special)
313                 var = make_new_array_variable (name);
314               else
315 #endif
316               var = bind_variable (name, "");
317             }
318
319           /* Cannot use declare +r to turn off readonly attribute. */ 
320           if (readonly_p (var) && (flags_off & att_readonly))
321             {
322               builtin_error ("%s: readonly variable", name);
323               any_failed++;
324               NEXT_VARIABLE ();
325             }
326
327           /* Cannot use declare to assign value to readonly variable. */
328           if (readonly_p (var) && offset)
329             {
330               builtin_error ("%s: readonly variable", name);
331               assign_error++;
332               NEXT_VARIABLE ();
333             }
334
335 #if defined (ARRAY_VARS)
336           /* declare -a name=value does not work; declare name=value when
337              name is already an array does not work. */
338           if ((making_array_special || (flags_on & att_array) || array_p (var)) && offset)
339             {
340               if (value[0] == '(' && strchr (value, ')'))
341                 assigning_array_special = 1;
342               else
343                 {
344                   builtin_error ("%s: cannot assign to array variables in this way", name);
345                   assign_error++;
346                   NEXT_VARIABLE ();
347                 }
348             }
349
350           /* Cannot use declare +a name to remove an array variable. */
351           if ((flags_off & att_array) && array_p (var))
352             {
353               builtin_error ("%s: cannot destroy array variables in this way", name);
354               any_failed++;
355               NEXT_VARIABLE ();
356             }
357
358           /* declare -a name makes name an array variable. */
359           if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0)
360             var = convert_var_to_array (var);
361 #endif /* ARRAY_VARS */
362
363           var->attributes |= flags_on;
364           var->attributes &= ~flags_off;
365
366 #if defined (ARRAY_VARS)
367           if (offset && assigning_array_special)
368             assign_array_var_from_string (var, value);
369           else
370 #endif
371           if (offset)
372             {
373               t = make_variable_value (var, value);
374               FREE (var->value);
375               var->value = t;
376             }
377         }
378
379       stupidly_hack_special_variables (name);
380
381       NEXT_VARIABLE ();
382     }
383
384   return (assign_error ? EX_BADASSIGN
385                        : ((any_failed == 0) ? EXECUTION_SUCCESS
386                                             : EXECUTION_FAILURE));
387 }