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