Bash-4.3 distribution sources and documentation
[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-2012 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 [-aAf] [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 or functions, depending on
97         whether or not the -f option is given
98
99 An argument of `--' disables further option processing.
100
101 Exit Status:
102 Returns success unless an invalid option is given or NAME is invalid.
103 $END
104
105 /* For each variable name in LIST, make that variable readonly.  Given an
106    empty LIST, print out all existing readonly variables. */
107 int
108 readonly_builtin (list)
109      register WORD_LIST *list;
110 {
111   return (set_or_show_attributes (list, att_readonly, 0));
112 }
113
114 #if defined (ARRAY_VARS)
115 #  define ATTROPTS      "aAfnp"
116 #else
117 #  define ATTROPTS      "fnp"
118 #endif
119
120 /* For each variable name in LIST, make that variable have the specified
121    ATTRIBUTE.  An arg of `-n' says to remove the attribute from the the
122    remaining names in LIST (doesn't work for readonly). */
123 int
124 set_or_show_attributes (list, attribute, nodefs)
125      register WORD_LIST *list;
126      int attribute, nodefs;
127 {
128   register SHELL_VAR *var;
129   int assign, undo, any_failed, assign_error, opt;
130   int functions_only, arrays_only, assoc_only;
131   int aflags;
132   char *name;
133 #if defined (ARRAY_VARS)
134   WORD_LIST *nlist, *tlist;
135   WORD_DESC *w;
136 #endif
137
138   functions_only = arrays_only = assoc_only = 0;
139   undo = any_failed = assign_error = 0;
140   /* Read arguments from the front of the list. */
141   reset_internal_getopt ();
142   while ((opt = internal_getopt (list, ATTROPTS)) != -1)
143     {
144       switch (opt)
145         {
146           case 'n':
147             undo = 1;
148             break;
149           case 'f':
150             functions_only = 1;
151             break;
152 #if defined (ARRAY_VARS)
153           case 'a':
154             arrays_only = 1;
155             break;
156           case 'A':
157             assoc_only = 1;
158             break;
159 #endif
160           case 'p':
161             break;
162           default:
163             builtin_usage ();
164             return (EX_USAGE);
165         }
166     }
167   list = loptend;
168
169   if (list)
170     {
171       if (attribute & att_exported)
172         array_needs_making = 1;
173
174       /* Cannot undo readonly status, silently disallowed. */
175       if (undo && (attribute & att_readonly))
176         attribute &= ~att_readonly;
177
178       while (list)
179         {
180           name = list->word->word;
181
182           if (functions_only)           /* xxx -f name */
183             {
184               var = find_function (name);
185               if (var == 0)
186                 {
187                   builtin_error (_("%s: not a function"), name);
188                   any_failed++;
189                 }
190               else
191                 SETVARATTR (var, attribute, undo);
192
193               list = list->next;
194               continue;
195             }
196
197           /* xxx [-np] name[=value] */
198           assign = assignment (name, 0);
199
200           aflags = 0;
201           if (assign)
202             {
203               name[assign] = '\0';
204               if (name[assign - 1] == '+')
205                 {
206                   aflags |= ASS_APPEND;
207                   name[assign - 1] = '\0';
208                 }
209             }
210
211           if (legal_identifier (name) == 0)
212             {
213               sh_invalidid (name);
214               if (assign)
215                 assign_error++;
216               else
217                 any_failed++;
218               list = list->next;
219               continue;
220             }
221
222           if (assign)   /* xxx [-np] name=value */
223             {
224               name[assign] = '=';
225               if (aflags & ASS_APPEND)
226                 name[assign - 1] = '+';
227 #if defined (ARRAY_VARS)
228               /* Let's try something here.  Turn readonly -a xxx=yyy into
229                  declare -ra xxx=yyy and see what that gets us. */
230               if (arrays_only || assoc_only)
231                 {
232                   tlist = list->next;
233                   list->next = (WORD_LIST *)NULL;
234                   w = arrays_only ? make_word ("-ra") : make_word ("-rA");
235                   nlist = make_word_list (w, list);
236                   opt = declare_builtin (nlist);
237                   if (opt != EXECUTION_SUCCESS)
238                     assign_error++;
239                   list->next = tlist;
240                   dispose_word (w);
241                   free (nlist);
242                 }
243               else
244 #endif
245               /* This word has already been expanded once with command
246                  and parameter expansion.  Call do_assignment_no_expand (),
247                  which does not do command or parameter substitution.  If
248                  the assignment is not performed correctly, flag an error. */
249               if (do_assignment_no_expand (name) == 0)
250                 assign_error++;
251               name[assign] = '\0';
252               if (aflags & ASS_APPEND)
253                 name[assign - 1] = '\0';
254             }
255
256           set_var_attribute (name, attribute, undo);
257           list = list->next;
258         }
259     }
260   else
261     {
262       SHELL_VAR **variable_list;
263       register int i;
264
265       if ((attribute & att_function) || functions_only)
266         {
267           variable_list = all_shell_functions ();
268           if (attribute != att_function)
269             attribute &= ~att_function; /* so declare -xf works, for example */
270         }
271       else
272         variable_list = all_shell_variables ();
273
274 #if defined (ARRAY_VARS)
275       if (attribute & att_array)
276         {
277           arrays_only++;
278           if (attribute != att_array)
279             attribute &= ~att_array;
280         }
281       else if (attribute & att_assoc)
282         {
283           assoc_only++;
284           if (attribute != att_assoc)
285             attribute &= ~att_assoc;
286         }
287 #endif
288
289       if (variable_list)
290         {
291           for (i = 0; var = variable_list[i]; i++)
292             {
293 #if defined (ARRAY_VARS)
294               if (arrays_only && array_p (var) == 0)
295                 continue;
296               else if (assoc_only && assoc_p (var) == 0)
297                 continue;
298 #endif
299               if ((var->attributes & attribute))
300                 {
301                   show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
302                   if (any_failed = sh_chkwrite (any_failed))
303                     break;
304                 }
305             }
306           free (variable_list);
307         }
308     }
309
310   return (assign_error ? EX_BADASSIGN
311                        : ((any_failed == 0) ? EXECUTION_SUCCESS
312                                             : EXECUTION_FAILURE));
313 }
314
315 /* Show all variable variables (v == 1) or functions (v == 0) with
316    attributes. */
317 int
318 show_all_var_attributes (v, nodefs)
319      int v, nodefs;
320 {
321   SHELL_VAR **variable_list, *var;
322   int any_failed;
323   register int i;
324
325   variable_list = v ? all_shell_variables () : all_shell_functions ();
326   if (variable_list == 0)  
327     return (EXECUTION_SUCCESS);
328
329   for (i = any_failed = 0; var = variable_list[i]; i++)
330     {
331       show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
332       if (any_failed = sh_chkwrite (any_failed))
333         break;
334     }
335   free (variable_list);
336   return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
337 }
338
339 /* Show the attributes for shell variable VAR.  If NODEFS is non-zero,
340    don't show function definitions along with the name.  If PATTR is
341    non-zero, it indicates we're being called from `export' or `readonly'.
342    In POSIX mode, this prints the name of the calling builtin (`export'
343    or `readonly') instead of `declare', and doesn't print function defs
344    when called by `export' or `readonly'. */
345 int
346 show_var_attributes (var, pattr, nodefs)
347      SHELL_VAR *var;
348      int pattr, nodefs;
349 {
350   char flags[16], *x;
351   int i;
352
353   i = 0;
354
355   /* pattr == 0 means we are called from `declare'. */
356   if (pattr == 0 || posixly_correct == 0)
357     {
358 #if defined (ARRAY_VARS)
359       if (array_p (var))
360         flags[i++] = 'a';
361
362       if (assoc_p (var))
363         flags[i++] = 'A';
364 #endif
365
366       if (function_p (var))
367         flags[i++] = 'f';
368
369       if (integer_p (var))
370         flags[i++] = 'i';
371
372       if (nameref_p (var))
373         flags[i++] = 'n';
374
375       if (readonly_p (var))
376         flags[i++] = 'r';
377
378       if (trace_p (var))
379         flags[i++] = 't';
380
381       if (exported_p (var))
382         flags[i++] = 'x';
383
384       if (capcase_p (var))
385         flags[i++] = 'c';
386
387       if (lowercase_p (var))
388         flags[i++] = 'l';
389
390       if (uppercase_p (var))
391         flags[i++] = 'u';
392     }
393   else
394     {
395 #if defined (ARRAY_VARS)
396       if (array_p (var))
397         flags[i++] = 'a';
398
399       if (assoc_p (var))
400         flags[i++] = 'A';
401 #endif
402
403       if (function_p (var))
404         flags[i++] = 'f';
405     }
406
407   flags[i] = '\0';
408
409   /* If we're printing functions with definitions, print the function def
410      first, then the attributes, instead of printing output that can't be
411      reused as input to recreate the current state. */
412   if (function_p (var) && nodefs == 0 && (pattr == 0 || posixly_correct == 0))
413     {
414       printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL));
415       nodefs++;
416       if (pattr == 0 && i == 1 && flags[0] == 'f')
417         return 0;               /* don't print `declare -f name' */
418     }
419
420   if (pattr == 0 || posixly_correct == 0)
421     printf ("declare -%s ", i ? flags : "-");
422   else if (i)
423     printf ("%s -%s ", this_command_name, flags);
424   else
425     printf ("%s ", this_command_name);
426
427 #if defined (ARRAY_VARS)
428   if (array_p (var))
429     print_array_assignment (var, 1);
430   else if (assoc_p (var))
431     print_assoc_assignment (var, 1);
432   else
433 #endif
434   /* force `readonly' and `export' to not print out function definitions
435      when in POSIX mode. */
436   if (nodefs || (function_p (var) && pattr != 0 && posixly_correct))
437     printf ("%s\n", var->name);
438   else if (function_p (var))
439     printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL));
440   else if (invisible_p (var) || var_isset (var) == 0)
441     printf ("%s\n", var->name);
442   else
443     {
444       x = sh_double_quote (value_cell (var));
445       printf ("%s=%s\n", var->name, x);
446       free (x);
447     }
448   return (0);
449 }
450
451 int
452 show_name_attributes (name, nodefs)
453      char *name;
454      int nodefs;
455 {
456   SHELL_VAR *var;
457
458 #if 0
459   var = find_variable_tempenv (name);
460 #else
461   var = find_variable_noref (name);
462 #endif
463
464   if (var && invisible_p (var) == 0)
465     {
466       show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
467       return (0);
468     }
469   else
470     return (1);
471 }
472
473 int
474 show_func_attributes (name, nodefs)
475      char *name;
476      int nodefs;
477 {
478   SHELL_VAR *var;
479
480   var = find_function (name);
481
482   if (var)
483     {
484       show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
485       return (0);
486     }
487   else
488     return (1);
489 }
490
491 void
492 set_var_attribute (name, attribute, undo)
493      char *name;
494      int attribute, undo;
495 {
496   SHELL_VAR *var, *tv, *v;
497   char *tvalue;
498
499   if (undo)
500     var = find_variable (name);
501   else
502     {
503       tv = find_tempenv_variable (name);
504       /* XXX -- need to handle case where tv is a temp variable in a
505          function-scope context, since function_env has been merged into
506          the local variables table. */
507       if (tv && tempvar_p (tv))
508         {
509           tvalue = var_isset (tv) ? savestring (value_cell (tv)) : savestring ("");
510
511           var = bind_variable (tv->name, tvalue, 0);
512           var->attributes |= tv->attributes & ~att_tempvar;
513           /* This avoids an error message when propagating a read-only var
514              later on. */
515           if (var->context == 0 && (attribute & att_readonly))
516             {
517               /* Don't bother to set the `propagate to the global variables
518                  table' flag if we've just bound the variable in that table */
519               v = find_global_variable (tv->name);
520               if (v != var)
521                 VSETATTR (tv, att_propagate);
522             }
523           else
524             VSETATTR (tv, att_propagate);
525           if (var->context != 0)
526             VSETATTR (var, att_propagate);
527           SETVARATTR (tv, attribute, undo);     /* XXX */
528
529           stupidly_hack_special_variables (tv->name);
530
531           free (tvalue);
532         }
533       else
534         {
535           var = find_variable_notempenv (name);
536           if (var == 0)
537             {
538               var = bind_variable (name, (char *)NULL, 0);
539               VSETATTR (var, att_invisible);
540             }
541           else if (var->context != 0)
542             VSETATTR (var, att_propagate);
543         }
544     }
545
546   if (var)
547     SETVARATTR (var, attribute, undo);
548
549   if (var && (exported_p (var) || (attribute & att_exported)))
550     array_needs_making++;       /* XXX */
551 }