]> git.ipfire.org Git - thirdparty/bash.git/blob - builtins/set.def
final set of ANSI C changes
[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-2023 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 (int, char *);
155 typedef int setopt_get_func_t (char *);
156
157 static int find_minus_o_option (char *);
158
159 static void print_minus_o_option (char *, int, int);
160 static void print_all_shell_variables (void);
161
162 static int set_ignoreeof (int, char *);
163 static int set_posix_mode (int, char *);
164
165 #if defined (READLINE)
166 static int set_edit_mode (int, char *);
167 static int get_edit_mode (char *);
168 #endif
169
170 #if defined (HISTORY)
171 static int bash_set_history (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 (char *name)
249 {
250 register int i;
251
252 for (i = 0; o_options[i].name; i++)
253 if (STREQ (name, o_options[i].name))
254 return i;
255 return -1;
256 }
257
258 int
259 minus_o_option_value (char *name)
260 {
261 register int i;
262 int *on_or_off;
263
264 i = find_minus_o_option (name);
265 if (i < 0)
266 return (-1);
267
268 if (o_options[i].letter)
269 {
270 on_or_off = find_flag (o_options[i].letter);
271 return ((on_or_off == FLAG_UNKNOWN) ? -1 : *on_or_off);
272 }
273 else
274 return (GET_BINARY_O_OPTION_VALUE (i, name));
275 }
276
277 #define MINUS_O_FORMAT "%-15s\t%s\n"
278
279 static void
280 print_minus_o_option (char *name, int value, int pflag)
281 {
282 if (pflag == 0)
283 printf (MINUS_O_FORMAT, name, value ? on : off);
284 else
285 printf ("set %co %s\n", value ? '-' : '+', name);
286 }
287
288 void
289 list_minus_o_opts (int mode, int reusable)
290 {
291 register int i;
292 int *on_or_off, value;
293
294 for (i = 0; o_options[i].name; i++)
295 {
296 if (o_options[i].letter)
297 {
298 value = 0;
299 on_or_off = find_flag (o_options[i].letter);
300 if (on_or_off == FLAG_UNKNOWN)
301 on_or_off = &value;
302 if (mode == -1 || mode == *on_or_off)
303 print_minus_o_option (o_options[i].name, *on_or_off, reusable);
304 }
305 else
306 {
307 value = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
308 if (mode == -1 || mode == value)
309 print_minus_o_option (o_options[i].name, value, reusable);
310 }
311 }
312 }
313
314 char **
315 get_minus_o_opts (void)
316 {
317 char **ret;
318 int i;
319
320 ret = strvec_create (N_O_OPTIONS + 1);
321 for (i = 0; o_options[i].name; i++)
322 ret[i] = o_options[i].name;
323 ret[i] = (char *)NULL;
324 return ret;
325 }
326
327 char *
328 get_current_options (void)
329 {
330 char *temp;
331 int i, posixopts;
332
333 posixopts = num_posix_options (); /* shopts modified by posix mode */
334 /* Make the buffer big enough to hold the set -o options and the shopt
335 options modified by posix mode. */
336 temp = (char *)xmalloc (1 + N_O_OPTIONS + posixopts);
337 for (i = 0; o_options[i].name; i++)
338 {
339 if (o_options[i].letter)
340 temp[i] = *(find_flag (o_options[i].letter));
341 else
342 temp[i] = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
343 }
344
345 /* Add the shell options that are modified by posix mode to the end of the
346 bitmap. They will be handled in set_current_options() */
347 get_posix_options (temp+i);
348 temp[i+posixopts] = '\0';
349 return (temp);
350 }
351
352 void
353 set_current_options (const char *bitmap)
354 {
355 int i, v, cv, *on_or_off;
356
357 if (bitmap == 0)
358 return;
359
360 for (i = 0; o_options[i].name; i++)
361 {
362 v = bitmap[i] ? FLAG_ON : FLAG_OFF;
363 if (o_options[i].letter)
364 {
365 /* We should not get FLAG_UNKNOWN here */
366 on_or_off = find_flag (o_options[i].letter);
367 cv = *on_or_off ? FLAG_ON : FLAG_OFF;
368 if (v != cv)
369 change_flag (o_options[i].letter, v);
370 }
371 else
372 {
373 cv = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
374 cv = cv ? FLAG_ON : FLAG_OFF;
375 if (v != cv)
376 SET_BINARY_O_OPTION_VALUE (i, v, o_options[i].name);
377 }
378 }
379
380 /* Now reset the variables changed by posix mode */
381 set_posix_options (bitmap+i);
382 }
383
384 static int
385 set_ignoreeof (int on_or_off, char *option_name)
386 {
387 ignoreeof = on_or_off == FLAG_ON;
388 unbind_variable_noref ("ignoreeof");
389 if (ignoreeof)
390 bind_variable ("IGNOREEOF", "10", 0);
391 else
392 unbind_variable_noref ("IGNOREEOF");
393 sv_ignoreeof ("IGNOREEOF");
394 return 0;
395 }
396
397 static int
398 set_posix_mode (int on_or_off, char *option_name)
399 {
400 /* short-circuit on no-op */
401 if ((on_or_off == FLAG_ON && posixly_correct) ||
402 (on_or_off == FLAG_OFF && posixly_correct == 0))
403 return 0;
404
405 posixly_correct = on_or_off == FLAG_ON;
406 if (posixly_correct == 0)
407 unbind_variable_noref ("POSIXLY_CORRECT");
408 else
409 bind_variable ("POSIXLY_CORRECT", "y", 0);
410 sv_strict_posix ("POSIXLY_CORRECT");
411 return (0);
412 }
413
414 #if defined (READLINE)
415 /* Magic. This code `knows' how readline handles rl_editing_mode. */
416 static int
417 set_edit_mode (int on_or_off, char *option_name)
418 {
419 int isemacs;
420
421 if (on_or_off == FLAG_ON)
422 {
423 rl_variable_bind ("editing-mode", option_name);
424
425 if (interactive && command_execution_string == 0)
426 with_input_from_stdin ();
427 no_line_editing = 0;
428 }
429 else
430 {
431 isemacs = rl_editing_mode == 1;
432 if ((isemacs && *option_name == 'e') || (!isemacs && *option_name == 'v'))
433 {
434 if (interactive && command_execution_string == 0)
435 with_input_from_stream (stdin, "stdin");
436 no_line_editing = 1;
437 }
438 }
439 return 1-no_line_editing;
440 }
441
442 static int
443 get_edit_mode (char *name)
444 {
445 return (*name == 'e' ? no_line_editing == 0 && rl_editing_mode == 1
446 : no_line_editing == 0 && rl_editing_mode == 0);
447 }
448 #endif /* READLINE */
449
450 #if defined (HISTORY)
451 static int
452 bash_set_history (int on_or_off, char *option_name)
453 {
454 if (on_or_off == FLAG_ON)
455 {
456 enable_history_list = 1;
457 bash_history_enable ();
458 if (history_lines_this_session == 0)
459 load_history ();
460 }
461 else
462 {
463 enable_history_list = 0;
464 bash_history_disable ();
465 }
466 return (1 - enable_history_list);
467 }
468 #endif
469
470 int
471 set_minus_o_option (int on_or_off, char *option_name)
472 {
473 register int i;
474
475 i = find_minus_o_option (option_name);
476 if (i < 0)
477 {
478 sh_invalidoptname (option_name);
479 return (EX_USAGE);
480 }
481
482 if (o_options[i].letter == 0)
483 {
484 previous_option_value = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
485 SET_BINARY_O_OPTION_VALUE (i, on_or_off, option_name);
486 return (EXECUTION_SUCCESS);
487 }
488 else
489 {
490 if ((previous_option_value = change_flag (o_options[i].letter, on_or_off)) == FLAG_ERROR)
491 {
492 sh_invalidoptname (option_name);
493 return (EXECUTION_FAILURE);
494 }
495 else
496 return (EXECUTION_SUCCESS);
497 }
498 }
499
500 static void
501 print_all_shell_variables (void)
502 {
503 SHELL_VAR **vars;
504
505 vars = all_shell_variables ();
506 if (vars)
507 {
508 print_var_list (vars);
509 free (vars);
510 }
511
512 /* POSIX.2 does not allow function names and definitions to be output when
513 `set' is invoked without options (PASC Interp #202). */
514 if (posixly_correct == 0)
515 {
516 vars = all_shell_functions ();
517 if (vars)
518 {
519 print_func_list (vars);
520 free (vars);
521 }
522 }
523 }
524
525 void
526 set_shellopts (void)
527 {
528 char *value;
529 char tflag[N_O_OPTIONS];
530 int i, *ip, exported;
531 size_t vsize, vptr;
532 SHELL_VAR *v;
533
534 for (vsize = i = 0; o_options[i].name; i++)
535 {
536 tflag[i] = 0;
537 if (o_options[i].letter)
538 {
539 ip = find_flag (o_options[i].letter);
540 if (ip && *ip)
541 {
542 vsize += strlen (o_options[i].name) + 1;
543 tflag[i] = 1;
544 }
545 }
546 else if (GET_BINARY_O_OPTION_VALUE (i, o_options[i].name))
547 {
548 vsize += strlen (o_options[i].name) + 1;
549 tflag[i] = 1;
550 }
551 }
552
553 value = (char *)xmalloc (vsize + 1);
554
555 for (i = vptr = 0; o_options[i].name; i++)
556 {
557 if (tflag[i])
558 {
559 strcpy (value + vptr, o_options[i].name);
560 vptr += strlen (o_options[i].name);
561 value[vptr++] = ':';
562 }
563 }
564
565 if (vptr)
566 vptr--; /* cut off trailing colon */
567 value[vptr] = '\0';
568
569 v = find_variable ("SHELLOPTS");
570
571 /* Turn off the read-only attribute so we can bind the new value, and
572 note whether or not the variable was exported. */
573 if (v)
574 {
575 VUNSETATTR (v, att_readonly);
576 exported = exported_p (v);
577 }
578 else
579 exported = 0;
580
581 v = bind_variable ("SHELLOPTS", value, 0);
582
583 /* Turn the read-only attribute back on, and turn off the export attribute
584 if it was set implicitly by mark_modified_vars and SHELLOPTS was not
585 exported before we bound the new value. */
586 VSETATTR (v, att_readonly);
587 if (mark_modified_vars && exported == 0 && exported_p (v))
588 VUNSETATTR (v, att_exported);
589
590 free (value);
591 }
592
593 void
594 parse_shellopts (char *value)
595 {
596 char *vname;
597 int vptr;
598
599 vptr = 0;
600 while (vname = extract_colon_unit (value, &vptr))
601 {
602 set_minus_o_option (FLAG_ON, vname);
603 free (vname);
604 }
605 }
606
607 void
608 initialize_shell_options (int no_shellopts)
609 {
610 char *temp;
611 SHELL_VAR *var;
612
613 if (no_shellopts == 0)
614 {
615 var = find_variable ("SHELLOPTS");
616 /* set up any shell options we may have inherited. */
617 if (var && imported_p (var))
618 {
619 temp = (array_p (var) || assoc_p (var)) ? (char *)NULL : savestring (value_cell (var));
620 if (temp)
621 {
622 parse_shellopts (temp);
623 free (temp);
624 }
625 }
626 }
627
628 /* Set up the $SHELLOPTS variable. */
629 set_shellopts ();
630 }
631
632 /* Reset the values of the -o options that are not also shell flags. This is
633 called from execute_cmd.c:initialize_subshell() when setting up a subshell
634 to run an executable shell script without a leading `#!'. */
635 void
636 reset_shell_options (void)
637 {
638 pipefail_opt = 0;
639 ignoreeof = 0;
640
641 #if defined (STRICT_POSIX)
642 posixly_correct = 1;
643 #else
644 posixly_correct = 0;
645 #endif
646 #if defined (HISTORY)
647 dont_save_function_defs = 0;
648 remember_on_history = enable_history_list = 1; /* XXX */
649 #endif
650 }
651
652 /* Set some flags from the word values in the input list. If LIST is empty,
653 then print out the values of the variables instead. If LIST contains
654 non-flags, then set $1 - $9 to the successive words of LIST. */
655 int
656 set_builtin (WORD_LIST *list)
657 {
658 int on_or_off, flag_name, force_assignment, opts_changed, rv, r;
659 register char *arg;
660 char s[3];
661
662 if (list == 0)
663 {
664 print_all_shell_variables ();
665 return (sh_chkwrite (EXECUTION_SUCCESS));
666 }
667
668 /* Check validity of flag arguments. */
669 rv = EXECUTION_SUCCESS;
670 reset_internal_getopt ();
671 while ((flag_name = internal_getopt (list, optflags)) != -1)
672 {
673 switch (flag_name)
674 {
675 case 'i': /* don't allow set -i */
676 s[0] = list_opttype;
677 s[1] = 'i';
678 s[2] = '\0';
679 sh_invalidopt (s);
680 builtin_usage ();
681 return (EX_USAGE);
682 CASE_HELPOPT;
683 case '?':
684 builtin_usage ();
685 return (list_optopt == '?' ? EXECUTION_SUCCESS : EX_USAGE);
686 default:
687 break;
688 }
689 }
690
691 /* Do the set command. While the list consists of words starting with
692 '-' or '+' treat them as flags, otherwise, start assigning them to
693 $1 ... $n. */
694 for (force_assignment = opts_changed = 0; list; )
695 {
696 arg = list->word->word;
697
698 /* If the argument is `--' or `-' then signal the end of the list
699 and remember the remaining arguments. */
700 if (arg[0] == '-' && (!arg[1] || (arg[1] == '-' && !arg[2])))
701 {
702 list = list->next;
703
704 /* `set --' unsets the positional parameters. */
705 if (arg[1] == '-')
706 force_assignment = 1;
707
708 /* Until told differently, the old shell behaviour of
709 `set - [arg ...]' being equivalent to `set +xv [arg ...]'
710 stands. Posix.2 says the behaviour is marked as obsolescent. */
711 else
712 {
713 change_flag ('x', '+');
714 change_flag ('v', '+');
715 opts_changed = 1;
716 }
717
718 break;
719 }
720
721 if ((on_or_off = *arg) && (on_or_off == '-' || on_or_off == '+'))
722 {
723 while (flag_name = *++arg)
724 {
725 if (flag_name == '?')
726 {
727 builtin_usage ();
728 return (EXECUTION_SUCCESS);
729 }
730 else if (flag_name == 'o') /* -+o option-name */
731 {
732 char *option_name;
733 WORD_LIST *opt;
734
735 opt = list->next;
736
737 if (opt == 0)
738 {
739 list_minus_o_opts (-1, (on_or_off == '+'));
740 rv = sh_chkwrite (rv);
741 continue;
742 }
743
744 option_name = opt->word->word;
745
746 if (option_name == 0 || *option_name == '\0' ||
747 *option_name == '-' || *option_name == '+')
748 {
749 list_minus_o_opts (-1, (on_or_off == '+'));
750 continue;
751 }
752 list = list->next; /* Skip over option name. */
753
754 opts_changed = 1;
755 if ((r = set_minus_o_option (on_or_off, option_name)) != EXECUTION_SUCCESS)
756 {
757 set_shellopts ();
758 return (r);
759 }
760 }
761 else if (change_flag (flag_name, on_or_off) == FLAG_ERROR)
762 {
763 s[0] = on_or_off;
764 s[1] = flag_name;
765 s[2] = '\0';
766 sh_invalidopt (s);
767 builtin_usage ();
768 set_shellopts ();
769 return (EXECUTION_FAILURE);
770 }
771 opts_changed = 1;
772 }
773 }
774 else
775 {
776 break;
777 }
778 list = list->next;
779 }
780
781 /* Assigning $1 ... $n */
782 if (list || force_assignment)
783 remember_args (list, 1);
784 /* Set up new value of $SHELLOPTS */
785 if (opts_changed)
786 set_shellopts ();
787 return (rv);
788 }
789
790 $BUILTIN unset
791 $FUNCTION unset_builtin
792 $SHORT_DOC unset [-f] [-v] [-n] [name ...]
793 Unset values and attributes of shell variables and functions.
794
795 For each NAME, remove the corresponding variable or function.
796
797 Options:
798 -f treat each NAME as a shell function
799 -v treat each NAME as a shell variable
800 -n treat each NAME as a name reference and unset the variable itself
801 rather than the variable it references
802
803 Without options, unset first tries to unset a variable, and if that fails,
804 tries to unset a function.
805
806 Some variables cannot be unset; also see `readonly'.
807
808 Exit Status:
809 Returns success unless an invalid option is given or a NAME is read-only.
810 $END
811
812 #define NEXT_VARIABLE() any_failed++; list = list->next; continue;
813
814 int
815 unset_builtin (WORD_LIST *list)
816 {
817 int unset_function, unset_variable, unset_array, opt, nameref, any_failed;
818 int global_unset_func, global_unset_var, vflags, base_vflags, valid_id;
819 int posix_utility_error;
820 char *name, *tname;
821
822 unset_function = unset_variable = unset_array = nameref = 0;
823 posix_utility_error = any_failed = 0;
824 global_unset_func = global_unset_var = 0;
825
826 reset_internal_getopt ();
827 while ((opt = internal_getopt (list, "fnv")) != -1)
828 {
829 switch (opt)
830 {
831 case 'f':
832 global_unset_func = 1;
833 break;
834 case 'v':
835 global_unset_var = 1;
836 break;
837 case 'n':
838 nameref = 1;
839 break;
840 CASE_HELPOPT;
841 default:
842 builtin_usage ();
843 return (EX_USAGE);
844 }
845 }
846
847 list = loptend;
848
849 if (global_unset_func && global_unset_var)
850 {
851 builtin_error (_("cannot simultaneously unset a function and a variable"));
852 return (EXECUTION_FAILURE);
853 }
854 else if (unset_function && nameref)
855 nameref = 0;
856
857 #if defined (ARRAY_VARS)
858 base_vflags = assoc_expand_once ? VA_NOEXPAND : 0;
859 #endif
860
861 while (list)
862 {
863 SHELL_VAR *var;
864 int tem;
865 #if defined (ARRAY_VARS)
866 char *t;
867 #endif
868
869 name = list->word->word;
870
871 unset_function = global_unset_func;
872 unset_variable = global_unset_var;
873
874 #if defined (ARRAY_VARS)
875 vflags = builtin_arrayref_flags (list->word, base_vflags);
876 #endif
877
878 #if defined (ARRAY_VARS)
879 unset_array = 0;
880 /* XXX valid array reference second arg was 0 */
881 if (!unset_function && nameref == 0 && tokenize_array_reference (name, vflags, &t))
882 unset_array = 1;
883 #endif
884 /* Get error checking out of the way first. The low-level functions
885 just perform the unset, relying on the caller to verify. */
886 valid_id = legal_identifier (name);
887
888 /* Whether or not we are in posix mode, if neither -f nor -v appears,
889 skip over trying to unset variables with invalid names and just
890 treat them as potential shell function names. */
891 if (global_unset_func == 0 && global_unset_var == 0 && valid_id == 0)
892 {
893 unset_variable = unset_array = 0;
894 unset_function = 1;
895 }
896
897 /* Bash allows functions with names which are not valid identifiers
898 to be created when not in posix mode, so check only when in posix
899 mode when unsetting a function. */
900 if (unset_function == 0 && valid_id == 0)
901 {
902 sh_invalidid (name);
903 posix_utility_error++;
904 NEXT_VARIABLE ();
905 }
906
907 /* Search for functions here if -f supplied or if NAME cannot be a
908 variable name. */
909 var = unset_function ? find_function (name)
910 : (nameref ? find_variable_last_nameref (name, 0) : find_variable (name));
911
912 /* Some variables (but not functions yet) cannot be unset, period. */
913 if (var && unset_function == 0 && non_unsettable_p (var))
914 {
915 builtin_error (_("%s: cannot unset"), name);
916 posix_utility_error++;
917 NEXT_VARIABLE ();
918 }
919
920 /* if we have a nameref we want to use it */
921 if (var && unset_function == 0 && nameref == 0 && STREQ (name, name_cell(var)) == 0)
922 name = name_cell (var);
923
924 /* Posix.2 says try variables first, then functions. If we would
925 find a function after unsuccessfully searching for a variable,
926 note that we're acting on a function now as if -f were
927 supplied. The readonly check below takes care of it. */
928 if (var == 0 && nameref == 0 && unset_variable == 0 && unset_function == 0)
929 {
930 if (var = find_function (name))
931 unset_function = 1;
932 }
933
934 /* Posix.2 says that unsetting readonly variables is an error. */
935 if (var && readonly_p (var))
936 {
937 builtin_error (_("%s: cannot unset: readonly %s"),
938 var->name, unset_function ? "function" : "variable");
939 posix_utility_error++;
940 NEXT_VARIABLE ();
941 }
942
943 /* Unless the -f option is supplied, the name refers to a variable. */
944 #if defined (ARRAY_VARS)
945 if (var && unset_array)
946 {
947 if (shell_compatibility_level <= 51)
948 vflags |= VA_ALLOWALL;
949
950 /* Let unbind_array_element decide what to do with non-array vars */
951 tem = unbind_array_element (var, t, vflags); /* XXX new third arg */
952 if (tem == -2 && array_p (var) == 0 && assoc_p (var) == 0)
953 {
954 builtin_error (_("%s: not an array variable"), var->name);
955 NEXT_VARIABLE ();
956 }
957 else if (tem < 0)
958 any_failed++;
959 }
960 else
961 #endif /* ARRAY_VARS */
962 /* If we're trying to unset a nameref variable whose value isn't a set
963 variable, make sure we still try to unset the nameref's value */
964 if (var == 0 && nameref == 0 && unset_function == 0)
965 {
966 var = find_variable_last_nameref (name, 0);
967 if (var && nameref_p (var))
968 {
969 #if defined (ARRAY_VARS)
970 if (valid_array_reference (nameref_cell (var), 0))
971 {
972 int len;
973
974 tname = savestring (nameref_cell (var));
975 if (var = array_variable_part (tname, 0, &t, &len))
976 {
977 /* change to what unbind_array_element now expects */
978 if (t[len - 1] == ']')
979 t[len - 1] = 0;
980 tem = unbind_array_element (var, t, vflags); /* XXX new third arg */
981 }
982 free (tname);
983 }
984 else
985 #endif
986 tem = unbind_variable (nameref_cell (var));
987 }
988 else
989 tem = unbind_variable (name);
990 }
991 else
992 tem = unset_function ? unbind_func (name) : (nameref ? unbind_nameref (name) : unbind_variable (name));
993
994 /* This is what Posix.2 says: ``If neither -f nor -v
995 is specified, the name refers to a variable; if a variable by
996 that name does not exist, it is unspecified whether a function
997 by that name, if any, shall be unset.'' The unspecified part is a
998 recent addition, so we continue to try to unset a shell function if
999 we don't find a variable named NAME. */
1000 if (tem == -1 && nameref == 0 && unset_function == 0 && unset_variable == 0)
1001 tem = unbind_func (name);
1002
1003 name = list->word->word; /* reset above for namerefs */
1004
1005 /* SUSv3, POSIX.1-2001 say: ``Unsetting a variable or function that
1006 was not previously set shall not be considered an error.'' */
1007
1008 if (unset_function == 0)
1009 stupidly_hack_special_variables (name);
1010
1011 list = list->next;
1012 }
1013
1014 return (any_failed ? (posix_utility_error ? EX_UTILERROR : EXECUTION_FAILURE) : EXECUTION_SUCCESS);
1015 }