]> git.ipfire.org Git - thirdparty/bash.git/blob - builtins/setattr.def
Bash-5.2 patch 26: fix typo when specifying readline's custom color prefix
[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-2015 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 "../execute_cmd.h"
38 #include "../flags.h"
39 #include "common.h"
40 #include "bashgetopt.h"
41
42 extern sh_builtin_func_t *this_shell_builtin;
43
44 #ifdef ARRAY_VARS
45 extern int declare_builtin __P((WORD_LIST *));
46 #endif
47
48 #define READONLY_OR_EXPORT \
49 (this_shell_builtin == readonly_builtin || this_shell_builtin == export_builtin)
50
51 $BUILTIN export
52 $FUNCTION export_builtin
53 $SHORT_DOC export [-fn] [name[=value] ...] or export -p
54 Set export attribute for shell variables.
55
56 Marks each NAME for automatic export to the environment of subsequently
57 executed commands. If VALUE is supplied, assign VALUE before exporting.
58
59 Options:
60 -f refer to shell functions
61 -n remove the export property from each NAME
62 -p display a list of all exported variables and functions
63
64 An argument of `--' disables further option processing.
65
66 Exit Status:
67 Returns success unless an invalid option is given or NAME is invalid.
68 $END
69
70 /* For each variable name in LIST, make that variable appear in the
71 environment passed to simple commands. If there is no LIST, then
72 print all such variables. An argument of `-n' says to remove the
73 exported attribute from variables named in LIST. An argument of
74 -f indicates that the names present in LIST refer to functions. */
75 int
76 export_builtin (list)
77 register WORD_LIST *list;
78 {
79 return (set_or_show_attributes (list, att_exported, 0));
80 }
81
82 $BUILTIN readonly
83 $FUNCTION readonly_builtin
84 $SHORT_DOC readonly [-aAf] [name[=value] ...] or readonly -p
85 Mark shell variables as unchangeable.
86
87 Mark each NAME as read-only; the values of these NAMEs may not be
88 changed by subsequent assignment. If VALUE is supplied, assign VALUE
89 before marking as read-only.
90
91 Options:
92 -a refer to indexed array variables
93 -A refer to associative array variables
94 -f refer to shell functions
95 -p display a list of all readonly variables or functions,
96 depending on whether or not the -f option is given
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 char optw[8];
136 int opti;
137 #endif
138
139 functions_only = arrays_only = assoc_only = 0;
140 undo = any_failed = assign_error = 0;
141 /* Read arguments from the front of the list. */
142 reset_internal_getopt ();
143 while ((opt = internal_getopt (list, ATTROPTS)) != -1)
144 {
145 switch (opt)
146 {
147 case 'n':
148 undo = 1;
149 break;
150 case 'f':
151 functions_only = 1;
152 break;
153 #if defined (ARRAY_VARS)
154 case 'a':
155 arrays_only = 1;
156 break;
157 case 'A':
158 assoc_only = 1;
159 break;
160 #endif
161 case 'p':
162 break;
163 CASE_HELPOPT;
164 default:
165 builtin_usage ();
166 return (EX_USAGE);
167 }
168 }
169 list = loptend;
170
171 if (list)
172 {
173 if (attribute & att_exported)
174 array_needs_making = 1;
175
176 /* Cannot undo readonly status, silently disallowed. */
177 if (undo && (attribute & att_readonly))
178 attribute &= ~att_readonly;
179
180 while (list)
181 {
182 name = list->word->word;
183
184 if (functions_only) /* xxx -f name */
185 {
186 var = find_function (name);
187 if (var == 0)
188 {
189 builtin_error (_("%s: not a function"), name);
190 any_failed++;
191 }
192 else if ((attribute & att_exported) && undo == 0 && exportable_function_name (name) == 0)
193 {
194 builtin_error (_("%s: cannot export"), name);
195 any_failed++;
196 }
197 else
198 SETVARATTR (var, attribute, undo);
199
200 list = list->next;
201 continue;
202 }
203
204 /* xxx [-np] name[=value] */
205 assign = assignment (name, 0);
206
207 aflags = 0;
208 if (assign)
209 {
210 name[assign] = '\0';
211 if (name[assign - 1] == '+')
212 {
213 aflags |= ASS_APPEND;
214 name[assign - 1] = '\0';
215 }
216 }
217
218 if (legal_identifier (name) == 0)
219 {
220 sh_invalidid (name);
221 if (assign)
222 assign_error++;
223 else
224 any_failed++;
225 list = list->next;
226 continue;
227 }
228
229 if (assign) /* xxx [-np] name=value */
230 {
231 name[assign] = '=';
232 if (aflags & ASS_APPEND)
233 name[assign - 1] = '+';
234 #if defined (ARRAY_VARS)
235 /* Let's try something here. Turn readonly -a xxx=yyy into
236 declare -ra xxx=yyy and see what that gets us. */
237 if (arrays_only || assoc_only)
238 {
239 tlist = list->next;
240 list->next = (WORD_LIST *)NULL;
241 /* Add -g to avoid readonly/export creating local variables:
242 only local/declare/typeset create local variables */
243 opti = 0;
244 optw[opti++] = '-';
245 optw[opti++] = 'g';
246 if (attribute & att_readonly)
247 optw[opti++] = 'r';
248 if (attribute & att_exported)
249 optw[opti++] = 'x';
250 if (arrays_only)
251 optw[opti++] = 'a';
252 else
253 optw[opti++] = 'A';
254 optw[opti] = '\0';
255
256 w = make_word (optw);
257 nlist = make_word_list (w, list);
258
259 opt = declare_builtin (nlist);
260 if (opt != EXECUTION_SUCCESS)
261 assign_error++;
262 list->next = tlist;
263 dispose_word (w);
264 free (nlist);
265 }
266 else
267 #endif
268 /* This word has already been expanded once with command
269 and parameter expansion. Call do_assignment_no_expand (),
270 which does not do command or parameter substitution. If
271 the assignment is not performed correctly, flag an error. */
272 if (do_assignment_no_expand (name) == 0)
273 assign_error++;
274 name[assign] = '\0';
275 if (aflags & ASS_APPEND)
276 name[assign - 1] = '\0';
277 }
278
279 set_var_attribute (name, attribute, undo);
280 if (assign) /* restore word */
281 {
282 name[assign] = '=';
283 if (aflags & ASS_APPEND)
284 name[assign-1] = '+';
285 }
286 list = list->next;
287 }
288 }
289 else
290 {
291 SHELL_VAR **variable_list;
292 register int i;
293
294 if ((attribute & att_function) || functions_only)
295 {
296 variable_list = all_shell_functions ();
297 if (attribute != att_function)
298 attribute &= ~att_function; /* so declare -xf works, for example */
299 }
300 else
301 variable_list = all_shell_variables ();
302
303 #if defined (ARRAY_VARS)
304 if (attribute & att_array)
305 {
306 arrays_only++;
307 if (attribute != att_array)
308 attribute &= ~att_array;
309 }
310 else if (attribute & att_assoc)
311 {
312 assoc_only++;
313 if (attribute != att_assoc)
314 attribute &= ~att_assoc;
315 }
316 #endif
317
318 if (variable_list)
319 {
320 for (i = 0; var = variable_list[i]; i++)
321 {
322 #if defined (ARRAY_VARS)
323 if (arrays_only && array_p (var) == 0)
324 continue;
325 else if (assoc_only && assoc_p (var) == 0)
326 continue;
327 #endif
328
329 /* If we imported a variable that's not a valid identifier, don't
330 show it in any lists. */
331 if ((var->attributes & (att_invisible|att_imported)) == (att_invisible|att_imported))
332 continue;
333
334 if ((var->attributes & attribute))
335 {
336 show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
337 if (any_failed = sh_chkwrite (any_failed))
338 break;
339 }
340 }
341 free (variable_list);
342 }
343 }
344
345 return (assign_error ? EX_BADASSIGN
346 : ((any_failed == 0) ? EXECUTION_SUCCESS
347 : EXECUTION_FAILURE));
348 }
349
350 /* Show all variable variables (v == 1) or functions (v == 0) with
351 attributes. */
352 int
353 show_all_var_attributes (v, nodefs)
354 int v, nodefs;
355 {
356 SHELL_VAR **variable_list, *var;
357 int any_failed;
358 register int i;
359
360 variable_list = v ? all_shell_variables () : all_shell_functions ();
361 if (variable_list == 0)
362 return (EXECUTION_SUCCESS);
363
364 for (i = any_failed = 0; var = variable_list[i]; i++)
365 {
366 show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
367 if (any_failed = sh_chkwrite (any_failed))
368 break;
369 }
370 free (variable_list);
371 return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
372 }
373
374 int
375 var_attribute_string (var, pattr, flags)
376 SHELL_VAR *var;
377 int pattr;
378 char *flags; /* filled in with attributes */
379 {
380 int i;
381
382 i = 0;
383
384 /* pattr == 0 means we are called from `declare'. */
385 if (pattr == 0 || posixly_correct == 0)
386 {
387 #if defined (ARRAY_VARS)
388 if (array_p (var))
389 flags[i++] = 'a';
390
391 if (assoc_p (var))
392 flags[i++] = 'A';
393 #endif
394
395 if (function_p (var))
396 flags[i++] = 'f';
397
398 if (integer_p (var))
399 flags[i++] = 'i';
400
401 if (nameref_p (var))
402 flags[i++] = 'n';
403
404 if (readonly_p (var))
405 flags[i++] = 'r';
406
407 if (trace_p (var))
408 flags[i++] = 't';
409
410 if (exported_p (var))
411 flags[i++] = 'x';
412
413 if (capcase_p (var))
414 flags[i++] = 'c';
415
416 if (lowercase_p (var))
417 flags[i++] = 'l';
418
419 if (uppercase_p (var))
420 flags[i++] = 'u';
421 }
422 else
423 {
424 #if defined (ARRAY_VARS)
425 if (array_p (var))
426 flags[i++] = 'a';
427
428 if (assoc_p (var))
429 flags[i++] = 'A';
430 #endif
431
432 if (function_p (var))
433 flags[i++] = 'f';
434 }
435
436 flags[i] = '\0';
437 return i;
438 }
439
440 /* Show the attributes for shell variable VAR. If NODEFS is non-zero,
441 don't show function definitions along with the name. If PATTR is
442 non-zero, it indicates we're being called from `export' or `readonly'.
443 In POSIX mode, this prints the name of the calling builtin (`export'
444 or `readonly') instead of `declare', and doesn't print function defs
445 when called by `export' or `readonly'. */
446 int
447 show_var_attributes (var, pattr, nodefs)
448 SHELL_VAR *var;
449 int pattr, nodefs;
450 {
451 char flags[MAX_ATTRIBUTES], *x;
452 int i;
453
454 i = var_attribute_string (var, pattr, flags);
455
456 /* If we're printing functions with definitions, print the function def
457 first, then the attributes, instead of printing output that can't be
458 reused as input to recreate the current state. */
459 if (function_p (var) && nodefs == 0 && (pattr == 0 || posixly_correct == 0))
460 {
461 printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL));
462 nodefs++;
463 if (pattr == 0 && i == 1 && flags[0] == 'f')
464 return 0; /* don't print `declare -f name' */
465 }
466
467 if (pattr == 0 || posixly_correct == 0)
468 printf ("declare -%s ", i ? flags : "-");
469 else if (i)
470 printf ("%s -%s ", this_command_name, flags);
471 else
472 printf ("%s ", this_command_name);
473
474 #if defined (ARRAY_VARS)
475 if (invisible_p (var) && (array_p (var) || assoc_p (var)))
476 printf ("%s\n", var->name);
477 else if (array_p (var))
478 print_array_assignment (var, 0);
479 else if (assoc_p (var))
480 print_assoc_assignment (var, 0);
481 else
482 #endif
483 /* force `readonly' and `export' to not print out function definitions
484 when in POSIX mode. */
485 if (nodefs || (function_p (var) && pattr != 0 && posixly_correct))
486 printf ("%s\n", var->name);
487 else if (function_p (var))
488 printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL));
489 else if (invisible_p (var) || var_isset (var) == 0)
490 printf ("%s\n", var->name);
491 else
492 {
493 x = sh_double_quote (value_cell (var));
494 printf ("%s=%s\n", var->name, x);
495 free (x);
496 }
497 return (0);
498 }
499
500 int
501 show_name_attributes (name, nodefs)
502 char *name;
503 int nodefs;
504 {
505 SHELL_VAR *var;
506
507 #if 0
508 var = find_variable_tempenv (name);
509 #else
510 var = find_variable_noref (name);
511 #endif
512
513 if (var /* && invisible_p (var) == 0 */)
514 {
515 show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
516 return (0);
517 }
518 else
519 return (1);
520 }
521
522 int
523 show_func_attributes (name, nodefs)
524 char *name;
525 int nodefs;
526 {
527 SHELL_VAR *var;
528
529 var = find_function (name);
530
531 if (var)
532 {
533 show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
534 return (0);
535 }
536 else
537 return (1);
538 }
539
540 void
541 set_var_attribute (name, attribute, undo)
542 char *name;
543 int attribute, undo;
544 {
545 SHELL_VAR *var, *tv, *v, *refvar;
546 char *tvalue;
547
548 if (undo)
549 var = find_variable (name);
550 else
551 {
552 tv = find_tempenv_variable (name);
553 /* XXX -- need to handle case where tv is a temp variable in a
554 function-scope context, since function_env has been merged into
555 the local variables table. */
556 if (tv && tempvar_p (tv))
557 {
558 tvalue = var_isset (tv) ? savestring (value_cell (tv)) : savestring ("");
559
560 var = bind_variable (tv->name, tvalue, 0);
561 if (var == 0)
562 {
563 free (tvalue);
564 return; /* XXX - no error message here */
565 }
566 var->attributes |= tv->attributes & ~att_tempvar;
567 /* This avoids an error message when propagating a read-only var
568 later on. */
569 if (posixly_correct || shell_compatibility_level <= 44)
570 {
571 if (var->context == 0 && (attribute & att_readonly))
572 {
573 /* Don't bother to set the `propagate to the global variables
574 table' flag if we've just bound the variable in that
575 table */
576 v = find_global_variable (tv->name);
577 if (v != var)
578 VSETATTR (tv, att_propagate);
579 }
580 else
581 VSETATTR (tv, att_propagate);
582 if (var->context != 0)
583 VSETATTR (var, att_propagate);
584 }
585
586 SETVARATTR (tv, attribute, undo); /* XXX */
587
588 stupidly_hack_special_variables (tv->name);
589
590 free (tvalue);
591 }
592 else
593 {
594 var = find_variable_notempenv (name);
595 if (var == 0)
596 {
597 /* We might have a nameref pointing to something that we can't
598 resolve to a shell variable. If we do, skip it. We do a little
599 checking just so we can print an error message. */
600 refvar = find_variable_nameref_for_create (name, 0);
601 if (refvar == INVALID_NAMEREF_VALUE)
602 return;
603 /* Otherwise we probably have a nameref pointing to a variable
604 that hasn't been created yet. bind_variable will take care
605 of that. */
606 }
607 if (var == 0)
608 {
609 var = bind_variable (name, (char *)NULL, 0);
610 if (var && no_invisible_vars == 0)
611 VSETATTR (var, att_invisible);
612 }
613 else if (var->context != 0)
614 VSETATTR (var, att_propagate);
615 }
616 }
617
618 if (var)
619 SETVARATTR (var, attribute, undo);
620
621 if (var && (exported_p (var) || (attribute & att_exported)))
622 array_needs_making++; /* XXX */
623 }