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