]> git.ipfire.org Git - thirdparty/bash.git/blobdiff - builtins/set.def
bash-4.3-beta overlay
[thirdparty/bash.git] / builtins / set.def
index fd7dc993fb1fba6359c68eb1bcaef9fd058fef85..c4a7001dffeb279cafe6294b44e49f961430531b 100644 (file)
@@ -1,23 +1,22 @@
 This file is set.def, from which is created set.c.
 It implements the "set" and "unset" builtins in Bash.
 
-Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
+Copyright (C) 1987-2012 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 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 3 of the License, 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.
+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.
+You should have received a copy of the GNU General Public License
+along with Bash.  If not, see <http://www.gnu.org/licenses/>.
 
 $PRODUCES set.c
 
@@ -33,6 +32,7 @@ $PRODUCES set.c
 #include <stdio.h>
 
 #include "../bashansi.h"
+#include "../bashintl.h"
 
 #include "../shell.h"
 #include "../flags.h"
@@ -49,162 +49,201 @@ $PRODUCES set.c
 #  include "../bashhist.h"
 #endif
 
-extern int interactive;
-extern int noclobber, posixly_correct, ignoreeof, eof_encountered_limit;
+extern int posixly_correct, ignoreeof, eof_encountered_limit;
+#if defined (HISTORY)
+extern int dont_save_function_defs;
+#endif
 #if defined (READLINE)
-extern int rl_editing_mode, no_line_editing;
+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.
-    -i  Force the shell to be an "interactive" one.  Interactive shells
-        always read `~/.bashrc' on startup.
-    -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
+$SHORT_DOC set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...]
+Set or unset values of shell options and positional parameters.
+
+Change the value of shell attributes and positional parameters, or
+display the names and values of shell variables.
+
+Options:
+  -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
+          emacs        use an emacs-style line editing interface
 #endif /* READLINE */
-            errexit      same as -e
-            hashall      same as -h
+          errexit      same as -e
+          errtrace     same as -E
+          functrace    same as -T
+          hashall      same as -h
 #if defined (BANG_HISTORY)
-            histexpand   same as -H
+          histexpand   same as -H
 #endif /* BANG_HISTORY */
 #if defined (HISTORY)
-            history      enable command 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
+#if defined (JOB_CONTROL)
+          monitor      same as -m
 #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
-            notify       same as -b
-            nounset      same as -u
-            onecmd       same as -t
-            physical     same as -P
-            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
+          noclobber    same as -C
+          noexec       same as -n
+          noglob       same as -f
+          nolog        currently accepted but ignored
+#if defined (JOB_CONTROL)
+          notify       same as -b
+#endif
+          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 Posix standard to
+                       match the standard
+          privileged   same as -p
+          verbose      same as -v
 #if defined (READLINE)
-            vi           use a vi-style line editing interface
+          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.
+          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
+  -B  the shell will perform brace expansion
 #endif /* BRACE_EXPANSION */
-    -C  If set, disallow existing regular files to be overwritten
-        by redirection of output.
+  -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.
+  -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.
+  -P  If set, do not resolve 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.
+      If there are no remaining arguments, the positional parameters
+      are unset.
+  -   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.
+
+Exit Status:
+Returns success unless an invalid option is given.
 $END
 
-static int set_ignoreeof ();
-static int set_posix_mode ();
+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 ();
-static int get_edit_mode ();
+static int set_edit_mode __P((int, char *));
+static int get_edit_mode __P((char *));
 #endif
 
 #if defined (HISTORY)
-static int bash_set_history ();
+static int bash_set_history __P((int, char *));
 #endif
 
-static char *on = "on";
-static char *off = "off";
+static const char * const on = "on";
+static const char * const off = "off";
 
-/* An a-list used to match long options for set -o to the corresponding
-   option letter. */
-struct {
+/* 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. */
+const struct {
   char *name;
   int letter;
+  int *variable;
+  setopt_set_func_t *set_func;
+  setopt_get_func_t *get_func;
 } o_options[] = {
-  { "allexport",  'a' },
+  { "allexport",  'a', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
 #if defined (BRACE_EXPANSION)
-  { "braceexpand",'B' },
+  { "braceexpand",'B', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
 #endif
-  { "errexit",   'e' },
-  { "hashall",    'h' },
+#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' },
+  { "histexpand", 'H', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
 #endif /* BANG_HISTORY */
-  { "keyword",    'k' },
-  { "monitor",   'm' },
-  { "noclobber",  'C' },
-  { "noexec",    'n' },
-  { "noglob",    'f' },
+#if defined (HISTORY)
+  { "history",   '\0', &enable_history_list, 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  },
 #if defined (JOB_CONTROL)
-  { "notify",    'b' },
-#endif /* JOB_CONTROL */
-  { "nounset",   'u' },
-  { "onecmd",    't' },
-  { "physical",   'P' },
-  { "privileged", 'p' },
-  { "verbose",   'v' },
-  { "xtrace",    'x' },
-  {(char *)NULL, 0 },
-};
-
-struct {
-  char *name;
-  int *variable;
-  Function *set_func;
-  Function *get_func;
-} binary_o_options[] = {
+  { "monitor",   'm', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL  },
+#endif
+  { "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)
-  { "history", &remember_on_history, bash_set_history, (Function *)NULL },
+  { "nolog",     '\0', &dont_save_function_defs, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
 #endif
-  { "ignoreeof", &ignoreeof, set_ignoreeof, (Function *)NULL },
-  { "interactive-comments", &interactive_comments, (Function *)NULL, (Function *)NULL },
-  { "posix", &posixly_correct, set_posix_mode, (Function *)NULL },
+#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)
-  { "emacs", (int *)NULL, set_edit_mode, get_edit_mode },
-  { "vi", (int *)NULL, set_edit_mode, get_edit_mode },
+  { "vi",        '\0', (int *)NULL, set_edit_mode, get_edit_mode },
 #endif
-  { (char *)NULL, (int *)NULL }
+  { "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) \
-  ((binary_o_options[i].get_func) ? (*binary_o_options[i].get_func) (name) \
-                                 : (*binary_o_options[i].variable))
+  ((o_options[i].get_func) ? (*o_options[i].get_func) (name) \
+                          : (*o_options[i].variable))
 
 #define SET_BINARY_O_OPTION_VALUE(i, onoff, name) \
-  ((binary_o_options[i].set_func) ? (*binary_o_options[i].set_func) (onoff, name) \
-                                 : (*binary_o_options[i].variable = (onoff == FLAG_ON)))
+  ((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)
@@ -217,16 +256,16 @@ minus_o_option_value (name)
     {
       if (STREQ (name, o_options[i].name))
        {
-         on_or_off = find_flag (o_options[i].letter);
-         return ((on_or_off == FLAG_UNKNOWN) ? -1 : *on_or_off);
+         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));
        }
     }
-  for (i = 0; binary_o_options[i].name; i++)
-    {
-      if (STREQ (name, binary_o_options[i].name))
-        return (GET_BINARY_O_OPTION_VALUE (i, name));
-    }
-        
+
   return (-1);
 }
 
@@ -250,19 +289,23 @@ list_minus_o_opts (mode, reusable)
   register int i;
   int *on_or_off, value;
 
-  for (value = i = 0; o_options[i].name; i++)
-    {
-      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);
-    }
-  for (i = 0; binary_o_options[i].name; i++)
+  for (i = 0; o_options[i].name; i++)
     {
-      value = GET_BINARY_O_OPTION_VALUE (i, binary_o_options[i].name);
-      if (mode == -1 || mode == value)
-        print_minus_o_option (binary_o_options[i].name, value, reusable);
+      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);
+       }
     }
 }
 
@@ -270,16 +313,12 @@ char **
 get_minus_o_opts ()
 {
   char **ret;
-  int n, i, ind;
-
-  n = (sizeof (o_options) / sizeof (o_options[0])) +
-      (sizeof (binary_o_options) / sizeof (binary_o_options[0]));
-  ret = alloc_array (n + 1);
-  for (i = ind = 0; o_options[i].name; i++)
-    ret[ind++] = o_options[i].name;
-  for (i = 0; binary_o_options[i].name; i++)
-    ret[ind++] = binary_o_options[i].name;
-  ret[ind] = (char *)NULL;
+  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;
 }
 
@@ -291,7 +330,7 @@ set_ignoreeof (on_or_off, option_name)
   ignoreeof = on_or_off == FLAG_ON;
   unbind_variable ("ignoreeof");
   if (ignoreeof)
-    bind_variable ("IGNOREEOF", "10"); 
+    bind_variable ("IGNOREEOF", "10", 0); 
   else
     unbind_variable ("IGNOREEOF");
   sv_ignoreeof ("IGNOREEOF");
@@ -307,7 +346,7 @@ set_posix_mode (on_or_off, option_name)
   if (posixly_correct == 0)
     unbind_variable ("POSIXLY_CORRECT");
   else
-    bind_variable ("POSIXLY_CORRECT", "y");
+    bind_variable ("POSIXLY_CORRECT", "y", 0);
   sv_strict_posix ("POSIXLY_CORRECT");
   return (0);
 }
@@ -359,13 +398,17 @@ bash_set_history (on_or_off, option_name)
 {
   if (on_or_off == FLAG_ON)
     {
+      enable_history_list = 1;
       bash_history_enable ();
       if (history_lines_this_session == 0)
        load_history ();
     }
   else
-    bash_history_disable ();
-  return (1 - remember_on_history);
+    {
+      enable_history_list = 0;
+      bash_history_disable ();
+    }
+  return (1 - enable_history_list);
 }
 #endif
 
@@ -374,38 +417,33 @@ set_minus_o_option (on_or_off, option_name)
      int on_or_off;
      char *option_name;
 {
-  int option_char;
-  VFunction *set_func;
   register int i;
 
-  for (i = 0; binary_o_options[i].name; i++)
+  for (i = 0; o_options[i].name; i++)
     {
-      if (STREQ (option_name, binary_o_options[i].name))
+      if (STREQ (option_name, o_options[i].name))
        {
-         SET_BINARY_O_OPTION_VALUE (i, on_or_off, option_name);
-         return (EXECUTION_SUCCESS);
+         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);
+           }
+
        }
     }
 
-  for (i = 0, option_char = -1, set_func = 0; o_options[i].name; i++)
-    {
-      if (STREQ (option_name, o_options[i].name))
-        {
-          option_char = o_options[i].letter;
-          break;
-        }
-    }
-  if (option_char == -1)
-    {
-      builtin_error ("%s: unknown option name", option_name);
-      return (EXECUTION_FAILURE);
-    }
- if (change_flag (option_char, on_or_off) == FLAG_ERROR)
-    {
-      bad_option (option_name);
-      return (EXECUTION_FAILURE);
-    }
-  return (EXECUTION_SUCCESS);
+  sh_invalidoptname (option_name);
+  return (EX_USAGE);
 }
 
 static void
@@ -420,11 +458,16 @@ print_all_shell_variables ()
       free (vars);
     }
 
-  vars = all_shell_functions ();
-  if (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)
     {
-      print_var_list (vars);
-      free (vars);
+      vars = all_shell_functions ();
+      if (vars)
+       {
+         print_func_list (vars);
+         free (vars);
+       }
     }
 }
 
@@ -432,38 +475,41 @@ 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++)
     {
-      ip = find_flag (o_options[i].letter);
-      if (ip && *ip)
-       vsize += strlen (o_options[i].name) + 1;
+      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;
+       }
     }
-  for (i = 0; binary_o_options[i].name; i++)
-    if (GET_BINARY_O_OPTION_VALUE (i, binary_o_options[i].name))
-      vsize += strlen (binary_o_options[i].name) + 1;
 
-  value = xmalloc (vsize + 1);
+  value = (char *)xmalloc (vsize + 1);
 
   for (i = vptr = 0; o_options[i].name; i++)
     {
-      ip = find_flag (o_options[i].letter);
-      if (ip && *ip)
+      if (tflag[i])
        {
          strcpy (value + vptr, o_options[i].name);
          vptr += strlen (o_options[i].name);
          value[vptr++] = ':';
        }
     }
-  for (i = 0; binary_o_options[i].name; i++)
-    if (GET_BINARY_O_OPTION_VALUE (i, binary_o_options[i].name))
-      {
-       strcpy (value + vptr, binary_o_options[i].name);
-       vptr += strlen (binary_o_options[i].name);
-       value[vptr++] = ':';
-      }
+
   if (vptr)
     vptr--;                    /* cut off trailing colon */
   value[vptr] = '\0';
@@ -480,7 +526,7 @@ set_shellopts ()
   else
     exported = 0;
 
-  v = bind_variable ("SHELLOPTS", value);
+  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
@@ -520,7 +566,7 @@ initialize_shell_options (no_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));
+         temp = (array_p (var) || assoc_p (var)) ? (char *)NULL : savestring (value_cell (var));
          if (temp)
            {
              parse_shellopts (temp);
@@ -533,14 +579,16 @@ initialize_shell_options (no_shellopts)
   set_shellopts ();
 }
 
-/* Reset the values of the -o options that are not also shell flags. */
+/* 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;
+  remember_on_history = enable_history_list = 1;
 #endif
-  ignoreeof = posixly_correct = 0;
+  ignoreeof = 0;
 }
 
 /* Set some flags from the word values in the input list.  If LIST is empty,
@@ -550,45 +598,31 @@ int
 set_builtin (list)
      WORD_LIST *list;
 {
-  int on_or_off, flag_name, force_assignment, opts_changed;
-  WORD_LIST *l;
+  int on_or_off, flag_name, force_assignment, opts_changed, rv, r;
   register char *arg;
+  char s[3];
 
   if (list == 0)
     {
       print_all_shell_variables ();
-      return (EXECUTION_SUCCESS);
+      return (sh_chkwrite (EXECUTION_SUCCESS));
     }
 
   /* Check validity of flag arguments. */
-  if (*list->word->word == '-' || *list->word->word == '+')
+  rv = EXECUTION_SUCCESS;
+  reset_internal_getopt ();
+  while ((flag_name = internal_getopt (list, optflags)) != -1)
     {
-      for (l = list; l && (arg = l->word->word); l = l->next)
+      switch (flag_name)
        {
-         char c;
-
-         if (arg[0] != '-' && arg[0] != '+')
-           break;
-
-         /* `-' or `--' signifies end of flag arguments. */
-         if (arg[0] == '-' && (!arg[1] || (arg[1] == '-' && !arg[2])))
+         case '?':
+           builtin_usage ();
+           return (list_optopt == '?' ? EXECUTION_SUCCESS : EX_USAGE);
+         default:
            break;
-
-         while (c = *++arg)
-           {
-             if (find_flag (c) == FLAG_UNKNOWN && c != 'o')
-               {
-                 char s[2];
-                 s[0] = c; s[1] = '\0';
-                 bad_option (s);
-                 if (c == '?')
-                   builtin_usage ();
-                 return (c == '?' ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
-               }
-           }
        }
     }
-
+    
   /* Do the set command.  While the list consists of words starting with
      '-' or '+' treat them as flags, otherwise, start assigning them to
      $1 ... $n. */
@@ -638,6 +672,7 @@ set_builtin (list)
                  if (opt == 0)
                    {
                      list_minus_o_opts (-1, (on_or_off == '+'));
+                     rv = sh_chkwrite (rv);
                      continue;
                    }
 
@@ -652,19 +687,18 @@ set_builtin (list)
                  list = list->next; /* Skip over option name. */
 
                  opts_changed = 1;
-                 if (set_minus_o_option (on_or_off, option_name) != EXECUTION_SUCCESS)
+                 if ((r = set_minus_o_option (on_or_off, option_name)) != EXECUTION_SUCCESS)
                    {
                      set_shellopts ();
-                     return (EXECUTION_FAILURE);
+                     return (r);
                    }
                }
              else if (change_flag (flag_name, on_or_off) == FLAG_ERROR)
                {
-                 char opt[3];
-                 opt[0] = on_or_off;
-                 opt[1] = flag_name;
-                 opt[2] = '\0';
-                 bad_option (opt);
+                 s[0] = on_or_off;
+                 s[1] = flag_name;
+                 s[2] = '\0';
+                 sh_invalidopt (s);
                  builtin_usage ();
                  set_shellopts ();
                  return (EXECUTION_FAILURE);
@@ -685,18 +719,29 @@ set_builtin (list)
   /* Set up new value of $SHELLOPTS */
   if (opts_changed)
     set_shellopts ();
-  return (EXECUTION_SUCCESS);
+  return (rv);
 }
 
 $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 (such as PATH and IFS) cannot be unset; also
-see readonly.
+$SHORT_DOC unset [-f] [-v] [-n] [name ...]
+Unset values and attributes of shell variables and functions.
+
+For each NAME, remove the corresponding variable or function.
+
+Options:
+  -f   treat each NAME as a shell function
+  -v   treat each NAME as a shell variable
+  -n   treat each NAME as a name reference and unset the variable itself
+       rather than the variable it references
+
+Without options, unset first tries to unset a variable, and if that fails,
+tries to unset a function.
+
+Some variables cannot be unset; also see `readonly'.
+
+Exit Status:
+Returns success unless an invalid option is given or a NAME is read-only.
 $END
 
 #define NEXT_VARIABLE()        any_failed++; list = list->next; continue;
@@ -705,13 +750,13 @@ int
 unset_builtin (list)
   WORD_LIST *list;
 {
-  int unset_function, unset_variable, unset_array, opt, any_failed;
+  int unset_function, unset_variable, unset_array, opt, nameref, any_failed;
   char *name;
 
-  unset_function = unset_variable = unset_array = any_failed = 0;
+  unset_function = unset_variable = unset_array = nameref = any_failed = 0;
 
   reset_internal_getopt ();
-  while ((opt = internal_getopt (list, "fv")) != -1)
+  while ((opt = internal_getopt (list, "fnv")) != -1)
     {
       switch (opt)
        {
@@ -721,6 +766,9 @@ unset_builtin (list)
        case 'v':
          unset_variable = 1;
          break;
+       case 'n':
+         nameref = 1;
+         break;
        default:
          builtin_usage ();
          return (EX_USAGE);
@@ -731,9 +779,11 @@ unset_builtin (list)
 
   if (unset_function && unset_variable)
     {
-      builtin_error ("cannot simultaneously unset a function and a variable");
+      builtin_error (_("cannot simultaneously unset a function and a variable"));
       return (EXECUTION_FAILURE);
     }
+  else if (unset_function && nameref)
+    nameref = 0;
 
   while (list)
     {
@@ -746,6 +796,7 @@ unset_builtin (list)
       name = list->word->word;
 
 #if defined (ARRAY_VARS)
+      unset_array = 0;
       if (!unset_function && valid_array_reference (name))
        {
          t = strchr (name, '[');
@@ -753,29 +804,44 @@ unset_builtin (list)
          unset_array++;
        }
 #endif
+      /* Get error checking out of the way first.  The low-level functions
+        just perform the unset, relying on the caller to verify. */
 
       /* 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)
-        {
-          builtin_error ("`%s': not a valid identifier", name);
-          NEXT_VARIABLE ();
-        }
+       {
+         sh_invalidid (name);
+         NEXT_VARIABLE ();
+       }
 
-      var = unset_function ? find_function (name) : find_variable (name);
+      /* Only search for functions here if -f supplied. */
+      var = unset_function ? find_function (name)
+                          : (nameref ? find_variable_last_nameref (name) : find_variable (name));
 
-      if (var && !unset_function && non_unsettable_p (var))
+      /* Some variables (but not functions yet) cannot be unset, period. */
+      if (var && unset_function == 0 && non_unsettable_p (var))
        {
-         builtin_error ("%s: cannot unset", name);
+         builtin_error (_("%s: cannot unset"), name);
          NEXT_VARIABLE ();
        }
 
+      /* Posix.2 says try variables first, then functions.  If we would
+        find a function after unsuccessfully searching for a variable,
+        note that we're acting on a function now as if -f were
+        supplied.  The readonly check below takes care of it. */
+      if (var == 0 && unset_variable == 0 && unset_function == 0)
+       {
+         if (var = find_function (name))
+           unset_function = 1;
+       }
+
       /* 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");
+         builtin_error (_("%s: cannot unset: readonly %s"),
+                        var->name, unset_function ? "function" : "variable");
          NEXT_VARIABLE ();
        }
 
@@ -783,28 +849,33 @@ unset_builtin (list)
 #if defined (ARRAY_VARS)
       if (var && unset_array)
        {
-         if (array_p (var) == 0)
+         if (array_p (var) == 0 && assoc_p (var) == 0)
            {
-             builtin_error ("%s: not an array variable", name);
+             builtin_error (_("%s: not an array variable"), var->name);
              NEXT_VARIABLE ();
            }
          else
-           tem = unbind_array_element (var, t);
+           {
+             tem = unbind_array_element (var, t);
+             if (tem == -1)
+               any_failed++;
+           }
        }
       else
 #endif /* ARRAY_VARS */
-      tem = makunbound (name, unset_function ? shell_functions : shell_variables);
+      tem = unset_function ? unbind_func (name) : (nameref ? unbind_nameref (name) : unbind_variable (name));
 
-      /* This is what Posix.2 draft 11+ says.  ``If neither -f nor -v
+      /* This is what Posix.2 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 = makunbound (name, shell_functions);
+      if (tem == -1 && unset_function == 0 && unset_variable == 0)
+       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 (tem == -1)
-       any_failed++;
-      else if (!unset_function)
+      if (unset_function == 0)
        stupidly_hack_special_variables (name);
 
       list = list->next;