d1086695a3d89171ccae84852ea464e9281f3d08
[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   register char *arg;
582   char s[3];
583
584   if (list == 0)
585     {
586       print_all_shell_variables ();
587       return (EXECUTION_SUCCESS);
588     }
589
590   /* Check validity of flag arguments. */
591   reset_internal_getopt ();
592   while ((flag_name = internal_getopt (list, optflags)) != -1)
593     {
594       switch (flag_name)
595         {
596           case '?':
597             builtin_usage ();
598             return (list_optopt == '?' ? EXECUTION_SUCCESS : EX_USAGE);
599           default:
600             break;
601         }
602     }
603     
604   /* Do the set command.  While the list consists of words starting with
605      '-' or '+' treat them as flags, otherwise, start assigning them to
606      $1 ... $n. */
607   for (force_assignment = opts_changed = 0; list; )
608     {
609       arg = list->word->word;
610
611       /* If the argument is `--' or `-' then signal the end of the list
612          and remember the remaining arguments. */
613       if (arg[0] == '-' && (!arg[1] || (arg[1] == '-' && !arg[2])))
614         {
615           list = list->next;
616
617           /* `set --' unsets the positional parameters. */
618           if (arg[1] == '-')
619             force_assignment = 1;
620
621           /* Until told differently, the old shell behaviour of
622              `set - [arg ...]' being equivalent to `set +xv [arg ...]'
623              stands.  Posix.2 says the behaviour is marked as obsolescent. */
624           else
625             {
626               change_flag ('x', '+');
627               change_flag ('v', '+');
628               opts_changed = 1;
629             }
630
631           break;
632         }
633
634       if ((on_or_off = *arg) && (on_or_off == '-' || on_or_off == '+'))
635         {
636           while (flag_name = *++arg)
637             {
638               if (flag_name == '?')
639                 {
640                   builtin_usage ();
641                   return (EXECUTION_SUCCESS);
642                 }
643               else if (flag_name == 'o') /* -+o option-name */
644                 {
645                   char *option_name;
646                   WORD_LIST *opt;
647
648                   opt = list->next;
649
650                   if (opt == 0)
651                     {
652                       list_minus_o_opts (-1, (on_or_off == '+'));
653                       continue;
654                     }
655
656                   option_name = opt->word->word;
657
658                   if (option_name == 0 || *option_name == '\0' ||
659                       *option_name == '-' || *option_name == '+')
660                     {
661                       list_minus_o_opts (-1, (on_or_off == '+'));
662                       continue;
663                     }
664                   list = list->next; /* Skip over option name. */
665
666                   opts_changed = 1;
667                   if (set_minus_o_option (on_or_off, option_name) != EXECUTION_SUCCESS)
668                     {
669                       set_shellopts ();
670                       return (EXECUTION_FAILURE);
671                     }
672                 }
673               else if (change_flag (flag_name, on_or_off) == FLAG_ERROR)
674                 {
675                   s[0] = on_or_off;
676                   s[1] = flag_name;
677                   s[2] = '\0';
678                   sh_invalidopt (s);
679                   builtin_usage ();
680                   set_shellopts ();
681                   return (EXECUTION_FAILURE);
682                 }
683               opts_changed = 1;
684             }
685         }
686       else
687         {
688           break;
689         }
690       list = list->next;
691     }
692
693   /* Assigning $1 ... $n */
694   if (list || force_assignment)
695     remember_args (list, 1);
696   /* Set up new value of $SHELLOPTS */
697   if (opts_changed)
698     set_shellopts ();
699   return (EXECUTION_SUCCESS);
700 }
701
702 $BUILTIN unset
703 $FUNCTION unset_builtin
704 $SHORT_DOC unset [-f] [-v] [name ...]
705 For each NAME, remove the corresponding variable or function.  Given
706 the `-v', unset will only act on variables.  Given the `-f' flag,
707 unset will only act on functions.  With neither flag, unset first
708 tries to unset a variable, and if that fails, then tries to unset a
709 function.  Some variables cannot be unset; also see readonly.
710 $END
711
712 #define NEXT_VARIABLE() any_failed++; list = list->next; continue;
713
714 int
715 unset_builtin (list)
716   WORD_LIST *list;
717 {
718   int unset_function, unset_variable, unset_array, opt, any_failed;
719   char *name;
720
721   unset_function = unset_variable = unset_array = any_failed = 0;
722
723   reset_internal_getopt ();
724   while ((opt = internal_getopt (list, "fv")) != -1)
725     {
726       switch (opt)
727         {
728         case 'f':
729           unset_function = 1;
730           break;
731         case 'v':
732           unset_variable = 1;
733           break;
734         default:
735           builtin_usage ();
736           return (EX_USAGE);
737         }
738     }
739
740   list = loptend;
741
742   if (unset_function && unset_variable)
743     {
744       builtin_error (_("cannot simultaneously unset a function and a variable"));
745       return (EXECUTION_FAILURE);
746     }
747
748   while (list)
749     {
750       SHELL_VAR *var;
751       int tem;
752 #if defined (ARRAY_VARS)
753       char *t;
754 #endif
755
756       name = list->word->word;
757
758 #if defined (ARRAY_VARS)
759       unset_array = 0;
760       if (!unset_function && valid_array_reference (name))
761         {
762           t = strchr (name, '[');
763           *t++ = '\0';
764           unset_array++;
765         }
766 #endif
767
768       /* Bash allows functions with names which are not valid identifiers
769          to be created when not in posix mode, so check only when in posix
770          mode when unsetting a function. */
771       if (((unset_function && posixly_correct) || !unset_function) && legal_identifier (name) == 0)
772         {
773           sh_invalidid (name);
774           NEXT_VARIABLE ();
775         }
776
777       var = unset_function ? find_function (name) : find_variable (name);
778
779       if (var && !unset_function && non_unsettable_p (var))
780         {
781           builtin_error (_("%s: cannot unset"), name);
782           NEXT_VARIABLE ();
783         }
784
785       /* Posix.2 says that unsetting readonly variables is an error. */
786       if (var && readonly_p (var))
787         {
788           builtin_error (_("%s: cannot unset: readonly %s"),
789                          name, unset_function ? "function" : "variable");
790           NEXT_VARIABLE ();
791         }
792
793       /* Unless the -f option is supplied, the name refers to a variable. */
794 #if defined (ARRAY_VARS)
795       if (var && unset_array)
796         {
797           if (array_p (var) == 0)
798             {
799               builtin_error (_("%s: not an array variable"), name);
800               NEXT_VARIABLE ();
801             }
802           else
803             {
804               tem = unbind_array_element (var, t);
805               if (tem == -1)
806                 any_failed++;
807             }
808         }
809       else
810 #endif /* ARRAY_VARS */
811       tem = unset_function ? unbind_func (name) : unbind_variable (name);
812
813       /* This is what Posix.2 draft 11+ says.  ``If neither -f nor -v
814          is specified, the name refers to a variable; if a variable by
815          that name does not exist, a function by that name, if any,
816          shall be unset.'' */
817       if (tem == -1 && !unset_function && !unset_variable)
818         tem = unbind_func (name);
819
820       /* SUSv3, POSIX.1-2001 say:  ``Unsetting a variable or function that
821          was not previously set shall not be considered an error.'' */
822
823       if (unset_function == 0)
824         stupidly_hack_special_variables (name);
825
826       list = list->next;
827     }
828
829   return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
830 }