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