1This file is set.def, from which is created set.c.
2It implements the "set" and "unset" builtins in Bash.
3
4Copyright (C) 1987-2004 Free Software Foundation, Inc.
5
6This file is part of GNU Bash, the Bourne Again SHell.
7
8Bash is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 2, or (at your option) any later
11version.
12
13Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License along
19with Bash; see the file COPYING.  If not, write to the Free Software
20Foundation, 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
53extern int posixly_correct, ignoreeof, eof_encountered_limit;
54#if defined (HISTORY)
55extern int dont_save_function_defs;
56#endif
57#if defined (READLINE)
58extern 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
139Using + rather than - causes these flags to be turned off.  The
140flags can also be used upon invocation of the shell.  The current
141set of flags may be found in $-.  The remaining n ARGs are positional
142parameters and are assigned, in order, to $1, $2, .. $n.  If no
143ARGs are given, all shell variables are printed.
144$END
145
146typedef int setopt_set_func_t __P((int, char *));
147typedef int setopt_get_func_t __P((char *));
148
149static void print_minus_o_option __P((char *, int, int));
150static void print_all_shell_variables __P((void));
151
152static int set_ignoreeof __P((int, char *));
153static int set_posix_mode __P((int, char *));
154
155#if defined (READLINE)
156static int set_edit_mode __P((int, char *));
157static int get_edit_mode __P((char *));
158#endif
159
160#if defined (HISTORY)
161static int bash_set_history __P((int, char *));
162#endif
163
164static char *on = "on";
165static 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. */
170struct {
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
231int
232minus_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
257static void
258print_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
268void
269list_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
295char **
296get_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
308static int
309set_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
323static int
324set_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. */
339static int
340set_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
367static int
368get_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)
377static int
378bash_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
398int
399set_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
432static void
433print_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
457void
458set_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
524void
525parse_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
539void
540initialize_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 `#!'. */
568void
569reset_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. */
580int
581set_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 ...]
709For each NAME, remove the corresponding variable or function.  Given
710the `-v', unset will only act on variables.  Given the `-f' flag,
711unset will only act on functions.  With neither flag, unset first
712tries to unset a variable, and if that fails, then tries to unset a
713function.  Some variables cannot be unset; also see readonly.
714$END
715
716#define NEXT_VARIABLE()	any_failed++; list = list->next; continue;
717
718int
719unset_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}
835