974 lines
		
	
	
	
		
			26 KiB
		
	
	
	
		
			Modula-2
		
	
	
	
	
	
			
		
		
	
	
			974 lines
		
	
	
	
		
			26 KiB
		
	
	
	
		
			Modula-2
		
	
	
	
	
	
| This file is set.def, from which is created set.c.
 | |
| It implements the "set" and "unset" builtins in Bash.
 | |
| 
 | |
| Copyright (C) 1987-2015 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 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.
 | |
| 
 | |
| 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
 | |
| 
 | |
| #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-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
 | |
| #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
 | |
| #if defined (JOB_CONTROL)
 | |
|           monitor      same as -m
 | |
| #endif
 | |
|           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
 | |
| #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 resolve symbolic links when executing commands
 | |
|       such as cd which change the current directory.
 | |
|   -T  If set, the DEBUG and RETURN traps are 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
 | |
| 
 | |
| 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 const char * const on = "on";
 | |
| static const char * const off = "off";
 | |
| 
 | |
| static int previous_option_value;
 | |
| 
 | |
| /* 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.  If you add a new variable name here
 | |
|    that doesn't have a corresponding single-character option letter, make
 | |
|    sure to set the value appropriately in reset_shell_options. */
 | |
| const 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', &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)
 | |
|   { "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)
 | |
|   { "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;
 | |
| }
 | |
| 
 | |
| char *
 | |
| get_current_options ()
 | |
| {
 | |
|   char *temp;
 | |
|   int i;
 | |
| 
 | |
|   temp = (char *)xmalloc (1 + N_O_OPTIONS);
 | |
|   for (i = 0; o_options[i].name; i++)
 | |
|     {
 | |
|       if (o_options[i].letter)
 | |
| 	temp[i] = *(find_flag (o_options[i].letter));
 | |
|       else
 | |
| 	temp[i] = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
 | |
|     }
 | |
|   temp[i] = '\0';
 | |
|   return (temp);
 | |
| }
 | |
| 
 | |
| void
 | |
| set_current_options (bitmap)
 | |
|      const char *bitmap;
 | |
| {
 | |
|   int i;
 | |
| 
 | |
|   if (bitmap == 0)
 | |
|     return;
 | |
|   for (i = 0; o_options[i].name; i++)
 | |
|     {
 | |
|       if (o_options[i].letter)
 | |
| 	change_flag (o_options[i].letter, bitmap[i] ? FLAG_ON : FLAG_OFF);
 | |
|       else
 | |
| 	SET_BINARY_O_OPTION_VALUE (i, bitmap[i] ? FLAG_ON : FLAG_OFF, o_options[i].name);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static int
 | |
| set_ignoreeof (on_or_off, option_name)
 | |
|      int on_or_off;
 | |
|      char *option_name;
 | |
| {
 | |
|   ignoreeof = on_or_off == FLAG_ON;
 | |
|   unbind_variable_noref ("ignoreeof");
 | |
|   if (ignoreeof)
 | |
|     bind_variable ("IGNOREEOF", "10", 0); 
 | |
|   else
 | |
|     unbind_variable_noref ("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_noref ("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)
 | |
|     {
 | |
|       enable_history_list = 1;
 | |
|       bash_history_enable ();
 | |
|       if (history_lines_this_session == 0)
 | |
| 	load_history ();
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       enable_history_list = 0;
 | |
|       bash_history_disable ();
 | |
|     }
 | |
|   return (1 - enable_history_list);
 | |
| }
 | |
| #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)
 | |
| 	    {
 | |
| 	      previous_option_value = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
 | |
| 	      SET_BINARY_O_OPTION_VALUE (i, on_or_off, option_name);
 | |
| 	      return (EXECUTION_SUCCESS);
 | |
| 	    }
 | |
| 	  else
 | |
| 	    {
 | |
| 	      if ((previous_option_value = 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 (EX_USAGE);
 | |
| }
 | |
| 
 | |
| 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) || assoc_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 ()
 | |
| {
 | |
|   pipefail_opt = 0;
 | |
|   ignoreeof = 0;
 | |
| 
 | |
| #if defined (STRICT_POSIX)
 | |
|   posixly_correct = 1;
 | |
| #else
 | |
|   posixly_correct = 0;
 | |
| #endif
 | |
| #if defined (HISTORY)
 | |
|   dont_save_function_defs = 0;
 | |
|   remember_on_history = enable_history_list = 1;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /* 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, rv, r;
 | |
|   register char *arg;
 | |
|   char s[3];
 | |
| 
 | |
|   if (list == 0)
 | |
|     {
 | |
|       print_all_shell_variables ();
 | |
|       return (sh_chkwrite (EXECUTION_SUCCESS));
 | |
|     }
 | |
| 
 | |
|   /* Check validity of flag arguments. */
 | |
|   rv = EXECUTION_SUCCESS;
 | |
|   reset_internal_getopt ();
 | |
|   while ((flag_name = internal_getopt (list, optflags)) != -1)
 | |
|     {
 | |
|       switch (flag_name)
 | |
| 	{
 | |
| 	  case 'i':	/* don't allow set -i */
 | |
| 	    s[0] = list_opttype;
 | |
| 	    s[1] = 'i';
 | |
| 	    s[2] = '\0';
 | |
| 	    sh_invalidopt (s);
 | |
| 	    builtin_usage ();
 | |
| 	    return (EX_USAGE);
 | |
| 	  CASE_HELPOPT;
 | |
| 	  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 == '+'));
 | |
| 		      rv = sh_chkwrite (rv);
 | |
| 		      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 ((r = set_minus_o_option (on_or_off, option_name)) != EXECUTION_SUCCESS)
 | |
| 		    {
 | |
| 		      set_shellopts ();
 | |
| 		      return (r);
 | |
| 		    }
 | |
| 		}
 | |
| 	      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 (rv);
 | |
| }
 | |
| 
 | |
| $BUILTIN unset
 | |
| $FUNCTION unset_builtin
 | |
| $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;
 | |
| 
 | |
| int
 | |
| unset_builtin (list)
 | |
|   WORD_LIST *list;
 | |
| {
 | |
|   int unset_function, unset_variable, unset_array, opt, nameref, any_failed;
 | |
|   int global_unset_func, global_unset_var;
 | |
|   char *name, *tname;
 | |
| 
 | |
|   unset_function = unset_variable = unset_array = nameref = any_failed = 0;
 | |
|   global_unset_func = global_unset_var = 0;
 | |
| 
 | |
|   reset_internal_getopt ();
 | |
|   while ((opt = internal_getopt (list, "fnv")) != -1)
 | |
|     {
 | |
|       switch (opt)
 | |
| 	{
 | |
| 	case 'f':
 | |
| 	  global_unset_func = 1;
 | |
| 	  break;
 | |
| 	case 'v':
 | |
| 	  global_unset_var = 1;
 | |
| 	  break;
 | |
| 	case 'n':
 | |
| 	  nameref = 1;
 | |
| 	  break;
 | |
| 	CASE_HELPOPT;
 | |
| 	default:
 | |
| 	  builtin_usage ();
 | |
| 	  return (EX_USAGE);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   list = loptend;
 | |
| 
 | |
|   if (global_unset_func && global_unset_var)
 | |
|     {
 | |
|       builtin_error (_("cannot simultaneously unset a function and a variable"));
 | |
|       return (EXECUTION_FAILURE);
 | |
|     }
 | |
|   else if (unset_function && nameref)
 | |
|     nameref = 0;
 | |
| 
 | |
|   while (list)
 | |
|     {
 | |
|       SHELL_VAR *var;
 | |
|       int tem;
 | |
| #if defined (ARRAY_VARS)
 | |
|       char *t;
 | |
| #endif
 | |
| 
 | |
|       name = list->word->word;
 | |
| 
 | |
|       unset_function = global_unset_func;
 | |
|       unset_variable = global_unset_var;
 | |
| 
 | |
| #if defined (ARRAY_VARS)
 | |
|       unset_array = 0;
 | |
|       if (!unset_function && nameref == 0 && valid_array_reference (name, 0))
 | |
| 	{
 | |
| 	  t = strchr (name, '[');
 | |
| 	  *t++ = '\0';
 | |
| 	  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)
 | |
| 	{
 | |
| 	  sh_invalidid (name);
 | |
| 	  NEXT_VARIABLE ();
 | |
| 	}
 | |
| 
 | |
|       /* Only search for functions here if -f supplied. */
 | |
|       var = unset_function ? find_function (name)
 | |
| 			   : (nameref ? find_variable_last_nameref (name, 0) : find_variable (name));
 | |
| 
 | |
|       /* 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);
 | |
| 	  NEXT_VARIABLE ();
 | |
| 	}
 | |
| 
 | |
|       /* if we have a nameref we want to use it */
 | |
|       if (var && unset_function == 0 && nameref == 0 && STREQ (name, name_cell(var)) == 0)
 | |
| 	name = name_cell (var);
 | |
| 
 | |
|       /* 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 && nameref == 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"),
 | |
| 			 var->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)
 | |
| 	{
 | |
| 	  /* Let unbind_array_element decide what to do with non-array vars */
 | |
| 	  tem = unbind_array_element (var, t);
 | |
| 	  if (tem == -2 && array_p (var) == 0 && assoc_p (var) == 0)
 | |
| 	    {
 | |
| 	      builtin_error (_("%s: not an array variable"), var->name);
 | |
| 	      NEXT_VARIABLE ();
 | |
| 	    }
 | |
| 	  else if (tem < 0)
 | |
| 	    any_failed++;
 | |
| 	}
 | |
|       else
 | |
| #endif /* ARRAY_VARS */
 | |
|       /* If we're trying to unset a nameref variable whose value isn't a set
 | |
| 	 variable, make sure we still try to unset the nameref's value */
 | |
|       if (var == 0 && nameref == 0 && unset_function == 0)
 | |
| 	{
 | |
| 	  var = find_variable_last_nameref (name, 0);
 | |
| 	  if (var && nameref_p (var))
 | |
| 	    {
 | |
| #if defined (ARRAY_VARS)
 | |
| 	      if (valid_array_reference (nameref_cell (var), 0))
 | |
| 		{
 | |
| 		  tname = savestring (nameref_cell (var));
 | |
| 		  if (var = array_variable_part (tname, &t, 0))
 | |
| 		    tem = unbind_array_element (var, t);
 | |
| 		  free (tname);
 | |
| 		}
 | |
| 	      else
 | |
| #endif
 | |
| 		tem = unbind_variable (nameref_cell (var));
 | |
| 	    }
 | |
| 	  else
 | |
| 	    tem = unbind_variable (name);
 | |
| 	}
 | |
|       else
 | |
| 	tem = unset_function ? unbind_func (name) : (nameref ? unbind_nameref (name) : unbind_variable (name));
 | |
| 
 | |
|       /* 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 && nameref == 0 && unset_function == 0 && unset_variable == 0)
 | |
| 	tem = unbind_func (name);
 | |
| 
 | |
|       name = list->word->word;		/* reset above for namerefs */
 | |
| 
 | |
|       /* 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);
 | |
| }
 | 
