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