Imported from ../bash-3.2.48.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', &enable_history_list, 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       enable_history_list = 1;
385       bash_history_enable ();
386       if (history_lines_this_session == 0)
387         load_history ();
388     }
389   else
390     {
391       enable_history_list = 0;
392       bash_history_disable ();
393     }
394   return (1 - enable_history_list);
395 }
396 #endif
397
398 int
399 set_minus_o_option (on_or_off, option_name)
400      int on_or_off;
401      char *option_name;
402 {
403   register int i;
404
405   for (i = 0; o_options[i].name; i++)
406     {
407       if (STREQ (option_name, o_options[i].name))
408         {
409           if (o_options[i].letter == 0)
410             {
411               SET_BINARY_O_OPTION_VALUE (i, on_or_off, option_name);
412               return (EXECUTION_SUCCESS);
413             }
414           else
415             {
416               if (change_flag (o_options[i].letter, on_or_off) == FLAG_ERROR)
417                 {
418                   sh_invalidoptname (option_name);
419                   return (EXECUTION_FAILURE);
420                 }
421               else
422                 return (EXECUTION_SUCCESS);
423             }
424
425         }
426     }
427
428   sh_invalidoptname (option_name);
429   return (EXECUTION_FAILURE);
430 }
431
432 static void
433 print_all_shell_variables ()
434 {
435   SHELL_VAR **vars;
436
437   vars = all_shell_variables ();
438   if (vars)
439     {
440       print_var_list (vars);
441       free (vars);
442     }
443
444   /* POSIX.2 does not allow function names and definitions to be output when
445      `set' is invoked without options (PASC Interp #202). */
446   if (posixly_correct == 0)
447     {
448       vars = all_shell_functions ();
449       if (vars)
450         {
451           print_func_list (vars);
452           free (vars);
453         }
454     }
455 }
456
457 void
458 set_shellopts ()
459 {
460   char *value;
461   char tflag[N_O_OPTIONS];
462   int vsize, i, vptr, *ip, exported;
463   SHELL_VAR *v;
464
465   for (vsize = i = 0; o_options[i].name; i++)
466     {
467       tflag[i] = 0;
468       if (o_options[i].letter)
469         {
470           ip = find_flag (o_options[i].letter);
471           if (ip && *ip)
472             {
473               vsize += strlen (o_options[i].name) + 1;
474               tflag[i] = 1;
475             }
476         }
477       else if (GET_BINARY_O_OPTION_VALUE (i, o_options[i].name))
478         {
479           vsize += strlen (o_options[i].name) + 1;
480           tflag[i] = 1;
481         }
482     }
483
484   value = (char *)xmalloc (vsize + 1);
485
486   for (i = vptr = 0; o_options[i].name; i++)
487     {
488       if (tflag[i])
489         {
490           strcpy (value + vptr, o_options[i].name);
491           vptr += strlen (o_options[i].name);
492           value[vptr++] = ':';
493         }
494     }
495
496   if (vptr)
497     vptr--;                     /* cut off trailing colon */
498   value[vptr] = '\0';
499
500   v = find_variable ("SHELLOPTS");
501
502   /* Turn off the read-only attribute so we can bind the new value, and
503      note whether or not the variable was exported. */
504   if (v)
505     {
506       VUNSETATTR (v, att_readonly);
507       exported = exported_p (v);
508     }
509   else
510     exported = 0;
511
512   v = bind_variable ("SHELLOPTS", value, 0);
513
514   /* Turn the read-only attribute back on, and turn off the export attribute
515      if it was set implicitly by mark_modified_vars and SHELLOPTS was not
516      exported before we bound the new value. */
517   VSETATTR (v, att_readonly);
518   if (mark_modified_vars && exported == 0 && exported_p (v))
519     VUNSETATTR (v, att_exported);
520
521   free (value);
522 }
523
524 void
525 parse_shellopts (value)
526      char *value;
527 {
528   char *vname;
529   int vptr;
530
531   vptr = 0;
532   while (vname = extract_colon_unit (value, &vptr))
533     {
534       set_minus_o_option (FLAG_ON, vname);
535       free (vname);
536     }
537 }
538
539 void
540 initialize_shell_options (no_shellopts)
541      int no_shellopts;
542 {
543   char *temp;
544   SHELL_VAR *var;
545
546   if (no_shellopts == 0)
547     {
548       var = find_variable ("SHELLOPTS");
549       /* set up any shell options we may have inherited. */
550       if (var && imported_p (var))
551         {
552           temp = (array_p (var)) ? (char *)NULL : savestring (value_cell (var));
553           if (temp)
554             {
555               parse_shellopts (temp);
556               free (temp);
557             }
558         }
559     }
560
561   /* Set up the $SHELLOPTS variable. */
562   set_shellopts ();
563 }
564
565 /* Reset the values of the -o options that are not also shell flags.  This is
566    called from execute_cmd.c:initialize_subshell() when setting up a subshell
567    to run an executable shell script without a leading `#!'. */
568 void
569 reset_shell_options ()
570 {
571 #if defined (HISTORY)
572   remember_on_history = enable_history_list = 1;
573 #endif
574   ignoreeof = 0;
575 }
576
577 /* Set some flags from the word values in the input list.  If LIST is empty,
578    then print out the values of the variables instead.  If LIST contains
579    non-flags, then set $1 - $9 to the successive words of LIST. */
580 int
581 set_builtin (list)
582      WORD_LIST *list;
583 {
584   int on_or_off, flag_name, force_assignment, opts_changed;
585   register char *arg;
586   char s[3];
587
588   if (list == 0)
589     {
590       print_all_shell_variables ();
591       return (EXECUTION_SUCCESS);
592     }
593
594   /* Check validity of flag arguments. */
595   reset_internal_getopt ();
596   while ((flag_name = internal_getopt (list, optflags)) != -1)
597     {
598       switch (flag_name)
599         {
600           case '?':
601             builtin_usage ();
602             return (list_optopt == '?' ? EXECUTION_SUCCESS : EX_USAGE);
603           default:
604             break;
605         }
606     }
607     
608   /* Do the set command.  While the list consists of words starting with
609      '-' or '+' treat them as flags, otherwise, start assigning them to
610      $1 ... $n. */
611   for (force_assignment = opts_changed = 0; list; )
612     {
613       arg = list->word->word;
614
615       /* If the argument is `--' or `-' then signal the end of the list
616          and remember the remaining arguments. */
617       if (arg[0] == '-' && (!arg[1] || (arg[1] == '-' && !arg[2])))
618         {
619           list = list->next;
620
621           /* `set --' unsets the positional parameters. */
622           if (arg[1] == '-')
623             force_assignment = 1;
624
625           /* Until told differently, the old shell behaviour of
626              `set - [arg ...]' being equivalent to `set +xv [arg ...]'
627              stands.  Posix.2 says the behaviour is marked as obsolescent. */
628           else
629             {
630               change_flag ('x', '+');
631               change_flag ('v', '+');
632               opts_changed = 1;
633             }
634
635           break;
636         }
637
638       if ((on_or_off = *arg) && (on_or_off == '-' || on_or_off == '+'))
639         {
640           while (flag_name = *++arg)
641             {
642               if (flag_name == '?')
643                 {
644                   builtin_usage ();
645                   return (EXECUTION_SUCCESS);
646                 }
647               else if (flag_name == 'o') /* -+o option-name */
648                 {
649                   char *option_name;
650                   WORD_LIST *opt;
651
652                   opt = list->next;
653
654                   if (opt == 0)
655                     {
656                       list_minus_o_opts (-1, (on_or_off == '+'));
657                       continue;
658                     }
659
660                   option_name = opt->word->word;
661
662                   if (option_name == 0 || *option_name == '\0' ||
663                       *option_name == '-' || *option_name == '+')
664                     {
665                       list_minus_o_opts (-1, (on_or_off == '+'));
666                       continue;
667                     }
668                   list = list->next; /* Skip over option name. */
669
670                   opts_changed = 1;
671                   if (set_minus_o_option (on_or_off, option_name) != EXECUTION_SUCCESS)
672                     {
673                       set_shellopts ();
674                       return (EXECUTION_FAILURE);
675                     }
676                 }
677               else if (change_flag (flag_name, on_or_off) == FLAG_ERROR)
678                 {
679                   s[0] = on_or_off;
680                   s[1] = flag_name;
681                   s[2] = '\0';
682                   sh_invalidopt (s);
683                   builtin_usage ();
684                   set_shellopts ();
685                   return (EXECUTION_FAILURE);
686                 }
687               opts_changed = 1;
688             }
689         }
690       else
691         {
692           break;
693         }
694       list = list->next;
695     }
696
697   /* Assigning $1 ... $n */
698   if (list || force_assignment)
699     remember_args (list, 1);
700   /* Set up new value of $SHELLOPTS */
701   if (opts_changed)
702     set_shellopts ();
703   return (EXECUTION_SUCCESS);
704 }
705
706 $BUILTIN unset
707 $FUNCTION unset_builtin
708 $SHORT_DOC unset [-f] [-v] [name ...]
709 For each NAME, remove the corresponding variable or function.  Given
710 the `-v', unset will only act on variables.  Given the `-f' flag,
711 unset will only act on functions.  With neither flag, unset first
712 tries to unset a variable, and if that fails, then tries to unset a
713 function.  Some variables cannot be unset; also see readonly.
714 $END
715
716 #define NEXT_VARIABLE() any_failed++; list = list->next; continue;
717
718 int
719 unset_builtin (list)
720   WORD_LIST *list;
721 {
722   int unset_function, unset_variable, unset_array, opt, any_failed;
723   char *name;
724
725   unset_function = unset_variable = unset_array = any_failed = 0;
726
727   reset_internal_getopt ();
728   while ((opt = internal_getopt (list, "fv")) != -1)
729     {
730       switch (opt)
731         {
732         case 'f':
733           unset_function = 1;
734           break;
735         case 'v':
736           unset_variable = 1;
737           break;
738         default:
739           builtin_usage ();
740           return (EX_USAGE);
741         }
742     }
743
744   list = loptend;
745
746   if (unset_function && unset_variable)
747     {
748       builtin_error (_("cannot simultaneously unset a function and a variable"));
749       return (EXECUTION_FAILURE);
750     }
751
752   while (list)
753     {
754       SHELL_VAR *var;
755       int tem;
756 #if defined (ARRAY_VARS)
757       char *t;
758 #endif
759
760       name = list->word->word;
761
762 #if defined (ARRAY_VARS)
763       unset_array = 0;
764       if (!unset_function && valid_array_reference (name))
765         {
766           t = strchr (name, '[');
767           *t++ = '\0';
768           unset_array++;
769         }
770 #endif
771
772       /* Bash allows functions with names which are not valid identifiers
773          to be created when not in posix mode, so check only when in posix
774          mode when unsetting a function. */
775       if (((unset_function && posixly_correct) || !unset_function) && legal_identifier (name) == 0)
776         {
777           sh_invalidid (name);
778           NEXT_VARIABLE ();
779         }
780
781       var = unset_function ? find_function (name) : find_variable (name);
782
783       if (var && !unset_function && non_unsettable_p (var))
784         {
785           builtin_error (_("%s: cannot unset"), name);
786           NEXT_VARIABLE ();
787         }
788
789       /* Posix.2 says that unsetting readonly variables is an error. */
790       if (var && readonly_p (var))
791         {
792           builtin_error (_("%s: cannot unset: readonly %s"),
793                          name, unset_function ? "function" : "variable");
794           NEXT_VARIABLE ();
795         }
796
797       /* Unless the -f option is supplied, the name refers to a variable. */
798 #if defined (ARRAY_VARS)
799       if (var && unset_array)
800         {
801           if (array_p (var) == 0)
802             {
803               builtin_error (_("%s: not an array variable"), name);
804               NEXT_VARIABLE ();
805             }
806           else
807             {
808               tem = unbind_array_element (var, t);
809               if (tem == -1)
810                 any_failed++;
811             }
812         }
813       else
814 #endif /* ARRAY_VARS */
815       tem = unset_function ? unbind_func (name) : unbind_variable (name);
816
817       /* This is what Posix.2 draft 11+ says.  ``If neither -f nor -v
818          is specified, the name refers to a variable; if a variable by
819          that name does not exist, a function by that name, if any,
820          shall be unset.'' */
821       if (tem == -1 && !unset_function && !unset_variable)
822         tem = unbind_func (name);
823
824       /* SUSv3, POSIX.1-2001 say:  ``Unsetting a variable or function that
825          was not previously set shall not be considered an error.'' */
826
827       if (unset_function == 0)
828         stupidly_hack_special_variables (name);
829
830       list = list->next;
831     }
832
833   return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
834 }