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