]> git.ipfire.org Git - thirdparty/bash.git/blob - builtins/setattr.def
commit bash-20100525 snapshot
[thirdparty/bash.git] / builtins / setattr.def
1 This file is setattr.def, from which is created setattr.c.
2 It implements the builtins "export" and "readonly", 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 setattr.c
22
23 #include <config.h>
24
25 #if defined (HAVE_UNISTD_H)
26 # ifdef _MINIX
27 # include <sys/types.h>
28 # endif
29 # include <unistd.h>
30 #endif
31
32 #include <stdio.h>
33 #include "../bashansi.h"
34 #include "../bashintl.h"
35
36 #include "../shell.h"
37 #include "common.h"
38 #include "bashgetopt.h"
39
40 extern int posixly_correct;
41 extern int array_needs_making;
42 extern char *this_command_name;
43 extern sh_builtin_func_t *this_shell_builtin;
44
45 #ifdef ARRAY_VARS
46 extern int declare_builtin __P((WORD_LIST *));
47 #endif
48
49 #define READONLY_OR_EXPORT \
50 (this_shell_builtin == readonly_builtin || this_shell_builtin == export_builtin)
51
52 $BUILTIN export
53 $FUNCTION export_builtin
54 $SHORT_DOC export [-fn] [name[=value] ...] or export -p
55 Set export attribute for shell variables.
56
57 Marks each NAME for automatic export to the environment of subsequently
58 executed commands. If VALUE is supplied, assign VALUE before exporting.
59
60 Options:
61 -f refer to shell functions
62 -n remove the export property from each NAME
63 -p display a list of all exported variables and functions
64
65 An argument of `--' disables further option processing.
66
67 Exit Status:
68 Returns success unless an invalid option is given or NAME is invalid.
69 $END
70
71 /* For each variable name in LIST, make that variable appear in the
72 environment passed to simple commands. If there is no LIST, then
73 print all such variables. An argument of `-n' says to remove the
74 exported attribute from variables named in LIST. An argument of
75 -f indicates that the names present in LIST refer to functions. */
76 int
77 export_builtin (list)
78 register WORD_LIST *list;
79 {
80 return (set_or_show_attributes (list, att_exported, 0));
81 }
82
83 $BUILTIN readonly
84 $FUNCTION readonly_builtin
85 $SHORT_DOC readonly [-af] [name[=value] ...] or readonly -p
86 Mark shell variables as unchangeable.
87
88 Mark each NAME as read-only; the values of these NAMEs may not be
89 changed by subsequent assignment. If VALUE is supplied, assign VALUE
90 before marking as read-only.
91
92 Options:
93 -a refer to indexed array variables
94 -A refer to associative array variables
95 -f refer to shell functions
96 -p display a list of all readonly variables and functions
97
98 An argument of `--' disables further option processing.
99
100 Exit Status:
101 Returns success unless an invalid option is given or NAME is invalid.
102 $END
103
104 /* For each variable name in LIST, make that variable readonly. Given an
105 empty LIST, print out all existing readonly variables. */
106 int
107 readonly_builtin (list)
108 register WORD_LIST *list;
109 {
110 return (set_or_show_attributes (list, att_readonly, 0));
111 }
112
113 #if defined (ARRAY_VARS)
114 # define ATTROPTS "aAfnp"
115 #else
116 # define ATTROPTS "fnp"
117 #endif
118
119 /* For each variable name in LIST, make that variable have the specified
120 ATTRIBUTE. An arg of `-n' says to remove the attribute from the the
121 remaining names in LIST (doesn't work for readonly). */
122 int
123 set_or_show_attributes (list, attribute, nodefs)
124 register WORD_LIST *list;
125 int attribute, nodefs;
126 {
127 register SHELL_VAR *var;
128 int assign, undo, any_failed, assign_error, opt;
129 int functions_only, arrays_only, assoc_only;
130 int aflags;
131 char *name;
132 #if defined (ARRAY_VARS)
133 WORD_LIST *nlist, *tlist;
134 WORD_DESC *w;
135 #endif
136
137 functions_only = arrays_only = assoc_only = 0;
138 undo = any_failed = assign_error = 0;
139 /* Read arguments from the front of the list. */
140 reset_internal_getopt ();
141 while ((opt = internal_getopt (list, ATTROPTS)) != -1)
142 {
143 switch (opt)
144 {
145 case 'n':
146 undo = 1;
147 break;
148 case 'f':
149 functions_only = 1;
150 break;
151 #if defined (ARRAY_VARS)
152 case 'a':
153 arrays_only = 1;
154 break;
155 case 'A':
156 assoc_only = 1;
157 break;
158 #endif
159 case 'p':
160 break;
161 default:
162 builtin_usage ();
163 return (EX_USAGE);
164 }
165 }
166 list = loptend;
167
168 if (list)
169 {
170 if (attribute & att_exported)
171 array_needs_making = 1;
172
173 /* Cannot undo readonly status, silently disallowed. */
174 if (undo && (attribute & att_readonly))
175 attribute &= ~att_readonly;
176
177 while (list)
178 {
179 name = list->word->word;
180
181 if (functions_only) /* xxx -f name */
182 {
183 var = find_function (name);
184 if (var == 0)
185 {
186 builtin_error (_("%s: not a function"), name);
187 any_failed++;
188 }
189 else
190 SETVARATTR (var, attribute, undo);
191
192 list = list->next;
193 continue;
194 }
195
196 /* xxx [-np] name[=value] */
197 assign = assignment (name, 0);
198
199 aflags = 0;
200 if (assign)
201 {
202 name[assign] = '\0';
203 if (name[assign - 1] == '+')
204 {
205 aflags |= ASS_APPEND;
206 name[assign - 1] = '\0';
207 }
208 }
209
210 if (legal_identifier (name) == 0)
211 {
212 sh_invalidid (name);
213 if (assign)
214 assign_error++;
215 else
216 any_failed++;
217 list = list->next;
218 continue;
219 }
220
221 if (assign) /* xxx [-np] name=value */
222 {
223 name[assign] = '=';
224 if (aflags & ASS_APPEND)
225 name[assign - 1] = '+';
226 #if defined (ARRAY_VARS)
227 /* Let's try something here. Turn readonly -a xxx=yyy into
228 declare -ra xxx=yyy and see what that gets us. */
229 if (arrays_only || assoc_only)
230 {
231 tlist = list->next;
232 list->next = (WORD_LIST *)NULL;
233 w = arrays_only ? make_word ("-ra") : make_word ("-rA");
234 nlist = make_word_list (w, list);
235 opt = declare_builtin (nlist);
236 if (opt != EXECUTION_SUCCESS)
237 assign_error++;
238 list->next = tlist;
239 dispose_word (w);
240 free (nlist);
241 }
242 else
243 #endif
244 /* This word has already been expanded once with command
245 and parameter expansion. Call do_assignment_no_expand (),
246 which does not do command or parameter substitution. If
247 the assignment is not performed correctly, flag an error. */
248 if (do_assignment_no_expand (name) == 0)
249 assign_error++;
250 name[assign] = '\0';
251 if (aflags & ASS_APPEND)
252 name[assign - 1] = '\0';
253 }
254
255 set_var_attribute (name, attribute, undo);
256 list = list->next;
257 }
258 }
259 else
260 {
261 SHELL_VAR **variable_list;
262 register int i;
263
264 if ((attribute & att_function) || functions_only)
265 {
266 variable_list = all_shell_functions ();
267 if (attribute != att_function)
268 attribute &= ~att_function; /* so declare -xf works, for example */
269 }
270 else
271 variable_list = all_shell_variables ();
272
273 #if defined (ARRAY_VARS)
274 if (attribute & att_array)
275 {
276 arrays_only++;
277 if (attribute != att_array)
278 attribute &= ~att_array;
279 }
280 else if (attribute & att_assoc)
281 {
282 assoc_only++;
283 if (attribute != att_assoc)
284 attribute &= ~att_assoc;
285 }
286 #endif
287
288 if (variable_list)
289 {
290 for (i = 0; var = variable_list[i]; i++)
291 {
292 #if defined (ARRAY_VARS)
293 if (arrays_only && array_p (var) == 0)
294 continue;
295 else if (assoc_only && assoc_p (var) == 0)
296 continue;
297 #endif
298 if ((var->attributes & attribute))
299 {
300 show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
301 if (any_failed = sh_chkwrite (any_failed))
302 break;
303 }
304 }
305 free (variable_list);
306 }
307 }
308
309 return (assign_error ? EX_BADASSIGN
310 : ((any_failed == 0) ? EXECUTION_SUCCESS
311 : EXECUTION_FAILURE));
312 }
313
314 /* Show all variable variables (v == 1) or functions (v == 0) with
315 attributes. */
316 int
317 show_all_var_attributes (v, nodefs)
318 int v, nodefs;
319 {
320 SHELL_VAR **variable_list, *var;
321 int any_failed;
322 register int i;
323
324 variable_list = v ? all_shell_variables () : all_shell_functions ();
325 if (variable_list == 0)
326 return (EXECUTION_SUCCESS);
327
328 for (i = any_failed = 0; var = variable_list[i]; i++)
329 {
330 show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
331 if (any_failed = sh_chkwrite (any_failed))
332 break;
333 }
334 free (variable_list);
335 return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
336 }
337
338 /* Show the attributes for shell variable VAR. If NODEFS is non-zero,
339 don't show function definitions along with the name. If PATTR is
340 non-zero, it indicates we're being called from `export' or `readonly'.
341 In POSIX mode, this prints the name of the calling builtin (`export'
342 or `readonly') instead of `declare', and doesn't print function defs
343 when called by `export' or `readonly'. */
344 int
345 show_var_attributes (var, pattr, nodefs)
346 SHELL_VAR *var;
347 int pattr, nodefs;
348 {
349 char flags[16], *x;
350 int i;
351
352 i = 0;
353
354 /* pattr == 0 means we are called from `declare'. */
355 if (pattr == 0 || posixly_correct == 0)
356 {
357 #if defined (ARRAY_VARS)
358 if (array_p (var))
359 flags[i++] = 'a';
360
361 if (assoc_p (var))
362 flags[i++] = 'A';
363 #endif
364
365 if (function_p (var))
366 flags[i++] = 'f';
367
368 if (integer_p (var))
369 flags[i++] = 'i';
370
371 if (readonly_p (var))
372 flags[i++] = 'r';
373
374 if (trace_p (var))
375 flags[i++] = 't';
376
377 if (exported_p (var))
378 flags[i++] = 'x';
379
380 if (capcase_p (var))
381 flags[i++] = 'c';
382
383 if (lowercase_p (var))
384 flags[i++] = 'l';
385
386 if (uppercase_p (var))
387 flags[i++] = 'u';
388 }
389 else
390 {
391 #if defined (ARRAY_VARS)
392 if (array_p (var))
393 flags[i++] = 'a';
394
395 if (assoc_p (var))
396 flags[i++] = 'A';
397 #endif
398
399 if (function_p (var))
400 flags[i++] = 'f';
401 }
402
403 flags[i] = '\0';
404
405 /* If we're printing functions with definitions, print the function def
406 first, then the attributes, instead of printing output that can't be
407 reused as input to recreate the current state. */
408 if (function_p (var) && nodefs == 0 && (pattr == 0 || posixly_correct == 0))
409 {
410 printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL));
411 nodefs++;
412 if (pattr == 0 && i == 1 && flags[0] == 'f')
413 return 0; /* don't print `declare -f name' */
414 }
415
416 if (pattr == 0 || posixly_correct == 0)
417 printf ("declare -%s ", i ? flags : "-");
418 else if (i)
419 printf ("%s -%s ", this_command_name, flags);
420 else
421 printf ("%s ", this_command_name);
422
423 #if defined (ARRAY_VARS)
424 if (array_p (var))
425 print_array_assignment (var, 1);
426 else if (assoc_p (var))
427 print_assoc_assignment (var, 1);
428 else
429 #endif
430 /* force `readonly' and `export' to not print out function definitions
431 when in POSIX mode. */
432 if (nodefs || (function_p (var) && pattr != 0 && posixly_correct))
433 printf ("%s\n", var->name);
434 else if (function_p (var))
435 printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL));
436 else if (invisible_p (var) || var_isset (var) == 0)
437 printf ("%s\n", var->name);
438 else
439 {
440 x = sh_double_quote (value_cell (var));
441 printf ("%s=%s\n", var->name, x);
442 free (x);
443 }
444 return (0);
445 }
446
447 int
448 show_name_attributes (name, nodefs)
449 char *name;
450 int nodefs;
451 {
452 SHELL_VAR *var;
453
454 var = find_variable_internal (name, 1);
455
456 if (var && invisible_p (var) == 0)
457 {
458 show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
459 return (0);
460 }
461 else
462 return (1);
463 }
464
465 void
466 set_var_attribute (name, attribute, undo)
467 char *name;
468 int attribute, undo;
469 {
470 SHELL_VAR *var, *tv;
471 char *tvalue;
472
473 if (undo)
474 var = find_variable (name);
475 else
476 {
477 tv = find_tempenv_variable (name);
478 /* XXX -- need to handle case where tv is a temp variable in a
479 function-scope context, since function_env has been merged into
480 the local variables table. */
481 if (tv && tempvar_p (tv))
482 {
483 tvalue = var_isset (tv) ? savestring (value_cell (tv)) : savestring ("");
484
485 var = bind_variable (tv->name, tvalue, 0);
486 var->attributes |= tv->attributes & ~att_tempvar;
487 VSETATTR (tv, att_propagate);
488 if (var->context != 0)
489 VSETATTR (var, att_propagate);
490 SETVARATTR (tv, attribute, undo); /* XXX */
491
492 stupidly_hack_special_variables (tv->name);
493
494 free (tvalue);
495 }
496 else
497 {
498 var = find_variable_internal (name, 0);
499 if (var == 0)
500 {
501 var = bind_variable (name, (char *)NULL, 0);
502 VSETATTR (var, att_invisible);
503 }
504 else if (var->context != 0)
505 VSETATTR (var, att_propagate);
506 }
507 }
508
509 if (var)
510 SETVARATTR (var, attribute, undo);
511
512 if (var && (exported_p (var) || (attribute & att_exported)))
513 array_needs_making++; /* XXX */
514 }