From b7fc9e0f6d6105ba2203f219743d4b269415e84b Mon Sep 17 00:00:00 2001
From: An-Cheng Huang <ancheng@vyatta.com>
Date: Mon, 12 Nov 2007 13:06:02 -0800
Subject: initial import from bash_3.1dfsg.orig.tar.gz

---
 builtins/set.def | 831 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 831 insertions(+)
 create mode 100644 builtins/set.def

(limited to 'builtins/set.def')

diff --git a/builtins/set.def b/builtins/set.def
new file mode 100644
index 0000000..3bb3270
--- /dev/null
+++ b/builtins/set.def
@@ -0,0 +1,831 @@
+This file is set.def, from which is created set.c.
+It implements the "set" and "unset" builtins in Bash.
+
+Copyright (C) 1987-2004 Free Software Foundation, Inc.
+
+This file is part of GNU Bash, the Bourne Again SHell.
+
+Bash is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING.  If not, write to the Free Software
+Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
+
+$PRODUCES set.c
+
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+#  ifdef _MINIX
+#    include <sys/types.h>
+#  endif
+#  include <unistd.h>
+#endif
+
+#include <stdio.h>
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "../flags.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+#if defined (READLINE)
+#  include "../input.h"
+#  include "../bashline.h"
+#  include <readline/readline.h>
+#endif
+
+#if defined (HISTORY)
+#  include "../bashhist.h"
+#endif
+
+extern int posixly_correct, ignoreeof, eof_encountered_limit;
+#if defined (HISTORY)
+extern int dont_save_function_defs;
+#endif
+#if defined (READLINE)
+extern int no_line_editing;
+#endif /* READLINE */
+
+$BUILTIN set
+$FUNCTION set_builtin
+$SHORT_DOC set [--abefhkmnptuvxBCHP] [-o option] [arg ...]
+    -a  Mark variables which are modified or created for export.
+    -b  Notify of job termination immediately.
+    -e  Exit immediately if a command exits with a non-zero status.
+    -f  Disable file name generation (globbing).
+    -h  Remember the location of commands as they are looked up.
+    -k  All assignment arguments are placed in the environment for a
+        command, not just those that precede the command name.
+    -m  Job control is enabled.
+    -n  Read commands but do not execute them.
+    -o option-name
+        Set the variable corresponding to option-name:
+            allexport    same as -a
+            braceexpand  same as -B
+#if defined (READLINE)
+            emacs        use an emacs-style line editing interface
+#endif /* READLINE */
+            errexit      same as -e
+            errtrace     same as -E
+            functrace    same as -T
+            hashall      same as -h
+#if defined (BANG_HISTORY)
+            histexpand   same as -H
+#endif /* BANG_HISTORY */
+#if defined (HISTORY)
+            history      enable command history
+#endif
+            ignoreeof    the shell will not exit upon reading EOF
+            interactive-comments
+                         allow comments to appear in interactive commands
+            keyword      same as -k
+            monitor      same as -m
+            noclobber    same as -C
+            noexec       same as -n
+            noglob       same as -f
+            nolog        currently accepted but ignored
+            notify       same as -b
+            nounset      same as -u
+            onecmd       same as -t
+            physical     same as -P
+            pipefail     the return value of a pipeline is the status of
+                         the last command to exit with a non-zero status,
+                         or zero if no command exited with a non-zero status
+            posix        change the behavior of bash where the default
+                         operation differs from the 1003.2 standard to
+                         match the standard
+            privileged   same as -p
+            verbose      same as -v
+#if defined (READLINE)
+            vi           use a vi-style line editing interface
+#endif /* READLINE */
+            xtrace       same as -x
+    -p  Turned on whenever the real and effective user ids do not match.
+        Disables processing of the $ENV file and importing of shell
+        functions.  Turning this option off causes the effective uid and
+        gid to be set to the real uid and gid.
+    -t  Exit after reading and executing one command.
+    -u  Treat unset variables as an error when substituting.
+    -v  Print shell input lines as they are read.
+    -x  Print commands and their arguments as they are executed.
+#if defined (BRACE_EXPANSION)
+    -B  the shell will perform brace expansion
+#endif /* BRACE_EXPANSION */
+    -C  If set, disallow existing regular files to be overwritten
+        by redirection of output.
+    -E  If set, the ERR trap is inherited by shell functions.
+#if defined (BANG_HISTORY)
+    -H  Enable ! style history substitution.  This flag is on
+        by default when the shell is interactive.
+#endif /* BANG_HISTORY */
+    -P  If set, do not follow symbolic links when executing commands
+        such as cd which change the current directory.
+    -T  If set, the DEBUG trap is inherited by shell functions.
+    -   Assign any remaining arguments to the positional parameters.
+        The -x and -v options are turned off.
+
+Using + rather than - causes these flags to be turned off.  The
+flags can also be used upon invocation of the shell.  The current
+set of flags may be found in $-.  The remaining n ARGs are positional
+parameters and are assigned, in order, to $1, $2, .. $n.  If no
+ARGs are given, all shell variables are printed.
+$END
+
+typedef int setopt_set_func_t __P((int, char *));
+typedef int setopt_get_func_t __P((char *));
+
+static void print_minus_o_option __P((char *, int, int));
+static void print_all_shell_variables __P((void));
+
+static int set_ignoreeof __P((int, char *));
+static int set_posix_mode __P((int, char *));
+
+#if defined (READLINE)
+static int set_edit_mode __P((int, char *));
+static int get_edit_mode __P((char *));
+#endif
+
+#if defined (HISTORY)
+static int bash_set_history __P((int, char *));
+#endif
+
+static char *on = "on";
+static char *off = "off";
+
+/* A struct used to match long options for set -o to the corresponding
+   option letter or internal variable.  The functions can be called to
+   dynamically generate values. */
+struct {
+  char *name;
+  int letter;
+  int *variable;
+  setopt_set_func_t *set_func;
+  setopt_get_func_t *get_func;
+} o_options[] = {
+  { "allexport",  'a', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+#if defined (BRACE_EXPANSION)
+  { "braceexpand",'B', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
+#endif
+#if defined (READLINE)
+  { "emacs",     '\0', (int *)NULL, set_edit_mode, get_edit_mode },
+#endif
+  { "errexit",	  'e', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
+  { "errtrace",	  'E', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
+  { "functrace",  'T', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
+  { "hashall",    'h', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
+#if defined (BANG_HISTORY)
+  { "histexpand", 'H', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
+#endif /* BANG_HISTORY */
+#if defined (HISTORY)
+  { "history",   '\0', &remember_on_history, bash_set_history, (setopt_get_func_t *)NULL },
+#endif
+  { "ignoreeof", '\0', &ignoreeof, set_ignoreeof, (setopt_get_func_t *)NULL },
+  { "interactive-comments", '\0', &interactive_comments, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+  { "keyword",    'k', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
+  { "monitor",	  'm', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
+  { "noclobber",  'C', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
+  { "noexec",	  'n', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
+  { "noglob",	  'f', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
+#if defined (HISTORY)
+  { "nolog",     '\0', &dont_save_function_defs, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+#endif
+#if defined (JOB_CONTROL)
+  { "notify",	  'b', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
+#endif /* JOB_CONTROL */
+  { "nounset",	  'u', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
+  { "onecmd",	  't', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+  { "physical",   'P', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
+  { "pipefail",  '\0', &pipefail_opt, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
+  { "posix",     '\0', &posixly_correct, set_posix_mode, (setopt_get_func_t *)NULL },
+  { "privileged", 'p', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
+  { "verbose",	  'v', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
+#if defined (READLINE)
+  { "vi",        '\0', (int *)NULL, set_edit_mode, get_edit_mode },
+#endif
+  { "xtrace",	  'x', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
+  {(char *)NULL, 0 , (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+};
+
+#define N_O_OPTIONS	(sizeof (o_options) / sizeof (o_options[0]))
+
+#define GET_BINARY_O_OPTION_VALUE(i, name) \
+  ((o_options[i].get_func) ? (*o_options[i].get_func) (name) \
+			   : (*o_options[i].variable))
+
+#define SET_BINARY_O_OPTION_VALUE(i, onoff, name) \
+  ((o_options[i].set_func) ? (*o_options[i].set_func) (onoff, name) \
+			   : (*o_options[i].variable = (onoff == FLAG_ON)))
+
+int
+minus_o_option_value (name)
+     char *name;
+{
+  register int	i;
+  int *on_or_off;
+
+  for (i = 0; o_options[i].name; i++)
+    {
+      if (STREQ (name, o_options[i].name))
+	{
+	  if (o_options[i].letter)
+	    {
+	      on_or_off = find_flag (o_options[i].letter);
+	      return ((on_or_off == FLAG_UNKNOWN) ? -1 : *on_or_off);
+	    }
+	  else
+	    return (GET_BINARY_O_OPTION_VALUE (i, name));
+	}
+    }
+
+  return (-1);
+}
+
+#define MINUS_O_FORMAT "%-15s\t%s\n"
+
+static void
+print_minus_o_option (name, value, pflag)
+     char *name;
+     int value, pflag;
+{
+  if (pflag == 0)
+    printf (MINUS_O_FORMAT, name, value ? on : off);
+  else
+    printf ("set %co %s\n", value ? '-' : '+', name);
+}
+
+void
+list_minus_o_opts (mode, reusable)
+     int mode, reusable;
+{
+  register int	i;
+  int *on_or_off, value;
+
+  for (i = 0; o_options[i].name; i++)
+    {
+      if (o_options[i].letter)
+	{
+	  value = 0;
+	  on_or_off = find_flag (o_options[i].letter);
+	  if (on_or_off == FLAG_UNKNOWN)
+	    on_or_off = &value;
+	  if (mode == -1 || mode == *on_or_off)
+	    print_minus_o_option (o_options[i].name, *on_or_off, reusable);
+	}
+      else
+	{
+	  value = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
+	  if (mode == -1 || mode == value)
+	    print_minus_o_option (o_options[i].name, value, reusable);
+	}
+    }
+}
+
+char **
+get_minus_o_opts ()
+{
+  char **ret;
+  int i;
+
+  ret = strvec_create (N_O_OPTIONS + 1);
+  for (i = 0; o_options[i].name; i++)
+    ret[i] = o_options[i].name;
+  ret[i] = (char *)NULL;
+  return ret;
+}
+
+static int
+set_ignoreeof (on_or_off, option_name)
+     int on_or_off;
+     char *option_name;
+{
+  ignoreeof = on_or_off == FLAG_ON;
+  unbind_variable ("ignoreeof");
+  if (ignoreeof)
+    bind_variable ("IGNOREEOF", "10", 0); 
+  else
+    unbind_variable ("IGNOREEOF");
+  sv_ignoreeof ("IGNOREEOF");
+  return 0;
+}
+
+static int
+set_posix_mode (on_or_off, option_name)
+     int on_or_off;
+     char *option_name;
+{
+  posixly_correct = on_or_off == FLAG_ON;
+  if (posixly_correct == 0)
+    unbind_variable ("POSIXLY_CORRECT");
+  else
+    bind_variable ("POSIXLY_CORRECT", "y", 0);
+  sv_strict_posix ("POSIXLY_CORRECT");
+  return (0);
+}
+
+#if defined (READLINE)
+/* Magic.  This code `knows' how readline handles rl_editing_mode. */
+static int
+set_edit_mode (on_or_off, option_name)
+     int on_or_off;
+     char *option_name;
+{
+  int isemacs;
+
+  if (on_or_off == FLAG_ON)
+    {
+      rl_variable_bind ("editing-mode", option_name);
+
+      if (interactive)
+	with_input_from_stdin ();
+      no_line_editing = 0;
+    }
+  else
+    {
+      isemacs = rl_editing_mode == 1;
+      if ((isemacs && *option_name == 'e') || (!isemacs && *option_name == 'v'))
+	{
+	  if (interactive)
+	    with_input_from_stream (stdin, "stdin");
+	  no_line_editing = 1;
+	}
+    }
+  return 1-no_line_editing;
+}
+
+static int
+get_edit_mode (name)
+     char *name;
+{
+  return (*name == 'e' ? no_line_editing == 0 && rl_editing_mode == 1
+		       : no_line_editing == 0 && rl_editing_mode == 0);
+}
+#endif /* READLINE */
+
+#if defined (HISTORY)
+static int
+bash_set_history (on_or_off, option_name)
+     int on_or_off;
+     char *option_name;
+{
+  if (on_or_off == FLAG_ON)
+    {
+      bash_history_enable ();
+      if (history_lines_this_session == 0)
+	load_history ();
+    }
+  else
+    bash_history_disable ();
+  return (1 - remember_on_history);
+}
+#endif
+
+int
+set_minus_o_option (on_or_off, option_name)
+     int on_or_off;
+     char *option_name;
+{
+  register int i;
+
+  for (i = 0; o_options[i].name; i++)
+    {
+      if (STREQ (option_name, o_options[i].name))
+	{
+	  if (o_options[i].letter == 0)
+	    {
+	      SET_BINARY_O_OPTION_VALUE (i, on_or_off, option_name);
+	      return (EXECUTION_SUCCESS);
+	    }
+	  else
+	    {
+	      if (change_flag (o_options[i].letter, on_or_off) == FLAG_ERROR)
+		{
+		  sh_invalidoptname (option_name);
+		  return (EXECUTION_FAILURE);
+		}
+	      else
+		return (EXECUTION_SUCCESS);
+	    }
+
+	}
+    }
+
+  sh_invalidoptname (option_name);
+  return (EXECUTION_FAILURE);
+}
+
+static void
+print_all_shell_variables ()
+{
+  SHELL_VAR **vars;
+
+  vars = all_shell_variables ();
+  if (vars)
+    {
+      print_var_list (vars);
+      free (vars);
+    }
+
+  /* POSIX.2 does not allow function names and definitions to be output when
+     `set' is invoked without options (PASC Interp #202). */
+  if (posixly_correct == 0)
+    {
+      vars = all_shell_functions ();
+      if (vars)
+	{
+	  print_func_list (vars);
+	  free (vars);
+	}
+    }
+}
+
+void
+set_shellopts ()
+{
+  char *value;
+  char tflag[N_O_OPTIONS];
+  int vsize, i, vptr, *ip, exported;
+  SHELL_VAR *v;
+
+  for (vsize = i = 0; o_options[i].name; i++)
+    {
+      tflag[i] = 0;
+      if (o_options[i].letter)
+	{
+	  ip = find_flag (o_options[i].letter);
+	  if (ip && *ip)
+	    {
+	      vsize += strlen (o_options[i].name) + 1;
+	      tflag[i] = 1;
+	    }
+	}
+      else if (GET_BINARY_O_OPTION_VALUE (i, o_options[i].name))
+	{
+	  vsize += strlen (o_options[i].name) + 1;
+	  tflag[i] = 1;
+	}
+    }
+
+  value = (char *)xmalloc (vsize + 1);
+
+  for (i = vptr = 0; o_options[i].name; i++)
+    {
+      if (tflag[i])
+	{
+	  strcpy (value + vptr, o_options[i].name);
+	  vptr += strlen (o_options[i].name);
+	  value[vptr++] = ':';
+	}
+    }
+
+  if (vptr)
+    vptr--;			/* cut off trailing colon */
+  value[vptr] = '\0';
+
+  v = find_variable ("SHELLOPTS");
+
+  /* Turn off the read-only attribute so we can bind the new value, and
+     note whether or not the variable was exported. */
+  if (v)
+    {
+      VUNSETATTR (v, att_readonly);
+      exported = exported_p (v);
+    }
+  else
+    exported = 0;
+
+  v = bind_variable ("SHELLOPTS", value, 0);
+
+  /* Turn the read-only attribute back on, and turn off the export attribute
+     if it was set implicitly by mark_modified_vars and SHELLOPTS was not
+     exported before we bound the new value. */
+  VSETATTR (v, att_readonly);
+  if (mark_modified_vars && exported == 0 && exported_p (v))
+    VUNSETATTR (v, att_exported);
+
+  free (value);
+}
+
+void
+parse_shellopts (value)
+     char *value;
+{
+  char *vname;
+  int vptr;
+
+  vptr = 0;
+  while (vname = extract_colon_unit (value, &vptr))
+    {
+      set_minus_o_option (FLAG_ON, vname);
+      free (vname);
+    }
+}
+
+void
+initialize_shell_options (no_shellopts)
+     int no_shellopts;
+{
+  char *temp;
+  SHELL_VAR *var;
+
+  if (no_shellopts == 0)
+    {
+      var = find_variable ("SHELLOPTS");
+      /* set up any shell options we may have inherited. */
+      if (var && imported_p (var))
+	{
+	  temp = (array_p (var)) ? (char *)NULL : savestring (value_cell (var));
+	  if (temp)
+	    {
+	      parse_shellopts (temp);
+	      free (temp);
+	    }
+	}
+    }
+
+  /* Set up the $SHELLOPTS variable. */
+  set_shellopts ();
+}
+
+/* Reset the values of the -o options that are not also shell flags.  This is
+   called from execute_cmd.c:initialize_subshell() when setting up a subshell
+   to run an executable shell script without a leading `#!'. */
+void
+reset_shell_options ()
+{
+#if defined (HISTORY)
+  remember_on_history = 1;
+#endif
+  ignoreeof = 0;
+}
+
+/* Set some flags from the word values in the input list.  If LIST is empty,
+   then print out the values of the variables instead.  If LIST contains
+   non-flags, then set $1 - $9 to the successive words of LIST. */
+int
+set_builtin (list)
+     WORD_LIST *list;
+{
+  int on_or_off, flag_name, force_assignment, opts_changed;
+  WORD_LIST *l;
+  register char *arg;
+  char s[3];
+
+  if (list == 0)
+    {
+      print_all_shell_variables ();
+      return (EXECUTION_SUCCESS);
+    }
+
+  /* Check validity of flag arguments. */
+  reset_internal_getopt ();
+  while ((flag_name = internal_getopt (list, optflags)) != -1)
+    {
+      switch (flag_name)
+	{
+	  case '?':
+	    builtin_usage ();
+	    return (list_optopt == '?' ? EXECUTION_SUCCESS : EX_USAGE);
+	  default:
+	    break;
+	}
+    }
+    
+  /* Do the set command.  While the list consists of words starting with
+     '-' or '+' treat them as flags, otherwise, start assigning them to
+     $1 ... $n. */
+  for (force_assignment = opts_changed = 0; list; )
+    {
+      arg = list->word->word;
+
+      /* If the argument is `--' or `-' then signal the end of the list
+	 and remember the remaining arguments. */
+      if (arg[0] == '-' && (!arg[1] || (arg[1] == '-' && !arg[2])))
+	{
+	  list = list->next;
+
+	  /* `set --' unsets the positional parameters. */
+	  if (arg[1] == '-')
+	    force_assignment = 1;
+
+	  /* Until told differently, the old shell behaviour of
+	     `set - [arg ...]' being equivalent to `set +xv [arg ...]'
+	     stands.  Posix.2 says the behaviour is marked as obsolescent. */
+	  else
+	    {
+	      change_flag ('x', '+');
+	      change_flag ('v', '+');
+	      opts_changed = 1;
+	    }
+
+	  break;
+	}
+
+      if ((on_or_off = *arg) && (on_or_off == '-' || on_or_off == '+'))
+	{
+	  while (flag_name = *++arg)
+	    {
+	      if (flag_name == '?')
+		{
+		  builtin_usage ();
+		  return (EXECUTION_SUCCESS);
+		}
+	      else if (flag_name == 'o') /* -+o option-name */
+		{
+		  char *option_name;
+		  WORD_LIST *opt;
+
+		  opt = list->next;
+
+		  if (opt == 0)
+		    {
+		      list_minus_o_opts (-1, (on_or_off == '+'));
+		      continue;
+		    }
+
+		  option_name = opt->word->word;
+
+		  if (option_name == 0 || *option_name == '\0' ||
+		      *option_name == '-' || *option_name == '+')
+		    {
+		      list_minus_o_opts (-1, (on_or_off == '+'));
+		      continue;
+		    }
+		  list = list->next; /* Skip over option name. */
+
+		  opts_changed = 1;
+		  if (set_minus_o_option (on_or_off, option_name) != EXECUTION_SUCCESS)
+		    {
+		      set_shellopts ();
+		      return (EXECUTION_FAILURE);
+		    }
+		}
+	      else if (change_flag (flag_name, on_or_off) == FLAG_ERROR)
+		{
+		  s[0] = on_or_off;
+		  s[1] = flag_name;
+		  s[2] = '\0';
+		  sh_invalidopt (s);
+		  builtin_usage ();
+		  set_shellopts ();
+		  return (EXECUTION_FAILURE);
+		}
+	      opts_changed = 1;
+	    }
+	}
+      else
+	{
+	  break;
+	}
+      list = list->next;
+    }
+
+  /* Assigning $1 ... $n */
+  if (list || force_assignment)
+    remember_args (list, 1);
+  /* Set up new value of $SHELLOPTS */
+  if (opts_changed)
+    set_shellopts ();
+  return (EXECUTION_SUCCESS);
+}
+
+$BUILTIN unset
+$FUNCTION unset_builtin
+$SHORT_DOC unset [-f] [-v] [name ...]
+For each NAME, remove the corresponding variable or function.  Given
+the `-v', unset will only act on variables.  Given the `-f' flag,
+unset will only act on functions.  With neither flag, unset first
+tries to unset a variable, and if that fails, then tries to unset a
+function.  Some variables cannot be unset; also see readonly.
+$END
+
+#define NEXT_VARIABLE()	any_failed++; list = list->next; continue;
+
+int
+unset_builtin (list)
+  WORD_LIST *list;
+{
+  int unset_function, unset_variable, unset_array, opt, any_failed;
+  char *name;
+
+  unset_function = unset_variable = unset_array = any_failed = 0;
+
+  reset_internal_getopt ();
+  while ((opt = internal_getopt (list, "fv")) != -1)
+    {
+      switch (opt)
+	{
+	case 'f':
+	  unset_function = 1;
+	  break;
+	case 'v':
+	  unset_variable = 1;
+	  break;
+	default:
+	  builtin_usage ();
+	  return (EX_USAGE);
+	}
+    }
+
+  list = loptend;
+
+  if (unset_function && unset_variable)
+    {
+      builtin_error (_("cannot simultaneously unset a function and a variable"));
+      return (EXECUTION_FAILURE);
+    }
+
+  while (list)
+    {
+      SHELL_VAR *var;
+      int tem;
+#if defined (ARRAY_VARS)
+      char *t;
+#endif
+
+      name = list->word->word;
+
+#if defined (ARRAY_VARS)
+      unset_array = 0;
+      if (!unset_function && valid_array_reference (name))
+	{
+	  t = strchr (name, '[');
+	  *t++ = '\0';
+	  unset_array++;
+	}
+#endif
+
+      /* Bash allows functions with names which are not valid identifiers
+	 to be created when not in posix mode, so check only when in posix
+	 mode when unsetting a function. */
+      if (((unset_function && posixly_correct) || !unset_function) && legal_identifier (name) == 0)
+	{
+	  sh_invalidid (name);
+	  NEXT_VARIABLE ();
+	}
+
+      var = unset_function ? find_function (name) : find_variable (name);
+
+      if (var && !unset_function && non_unsettable_p (var))
+	{
+	  builtin_error (_("%s: cannot unset"), name);
+	  NEXT_VARIABLE ();
+	}
+
+      /* Posix.2 says that unsetting readonly variables is an error. */
+      if (var && readonly_p (var))
+	{
+	  builtin_error (_("%s: cannot unset: readonly %s"),
+			 name, unset_function ? "function" : "variable");
+	  NEXT_VARIABLE ();
+	}
+
+      /* Unless the -f option is supplied, the name refers to a variable. */
+#if defined (ARRAY_VARS)
+      if (var && unset_array)
+	{
+	  if (array_p (var) == 0)
+	    {
+	      builtin_error (_("%s: not an array variable"), name);
+	      NEXT_VARIABLE ();
+	    }
+	  else
+	    {
+	      tem = unbind_array_element (var, t);
+	      if (tem == -1)
+		any_failed++;
+	    }
+	}
+      else
+#endif /* ARRAY_VARS */
+      tem = unset_function ? unbind_func (name) : unbind_variable (name);
+
+      /* This is what Posix.2 draft 11+ says.  ``If neither -f nor -v
+	 is specified, the name refers to a variable; if a variable by
+	 that name does not exist, a function by that name, if any,
+	 shall be unset.'' */
+      if (tem == -1 && !unset_function && !unset_variable)
+	tem = unbind_func (name);
+
+      /* SUSv3, POSIX.1-2001 say:  ``Unsetting a variable or function that
+	 was not previously set shall not be considered an error.'' */
+
+      if (unset_function == 0)
+	stupidly_hack_special_variables (name);
+
+      list = list->next;
+    }
+
+  return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
+}
-- 
cgit v1.2.3

