5e550cbc9b6e09e14eaf7e93f2de31e4a864787d
[platform/upstream/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-2009 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 "../flags.h"
39 #include "common.h"
40 #include "bashgetopt.h"
41
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
52 extern int posixly_correct, ignoreeof, eof_encountered_limit;
53 #if defined (HISTORY)
54 extern int dont_save_function_defs;
55 #endif
56 #if defined (READLINE)
57 extern int no_line_editing;
58 #endif /* READLINE */
59
60 $BUILTIN set
61 $FUNCTION set_builtin
62 $SHORT_DOC set [--abefhkmnptuvxBCHP] [-o option-name] [arg ...]
63 Set or unset values of shell options and positional parameters.
64
65 Change the value of shell attributes and positional parameters, or
66 display the names and values of shell variables.
67
68 Options:
69   -a  Mark variables which are modified or created for export.
70   -b  Notify of job termination immediately.
71   -e  Exit immediately if a command exits with a non-zero status.
72   -f  Disable file name generation (globbing).
73   -h  Remember the location of commands as they are looked up.
74   -k  All assignment arguments are placed in the environment for a
75       command, not just those that precede the command name.
76   -m  Job control is enabled.
77   -n  Read commands but do not execute them.
78   -o option-name
79       Set the variable corresponding to option-name:
80           allexport    same as -a
81           braceexpand  same as -B
82 #if defined (READLINE)
83           emacs        use an emacs-style line editing interface
84 #endif /* READLINE */
85           errexit      same as -e
86           errtrace     same as -E
87           functrace    same as -T
88           hashall      same as -h
89 #if defined (BANG_HISTORY)
90           histexpand   same as -H
91 #endif /* BANG_HISTORY */
92 #if defined (HISTORY)
93           history      enable command history
94 #endif
95           ignoreeof    the shell will not exit upon reading EOF
96           interactive-comments
97                        allow comments to appear in interactive commands
98           keyword      same as -k
99           monitor      same as -m
100           noclobber    same as -C
101           noexec       same as -n
102           noglob       same as -f
103           nolog        currently accepted but ignored
104           notify       same as -b
105           nounset      same as -u
106           onecmd       same as -t
107           physical     same as -P
108           pipefail     the return value of a pipeline is the status of
109                        the last command to exit with a non-zero status,
110                        or zero if no command exited with a non-zero status
111           posix        change the behavior of bash where the default
112                        operation differs from the Posix standard to
113                        match the standard
114           privileged   same as -p
115           verbose      same as -v
116 #if defined (READLINE)
117           vi           use a vi-style line editing interface
118 #endif /* READLINE */
119           xtrace       same as -x
120   -p  Turned on whenever the real and effective user ids do not match.
121       Disables processing of the $ENV file and importing of shell
122       functions.  Turning this option off causes the effective uid and
123       gid to be set to the real uid and gid.
124   -t  Exit after reading and executing one command.
125   -u  Treat unset variables as an error when substituting.
126   -v  Print shell input lines as they are read.
127   -x  Print commands and their arguments as they are executed.
128 #if defined (BRACE_EXPANSION)
129   -B  the shell will perform brace expansion
130 #endif /* BRACE_EXPANSION */
131   -C  If set, disallow existing regular files to be overwritten
132       by redirection of output.
133   -E  If set, the ERR trap is inherited by shell functions.
134 #if defined (BANG_HISTORY)
135   -H  Enable ! style history substitution.  This flag is on
136       by default when the shell is interactive.
137 #endif /* BANG_HISTORY */
138   -P  If set, do not follow symbolic links when executing commands
139       such as cd which change the current directory.
140   -T  If set, the DEBUG trap is inherited by shell functions.
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 __P((int, char *));
155 typedef int setopt_get_func_t __P((char *));
156
157 static void print_minus_o_option __P((char *, int, int));
158 static void print_all_shell_variables __P((void));
159
160 static int set_ignoreeof __P((int, char *));
161 static int set_posix_mode __P((int, char *));
162
163 #if defined (READLINE)
164 static int set_edit_mode __P((int, char *));
165 static int get_edit_mode __P((char *));
166 #endif
167
168 #if defined (HISTORY)
169 static int bash_set_history __P((int, char *));
170 #endif
171
172 static const char * const on = "on";
173 static const char * const off = "off";
174
175 /* A struct used to match long options for set -o to the corresponding
176    option letter or internal variable.  The functions can be called to
177    dynamically generate values. */
178 const struct {
179   char *name;
180   int letter;
181   int *variable;
182   setopt_set_func_t *set_func;
183   setopt_get_func_t *get_func;
184 } o_options[] = {
185   { "allexport",  'a', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
186 #if defined (BRACE_EXPANSION)
187   { "braceexpand",'B', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
188 #endif
189 #if defined (READLINE)
190   { "emacs",     '\0', (int *)NULL, set_edit_mode, get_edit_mode },
191 #endif
192   { "errexit",    'e', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
193   { "errtrace",   'E', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
194   { "functrace",  'T', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
195   { "hashall",    'h', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
196 #if defined (BANG_HISTORY)
197   { "histexpand", 'H', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
198 #endif /* BANG_HISTORY */
199 #if defined (HISTORY)
200   { "history",   '\0', &enable_history_list, bash_set_history, (setopt_get_func_t *)NULL },
201 #endif
202   { "ignoreeof", '\0', &ignoreeof, set_ignoreeof, (setopt_get_func_t *)NULL },
203   { "interactive-comments", '\0', &interactive_comments, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
204   { "keyword",    'k', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
205   { "monitor",    'm', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
206   { "noclobber",  'C', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
207   { "noexec",     'n', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
208   { "noglob",     'f', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
209 #if defined (HISTORY)
210   { "nolog",     '\0', &dont_save_function_defs, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
211 #endif
212 #if defined (JOB_CONTROL)
213   { "notify",     'b', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
214 #endif /* JOB_CONTROL */
215   { "nounset",    'u', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
216   { "onecmd",     't', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
217   { "physical",   'P', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
218   { "pipefail",  '\0', &pipefail_opt, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
219   { "posix",     '\0', &posixly_correct, set_posix_mode, (setopt_get_func_t *)NULL },
220   { "privileged", 'p', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
221   { "verbose",    'v', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
222 #if defined (READLINE)
223   { "vi",        '\0', (int *)NULL, set_edit_mode, get_edit_mode },
224 #endif
225   { "xtrace",     'x', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
226   {(char *)NULL, 0 , (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
227 };
228
229 #define N_O_OPTIONS     (sizeof (o_options) / sizeof (o_options[0]))
230
231 #define GET_BINARY_O_OPTION_VALUE(i, name) \
232   ((o_options[i].get_func) ? (*o_options[i].get_func) (name) \
233                            : (*o_options[i].variable))
234
235 #define SET_BINARY_O_OPTION_VALUE(i, onoff, name) \
236   ((o_options[i].set_func) ? (*o_options[i].set_func) (onoff, name) \
237                            : (*o_options[i].variable = (onoff == FLAG_ON)))
238
239 int
240 minus_o_option_value (name)
241      char *name;
242 {
243   register int  i;
244   int *on_or_off;
245
246   for (i = 0; o_options[i].name; i++)
247     {
248       if (STREQ (name, o_options[i].name))
249         {
250           if (o_options[i].letter)
251             {
252               on_or_off = find_flag (o_options[i].letter);
253               return ((on_or_off == FLAG_UNKNOWN) ? -1 : *on_or_off);
254             }
255           else
256             return (GET_BINARY_O_OPTION_VALUE (i, name));
257         }
258     }
259
260   return (-1);
261 }
262
263 #define MINUS_O_FORMAT "%-15s\t%s\n"
264
265 static void
266 print_minus_o_option (name, value, pflag)
267      char *name;
268      int value, pflag;
269 {
270   if (pflag == 0)
271     printf (MINUS_O_FORMAT, name, value ? on : off);
272   else
273     printf ("set %co %s\n", value ? '-' : '+', name);
274 }
275
276 void
277 list_minus_o_opts (mode, reusable)
278      int mode, reusable;
279 {
280   register int  i;
281   int *on_or_off, value;
282
283   for (i = 0; o_options[i].name; i++)
284     {
285       if (o_options[i].letter)
286         {
287           value = 0;
288           on_or_off = find_flag (o_options[i].letter);
289           if (on_or_off == FLAG_UNKNOWN)
290             on_or_off = &value;
291           if (mode == -1 || mode == *on_or_off)
292             print_minus_o_option (o_options[i].name, *on_or_off, reusable);
293         }
294       else
295         {
296           value = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
297           if (mode == -1 || mode == value)
298             print_minus_o_option (o_options[i].name, value, reusable);
299         }
300     }
301 }
302
303 char **
304 get_minus_o_opts ()
305 {
306   char **ret;
307   int i;
308
309   ret = strvec_create (N_O_OPTIONS + 1);
310   for (i = 0; o_options[i].name; i++)
311     ret[i] = o_options[i].name;
312   ret[i] = (char *)NULL;
313   return ret;
314 }
315
316 static int
317 set_ignoreeof (on_or_off, option_name)
318      int on_or_off;
319      char *option_name;
320 {
321   ignoreeof = on_or_off == FLAG_ON;
322   unbind_variable ("ignoreeof");
323   if (ignoreeof)
324     bind_variable ("IGNOREEOF", "10", 0); 
325   else
326     unbind_variable ("IGNOREEOF");
327   sv_ignoreeof ("IGNOREEOF");
328   return 0;
329 }
330
331 static int
332 set_posix_mode (on_or_off, option_name)
333      int on_or_off;
334      char *option_name;
335 {
336   posixly_correct = on_or_off == FLAG_ON;
337   if (posixly_correct == 0)
338     unbind_variable ("POSIXLY_CORRECT");
339   else
340     bind_variable ("POSIXLY_CORRECT", "y", 0);
341   sv_strict_posix ("POSIXLY_CORRECT");
342   return (0);
343 }
344
345 #if defined (READLINE)
346 /* Magic.  This code `knows' how readline handles rl_editing_mode. */
347 static int
348 set_edit_mode (on_or_off, option_name)
349      int on_or_off;
350      char *option_name;
351 {
352   int isemacs;
353
354   if (on_or_off == FLAG_ON)
355     {
356       rl_variable_bind ("editing-mode", option_name);
357
358       if (interactive)
359         with_input_from_stdin ();
360       no_line_editing = 0;
361     }
362   else
363     {
364       isemacs = rl_editing_mode == 1;
365       if ((isemacs && *option_name == 'e') || (!isemacs && *option_name == 'v'))
366         {
367           if (interactive)
368             with_input_from_stream (stdin, "stdin");
369           no_line_editing = 1;
370         }
371     }
372   return 1-no_line_editing;
373 }
374
375 static int
376 get_edit_mode (name)
377      char *name;
378 {
379   return (*name == 'e' ? no_line_editing == 0 && rl_editing_mode == 1
380                        : no_line_editing == 0 && rl_editing_mode == 0);
381 }
382 #endif /* READLINE */
383
384 #if defined (HISTORY)
385 static int
386 bash_set_history (on_or_off, option_name)
387      int on_or_off;
388      char *option_name;
389 {
390   if (on_or_off == FLAG_ON)
391     {
392       enable_history_list = 1;
393       bash_history_enable ();
394       if (history_lines_this_session == 0)
395         load_history ();
396     }
397   else
398     {
399       enable_history_list = 0;
400       bash_history_disable ();
401     }
402   return (1 - enable_history_list);
403 }
404 #endif
405
406 int
407 set_minus_o_option (on_or_off, option_name)
408      int on_or_off;
409      char *option_name;
410 {
411   register int i;
412
413   for (i = 0; o_options[i].name; i++)
414     {
415       if (STREQ (option_name, o_options[i].name))
416         {
417           if (o_options[i].letter == 0)
418             {
419               SET_BINARY_O_OPTION_VALUE (i, on_or_off, option_name);
420               return (EXECUTION_SUCCESS);
421             }
422           else
423             {
424               if (change_flag (o_options[i].letter, on_or_off) == FLAG_ERROR)
425                 {
426                   sh_invalidoptname (option_name);
427                   return (EXECUTION_FAILURE);
428                 }
429               else
430                 return (EXECUTION_SUCCESS);
431             }
432
433         }
434     }
435
436   sh_invalidoptname (option_name);
437   return (EX_USAGE);
438 }
439
440 static void
441 print_all_shell_variables ()
442 {
443   SHELL_VAR **vars;
444
445   vars = all_shell_variables ();
446   if (vars)
447     {
448       print_var_list (vars);
449       free (vars);
450     }
451
452   /* POSIX.2 does not allow function names and definitions to be output when
453      `set' is invoked without options (PASC Interp #202). */
454   if (posixly_correct == 0)
455     {
456       vars = all_shell_functions ();
457       if (vars)
458         {
459           print_func_list (vars);
460           free (vars);
461         }
462     }
463 }
464
465 void
466 set_shellopts ()
467 {
468   char *value;
469   char tflag[N_O_OPTIONS];
470   int vsize, i, vptr, *ip, exported;
471   SHELL_VAR *v;
472
473   for (vsize = i = 0; o_options[i].name; i++)
474     {
475       tflag[i] = 0;
476       if (o_options[i].letter)
477         {
478           ip = find_flag (o_options[i].letter);
479           if (ip && *ip)
480             {
481               vsize += strlen (o_options[i].name) + 1;
482               tflag[i] = 1;
483             }
484         }
485       else if (GET_BINARY_O_OPTION_VALUE (i, o_options[i].name))
486         {
487           vsize += strlen (o_options[i].name) + 1;
488           tflag[i] = 1;
489         }
490     }
491
492   value = (char *)xmalloc (vsize + 1);
493
494   for (i = vptr = 0; o_options[i].name; i++)
495     {
496       if (tflag[i])
497         {
498           strcpy (value + vptr, o_options[i].name);
499           vptr += strlen (o_options[i].name);
500           value[vptr++] = ':';
501         }
502     }
503
504   if (vptr)
505     vptr--;                     /* cut off trailing colon */
506   value[vptr] = '\0';
507
508   v = find_variable ("SHELLOPTS");
509
510   /* Turn off the read-only attribute so we can bind the new value, and
511      note whether or not the variable was exported. */
512   if (v)
513     {
514       VUNSETATTR (v, att_readonly);
515       exported = exported_p (v);
516     }
517   else
518     exported = 0;
519
520   v = bind_variable ("SHELLOPTS", value, 0);
521
522   /* Turn the read-only attribute back on, and turn off the export attribute
523      if it was set implicitly by mark_modified_vars and SHELLOPTS was not
524      exported before we bound the new value. */
525   VSETATTR (v, att_readonly);
526   if (mark_modified_vars && exported == 0 && exported_p (v))
527     VUNSETATTR (v, att_exported);
528
529   free (value);
530 }
531
532 void
533 parse_shellopts (value)
534      char *value;
535 {
536   char *vname;
537   int vptr;
538
539   vptr = 0;
540   while (vname = extract_colon_unit (value, &vptr))
541     {
542       set_minus_o_option (FLAG_ON, vname);
543       free (vname);
544     }
545 }
546
547 void
548 initialize_shell_options (no_shellopts)
549      int no_shellopts;
550 {
551   char *temp;
552   SHELL_VAR *var;
553
554   if (no_shellopts == 0)
555     {
556       var = find_variable ("SHELLOPTS");
557       /* set up any shell options we may have inherited. */
558       if (var && imported_p (var))
559         {
560           temp = (array_p (var) || assoc_p (var)) ? (char *)NULL : savestring (value_cell (var));
561           if (temp)
562             {
563               parse_shellopts (temp);
564               free (temp);
565             }
566         }
567     }
568
569   /* Set up the $SHELLOPTS variable. */
570   set_shellopts ();
571 }
572
573 /* Reset the values of the -o options that are not also shell flags.  This is
574    called from execute_cmd.c:initialize_subshell() when setting up a subshell
575    to run an executable shell script without a leading `#!'. */
576 void
577 reset_shell_options ()
578 {
579 #if defined (HISTORY)
580   remember_on_history = enable_history_list = 1;
581 #endif
582   ignoreeof = 0;
583 }
584
585 /* Set some flags from the word values in the input list.  If LIST is empty,
586    then print out the values of the variables instead.  If LIST contains
587    non-flags, then set $1 - $9 to the successive words of LIST. */
588 int
589 set_builtin (list)
590      WORD_LIST *list;
591 {
592   int on_or_off, flag_name, force_assignment, opts_changed, rv, r;
593   register char *arg;
594   char s[3];
595
596   if (list == 0)
597     {
598       print_all_shell_variables ();
599       return (sh_chkwrite (EXECUTION_SUCCESS));
600     }
601
602   /* Check validity of flag arguments. */
603   rv = EXECUTION_SUCCESS;
604   reset_internal_getopt ();
605   while ((flag_name = internal_getopt (list, optflags)) != -1)
606     {
607       switch (flag_name)
608         {
609           case '?':
610             builtin_usage ();
611             return (list_optopt == '?' ? EXECUTION_SUCCESS : EX_USAGE);
612           default:
613             break;
614         }
615     }
616     
617   /* Do the set command.  While the list consists of words starting with
618      '-' or '+' treat them as flags, otherwise, start assigning them to
619      $1 ... $n. */
620   for (force_assignment = opts_changed = 0; list; )
621     {
622       arg = list->word->word;
623
624       /* If the argument is `--' or `-' then signal the end of the list
625          and remember the remaining arguments. */
626       if (arg[0] == '-' && (!arg[1] || (arg[1] == '-' && !arg[2])))
627         {
628           list = list->next;
629
630           /* `set --' unsets the positional parameters. */
631           if (arg[1] == '-')
632             force_assignment = 1;
633
634           /* Until told differently, the old shell behaviour of
635              `set - [arg ...]' being equivalent to `set +xv [arg ...]'
636              stands.  Posix.2 says the behaviour is marked as obsolescent. */
637           else
638             {
639               change_flag ('x', '+');
640               change_flag ('v', '+');
641               opts_changed = 1;
642             }
643
644           break;
645         }
646
647       if ((on_or_off = *arg) && (on_or_off == '-' || on_or_off == '+'))
648         {
649           while (flag_name = *++arg)
650             {
651               if (flag_name == '?')
652                 {
653                   builtin_usage ();
654                   return (EXECUTION_SUCCESS);
655                 }
656               else if (flag_name == 'o') /* -+o option-name */
657                 {
658                   char *option_name;
659                   WORD_LIST *opt;
660
661                   opt = list->next;
662
663                   if (opt == 0)
664                     {
665                       list_minus_o_opts (-1, (on_or_off == '+'));
666                       rv = sh_chkwrite (rv);
667                       continue;
668                     }
669
670                   option_name = opt->word->word;
671
672                   if (option_name == 0 || *option_name == '\0' ||
673                       *option_name == '-' || *option_name == '+')
674                     {
675                       list_minus_o_opts (-1, (on_or_off == '+'));
676                       continue;
677                     }
678                   list = list->next; /* Skip over option name. */
679
680                   opts_changed = 1;
681                   if ((r = set_minus_o_option (on_or_off, option_name)) != EXECUTION_SUCCESS)
682                     {
683                       set_shellopts ();
684                       return (r);
685                     }
686                 }
687               else if (change_flag (flag_name, on_or_off) == FLAG_ERROR)
688                 {
689                   s[0] = on_or_off;
690                   s[1] = flag_name;
691                   s[2] = '\0';
692                   sh_invalidopt (s);
693                   builtin_usage ();
694                   set_shellopts ();
695                   return (EXECUTION_FAILURE);
696                 }
697               opts_changed = 1;
698             }
699         }
700       else
701         {
702           break;
703         }
704       list = list->next;
705     }
706
707   /* Assigning $1 ... $n */
708   if (list || force_assignment)
709     remember_args (list, 1);
710   /* Set up new value of $SHELLOPTS */
711   if (opts_changed)
712     set_shellopts ();
713   return (rv);
714 }
715
716 $BUILTIN unset
717 $FUNCTION unset_builtin
718 $SHORT_DOC unset [-f] [-v] [name ...]
719 Unset values and attributes of shell variables and functions.
720
721 For each NAME, remove the corresponding variable or function.
722
723 Options:
724   -f    treat each NAME as a shell function
725   -v    treat each NAME as a shell variable
726
727 Without options, unset first tries to unset a variable, and if that fails,
728 tries to unset a function.
729
730 Some variables cannot be unset; also see `readonly'.
731
732 Exit Status:
733 Returns success unless an invalid option is given or a NAME is read-only.
734 $END
735
736 #define NEXT_VARIABLE() any_failed++; list = list->next; continue;
737
738 int
739 unset_builtin (list)
740   WORD_LIST *list;
741 {
742   int unset_function, unset_variable, unset_array, opt, any_failed;
743   char *name;
744
745   unset_function = unset_variable = unset_array = any_failed = 0;
746
747   reset_internal_getopt ();
748   while ((opt = internal_getopt (list, "fv")) != -1)
749     {
750       switch (opt)
751         {
752         case 'f':
753           unset_function = 1;
754           break;
755         case 'v':
756           unset_variable = 1;
757           break;
758         default:
759           builtin_usage ();
760           return (EX_USAGE);
761         }
762     }
763
764   list = loptend;
765
766   if (unset_function && unset_variable)
767     {
768       builtin_error (_("cannot simultaneously unset a function and a variable"));
769       return (EXECUTION_FAILURE);
770     }
771
772   while (list)
773     {
774       SHELL_VAR *var;
775       int tem;
776 #if defined (ARRAY_VARS)
777       char *t;
778 #endif
779
780       name = list->word->word;
781
782 #if defined (ARRAY_VARS)
783       unset_array = 0;
784       if (!unset_function && valid_array_reference (name))
785         {
786           t = strchr (name, '[');
787           *t++ = '\0';
788           unset_array++;
789         }
790 #endif
791
792       /* Bash allows functions with names which are not valid identifiers
793          to be created when not in posix mode, so check only when in posix
794          mode when unsetting a function. */
795       if (((unset_function && posixly_correct) || !unset_function) && legal_identifier (name) == 0)
796         {
797           sh_invalidid (name);
798           NEXT_VARIABLE ();
799         }
800
801       var = unset_function ? find_function (name) : find_variable (name);
802
803       if (var && !unset_function && non_unsettable_p (var))
804         {
805           builtin_error (_("%s: cannot unset"), name);
806           NEXT_VARIABLE ();
807         }
808
809       /* Posix.2 says that unsetting readonly variables is an error. */
810       if (var && readonly_p (var))
811         {
812           builtin_error (_("%s: cannot unset: readonly %s"),
813                          name, unset_function ? "function" : "variable");
814           NEXT_VARIABLE ();
815         }
816
817       /* Unless the -f option is supplied, the name refers to a variable. */
818 #if defined (ARRAY_VARS)
819       if (var && unset_array)
820         {
821           if (array_p (var) == 0 && assoc_p (var) == 0)
822             {
823               builtin_error (_("%s: not an array variable"), name);
824               NEXT_VARIABLE ();
825             }
826           else
827             {
828               tem = unbind_array_element (var, t);
829               if (tem == -1)
830                 any_failed++;
831             }
832         }
833       else
834 #endif /* ARRAY_VARS */
835       tem = unset_function ? unbind_func (name) : unbind_variable (name);
836
837       /* This is what Posix.2 draft 11+ says.  ``If neither -f nor -v
838          is specified, the name refers to a variable; if a variable by
839          that name does not exist, a function by that name, if any,
840          shall be unset.'' */
841       if (tem == -1 && !unset_function && !unset_variable)
842         tem = unbind_func (name);
843
844       /* SUSv3, POSIX.1-2001 say:  ``Unsetting a variable or function that
845          was not previously set shall not be considered an error.'' */
846
847       if (unset_function == 0)
848         stupidly_hack_special_variables (name);
849
850       list = list->next;
851     }
852
853   return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
854 }