Imported from ../bash-4.0-rc1.tar.gz.
[platform/upstream/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-2009 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))
437     printf ("%s\n", var->name);
438   else
439     {
440       x = sh_double_quote (var_isset (var) ? 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 }