]> git.ipfire.org Git - thirdparty/bash.git/blame - builtins/set.def
Imported from ../bash-2.02.tar.gz.
[thirdparty/bash.git] / builtins / set.def
CommitLineData
726f6388
JA
1This file is set.def, from which is created set.c.
2It implements the "set" and "unset" builtins in Bash.
3
4Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
5
6This file is part of GNU Bash, the Bourne Again SHell.
7
8Bash is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 1, or (at your option) any later
11version.
12
13Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License along
19with Bash; see the file COPYING. If not, write to the Free Software
20Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21
22$PRODUCES set.c
23
ccc6cda3
JA
24#include <config.h>
25
26#if defined (HAVE_UNISTD_H)
cce855bc
JA
27# ifdef _MINIX
28# include <sys/types.h>
29# endif
ccc6cda3
JA
30# include <unistd.h>
31#endif
32
726f6388 33#include <stdio.h>
ccc6cda3
JA
34
35#include "../bashansi.h"
36
726f6388
JA
37#include "../shell.h"
38#include "../flags.h"
ccc6cda3 39#include "common.h"
726f6388
JA
40#include "bashgetopt.h"
41
ccc6cda3
JA
42#if defined (READLINE)
43# include "../input.h"
44# include "../bashline.h"
45# include <readline/readline.h>
46#endif
47
48#if defined (HISTORY)
49# include "../bashhist.h"
50#endif
51
726f6388 52extern int interactive;
ccc6cda3 53extern int noclobber, posixly_correct, ignoreeof, eof_encountered_limit;
726f6388
JA
54#if defined (READLINE)
55extern int rl_editing_mode, no_line_editing;
56#endif /* READLINE */
57
726f6388
JA
58$BUILTIN set
59$FUNCTION set_builtin
ccc6cda3 60$SHORT_DOC set [--abefhkmnptuvxBCHP] [-o option] [arg ...]
726f6388
JA
61 -a Mark variables which are modified or created for export.
62 -b Notify of job termination immediately.
63 -e Exit immediately if a command exits with a non-zero status.
64 -f Disable file name generation (globbing).
ccc6cda3 65 -h Remember the location of commands as they are looked up.
726f6388
JA
66 -i Force the shell to be an "interactive" one. Interactive shells
67 always read `~/.bashrc' on startup.
ccc6cda3 68 -k All assignment arguments are placed in the environment for a
726f6388
JA
69 command, not just those that precede the command name.
70 -m Job control is enabled.
71 -n Read commands but do not execute them.
72 -o option-name
73 Set the variable corresponding to option-name:
74 allexport same as -a
ccc6cda3 75 braceexpand same as -B
726f6388
JA
76#if defined (READLINE)
77 emacs use an emacs-style line editing interface
78#endif /* READLINE */
79 errexit same as -e
ccc6cda3 80 hashall same as -h
726f6388
JA
81#if defined (BANG_HISTORY)
82 histexpand same as -H
83#endif /* BANG_HISTORY */
d166f048
JA
84#if defined (HISTORY)
85 history enable command history
86#endif
726f6388
JA
87 ignoreeof the shell will not exit upon reading EOF
88 interactive-comments
89 allow comments to appear in interactive commands
ccc6cda3 90 keyword same as -k
726f6388 91 monitor same as -m
ccc6cda3 92 noclobber same as -C
726f6388
JA
93 noexec same as -n
94 noglob same as -f
726f6388
JA
95 notify save as -b
96 nounset same as -u
ccc6cda3
JA
97 onecmd same as -t
98 physical same as -P
99 posix change the behavior of bash where the default
100 operation differs from the 1003.2 standard to
101 match the standard
102 privileged same as -p
726f6388
JA
103 verbose same as -v
104#if defined (READLINE)
105 vi use a vi-style line editing interface
106#endif /* READLINE */
107 xtrace same as -x
108 -p Turned on whenever the real and effective user ids do not match.
109 Disables processing of the $ENV file and importing of shell
110 functions. Turning this option off causes the effective uid and
ccc6cda3 111 gid to be set to the real uid and gid.
726f6388
JA
112 -t Exit after reading and executing one command.
113 -u Treat unset variables as an error when substituting.
114 -v Print shell input lines as they are read.
115 -x Print commands and their arguments as they are executed.
ccc6cda3
JA
116#if defined (BRACE_EXPANSION)
117 -B the shell will perform brace expansion
118#endif /* BRACE_EXPANSION */
d166f048
JA
119 -C If set, disallow existing regular files to be overwritten
120 by redirection of output.
726f6388
JA
121#if defined (BANG_HISTORY)
122 -H Enable ! style history substitution. This flag is on
123 by default.
124#endif /* BANG_HISTORY */
726f6388
JA
125 -P If set, do not follow symbolic links when executing commands
126 such as cd which change the current directory.
127
128Using + rather than - causes these flags to be turned off. The
129flags can also be used upon invocation of the shell. The current
130set of flags may be found in $-. The remaining n ARGs are positional
131parameters and are assigned, in order, to $1, $2, .. $n. If no
132ARGs are given, all shell variables are printed.
133$END
134
ccc6cda3 135static int set_ignoreeof ();
d166f048 136static int set_posix_mode ();
ccc6cda3
JA
137
138#if defined (READLINE)
139static int set_edit_mode ();
140static int get_edit_mode ();
141#endif
142
143#if defined (HISTORY)
144static int bash_set_history ();
145#endif
146
147static char *on = "on";
148static char *off = "off";
149
726f6388
JA
150/* An a-list used to match long options for set -o to the corresponding
151 option letter. */
152struct {
153 char *name;
154 int letter;
155} o_options[] = {
156 { "allexport", 'a' },
ccc6cda3
JA
157#if defined (BRACE_EXPANSION)
158 { "braceexpand",'B' },
159#endif
726f6388 160 { "errexit", 'e' },
ccc6cda3 161 { "hashall", 'h' },
726f6388
JA
162#if defined (BANG_HISTORY)
163 { "histexpand", 'H' },
164#endif /* BANG_HISTORY */
ccc6cda3 165 { "keyword", 'k' },
726f6388 166 { "monitor", 'm' },
ccc6cda3 167 { "noclobber", 'C' },
726f6388
JA
168 { "noexec", 'n' },
169 { "noglob", 'f' },
726f6388
JA
170#if defined (JOB_CONTROL)
171 { "notify", 'b' },
172#endif /* JOB_CONTROL */
ccc6cda3
JA
173 { "nounset", 'u' },
174 { "onecmd", 't' },
175 { "physical", 'P' },
176 { "privileged", 'p' },
177 { "verbose", 'v' },
178 { "xtrace", 'x' },
179 {(char *)NULL, 0 },
180};
181
182struct {
183 char *name;
184 int *variable;
185 Function *set_func;
186 Function *get_func;
187} binary_o_options[] = {
188#if defined (HISTORY)
189 { "history", &remember_on_history, bash_set_history, (Function *)NULL },
190#endif
191 { "ignoreeof", &ignoreeof, set_ignoreeof, (Function *)NULL },
192 { "interactive-comments", &interactive_comments, (Function *)NULL, (Function *)NULL },
d166f048 193 { "posix", &posixly_correct, set_posix_mode, (Function *)NULL },
ccc6cda3
JA
194#if defined (READLINE)
195 { "emacs", (int *)NULL, set_edit_mode, get_edit_mode },
196 { "vi", (int *)NULL, set_edit_mode, get_edit_mode },
197#endif
198 { (char *)NULL, (int *)NULL }
726f6388
JA
199};
200
ccc6cda3
JA
201#define GET_BINARY_O_OPTION_VALUE(i, name) \
202 ((binary_o_options[i].get_func) ? (*binary_o_options[i].get_func) (name) \
203 : (*binary_o_options[i].variable))
204
205#define SET_BINARY_O_OPTION_VALUE(i, onoff, name) \
206 ((binary_o_options[i].set_func) ? (*binary_o_options[i].set_func) (onoff, name) \
207 : (*binary_o_options[i].variable = (onoff == FLAG_ON)))
208
209int
210minus_o_option_value (name)
211 char *name;
212{
213 register int i;
214 int *on_or_off;
215
216 for (i = 0; o_options[i].name; i++)
217 {
218 if (STREQ (name, o_options[i].name))
219 {
220 on_or_off = find_flag (o_options[i].letter);
221 return ((on_or_off == FLAG_UNKNOWN) ? -1 : *on_or_off);
222 }
223 }
224 for (i = 0; binary_o_options[i].name; i++)
225 {
226 if (STREQ (name, binary_o_options[i].name))
227 return (GET_BINARY_O_OPTION_VALUE (i, name));
228 }
229
230 return (-1);
231}
232
726f6388
JA
233#define MINUS_O_FORMAT "%-15s\t%s\n"
234
cce855bc
JA
235static void
236print_minus_o_option (name, value, pflag)
237 char *name;
238 int value, pflag;
726f6388 239{
cce855bc
JA
240 if (pflag == 0)
241 printf (MINUS_O_FORMAT, name, value ? on : off);
242 else
243 printf ("set %co %s\n", value ? '-' : '+', name);
ccc6cda3 244}
726f6388 245
cce855bc
JA
246void
247list_minus_o_opts (mode, reusable)
248 int mode, reusable;
ccc6cda3
JA
249{
250 register int i;
251 int *on_or_off, value;
726f6388 252
ccc6cda3
JA
253 for (value = i = 0; o_options[i].name; i++)
254 {
255 on_or_off = find_flag (o_options[i].letter);
256 if (on_or_off == FLAG_UNKNOWN)
257 on_or_off = &value;
cce855bc
JA
258 if (mode == -1 || mode == *on_or_off)
259 print_minus_o_option (o_options[i].name, *on_or_off, reusable);
ccc6cda3
JA
260 }
261 for (i = 0; binary_o_options[i].name; i++)
262 {
263 value = GET_BINARY_O_OPTION_VALUE (i, binary_o_options[i].name);
cce855bc
JA
264 if (mode == -1 || mode == value)
265 print_minus_o_option (binary_o_options[i].name, value, reusable);
ccc6cda3
JA
266 }
267}
726f6388 268
ccc6cda3
JA
269static int
270set_ignoreeof (on_or_off, option_name)
271 int on_or_off;
272 char *option_name;
273{
274 ignoreeof = on_or_off == FLAG_ON;
275 unbind_variable ("ignoreeof");
276 if (ignoreeof)
277 bind_variable ("IGNOREEOF", "10");
278 else
279 unbind_variable ("IGNOREEOF");
280 sv_ignoreeof ("IGNOREEOF");
281 return 0;
282}
726f6388 283
d166f048
JA
284static int
285set_posix_mode (on_or_off, option_name)
286 int on_or_off;
287 char *option_name;
288{
289 posixly_correct = on_or_off == FLAG_ON;
290 if (posixly_correct == 0)
291 unbind_variable ("POSIXLY_CORRECT");
292 else
293 bind_variable ("POSIXLY_CORRECT", "y");
294 sv_strict_posix ("POSIXLY_CORRECT");
295 return (0);
296}
297
726f6388 298#if defined (READLINE)
ccc6cda3
JA
299/* Magic. This code `knows' how readline handles rl_editing_mode. */
300static int
301set_edit_mode (on_or_off, option_name)
302 int on_or_off;
303 char *option_name;
304{
305 int isemacs;
306
307 if (on_or_off == FLAG_ON)
726f6388 308 {
ccc6cda3
JA
309 rl_variable_bind ("editing-mode", option_name);
310
311 if (interactive)
312 with_input_from_stdin ();
313 no_line_editing = 0;
726f6388
JA
314 }
315 else
316 {
ccc6cda3
JA
317 isemacs = rl_editing_mode == 1;
318 if ((isemacs && *option_name == 'e') || (!isemacs && *option_name == 'v'))
319 {
320 if (interactive)
321 with_input_from_stream (stdin, "stdin");
322 no_line_editing = 1;
323 }
726f6388 324 }
ccc6cda3
JA
325 return 1-no_line_editing;
326}
327
328static int
329get_edit_mode (name)
330 char *name;
331{
332 return (*name == 'e' ? no_line_editing == 0 && rl_editing_mode == 1
333 : no_line_editing == 0 && rl_editing_mode == 0);
334}
726f6388
JA
335#endif /* READLINE */
336
ccc6cda3
JA
337#if defined (HISTORY)
338static int
339bash_set_history (on_or_off, option_name)
340 int on_or_off;
341 char *option_name;
342{
343 if (on_or_off == FLAG_ON)
726f6388 344 {
ccc6cda3
JA
345 bash_history_enable ();
346 if (history_lines_this_session == 0)
347 load_history ();
726f6388 348 }
ccc6cda3
JA
349 else
350 bash_history_disable ();
351 return (1 - remember_on_history);
726f6388 352}
ccc6cda3 353#endif
726f6388 354
ccc6cda3 355int
726f6388
JA
356set_minus_o_option (on_or_off, option_name)
357 int on_or_off;
358 char *option_name;
359{
ccc6cda3
JA
360 int option_char;
361 VFunction *set_func;
362 register int i;
726f6388 363
ccc6cda3 364 for (i = 0; binary_o_options[i].name; i++)
726f6388 365 {
ccc6cda3
JA
366 if (STREQ (option_name, binary_o_options[i].name))
367 {
368 SET_BINARY_O_OPTION_VALUE (i, on_or_off, option_name);
369 return (EXECUTION_SUCCESS);
370 }
726f6388 371 }
ccc6cda3
JA
372
373 for (i = 0, option_char = -1, set_func = 0; o_options[i].name; i++)
726f6388 374 {
ccc6cda3
JA
375 if (STREQ (option_name, o_options[i].name))
376 {
377 option_char = o_options[i].letter;
378 break;
379 }
726f6388 380 }
ccc6cda3 381 if (option_char == -1)
726f6388 382 {
ccc6cda3
JA
383 builtin_error ("%s: unknown option name", option_name);
384 return (EXECUTION_FAILURE);
726f6388 385 }
ccc6cda3 386 if (change_flag (option_char, on_or_off) == FLAG_ERROR)
726f6388 387 {
ccc6cda3
JA
388 bad_option (option_name);
389 return (EXECUTION_FAILURE);
390 }
391 return (EXECUTION_SUCCESS);
392}
726f6388 393
ccc6cda3
JA
394static void
395print_all_shell_variables ()
396{
397 SHELL_VAR **vars;
398
399 vars = all_shell_variables ();
400 if (vars)
401 {
402 print_var_list (vars);
403 free (vars);
726f6388 404 }
ccc6cda3
JA
405
406 vars = all_shell_functions ();
407 if (vars)
726f6388 408 {
ccc6cda3
JA
409 print_var_list (vars);
410 free (vars);
726f6388 411 }
ccc6cda3
JA
412}
413
414void
415set_shellopts ()
416{
417 char *value;
cce855bc 418 int vsize, i, vptr, *ip, exported;
ccc6cda3
JA
419 SHELL_VAR *v;
420
421 for (vsize = i = 0; o_options[i].name; i++)
726f6388 422 {
ccc6cda3
JA
423 ip = find_flag (o_options[i].letter);
424 if (ip && *ip)
425 vsize += strlen (o_options[i].name) + 1;
426 }
427 for (i = 0; binary_o_options[i].name; i++)
428 if (GET_BINARY_O_OPTION_VALUE (i, binary_o_options[i].name))
429 vsize += strlen (binary_o_options[i].name) + 1;
430
431 value = xmalloc (vsize + 1);
432
433 for (i = vptr = 0; o_options[i].name; i++)
434 {
435 ip = find_flag (o_options[i].letter);
436 if (ip && *ip)
726f6388 437 {
ccc6cda3
JA
438 strcpy (value + vptr, o_options[i].name);
439 vptr += strlen (o_options[i].name);
440 value[vptr++] = ':';
726f6388
JA
441 }
442 }
ccc6cda3
JA
443 for (i = 0; binary_o_options[i].name; i++)
444 if (GET_BINARY_O_OPTION_VALUE (i, binary_o_options[i].name))
445 {
446 strcpy (value + vptr, binary_o_options[i].name);
447 vptr += strlen (binary_o_options[i].name);
448 value[vptr++] = ':';
449 }
d166f048
JA
450 if (vptr)
451 vptr--; /* cut off trailing colon */
452 value[vptr] = '\0';
ccc6cda3
JA
453
454 v = find_variable ("SHELLOPTS");
cce855bc
JA
455
456 /* Turn off the read-only attribute so we can bind the new value, and
457 note whether or not the variable was exported. */
ccc6cda3 458 if (v)
cce855bc
JA
459 {
460 v->attributes &= ~att_readonly;
461 exported = exported_p (v);
462 }
463 else
464 exported = 0;
465
ccc6cda3 466 v = bind_variable ("SHELLOPTS", value);
cce855bc
JA
467
468 /* Turn the read-only attribute back on, and turn off the export attribute
469 if it was set implicitly by mark_modified_vars and SHELLOPTS was not
470 exported before we bound the new value. */
ccc6cda3 471 v->attributes |= att_readonly;
cce855bc
JA
472 if (mark_modified_vars && exported == 0 && exported_p (v))
473 v->attributes &= ~att_exported;
ccc6cda3
JA
474
475 free (value);
476}
477
478void
479parse_shellopts (value)
480 char *value;
481{
482 char *vname;
483 int vptr;
484
485 vptr = 0;
486 while (vname = extract_colon_unit (value, &vptr))
487 {
488 set_minus_o_option (FLAG_ON, vname);
489 free (vname);
490 }
491}
492
493void
cce855bc
JA
494initialize_shell_options (no_shellopts)
495 int no_shellopts;
ccc6cda3
JA
496{
497 char *temp;
d166f048 498 SHELL_VAR *var;
ccc6cda3 499
cce855bc 500 if (no_shellopts == 0)
d166f048 501 {
cce855bc
JA
502 var = find_variable ("SHELLOPTS");
503 /* set up any shell options we may have inherited. */
504 if (var && imported_p (var))
d166f048 505 {
cce855bc
JA
506 temp = (array_p (var)) ? (char *)NULL : savestring (value_cell (var));
507 if (temp)
508 {
509 parse_shellopts (temp);
510 free (temp);
511 }
d166f048
JA
512 }
513 }
ccc6cda3
JA
514
515 /* Set up the $SHELLOPTS variable. */
516 set_shellopts ();
726f6388
JA
517}
518
d166f048
JA
519/* Reset the values of the -o options that are not also shell flags. */
520void
521reset_shell_options ()
522{
523#if defined (HISTORY)
524 remember_on_history = 1;
525#endif
526 ignoreeof = posixly_correct = 0;
527}
528
726f6388
JA
529/* Set some flags from the word values in the input list. If LIST is empty,
530 then print out the values of the variables instead. If LIST contains
531 non-flags, then set $1 - $9 to the successive words of LIST. */
ccc6cda3 532int
726f6388
JA
533set_builtin (list)
534 WORD_LIST *list;
535{
ccc6cda3
JA
536 int on_or_off, flag_name, force_assignment, opts_changed;
537 WORD_LIST *l;
538 register char *arg;
726f6388 539
ccc6cda3 540 if (list == 0)
726f6388 541 {
ccc6cda3 542 print_all_shell_variables ();
726f6388
JA
543 return (EXECUTION_SUCCESS);
544 }
545
546 /* Check validity of flag arguments. */
547 if (*list->word->word == '-' || *list->word->word == '+')
548 {
ccc6cda3 549 for (l = list; l && (arg = l->word->word); l = l->next)
726f6388
JA
550 {
551 char c;
552
553 if (arg[0] != '-' && arg[0] != '+')
554 break;
555
556 /* `-' or `--' signifies end of flag arguments. */
ccc6cda3 557 if (arg[0] == '-' && (!arg[1] || (arg[1] == '-' && !arg[2])))
726f6388
JA
558 break;
559
560 while (c = *++arg)
561 {
562 if (find_flag (c) == FLAG_UNKNOWN && c != 'o')
563 {
564 char s[2];
565 s[0] = c; s[1] = '\0';
566 bad_option (s);
567 if (c == '?')
ccc6cda3 568 builtin_usage ();
726f6388
JA
569 return (c == '?' ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
570 }
571 }
726f6388 572 }
726f6388
JA
573 }
574
575 /* Do the set command. While the list consists of words starting with
576 '-' or '+' treat them as flags, otherwise, start assigning them to
577 $1 ... $n. */
ccc6cda3 578 for (force_assignment = opts_changed = 0; list; )
726f6388 579 {
ccc6cda3 580 arg = list->word->word;
726f6388
JA
581
582 /* If the argument is `--' or `-' then signal the end of the list
583 and remember the remaining arguments. */
ccc6cda3 584 if (arg[0] == '-' && (!arg[1] || (arg[1] == '-' && !arg[2])))
726f6388
JA
585 {
586 list = list->next;
587
588 /* `set --' unsets the positional parameters. */
ccc6cda3 589 if (arg[1] == '-')
726f6388
JA
590 force_assignment = 1;
591
592 /* Until told differently, the old shell behaviour of
593 `set - [arg ...]' being equivalent to `set +xv [arg ...]'
594 stands. Posix.2 says the behaviour is marked as obsolescent. */
595 else
596 {
597 change_flag ('x', '+');
598 change_flag ('v', '+');
ccc6cda3 599 opts_changed = 1;
726f6388
JA
600 }
601
602 break;
603 }
604
ccc6cda3 605 if ((on_or_off = *arg) && (on_or_off == '-' || on_or_off == '+'))
726f6388 606 {
ccc6cda3 607 while (flag_name = *++arg)
726f6388
JA
608 {
609 if (flag_name == '?')
610 {
ccc6cda3 611 builtin_usage ();
726f6388
JA
612 return (EXECUTION_SUCCESS);
613 }
614 else if (flag_name == 'o') /* -+o option-name */
615 {
616 char *option_name;
617 WORD_LIST *opt;
618
619 opt = list->next;
620
ccc6cda3 621 if (opt == 0)
726f6388 622 {
cce855bc 623 list_minus_o_opts (-1, (on_or_off == '+'));
726f6388
JA
624 continue;
625 }
626
627 option_name = opt->word->word;
628
ccc6cda3
JA
629 if (option_name == 0 || *option_name == '\0' ||
630 *option_name == '-' || *option_name == '+')
726f6388 631 {
cce855bc 632 list_minus_o_opts (-1, (on_or_off == '+'));
726f6388
JA
633 continue;
634 }
635 list = list->next; /* Skip over option name. */
636
ccc6cda3 637 opts_changed = 1;
726f6388 638 if (set_minus_o_option (on_or_off, option_name) != EXECUTION_SUCCESS)
726f6388 639 {
ccc6cda3 640 set_shellopts ();
726f6388
JA
641 return (EXECUTION_FAILURE);
642 }
643 }
ccc6cda3
JA
644 else if (change_flag (flag_name, on_or_off) == FLAG_ERROR)
645 {
646 char opt[3];
647 opt[0] = on_or_off;
648 opt[1] = flag_name;
649 opt[2] = '\0';
650 bad_option (opt);
651 builtin_usage ();
652 set_shellopts ();
653 return (EXECUTION_FAILURE);
654 }
655 opts_changed = 1;
726f6388
JA
656 }
657 }
658 else
659 {
660 break;
661 }
662 list = list->next;
663 }
664
665 /* Assigning $1 ... $n */
666 if (list || force_assignment)
667 remember_args (list, 1);
ccc6cda3
JA
668 /* Set up new value of $SHELLOPTS */
669 if (opts_changed)
670 set_shellopts ();
726f6388
JA
671 return (EXECUTION_SUCCESS);
672}
673
674$BUILTIN unset
675$FUNCTION unset_builtin
676$SHORT_DOC unset [-f] [-v] [name ...]
677For each NAME, remove the corresponding variable or function. Given
678the `-v', unset will only act on variables. Given the `-f' flag,
679unset will only act on functions. With neither flag, unset first
680tries to unset a variable, and if that fails, then tries to unset a
681function. Some variables (such as PATH and IFS) cannot be unset; also
682see readonly.
683$END
684
ccc6cda3
JA
685#define NEXT_VARIABLE() any_failed++; list = list->next; continue;
686
687int
726f6388
JA
688unset_builtin (list)
689 WORD_LIST *list;
690{
ccc6cda3 691 int unset_function, unset_variable, unset_array, opt, any_failed;
726f6388
JA
692 char *name;
693
ccc6cda3
JA
694 unset_function = unset_variable = unset_array = any_failed = 0;
695
726f6388
JA
696 reset_internal_getopt ();
697 while ((opt = internal_getopt (list, "fv")) != -1)
698 {
699 switch (opt)
700 {
701 case 'f':
702 unset_function = 1;
703 break;
704 case 'v':
705 unset_variable = 1;
706 break;
707 default:
ccc6cda3
JA
708 builtin_usage ();
709 return (EX_USAGE);
726f6388
JA
710 }
711 }
712
713 list = loptend;
714
715 if (unset_function && unset_variable)
716 {
717 builtin_error ("cannot simultaneously unset a function and a variable");
718 return (EXECUTION_FAILURE);
719 }
720
721 while (list)
722 {
ccc6cda3
JA
723 SHELL_VAR *var;
724 int tem;
725#if defined (ARRAY_VARS)
726 char *t;
727#endif
728
726f6388
JA
729 name = list->word->word;
730
ccc6cda3
JA
731#if defined (ARRAY_VARS)
732 if (!unset_function && valid_array_reference (name))
726f6388 733 {
ccc6cda3
JA
734 t = strchr (name, '[');
735 *t++ = '\0';
736 unset_array++;
726f6388 737 }
ccc6cda3
JA
738#endif
739
cce855bc
JA
740 /* Bash allows functions with names which are not valid identifiers
741 to be created when not in posix mode, so check only when in posix
742 mode when unsetting a function. */
743 if (((unset_function && posixly_correct) || !unset_function) && legal_identifier (name) == 0)
d166f048
JA
744 {
745 builtin_error ("`%s': not a valid identifier", name);
746 NEXT_VARIABLE ();
747 }
748
ccc6cda3
JA
749 var = unset_function ? find_function (name) : find_variable (name);
750
751 if (var && !unset_function && non_unsettable_p (var))
726f6388 752 {
ccc6cda3
JA
753 builtin_error ("%s: cannot unset", name);
754 NEXT_VARIABLE ();
755 }
726f6388 756
ccc6cda3
JA
757 /* Posix.2 says that unsetting readonly variables is an error. */
758 if (var && readonly_p (var))
759 {
760 builtin_error ("%s: cannot unset: readonly %s",
761 name, unset_function ? "function" : "variable");
762 NEXT_VARIABLE ();
763 }
726f6388 764
ccc6cda3
JA
765 /* Unless the -f option is supplied, the name refers to a variable. */
766#if defined (ARRAY_VARS)
767 if (var && unset_array)
768 {
769 if (array_p (var) == 0)
726f6388 770 {
ccc6cda3
JA
771 builtin_error ("%s: not an array variable", name);
772 NEXT_VARIABLE ();
726f6388 773 }
ccc6cda3
JA
774 else
775 tem = unbind_array_element (var, t);
726f6388 776 }
ccc6cda3
JA
777 else
778#endif /* ARRAY_VARS */
779 tem = makunbound (name, unset_function ? shell_functions : shell_variables);
780
781 /* This is what Posix.2 draft 11+ says. ``If neither -f nor -v
782 is specified, the name refers to a variable; if a variable by
783 that name does not exist, a function by that name, if any,
784 shall be unset.'' */
785 if (tem == -1 && !unset_function && !unset_variable)
786 tem = makunbound (name, shell_functions);
787
788 if (tem == -1)
789 any_failed++;
790 else if (!unset_function)
791 stupidly_hack_special_variables (name);
792
726f6388
JA
793 list = list->next;
794 }
795
ccc6cda3 796 return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
726f6388 797}