]> git.ipfire.org Git - thirdparty/bash.git/blob - builtins/set.def
Bash-5.2 patch 17: fix for optimizing forks when using the . builtin in a subshell
[thirdparty/bash.git] / builtins / set.def
1 This file is set.def, from which is created set.c.
2 It implements the "set" and "unset" builtins in Bash.
3
4 Copyright (C) 1987-2021 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 set.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
34 #include "../bashansi.h"
35 #include "../bashintl.h"
36
37 #include "../shell.h"
38 #include "../parser.h"
39 #include "../flags.h"
40 #include "common.h"
41 #include "bashgetopt.h"
42
43 #if defined (READLINE)
44 # include "../input.h"
45 # include "../bashline.h"
46 # include <readline/readline.h>
47 #endif
48
49 #if defined (HISTORY)
50 # include "../bashhist.h"
51 #endif
52
53 $BUILTIN set
54 $FUNCTION set_builtin
55 $SHORT_DOC set [-abefhkmnptuvxBCEHPT] [-o option-name] [--] [-] [arg ...]
56 Set or unset values of shell options and positional parameters.
57
58 Change the value of shell attributes and positional parameters, or
59 display the names and values of shell variables.
60
61 Options:
62 -a Mark variables which are modified or created for export.
63 -b Notify of job termination immediately.
64 -e Exit immediately if a command exits with a non-zero status.
65 -f Disable file name generation (globbing).
66 -h Remember the location of commands as they are looked up.
67 -k All assignment arguments are placed in the environment for a
68 command, not just those that precede the command name.
69 -m Job control is enabled.
70 -n Read commands but do not execute them.
71 -o option-name
72 Set the variable corresponding to option-name:
73 allexport same as -a
74 braceexpand same as -B
75 #if defined (READLINE)
76 emacs use an emacs-style line editing interface
77 #endif /* READLINE */
78 errexit same as -e
79 errtrace same as -E
80 functrace same as -T
81 hashall same as -h
82 #if defined (BANG_HISTORY)
83 histexpand same as -H
84 #endif /* BANG_HISTORY */
85 #if defined (HISTORY)
86 history enable command history
87 #endif
88 ignoreeof the shell will not exit upon reading EOF
89 interactive-comments
90 allow comments to appear in interactive commands
91 keyword same as -k
92 #if defined (JOB_CONTROL)
93 monitor same as -m
94 #endif
95 noclobber same as -C
96 noexec same as -n
97 noglob same as -f
98 nolog currently accepted but ignored
99 #if defined (JOB_CONTROL)
100 notify same as -b
101 #endif
102 nounset same as -u
103 onecmd same as -t
104 physical same as -P
105 pipefail the return value of a pipeline is the status of
106 the last command to exit with a non-zero status,
107 or zero if no command exited with a non-zero status
108 posix change the behavior of bash where the default
109 operation differs from the Posix standard to
110 match the standard
111 privileged same as -p
112 verbose same as -v
113 #if defined (READLINE)
114 vi use a vi-style line editing interface
115 #endif /* READLINE */
116 xtrace same as -x
117 -p Turned on whenever the real and effective user ids do not match.
118 Disables processing of the $ENV file and importing of shell
119 functions. Turning this option off causes the effective uid and
120 gid to be set to the real uid and gid.
121 -t Exit after reading and executing one command.
122 -u Treat unset variables as an error when substituting.
123 -v Print shell input lines as they are read.
124 -x Print commands and their arguments as they are executed.
125 #if defined (BRACE_EXPANSION)
126 -B the shell will perform brace expansion
127 #endif /* BRACE_EXPANSION */
128 -C If set, disallow existing regular files to be overwritten
129 by redirection of output.
130 -E If set, the ERR trap is inherited by shell functions.
131 #if defined (BANG_HISTORY)
132 -H Enable ! style history substitution. This flag is on
133 by default when the shell is interactive.
134 #endif /* BANG_HISTORY */
135 -P If set, do not resolve symbolic links when executing commands
136 such as cd which change the current directory.
137 -T If set, the DEBUG and RETURN traps are inherited by shell functions.
138 -- Assign any remaining arguments to the positional parameters.
139 If there are no remaining arguments, the positional parameters
140 are unset.
141 - Assign any remaining arguments to the positional parameters.
142 The -x and -v options are turned off.
143
144 Using + rather than - causes these flags to be turned off. The
145 flags can also be used upon invocation of the shell. The current
146 set of flags may be found in $-. The remaining n ARGs are positional
147 parameters and are assigned, in order, to $1, $2, .. $n. If no
148 ARGs are given, all shell variables are printed.
149
150 Exit Status:
151 Returns success unless an invalid option is given.
152 $END
153
154 typedef int setopt_set_func_t PARAMS((int, char *));
155 typedef int setopt_get_func_t PARAMS((char *));
156
157 static int find_minus_o_option PARAMS((char *));
158
159 static void print_minus_o_option PARAMS((char *, int, int));
160 static void print_all_shell_variables PARAMS((void));
161
162 static int set_ignoreeof PARAMS((int, char *));
163 static int set_posix_mode PARAMS((int, char *));
164
165 #if defined (READLINE)
166 static int set_edit_mode PARAMS((int, char *));
167 static int get_edit_mode PARAMS((char *));
168 #endif
169
170 #if defined (HISTORY)
171 static int bash_set_history PARAMS((int, char *));
172 #endif
173
174 static const char * const on = "on";
175 static const char * const off = "off";
176
177 static int previous_option_value;
178
179 /* A struct used to match long options for set -o to the corresponding
180 option letter or internal variable. The functions can be called to
181 dynamically generate values. If you add a new variable name here
182 that doesn't have a corresponding single-character option letter, make
183 sure to set the value appropriately in reset_shell_options. */
184 const struct {
185 char *name;
186 int letter;
187 int *variable;
188 setopt_set_func_t *set_func;
189 setopt_get_func_t *get_func;
190 } o_options[] = {
191 { "allexport", 'a', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
192 #if defined (BRACE_EXPANSION)
193 { "braceexpand",'B', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
194 #endif
195 #if defined (READLINE)
196 { "emacs", '\0', (int *)NULL, set_edit_mode, get_edit_mode },
197 #endif
198 { "errexit", 'e', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
199 { "errtrace", 'E', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
200 { "functrace", 'T', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
201 { "hashall", 'h', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
202 #if defined (BANG_HISTORY)
203 { "histexpand", 'H', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
204 #endif /* BANG_HISTORY */
205 #if defined (HISTORY)
206 { "history", '\0', &enable_history_list, bash_set_history, (setopt_get_func_t *)NULL },
207 #endif
208 { "ignoreeof", '\0', &ignoreeof, set_ignoreeof, (setopt_get_func_t *)NULL },
209 { "interactive-comments", '\0', &interactive_comments, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
210 { "keyword", 'k', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
211 #if defined (JOB_CONTROL)
212 { "monitor", 'm', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
213 #endif
214 { "noclobber", 'C', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
215 { "noexec", 'n', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
216 { "noglob", 'f', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
217 #if defined (HISTORY)
218 { "nolog", '\0', &dont_save_function_defs, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
219 #endif
220 #if defined (JOB_CONTROL)
221 { "notify", 'b', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
222 #endif /* JOB_CONTROL */
223 { "nounset", 'u', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
224 { "onecmd", 't', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
225 { "physical", 'P', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
226 { "pipefail", '\0', &pipefail_opt, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
227 { "posix", '\0', &posixly_correct, set_posix_mode, (setopt_get_func_t *)NULL },
228 { "privileged", 'p', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
229 { "verbose", 'v', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
230 #if defined (READLINE)
231 { "vi", '\0', (int *)NULL, set_edit_mode, get_edit_mode },
232 #endif
233 { "xtrace", 'x', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
234 {(char *)NULL, 0 , (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
235 };
236
237 #define N_O_OPTIONS (sizeof (o_options) / sizeof (o_options[0]))
238
239 #define GET_BINARY_O_OPTION_VALUE(i, name) \
240 ((o_options[i].get_func) ? (*o_options[i].get_func) (name) \
241 : (*o_options[i].variable))
242
243 #define SET_BINARY_O_OPTION_VALUE(i, onoff, name) \
244 ((o_options[i].set_func) ? (*o_options[i].set_func) (onoff, name) \
245 : (*o_options[i].variable = (onoff == FLAG_ON)))
246
247 static int
248 find_minus_o_option (name)
249 char *name;
250 {
251 register int i;
252
253 for (i = 0; o_options[i].name; i++)
254 if (STREQ (name, o_options[i].name))
255 return i;
256 return -1;
257 }
258
259 int
260 minus_o_option_value (name)
261 char *name;
262 {
263 register int i;
264 int *on_or_off;
265
266 i = find_minus_o_option (name);
267 if (i < 0)
268 return (-1);
269
270 if (o_options[i].letter)
271 {
272 on_or_off = find_flag (o_options[i].letter);
273 return ((on_or_off == FLAG_UNKNOWN) ? -1 : *on_or_off);
274 }
275 else
276 return (GET_BINARY_O_OPTION_VALUE (i, name));
277 }
278
279 #define MINUS_O_FORMAT "%-15s\t%s\n"
280
281 static void
282 print_minus_o_option (name, value, pflag)
283 char *name;
284 int value, pflag;
285 {
286 if (pflag == 0)
287 printf (MINUS_O_FORMAT, name, value ? on : off);
288 else
289 printf ("set %co %s\n", value ? '-' : '+', name);
290 }
291
292 void
293 list_minus_o_opts (mode, reusable)
294 int mode, reusable;
295 {
296 register int i;
297 int *on_or_off, value;
298
299 for (i = 0; o_options[i].name; i++)
300 {
301 if (o_options[i].letter)
302 {
303 value = 0;
304 on_or_off = find_flag (o_options[i].letter);
305 if (on_or_off == FLAG_UNKNOWN)
306 on_or_off = &value;
307 if (mode == -1 || mode == *on_or_off)
308 print_minus_o_option (o_options[i].name, *on_or_off, reusable);
309 }
310 else
311 {
312 value = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
313 if (mode == -1 || mode == value)
314 print_minus_o_option (o_options[i].name, value, reusable);
315 }
316 }
317 }
318
319 char **
320 get_minus_o_opts ()
321 {
322 char **ret;
323 int i;
324
325 ret = strvec_create (N_O_OPTIONS + 1);
326 for (i = 0; o_options[i].name; i++)
327 ret[i] = o_options[i].name;
328 ret[i] = (char *)NULL;
329 return ret;
330 }
331
332 char *
333 get_current_options ()
334 {
335 char *temp;
336 int i, posixopts;
337
338 posixopts = num_posix_options (); /* shopts modified by posix mode */
339 /* Make the buffer big enough to hold the set -o options and the shopt
340 options modified by posix mode. */
341 temp = (char *)xmalloc (1 + N_O_OPTIONS + posixopts);
342 for (i = 0; o_options[i].name; i++)
343 {
344 if (o_options[i].letter)
345 temp[i] = *(find_flag (o_options[i].letter));
346 else
347 temp[i] = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
348 }
349
350 /* Add the shell options that are modified by posix mode to the end of the
351 bitmap. They will be handled in set_current_options() */
352 get_posix_options (temp+i);
353 temp[i+posixopts] = '\0';
354 return (temp);
355 }
356
357 void
358 set_current_options (bitmap)
359 const char *bitmap;
360 {
361 int i, v, cv, *on_or_off;
362
363 if (bitmap == 0)
364 return;
365
366 for (i = 0; o_options[i].name; i++)
367 {
368 v = bitmap[i] ? FLAG_ON : FLAG_OFF;
369 if (o_options[i].letter)
370 {
371 /* We should not get FLAG_UNKNOWN here */
372 on_or_off = find_flag (o_options[i].letter);
373 cv = *on_or_off ? FLAG_ON : FLAG_OFF;
374 if (v != cv)
375 change_flag (o_options[i].letter, v);
376 }
377 else
378 {
379 cv = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
380 cv = cv ? FLAG_ON : FLAG_OFF;
381 if (v != cv)
382 SET_BINARY_O_OPTION_VALUE (i, v, o_options[i].name);
383 }
384 }
385
386 /* Now reset the variables changed by posix mode */
387 set_posix_options (bitmap+i);
388 }
389
390 static int
391 set_ignoreeof (on_or_off, option_name)
392 int on_or_off;
393 char *option_name;
394 {
395 ignoreeof = on_or_off == FLAG_ON;
396 unbind_variable_noref ("ignoreeof");
397 if (ignoreeof)
398 bind_variable ("IGNOREEOF", "10", 0);
399 else
400 unbind_variable_noref ("IGNOREEOF");
401 sv_ignoreeof ("IGNOREEOF");
402 return 0;
403 }
404
405 static int
406 set_posix_mode (on_or_off, option_name)
407 int on_or_off;
408 char *option_name;
409 {
410 /* short-circuit on no-op */
411 if ((on_or_off == FLAG_ON && posixly_correct) ||
412 (on_or_off == FLAG_OFF && posixly_correct == 0))
413 return 0;
414
415 posixly_correct = on_or_off == FLAG_ON;
416 if (posixly_correct == 0)
417 unbind_variable_noref ("POSIXLY_CORRECT");
418 else
419 bind_variable ("POSIXLY_CORRECT", "y", 0);
420 sv_strict_posix ("POSIXLY_CORRECT");
421 return (0);
422 }
423
424 #if defined (READLINE)
425 /* Magic. This code `knows' how readline handles rl_editing_mode. */
426 static int
427 set_edit_mode (on_or_off, option_name)
428 int on_or_off;
429 char *option_name;
430 {
431 int isemacs;
432
433 if (on_or_off == FLAG_ON)
434 {
435 rl_variable_bind ("editing-mode", option_name);
436
437 if (interactive)
438 with_input_from_stdin ();
439 no_line_editing = 0;
440 }
441 else
442 {
443 isemacs = rl_editing_mode == 1;
444 if ((isemacs && *option_name == 'e') || (!isemacs && *option_name == 'v'))
445 {
446 if (interactive)
447 with_input_from_stream (stdin, "stdin");
448 no_line_editing = 1;
449 }
450 }
451 return 1-no_line_editing;
452 }
453
454 static int
455 get_edit_mode (name)
456 char *name;
457 {
458 return (*name == 'e' ? no_line_editing == 0 && rl_editing_mode == 1
459 : no_line_editing == 0 && rl_editing_mode == 0);
460 }
461 #endif /* READLINE */
462
463 #if defined (HISTORY)
464 static int
465 bash_set_history (on_or_off, option_name)
466 int on_or_off;
467 char *option_name;
468 {
469 if (on_or_off == FLAG_ON)
470 {
471 enable_history_list = 1;
472 bash_history_enable ();
473 if (history_lines_this_session == 0)
474 load_history ();
475 }
476 else
477 {
478 enable_history_list = 0;
479 bash_history_disable ();
480 }
481 return (1 - enable_history_list);
482 }
483 #endif
484
485 int
486 set_minus_o_option (on_or_off, option_name)
487 int on_or_off;
488 char *option_name;
489 {
490 register int i;
491
492 i = find_minus_o_option (option_name);
493 if (i < 0)
494 {
495 sh_invalidoptname (option_name);
496 return (EX_USAGE);
497 }
498
499 if (o_options[i].letter == 0)
500 {
501 previous_option_value = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
502 SET_BINARY_O_OPTION_VALUE (i, on_or_off, option_name);
503 return (EXECUTION_SUCCESS);
504 }
505 else
506 {
507 if ((previous_option_value = change_flag (o_options[i].letter, on_or_off)) == FLAG_ERROR)
508 {
509 sh_invalidoptname (option_name);
510 return (EXECUTION_FAILURE);
511 }
512 else
513 return (EXECUTION_SUCCESS);
514 }
515 }
516
517 static void
518 print_all_shell_variables ()
519 {
520 SHELL_VAR **vars;
521
522 vars = all_shell_variables ();
523 if (vars)
524 {
525 print_var_list (vars);
526 free (vars);
527 }
528
529 /* POSIX.2 does not allow function names and definitions to be output when
530 `set' is invoked without options (PASC Interp #202). */
531 if (posixly_correct == 0)
532 {
533 vars = all_shell_functions ();
534 if (vars)
535 {
536 print_func_list (vars);
537 free (vars);
538 }
539 }
540 }
541
542 void
543 set_shellopts ()
544 {
545 char *value;
546 char tflag[N_O_OPTIONS];
547 int vsize, i, vptr, *ip, exported;
548 SHELL_VAR *v;
549
550 for (vsize = i = 0; o_options[i].name; i++)
551 {
552 tflag[i] = 0;
553 if (o_options[i].letter)
554 {
555 ip = find_flag (o_options[i].letter);
556 if (ip && *ip)
557 {
558 vsize += strlen (o_options[i].name) + 1;
559 tflag[i] = 1;
560 }
561 }
562 else if (GET_BINARY_O_OPTION_VALUE (i, o_options[i].name))
563 {
564 vsize += strlen (o_options[i].name) + 1;
565 tflag[i] = 1;
566 }
567 }
568
569 value = (char *)xmalloc (vsize + 1);
570
571 for (i = vptr = 0; o_options[i].name; i++)
572 {
573 if (tflag[i])
574 {
575 strcpy (value + vptr, o_options[i].name);
576 vptr += strlen (o_options[i].name);
577 value[vptr++] = ':';
578 }
579 }
580
581 if (vptr)
582 vptr--; /* cut off trailing colon */
583 value[vptr] = '\0';
584
585 v = find_variable ("SHELLOPTS");
586
587 /* Turn off the read-only attribute so we can bind the new value, and
588 note whether or not the variable was exported. */
589 if (v)
590 {
591 VUNSETATTR (v, att_readonly);
592 exported = exported_p (v);
593 }
594 else
595 exported = 0;
596
597 v = bind_variable ("SHELLOPTS", value, 0);
598
599 /* Turn the read-only attribute back on, and turn off the export attribute
600 if it was set implicitly by mark_modified_vars and SHELLOPTS was not
601 exported before we bound the new value. */
602 VSETATTR (v, att_readonly);
603 if (mark_modified_vars && exported == 0 && exported_p (v))
604 VUNSETATTR (v, att_exported);
605
606 free (value);
607 }
608
609 void
610 parse_shellopts (value)
611 char *value;
612 {
613 char *vname;
614 int vptr;
615
616 vptr = 0;
617 while (vname = extract_colon_unit (value, &vptr))
618 {
619 set_minus_o_option (FLAG_ON, vname);
620 free (vname);
621 }
622 }
623
624 void
625 initialize_shell_options (no_shellopts)
626 int no_shellopts;
627 {
628 char *temp;
629 SHELL_VAR *var;
630
631 if (no_shellopts == 0)
632 {
633 var = find_variable ("SHELLOPTS");
634 /* set up any shell options we may have inherited. */
635 if (var && imported_p (var))
636 {
637 temp = (array_p (var) || assoc_p (var)) ? (char *)NULL : savestring (value_cell (var));
638 if (temp)
639 {
640 parse_shellopts (temp);
641 free (temp);
642 }
643 }
644 }
645
646 /* Set up the $SHELLOPTS variable. */
647 set_shellopts ();
648 }
649
650 /* Reset the values of the -o options that are not also shell flags. This is
651 called from execute_cmd.c:initialize_subshell() when setting up a subshell
652 to run an executable shell script without a leading `#!'. */
653 void
654 reset_shell_options ()
655 {
656 pipefail_opt = 0;
657 ignoreeof = 0;
658
659 #if defined (STRICT_POSIX)
660 posixly_correct = 1;
661 #else
662 posixly_correct = 0;
663 #endif
664 #if defined (HISTORY)
665 dont_save_function_defs = 0;
666 remember_on_history = enable_history_list = 1; /* XXX */
667 #endif
668 }
669
670 /* Set some flags from the word values in the input list. If LIST is empty,
671 then print out the values of the variables instead. If LIST contains
672 non-flags, then set $1 - $9 to the successive words of LIST. */
673 int
674 set_builtin (list)
675 WORD_LIST *list;
676 {
677 int on_or_off, flag_name, force_assignment, opts_changed, rv, r;
678 register char *arg;
679 char s[3];
680
681 if (list == 0)
682 {
683 print_all_shell_variables ();
684 return (sh_chkwrite (EXECUTION_SUCCESS));
685 }
686
687 /* Check validity of flag arguments. */
688 rv = EXECUTION_SUCCESS;
689 reset_internal_getopt ();
690 while ((flag_name = internal_getopt (list, optflags)) != -1)
691 {
692 switch (flag_name)
693 {
694 case 'i': /* don't allow set -i */
695 s[0] = list_opttype;
696 s[1] = 'i';
697 s[2] = '\0';
698 sh_invalidopt (s);
699 builtin_usage ();
700 return (EX_USAGE);
701 CASE_HELPOPT;
702 case '?':
703 builtin_usage ();
704 return (list_optopt == '?' ? EXECUTION_SUCCESS : EX_USAGE);
705 default:
706 break;
707 }
708 }
709
710 /* Do the set command. While the list consists of words starting with
711 '-' or '+' treat them as flags, otherwise, start assigning them to
712 $1 ... $n. */
713 for (force_assignment = opts_changed = 0; list; )
714 {
715 arg = list->word->word;
716
717 /* If the argument is `--' or `-' then signal the end of the list
718 and remember the remaining arguments. */
719 if (arg[0] == '-' && (!arg[1] || (arg[1] == '-' && !arg[2])))
720 {
721 list = list->next;
722
723 /* `set --' unsets the positional parameters. */
724 if (arg[1] == '-')
725 force_assignment = 1;
726
727 /* Until told differently, the old shell behaviour of
728 `set - [arg ...]' being equivalent to `set +xv [arg ...]'
729 stands. Posix.2 says the behaviour is marked as obsolescent. */
730 else
731 {
732 change_flag ('x', '+');
733 change_flag ('v', '+');
734 opts_changed = 1;
735 }
736
737 break;
738 }
739
740 if ((on_or_off = *arg) && (on_or_off == '-' || on_or_off == '+'))
741 {
742 while (flag_name = *++arg)
743 {
744 if (flag_name == '?')
745 {
746 builtin_usage ();
747 return (EXECUTION_SUCCESS);
748 }
749 else if (flag_name == 'o') /* -+o option-name */
750 {
751 char *option_name;
752 WORD_LIST *opt;
753
754 opt = list->next;
755
756 if (opt == 0)
757 {
758 list_minus_o_opts (-1, (on_or_off == '+'));
759 rv = sh_chkwrite (rv);
760 continue;
761 }
762
763 option_name = opt->word->word;
764
765 if (option_name == 0 || *option_name == '\0' ||
766 *option_name == '-' || *option_name == '+')
767 {
768 list_minus_o_opts (-1, (on_or_off == '+'));
769 continue;
770 }
771 list = list->next; /* Skip over option name. */
772
773 opts_changed = 1;
774 if ((r = set_minus_o_option (on_or_off, option_name)) != EXECUTION_SUCCESS)
775 {
776 set_shellopts ();
777 return (r);
778 }
779 }
780 else if (change_flag (flag_name, on_or_off) == FLAG_ERROR)
781 {
782 s[0] = on_or_off;
783 s[1] = flag_name;
784 s[2] = '\0';
785 sh_invalidopt (s);
786 builtin_usage ();
787 set_shellopts ();
788 return (EXECUTION_FAILURE);
789 }
790 opts_changed = 1;
791 }
792 }
793 else
794 {
795 break;
796 }
797 list = list->next;
798 }
799
800 /* Assigning $1 ... $n */
801 if (list || force_assignment)
802 remember_args (list, 1);
803 /* Set up new value of $SHELLOPTS */
804 if (opts_changed)
805 set_shellopts ();
806 return (rv);
807 }
808
809 $BUILTIN unset
810 $FUNCTION unset_builtin
811 $SHORT_DOC unset [-f] [-v] [-n] [name ...]
812 Unset values and attributes of shell variables and functions.
813
814 For each NAME, remove the corresponding variable or function.
815
816 Options:
817 -f treat each NAME as a shell function
818 -v treat each NAME as a shell variable
819 -n treat each NAME as a name reference and unset the variable itself
820 rather than the variable it references
821
822 Without options, unset first tries to unset a variable, and if that fails,
823 tries to unset a function.
824
825 Some variables cannot be unset; also see `readonly'.
826
827 Exit Status:
828 Returns success unless an invalid option is given or a NAME is read-only.
829 $END
830
831 #define NEXT_VARIABLE() any_failed++; list = list->next; continue;
832
833 int
834 unset_builtin (list)
835 WORD_LIST *list;
836 {
837 int unset_function, unset_variable, unset_array, opt, nameref, any_failed;
838 int global_unset_func, global_unset_var, vflags, base_vflags, valid_id;
839 char *name, *tname;
840
841 unset_function = unset_variable = unset_array = nameref = any_failed = 0;
842 global_unset_func = global_unset_var = 0;
843
844 reset_internal_getopt ();
845 while ((opt = internal_getopt (list, "fnv")) != -1)
846 {
847 switch (opt)
848 {
849 case 'f':
850 global_unset_func = 1;
851 break;
852 case 'v':
853 global_unset_var = 1;
854 break;
855 case 'n':
856 nameref = 1;
857 break;
858 CASE_HELPOPT;
859 default:
860 builtin_usage ();
861 return (EX_USAGE);
862 }
863 }
864
865 list = loptend;
866
867 if (global_unset_func && global_unset_var)
868 {
869 builtin_error (_("cannot simultaneously unset a function and a variable"));
870 return (EXECUTION_FAILURE);
871 }
872 else if (unset_function && nameref)
873 nameref = 0;
874
875 #if defined (ARRAY_VARS)
876 base_vflags = assoc_expand_once ? VA_NOEXPAND : 0;
877 #endif
878
879 while (list)
880 {
881 SHELL_VAR *var;
882 int tem;
883 #if defined (ARRAY_VARS)
884 char *t;
885 #endif
886
887 name = list->word->word;
888
889 unset_function = global_unset_func;
890 unset_variable = global_unset_var;
891
892 #if defined (ARRAY_VARS)
893 vflags = builtin_arrayref_flags (list->word, base_vflags);
894 #endif
895
896 #if defined (ARRAY_VARS)
897 unset_array = 0;
898 /* XXX valid array reference second arg was 0 */
899 if (!unset_function && nameref == 0 && tokenize_array_reference (name, vflags, &t))
900 unset_array = 1;
901 #endif
902 /* Get error checking out of the way first. The low-level functions
903 just perform the unset, relying on the caller to verify. */
904 valid_id = legal_identifier (name);
905
906 /* Whether or not we are in posix mode, if neither -f nor -v appears,
907 skip over trying to unset variables with invalid names and just
908 treat them as potential shell function names. */
909 if (global_unset_func == 0 && global_unset_var == 0 && valid_id == 0)
910 {
911 unset_variable = unset_array = 0;
912 unset_function = 1;
913 }
914
915 /* Bash allows functions with names which are not valid identifiers
916 to be created when not in posix mode, so check only when in posix
917 mode when unsetting a function. */
918 if (unset_function == 0 && valid_id == 0)
919 {
920 sh_invalidid (name);
921 NEXT_VARIABLE ();
922 }
923
924 /* Search for functions here if -f supplied or if NAME cannot be a
925 variable name. */
926 var = unset_function ? find_function (name)
927 : (nameref ? find_variable_last_nameref (name, 0) : find_variable (name));
928
929 /* Some variables (but not functions yet) cannot be unset, period. */
930 if (var && unset_function == 0 && non_unsettable_p (var))
931 {
932 builtin_error (_("%s: cannot unset"), name);
933 NEXT_VARIABLE ();
934 }
935
936 /* if we have a nameref we want to use it */
937 if (var && unset_function == 0 && nameref == 0 && STREQ (name, name_cell(var)) == 0)
938 name = name_cell (var);
939
940 /* Posix.2 says try variables first, then functions. If we would
941 find a function after unsuccessfully searching for a variable,
942 note that we're acting on a function now as if -f were
943 supplied. The readonly check below takes care of it. */
944 if (var == 0 && nameref == 0 && unset_variable == 0 && unset_function == 0)
945 {
946 if (var = find_function (name))
947 unset_function = 1;
948 }
949
950 /* Posix.2 says that unsetting readonly variables is an error. */
951 if (var && readonly_p (var))
952 {
953 builtin_error (_("%s: cannot unset: readonly %s"),
954 var->name, unset_function ? "function" : "variable");
955 NEXT_VARIABLE ();
956 }
957
958 /* Unless the -f option is supplied, the name refers to a variable. */
959 #if defined (ARRAY_VARS)
960 if (var && unset_array)
961 {
962 if (shell_compatibility_level <= 51)
963 vflags |= VA_ALLOWALL;
964
965 /* Let unbind_array_element decide what to do with non-array vars */
966 tem = unbind_array_element (var, t, vflags); /* XXX new third arg */
967 if (tem == -2 && array_p (var) == 0 && assoc_p (var) == 0)
968 {
969 builtin_error (_("%s: not an array variable"), var->name);
970 NEXT_VARIABLE ();
971 }
972 else if (tem < 0)
973 any_failed++;
974 }
975 else
976 #endif /* ARRAY_VARS */
977 /* If we're trying to unset a nameref variable whose value isn't a set
978 variable, make sure we still try to unset the nameref's value */
979 if (var == 0 && nameref == 0 && unset_function == 0)
980 {
981 var = find_variable_last_nameref (name, 0);
982 if (var && nameref_p (var))
983 {
984 #if defined (ARRAY_VARS)
985 if (valid_array_reference (nameref_cell (var), 0))
986 {
987 int len;
988
989 tname = savestring (nameref_cell (var));
990 if (var = array_variable_part (tname, 0, &t, &len))
991 {
992 /* change to what unbind_array_element now expects */
993 if (t[len - 1] == ']')
994 t[len - 1] = 0;
995 tem = unbind_array_element (var, t, vflags); /* XXX new third arg */
996 }
997 free (tname);
998 }
999 else
1000 #endif
1001 tem = unbind_variable (nameref_cell (var));
1002 }
1003 else
1004 tem = unbind_variable (name);
1005 }
1006 else
1007 tem = unset_function ? unbind_func (name) : (nameref ? unbind_nameref (name) : unbind_variable (name));
1008
1009 /* This is what Posix.2 says: ``If neither -f nor -v
1010 is specified, the name refers to a variable; if a variable by
1011 that name does not exist, a function by that name, if any,
1012 shall be unset.'' */
1013 if (tem == -1 && nameref == 0 && unset_function == 0 && unset_variable == 0)
1014 tem = unbind_func (name);
1015
1016 name = list->word->word; /* reset above for namerefs */
1017
1018 /* SUSv3, POSIX.1-2001 say: ``Unsetting a variable or function that
1019 was not previously set shall not be considered an error.'' */
1020
1021 if (unset_function == 0)
1022 stupidly_hack_special_variables (name);
1023
1024 list = list->next;
1025 }
1026
1027 return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
1028 }