- diff --git a/ptxdist/configs/ecu01/ptxconfig b/ptxdist/configs/ecu01/ptxconfig
- index a725eb0..0fd28b4 100644
- --- a/ptxdist/configs/ecu01/ptxconfig
- +++ b/ptxdist/configs/ecu01/ptxconfig
- @@ -261,7 +261,7 @@ PTXCONF_ROOTFS_HOSTS=y
- PTXCONF_ROOTFS_ISSUE=y
- # PTXCONF_ROOTFS_MODPROBE_CONF is not set
- PTXCONF_ROOTFS_NSSWITCH_CONF=y
- -PTXCONF_ROOTFS_PROFILE=y
- +# PTXCONF_ROOTFS_PROFILE is not set
- PTXCONF_ROOTFS_PROTOCOLS=y
- PTXCONF_ROOTFS_RESOLV_FILE=y
- # PTXCONF_ROOTFS_RESOLV_LINK is not set
- @@ -360,21 +360,35 @@ PTXCONF_BASH_ARITHMETIC_FOR=y
- PTXCONF_BASH_ARRAY=y
- PTXCONF_BASH_HISTORY=y
- PTXCONF_BASH_BRACE=y
- +PTXCONF_BASH_CASEMODATTR=y
- +PTXCONF_BASH_CASEMODEXP=y
- +PTXCONF_BASH_CMDTIMING=y
- PTXCONF_BASH_CONDITIONAL=y
- +PTXCONF_BASH_CONDITIONAL_REGEX=y
- +PTXCONF_BASH_COPROCESSES=y
- +# PTXCONF_BASH_DEBUGGER is not set
- +# PTXCONF_BASH_DIREXPDEFLT is not set
- PTXCONF_BASH_DIRSTACK=y
- +PTXCONF_BASH_DISABLED_BUILDINS=y
- +PTXCONF_BASH_DPARAN_ARITH=y
- PTXCONF_BASH_EXTPATTERN=y
- +PTXCONF_BASH_EXTPATTERN_DEFLT=y
- +# PTXCONF_BASH_GLOB_ASCIIRANGE_DEFLT is not set
- PTXCONF_BASH_HELP=y
- PTXCONF_BASH_CMDHISTORY=y
- PTXCONF_BASH_JOBS=y
- +PTXCONF_BASH_MULTIBYTE=y
- PTXCONF_BASH_PROCSUBST=y
- -PTXCONF_BASH_COMPLETION=y
- +# PTXCONF_BASH_BASHCOMPLETION is not set
- PTXCONF_BASH_ESC=y
- PTXCONF_BASH_EDIT=y
- # PTXCONF_BASH_RESTRICTED is not set
- # PTXCONF_BASH_SELECT is not set
- +# PTXCONF_BASH_SINGLE_HELPLINE is not set
- # PTXCONF_BASH_GPROF is not set
- PTXCONF_BASH_STATIC=y
- # PTXCONF_BASH_CURSES is not set
- +# PTXCONF_BASH_SH is not set
- # PTXCONF_BC is not set
- PTXCONF_BUSYBOX=y
- PTXCONF_BUSYBOX_TELNETD_STARTSCRIPT=y
- @@ -2028,7 +2042,8 @@ PTXCONF_NCURSES_TERMCAP=y
- # PTXCONF_SLANG is not set
- # PTXCONF_SPARSEHASH is not set
- # PTXCONF_SQLITE is not set
- -# PTXCONF_TERMCAP is not set
- +PTXCONF_TERMCAP=y
- +PTXCONF_TERMCAP_TERMCAP=y
- # PTXCONF_XERCES is not set
- PTXCONF_ZLIB=y
- # PTXCONF_ZLIB_STATIC is not set
- diff --git a/ptxdist/local_src/ecu01-basicsys/etc/bash.bashrc b/ptxdist/local_src/ecu01-basicsys/etc/bash.bashrc
- new file mode 100644
- index 0000000..1aa9e30
- --- /dev/null
- +++ b/ptxdist/local_src/ecu01-basicsys/etc/bash.bashrc
- @@ -0,0 +1,41 @@
- +#
- +# /etc/bash.bashrc - config file for *interactive* bash shells
- +#
- +# (this is sourced after profile scripts (/etc/profile and
- +# ~/.profile, but before config script ~/.bashrc))
- +#
- +# Note that /etc/profile and ~/.profile are ONLY sourced for
- +# *LOGIN* shells, while /etc/bash.bashrc and ~/.bashrc are sourced
- +# for all interactive bash shells
- +#
- +
- +printf $"# Running /etc/bash.bashrc ...\n"
- +
- +# /etc/profile.environment - config for sub-shells
- +#PS1="\\u@\\h:\\w "
- +PS1='\u \t : \w # '
- +PS2=" >"
- +PS4="+ "
- +
- +alias vim='vi'
- +alias l='ls -l'
- +alias ll='ls -al'
- +alias ..='cd ..'
- +alias ...='cd ../..'
- +alias md='mkdir'
- +alias rd='rmdir'
- +
- +# Quantron: persistent history file for bash shells
- +#
- +# (note that HIST* variables, including HISTFILE, are settings
- +# for interactive shells and therefore do not belong into
- +# /etc/profile or ~/.profile.
- +# It should also NOT be exportet to the environment since HISTFILE
- +# affects ksh/ksh93 and other POSIX(-like) shells, which use
- +# different history file formats)
- +#
- +# (this means ptxdist usage of HISTFILE in ptx-supplied
- +# /etc/profile is plain wrong)
- +HISTFILE='/var/dyn/bash_history'
- +
- +# EOF.
- diff --git a/ptxdist/local_src/ecu01-basicsys/etc/profile b/ptxdist/local_src/ecu01-basicsys/etc/profile
- new file mode 100644
- index 0000000..02fa716
- --- /dev/null
- +++ b/ptxdist/local_src/ecu01-basicsys/etc/profile
- @@ -0,0 +1,36 @@
- +#
- +# /etc/profile - config for profile shells
- +#
- +
- +printf "## Running /etc/profile ...\n"
- +
- +# do not set interactive shell properties like HISTFILE, PS1, PS2,
- +# ..., or aliases here.
- +# Such stuff belongs into the startup files for *interactive* shell
- +# sessions/etc/bash.bashrc or /etc/ksh.kshrc
- +
- +# This fixes the backspace when telnetting in.
- +if [ "$TERM" != "linux" ]; then
- + stty erase ^H
- +fi
- +
- +
- +# Exec local profile
- +if [ -e "/etc/profile.local" ]; then
- + printf "running /etc/profile.local\n"
- + . /etc/profile.local
- +fi
- +
- +# bug: workaround for issue with bash4 where an interactive login
- +# shell does not source /etc/bash.bashrc & ~/.bashrc
- +# Ordering is wrong with this workaround, because /etc/profile and
- +# ~/.profile should be sourced before /etc/bash.bashrc and
- +# ~/.bashrc instead of somewhere in the middle as in this ugly
- +# workaround
- +if [[ "$-" == *i* ]] && [[ "$0" == *bash* ]] ; then
- + [[ -r /etc/bash.bashrc ]] && source /etc/bash.bashrc
- + [[ -r $HOME/.bashrc ]] && source $HOME/.bashrc
- +fi
- +
- +
- +# EOF.
- diff --git a/ptxdist/patches/bash-4.3.30/0001-Bash-4.3-patch-31.patch b/ptxdist/patches/bash-4.3.30/0001-Bash-4.3-patch-31.patch
- new file mode 100644
- index 0000000..d9a187d
- --- /dev/null
- +++ b/ptxdist/patches/bash-4.3.30/0001-Bash-4.3-patch-31.patch
- @@ -0,0 +1,5467 @@
- +From: Chet Ramey <chet.ramey@case.edu>
- +Date: Thu, 15 Jan 2015 10:20:04 -0500
- +Subject: [PATCH] Bash-4.3 patch 31
- +
- +---
- + patchlevel.h | 2 +-
- + subst.h | 1 +
- + variables.c | 32 +-
- + variables.c.orig | 5365 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
- + 4 files changed, 5397 insertions(+), 3 deletions(-)
- + create mode 100644 variables.c.orig
- +
- +diff --git a/patchlevel.h b/patchlevel.h
- +index e5dde5245275..0ad46aafbdd9 100644
- +--- a/patchlevel.h
- ++++ b/patchlevel.h
- +@@ -25,6 +25,6 @@
- + regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
- + looks for to find the patch level (for the sccs version string). */
- +
- +-#define PATCHLEVEL 30
- ++#define PATCHLEVEL 31
- +
- + #endif /* _PATCHLEVEL_H_ */
- +diff --git a/subst.h b/subst.h
- +index cedaf8b6b444..1c300ab96b04 100644
- +--- a/subst.h
- ++++ b/subst.h
- +@@ -47,6 +47,7 @@
- + #define ASS_MKASSOC 0x0004
- + #define ASS_MKGLOBAL 0x0008 /* force global assignment */
- + #define ASS_NAMEREF 0x0010 /* assigning to nameref variable */
- ++#define ASS_FROMREF 0x0020 /* assigning from value of nameref variable */
- +
- + /* Flags for the string extraction functions. */
- + #define SX_NOALLOC 0x0001 /* just skip; don't return substring */
- +diff --git a/variables.c b/variables.c
- +index 7c82710e0f0b..81b7877e32e8 100644
- +--- a/variables.c
- ++++ b/variables.c
- +@@ -2516,10 +2516,27 @@ bind_variable_internal (name, value, table, hflags, aflags)
- + HASH_TABLE *table;
- + int hflags, aflags;
- + {
- +- char *newval;
- ++ char *newname, *newval;
- + SHELL_VAR *entry;
- ++#if defined (ARRAY_VARS)
- ++ arrayind_t ind;
- ++ char *subp;
- ++ int sublen;
- ++#endif
- +
- ++ newname = 0;
- ++#if defined (ARRAY_VARS)
- ++ if ((aflags & ASS_FROMREF) && (hflags & HASH_NOSRCH) == 0 && valid_array_reference (name))
- ++ {
- ++ newname = array_variable_name (name, &subp, &sublen);
- ++ if (newname == 0)
- ++ return (SHELL_VAR *)NULL; /* XXX */
- ++ entry = hash_lookup (newname, table);
- ++ }
- ++ else
- ++#endif
- + entry = (hflags & HASH_NOSRCH) ? (SHELL_VAR *)NULL : hash_lookup (name, table);
- ++
- + /* Follow the nameref chain here if this is the global variables table */
- + if (entry && nameref_p (entry) && (invisible_p (entry) == 0) && table == global_variables->table)
- + {
- +@@ -2550,6 +2567,16 @@ bind_variable_internal (name, value, table, hflags, aflags)
- + var_setvalue (entry, make_variable_value (entry, value, 0));
- + }
- + }
- ++#if defined (ARRAY_VARS)
- ++ else if (entry == 0 && newname)
- ++ {
- ++ entry = make_new_array_variable (newname); /* indexed array by default */
- ++ if (entry == 0)
- ++ return entry;
- ++ ind = array_expand_index (name, subp, sublen);
- ++ bind_array_element (entry, ind, value, aflags);
- ++ }
- ++#endif
- + else if (entry == 0)
- + {
- + entry = make_new_variable (name, table);
- +@@ -2670,7 +2697,8 @@ bind_variable (name, value, flags)
- + normal. */
- + if (nameref_cell (nv) == 0)
- + return (bind_variable_internal (nv->name, value, nvc->table, 0, flags));
- +- return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags));
- ++ /* XXX - bug here with ref=array[index] */
- ++ return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags|ASS_FROMREF));
- + }
- + else
- + v = nv;
- +diff --git a/variables.c.orig b/variables.c.orig
- +new file mode 100644
- +index 000000000000..7c82710e0f0b
- +--- /dev/null
- ++++ b/variables.c.orig
- +@@ -0,0 +1,5365 @@
- ++/* variables.c -- Functions for hacking shell variables. */
- ++
- ++/* Copyright (C) 1987-2013 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/>.
- ++*/
- ++
- ++#include "config.h"
- ++
- ++#include "bashtypes.h"
- ++#include "posixstat.h"
- ++#include "posixtime.h"
- ++
- ++#if defined (__QNX__)
- ++# if defined (__QNXNTO__)
- ++# include <sys/netmgr.h>
- ++# else
- ++# include <sys/vc.h>
- ++# endif /* !__QNXNTO__ */
- ++#endif /* __QNX__ */
- ++
- ++#if defined (HAVE_UNISTD_H)
- ++# include <unistd.h>
- ++#endif
- ++
- ++#include <stdio.h>
- ++#include "chartypes.h"
- ++#if defined (HAVE_PWD_H)
- ++# include <pwd.h>
- ++#endif
- ++#include "bashansi.h"
- ++#include "bashintl.h"
- ++
- ++#define NEED_XTRACE_SET_DECL
- ++
- ++#include "shell.h"
- ++#include "flags.h"
- ++#include "execute_cmd.h"
- ++#include "findcmd.h"
- ++#include "mailcheck.h"
- ++#include "input.h"
- ++#include "hashcmd.h"
- ++#include "pathexp.h"
- ++#include "alias.h"
- ++#include "jobs.h"
- ++
- ++#include "version.h"
- ++
- ++#include "builtins/getopt.h"
- ++#include "builtins/common.h"
- ++#include "builtins/builtext.h"
- ++
- ++#if defined (READLINE)
- ++# include "bashline.h"
- ++# include <readline/readline.h>
- ++#else
- ++# include <tilde/tilde.h>
- ++#endif
- ++
- ++#if defined (HISTORY)
- ++# include "bashhist.h"
- ++# include <readline/history.h>
- ++#endif /* HISTORY */
- ++
- ++#if defined (PROGRAMMABLE_COMPLETION)
- ++# include "pcomplete.h"
- ++#endif
- ++
- ++#define TEMPENV_HASH_BUCKETS 4 /* must be power of two */
- ++
- ++#define ifsname(s) ((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0')
- ++
- ++#define BASHFUNC_PREFIX "BASH_FUNC_"
- ++#define BASHFUNC_PREFLEN 10 /* == strlen(BASHFUNC_PREFIX */
- ++#define BASHFUNC_SUFFIX "%%"
- ++#define BASHFUNC_SUFFLEN 2 /* == strlen(BASHFUNC_SUFFIX) */
- ++
- ++extern char **environ;
- ++
- ++/* Variables used here and defined in other files. */
- ++extern int posixly_correct;
- ++extern int line_number, line_number_base;
- ++extern int subshell_environment, indirection_level, subshell_level;
- ++extern int build_version, patch_level;
- ++extern int expanding_redir;
- ++extern int last_command_exit_value;
- ++extern char *dist_version, *release_status;
- ++extern char *shell_name;
- ++extern char *primary_prompt, *secondary_prompt;
- ++extern char *current_host_name;
- ++extern sh_builtin_func_t *this_shell_builtin;
- ++extern SHELL_VAR *this_shell_function;
- ++extern char *the_printed_command_except_trap;
- ++extern char *this_command_name;
- ++extern char *command_execution_string;
- ++extern time_t shell_start_time;
- ++extern int assigning_in_environment;
- ++extern int executing_builtin;
- ++extern int funcnest_max;
- ++
- ++#if defined (READLINE)
- ++extern int no_line_editing;
- ++extern int perform_hostname_completion;
- ++#endif
- ++
- ++/* The list of shell variables that the user has created at the global
- ++ scope, or that came from the environment. */
- ++VAR_CONTEXT *global_variables = (VAR_CONTEXT *)NULL;
- ++
- ++/* The current list of shell variables, including function scopes */
- ++VAR_CONTEXT *shell_variables = (VAR_CONTEXT *)NULL;
- ++
- ++/* The list of shell functions that the user has created, or that came from
- ++ the environment. */
- ++HASH_TABLE *shell_functions = (HASH_TABLE *)NULL;
- ++
- ++#if defined (DEBUGGER)
- ++/* The table of shell function definitions that the user defined or that
- ++ came from the environment. */
- ++HASH_TABLE *shell_function_defs = (HASH_TABLE *)NULL;
- ++#endif
- ++
- ++/* The current variable context. This is really a count of how deep into
- ++ executing functions we are. */
- ++int variable_context = 0;
- ++
- ++/* The set of shell assignments which are made only in the environment
- ++ for a single command. */
- ++HASH_TABLE *temporary_env = (HASH_TABLE *)NULL;
- ++
- ++/* Set to non-zero if an assignment error occurs while putting variables
- ++ into the temporary environment. */
- ++int tempenv_assign_error;
- ++
- ++/* Some funky variables which are known about specially. Here is where
- ++ "$*", "$1", and all the cruft is kept. */
- ++char *dollar_vars[10];
- ++WORD_LIST *rest_of_args = (WORD_LIST *)NULL;
- ++
- ++/* The value of $$. */
- ++pid_t dollar_dollar_pid;
- ++
- ++/* Non-zero means that we have to remake EXPORT_ENV. */
- ++int array_needs_making = 1;
- ++
- ++/* The number of times BASH has been executed. This is set
- ++ by initialize_variables (). */
- ++int shell_level = 0;
- ++
- ++/* An array which is passed to commands as their environment. It is
- ++ manufactured from the union of the initial environment and the
- ++ shell variables that are marked for export. */
- ++char **export_env = (char **)NULL;
- ++static int export_env_index;
- ++static int export_env_size;
- ++
- ++#if defined (READLINE)
- ++static int winsize_assignment; /* currently assigning to LINES or COLUMNS */
- ++#endif
- ++
- ++static HASH_TABLE *last_table_searched; /* hash_lookup sets this */
- ++
- ++/* Some forward declarations. */
- ++static void create_variable_tables __P((void));
- ++
- ++static void set_machine_vars __P((void));
- ++static void set_home_var __P((void));
- ++static void set_shell_var __P((void));
- ++static char *get_bash_name __P((void));
- ++static void initialize_shell_level __P((void));
- ++static void uidset __P((void));
- ++#if defined (ARRAY_VARS)
- ++static void make_vers_array __P((void));
- ++#endif
- ++
- ++static SHELL_VAR *null_assign __P((SHELL_VAR *, char *, arrayind_t, char *));
- ++#if defined (ARRAY_VARS)
- ++static SHELL_VAR *null_array_assign __P((SHELL_VAR *, char *, arrayind_t, char *));
- ++#endif
- ++static SHELL_VAR *get_self __P((SHELL_VAR *));
- ++
- ++#if defined (ARRAY_VARS)
- ++static SHELL_VAR *init_dynamic_array_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int));
- ++static SHELL_VAR *init_dynamic_assoc_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int));
- ++#endif
- ++
- ++static SHELL_VAR *assign_seconds __P((SHELL_VAR *, char *, arrayind_t, char *));
- ++static SHELL_VAR *get_seconds __P((SHELL_VAR *));
- ++static SHELL_VAR *init_seconds_var __P((void));
- ++
- ++static int brand __P((void));
- ++static void sbrand __P((unsigned long)); /* set bash random number generator. */
- ++static void seedrand __P((void)); /* seed generator randomly */
- ++static SHELL_VAR *assign_random __P((SHELL_VAR *, char *, arrayind_t, char *));
- ++static SHELL_VAR *get_random __P((SHELL_VAR *));
- ++
- ++static SHELL_VAR *assign_lineno __P((SHELL_VAR *, char *, arrayind_t, char *));
- ++static SHELL_VAR *get_lineno __P((SHELL_VAR *));
- ++
- ++static SHELL_VAR *assign_subshell __P((SHELL_VAR *, char *, arrayind_t, char *));
- ++static SHELL_VAR *get_subshell __P((SHELL_VAR *));
- ++
- ++static SHELL_VAR *get_bashpid __P((SHELL_VAR *));
- ++
- ++#if defined (HISTORY)
- ++static SHELL_VAR *get_histcmd __P((SHELL_VAR *));
- ++#endif
- ++
- ++#if defined (READLINE)
- ++static SHELL_VAR *get_comp_wordbreaks __P((SHELL_VAR *));
- ++static SHELL_VAR *assign_comp_wordbreaks __P((SHELL_VAR *, char *, arrayind_t, char *));
- ++#endif
- ++
- ++#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
- ++static SHELL_VAR *assign_dirstack __P((SHELL_VAR *, char *, arrayind_t, char *));
- ++static SHELL_VAR *get_dirstack __P((SHELL_VAR *));
- ++#endif
- ++
- ++#if defined (ARRAY_VARS)
- ++static SHELL_VAR *get_groupset __P((SHELL_VAR *));
- ++
- ++static SHELL_VAR *build_hashcmd __P((SHELL_VAR *));
- ++static SHELL_VAR *get_hashcmd __P((SHELL_VAR *));
- ++static SHELL_VAR *assign_hashcmd __P((SHELL_VAR *, char *, arrayind_t, char *));
- ++# if defined (ALIAS)
- ++static SHELL_VAR *build_aliasvar __P((SHELL_VAR *));
- ++static SHELL_VAR *get_aliasvar __P((SHELL_VAR *));
- ++static SHELL_VAR *assign_aliasvar __P((SHELL_VAR *, char *, arrayind_t, char *));
- ++# endif
- ++#endif
- ++
- ++static SHELL_VAR *get_funcname __P((SHELL_VAR *));
- ++static SHELL_VAR *init_funcname_var __P((void));
- ++
- ++static void initialize_dynamic_variables __P((void));
- ++
- ++static SHELL_VAR *hash_lookup __P((const char *, HASH_TABLE *));
- ++static SHELL_VAR *new_shell_variable __P((const char *));
- ++static SHELL_VAR *make_new_variable __P((const char *, HASH_TABLE *));
- ++static SHELL_VAR *bind_variable_internal __P((const char *, char *, HASH_TABLE *, int, int));
- ++
- ++static void dispose_variable_value __P((SHELL_VAR *));
- ++static void free_variable_hash_data __P((PTR_T));
- ++
- ++static VARLIST *vlist_alloc __P((int));
- ++static VARLIST *vlist_realloc __P((VARLIST *, int));
- ++static void vlist_add __P((VARLIST *, SHELL_VAR *, int));
- ++
- ++static void flatten __P((HASH_TABLE *, sh_var_map_func_t *, VARLIST *, int));
- ++
- ++static int qsort_var_comp __P((SHELL_VAR **, SHELL_VAR **));
- ++
- ++static SHELL_VAR **vapply __P((sh_var_map_func_t *));
- ++static SHELL_VAR **fapply __P((sh_var_map_func_t *));
- ++
- ++static int visible_var __P((SHELL_VAR *));
- ++static int visible_and_exported __P((SHELL_VAR *));
- ++static int export_environment_candidate __P((SHELL_VAR *));
- ++static int local_and_exported __P((SHELL_VAR *));
- ++static int variable_in_context __P((SHELL_VAR *));
- ++#if defined (ARRAY_VARS)
- ++static int visible_array_vars __P((SHELL_VAR *));
- ++#endif
- ++
- ++static SHELL_VAR *find_nameref_at_context __P((SHELL_VAR *, VAR_CONTEXT *));
- ++static SHELL_VAR *find_variable_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **));
- ++static SHELL_VAR *find_variable_last_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **));
- ++
- ++static SHELL_VAR *bind_tempenv_variable __P((const char *, char *));
- ++static void push_temp_var __P((PTR_T));
- ++static void propagate_temp_var __P((PTR_T));
- ++static void dispose_temporary_env __P((sh_free_func_t *));
- ++
- ++static inline char *mk_env_string __P((const char *, const char *, int));
- ++static char **make_env_array_from_var_list __P((SHELL_VAR **));
- ++static char **make_var_export_array __P((VAR_CONTEXT *));
- ++static char **make_func_export_array __P((void));
- ++static void add_temp_array_to_env __P((char **, int, int));
- ++
- ++static int n_shell_variables __P((void));
- ++static int set_context __P((SHELL_VAR *));
- ++
- ++static void push_func_var __P((PTR_T));
- ++static void push_exported_var __P((PTR_T));
- ++
- ++static inline int find_special_var __P((const char *));
- ++
- ++static void
- ++create_variable_tables ()
- ++{
- ++ if (shell_variables == 0)
- ++ {
- ++ shell_variables = global_variables = new_var_context ((char *)NULL, 0);
- ++ shell_variables->scope = 0;
- ++ shell_variables->table = hash_create (0);
- ++ }
- ++
- ++ if (shell_functions == 0)
- ++ shell_functions = hash_create (0);
- ++
- ++#if defined (DEBUGGER)
- ++ if (shell_function_defs == 0)
- ++ shell_function_defs = hash_create (0);
- ++#endif
- ++}
- ++
- ++/* Initialize the shell variables from the current environment.
- ++ If PRIVMODE is nonzero, don't import functions from ENV or
- ++ parse $SHELLOPTS. */
- ++void
- ++initialize_shell_variables (env, privmode)
- ++ char **env;
- ++ int privmode;
- ++{
- ++ char *name, *string, *temp_string;
- ++ int c, char_index, string_index, string_length, ro;
- ++ SHELL_VAR *temp_var;
- ++
- ++ create_variable_tables ();
- ++
- ++ for (string_index = 0; string = env[string_index++]; )
- ++ {
- ++ char_index = 0;
- ++ name = string;
- ++ while ((c = *string++) && c != '=')
- ++ ;
- ++ if (string[-1] == '=')
- ++ char_index = string - name - 1;
- ++
- ++ /* If there are weird things in the environment, like `=xxx' or a
- ++ string without an `=', just skip them. */
- ++ if (char_index == 0)
- ++ continue;
- ++
- ++ /* ASSERT(name[char_index] == '=') */
- ++ name[char_index] = '\0';
- ++ /* Now, name = env variable name, string = env variable value, and
- ++ char_index == strlen (name) */
- ++
- ++ temp_var = (SHELL_VAR *)NULL;
- ++
- ++ /* If exported function, define it now. Don't import functions from
- ++ the environment in privileged mode. */
- ++ if (privmode == 0 && read_but_dont_execute == 0 &&
- ++ STREQN (BASHFUNC_PREFIX, name, BASHFUNC_PREFLEN) &&
- ++ STREQ (BASHFUNC_SUFFIX, name + char_index - BASHFUNC_SUFFLEN) &&
- ++ STREQN ("() {", string, 4))
- ++ {
- ++ size_t namelen;
- ++ char *tname; /* desired imported function name */
- ++
- ++ namelen = char_index - BASHFUNC_PREFLEN - BASHFUNC_SUFFLEN;
- ++
- ++ tname = name + BASHFUNC_PREFLEN; /* start of func name */
- ++ tname[namelen] = '\0'; /* now tname == func name */
- ++
- ++ string_length = strlen (string);
- ++ temp_string = (char *)xmalloc (namelen + string_length + 2);
- ++
- ++ memcpy (temp_string, tname, namelen);
- ++ temp_string[namelen] = ' ';
- ++ memcpy (temp_string + namelen + 1, string, string_length + 1);
- ++
- ++ /* Don't import function names that are invalid identifiers from the
- ++ environment, though we still allow them to be defined as shell
- ++ variables. */
- ++ if (absolute_program (tname) == 0 && (posixly_correct == 0 || legal_identifier (tname)))
- ++ parse_and_execute (temp_string, tname, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
- ++
- ++ if (temp_var = find_function (tname))
- ++ {
- ++ VSETATTR (temp_var, (att_exported|att_imported));
- ++ array_needs_making = 1;
- ++ }
- ++ else
- ++ {
- ++ if (temp_var = bind_variable (name, string, 0))
- ++ {
- ++ VSETATTR (temp_var, (att_exported | att_imported | att_invisible));
- ++ array_needs_making = 1;
- ++ }
- ++ last_command_exit_value = 1;
- ++ report_error (_("error importing function definition for `%s'"), tname);
- ++ }
- ++
- ++ /* Restore original suffix */
- ++ tname[namelen] = BASHFUNC_SUFFIX[0];
- ++ }
- ++#if defined (ARRAY_VARS)
- ++# if ARRAY_EXPORT
- ++ /* Array variables may not yet be exported. */
- ++ else if (*string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')')
- ++ {
- ++ string_length = 1;
- ++ temp_string = extract_array_assignment_list (string, &string_length);
- ++ temp_var = assign_array_from_string (name, temp_string);
- ++ FREE (temp_string);
- ++ VSETATTR (temp_var, (att_exported | att_imported));
- ++ array_needs_making = 1;
- ++ }
- ++# endif /* ARRAY_EXPORT */
- ++#endif
- ++#if 0
- ++ else if (legal_identifier (name))
- ++#else
- ++ else
- ++#endif
- ++ {
- ++ ro = 0;
- ++ if (posixly_correct && STREQ (name, "SHELLOPTS"))
- ++ {
- ++ temp_var = find_variable ("SHELLOPTS");
- ++ ro = temp_var && readonly_p (temp_var);
- ++ if (temp_var)
- ++ VUNSETATTR (temp_var, att_readonly);
- ++ }
- ++ temp_var = bind_variable (name, string, 0);
- ++ if (temp_var)
- ++ {
- ++ if (legal_identifier (name))
- ++ VSETATTR (temp_var, (att_exported | att_imported));
- ++ else
- ++ VSETATTR (temp_var, (att_exported | att_imported | att_invisible));
- ++ if (ro)
- ++ VSETATTR (temp_var, att_readonly);
- ++ array_needs_making = 1;
- ++ }
- ++ }
- ++
- ++ name[char_index] = '=';
- ++ /* temp_var can be NULL if it was an exported function with a syntax
- ++ error (a different bug, but it still shouldn't dump core). */
- ++ if (temp_var && function_p (temp_var) == 0) /* XXX not yet */
- ++ {
- ++ CACHE_IMPORTSTR (temp_var, name);
- ++ }
- ++ }
- ++
- ++ set_pwd ();
- ++
- ++ /* Set up initial value of $_ */
- ++ temp_var = set_if_not ("_", dollar_vars[0]);
- ++
- ++ /* Remember this pid. */
- ++ dollar_dollar_pid = getpid ();
- ++
- ++ /* Now make our own defaults in case the vars that we think are
- ++ important are missing. */
- ++ temp_var = set_if_not ("PATH", DEFAULT_PATH_VALUE);
- ++#if 0
- ++ set_auto_export (temp_var); /* XXX */
- ++#endif
- ++
- ++ temp_var = set_if_not ("TERM", "dumb");
- ++#if 0
- ++ set_auto_export (temp_var); /* XXX */
- ++#endif
- ++
- ++#if defined (__QNX__)
- ++ /* set node id -- don't import it from the environment */
- ++ {
- ++ char node_name[22];
- ++# if defined (__QNXNTO__)
- ++ netmgr_ndtostr(ND2S_LOCAL_STR, ND_LOCAL_NODE, node_name, sizeof(node_name));
- ++# else
- ++ qnx_nidtostr (getnid (), node_name, sizeof (node_name));
- ++# endif
- ++ temp_var = bind_variable ("NODE", node_name, 0);
- ++ set_auto_export (temp_var);
- ++ }
- ++#endif
- ++
- ++ /* set up the prompts. */
- ++ if (interactive_shell)
- ++ {
- ++#if defined (PROMPT_STRING_DECODE)
- ++ set_if_not ("PS1", primary_prompt);
- ++#else
- ++ if (current_user.uid == -1)
- ++ get_current_user_info ();
- ++ set_if_not ("PS1", current_user.euid == 0 ? "# " : primary_prompt);
- ++#endif
- ++ set_if_not ("PS2", secondary_prompt);
- ++ }
- ++ set_if_not ("PS4", "+ ");
- ++
- ++ /* Don't allow IFS to be imported from the environment. */
- ++ temp_var = bind_variable ("IFS", " \t\n", 0);
- ++ setifs (temp_var);
- ++
- ++ /* Magic machine types. Pretty convenient. */
- ++ set_machine_vars ();
- ++
- ++ /* Default MAILCHECK for interactive shells. Defer the creation of a
- ++ default MAILPATH until the startup files are read, because MAIL
- ++ names a mail file if MAILPATH is not set, and we should provide a
- ++ default only if neither is set. */
- ++ if (interactive_shell)
- ++ {
- ++ temp_var = set_if_not ("MAILCHECK", posixly_correct ? "600" : "60");
- ++ VSETATTR (temp_var, att_integer);
- ++ }
- ++
- ++ /* Do some things with shell level. */
- ++ initialize_shell_level ();
- ++
- ++ set_ppid ();
- ++
- ++ /* Initialize the `getopts' stuff. */
- ++ temp_var = bind_variable ("OPTIND", "1", 0);
- ++ VSETATTR (temp_var, att_integer);
- ++ getopts_reset (0);
- ++ bind_variable ("OPTERR", "1", 0);
- ++ sh_opterr = 1;
- ++
- ++ if (login_shell == 1 && posixly_correct == 0)
- ++ set_home_var ();
- ++
- ++ /* Get the full pathname to THIS shell, and set the BASH variable
- ++ to it. */
- ++ name = get_bash_name ();
- ++ temp_var = bind_variable ("BASH", name, 0);
- ++ free (name);
- ++
- ++ /* Make the exported environment variable SHELL be the user's login
- ++ shell. Note that the `tset' command looks at this variable
- ++ to determine what style of commands to output; if it ends in "csh",
- ++ then C-shell commands are output, else Bourne shell commands. */
- ++ set_shell_var ();
- ++
- ++ /* Make a variable called BASH_VERSION which contains the version info. */
- ++ bind_variable ("BASH_VERSION", shell_version_string (), 0);
- ++#if defined (ARRAY_VARS)
- ++ make_vers_array ();
- ++#endif
- ++
- ++ if (command_execution_string)
- ++ bind_variable ("BASH_EXECUTION_STRING", command_execution_string, 0);
- ++
- ++ /* Find out if we're supposed to be in Posix.2 mode via an
- ++ environment variable. */
- ++ temp_var = find_variable ("POSIXLY_CORRECT");
- ++ if (!temp_var)
- ++ temp_var = find_variable ("POSIX_PEDANTIC");
- ++ if (temp_var && imported_p (temp_var))
- ++ sv_strict_posix (temp_var->name);
- ++
- ++#if defined (HISTORY)
- ++ /* Set history variables to defaults, and then do whatever we would
- ++ do if the variable had just been set. Do this only in the case
- ++ that we are remembering commands on the history list. */
- ++ if (remember_on_history)
- ++ {
- ++ name = bash_tilde_expand (posixly_correct ? "~/.sh_history" : "~/.bash_history", 0);
- ++
- ++ set_if_not ("HISTFILE", name);
- ++ free (name);
- ++ }
- ++#endif /* HISTORY */
- ++
- ++ /* Seed the random number generator. */
- ++ seedrand ();
- ++
- ++ /* Handle some "special" variables that we may have inherited from a
- ++ parent shell. */
- ++ if (interactive_shell)
- ++ {
- ++ temp_var = find_variable ("IGNOREEOF");
- ++ if (!temp_var)
- ++ temp_var = find_variable ("ignoreeof");
- ++ if (temp_var && imported_p (temp_var))
- ++ sv_ignoreeof (temp_var->name);
- ++ }
- ++
- ++#if defined (HISTORY)
- ++ if (interactive_shell && remember_on_history)
- ++ {
- ++ sv_history_control ("HISTCONTROL");
- ++ sv_histignore ("HISTIGNORE");
- ++ sv_histtimefmt ("HISTTIMEFORMAT");
- ++ }
- ++#endif /* HISTORY */
- ++
- ++#if defined (READLINE) && defined (STRICT_POSIX)
- ++ /* POSIXLY_CORRECT will only be 1 here if the shell was compiled
- ++ -DSTRICT_POSIX */
- ++ if (interactive_shell && posixly_correct && no_line_editing == 0)
- ++ rl_prefer_env_winsize = 1;
- ++#endif /* READLINE && STRICT_POSIX */
- ++
- ++ /*
- ++ * 24 October 2001
- ++ *
- ++ * I'm tired of the arguing and bug reports. Bash now leaves SSH_CLIENT
- ++ * and SSH2_CLIENT alone. I'm going to rely on the shell_level check in
- ++ * isnetconn() to avoid running the startup files more often than wanted.
- ++ * That will, of course, only work if the user's login shell is bash, so
- ++ * I've made that behavior conditional on SSH_SOURCE_BASHRC being defined
- ++ * in config-top.h.
- ++ */
- ++#if 0
- ++ temp_var = find_variable ("SSH_CLIENT");
- ++ if (temp_var && imported_p (temp_var))
- ++ {
- ++ VUNSETATTR (temp_var, att_exported);
- ++ array_needs_making = 1;
- ++ }
- ++ temp_var = find_variable ("SSH2_CLIENT");
- ++ if (temp_var && imported_p (temp_var))
- ++ {
- ++ VUNSETATTR (temp_var, att_exported);
- ++ array_needs_making = 1;
- ++ }
- ++#endif
- ++
- ++ /* Get the user's real and effective user ids. */
- ++ uidset ();
- ++
- ++ temp_var = find_variable ("BASH_XTRACEFD");
- ++ if (temp_var && imported_p (temp_var))
- ++ sv_xtracefd (temp_var->name);
- ++
- ++ /* Initialize the dynamic variables, and seed their values. */
- ++ initialize_dynamic_variables ();
- ++}
- ++
- ++/* **************************************************************** */
- ++/* */
- ++/* Setting values for special shell variables */
- ++/* */
- ++/* **************************************************************** */
- ++
- ++static void
- ++set_machine_vars ()
- ++{
- ++ SHELL_VAR *temp_var;
- ++
- ++ temp_var = set_if_not ("HOSTTYPE", HOSTTYPE);
- ++ temp_var = set_if_not ("OSTYPE", OSTYPE);
- ++ temp_var = set_if_not ("MACHTYPE", MACHTYPE);
- ++
- ++ temp_var = set_if_not ("HOSTNAME", current_host_name);
- ++}
- ++
- ++/* Set $HOME to the information in the password file if we didn't get
- ++ it from the environment. */
- ++
- ++/* This function is not static so the tilde and readline libraries can
- ++ use it. */
- ++char *
- ++sh_get_home_dir ()
- ++{
- ++ if (current_user.home_dir == 0)
- ++ get_current_user_info ();
- ++ return current_user.home_dir;
- ++}
- ++
- ++static void
- ++set_home_var ()
- ++{
- ++ SHELL_VAR *temp_var;
- ++
- ++ temp_var = find_variable ("HOME");
- ++ if (temp_var == 0)
- ++ temp_var = bind_variable ("HOME", sh_get_home_dir (), 0);
- ++#if 0
- ++ VSETATTR (temp_var, att_exported);
- ++#endif
- ++}
- ++
- ++/* Set $SHELL to the user's login shell if it is not already set. Call
- ++ get_current_user_info if we haven't already fetched the shell. */
- ++static void
- ++set_shell_var ()
- ++{
- ++ SHELL_VAR *temp_var;
- ++
- ++ temp_var = find_variable ("SHELL");
- ++ if (temp_var == 0)
- ++ {
- ++ if (current_user.shell == 0)
- ++ get_current_user_info ();
- ++ temp_var = bind_variable ("SHELL", current_user.shell, 0);
- ++ }
- ++#if 0
- ++ VSETATTR (temp_var, att_exported);
- ++#endif
- ++}
- ++
- ++static char *
- ++get_bash_name ()
- ++{
- ++ char *name;
- ++
- ++ if ((login_shell == 1) && RELPATH(shell_name))
- ++ {
- ++ if (current_user.shell == 0)
- ++ get_current_user_info ();
- ++ name = savestring (current_user.shell);
- ++ }
- ++ else if (ABSPATH(shell_name))
- ++ name = savestring (shell_name);
- ++ else if (shell_name[0] == '.' && shell_name[1] == '/')
- ++ {
- ++ /* Fast path for common case. */
- ++ char *cdir;
- ++ int len;
- ++
- ++ cdir = get_string_value ("PWD");
- ++ if (cdir)
- ++ {
- ++ len = strlen (cdir);
- ++ name = (char *)xmalloc (len + strlen (shell_name) + 1);
- ++ strcpy (name, cdir);
- ++ strcpy (name + len, shell_name + 1);
- ++ }
- ++ else
- ++ name = savestring (shell_name);
- ++ }
- ++ else
- ++ {
- ++ char *tname;
- ++ int s;
- ++
- ++ tname = find_user_command (shell_name);
- ++
- ++ if (tname == 0)
- ++ {
- ++ /* Try the current directory. If there is not an executable
- ++ there, just punt and use the login shell. */
- ++ s = file_status (shell_name);
- ++ if (s & FS_EXECABLE)
- ++ {
- ++ tname = make_absolute (shell_name, get_string_value ("PWD"));
- ++ if (*shell_name == '.')
- ++ {
- ++ name = sh_canonpath (tname, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
- ++ if (name == 0)
- ++ name = tname;
- ++ else
- ++ free (tname);
- ++ }
- ++ else
- ++ name = tname;
- ++ }
- ++ else
- ++ {
- ++ if (current_user.shell == 0)
- ++ get_current_user_info ();
- ++ name = savestring (current_user.shell);
- ++ }
- ++ }
- ++ else
- ++ {
- ++ name = full_pathname (tname);
- ++ free (tname);
- ++ }
- ++ }
- ++
- ++ return (name);
- ++}
- ++
- ++void
- ++adjust_shell_level (change)
- ++ int change;
- ++{
- ++ char new_level[5], *old_SHLVL;
- ++ intmax_t old_level;
- ++ SHELL_VAR *temp_var;
- ++
- ++ old_SHLVL = get_string_value ("SHLVL");
- ++ if (old_SHLVL == 0 || *old_SHLVL == '\0' || legal_number (old_SHLVL, &old_level) == 0)
- ++ old_level = 0;
- ++
- ++ shell_level = old_level + change;
- ++ if (shell_level < 0)
- ++ shell_level = 0;
- ++ else if (shell_level > 1000)
- ++ {
- ++ internal_warning (_("shell level (%d) too high, resetting to 1"), shell_level);
- ++ shell_level = 1;
- ++ }
- ++
- ++ /* We don't need the full generality of itos here. */
- ++ if (shell_level < 10)
- ++ {
- ++ new_level[0] = shell_level + '0';
- ++ new_level[1] = '\0';
- ++ }
- ++ else if (shell_level < 100)
- ++ {
- ++ new_level[0] = (shell_level / 10) + '0';
- ++ new_level[1] = (shell_level % 10) + '0';
- ++ new_level[2] = '\0';
- ++ }
- ++ else if (shell_level < 1000)
- ++ {
- ++ new_level[0] = (shell_level / 100) + '0';
- ++ old_level = shell_level % 100;
- ++ new_level[1] = (old_level / 10) + '0';
- ++ new_level[2] = (old_level % 10) + '0';
- ++ new_level[3] = '\0';
- ++ }
- ++
- ++ temp_var = bind_variable ("SHLVL", new_level, 0);
- ++ set_auto_export (temp_var);
- ++}
- ++
- ++static void
- ++initialize_shell_level ()
- ++{
- ++ adjust_shell_level (1);
- ++}
- ++
- ++/* If we got PWD from the environment, update our idea of the current
- ++ working directory. In any case, make sure that PWD exists before
- ++ checking it. It is possible for getcwd () to fail on shell startup,
- ++ and in that case, PWD would be undefined. If this is an interactive
- ++ login shell, see if $HOME is the current working directory, and if
- ++ that's not the same string as $PWD, set PWD=$HOME. */
- ++
- ++void
- ++set_pwd ()
- ++{
- ++ SHELL_VAR *temp_var, *home_var;
- ++ char *temp_string, *home_string;
- ++
- ++ home_var = find_variable ("HOME");
- ++ home_string = home_var ? value_cell (home_var) : (char *)NULL;
- ++
- ++ temp_var = find_variable ("PWD");
- ++ if (temp_var && imported_p (temp_var) &&
- ++ (temp_string = value_cell (temp_var)) &&
- ++ same_file (temp_string, ".", (struct stat *)NULL, (struct stat *)NULL))
- ++ set_working_directory (temp_string);
- ++ else if (home_string && interactive_shell && login_shell &&
- ++ same_file (home_string, ".", (struct stat *)NULL, (struct stat *)NULL))
- ++ {
- ++ set_working_directory (home_string);
- ++ temp_var = bind_variable ("PWD", home_string, 0);
- ++ set_auto_export (temp_var);
- ++ }
- ++ else
- ++ {
- ++ temp_string = get_working_directory ("shell-init");
- ++ if (temp_string)
- ++ {
- ++ temp_var = bind_variable ("PWD", temp_string, 0);
- ++ set_auto_export (temp_var);
- ++ free (temp_string);
- ++ }
- ++ }
- ++
- ++ /* According to the Single Unix Specification, v2, $OLDPWD is an
- ++ `environment variable' and therefore should be auto-exported.
- ++ Make a dummy invisible variable for OLDPWD, and mark it as exported. */
- ++ temp_var = bind_variable ("OLDPWD", (char *)NULL, 0);
- ++ VSETATTR (temp_var, (att_exported | att_invisible));
- ++}
- ++
- ++/* Make a variable $PPID, which holds the pid of the shell's parent. */
- ++void
- ++set_ppid ()
- ++{
- ++ char namebuf[INT_STRLEN_BOUND(pid_t) + 1], *name;
- ++ SHELL_VAR *temp_var;
- ++
- ++ name = inttostr (getppid (), namebuf, sizeof(namebuf));
- ++ temp_var = find_variable ("PPID");
- ++ if (temp_var)
- ++ VUNSETATTR (temp_var, (att_readonly | att_exported));
- ++ temp_var = bind_variable ("PPID", name, 0);
- ++ VSETATTR (temp_var, (att_readonly | att_integer));
- ++}
- ++
- ++static void
- ++uidset ()
- ++{
- ++ char buff[INT_STRLEN_BOUND(uid_t) + 1], *b;
- ++ register SHELL_VAR *v;
- ++
- ++ b = inttostr (current_user.uid, buff, sizeof (buff));
- ++ v = find_variable ("UID");
- ++ if (v == 0)
- ++ {
- ++ v = bind_variable ("UID", b, 0);
- ++ VSETATTR (v, (att_readonly | att_integer));
- ++ }
- ++
- ++ if (current_user.euid != current_user.uid)
- ++ b = inttostr (current_user.euid, buff, sizeof (buff));
- ++
- ++ v = find_variable ("EUID");
- ++ if (v == 0)
- ++ {
- ++ v = bind_variable ("EUID", b, 0);
- ++ VSETATTR (v, (att_readonly | att_integer));
- ++ }
- ++}
- ++
- ++#if defined (ARRAY_VARS)
- ++static void
- ++make_vers_array ()
- ++{
- ++ SHELL_VAR *vv;
- ++ ARRAY *av;
- ++ char *s, d[32], b[INT_STRLEN_BOUND(int) + 1];
- ++
- ++ unbind_variable ("BASH_VERSINFO");
- ++
- ++ vv = make_new_array_variable ("BASH_VERSINFO");
- ++ av = array_cell (vv);
- ++ strcpy (d, dist_version);
- ++ s = strchr (d, '.');
- ++ if (s)
- ++ *s++ = '\0';
- ++ array_insert (av, 0, d);
- ++ array_insert (av, 1, s);
- ++ s = inttostr (patch_level, b, sizeof (b));
- ++ array_insert (av, 2, s);
- ++ s = inttostr (build_version, b, sizeof (b));
- ++ array_insert (av, 3, s);
- ++ array_insert (av, 4, release_status);
- ++ array_insert (av, 5, MACHTYPE);
- ++
- ++ VSETATTR (vv, att_readonly);
- ++}
- ++#endif /* ARRAY_VARS */
- ++
- ++/* Set the environment variables $LINES and $COLUMNS in response to
- ++ a window size change. */
- ++void
- ++sh_set_lines_and_columns (lines, cols)
- ++ int lines, cols;
- ++{
- ++ char val[INT_STRLEN_BOUND(int) + 1], *v;
- ++
- ++#if defined (READLINE)
- ++ /* If we are currently assigning to LINES or COLUMNS, don't do anything. */
- ++ if (winsize_assignment)
- ++ return;
- ++#endif
- ++
- ++ v = inttostr (lines, val, sizeof (val));
- ++ bind_variable ("LINES", v, 0);
- ++
- ++ v = inttostr (cols, val, sizeof (val));
- ++ bind_variable ("COLUMNS", v, 0);
- ++}
- ++
- ++/* **************************************************************** */
- ++/* */
- ++/* Printing variables and values */
- ++/* */
- ++/* **************************************************************** */
- ++
- ++/* Print LIST (a list of shell variables) to stdout in such a way that
- ++ they can be read back in. */
- ++void
- ++print_var_list (list)
- ++ register SHELL_VAR **list;
- ++{
- ++ register int i;
- ++ register SHELL_VAR *var;
- ++
- ++ for (i = 0; list && (var = list[i]); i++)
- ++ if (invisible_p (var) == 0)
- ++ print_assignment (var);
- ++}
- ++
- ++/* Print LIST (a list of shell functions) to stdout in such a way that
- ++ they can be read back in. */
- ++void
- ++print_func_list (list)
- ++ register SHELL_VAR **list;
- ++{
- ++ register int i;
- ++ register SHELL_VAR *var;
- ++
- ++ for (i = 0; list && (var = list[i]); i++)
- ++ {
- ++ printf ("%s ", var->name);
- ++ print_var_function (var);
- ++ printf ("\n");
- ++ }
- ++}
- ++
- ++/* Print the value of a single SHELL_VAR. No newline is
- ++ output, but the variable is printed in such a way that
- ++ it can be read back in. */
- ++void
- ++print_assignment (var)
- ++ SHELL_VAR *var;
- ++{
- ++ if (var_isset (var) == 0)
- ++ return;
- ++
- ++ if (function_p (var))
- ++ {
- ++ printf ("%s", var->name);
- ++ print_var_function (var);
- ++ printf ("\n");
- ++ }
- ++#if defined (ARRAY_VARS)
- ++ else if (array_p (var))
- ++ print_array_assignment (var, 0);
- ++ else if (assoc_p (var))
- ++ print_assoc_assignment (var, 0);
- ++#endif /* ARRAY_VARS */
- ++ else
- ++ {
- ++ printf ("%s=", var->name);
- ++ print_var_value (var, 1);
- ++ printf ("\n");
- ++ }
- ++}
- ++
- ++/* Print the value cell of VAR, a shell variable. Do not print
- ++ the name, nor leading/trailing newline. If QUOTE is non-zero,
- ++ and the value contains shell metacharacters, quote the value
- ++ in such a way that it can be read back in. */
- ++void
- ++print_var_value (var, quote)
- ++ SHELL_VAR *var;
- ++ int quote;
- ++{
- ++ char *t;
- ++
- ++ if (var_isset (var) == 0)
- ++ return;
- ++
- ++ if (quote && posixly_correct == 0 && ansic_shouldquote (value_cell (var)))
- ++ {
- ++ t = ansic_quote (value_cell (var), 0, (int *)0);
- ++ printf ("%s", t);
- ++ free (t);
- ++ }
- ++ else if (quote && sh_contains_shell_metas (value_cell (var)))
- ++ {
- ++ t = sh_single_quote (value_cell (var));
- ++ printf ("%s", t);
- ++ free (t);
- ++ }
- ++ else
- ++ printf ("%s", value_cell (var));
- ++}
- ++
- ++/* Print the function cell of VAR, a shell variable. Do not
- ++ print the name, nor leading/trailing newline. */
- ++void
- ++print_var_function (var)
- ++ SHELL_VAR *var;
- ++{
- ++ char *x;
- ++
- ++ if (function_p (var) && var_isset (var))
- ++ {
- ++ x = named_function_string ((char *)NULL, function_cell(var), FUNC_MULTILINE|FUNC_EXTERNAL);
- ++ printf ("%s", x);
- ++ }
- ++}
- ++
- ++/* **************************************************************** */
- ++/* */
- ++/* Dynamic Variables */
- ++/* */
- ++/* **************************************************************** */
- ++
- ++/* DYNAMIC VARIABLES
- ++
- ++ These are variables whose values are generated anew each time they are
- ++ referenced. These are implemented using a pair of function pointers
- ++ in the struct variable: assign_func, which is called from bind_variable
- ++ and, if arrays are compiled into the shell, some of the functions in
- ++ arrayfunc.c, and dynamic_value, which is called from find_variable.
- ++
- ++ assign_func is called from bind_variable_internal, if
- ++ bind_variable_internal discovers that the variable being assigned to
- ++ has such a function. The function is called as
- ++ SHELL_VAR *temp = (*(entry->assign_func)) (entry, value, ind)
- ++ and the (SHELL_VAR *)temp is returned as the value of bind_variable. It
- ++ is usually ENTRY (self). IND is an index for an array variable, and
- ++ unused otherwise.
- ++
- ++ dynamic_value is called from find_variable_internal to return a `new'
- ++ value for the specified dynamic varible. If this function is NULL,
- ++ the variable is treated as a `normal' shell variable. If it is not,
- ++ however, then this function is called like this:
- ++ tempvar = (*(var->dynamic_value)) (var);
- ++
- ++ Sometimes `tempvar' will replace the value of `var'. Other times, the
- ++ shell will simply use the string value. Pretty object-oriented, huh?
- ++
- ++ Be warned, though: if you `unset' a special variable, it loses its
- ++ special meaning, even if you subsequently set it.
- ++
- ++ The special assignment code would probably have been better put in
- ++ subst.c: do_assignment_internal, in the same style as
- ++ stupidly_hack_special_variables, but I wanted the changes as
- ++ localized as possible. */
- ++
- ++#define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \
- ++ do \
- ++ { \
- ++ v = bind_variable (var, (val), 0); \
- ++ v->dynamic_value = gfunc; \
- ++ v->assign_func = afunc; \
- ++ } \
- ++ while (0)
- ++
- ++#define INIT_DYNAMIC_ARRAY_VAR(var, gfunc, afunc) \
- ++ do \
- ++ { \
- ++ v = make_new_array_variable (var); \
- ++ v->dynamic_value = gfunc; \
- ++ v->assign_func = afunc; \
- ++ } \
- ++ while (0)
- ++
- ++#define INIT_DYNAMIC_ASSOC_VAR(var, gfunc, afunc) \
- ++ do \
- ++ { \
- ++ v = make_new_assoc_variable (var); \
- ++ v->dynamic_value = gfunc; \
- ++ v->assign_func = afunc; \
- ++ } \
- ++ while (0)
- ++
- ++static SHELL_VAR *
- ++null_assign (self, value, unused, key)
- ++ SHELL_VAR *self;
- ++ char *value;
- ++ arrayind_t unused;
- ++ char *key;
- ++{
- ++ return (self);
- ++}
- ++
- ++#if defined (ARRAY_VARS)
- ++static SHELL_VAR *
- ++null_array_assign (self, value, ind, key)
- ++ SHELL_VAR *self;
- ++ char *value;
- ++ arrayind_t ind;
- ++ char *key;
- ++{
- ++ return (self);
- ++}
- ++#endif
- ++
- ++/* Degenerate `dynamic_value' function; just returns what's passed without
- ++ manipulation. */
- ++static SHELL_VAR *
- ++get_self (self)
- ++ SHELL_VAR *self;
- ++{
- ++ return (self);
- ++}
- ++
- ++#if defined (ARRAY_VARS)
- ++/* A generic dynamic array variable initializer. Initialize array variable
- ++ NAME with dynamic value function GETFUNC and assignment function SETFUNC. */
- ++static SHELL_VAR *
- ++init_dynamic_array_var (name, getfunc, setfunc, attrs)
- ++ char *name;
- ++ sh_var_value_func_t *getfunc;
- ++ sh_var_assign_func_t *setfunc;
- ++ int attrs;
- ++{
- ++ SHELL_VAR *v;
- ++
- ++ v = find_variable (name);
- ++ if (v)
- ++ return (v);
- ++ INIT_DYNAMIC_ARRAY_VAR (name, getfunc, setfunc);
- ++ if (attrs)
- ++ VSETATTR (v, attrs);
- ++ return v;
- ++}
- ++
- ++static SHELL_VAR *
- ++init_dynamic_assoc_var (name, getfunc, setfunc, attrs)
- ++ char *name;
- ++ sh_var_value_func_t *getfunc;
- ++ sh_var_assign_func_t *setfunc;
- ++ int attrs;
- ++{
- ++ SHELL_VAR *v;
- ++
- ++ v = find_variable (name);
- ++ if (v)
- ++ return (v);
- ++ INIT_DYNAMIC_ASSOC_VAR (name, getfunc, setfunc);
- ++ if (attrs)
- ++ VSETATTR (v, attrs);
- ++ return v;
- ++}
- ++#endif
- ++
- ++/* The value of $SECONDS. This is the number of seconds since shell
- ++ invocation, or, the number of seconds since the last assignment + the
- ++ value of the last assignment. */
- ++static intmax_t seconds_value_assigned;
- ++
- ++static SHELL_VAR *
- ++assign_seconds (self, value, unused, key)
- ++ SHELL_VAR *self;
- ++ char *value;
- ++ arrayind_t unused;
- ++ char *key;
- ++{
- ++ if (legal_number (value, &seconds_value_assigned) == 0)
- ++ seconds_value_assigned = 0;
- ++ shell_start_time = NOW;
- ++ return (self);
- ++}
- ++
- ++static SHELL_VAR *
- ++get_seconds (var)
- ++ SHELL_VAR *var;
- ++{
- ++ time_t time_since_start;
- ++ char *p;
- ++
- ++ time_since_start = NOW - shell_start_time;
- ++ p = itos(seconds_value_assigned + time_since_start);
- ++
- ++ FREE (value_cell (var));
- ++
- ++ VSETATTR (var, att_integer);
- ++ var_setvalue (var, p);
- ++ return (var);
- ++}
- ++
- ++static SHELL_VAR *
- ++init_seconds_var ()
- ++{
- ++ SHELL_VAR *v;
- ++
- ++ v = find_variable ("SECONDS");
- ++ if (v)
- ++ {
- ++ if (legal_number (value_cell(v), &seconds_value_assigned) == 0)
- ++ seconds_value_assigned = 0;
- ++ }
- ++ INIT_DYNAMIC_VAR ("SECONDS", (v ? value_cell (v) : (char *)NULL), get_seconds, assign_seconds);
- ++ return v;
- ++}
- ++
- ++/* The random number seed. You can change this by setting RANDOM. */
- ++static unsigned long rseed = 1;
- ++static int last_random_value;
- ++static int seeded_subshell = 0;
- ++
- ++/* A linear congruential random number generator based on the example
- ++ one in the ANSI C standard. This one isn't very good, but a more
- ++ complicated one is overkill. */
- ++
- ++/* Returns a pseudo-random number between 0 and 32767. */
- ++static int
- ++brand ()
- ++{
- ++ /* From "Random number generators: good ones are hard to find",
- ++ Park and Miller, Communications of the ACM, vol. 31, no. 10,
- ++ October 1988, p. 1195. filtered through FreeBSD */
- ++ long h, l;
- ++
- ++ /* Can't seed with 0. */
- ++ if (rseed == 0)
- ++ rseed = 123459876;
- ++ h = rseed / 127773;
- ++ l = rseed % 127773;
- ++ rseed = 16807 * l - 2836 * h;
- ++#if 0
- ++ if (rseed < 0)
- ++ rseed += 0x7fffffff;
- ++#endif
- ++ return ((unsigned int)(rseed & 32767)); /* was % 32768 */
- ++}
- ++
- ++/* Set the random number generator seed to SEED. */
- ++static void
- ++sbrand (seed)
- ++ unsigned long seed;
- ++{
- ++ rseed = seed;
- ++ last_random_value = 0;
- ++}
- ++
- ++static void
- ++seedrand ()
- ++{
- ++ struct timeval tv;
- ++
- ++ gettimeofday (&tv, NULL);
- ++ sbrand (tv.tv_sec ^ tv.tv_usec ^ getpid ());
- ++}
- ++
- ++static SHELL_VAR *
- ++assign_random (self, value, unused, key)
- ++ SHELL_VAR *self;
- ++ char *value;
- ++ arrayind_t unused;
- ++ char *key;
- ++{
- ++ sbrand (strtoul (value, (char **)NULL, 10));
- ++ if (subshell_environment)
- ++ seeded_subshell = getpid ();
- ++ return (self);
- ++}
- ++
- ++int
- ++get_random_number ()
- ++{
- ++ int rv, pid;
- ++
- ++ /* Reset for command and process substitution. */
- ++ pid = getpid ();
- ++ if (subshell_environment && seeded_subshell != pid)
- ++ {
- ++ seedrand ();
- ++ seeded_subshell = pid;
- ++ }
- ++
- ++ do
- ++ rv = brand ();
- ++ while (rv == last_random_value);
- ++ return rv;
- ++}
- ++
- ++static SHELL_VAR *
- ++get_random (var)
- ++ SHELL_VAR *var;
- ++{
- ++ int rv;
- ++ char *p;
- ++
- ++ rv = get_random_number ();
- ++ last_random_value = rv;
- ++ p = itos (rv);
- ++
- ++ FREE (value_cell (var));
- ++
- ++ VSETATTR (var, att_integer);
- ++ var_setvalue (var, p);
- ++ return (var);
- ++}
- ++
- ++static SHELL_VAR *
- ++assign_lineno (var, value, unused, key)
- ++ SHELL_VAR *var;
- ++ char *value;
- ++ arrayind_t unused;
- ++ char *key;
- ++{
- ++ intmax_t new_value;
- ++
- ++ if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0)
- ++ new_value = 0;
- ++ line_number = line_number_base = new_value;
- ++ return var;
- ++}
- ++
- ++/* Function which returns the current line number. */
- ++static SHELL_VAR *
- ++get_lineno (var)
- ++ SHELL_VAR *var;
- ++{
- ++ char *p;
- ++ int ln;
- ++
- ++ ln = executing_line_number ();
- ++ p = itos (ln);
- ++ FREE (value_cell (var));
- ++ var_setvalue (var, p);
- ++ return (var);
- ++}
- ++
- ++static SHELL_VAR *
- ++assign_subshell (var, value, unused, key)
- ++ SHELL_VAR *var;
- ++ char *value;
- ++ arrayind_t unused;
- ++ char *key;
- ++{
- ++ intmax_t new_value;
- ++
- ++ if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0)
- ++ new_value = 0;
- ++ subshell_level = new_value;
- ++ return var;
- ++}
- ++
- ++static SHELL_VAR *
- ++get_subshell (var)
- ++ SHELL_VAR *var;
- ++{
- ++ char *p;
- ++
- ++ p = itos (subshell_level);
- ++ FREE (value_cell (var));
- ++ var_setvalue (var, p);
- ++ return (var);
- ++}
- ++
- ++static SHELL_VAR *
- ++get_bashpid (var)
- ++ SHELL_VAR *var;
- ++{
- ++ int pid;
- ++ char *p;
- ++
- ++ pid = getpid ();
- ++ p = itos (pid);
- ++
- ++ FREE (value_cell (var));
- ++ VSETATTR (var, att_integer|att_readonly);
- ++ var_setvalue (var, p);
- ++ return (var);
- ++}
- ++
- ++static SHELL_VAR *
- ++get_bash_command (var)
- ++ SHELL_VAR *var;
- ++{
- ++ char *p;
- ++
- ++ if (the_printed_command_except_trap)
- ++ p = savestring (the_printed_command_except_trap);
- ++ else
- ++ {
- ++ p = (char *)xmalloc (1);
- ++ p[0] = '\0';
- ++ }
- ++ FREE (value_cell (var));
- ++ var_setvalue (var, p);
- ++ return (var);
- ++}
- ++
- ++#if defined (HISTORY)
- ++static SHELL_VAR *
- ++get_histcmd (var)
- ++ SHELL_VAR *var;
- ++{
- ++ char *p;
- ++
- ++ p = itos (history_number ());
- ++ FREE (value_cell (var));
- ++ var_setvalue (var, p);
- ++ return (var);
- ++}
- ++#endif
- ++
- ++#if defined (READLINE)
- ++/* When this function returns, VAR->value points to malloced memory. */
- ++static SHELL_VAR *
- ++get_comp_wordbreaks (var)
- ++ SHELL_VAR *var;
- ++{
- ++ /* If we don't have anything yet, assign a default value. */
- ++ if (rl_completer_word_break_characters == 0 && bash_readline_initialized == 0)
- ++ enable_hostname_completion (perform_hostname_completion);
- ++
- ++ FREE (value_cell (var));
- ++ var_setvalue (var, savestring (rl_completer_word_break_characters));
- ++
- ++ return (var);
- ++}
- ++
- ++/* When this function returns, rl_completer_word_break_characters points to
- ++ malloced memory. */
- ++static SHELL_VAR *
- ++assign_comp_wordbreaks (self, value, unused, key)
- ++ SHELL_VAR *self;
- ++ char *value;
- ++ arrayind_t unused;
- ++ char *key;
- ++{
- ++ if (rl_completer_word_break_characters &&
- ++ rl_completer_word_break_characters != rl_basic_word_break_characters)
- ++ free (rl_completer_word_break_characters);
- ++
- ++ rl_completer_word_break_characters = savestring (value);
- ++ return self;
- ++}
- ++#endif /* READLINE */
- ++
- ++#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
- ++static SHELL_VAR *
- ++assign_dirstack (self, value, ind, key)
- ++ SHELL_VAR *self;
- ++ char *value;
- ++ arrayind_t ind;
- ++ char *key;
- ++{
- ++ set_dirstack_element (ind, 1, value);
- ++ return self;
- ++}
- ++
- ++static SHELL_VAR *
- ++get_dirstack (self)
- ++ SHELL_VAR *self;
- ++{
- ++ ARRAY *a;
- ++ WORD_LIST *l;
- ++
- ++ l = get_directory_stack (0);
- ++ a = array_from_word_list (l);
- ++ array_dispose (array_cell (self));
- ++ dispose_words (l);
- ++ var_setarray (self, a);
- ++ return self;
- ++}
- ++#endif /* PUSHD AND POPD && ARRAY_VARS */
- ++
- ++#if defined (ARRAY_VARS)
- ++/* We don't want to initialize the group set with a call to getgroups()
- ++ unless we're asked to, but we only want to do it once. */
- ++static SHELL_VAR *
- ++get_groupset (self)
- ++ SHELL_VAR *self;
- ++{
- ++ register int i;
- ++ int ng;
- ++ ARRAY *a;
- ++ static char **group_set = (char **)NULL;
- ++
- ++ if (group_set == 0)
- ++ {
- ++ group_set = get_group_list (&ng);
- ++ a = array_cell (self);
- ++ for (i = 0; i < ng; i++)
- ++ array_insert (a, i, group_set[i]);
- ++ }
- ++ return (self);
- ++}
- ++
- ++static SHELL_VAR *
- ++build_hashcmd (self)
- ++ SHELL_VAR *self;
- ++{
- ++ HASH_TABLE *h;
- ++ int i;
- ++ char *k, *v;
- ++ BUCKET_CONTENTS *item;
- ++
- ++ h = assoc_cell (self);
- ++ if (h)
- ++ assoc_dispose (h);
- ++
- ++ if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0)
- ++ {
- ++ var_setvalue (self, (char *)NULL);
- ++ return self;
- ++ }
- ++
- ++ h = assoc_create (hashed_filenames->nbuckets);
- ++ for (i = 0; i < hashed_filenames->nbuckets; i++)
- ++ {
- ++ for (item = hash_items (i, hashed_filenames); item; item = item->next)
- ++ {
- ++ k = savestring (item->key);
- ++ v = pathdata(item)->path;
- ++ assoc_insert (h, k, v);
- ++ }
- ++ }
- ++
- ++ var_setvalue (self, (char *)h);
- ++ return self;
- ++}
- ++
- ++static SHELL_VAR *
- ++get_hashcmd (self)
- ++ SHELL_VAR *self;
- ++{
- ++ build_hashcmd (self);
- ++ return (self);
- ++}
- ++
- ++static SHELL_VAR *
- ++assign_hashcmd (self, value, ind, key)
- ++ SHELL_VAR *self;
- ++ char *value;
- ++ arrayind_t ind;
- ++ char *key;
- ++{
- ++ phash_insert (key, value, 0, 0);
- ++ return (build_hashcmd (self));
- ++}
- ++
- ++#if defined (ALIAS)
- ++static SHELL_VAR *
- ++build_aliasvar (self)
- ++ SHELL_VAR *self;
- ++{
- ++ HASH_TABLE *h;
- ++ int i;
- ++ char *k, *v;
- ++ BUCKET_CONTENTS *item;
- ++
- ++ h = assoc_cell (self);
- ++ if (h)
- ++ assoc_dispose (h);
- ++
- ++ if (aliases == 0 || HASH_ENTRIES (aliases) == 0)
- ++ {
- ++ var_setvalue (self, (char *)NULL);
- ++ return self;
- ++ }
- ++
- ++ h = assoc_create (aliases->nbuckets);
- ++ for (i = 0; i < aliases->nbuckets; i++)
- ++ {
- ++ for (item = hash_items (i, aliases); item; item = item->next)
- ++ {
- ++ k = savestring (item->key);
- ++ v = ((alias_t *)(item->data))->value;
- ++ assoc_insert (h, k, v);
- ++ }
- ++ }
- ++
- ++ var_setvalue (self, (char *)h);
- ++ return self;
- ++}
- ++
- ++static SHELL_VAR *
- ++get_aliasvar (self)
- ++ SHELL_VAR *self;
- ++{
- ++ build_aliasvar (self);
- ++ return (self);
- ++}
- ++
- ++static SHELL_VAR *
- ++assign_aliasvar (self, value, ind, key)
- ++ SHELL_VAR *self;
- ++ char *value;
- ++ arrayind_t ind;
- ++ char *key;
- ++{
- ++ add_alias (key, value);
- ++ return (build_aliasvar (self));
- ++}
- ++#endif /* ALIAS */
- ++
- ++#endif /* ARRAY_VARS */
- ++
- ++/* If ARRAY_VARS is not defined, this just returns the name of any
- ++ currently-executing function. If we have arrays, it's a call stack. */
- ++static SHELL_VAR *
- ++get_funcname (self)
- ++ SHELL_VAR *self;
- ++{
- ++#if ! defined (ARRAY_VARS)
- ++ char *t;
- ++ if (variable_context && this_shell_function)
- ++ {
- ++ FREE (value_cell (self));
- ++ t = savestring (this_shell_function->name);
- ++ var_setvalue (self, t);
- ++ }
- ++#endif
- ++ return (self);
- ++}
- ++
- ++void
- ++make_funcname_visible (on_or_off)
- ++ int on_or_off;
- ++{
- ++ SHELL_VAR *v;
- ++
- ++ v = find_variable ("FUNCNAME");
- ++ if (v == 0 || v->dynamic_value == 0)
- ++ return;
- ++
- ++ if (on_or_off)
- ++ VUNSETATTR (v, att_invisible);
- ++ else
- ++ VSETATTR (v, att_invisible);
- ++}
- ++
- ++static SHELL_VAR *
- ++init_funcname_var ()
- ++{
- ++ SHELL_VAR *v;
- ++
- ++ v = find_variable ("FUNCNAME");
- ++ if (v)
- ++ return v;
- ++#if defined (ARRAY_VARS)
- ++ INIT_DYNAMIC_ARRAY_VAR ("FUNCNAME", get_funcname, null_array_assign);
- ++#else
- ++ INIT_DYNAMIC_VAR ("FUNCNAME", (char *)NULL, get_funcname, null_assign);
- ++#endif
- ++ VSETATTR (v, att_invisible|att_noassign);
- ++ return v;
- ++}
- ++
- ++static void
- ++initialize_dynamic_variables ()
- ++{
- ++ SHELL_VAR *v;
- ++
- ++ v = init_seconds_var ();
- ++
- ++ INIT_DYNAMIC_VAR ("BASH_COMMAND", (char *)NULL, get_bash_command, (sh_var_assign_func_t *)NULL);
- ++ INIT_DYNAMIC_VAR ("BASH_SUBSHELL", (char *)NULL, get_subshell, assign_subshell);
- ++
- ++ INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random);
- ++ VSETATTR (v, att_integer);
- ++ INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno);
- ++ VSETATTR (v, att_integer);
- ++
- ++ INIT_DYNAMIC_VAR ("BASHPID", (char *)NULL, get_bashpid, null_assign);
- ++ VSETATTR (v, att_integer|att_readonly);
- ++
- ++#if defined (HISTORY)
- ++ INIT_DYNAMIC_VAR ("HISTCMD", (char *)NULL, get_histcmd, (sh_var_assign_func_t *)NULL);
- ++ VSETATTR (v, att_integer);
- ++#endif
- ++
- ++#if defined (READLINE)
- ++ INIT_DYNAMIC_VAR ("COMP_WORDBREAKS", (char *)NULL, get_comp_wordbreaks, assign_comp_wordbreaks);
- ++#endif
- ++
- ++#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
- ++ v = init_dynamic_array_var ("DIRSTACK", get_dirstack, assign_dirstack, 0);
- ++#endif /* PUSHD_AND_POPD && ARRAY_VARS */
- ++
- ++#if defined (ARRAY_VARS)
- ++ v = init_dynamic_array_var ("GROUPS", get_groupset, null_array_assign, att_noassign);
- ++
- ++# if defined (DEBUGGER)
- ++ v = init_dynamic_array_var ("BASH_ARGC", get_self, null_array_assign, att_noassign|att_nounset);
- ++ v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, att_noassign|att_nounset);
- ++# endif /* DEBUGGER */
- ++ v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, att_noassign|att_nounset);
- ++ v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, att_noassign|att_nounset);
- ++
- ++ v = init_dynamic_assoc_var ("BASH_CMDS", get_hashcmd, assign_hashcmd, att_nofree);
- ++# if defined (ALIAS)
- ++ v = init_dynamic_assoc_var ("BASH_ALIASES", get_aliasvar, assign_aliasvar, att_nofree);
- ++# endif
- ++#endif
- ++
- ++ v = init_funcname_var ();
- ++}
- ++
- ++/* **************************************************************** */
- ++/* */
- ++/* Retrieving variables and values */
- ++/* */
- ++/* **************************************************************** */
- ++
- ++/* How to get a pointer to the shell variable or function named NAME.
- ++ HASHED_VARS is a pointer to the hash table containing the list
- ++ of interest (either variables or functions). */
- ++
- ++static SHELL_VAR *
- ++hash_lookup (name, hashed_vars)
- ++ const char *name;
- ++ HASH_TABLE *hashed_vars;
- ++{
- ++ BUCKET_CONTENTS *bucket;
- ++
- ++ bucket = hash_search (name, hashed_vars, 0);
- ++ /* If we find the name in HASHED_VARS, set LAST_TABLE_SEARCHED to that
- ++ table. */
- ++ if (bucket)
- ++ last_table_searched = hashed_vars;
- ++ return (bucket ? (SHELL_VAR *)bucket->data : (SHELL_VAR *)NULL);
- ++}
- ++
- ++SHELL_VAR *
- ++var_lookup (name, vcontext)
- ++ const char *name;
- ++ VAR_CONTEXT *vcontext;
- ++{
- ++ VAR_CONTEXT *vc;
- ++ SHELL_VAR *v;
- ++
- ++ v = (SHELL_VAR *)NULL;
- ++ for (vc = vcontext; vc; vc = vc->down)
- ++ if (v = hash_lookup (name, vc->table))
- ++ break;
- ++
- ++ return v;
- ++}
- ++
- ++/* Look up the variable entry named NAME. If SEARCH_TEMPENV is non-zero,
- ++ then also search the temporarily built list of exported variables.
- ++ The lookup order is:
- ++ temporary_env
- ++ shell_variables list
- ++*/
- ++
- ++SHELL_VAR *
- ++find_variable_internal (name, force_tempenv)
- ++ const char *name;
- ++ int force_tempenv;
- ++{
- ++ SHELL_VAR *var;
- ++ int search_tempenv;
- ++ VAR_CONTEXT *vc;
- ++
- ++ var = (SHELL_VAR *)NULL;
- ++
- ++ /* If explicitly requested, first look in the temporary environment for
- ++ the variable. This allows constructs such as "foo=x eval 'echo $foo'"
- ++ to get the `exported' value of $foo. This happens if we are executing
- ++ a function or builtin, or if we are looking up a variable in a
- ++ "subshell environment". */
- ++ search_tempenv = force_tempenv || (expanding_redir == 0 && subshell_environment);
- ++
- ++ if (search_tempenv && temporary_env)
- ++ var = hash_lookup (name, temporary_env);
- ++
- ++ vc = shell_variables;
- ++#if 0
- ++if (search_tempenv == 0 && /* (subshell_environment & SUBSHELL_COMSUB) && */
- ++ expanding_redir &&
- ++ (this_shell_builtin == eval_builtin || this_shell_builtin == command_builtin))
- ++ {
- ++ itrace("find_variable_internal: search_tempenv == 0: skipping VC_BLTNENV");
- ++ while (vc && (vc->flags & VC_BLTNENV))
- ++ vc = vc->down;
- ++ if (vc == 0)
- ++ vc = shell_variables;
- ++ }
- ++#endif
- ++
- ++ if (var == 0)
- ++ var = var_lookup (name, vc);
- ++
- ++ if (var == 0)
- ++ return ((SHELL_VAR *)NULL);
- ++
- ++ return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
- ++}
- ++
- ++/* Look up and resolve the chain of nameref variables starting at V all the
- ++ way to NULL or non-nameref. */
- ++SHELL_VAR *
- ++find_variable_nameref (v)
- ++ SHELL_VAR *v;
- ++{
- ++ int level;
- ++ char *newname;
- ++ SHELL_VAR *orig, *oldv;
- ++
- ++ level = 0;
- ++ orig = v;
- ++ while (v && nameref_p (v))
- ++ {
- ++ level++;
- ++ if (level > NAMEREF_MAX)
- ++ return ((SHELL_VAR *)0); /* error message here? */
- ++ newname = nameref_cell (v);
- ++ if (newname == 0 || *newname == '\0')
- ++ return ((SHELL_VAR *)0);
- ++ oldv = v;
- ++ v = find_variable_internal (newname, (expanding_redir == 0 && (assigning_in_environment || executing_builtin)));
- ++ if (v == orig || v == oldv)
- ++ {
- ++ internal_warning (_("%s: circular name reference"), orig->name);
- ++ return ((SHELL_VAR *)0);
- ++ }
- ++ }
- ++ return v;
- ++}
- ++
- ++/* Resolve the chain of nameref variables for NAME. XXX - could change later */
- ++SHELL_VAR *
- ++find_variable_last_nameref (name)
- ++ const char *name;
- ++{
- ++ SHELL_VAR *v, *nv;
- ++ char *newname;
- ++ int level;
- ++
- ++ nv = v = find_variable_noref (name);
- ++ level = 0;
- ++ while (v && nameref_p (v))
- ++ {
- ++ level++;
- ++ if (level > NAMEREF_MAX)
- ++ return ((SHELL_VAR *)0); /* error message here? */
- ++ newname = nameref_cell (v);
- ++ if (newname == 0 || *newname == '\0')
- ++ return ((SHELL_VAR *)0);
- ++ nv = v;
- ++ v = find_variable_internal (newname, (expanding_redir == 0 && (assigning_in_environment || executing_builtin)));
- ++ }
- ++ return nv;
- ++}
- ++
- ++/* Resolve the chain of nameref variables for NAME. XXX - could change later */
- ++SHELL_VAR *
- ++find_global_variable_last_nameref (name)
- ++ const char *name;
- ++{
- ++ SHELL_VAR *v, *nv;
- ++ char *newname;
- ++ int level;
- ++
- ++ nv = v = find_global_variable_noref (name);
- ++ level = 0;
- ++ while (v && nameref_p (v))
- ++ {
- ++ level++;
- ++ if (level > NAMEREF_MAX)
- ++ return ((SHELL_VAR *)0); /* error message here? */
- ++ newname = nameref_cell (v);
- ++ if (newname == 0 || *newname == '\0')
- ++ return ((SHELL_VAR *)0);
- ++ nv = v;
- ++ v = find_global_variable_noref (newname);
- ++ }
- ++ return nv;
- ++}
- ++
- ++static SHELL_VAR *
- ++find_nameref_at_context (v, vc)
- ++ SHELL_VAR *v;
- ++ VAR_CONTEXT *vc;
- ++{
- ++ SHELL_VAR *nv, *nv2;
- ++ VAR_CONTEXT *nvc;
- ++ char *newname;
- ++ int level;
- ++
- ++ nv = v;
- ++ level = 1;
- ++ while (nv && nameref_p (nv))
- ++ {
- ++ level++;
- ++ if (level > NAMEREF_MAX)
- ++ return ((SHELL_VAR *)NULL);
- ++ newname = nameref_cell (nv);
- ++ if (newname == 0 || *newname == '\0')
- ++ return ((SHELL_VAR *)NULL);
- ++ nv2 = hash_lookup (newname, vc->table);
- ++ if (nv2 == 0)
- ++ break;
- ++ nv = nv2;
- ++ }
- ++ return nv;
- ++}
- ++
- ++/* Do nameref resolution from the VC, which is the local context for some
- ++ function or builtin, `up' the chain to the global variables context. If
- ++ NVCP is not NULL, return the variable context where we finally ended the
- ++ nameref resolution (so the bind_variable_internal can use the correct
- ++ variable context and hash table). */
- ++static SHELL_VAR *
- ++find_variable_nameref_context (v, vc, nvcp)
- ++ SHELL_VAR *v;
- ++ VAR_CONTEXT *vc;
- ++ VAR_CONTEXT **nvcp;
- ++{
- ++ SHELL_VAR *nv, *nv2;
- ++ VAR_CONTEXT *nvc;
- ++
- ++ /* Look starting at the current context all the way `up' */
- ++ for (nv = v, nvc = vc; nvc; nvc = nvc->down)
- ++ {
- ++ nv2 = find_nameref_at_context (nv, nvc);
- ++ if (nv2 == 0)
- ++ continue;
- ++ nv = nv2;
- ++ if (*nvcp)
- ++ *nvcp = nvc;
- ++ if (nameref_p (nv) == 0)
- ++ break;
- ++ }
- ++ return (nameref_p (nv) ? (SHELL_VAR *)NULL : nv);
- ++}
- ++
- ++/* Do nameref resolution from the VC, which is the local context for some
- ++ function or builtin, `up' the chain to the global variables context. If
- ++ NVCP is not NULL, return the variable context where we finally ended the
- ++ nameref resolution (so the bind_variable_internal can use the correct
- ++ variable context and hash table). */
- ++static SHELL_VAR *
- ++find_variable_last_nameref_context (v, vc, nvcp)
- ++ SHELL_VAR *v;
- ++ VAR_CONTEXT *vc;
- ++ VAR_CONTEXT **nvcp;
- ++{
- ++ SHELL_VAR *nv, *nv2;
- ++ VAR_CONTEXT *nvc;
- ++
- ++ /* Look starting at the current context all the way `up' */
- ++ for (nv = v, nvc = vc; nvc; nvc = nvc->down)
- ++ {
- ++ nv2 = find_nameref_at_context (nv, nvc);
- ++ if (nv2 == 0)
- ++ continue;
- ++ nv = nv2;
- ++ if (*nvcp)
- ++ *nvcp = nvc;
- ++ }
- ++ return (nameref_p (nv) ? nv : (SHELL_VAR *)NULL);
- ++}
- ++
- ++/* Find a variable, forcing a search of the temporary environment first */
- ++SHELL_VAR *
- ++find_variable_tempenv (name)
- ++ const char *name;
- ++{
- ++ SHELL_VAR *var;
- ++
- ++ var = find_variable_internal (name, 1);
- ++ if (var && nameref_p (var))
- ++ var = find_variable_nameref (var);
- ++ return (var);
- ++}
- ++
- ++/* Find a variable, not forcing a search of the temporary environment first */
- ++SHELL_VAR *
- ++find_variable_notempenv (name)
- ++ const char *name;
- ++{
- ++ SHELL_VAR *var;
- ++
- ++ var = find_variable_internal (name, 0);
- ++ if (var && nameref_p (var))
- ++ var = find_variable_nameref (var);
- ++ return (var);
- ++}
- ++
- ++SHELL_VAR *
- ++find_global_variable (name)
- ++ const char *name;
- ++{
- ++ SHELL_VAR *var;
- ++
- ++ var = var_lookup (name, global_variables);
- ++ if (var && nameref_p (var))
- ++ var = find_variable_nameref (var);
- ++
- ++ if (var == 0)
- ++ return ((SHELL_VAR *)NULL);
- ++
- ++ return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
- ++}
- ++
- ++SHELL_VAR *
- ++find_global_variable_noref (name)
- ++ const char *name;
- ++{
- ++ SHELL_VAR *var;
- ++
- ++ var = var_lookup (name, global_variables);
- ++
- ++ if (var == 0)
- ++ return ((SHELL_VAR *)NULL);
- ++
- ++ return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
- ++}
- ++
- ++SHELL_VAR *
- ++find_shell_variable (name)
- ++ const char *name;
- ++{
- ++ SHELL_VAR *var;
- ++
- ++ var = var_lookup (name, shell_variables);
- ++ if (var && nameref_p (var))
- ++ var = find_variable_nameref (var);
- ++
- ++ if (var == 0)
- ++ return ((SHELL_VAR *)NULL);
- ++
- ++ return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
- ++}
- ++
- ++/* Look up the variable entry named NAME. Returns the entry or NULL. */
- ++SHELL_VAR *
- ++find_variable (name)
- ++ const char *name;
- ++{
- ++ SHELL_VAR *v;
- ++
- ++ last_table_searched = 0;
- ++ v = find_variable_internal (name, (expanding_redir == 0 && (assigning_in_environment || executing_builtin)));
- ++ if (v && nameref_p (v))
- ++ v = find_variable_nameref (v);
- ++ return v;
- ++}
- ++
- ++SHELL_VAR *
- ++find_variable_noref (name)
- ++ const char *name;
- ++{
- ++ SHELL_VAR *v;
- ++
- ++ v = find_variable_internal (name, (expanding_redir == 0 && (assigning_in_environment || executing_builtin)));
- ++ return v;
- ++}
- ++
- ++/* Look up the function entry whose name matches STRING.
- ++ Returns the entry or NULL. */
- ++SHELL_VAR *
- ++find_function (name)
- ++ const char *name;
- ++{
- ++ return (hash_lookup (name, shell_functions));
- ++}
- ++
- ++/* Find the function definition for the shell function named NAME. Returns
- ++ the entry or NULL. */
- ++FUNCTION_DEF *
- ++find_function_def (name)
- ++ const char *name;
- ++{
- ++#if defined (DEBUGGER)
- ++ return ((FUNCTION_DEF *)hash_lookup (name, shell_function_defs));
- ++#else
- ++ return ((FUNCTION_DEF *)0);
- ++#endif
- ++}
- ++
- ++/* Return the value of VAR. VAR is assumed to have been the result of a
- ++ lookup without any subscript, if arrays are compiled into the shell. */
- ++char *
- ++get_variable_value (var)
- ++ SHELL_VAR *var;
- ++{
- ++ if (var == 0)
- ++ return ((char *)NULL);
- ++#if defined (ARRAY_VARS)
- ++ else if (array_p (var))
- ++ return (array_reference (array_cell (var), 0));
- ++ else if (assoc_p (var))
- ++ return (assoc_reference (assoc_cell (var), "0"));
- ++#endif
- ++ else
- ++ return (value_cell (var));
- ++}
- ++
- ++/* Return the string value of a variable. Return NULL if the variable
- ++ doesn't exist. Don't cons a new string. This is a potential memory
- ++ leak if the variable is found in the temporary environment. Since
- ++ functions and variables have separate name spaces, returns NULL if
- ++ var_name is a shell function only. */
- ++char *
- ++get_string_value (var_name)
- ++ const char *var_name;
- ++{
- ++ SHELL_VAR *var;
- ++
- ++ var = find_variable (var_name);
- ++ return ((var) ? get_variable_value (var) : (char *)NULL);
- ++}
- ++
- ++/* This is present for use by the tilde and readline libraries. */
- ++char *
- ++sh_get_env_value (v)
- ++ const char *v;
- ++{
- ++ return get_string_value (v);
- ++}
- ++
- ++/* **************************************************************** */
- ++/* */
- ++/* Creating and setting variables */
- ++/* */
- ++/* **************************************************************** */
- ++
- ++/* Set NAME to VALUE if NAME has no value. */
- ++SHELL_VAR *
- ++set_if_not (name, value)
- ++ char *name, *value;
- ++{
- ++ SHELL_VAR *v;
- ++
- ++ if (shell_variables == 0)
- ++ create_variable_tables ();
- ++
- ++ v = find_variable (name);
- ++ if (v == 0)
- ++ v = bind_variable_internal (name, value, global_variables->table, HASH_NOSRCH, 0);
- ++ return (v);
- ++}
- ++
- ++/* Create a local variable referenced by NAME. */
- ++SHELL_VAR *
- ++make_local_variable (name)
- ++ const char *name;
- ++{
- ++ SHELL_VAR *new_var, *old_var;
- ++ VAR_CONTEXT *vc;
- ++ int was_tmpvar;
- ++ char *tmp_value;
- ++
- ++ /* local foo; local foo; is a no-op. */
- ++ old_var = find_variable (name);
- ++ if (old_var && local_p (old_var) && old_var->context == variable_context)
- ++ return (old_var);
- ++
- ++ was_tmpvar = old_var && tempvar_p (old_var);
- ++ /* If we're making a local variable in a shell function, the temporary env
- ++ has already been merged into the function's variable context stack. We
- ++ can assume that a temporary var in the same context appears in the same
- ++ VAR_CONTEXT and can safely be returned without creating a new variable
- ++ (which results in duplicate names in the same VAR_CONTEXT->table */
- ++ /* We can't just test tmpvar_p because variables in the temporary env given
- ++ to a shell function appear in the function's local variable VAR_CONTEXT
- ++ but retain their tempvar attribute. We want temporary variables that are
- ++ found in temporary_env, hence the test for last_table_searched, which is
- ++ set in hash_lookup and only (so far) checked here. */
- ++ if (was_tmpvar && old_var->context == variable_context && last_table_searched != temporary_env)
- ++ {
- ++ VUNSETATTR (old_var, att_invisible);
- ++ return (old_var);
- ++ }
- ++ if (was_tmpvar)
- ++ tmp_value = value_cell (old_var);
- ++
- ++ for (vc = shell_variables; vc; vc = vc->down)
- ++ if (vc_isfuncenv (vc) && vc->scope == variable_context)
- ++ break;
- ++
- ++ if (vc == 0)
- ++ {
- ++ internal_error (_("make_local_variable: no function context at current scope"));
- ++ return ((SHELL_VAR *)NULL);
- ++ }
- ++ else if (vc->table == 0)
- ++ vc->table = hash_create (TEMPENV_HASH_BUCKETS);
- ++
- ++ /* Since this is called only from the local/declare/typeset code, we can
- ++ call builtin_error here without worry (of course, it will also work
- ++ for anything that sets this_command_name). Variables with the `noassign'
- ++ attribute may not be made local. The test against old_var's context
- ++ level is to disallow local copies of readonly global variables (since I
- ++ believe that this could be a security hole). Readonly copies of calling
- ++ function local variables are OK. */
- ++ if (old_var && (noassign_p (old_var) ||
- ++ (readonly_p (old_var) && old_var->context == 0)))
- ++ {
- ++ if (readonly_p (old_var))
- ++ sh_readonly (name);
- ++ else if (noassign_p (old_var))
- ++ builtin_error (_("%s: variable may not be assigned value"), name);
- ++#if 0
- ++ /* Let noassign variables through with a warning */
- ++ if (readonly_p (old_var))
- ++#endif
- ++ return ((SHELL_VAR *)NULL);
- ++ }
- ++
- ++ if (old_var == 0)
- ++ new_var = make_new_variable (name, vc->table);
- ++ else
- ++ {
- ++ new_var = make_new_variable (name, vc->table);
- ++
- ++ /* If we found this variable in one of the temporary environments,
- ++ inherit its value. Watch to see if this causes problems with
- ++ things like `x=4 local x'. XXX - see above for temporary env
- ++ variables with the same context level as variable_context */
- ++ /* XXX - we should only do this if the variable is not an array. */
- ++ if (was_tmpvar)
- ++ var_setvalue (new_var, savestring (tmp_value));
- ++
- ++ new_var->attributes = exported_p (old_var) ? att_exported : 0;
- ++ }
- ++
- ++ vc->flags |= VC_HASLOCAL;
- ++
- ++ new_var->context = variable_context;
- ++ VSETATTR (new_var, att_local);
- ++
- ++ if (ifsname (name))
- ++ setifs (new_var);
- ++
- ++ if (was_tmpvar == 0)
- ++ VSETATTR (new_var, att_invisible); /* XXX */
- ++ return (new_var);
- ++}
- ++
- ++/* Create a new shell variable with name NAME. */
- ++static SHELL_VAR *
- ++new_shell_variable (name)
- ++ const char *name;
- ++{
- ++ SHELL_VAR *entry;
- ++
- ++ entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
- ++
- ++ entry->name = savestring (name);
- ++ var_setvalue (entry, (char *)NULL);
- ++ CLEAR_EXPORTSTR (entry);
- ++
- ++ entry->dynamic_value = (sh_var_value_func_t *)NULL;
- ++ entry->assign_func = (sh_var_assign_func_t *)NULL;
- ++
- ++ entry->attributes = 0;
- ++
- ++ /* Always assume variables are to be made at toplevel!
- ++ make_local_variable has the responsibility of changing the
- ++ variable context. */
- ++ entry->context = 0;
- ++
- ++ return (entry);
- ++}
- ++
- ++/* Create a new shell variable with name NAME and add it to the hash table
- ++ TABLE. */
- ++static SHELL_VAR *
- ++make_new_variable (name, table)
- ++ const char *name;
- ++ HASH_TABLE *table;
- ++{
- ++ SHELL_VAR *entry;
- ++ BUCKET_CONTENTS *elt;
- ++
- ++ entry = new_shell_variable (name);
- ++
- ++ /* Make sure we have a shell_variables hash table to add to. */
- ++ if (shell_variables == 0)
- ++ create_variable_tables ();
- ++
- ++ elt = hash_insert (savestring (name), table, HASH_NOSRCH);
- ++ elt->data = (PTR_T)entry;
- ++
- ++ return entry;
- ++}
- ++
- ++#if defined (ARRAY_VARS)
- ++SHELL_VAR *
- ++make_new_array_variable (name)
- ++ char *name;
- ++{
- ++ SHELL_VAR *entry;
- ++ ARRAY *array;
- ++
- ++ entry = make_new_variable (name, global_variables->table);
- ++ array = array_create ();
- ++
- ++ var_setarray (entry, array);
- ++ VSETATTR (entry, att_array);
- ++ return entry;
- ++}
- ++
- ++SHELL_VAR *
- ++make_local_array_variable (name, assoc_ok)
- ++ char *name;
- ++ int assoc_ok;
- ++{
- ++ SHELL_VAR *var;
- ++ ARRAY *array;
- ++
- ++ var = make_local_variable (name);
- ++ if (var == 0 || array_p (var) || (assoc_ok && assoc_p (var)))
- ++ return var;
- ++
- ++ array = array_create ();
- ++
- ++ dispose_variable_value (var);
- ++ var_setarray (var, array);
- ++ VSETATTR (var, att_array);
- ++ return var;
- ++}
- ++
- ++SHELL_VAR *
- ++make_new_assoc_variable (name)
- ++ char *name;
- ++{
- ++ SHELL_VAR *entry;
- ++ HASH_TABLE *hash;
- ++
- ++ entry = make_new_variable (name, global_variables->table);
- ++ hash = assoc_create (0);
- ++
- ++ var_setassoc (entry, hash);
- ++ VSETATTR (entry, att_assoc);
- ++ return entry;
- ++}
- ++
- ++SHELL_VAR *
- ++make_local_assoc_variable (name)
- ++ char *name;
- ++{
- ++ SHELL_VAR *var;
- ++ HASH_TABLE *hash;
- ++
- ++ var = make_local_variable (name);
- ++ if (var == 0 || assoc_p (var))
- ++ return var;
- ++
- ++ dispose_variable_value (var);
- ++ hash = assoc_create (0);
- ++
- ++ var_setassoc (var, hash);
- ++ VSETATTR (var, att_assoc);
- ++ return var;
- ++}
- ++#endif
- ++
- ++char *
- ++make_variable_value (var, value, flags)
- ++ SHELL_VAR *var;
- ++ char *value;
- ++ int flags;
- ++{
- ++ char *retval, *oval;
- ++ intmax_t lval, rval;
- ++ int expok, olen, op;
- ++
- ++ /* If this variable has had its type set to integer (via `declare -i'),
- ++ then do expression evaluation on it and store the result. The
- ++ functions in expr.c (evalexp()) and bind_int_variable() are responsible
- ++ for turning off the integer flag if they don't want further
- ++ evaluation done. */
- ++ if (integer_p (var))
- ++ {
- ++ if (flags & ASS_APPEND)
- ++ {
- ++ oval = value_cell (var);
- ++ lval = evalexp (oval, &expok); /* ksh93 seems to do this */
- ++ if (expok == 0)
- ++ {
- ++ top_level_cleanup ();
- ++ jump_to_top_level (DISCARD);
- ++ }
- ++ }
- ++ rval = evalexp (value, &expok);
- ++ if (expok == 0)
- ++ {
- ++ top_level_cleanup ();
- ++ jump_to_top_level (DISCARD);
- ++ }
- ++ /* This can be fooled if the variable's value changes while evaluating
- ++ `rval'. We can change it if we move the evaluation of lval to here. */
- ++ if (flags & ASS_APPEND)
- ++ rval += lval;
- ++ retval = itos (rval);
- ++ }
- ++#if defined (CASEMOD_ATTRS)
- ++ else if (capcase_p (var) || uppercase_p (var) || lowercase_p (var))
- ++ {
- ++ if (flags & ASS_APPEND)
- ++ {
- ++ oval = get_variable_value (var);
- ++ if (oval == 0) /* paranoia */
- ++ oval = "";
- ++ olen = STRLEN (oval);
- ++ retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1);
- ++ strcpy (retval, oval);
- ++ if (value)
- ++ strcpy (retval+olen, value);
- ++ }
- ++ else if (*value)
- ++ retval = savestring (value);
- ++ else
- ++ {
- ++ retval = (char *)xmalloc (1);
- ++ retval[0] = '\0';
- ++ }
- ++ op = capcase_p (var) ? CASE_CAPITALIZE
- ++ : (uppercase_p (var) ? CASE_UPPER : CASE_LOWER);
- ++ oval = sh_modcase (retval, (char *)0, op);
- ++ free (retval);
- ++ retval = oval;
- ++ }
- ++#endif /* CASEMOD_ATTRS */
- ++ else if (value)
- ++ {
- ++ if (flags & ASS_APPEND)
- ++ {
- ++ oval = get_variable_value (var);
- ++ if (oval == 0) /* paranoia */
- ++ oval = "";
- ++ olen = STRLEN (oval);
- ++ retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1);
- ++ strcpy (retval, oval);
- ++ if (value)
- ++ strcpy (retval+olen, value);
- ++ }
- ++ else if (*value)
- ++ retval = savestring (value);
- ++ else
- ++ {
- ++ retval = (char *)xmalloc (1);
- ++ retval[0] = '\0';
- ++ }
- ++ }
- ++ else
- ++ retval = (char *)NULL;
- ++
- ++ return retval;
- ++}
- ++
- ++/* Bind a variable NAME to VALUE in the HASH_TABLE TABLE, which may be the
- ++ temporary environment (but usually is not). */
- ++static SHELL_VAR *
- ++bind_variable_internal (name, value, table, hflags, aflags)
- ++ const char *name;
- ++ char *value;
- ++ HASH_TABLE *table;
- ++ int hflags, aflags;
- ++{
- ++ char *newval;
- ++ SHELL_VAR *entry;
- ++
- ++ entry = (hflags & HASH_NOSRCH) ? (SHELL_VAR *)NULL : hash_lookup (name, table);
- ++ /* Follow the nameref chain here if this is the global variables table */
- ++ if (entry && nameref_p (entry) && (invisible_p (entry) == 0) && table == global_variables->table)
- ++ {
- ++ entry = find_global_variable (entry->name);
- ++ /* Let's see if we have a nameref referencing a variable that hasn't yet
- ++ been created. */
- ++ if (entry == 0)
- ++ entry = find_variable_last_nameref (name); /* XXX */
- ++ if (entry == 0) /* just in case */
- ++ return (entry);
- ++ }
- ++
- ++ /* The first clause handles `declare -n ref; ref=x;' */
- ++ if (entry && invisible_p (entry) && nameref_p (entry))
- ++ goto assign_value;
- ++ else if (entry && nameref_p (entry))
- ++ {
- ++ newval = nameref_cell (entry);
- ++#if defined (ARRAY_VARS)
- ++ /* declare -n foo=x[2] */
- ++ if (valid_array_reference (newval))
- ++ /* XXX - should it be aflags? */
- ++ entry = assign_array_element (newval, make_variable_value (entry, value, 0), aflags);
- ++ else
- ++#endif
- ++ {
- ++ entry = make_new_variable (newval, table);
- ++ var_setvalue (entry, make_variable_value (entry, value, 0));
- ++ }
- ++ }
- ++ else if (entry == 0)
- ++ {
- ++ entry = make_new_variable (name, table);
- ++ var_setvalue (entry, make_variable_value (entry, value, 0)); /* XXX */
- ++ }
- ++ else if (entry->assign_func) /* array vars have assign functions now */
- ++ {
- ++ INVALIDATE_EXPORTSTR (entry);
- ++ newval = (aflags & ASS_APPEND) ? make_variable_value (entry, value, aflags) : value;
- ++ if (assoc_p (entry))
- ++ entry = (*(entry->assign_func)) (entry, newval, -1, savestring ("0"));
- ++ else if (array_p (entry))
- ++ entry = (*(entry->assign_func)) (entry, newval, 0, 0);
- ++ else
- ++ entry = (*(entry->assign_func)) (entry, newval, -1, 0);
- ++ if (newval != value)
- ++ free (newval);
- ++ return (entry);
- ++ }
- ++ else
- ++ {
- ++assign_value:
- ++ if (readonly_p (entry) || noassign_p (entry))
- ++ {
- ++ if (readonly_p (entry))
- ++ err_readonly (name);
- ++ return (entry);
- ++ }
- ++
- ++ /* Variables which are bound are visible. */
- ++ VUNSETATTR (entry, att_invisible);
- ++
- ++#if defined (ARRAY_VARS)
- ++ if (assoc_p (entry) || array_p (entry))
- ++ newval = make_array_variable_value (entry, 0, "0", value, aflags);
- ++ else
- ++#endif
- ++
- ++ newval = make_variable_value (entry, value, aflags); /* XXX */
- ++
- ++ /* Invalidate any cached export string */
- ++ INVALIDATE_EXPORTSTR (entry);
- ++
- ++#if defined (ARRAY_VARS)
- ++ /* XXX -- this bears looking at again -- XXX */
- ++ /* If an existing array variable x is being assigned to with x=b or
- ++ `read x' or something of that nature, silently convert it to
- ++ x[0]=b or `read x[0]'. */
- ++ if (assoc_p (entry))
- ++ {
- ++ assoc_insert (assoc_cell (entry), savestring ("0"), newval);
- ++ free (newval);
- ++ }
- ++ else if (array_p (entry))
- ++ {
- ++ array_insert (array_cell (entry), 0, newval);
- ++ free (newval);
- ++ }
- ++ else
- ++#endif
- ++ {
- ++ FREE (value_cell (entry));
- ++ var_setvalue (entry, newval);
- ++ }
- ++ }
- ++
- ++ if (mark_modified_vars)
- ++ VSETATTR (entry, att_exported);
- ++
- ++ if (exported_p (entry))
- ++ array_needs_making = 1;
- ++
- ++ return (entry);
- ++}
- ++
- ++/* Bind a variable NAME to VALUE. This conses up the name
- ++ and value strings. If we have a temporary environment, we bind there
- ++ first, then we bind into shell_variables. */
- ++
- ++SHELL_VAR *
- ++bind_variable (name, value, flags)
- ++ const char *name;
- ++ char *value;
- ++ int flags;
- ++{
- ++ SHELL_VAR *v, *nv;
- ++ VAR_CONTEXT *vc, *nvc;
- ++ int level;
- ++
- ++ if (shell_variables == 0)
- ++ create_variable_tables ();
- ++
- ++ /* If we have a temporary environment, look there first for the variable,
- ++ and, if found, modify the value there before modifying it in the
- ++ shell_variables table. This allows sourced scripts to modify values
- ++ given to them in a temporary environment while modifying the variable
- ++ value that the caller sees. */
- ++ if (temporary_env)
- ++ bind_tempenv_variable (name, value);
- ++
- ++ /* XXX -- handle local variables here. */
- ++ for (vc = shell_variables; vc; vc = vc->down)
- ++ {
- ++ if (vc_isfuncenv (vc) || vc_isbltnenv (vc))
- ++ {
- ++ v = hash_lookup (name, vc->table);
- ++ nvc = vc;
- ++ if (v && nameref_p (v))
- ++ {
- ++ nv = find_variable_nameref_context (v, vc, &nvc);
- ++ if (nv == 0)
- ++ {
- ++ nv = find_variable_last_nameref_context (v, vc, &nvc);
- ++ if (nv && nameref_p (nv))
- ++ {
- ++ /* If this nameref variable doesn't have a value yet,
- ++ set the value. Otherwise, assign using the value as
- ++ normal. */
- ++ if (nameref_cell (nv) == 0)
- ++ return (bind_variable_internal (nv->name, value, nvc->table, 0, flags));
- ++ return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags));
- ++ }
- ++ else
- ++ v = nv;
- ++ }
- ++ else
- ++ v = nv;
- ++ }
- ++ if (v)
- ++ return (bind_variable_internal (v->name, value, nvc->table, 0, flags));
- ++ }
- ++ }
- ++ /* bind_variable_internal will handle nameref resolution in this case */
- ++ return (bind_variable_internal (name, value, global_variables->table, 0, flags));
- ++}
- ++
- ++SHELL_VAR *
- ++bind_global_variable (name, value, flags)
- ++ const char *name;
- ++ char *value;
- ++ int flags;
- ++{
- ++ SHELL_VAR *v, *nv;
- ++ VAR_CONTEXT *vc, *nvc;
- ++ int level;
- ++
- ++ if (shell_variables == 0)
- ++ create_variable_tables ();
- ++
- ++ /* bind_variable_internal will handle nameref resolution in this case */
- ++ return (bind_variable_internal (name, value, global_variables->table, 0, flags));
- ++}
- ++
- ++/* Make VAR, a simple shell variable, have value VALUE. Once assigned a
- ++ value, variables are no longer invisible. This is a duplicate of part
- ++ of the internals of bind_variable. If the variable is exported, or
- ++ all modified variables should be exported, mark the variable for export
- ++ and note that the export environment needs to be recreated. */
- ++SHELL_VAR *
- ++bind_variable_value (var, value, aflags)
- ++ SHELL_VAR *var;
- ++ char *value;
- ++ int aflags;
- ++{
- ++ char *t;
- ++ int invis;
- ++
- ++ invis = invisible_p (var);
- ++ VUNSETATTR (var, att_invisible);
- ++
- ++ if (var->assign_func)
- ++ {
- ++ /* If we're appending, we need the old value, so use
- ++ make_variable_value */
- ++ t = (aflags & ASS_APPEND) ? make_variable_value (var, value, aflags) : value;
- ++ (*(var->assign_func)) (var, t, -1, 0);
- ++ if (t != value && t)
- ++ free (t);
- ++ }
- ++ else
- ++ {
- ++ t = make_variable_value (var, value, aflags);
- ++#if defined (ARRAY_VARS)
- ++ if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || (legal_identifier (t) == 0 && valid_array_reference (t) == 0)))
- ++#else
- ++ if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || legal_identifier (t) == 0))
- ++#endif
- ++ {
- ++ free (t);
- ++ if (invis)
- ++ VSETATTR (var, att_invisible); /* XXX */
- ++ return ((SHELL_VAR *)NULL);
- ++ }
- ++ FREE (value_cell (var));
- ++ var_setvalue (var, t);
- ++ }
- ++
- ++ INVALIDATE_EXPORTSTR (var);
- ++
- ++ if (mark_modified_vars)
- ++ VSETATTR (var, att_exported);
- ++
- ++ if (exported_p (var))
- ++ array_needs_making = 1;
- ++
- ++ return (var);
- ++}
- ++
- ++/* Bind/create a shell variable with the name LHS to the RHS.
- ++ This creates or modifies a variable such that it is an integer.
- ++
- ++ This used to be in expr.c, but it is here so that all of the
- ++ variable binding stuff is localized. Since we don't want any
- ++ recursive evaluation from bind_variable() (possible without this code,
- ++ since bind_variable() calls the evaluator for variables with the integer
- ++ attribute set), we temporarily turn off the integer attribute for each
- ++ variable we set here, then turn it back on after binding as necessary. */
- ++
- ++SHELL_VAR *
- ++bind_int_variable (lhs, rhs)
- ++ char *lhs, *rhs;
- ++{
- ++ register SHELL_VAR *v;
- ++ int isint, isarr, implicitarray;
- ++
- ++ isint = isarr = implicitarray = 0;
- ++#if defined (ARRAY_VARS)
- ++ if (valid_array_reference (lhs))
- ++ {
- ++ isarr = 1;
- ++ v = array_variable_part (lhs, (char **)0, (int *)0);
- ++ }
- ++ else
- ++#endif
- ++ v = find_variable (lhs);
- ++
- ++ if (v)
- ++ {
- ++ isint = integer_p (v);
- ++ VUNSETATTR (v, att_integer);
- ++#if defined (ARRAY_VARS)
- ++ if (array_p (v) && isarr == 0)
- ++ implicitarray = 1;
- ++#endif
- ++ }
- ++
- ++#if defined (ARRAY_VARS)
- ++ if (isarr)
- ++ v = assign_array_element (lhs, rhs, 0);
- ++ else if (implicitarray)
- ++ v = bind_array_variable (lhs, 0, rhs, 0);
- ++ else
- ++#endif
- ++ v = bind_variable (lhs, rhs, 0);
- ++
- ++ if (v && isint)
- ++ VSETATTR (v, att_integer);
- ++
- ++ VUNSETATTR (v, att_invisible);
- ++
- ++ return (v);
- ++}
- ++
- ++SHELL_VAR *
- ++bind_var_to_int (var, val)
- ++ char *var;
- ++ intmax_t val;
- ++{
- ++ char ibuf[INT_STRLEN_BOUND (intmax_t) + 1], *p;
- ++
- ++ p = fmtulong (val, 10, ibuf, sizeof (ibuf), 0);
- ++ return (bind_int_variable (var, p));
- ++}
- ++
- ++/* Do a function binding to a variable. You pass the name and
- ++ the command to bind to. This conses the name and command. */
- ++SHELL_VAR *
- ++bind_function (name, value)
- ++ const char *name;
- ++ COMMAND *value;
- ++{
- ++ SHELL_VAR *entry;
- ++
- ++ entry = find_function (name);
- ++ if (entry == 0)
- ++ {
- ++ BUCKET_CONTENTS *elt;
- ++
- ++ elt = hash_insert (savestring (name), shell_functions, HASH_NOSRCH);
- ++ entry = new_shell_variable (name);
- ++ elt->data = (PTR_T)entry;
- ++ }
- ++ else
- ++ INVALIDATE_EXPORTSTR (entry);
- ++
- ++ if (var_isset (entry))
- ++ dispose_command (function_cell (entry));
- ++
- ++ if (value)
- ++ var_setfunc (entry, copy_command (value));
- ++ else
- ++ var_setfunc (entry, 0);
- ++
- ++ VSETATTR (entry, att_function);
- ++
- ++ if (mark_modified_vars)
- ++ VSETATTR (entry, att_exported);
- ++
- ++ VUNSETATTR (entry, att_invisible); /* Just to be sure */
- ++
- ++ if (exported_p (entry))
- ++ array_needs_making = 1;
- ++
- ++#if defined (PROGRAMMABLE_COMPLETION)
- ++ set_itemlist_dirty (&it_functions);
- ++#endif
- ++
- ++ return (entry);
- ++}
- ++
- ++#if defined (DEBUGGER)
- ++/* Bind a function definition, which includes source file and line number
- ++ information in addition to the command, into the FUNCTION_DEF hash table.*/
- ++void
- ++bind_function_def (name, value)
- ++ const char *name;
- ++ FUNCTION_DEF *value;
- ++{
- ++ FUNCTION_DEF *entry;
- ++ BUCKET_CONTENTS *elt;
- ++ COMMAND *cmd;
- ++
- ++ entry = find_function_def (name);
- ++ if (entry)
- ++ {
- ++ dispose_function_def_contents (entry);
- ++ entry = copy_function_def_contents (value, entry);
- ++ }
- ++ else
- ++ {
- ++ cmd = value->command;
- ++ value->command = 0;
- ++ entry = copy_function_def (value);
- ++ value->command = cmd;
- ++
- ++ elt = hash_insert (savestring (name), shell_function_defs, HASH_NOSRCH);
- ++ elt->data = (PTR_T *)entry;
- ++ }
- ++}
- ++#endif /* DEBUGGER */
- ++
- ++/* Add STRING, which is of the form foo=bar, to the temporary environment
- ++ HASH_TABLE (temporary_env). The functions in execute_cmd.c are
- ++ responsible for moving the main temporary env to one of the other
- ++ temporary environments. The expansion code in subst.c calls this. */
- ++int
- ++assign_in_env (word, flags)
- ++ WORD_DESC *word;
- ++ int flags;
- ++{
- ++ int offset, aflags;
- ++ char *name, *temp, *value;
- ++ SHELL_VAR *var;
- ++ const char *string;
- ++
- ++ string = word->word;
- ++
- ++ aflags = 0;
- ++ offset = assignment (string, 0);
- ++ name = savestring (string);
- ++ value = (char *)NULL;
- ++
- ++ if (name[offset] == '=')
- ++ {
- ++ name[offset] = 0;
- ++
- ++ /* don't ignore the `+' when assigning temporary environment */
- ++ if (name[offset - 1] == '+')
- ++ {
- ++ name[offset - 1] = '\0';
- ++ aflags |= ASS_APPEND;
- ++ }
- ++
- ++ var = find_variable (name);
- ++ if (var && (readonly_p (var) || noassign_p (var)))
- ++ {
- ++ if (readonly_p (var))
- ++ err_readonly (name);
- ++ free (name);
- ++ return (0);
- ++ }
- ++
- ++ temp = name + offset + 1;
- ++ value = expand_assignment_string_to_string (temp, 0);
- ++
- ++ if (var && (aflags & ASS_APPEND))
- ++ {
- ++ temp = make_variable_value (var, value, aflags);
- ++ FREE (value);
- ++ value = temp;
- ++ }
- ++ }
- ++
- ++ if (temporary_env == 0)
- ++ temporary_env = hash_create (TEMPENV_HASH_BUCKETS);
- ++
- ++ var = hash_lookup (name, temporary_env);
- ++ if (var == 0)
- ++ var = make_new_variable (name, temporary_env);
- ++ else
- ++ FREE (value_cell (var));
- ++
- ++ if (value == 0)
- ++ {
- ++ value = (char *)xmalloc (1); /* like do_assignment_internal */
- ++ value[0] = '\0';
- ++ }
- ++
- ++ var_setvalue (var, value);
- ++ var->attributes |= (att_exported|att_tempvar);
- ++ var->context = variable_context; /* XXX */
- ++
- ++ INVALIDATE_EXPORTSTR (var);
- ++ var->exportstr = mk_env_string (name, value, 0);
- ++
- ++ array_needs_making = 1;
- ++
- ++ if (flags)
- ++ stupidly_hack_special_variables (name);
- ++
- ++ if (echo_command_at_execute)
- ++ /* The Korn shell prints the `+ ' in front of assignment statements,
- ++ so we do too. */
- ++ xtrace_print_assignment (name, value, 0, 1);
- ++
- ++ free (name);
- ++ return 1;
- ++}
- ++
- ++/* **************************************************************** */
- ++/* */
- ++/* Copying variables */
- ++/* */
- ++/* **************************************************************** */
- ++
- ++#ifdef INCLUDE_UNUSED
- ++/* Copy VAR to a new data structure and return that structure. */
- ++SHELL_VAR *
- ++copy_variable (var)
- ++ SHELL_VAR *var;
- ++{
- ++ SHELL_VAR *copy = (SHELL_VAR *)NULL;
- ++
- ++ if (var)
- ++ {
- ++ copy = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
- ++
- ++ copy->attributes = var->attributes;
- ++ copy->name = savestring (var->name);
- ++
- ++ if (function_p (var))
- ++ var_setfunc (copy, copy_command (function_cell (var)));
- ++#if defined (ARRAY_VARS)
- ++ else if (array_p (var))
- ++ var_setarray (copy, array_copy (array_cell (var)));
- ++ else if (assoc_p (var))
- ++ var_setassoc (copy, assoc_copy (assoc_cell (var)));
- ++#endif
- ++ else if (nameref_cell (var)) /* XXX - nameref */
- ++ var_setref (copy, savestring (nameref_cell (var)));
- ++ else if (value_cell (var)) /* XXX - nameref */
- ++ var_setvalue (copy, savestring (value_cell (var)));
- ++ else
- ++ var_setvalue (copy, (char *)NULL);
- ++
- ++ copy->dynamic_value = var->dynamic_value;
- ++ copy->assign_func = var->assign_func;
- ++
- ++ copy->exportstr = COPY_EXPORTSTR (var);
- ++
- ++ copy->context = var->context;
- ++ }
- ++ return (copy);
- ++}
- ++#endif
- ++
- ++/* **************************************************************** */
- ++/* */
- ++/* Deleting and unsetting variables */
- ++/* */
- ++/* **************************************************************** */
- ++
- ++/* Dispose of the information attached to VAR. */
- ++static void
- ++dispose_variable_value (var)
- ++ SHELL_VAR *var;
- ++{
- ++ if (function_p (var))
- ++ dispose_command (function_cell (var));
- ++#if defined (ARRAY_VARS)
- ++ else if (array_p (var))
- ++ array_dispose (array_cell (var));
- ++ else if (assoc_p (var))
- ++ assoc_dispose (assoc_cell (var));
- ++#endif
- ++ else if (nameref_p (var))
- ++ FREE (nameref_cell (var));
- ++ else
- ++ FREE (value_cell (var));
- ++}
- ++
- ++void
- ++dispose_variable (var)
- ++ SHELL_VAR *var;
- ++{
- ++ if (var == 0)
- ++ return;
- ++
- ++ if (nofree_p (var) == 0)
- ++ dispose_variable_value (var);
- ++
- ++ FREE_EXPORTSTR (var);
- ++
- ++ free (var->name);
- ++
- ++ if (exported_p (var))
- ++ array_needs_making = 1;
- ++
- ++ free (var);
- ++}
- ++
- ++/* Unset the shell variable referenced by NAME. Unsetting a nameref variable
- ++ unsets the variable it resolves to but leaves the nameref alone. */
- ++int
- ++unbind_variable (name)
- ++ const char *name;
- ++{
- ++ SHELL_VAR *v, *nv;
- ++ int r;
- ++
- ++ v = var_lookup (name, shell_variables);
- ++ nv = (v && nameref_p (v)) ? find_variable_nameref (v) : (SHELL_VAR *)NULL;
- ++
- ++ r = nv ? makunbound (nv->name, shell_variables) : makunbound (name, shell_variables);
- ++ return r;
- ++}
- ++
- ++/* Unbind NAME, where NAME is assumed to be a nameref variable */
- ++int
- ++unbind_nameref (name)
- ++ const char *name;
- ++{
- ++ SHELL_VAR *v;
- ++
- ++ v = var_lookup (name, shell_variables);
- ++ if (v && nameref_p (v))
- ++ return makunbound (name, shell_variables);
- ++ return 0;
- ++}
- ++
- ++/* Unset the shell function named NAME. */
- ++int
- ++unbind_func (name)
- ++ const char *name;
- ++{
- ++ BUCKET_CONTENTS *elt;
- ++ SHELL_VAR *func;
- ++
- ++ elt = hash_remove (name, shell_functions, 0);
- ++
- ++ if (elt == 0)
- ++ return -1;
- ++
- ++#if defined (PROGRAMMABLE_COMPLETION)
- ++ set_itemlist_dirty (&it_functions);
- ++#endif
- ++
- ++ func = (SHELL_VAR *)elt->data;
- ++ if (func)
- ++ {
- ++ if (exported_p (func))
- ++ array_needs_making++;
- ++ dispose_variable (func);
- ++ }
- ++
- ++ free (elt->key);
- ++ free (elt);
- ++
- ++ return 0;
- ++}
- ++
- ++#if defined (DEBUGGER)
- ++int
- ++unbind_function_def (name)
- ++ const char *name;
- ++{
- ++ BUCKET_CONTENTS *elt;
- ++ FUNCTION_DEF *funcdef;
- ++
- ++ elt = hash_remove (name, shell_function_defs, 0);
- ++
- ++ if (elt == 0)
- ++ return -1;
- ++
- ++ funcdef = (FUNCTION_DEF *)elt->data;
- ++ if (funcdef)
- ++ dispose_function_def (funcdef);
- ++
- ++ free (elt->key);
- ++ free (elt);
- ++
- ++ return 0;
- ++}
- ++#endif /* DEBUGGER */
- ++
- ++int
- ++delete_var (name, vc)
- ++ const char *name;
- ++ VAR_CONTEXT *vc;
- ++{
- ++ BUCKET_CONTENTS *elt;
- ++ SHELL_VAR *old_var;
- ++ VAR_CONTEXT *v;
- ++
- ++ for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down)
- ++ if (elt = hash_remove (name, v->table, 0))
- ++ break;
- ++
- ++ if (elt == 0)
- ++ return (-1);
- ++
- ++ old_var = (SHELL_VAR *)elt->data;
- ++ free (elt->key);
- ++ free (elt);
- ++
- ++ dispose_variable (old_var);
- ++ return (0);
- ++}
- ++
- ++/* Make the variable associated with NAME go away. HASH_LIST is the
- ++ hash table from which this variable should be deleted (either
- ++ shell_variables or shell_functions).
- ++ Returns non-zero if the variable couldn't be found. */
- ++int
- ++makunbound (name, vc)
- ++ const char *name;
- ++ VAR_CONTEXT *vc;
- ++{
- ++ BUCKET_CONTENTS *elt, *new_elt;
- ++ SHELL_VAR *old_var;
- ++ VAR_CONTEXT *v;
- ++ char *t;
- ++
- ++ for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down)
- ++ if (elt = hash_remove (name, v->table, 0))
- ++ break;
- ++
- ++ if (elt == 0)
- ++ return (-1);
- ++
- ++ old_var = (SHELL_VAR *)elt->data;
- ++
- ++ if (old_var && exported_p (old_var))
- ++ array_needs_making++;
- ++
- ++ /* If we're unsetting a local variable and we're still executing inside
- ++ the function, just mark the variable as invisible. The function
- ++ eventually called by pop_var_context() will clean it up later. This
- ++ must be done so that if the variable is subsequently assigned a new
- ++ value inside the function, the `local' attribute is still present.
- ++ We also need to add it back into the correct hash table. */
- ++ if (old_var && local_p (old_var) && variable_context == old_var->context)
- ++ {
- ++ if (nofree_p (old_var))
- ++ var_setvalue (old_var, (char *)NULL);
- ++#if defined (ARRAY_VARS)
- ++ else if (array_p (old_var))
- ++ array_dispose (array_cell (old_var));
- ++ else if (assoc_p (old_var))
- ++ assoc_dispose (assoc_cell (old_var));
- ++#endif
- ++ else if (nameref_p (old_var))
- ++ FREE (nameref_cell (old_var));
- ++ else
- ++ FREE (value_cell (old_var));
- ++ /* Reset the attributes. Preserve the export attribute if the variable
- ++ came from a temporary environment. Make sure it stays local, and
- ++ make it invisible. */
- ++ old_var->attributes = (exported_p (old_var) && tempvar_p (old_var)) ? att_exported : 0;
- ++ VSETATTR (old_var, att_local);
- ++ VSETATTR (old_var, att_invisible);
- ++ var_setvalue (old_var, (char *)NULL);
- ++ INVALIDATE_EXPORTSTR (old_var);
- ++
- ++ new_elt = hash_insert (savestring (old_var->name), v->table, 0);
- ++ new_elt->data = (PTR_T)old_var;
- ++ stupidly_hack_special_variables (old_var->name);
- ++
- ++ free (elt->key);
- ++ free (elt);
- ++ return (0);
- ++ }
- ++
- ++ /* Have to save a copy of name here, because it might refer to
- ++ old_var->name. If so, stupidly_hack_special_variables will
- ++ reference freed memory. */
- ++ t = savestring (name);
- ++
- ++ free (elt->key);
- ++ free (elt);
- ++
- ++ dispose_variable (old_var);
- ++ stupidly_hack_special_variables (t);
- ++ free (t);
- ++
- ++ return (0);
- ++}
- ++
- ++/* Get rid of all of the variables in the current context. */
- ++void
- ++kill_all_local_variables ()
- ++{
- ++ VAR_CONTEXT *vc;
- ++
- ++ for (vc = shell_variables; vc; vc = vc->down)
- ++ if (vc_isfuncenv (vc) && vc->scope == variable_context)
- ++ break;
- ++ if (vc == 0)
- ++ return; /* XXX */
- ++
- ++ if (vc->table && vc_haslocals (vc))
- ++ {
- ++ delete_all_variables (vc->table);
- ++ hash_dispose (vc->table);
- ++ }
- ++ vc->table = (HASH_TABLE *)NULL;
- ++}
- ++
- ++static void
- ++free_variable_hash_data (data)
- ++ PTR_T data;
- ++{
- ++ SHELL_VAR *var;
- ++
- ++ var = (SHELL_VAR *)data;
- ++ dispose_variable (var);
- ++}
- ++
- ++/* Delete the entire contents of the hash table. */
- ++void
- ++delete_all_variables (hashed_vars)
- ++ HASH_TABLE *hashed_vars;
- ++{
- ++ hash_flush (hashed_vars, free_variable_hash_data);
- ++}
- ++
- ++/* **************************************************************** */
- ++/* */
- ++/* Setting variable attributes */
- ++/* */
- ++/* **************************************************************** */
- ++
- ++#define FIND_OR_MAKE_VARIABLE(name, entry) \
- ++ do \
- ++ { \
- ++ entry = find_variable (name); \
- ++ if (!entry) \
- ++ { \
- ++ entry = bind_variable (name, "", 0); \
- ++ if (!no_invisible_vars && entry) entry->attributes |= att_invisible; \
- ++ } \
- ++ } \
- ++ while (0)
- ++
- ++/* Make the variable associated with NAME be readonly.
- ++ If NAME does not exist yet, create it. */
- ++void
- ++set_var_read_only (name)
- ++ char *name;
- ++{
- ++ SHELL_VAR *entry;
- ++
- ++ FIND_OR_MAKE_VARIABLE (name, entry);
- ++ VSETATTR (entry, att_readonly);
- ++}
- ++
- ++#ifdef INCLUDE_UNUSED
- ++/* Make the function associated with NAME be readonly.
- ++ If NAME does not exist, we just punt, like auto_export code below. */
- ++void
- ++set_func_read_only (name)
- ++ const char *name;
- ++{
- ++ SHELL_VAR *entry;
- ++
- ++ entry = find_function (name);
- ++ if (entry)
- ++ VSETATTR (entry, att_readonly);
- ++}
- ++
- ++/* Make the variable associated with NAME be auto-exported.
- ++ If NAME does not exist yet, create it. */
- ++void
- ++set_var_auto_export (name)
- ++ char *name;
- ++{
- ++ SHELL_VAR *entry;
- ++
- ++ FIND_OR_MAKE_VARIABLE (name, entry);
- ++ set_auto_export (entry);
- ++}
- ++
- ++/* Make the function associated with NAME be auto-exported. */
- ++void
- ++set_func_auto_export (name)
- ++ const char *name;
- ++{
- ++ SHELL_VAR *entry;
- ++
- ++ entry = find_function (name);
- ++ if (entry)
- ++ set_auto_export (entry);
- ++}
- ++#endif
- ++
- ++/* **************************************************************** */
- ++/* */
- ++/* Creating lists of variables */
- ++/* */
- ++/* **************************************************************** */
- ++
- ++static VARLIST *
- ++vlist_alloc (nentries)
- ++ int nentries;
- ++{
- ++ VARLIST *vlist;
- ++
- ++ vlist = (VARLIST *)xmalloc (sizeof (VARLIST));
- ++ vlist->list = (SHELL_VAR **)xmalloc ((nentries + 1) * sizeof (SHELL_VAR *));
- ++ vlist->list_size = nentries;
- ++ vlist->list_len = 0;
- ++ vlist->list[0] = (SHELL_VAR *)NULL;
- ++
- ++ return vlist;
- ++}
- ++
- ++static VARLIST *
- ++vlist_realloc (vlist, n)
- ++ VARLIST *vlist;
- ++ int n;
- ++{
- ++ if (vlist == 0)
- ++ return (vlist = vlist_alloc (n));
- ++ if (n > vlist->list_size)
- ++ {
- ++ vlist->list_size = n;
- ++ vlist->list = (SHELL_VAR **)xrealloc (vlist->list, (vlist->list_size + 1) * sizeof (SHELL_VAR *));
- ++ }
- ++ return vlist;
- ++}
- ++
- ++static void
- ++vlist_add (vlist, var, flags)
- ++ VARLIST *vlist;
- ++ SHELL_VAR *var;
- ++ int flags;
- ++{
- ++ register int i;
- ++
- ++ for (i = 0; i < vlist->list_len; i++)
- ++ if (STREQ (var->name, vlist->list[i]->name))
- ++ break;
- ++ if (i < vlist->list_len)
- ++ return;
- ++
- ++ if (i >= vlist->list_size)
- ++ vlist = vlist_realloc (vlist, vlist->list_size + 16);
- ++
- ++ vlist->list[vlist->list_len++] = var;
- ++ vlist->list[vlist->list_len] = (SHELL_VAR *)NULL;
- ++}
- ++
- ++/* Map FUNCTION over the variables in VAR_HASH_TABLE. Return an array of the
- ++ variables for which FUNCTION returns a non-zero value. A NULL value
- ++ for FUNCTION means to use all variables. */
- ++SHELL_VAR **
- ++map_over (function, vc)
- ++ sh_var_map_func_t *function;
- ++ VAR_CONTEXT *vc;
- ++{
- ++ VAR_CONTEXT *v;
- ++ VARLIST *vlist;
- ++ SHELL_VAR **ret;
- ++ int nentries;
- ++
- ++ for (nentries = 0, v = vc; v; v = v->down)
- ++ nentries += HASH_ENTRIES (v->table);
- ++
- ++ if (nentries == 0)
- ++ return (SHELL_VAR **)NULL;
- ++
- ++ vlist = vlist_alloc (nentries);
- ++
- ++ for (v = vc; v; v = v->down)
- ++ flatten (v->table, function, vlist, 0);
- ++
- ++ ret = vlist->list;
- ++ free (vlist);
- ++ return ret;
- ++}
- ++
- ++SHELL_VAR **
- ++map_over_funcs (function)
- ++ sh_var_map_func_t *function;
- ++{
- ++ VARLIST *vlist;
- ++ SHELL_VAR **ret;
- ++
- ++ if (shell_functions == 0 || HASH_ENTRIES (shell_functions) == 0)
- ++ return ((SHELL_VAR **)NULL);
- ++
- ++ vlist = vlist_alloc (HASH_ENTRIES (shell_functions));
- ++
- ++ flatten (shell_functions, function, vlist, 0);
- ++
- ++ ret = vlist->list;
- ++ free (vlist);
- ++ return ret;
- ++}
- ++
- ++/* Flatten VAR_HASH_TABLE, applying FUNC to each member and adding those
- ++ elements for which FUNC succeeds to VLIST->list. FLAGS is reserved
- ++ for future use. Only unique names are added to VLIST. If FUNC is
- ++ NULL, each variable in VAR_HASH_TABLE is added to VLIST. If VLIST is
- ++ NULL, FUNC is applied to each SHELL_VAR in VAR_HASH_TABLE. If VLIST
- ++ and FUNC are both NULL, nothing happens. */
- ++static void
- ++flatten (var_hash_table, func, vlist, flags)
- ++ HASH_TABLE *var_hash_table;
- ++ sh_var_map_func_t *func;
- ++ VARLIST *vlist;
- ++ int flags;
- ++{
- ++ register int i;
- ++ register BUCKET_CONTENTS *tlist;
- ++ int r;
- ++ SHELL_VAR *var;
- ++
- ++ if (var_hash_table == 0 || (HASH_ENTRIES (var_hash_table) == 0) || (vlist == 0 && func == 0))
- ++ return;
- ++
- ++ for (i = 0; i < var_hash_table->nbuckets; i++)
- ++ {
- ++ for (tlist = hash_items (i, var_hash_table); tlist; tlist = tlist->next)
- ++ {
- ++ var = (SHELL_VAR *)tlist->data;
- ++
- ++ r = func ? (*func) (var) : 1;
- ++ if (r && vlist)
- ++ vlist_add (vlist, var, flags);
- ++ }
- ++ }
- ++}
- ++
- ++void
- ++sort_variables (array)
- ++ SHELL_VAR **array;
- ++{
- ++ qsort (array, strvec_len ((char **)array), sizeof (SHELL_VAR *), (QSFUNC *)qsort_var_comp);
- ++}
- ++
- ++static int
- ++qsort_var_comp (var1, var2)
- ++ SHELL_VAR **var1, **var2;
- ++{
- ++ int result;
- ++
- ++ if ((result = (*var1)->name[0] - (*var2)->name[0]) == 0)
- ++ result = strcmp ((*var1)->name, (*var2)->name);
- ++
- ++ return (result);
- ++}
- ++
- ++/* Apply FUNC to each variable in SHELL_VARIABLES, adding each one for
- ++ which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */
- ++static SHELL_VAR **
- ++vapply (func)
- ++ sh_var_map_func_t *func;
- ++{
- ++ SHELL_VAR **list;
- ++
- ++ list = map_over (func, shell_variables);
- ++ if (list /* && posixly_correct */)
- ++ sort_variables (list);
- ++ return (list);
- ++}
- ++
- ++/* Apply FUNC to each variable in SHELL_FUNCTIONS, adding each one for
- ++ which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */
- ++static SHELL_VAR **
- ++fapply (func)
- ++ sh_var_map_func_t *func;
- ++{
- ++ SHELL_VAR **list;
- ++
- ++ list = map_over_funcs (func);
- ++ if (list /* && posixly_correct */)
- ++ sort_variables (list);
- ++ return (list);
- ++}
- ++
- ++/* Create a NULL terminated array of all the shell variables. */
- ++SHELL_VAR **
- ++all_shell_variables ()
- ++{
- ++ return (vapply ((sh_var_map_func_t *)NULL));
- ++}
- ++
- ++/* Create a NULL terminated array of all the shell functions. */
- ++SHELL_VAR **
- ++all_shell_functions ()
- ++{
- ++ return (fapply ((sh_var_map_func_t *)NULL));
- ++}
- ++
- ++static int
- ++visible_var (var)
- ++ SHELL_VAR *var;
- ++{
- ++ return (invisible_p (var) == 0);
- ++}
- ++
- ++SHELL_VAR **
- ++all_visible_functions ()
- ++{
- ++ return (fapply (visible_var));
- ++}
- ++
- ++SHELL_VAR **
- ++all_visible_variables ()
- ++{
- ++ return (vapply (visible_var));
- ++}
- ++
- ++/* Return non-zero if the variable VAR is visible and exported. Array
- ++ variables cannot be exported. */
- ++static int
- ++visible_and_exported (var)
- ++ SHELL_VAR *var;
- ++{
- ++ return (invisible_p (var) == 0 && exported_p (var));
- ++}
- ++
- ++/* Candidate variables for the export environment are either valid variables
- ++ with the export attribute or invalid variables inherited from the initial
- ++ environment and simply passed through. */
- ++static int
- ++export_environment_candidate (var)
- ++ SHELL_VAR *var;
- ++{
- ++ return (exported_p (var) && (invisible_p (var) == 0 || imported_p (var)));
- ++}
- ++
- ++/* Return non-zero if VAR is a local variable in the current context and
- ++ is exported. */
- ++static int
- ++local_and_exported (var)
- ++ SHELL_VAR *var;
- ++{
- ++ return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context && exported_p (var));
- ++}
- ++
- ++SHELL_VAR **
- ++all_exported_variables ()
- ++{
- ++ return (vapply (visible_and_exported));
- ++}
- ++
- ++SHELL_VAR **
- ++local_exported_variables ()
- ++{
- ++ return (vapply (local_and_exported));
- ++}
- ++
- ++static int
- ++variable_in_context (var)
- ++ SHELL_VAR *var;
- ++{
- ++ return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context);
- ++}
- ++
- ++SHELL_VAR **
- ++all_local_variables ()
- ++{
- ++ VARLIST *vlist;
- ++ SHELL_VAR **ret;
- ++ VAR_CONTEXT *vc;
- ++
- ++ vc = shell_variables;
- ++ for (vc = shell_variables; vc; vc = vc->down)
- ++ if (vc_isfuncenv (vc) && vc->scope == variable_context)
- ++ break;
- ++
- ++ if (vc == 0)
- ++ {
- ++ internal_error (_("all_local_variables: no function context at current scope"));
- ++ return (SHELL_VAR **)NULL;
- ++ }
- ++ if (vc->table == 0 || HASH_ENTRIES (vc->table) == 0 || vc_haslocals (vc) == 0)
- ++ return (SHELL_VAR **)NULL;
- ++
- ++ vlist = vlist_alloc (HASH_ENTRIES (vc->table));
- ++
- ++ flatten (vc->table, variable_in_context, vlist, 0);
- ++
- ++ ret = vlist->list;
- ++ free (vlist);
- ++ if (ret)
- ++ sort_variables (ret);
- ++ return ret;
- ++}
- ++
- ++#if defined (ARRAY_VARS)
- ++/* Return non-zero if the variable VAR is visible and an array. */
- ++static int
- ++visible_array_vars (var)
- ++ SHELL_VAR *var;
- ++{
- ++ return (invisible_p (var) == 0 && array_p (var));
- ++}
- ++
- ++SHELL_VAR **
- ++all_array_variables ()
- ++{
- ++ return (vapply (visible_array_vars));
- ++}
- ++#endif /* ARRAY_VARS */
- ++
- ++char **
- ++all_variables_matching_prefix (prefix)
- ++ const char *prefix;
- ++{
- ++ SHELL_VAR **varlist;
- ++ char **rlist;
- ++ int vind, rind, plen;
- ++
- ++ plen = STRLEN (prefix);
- ++ varlist = all_visible_variables ();
- ++ for (vind = 0; varlist && varlist[vind]; vind++)
- ++ ;
- ++ if (varlist == 0 || vind == 0)
- ++ return ((char **)NULL);
- ++ rlist = strvec_create (vind + 1);
- ++ for (vind = rind = 0; varlist[vind]; vind++)
- ++ {
- ++ if (plen == 0 || STREQN (prefix, varlist[vind]->name, plen))
- ++ rlist[rind++] = savestring (varlist[vind]->name);
- ++ }
- ++ rlist[rind] = (char *)0;
- ++ free (varlist);
- ++
- ++ return rlist;
- ++}
- ++
- ++/* **************************************************************** */
- ++/* */
- ++/* Managing temporary variable scopes */
- ++/* */
- ++/* **************************************************************** */
- ++
- ++/* Make variable NAME have VALUE in the temporary environment. */
- ++static SHELL_VAR *
- ++bind_tempenv_variable (name, value)
- ++ const char *name;
- ++ char *value;
- ++{
- ++ SHELL_VAR *var;
- ++
- ++ var = temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL;
- ++
- ++ if (var)
- ++ {
- ++ FREE (value_cell (var));
- ++ var_setvalue (var, savestring (value));
- ++ INVALIDATE_EXPORTSTR (var);
- ++ }
- ++
- ++ return (var);
- ++}
- ++
- ++/* Find a variable in the temporary environment that is named NAME.
- ++ Return the SHELL_VAR *, or NULL if not found. */
- ++SHELL_VAR *
- ++find_tempenv_variable (name)
- ++ const char *name;
- ++{
- ++ return (temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL);
- ++}
- ++
- ++char **tempvar_list;
- ++int tvlist_ind;
- ++
- ++/* Push the variable described by (SHELL_VAR *)DATA down to the next
- ++ variable context from the temporary environment. */
- ++static void
- ++push_temp_var (data)
- ++ PTR_T data;
- ++{
- ++ SHELL_VAR *var, *v;
- ++ HASH_TABLE *binding_table;
- ++
- ++ var = (SHELL_VAR *)data;
- ++
- ++ binding_table = shell_variables->table;
- ++ if (binding_table == 0)
- ++ {
- ++ if (shell_variables == global_variables)
- ++ /* shouldn't happen */
- ++ binding_table = shell_variables->table = global_variables->table = hash_create (0);
- ++ else
- ++ binding_table = shell_variables->table = hash_create (TEMPENV_HASH_BUCKETS);
- ++ }
- ++
- ++ v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, 0);
- ++
- ++ /* XXX - should we set the context here? It shouldn't matter because of how
- ++ assign_in_env works, but might want to check. */
- ++ if (binding_table == global_variables->table) /* XXX */
- ++ var->attributes &= ~(att_tempvar|att_propagate);
- ++ else
- ++ {
- ++ var->attributes |= att_propagate;
- ++ if (binding_table == shell_variables->table)
- ++ shell_variables->flags |= VC_HASTMPVAR;
- ++ }
- ++ v->attributes |= var->attributes;
- ++
- ++ if (find_special_var (var->name) >= 0)
- ++ tempvar_list[tvlist_ind++] = savestring (var->name);
- ++
- ++ dispose_variable (var);
- ++}
- ++
- ++static void
- ++propagate_temp_var (data)
- ++ PTR_T data;
- ++{
- ++ SHELL_VAR *var;
- ++
- ++ var = (SHELL_VAR *)data;
- ++ if (tempvar_p (var) && (var->attributes & att_propagate))
- ++ push_temp_var (data);
- ++ else
- ++ {
- ++ if (find_special_var (var->name) >= 0)
- ++ tempvar_list[tvlist_ind++] = savestring (var->name);
- ++ dispose_variable (var);
- ++ }
- ++}
- ++
- ++/* Free the storage used in the hash table for temporary
- ++ environment variables. PUSHF is a function to be called
- ++ to free each hash table entry. It takes care of pushing variables
- ++ to previous scopes if appropriate. PUSHF stores names of variables
- ++ that require special handling (e.g., IFS) on tempvar_list, so this
- ++ function can call stupidly_hack_special_variables on all the
- ++ variables in the list when the temporary hash table is destroyed. */
- ++static void
- ++dispose_temporary_env (pushf)
- ++ sh_free_func_t *pushf;
- ++{
- ++ int i;
- ++
- ++ tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1);
- ++ tempvar_list[tvlist_ind = 0] = 0;
- ++
- ++ hash_flush (temporary_env, pushf);
- ++ hash_dispose (temporary_env);
- ++ temporary_env = (HASH_TABLE *)NULL;
- ++
- ++ tempvar_list[tvlist_ind] = 0;
- ++
- ++ array_needs_making = 1;
- ++
- ++#if 0
- ++ sv_ifs ("IFS"); /* XXX here for now -- check setifs in assign_in_env */
- ++#endif
- ++ for (i = 0; i < tvlist_ind; i++)
- ++ stupidly_hack_special_variables (tempvar_list[i]);
- ++
- ++ strvec_dispose (tempvar_list);
- ++ tempvar_list = 0;
- ++ tvlist_ind = 0;
- ++}
- ++
- ++void
- ++dispose_used_env_vars ()
- ++{
- ++ if (temporary_env)
- ++ {
- ++ dispose_temporary_env (propagate_temp_var);
- ++ maybe_make_export_env ();
- ++ }
- ++}
- ++
- ++/* Take all of the shell variables in the temporary environment HASH_TABLE
- ++ and make shell variables from them at the current variable context. */
- ++void
- ++merge_temporary_env ()
- ++{
- ++ if (temporary_env)
- ++ dispose_temporary_env (push_temp_var);
- ++}
- ++
- ++/* **************************************************************** */
- ++/* */
- ++/* Creating and manipulating the environment */
- ++/* */
- ++/* **************************************************************** */
- ++
- ++static inline char *
- ++mk_env_string (name, value, isfunc)
- ++ const char *name, *value;
- ++ int isfunc;
- ++{
- ++ size_t name_len, value_len;
- ++ char *p, *q;
- ++
- ++ name_len = strlen (name);
- ++ value_len = STRLEN (value);
- ++
- ++ /* If we are exporting a shell function, construct the encoded function
- ++ name. */
- ++ if (isfunc && value)
- ++ {
- ++ p = (char *)xmalloc (BASHFUNC_PREFLEN + name_len + BASHFUNC_SUFFLEN + value_len + 2);
- ++ q = p;
- ++ memcpy (q, BASHFUNC_PREFIX, BASHFUNC_PREFLEN);
- ++ q += BASHFUNC_PREFLEN;
- ++ memcpy (q, name, name_len);
- ++ q += name_len;
- ++ memcpy (q, BASHFUNC_SUFFIX, BASHFUNC_SUFFLEN);
- ++ q += BASHFUNC_SUFFLEN;
- ++ }
- ++ else
- ++ {
- ++ p = (char *)xmalloc (2 + name_len + value_len);
- ++ memcpy (p, name, name_len);
- ++ q = p + name_len;
- ++ }
- ++
- ++ q[0] = '=';
- ++ if (value && *value)
- ++ memcpy (q + 1, value, value_len + 1);
- ++ else
- ++ q[1] = '\0';
- ++
- ++ return (p);
- ++}
- ++
- ++#ifdef DEBUG
- ++/* Debugging */
- ++static int
- ++valid_exportstr (v)
- ++ SHELL_VAR *v;
- ++{
- ++ char *s;
- ++
- ++ s = v->exportstr;
- ++ if (s == 0)
- ++ {
- ++ internal_error (_("%s has null exportstr"), v->name);
- ++ return (0);
- ++ }
- ++ if (legal_variable_starter ((unsigned char)*s) == 0)
- ++ {
- ++ internal_error (_("invalid character %d in exportstr for %s"), *s, v->name);
- ++ return (0);
- ++ }
- ++ for (s = v->exportstr + 1; s && *s; s++)
- ++ {
- ++ if (*s == '=')
- ++ break;
- ++ if (legal_variable_char ((unsigned char)*s) == 0)
- ++ {
- ++ internal_error (_("invalid character %d in exportstr for %s"), *s, v->name);
- ++ return (0);
- ++ }
- ++ }
- ++ if (*s != '=')
- ++ {
- ++ internal_error (_("no `=' in exportstr for %s"), v->name);
- ++ return (0);
- ++ }
- ++ return (1);
- ++}
- ++#endif
- ++
- ++static char **
- ++make_env_array_from_var_list (vars)
- ++ SHELL_VAR **vars;
- ++{
- ++ register int i, list_index;
- ++ register SHELL_VAR *var;
- ++ char **list, *value;
- ++
- ++ list = strvec_create ((1 + strvec_len ((char **)vars)));
- ++
- ++#define USE_EXPORTSTR (value == var->exportstr)
- ++
- ++ for (i = 0, list_index = 0; var = vars[i]; i++)
- ++ {
- ++#if defined (__CYGWIN__)
- ++ /* We don't use the exportstr stuff on Cygwin at all. */
- ++ INVALIDATE_EXPORTSTR (var);
- ++#endif
- ++ if (var->exportstr)
- ++ value = var->exportstr;
- ++ else if (function_p (var))
- ++ value = named_function_string ((char *)NULL, function_cell (var), 0);
- ++#if defined (ARRAY_VARS)
- ++ else if (array_p (var))
- ++# if ARRAY_EXPORT
- ++ value = array_to_assignment_string (array_cell (var));
- ++# else
- ++ continue; /* XXX array vars cannot yet be exported */
- ++# endif /* ARRAY_EXPORT */
- ++ else if (assoc_p (var))
- ++# if 0
- ++ value = assoc_to_assignment_string (assoc_cell (var));
- ++# else
- ++ continue; /* XXX associative array vars cannot yet be exported */
- ++# endif
- ++#endif
- ++ else
- ++ value = value_cell (var);
- ++
- ++ if (value)
- ++ {
- ++ /* Gee, I'd like to get away with not using savestring() if we're
- ++ using the cached exportstr... */
- ++ list[list_index] = USE_EXPORTSTR ? savestring (value)
- ++ : mk_env_string (var->name, value, function_p (var));
- ++
- ++ if (USE_EXPORTSTR == 0)
- ++ SAVE_EXPORTSTR (var, list[list_index]);
- ++
- ++ list_index++;
- ++#undef USE_EXPORTSTR
- ++
- ++#if 0 /* not yet */
- ++#if defined (ARRAY_VARS)
- ++ if (array_p (var) || assoc_p (var))
- ++ free (value);
- ++#endif
- ++#endif
- ++ }
- ++ }
- ++
- ++ list[list_index] = (char *)NULL;
- ++ return (list);
- ++}
- ++
- ++/* Make an array of assignment statements from the hash table
- ++ HASHED_VARS which contains SHELL_VARs. Only visible, exported
- ++ variables are eligible. */
- ++static char **
- ++make_var_export_array (vcxt)
- ++ VAR_CONTEXT *vcxt;
- ++{
- ++ char **list;
- ++ SHELL_VAR **vars;
- ++
- ++#if 0
- ++ vars = map_over (visible_and_exported, vcxt);
- ++#else
- ++ vars = map_over (export_environment_candidate, vcxt);
- ++#endif
- ++
- ++ if (vars == 0)
- ++ return (char **)NULL;
- ++
- ++ list = make_env_array_from_var_list (vars);
- ++
- ++ free (vars);
- ++ return (list);
- ++}
- ++
- ++static char **
- ++make_func_export_array ()
- ++{
- ++ char **list;
- ++ SHELL_VAR **vars;
- ++
- ++ vars = map_over_funcs (visible_and_exported);
- ++ if (vars == 0)
- ++ return (char **)NULL;
- ++
- ++ list = make_env_array_from_var_list (vars);
- ++
- ++ free (vars);
- ++ return (list);
- ++}
- ++
- ++/* Add ENVSTR to the end of the exported environment, EXPORT_ENV. */
- ++#define add_to_export_env(envstr,do_alloc) \
- ++do \
- ++ { \
- ++ if (export_env_index >= (export_env_size - 1)) \
- ++ { \
- ++ export_env_size += 16; \
- ++ export_env = strvec_resize (export_env, export_env_size); \
- ++ environ = export_env; \
- ++ } \
- ++ export_env[export_env_index++] = (do_alloc) ? savestring (envstr) : envstr; \
- ++ export_env[export_env_index] = (char *)NULL; \
- ++ } while (0)
- ++
- ++/* Add ASSIGN to EXPORT_ENV, or supercede a previous assignment in the
- ++ array with the same left-hand side. Return the new EXPORT_ENV. */
- ++char **
- ++add_or_supercede_exported_var (assign, do_alloc)
- ++ char *assign;
- ++ int do_alloc;
- ++{
- ++ register int i;
- ++ int equal_offset;
- ++
- ++ equal_offset = assignment (assign, 0);
- ++ if (equal_offset == 0)
- ++ return (export_env);
- ++
- ++ /* If this is a function, then only supersede the function definition.
- ++ We do this by including the `=() {' in the comparison, like
- ++ initialize_shell_variables does. */
- ++ if (assign[equal_offset + 1] == '(' &&
- ++ strncmp (assign + equal_offset + 2, ") {", 3) == 0) /* } */
- ++ equal_offset += 4;
- ++
- ++ for (i = 0; i < export_env_index; i++)
- ++ {
- ++ if (STREQN (assign, export_env[i], equal_offset + 1))
- ++ {
- ++ free (export_env[i]);
- ++ export_env[i] = do_alloc ? savestring (assign) : assign;
- ++ return (export_env);
- ++ }
- ++ }
- ++ add_to_export_env (assign, do_alloc);
- ++ return (export_env);
- ++}
- ++
- ++static void
- ++add_temp_array_to_env (temp_array, do_alloc, do_supercede)
- ++ char **temp_array;
- ++ int do_alloc, do_supercede;
- ++{
- ++ register int i;
- ++
- ++ if (temp_array == 0)
- ++ return;
- ++
- ++ for (i = 0; temp_array[i]; i++)
- ++ {
- ++ if (do_supercede)
- ++ export_env = add_or_supercede_exported_var (temp_array[i], do_alloc);
- ++ else
- ++ add_to_export_env (temp_array[i], do_alloc);
- ++ }
- ++
- ++ free (temp_array);
- ++}
- ++
- ++/* Make the environment array for the command about to be executed, if the
- ++ array needs making. Otherwise, do nothing. If a shell action could
- ++ change the array that commands receive for their environment, then the
- ++ code should `array_needs_making++'.
- ++
- ++ The order to add to the array is:
- ++ temporary_env
- ++ list of var contexts whose head is shell_variables
- ++ shell_functions
- ++
- ++ This is the shell variable lookup order. We add only new variable
- ++ names at each step, which allows local variables and variables in
- ++ the temporary environments to shadow variables in the global (or
- ++ any previous) scope.
- ++*/
- ++
- ++static int
- ++n_shell_variables ()
- ++{
- ++ VAR_CONTEXT *vc;
- ++ int n;
- ++
- ++ for (n = 0, vc = shell_variables; vc; vc = vc->down)
- ++ n += HASH_ENTRIES (vc->table);
- ++ return n;
- ++}
- ++
- ++int
- ++chkexport (name)
- ++ char *name;
- ++{
- ++ SHELL_VAR *v;
- ++
- ++ v = find_variable (name);
- ++ if (v && exported_p (v))
- ++ {
- ++ array_needs_making = 1;
- ++ maybe_make_export_env ();
- ++ return 1;
- ++ }
- ++ return 0;
- ++}
- ++
- ++void
- ++maybe_make_export_env ()
- ++{
- ++ register char **temp_array;
- ++ int new_size;
- ++ VAR_CONTEXT *tcxt;
- ++
- ++ if (array_needs_making)
- ++ {
- ++ if (export_env)
- ++ strvec_flush (export_env);
- ++
- ++ /* Make a guess based on how many shell variables and functions we
- ++ have. Since there will always be array variables, and array
- ++ variables are not (yet) exported, this will always be big enough
- ++ for the exported variables and functions. */
- ++ new_size = n_shell_variables () + HASH_ENTRIES (shell_functions) + 1 +
- ++ HASH_ENTRIES (temporary_env);
- ++ if (new_size > export_env_size)
- ++ {
- ++ export_env_size = new_size;
- ++ export_env = strvec_resize (export_env, export_env_size);
- ++ environ = export_env;
- ++ }
- ++ export_env[export_env_index = 0] = (char *)NULL;
- ++
- ++ /* Make a dummy variable context from the temporary_env, stick it on
- ++ the front of shell_variables, call make_var_export_array on the
- ++ whole thing to flatten it, and convert the list of SHELL_VAR *s
- ++ to the form needed by the environment. */
- ++ if (temporary_env)
- ++ {
- ++ tcxt = new_var_context ((char *)NULL, 0);
- ++ tcxt->table = temporary_env;
- ++ tcxt->down = shell_variables;
- ++ }
- ++ else
- ++ tcxt = shell_variables;
- ++
- ++ temp_array = make_var_export_array (tcxt);
- ++ if (temp_array)
- ++ add_temp_array_to_env (temp_array, 0, 0);
- ++
- ++ if (tcxt != shell_variables)
- ++ free (tcxt);
- ++
- ++#if defined (RESTRICTED_SHELL)
- ++ /* Restricted shells may not export shell functions. */
- ++ temp_array = restricted ? (char **)0 : make_func_export_array ();
- ++#else
- ++ temp_array = make_func_export_array ();
- ++#endif
- ++ if (temp_array)
- ++ add_temp_array_to_env (temp_array, 0, 0);
- ++
- ++ array_needs_making = 0;
- ++ }
- ++}
- ++
- ++/* This is an efficiency hack. PWD and OLDPWD are auto-exported, so
- ++ we will need to remake the exported environment every time we
- ++ change directories. `_' is always put into the environment for
- ++ every external command, so without special treatment it will always
- ++ cause the environment to be remade.
- ++
- ++ If there is no other reason to make the exported environment, we can
- ++ just update the variables in place and mark the exported environment
- ++ as no longer needing a remake. */
- ++void
- ++update_export_env_inplace (env_prefix, preflen, value)
- ++ char *env_prefix;
- ++ int preflen;
- ++ char *value;
- ++{
- ++ char *evar;
- ++
- ++ evar = (char *)xmalloc (STRLEN (value) + preflen + 1);
- ++ strcpy (evar, env_prefix);
- ++ if (value)
- ++ strcpy (evar + preflen, value);
- ++ export_env = add_or_supercede_exported_var (evar, 0);
- ++}
- ++
- ++/* We always put _ in the environment as the name of this command. */
- ++void
- ++put_command_name_into_env (command_name)
- ++ char *command_name;
- ++{
- ++ update_export_env_inplace ("_=", 2, command_name);
- ++}
- ++
- ++/* **************************************************************** */
- ++/* */
- ++/* Managing variable contexts */
- ++/* */
- ++/* **************************************************************** */
- ++
- ++/* Allocate and return a new variable context with NAME and FLAGS.
- ++ NAME can be NULL. */
- ++
- ++VAR_CONTEXT *
- ++new_var_context (name, flags)
- ++ char *name;
- ++ int flags;
- ++{
- ++ VAR_CONTEXT *vc;
- ++
- ++ vc = (VAR_CONTEXT *)xmalloc (sizeof (VAR_CONTEXT));
- ++ vc->name = name ? savestring (name) : (char *)NULL;
- ++ vc->scope = variable_context;
- ++ vc->flags = flags;
- ++
- ++ vc->up = vc->down = (VAR_CONTEXT *)NULL;
- ++ vc->table = (HASH_TABLE *)NULL;
- ++
- ++ return vc;
- ++}
- ++
- ++/* Free a variable context and its data, including the hash table. Dispose
- ++ all of the variables. */
- ++void
- ++dispose_var_context (vc)
- ++ VAR_CONTEXT *vc;
- ++{
- ++ FREE (vc->name);
- ++
- ++ if (vc->table)
- ++ {
- ++ delete_all_variables (vc->table);
- ++ hash_dispose (vc->table);
- ++ }
- ++
- ++ free (vc);
- ++}
- ++
- ++/* Set VAR's scope level to the current variable context. */
- ++static int
- ++set_context (var)
- ++ SHELL_VAR *var;
- ++{
- ++ return (var->context = variable_context);
- ++}
- ++
- ++/* Make a new variable context with NAME and FLAGS and a HASH_TABLE of
- ++ temporary variables, and push it onto shell_variables. This is
- ++ for shell functions. */
- ++VAR_CONTEXT *
- ++push_var_context (name, flags, tempvars)
- ++ char *name;
- ++ int flags;
- ++ HASH_TABLE *tempvars;
- ++{
- ++ VAR_CONTEXT *vc;
- ++
- ++ vc = new_var_context (name, flags);
- ++ vc->table = tempvars;
- ++ if (tempvars)
- ++ {
- ++ /* Have to do this because the temp environment was created before
- ++ variable_context was incremented. */
- ++ flatten (tempvars, set_context, (VARLIST *)NULL, 0);
- ++ vc->flags |= VC_HASTMPVAR;
- ++ }
- ++ vc->down = shell_variables;
- ++ shell_variables->up = vc;
- ++
- ++ return (shell_variables = vc);
- ++}
- ++
- ++static void
- ++push_func_var (data)
- ++ PTR_T data;
- ++{
- ++ SHELL_VAR *var, *v;
- ++
- ++ var = (SHELL_VAR *)data;
- ++
- ++ if (tempvar_p (var) && (posixly_correct || (var->attributes & att_propagate)))
- ++ {
- ++ /* Make sure we have a hash table to store the variable in while it is
- ++ being propagated down to the global variables table. Create one if
- ++ we have to */
- ++ if ((vc_isfuncenv (shell_variables) || vc_istempenv (shell_variables)) && shell_variables->table == 0)
- ++ shell_variables->table = hash_create (0);
- ++ /* XXX - should we set v->context here? */
- ++ v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);
- ++ if (shell_variables == global_variables)
- ++ var->attributes &= ~(att_tempvar|att_propagate);
- ++ else
- ++ shell_variables->flags |= VC_HASTMPVAR;
- ++ v->attributes |= var->attributes;
- ++ }
- ++ else
- ++ stupidly_hack_special_variables (var->name); /* XXX */
- ++
- ++ dispose_variable (var);
- ++}
- ++
- ++/* Pop the top context off of VCXT and dispose of it, returning the rest of
- ++ the stack. */
- ++void
- ++pop_var_context ()
- ++{
- ++ VAR_CONTEXT *ret, *vcxt;
- ++
- ++ vcxt = shell_variables;
- ++ if (vc_isfuncenv (vcxt) == 0)
- ++ {
- ++ internal_error (_("pop_var_context: head of shell_variables not a function context"));
- ++ return;
- ++ }
- ++
- ++ if (ret = vcxt->down)
- ++ {
- ++ ret->up = (VAR_CONTEXT *)NULL;
- ++ shell_variables = ret;
- ++ if (vcxt->table)
- ++ hash_flush (vcxt->table, push_func_var);
- ++ dispose_var_context (vcxt);
- ++ }
- ++ else
- ++ internal_error (_("pop_var_context: no global_variables context"));
- ++}
- ++
- ++/* Delete the HASH_TABLEs for all variable contexts beginning at VCXT, and
- ++ all of the VAR_CONTEXTs except GLOBAL_VARIABLES. */
- ++void
- ++delete_all_contexts (vcxt)
- ++ VAR_CONTEXT *vcxt;
- ++{
- ++ VAR_CONTEXT *v, *t;
- ++
- ++ for (v = vcxt; v != global_variables; v = t)
- ++ {
- ++ t = v->down;
- ++ dispose_var_context (v);
- ++ }
- ++
- ++ delete_all_variables (global_variables->table);
- ++ shell_variables = global_variables;
- ++}
- ++
- ++/* **************************************************************** */
- ++/* */
- ++/* Pushing and Popping temporary variable scopes */
- ++/* */
- ++/* **************************************************************** */
- ++
- ++VAR_CONTEXT *
- ++push_scope (flags, tmpvars)
- ++ int flags;
- ++ HASH_TABLE *tmpvars;
- ++{
- ++ return (push_var_context ((char *)NULL, flags, tmpvars));
- ++}
- ++
- ++static void
- ++push_exported_var (data)
- ++ PTR_T data;
- ++{
- ++ SHELL_VAR *var, *v;
- ++
- ++ var = (SHELL_VAR *)data;
- ++
- ++ /* If a temp var had its export attribute set, or it's marked to be
- ++ propagated, bind it in the previous scope before disposing it. */
- ++ /* XXX - This isn't exactly right, because all tempenv variables have the
- ++ export attribute set. */
- ++#if 0
- ++ if (exported_p (var) || (var->attributes & att_propagate))
- ++#else
- ++ if (tempvar_p (var) && exported_p (var) && (var->attributes & att_propagate))
- ++#endif
- ++ {
- ++ var->attributes &= ~att_tempvar; /* XXX */
- ++ v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);
- ++ if (shell_variables == global_variables)
- ++ var->attributes &= ~att_propagate;
- ++ v->attributes |= var->attributes;
- ++ }
- ++ else
- ++ stupidly_hack_special_variables (var->name); /* XXX */
- ++
- ++ dispose_variable (var);
- ++}
- ++
- ++void
- ++pop_scope (is_special)
- ++ int is_special;
- ++{
- ++ VAR_CONTEXT *vcxt, *ret;
- ++
- ++ vcxt = shell_variables;
- ++ if (vc_istempscope (vcxt) == 0)
- ++ {
- ++ internal_error (_("pop_scope: head of shell_variables not a temporary environment scope"));
- ++ return;
- ++ }
- ++
- ++ ret = vcxt->down;
- ++ if (ret)
- ++ ret->up = (VAR_CONTEXT *)NULL;
- ++
- ++ shell_variables = ret;
- ++
- ++ /* Now we can take care of merging variables in VCXT into set of scopes
- ++ whose head is RET (shell_variables). */
- ++ FREE (vcxt->name);
- ++ if (vcxt->table)
- ++ {
- ++ if (is_special)
- ++ hash_flush (vcxt->table, push_func_var);
- ++ else
- ++ hash_flush (vcxt->table, push_exported_var);
- ++ hash_dispose (vcxt->table);
- ++ }
- ++ free (vcxt);
- ++
- ++ sv_ifs ("IFS"); /* XXX here for now */
- ++}
- ++
- ++/* **************************************************************** */
- ++/* */
- ++/* Pushing and Popping function contexts */
- ++/* */
- ++/* **************************************************************** */
- ++
- ++static WORD_LIST **dollar_arg_stack = (WORD_LIST **)NULL;
- ++static int dollar_arg_stack_slots;
- ++static int dollar_arg_stack_index;
- ++
- ++/* XXX - we might want to consider pushing and popping the `getopts' state
- ++ when we modify the positional parameters. */
- ++void
- ++push_context (name, is_subshell, tempvars)
- ++ char *name; /* function name */
- ++ int is_subshell;
- ++ HASH_TABLE *tempvars;
- ++{
- ++ if (is_subshell == 0)
- ++ push_dollar_vars ();
- ++ variable_context++;
- ++ push_var_context (name, VC_FUNCENV, tempvars);
- ++}
- ++
- ++/* Only called when subshell == 0, so we don't need to check, and can
- ++ unconditionally pop the dollar vars off the stack. */
- ++void
- ++pop_context ()
- ++{
- ++ pop_dollar_vars ();
- ++ variable_context--;
- ++ pop_var_context ();
- ++
- ++ sv_ifs ("IFS"); /* XXX here for now */
- ++}
- ++
- ++/* Save the existing positional parameters on a stack. */
- ++void
- ++push_dollar_vars ()
- ++{
- ++ if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots)
- ++ {
- ++ dollar_arg_stack = (WORD_LIST **)
- ++ xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10)
- ++ * sizeof (WORD_LIST *));
- ++ }
- ++ dollar_arg_stack[dollar_arg_stack_index++] = list_rest_of_args ();
- ++ dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
- ++}
- ++
- ++/* Restore the positional parameters from our stack. */
- ++void
- ++pop_dollar_vars ()
- ++{
- ++ if (!dollar_arg_stack || dollar_arg_stack_index == 0)
- ++ return;
- ++
- ++ remember_args (dollar_arg_stack[--dollar_arg_stack_index], 1);
- ++ dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
- ++ dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
- ++ set_dollar_vars_unchanged ();
- ++}
- ++
- ++void
- ++dispose_saved_dollar_vars ()
- ++{
- ++ if (!dollar_arg_stack || dollar_arg_stack_index == 0)
- ++ return;
- ++
- ++ dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
- ++ dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
- ++}
- ++
- ++/* Manipulate the special BASH_ARGV and BASH_ARGC variables. */
- ++
- ++void
- ++push_args (list)
- ++ WORD_LIST *list;
- ++{
- ++#if defined (ARRAY_VARS) && defined (DEBUGGER)
- ++ SHELL_VAR *bash_argv_v, *bash_argc_v;
- ++ ARRAY *bash_argv_a, *bash_argc_a;
- ++ WORD_LIST *l;
- ++ arrayind_t i;
- ++ char *t;
- ++
- ++ GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
- ++ GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
- ++
- ++ for (l = list, i = 0; l; l = l->next, i++)
- ++ array_push (bash_argv_a, l->word->word);
- ++
- ++ t = itos (i);
- ++ array_push (bash_argc_a, t);
- ++ free (t);
- ++#endif /* ARRAY_VARS && DEBUGGER */
- ++}
- ++
- ++/* Remove arguments from BASH_ARGV array. Pop top element off BASH_ARGC
- ++ array and use that value as the count of elements to remove from
- ++ BASH_ARGV. */
- ++void
- ++pop_args ()
- ++{
- ++#if defined (ARRAY_VARS) && defined (DEBUGGER)
- ++ SHELL_VAR *bash_argv_v, *bash_argc_v;
- ++ ARRAY *bash_argv_a, *bash_argc_a;
- ++ ARRAY_ELEMENT *ce;
- ++ intmax_t i;
- ++
- ++ GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
- ++ GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
- ++
- ++ ce = array_shift (bash_argc_a, 1, 0);
- ++ if (ce == 0 || legal_number (element_value (ce), &i) == 0)
- ++ i = 0;
- ++
- ++ for ( ; i > 0; i--)
- ++ array_pop (bash_argv_a);
- ++ array_dispose_element (ce);
- ++#endif /* ARRAY_VARS && DEBUGGER */
- ++}
- ++
- ++/*************************************************
- ++ * *
- ++ * Functions to manage special variables *
- ++ * *
- ++ *************************************************/
- ++
- ++/* Extern declarations for variables this code has to manage. */
- ++extern int eof_encountered, eof_encountered_limit, ignoreeof;
- ++
- ++#if defined (READLINE)
- ++extern int hostname_list_initialized;
- ++#endif
- ++
- ++/* An alist of name.function for each special variable. Most of the
- ++ functions don't do much, and in fact, this would be faster with a
- ++ switch statement, but by the end of this file, I am sick of switch
- ++ statements. */
- ++
- ++#define SET_INT_VAR(name, intvar) intvar = find_variable (name) != 0
- ++
- ++/* This table will be sorted with qsort() the first time it's accessed. */
- ++struct name_and_function {
- ++ char *name;
- ++ sh_sv_func_t *function;
- ++};
- ++
- ++static struct name_and_function special_vars[] = {
- ++ { "BASH_COMPAT", sv_shcompat },
- ++ { "BASH_XTRACEFD", sv_xtracefd },
- ++
- ++#if defined (JOB_CONTROL)
- ++ { "CHILD_MAX", sv_childmax },
- ++#endif
- ++
- ++#if defined (READLINE)
- ++# if defined (STRICT_POSIX)
- ++ { "COLUMNS", sv_winsize },
- ++# endif
- ++ { "COMP_WORDBREAKS", sv_comp_wordbreaks },
- ++#endif
- ++
- ++ { "FUNCNEST", sv_funcnest },
- ++
- ++ { "GLOBIGNORE", sv_globignore },
- ++
- ++#if defined (HISTORY)
- ++ { "HISTCONTROL", sv_history_control },
- ++ { "HISTFILESIZE", sv_histsize },
- ++ { "HISTIGNORE", sv_histignore },
- ++ { "HISTSIZE", sv_histsize },
- ++ { "HISTTIMEFORMAT", sv_histtimefmt },
- ++#endif
- ++
- ++#if defined (__CYGWIN__)
- ++ { "HOME", sv_home },
- ++#endif
- ++
- ++#if defined (READLINE)
- ++ { "HOSTFILE", sv_hostfile },
- ++#endif
- ++
- ++ { "IFS", sv_ifs },
- ++ { "IGNOREEOF", sv_ignoreeof },
- ++
- ++ { "LANG", sv_locale },
- ++ { "LC_ALL", sv_locale },
- ++ { "LC_COLLATE", sv_locale },
- ++ { "LC_CTYPE", sv_locale },
- ++ { "LC_MESSAGES", sv_locale },
- ++ { "LC_NUMERIC", sv_locale },
- ++ { "LC_TIME", sv_locale },
- ++
- ++#if defined (READLINE) && defined (STRICT_POSIX)
- ++ { "LINES", sv_winsize },
- ++#endif
- ++
- ++ { "MAIL", sv_mail },
- ++ { "MAILCHECK", sv_mail },
- ++ { "MAILPATH", sv_mail },
- ++
- ++ { "OPTERR", sv_opterr },
- ++ { "OPTIND", sv_optind },
- ++
- ++ { "PATH", sv_path },
- ++ { "POSIXLY_CORRECT", sv_strict_posix },
- ++
- ++#if defined (READLINE)
- ++ { "TERM", sv_terminal },
- ++ { "TERMCAP", sv_terminal },
- ++ { "TERMINFO", sv_terminal },
- ++#endif /* READLINE */
- ++
- ++ { "TEXTDOMAIN", sv_locale },
- ++ { "TEXTDOMAINDIR", sv_locale },
- ++
- ++#if defined (HAVE_TZSET)
- ++ { "TZ", sv_tz },
- ++#endif
- ++
- ++#if defined (HISTORY) && defined (BANG_HISTORY)
- ++ { "histchars", sv_histchars },
- ++#endif /* HISTORY && BANG_HISTORY */
- ++
- ++ { "ignoreeof", sv_ignoreeof },
- ++
- ++ { (char *)0, (sh_sv_func_t *)0 }
- ++};
- ++
- ++#define N_SPECIAL_VARS (sizeof (special_vars) / sizeof (special_vars[0]) - 1)
- ++
- ++static int
- ++sv_compare (sv1, sv2)
- ++ struct name_and_function *sv1, *sv2;
- ++{
- ++ int r;
- ++
- ++ if ((r = sv1->name[0] - sv2->name[0]) == 0)
- ++ r = strcmp (sv1->name, sv2->name);
- ++ return r;
- ++}
- ++
- ++static inline int
- ++find_special_var (name)
- ++ const char *name;
- ++{
- ++ register int i, r;
- ++
- ++ for (i = 0; special_vars[i].name; i++)
- ++ {
- ++ r = special_vars[i].name[0] - name[0];
- ++ if (r == 0)
- ++ r = strcmp (special_vars[i].name, name);
- ++ if (r == 0)
- ++ return i;
- ++ else if (r > 0)
- ++ /* Can't match any of rest of elements in sorted list. Take this out
- ++ if it causes problems in certain environments. */
- ++ break;
- ++ }
- ++ return -1;
- ++}
- ++
- ++/* The variable in NAME has just had its state changed. Check to see if it
- ++ is one of the special ones where something special happens. */
- ++void
- ++stupidly_hack_special_variables (name)
- ++ char *name;
- ++{
- ++ static int sv_sorted = 0;
- ++ int i;
- ++
- ++ if (sv_sorted == 0) /* shouldn't need, but it's fairly cheap. */
- ++ {
- ++ qsort (special_vars, N_SPECIAL_VARS, sizeof (special_vars[0]),
- ++ (QSFUNC *)sv_compare);
- ++ sv_sorted = 1;
- ++ }
- ++
- ++ i = find_special_var (name);
- ++ if (i != -1)
- ++ (*(special_vars[i].function)) (name);
- ++}
- ++
- ++/* Special variables that need hooks to be run when they are unset as part
- ++ of shell reinitialization should have their sv_ functions run here. */
- ++void
- ++reinit_special_variables ()
- ++{
- ++#if defined (READLINE)
- ++ sv_comp_wordbreaks ("COMP_WORDBREAKS");
- ++#endif
- ++ sv_globignore ("GLOBIGNORE");
- ++ sv_opterr ("OPTERR");
- ++}
- ++
- ++void
- ++sv_ifs (name)
- ++ char *name;
- ++{
- ++ SHELL_VAR *v;
- ++
- ++ v = find_variable ("IFS");
- ++ setifs (v);
- ++}
- ++
- ++/* What to do just after the PATH variable has changed. */
- ++void
- ++sv_path (name)
- ++ char *name;
- ++{
- ++ /* hash -r */
- ++ phash_flush ();
- ++}
- ++
- ++/* What to do just after one of the MAILxxxx variables has changed. NAME
- ++ is the name of the variable. This is called with NAME set to one of
- ++ MAIL, MAILCHECK, or MAILPATH. */
- ++void
- ++sv_mail (name)
- ++ char *name;
- ++{
- ++ /* If the time interval for checking the files has changed, then
- ++ reset the mail timer. Otherwise, one of the pathname vars
- ++ to the users mailbox has changed, so rebuild the array of
- ++ filenames. */
- ++ if (name[4] == 'C') /* if (strcmp (name, "MAILCHECK") == 0) */
- ++ reset_mail_timer ();
- ++ else
- ++ {
- ++ free_mail_files ();
- ++ remember_mail_dates ();
- ++ }
- ++}
- ++
- ++void
- ++sv_funcnest (name)
- ++ char *name;
- ++{
- ++ SHELL_VAR *v;
- ++ intmax_t num;
- ++
- ++ v = find_variable (name);
- ++ if (v == 0)
- ++ funcnest_max = 0;
- ++ else if (legal_number (value_cell (v), &num) == 0)
- ++ funcnest_max = 0;
- ++ else
- ++ funcnest_max = num;
- ++}
- ++
- ++/* What to do when GLOBIGNORE changes. */
- ++void
- ++sv_globignore (name)
- ++ char *name;
- ++{
- ++ if (privileged_mode == 0)
- ++ setup_glob_ignore (name);
- ++}
- ++
- ++#if defined (READLINE)
- ++void
- ++sv_comp_wordbreaks (name)
- ++ char *name;
- ++{
- ++ SHELL_VAR *sv;
- ++
- ++ sv = find_variable (name);
- ++ if (sv == 0)
- ++ reset_completer_word_break_chars ();
- ++}
- ++
- ++/* What to do just after one of the TERMxxx variables has changed.
- ++ If we are an interactive shell, then try to reset the terminal
- ++ information in readline. */
- ++void
- ++sv_terminal (name)
- ++ char *name;
- ++{
- ++ if (interactive_shell && no_line_editing == 0)
- ++ rl_reset_terminal (get_string_value ("TERM"));
- ++}
- ++
- ++void
- ++sv_hostfile (name)
- ++ char *name;
- ++{
- ++ SHELL_VAR *v;
- ++
- ++ v = find_variable (name);
- ++ if (v == 0)
- ++ clear_hostname_list ();
- ++ else
- ++ hostname_list_initialized = 0;
- ++}
- ++
- ++#if defined (STRICT_POSIX)
- ++/* In strict posix mode, we allow assignments to LINES and COLUMNS (and values
- ++ found in the initial environment) to override the terminal size reported by
- ++ the kernel. */
- ++void
- ++sv_winsize (name)
- ++ char *name;
- ++{
- ++ SHELL_VAR *v;
- ++ intmax_t xd;
- ++ int d;
- ++
- ++ if (posixly_correct == 0 || interactive_shell == 0 || no_line_editing)
- ++ return;
- ++
- ++ v = find_variable (name);
- ++ if (v == 0 || var_isnull (v))
- ++ rl_reset_screen_size ();
- ++ else
- ++ {
- ++ if (legal_number (value_cell (v), &xd) == 0)
- ++ return;
- ++ winsize_assignment = 1;
- ++ d = xd; /* truncate */
- ++ if (name[0] == 'L') /* LINES */
- ++ rl_set_screen_size (d, -1);
- ++ else /* COLUMNS */
- ++ rl_set_screen_size (-1, d);
- ++ winsize_assignment = 0;
- ++ }
- ++}
- ++#endif /* STRICT_POSIX */
- ++#endif /* READLINE */
- ++
- ++/* Update the value of HOME in the export environment so tilde expansion will
- ++ work on cygwin. */
- ++#if defined (__CYGWIN__)
- ++sv_home (name)
- ++ char *name;
- ++{
- ++ array_needs_making = 1;
- ++ maybe_make_export_env ();
- ++}
- ++#endif
- ++
- ++#if defined (HISTORY)
- ++/* What to do after the HISTSIZE or HISTFILESIZE variables change.
- ++ If there is a value for this HISTSIZE (and it is numeric), then stifle
- ++ the history. Otherwise, if there is NO value for this variable,
- ++ unstifle the history. If name is HISTFILESIZE, and its value is
- ++ numeric, truncate the history file to hold no more than that many
- ++ lines. */
- ++void
- ++sv_histsize (name)
- ++ char *name;
- ++{
- ++ char *temp;
- ++ intmax_t num;
- ++ int hmax;
- ++
- ++ temp = get_string_value (name);
- ++
- ++ if (temp && *temp)
- ++ {
- ++ if (legal_number (temp, &num))
- ++ {
- ++ hmax = num;
- ++ if (hmax < 0 && name[4] == 'S')
- ++ unstifle_history (); /* unstifle history if HISTSIZE < 0 */
- ++ else if (name[4] == 'S')
- ++ {
- ++ stifle_history (hmax);
- ++ hmax = where_history ();
- ++ if (history_lines_this_session > hmax)
- ++ history_lines_this_session = hmax;
- ++ }
- ++ else if (hmax >= 0) /* truncate HISTFILE if HISTFILESIZE >= 0 */
- ++ {
- ++ history_truncate_file (get_string_value ("HISTFILE"), hmax);
- ++ if (hmax <= history_lines_in_file)
- ++ history_lines_in_file = hmax;
- ++ }
- ++ }
- ++ }
- ++ else if (name[4] == 'S')
- ++ unstifle_history ();
- ++}
- ++
- ++/* What to do after the HISTIGNORE variable changes. */
- ++void
- ++sv_histignore (name)
- ++ char *name;
- ++{
- ++ setup_history_ignore (name);
- ++}
- ++
- ++/* What to do after the HISTCONTROL variable changes. */
- ++void
- ++sv_history_control (name)
- ++ char *name;
- ++{
- ++ char *temp;
- ++ char *val;
- ++ int tptr;
- ++
- ++ history_control = 0;
- ++ temp = get_string_value (name);
- ++
- ++ if (temp == 0 || *temp == 0)
- ++ return;
- ++
- ++ tptr = 0;
- ++ while (val = extract_colon_unit (temp, &tptr))
- ++ {
- ++ if (STREQ (val, "ignorespace"))
- ++ history_control |= HC_IGNSPACE;
- ++ else if (STREQ (val, "ignoredups"))
- ++ history_control |= HC_IGNDUPS;
- ++ else if (STREQ (val, "ignoreboth"))
- ++ history_control |= HC_IGNBOTH;
- ++ else if (STREQ (val, "erasedups"))
- ++ history_control |= HC_ERASEDUPS;
- ++
- ++ free (val);
- ++ }
- ++}
- ++
- ++#if defined (BANG_HISTORY)
- ++/* Setting/unsetting of the history expansion character. */
- ++void
- ++sv_histchars (name)
- ++ char *name;
- ++{
- ++ char *temp;
- ++
- ++ temp = get_string_value (name);
- ++ if (temp)
- ++ {
- ++ history_expansion_char = *temp;
- ++ if (temp[0] && temp[1])
- ++ {
- ++ history_subst_char = temp[1];
- ++ if (temp[2])
- ++ history_comment_char = temp[2];
- ++ }
- ++ }
- ++ else
- ++ {
- ++ history_expansion_char = '!';
- ++ history_subst_char = '^';
- ++ history_comment_char = '#';
- ++ }
- ++}
- ++#endif /* BANG_HISTORY */
- ++
- ++void
- ++sv_histtimefmt (name)
- ++ char *name;
- ++{
- ++ SHELL_VAR *v;
- ++
- ++ if (v = find_variable (name))
- ++ {
- ++ if (history_comment_char == 0)
- ++ history_comment_char = '#';
- ++ }
- ++ history_write_timestamps = (v != 0);
- ++}
- ++#endif /* HISTORY */
- ++
- ++#if defined (HAVE_TZSET)
- ++void
- ++sv_tz (name)
- ++ char *name;
- ++{
- ++ if (chkexport (name))
- ++ tzset ();
- ++}
- ++#endif
- ++
- ++/* If the variable exists, then the value of it can be the number
- ++ of times we actually ignore the EOF. The default is small,
- ++ (smaller than csh, anyway). */
- ++void
- ++sv_ignoreeof (name)
- ++ char *name;
- ++{
- ++ SHELL_VAR *tmp_var;
- ++ char *temp;
- ++
- ++ eof_encountered = 0;
- ++
- ++ tmp_var = find_variable (name);
- ++ ignoreeof = tmp_var != 0;
- ++ temp = tmp_var ? value_cell (tmp_var) : (char *)NULL;
- ++ if (temp)
- ++ eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10;
- ++ set_shellopts (); /* make sure `ignoreeof' is/is not in $SHELLOPTS */
- ++}
- ++
- ++void
- ++sv_optind (name)
- ++ char *name;
- ++{
- ++ char *tt;
- ++ int s;
- ++
- ++ tt = get_string_value ("OPTIND");
- ++ if (tt && *tt)
- ++ {
- ++ s = atoi (tt);
- ++
- ++ /* According to POSIX, setting OPTIND=1 resets the internal state
- ++ of getopt (). */
- ++ if (s < 0 || s == 1)
- ++ s = 0;
- ++ }
- ++ else
- ++ s = 0;
- ++ getopts_reset (s);
- ++}
- ++
- ++void
- ++sv_opterr (name)
- ++ char *name;
- ++{
- ++ char *tt;
- ++
- ++ tt = get_string_value ("OPTERR");
- ++ sh_opterr = (tt && *tt) ? atoi (tt) : 1;
- ++}
- ++
- ++void
- ++sv_strict_posix (name)
- ++ char *name;
- ++{
- ++ SET_INT_VAR (name, posixly_correct);
- ++ posix_initialize (posixly_correct);
- ++#if defined (READLINE)
- ++ if (interactive_shell)
- ++ posix_readline_initialize (posixly_correct);
- ++#endif /* READLINE */
- ++ set_shellopts (); /* make sure `posix' is/is not in $SHELLOPTS */
- ++}
- ++
- ++void
- ++sv_locale (name)
- ++ char *name;
- ++{
- ++ char *v;
- ++ int r;
- ++
- ++ v = get_string_value (name);
- ++ if (name[0] == 'L' && name[1] == 'A') /* LANG */
- ++ r = set_lang (name, v);
- ++ else
- ++ r = set_locale_var (name, v); /* LC_*, TEXTDOMAIN* */
- ++
- ++#if 1
- ++ if (r == 0 && posixly_correct)
- ++ last_command_exit_value = 1;
- ++#endif
- ++}
- ++
- ++#if defined (ARRAY_VARS)
- ++void
- ++set_pipestatus_array (ps, nproc)
- ++ int *ps;
- ++ int nproc;
- ++{
- ++ SHELL_VAR *v;
- ++ ARRAY *a;
- ++ ARRAY_ELEMENT *ae;
- ++ register int i;
- ++ char *t, tbuf[INT_STRLEN_BOUND(int) + 1];
- ++
- ++ v = find_variable ("PIPESTATUS");
- ++ if (v == 0)
- ++ v = make_new_array_variable ("PIPESTATUS");
- ++ if (array_p (v) == 0)
- ++ return; /* Do nothing if not an array variable. */
- ++ a = array_cell (v);
- ++
- ++ if (a == 0 || array_num_elements (a) == 0)
- ++ {
- ++ for (i = 0; i < nproc; i++) /* was ps[i] != -1, not i < nproc */
- ++ {
- ++ t = inttostr (ps[i], tbuf, sizeof (tbuf));
- ++ array_insert (a, i, t);
- ++ }
- ++ return;
- ++ }
- ++
- ++ /* Fast case */
- ++ if (array_num_elements (a) == nproc && nproc == 1)
- ++ {
- ++ ae = element_forw (a->head);
- ++ free (element_value (ae));
- ++ ae->value = itos (ps[0]);
- ++ }
- ++ else if (array_num_elements (a) <= nproc)
- ++ {
- ++ /* modify in array_num_elements members in place, then add */
- ++ ae = a->head;
- ++ for (i = 0; i < array_num_elements (a); i++)
- ++ {
- ++ ae = element_forw (ae);
- ++ free (element_value (ae));
- ++ ae->value = itos (ps[i]);
- ++ }
- ++ /* add any more */
- ++ for ( ; i < nproc; i++)
- ++ {
- ++ t = inttostr (ps[i], tbuf, sizeof (tbuf));
- ++ array_insert (a, i, t);
- ++ }
- ++ }
- ++ else
- ++ {
- ++ /* deleting elements. it's faster to rebuild the array. */
- ++ array_flush (a);
- ++ for (i = 0; ps[i] != -1; i++)
- ++ {
- ++ t = inttostr (ps[i], tbuf, sizeof (tbuf));
- ++ array_insert (a, i, t);
- ++ }
- ++ }
- ++}
- ++
- ++ARRAY *
- ++save_pipestatus_array ()
- ++{
- ++ SHELL_VAR *v;
- ++ ARRAY *a, *a2;
- ++
- ++ v = find_variable ("PIPESTATUS");
- ++ if (v == 0 || array_p (v) == 0 || array_cell (v) == 0)
- ++ return ((ARRAY *)NULL);
- ++
- ++ a = array_cell (v);
- ++ a2 = array_copy (array_cell (v));
- ++
- ++ return a2;
- ++}
- ++
- ++void
- ++restore_pipestatus_array (a)
- ++ ARRAY *a;
- ++{
- ++ SHELL_VAR *v;
- ++ ARRAY *a2;
- ++
- ++ v = find_variable ("PIPESTATUS");
- ++ /* XXX - should we still assign even if existing value is NULL? */
- ++ if (v == 0 || array_p (v) == 0 || array_cell (v) == 0)
- ++ return;
- ++
- ++ a2 = array_cell (v);
- ++ var_setarray (v, a);
- ++
- ++ array_dispose (a2);
- ++}
- ++#endif
- ++
- ++void
- ++set_pipestatus_from_exit (s)
- ++ int s;
- ++{
- ++#if defined (ARRAY_VARS)
- ++ static int v[2] = { 0, -1 };
- ++
- ++ v[0] = s;
- ++ set_pipestatus_array (v, 1);
- ++#endif
- ++}
- ++
- ++void
- ++sv_xtracefd (name)
- ++ char *name;
- ++{
- ++ SHELL_VAR *v;
- ++ char *t, *e;
- ++ int fd;
- ++ FILE *fp;
- ++
- ++ v = find_variable (name);
- ++ if (v == 0)
- ++ {
- ++ xtrace_reset ();
- ++ return;
- ++ }
- ++
- ++ t = value_cell (v);
- ++ if (t == 0 || *t == 0)
- ++ xtrace_reset ();
- ++ else
- ++ {
- ++ fd = (int)strtol (t, &e, 10);
- ++ if (e != t && *e == '\0' && sh_validfd (fd))
- ++ {
- ++ fp = fdopen (fd, "w");
- ++ if (fp == 0)
- ++ internal_error (_("%s: %s: cannot open as FILE"), name, value_cell (v));
- ++ else
- ++ xtrace_set (fd, fp);
- ++ }
- ++ else
- ++ internal_error (_("%s: %s: invalid value for trace file descriptor"), name, value_cell (v));
- ++ }
- ++}
- ++
- ++#define MIN_COMPAT_LEVEL 31
- ++
- ++void
- ++sv_shcompat (name)
- ++ char *name;
- ++{
- ++ SHELL_VAR *v;
- ++ char *val;
- ++ int tens, ones, compatval;
- ++
- ++ v = find_variable (name);
- ++ if (v == 0)
- ++ {
- ++ shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
- ++ set_compatibility_opts ();
- ++ return;
- ++ }
- ++ val = value_cell (v);
- ++ if (val == 0 || *val == '\0')
- ++ {
- ++ shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
- ++ set_compatibility_opts ();
- ++ return;
- ++ }
- ++ /* Handle decimal-like compatibility version specifications: 4.2 */
- ++ if (isdigit (val[0]) && val[1] == '.' && isdigit (val[2]) && val[3] == 0)
- ++ {
- ++ tens = val[0] - '0';
- ++ ones = val[2] - '0';
- ++ compatval = tens*10 + ones;
- ++ }
- ++ /* Handle integer-like compatibility version specifications: 42 */
- ++ else if (isdigit (val[0]) && isdigit (val[1]) && val[2] == 0)
- ++ {
- ++ tens = val[0] - '0';
- ++ ones = val[1] - '0';
- ++ compatval = tens*10 + ones;
- ++ }
- ++ else
- ++ {
- ++compat_error:
- ++ internal_error (_("%s: %s: compatibility value out of range"), name, val);
- ++ shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
- ++ set_compatibility_opts ();
- ++ return;
- ++ }
- ++
- ++ if (compatval < MIN_COMPAT_LEVEL || compatval > DEFAULT_COMPAT_LEVEL)
- ++ goto compat_error;
- ++
- ++ shell_compatibility_level = compatval;
- ++ set_compatibility_opts ();
- ++}
- ++
- ++#if defined (JOB_CONTROL)
- ++void
- ++sv_childmax (name)
- ++ char *name;
- ++{
- ++ char *tt;
- ++ int s;
- ++
- ++ tt = get_string_value (name);
- ++ s = (tt && *tt) ? atoi (tt) : 0;
- ++ set_maxchild (s);
- ++}
- ++#endif
- diff --git a/ptxdist/patches/bash-4.3.30/0002-Bash-4.3-patch-32.patch b/ptxdist/patches/bash-4.3.30/0002-Bash-4.3-patch-32.patch
- new file mode 100644
- index 0000000..801b4a6
- --- /dev/null
- +++ b/ptxdist/patches/bash-4.3.30/0002-Bash-4.3-patch-32.patch
- @@ -0,0 +1,5409 @@
- +From: Chet Ramey <chet.ramey@case.edu>
- +Date: Thu, 15 Jan 2015 10:20:45 -0500
- +Subject: [PATCH] Bash-4.3 patch 32
- +
- +---
- + jobs.c | 4 +-
- + patchlevel.h | 2 +-
- + variables.c.orig | 5365 ------------------------------------------------------
- + 3 files changed, 4 insertions(+), 5367 deletions(-)
- + delete mode 100644 variables.c.orig
- +
- +diff --git a/jobs.c b/jobs.c
- +index f38b0c3f4446..b6e59eba0de8 100644
- +--- a/jobs.c
- ++++ b/jobs.c
- +@@ -3339,7 +3339,9 @@ itrace("waitchld: waitpid returns %d block = %d", pid, block);
- + if (posixly_correct && this_shell_builtin && this_shell_builtin == wait_builtin)
- + {
- + interrupt_immediately = 0;
- +- trap_handler (SIGCHLD); /* set pending_traps[SIGCHLD] */
- ++ /* This was trap_handler (SIGCHLD) but that can lose traps if
- ++ children_exited > 1 */
- ++ queue_sigchld_trap (children_exited);
- + wait_signal_received = SIGCHLD;
- + /* If we're in a signal handler, let CHECK_WAIT_INTR pick it up;
- + run_pending_traps will call run_sigchld_trap later */
- +diff --git a/patchlevel.h b/patchlevel.h
- +index 0ad46aafbdd9..b8bf38704ed2 100644
- +--- a/patchlevel.h
- ++++ b/patchlevel.h
- +@@ -25,6 +25,6 @@
- + regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
- + looks for to find the patch level (for the sccs version string). */
- +
- +-#define PATCHLEVEL 31
- ++#define PATCHLEVEL 32
- +
- + #endif /* _PATCHLEVEL_H_ */
- +diff --git a/variables.c.orig b/variables.c.orig
- +deleted file mode 100644
- +index 7c82710e0f0b..000000000000
- +--- a/variables.c.orig
- ++++ /dev/null
- +@@ -1,5365 +0,0 @@
- +-/* variables.c -- Functions for hacking shell variables. */
- +-
- +-/* Copyright (C) 1987-2013 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/>.
- +-*/
- +-
- +-#include "config.h"
- +-
- +-#include "bashtypes.h"
- +-#include "posixstat.h"
- +-#include "posixtime.h"
- +-
- +-#if defined (__QNX__)
- +-# if defined (__QNXNTO__)
- +-# include <sys/netmgr.h>
- +-# else
- +-# include <sys/vc.h>
- +-# endif /* !__QNXNTO__ */
- +-#endif /* __QNX__ */
- +-
- +-#if defined (HAVE_UNISTD_H)
- +-# include <unistd.h>
- +-#endif
- +-
- +-#include <stdio.h>
- +-#include "chartypes.h"
- +-#if defined (HAVE_PWD_H)
- +-# include <pwd.h>
- +-#endif
- +-#include "bashansi.h"
- +-#include "bashintl.h"
- +-
- +-#define NEED_XTRACE_SET_DECL
- +-
- +-#include "shell.h"
- +-#include "flags.h"
- +-#include "execute_cmd.h"
- +-#include "findcmd.h"
- +-#include "mailcheck.h"
- +-#include "input.h"
- +-#include "hashcmd.h"
- +-#include "pathexp.h"
- +-#include "alias.h"
- +-#include "jobs.h"
- +-
- +-#include "version.h"
- +-
- +-#include "builtins/getopt.h"
- +-#include "builtins/common.h"
- +-#include "builtins/builtext.h"
- +-
- +-#if defined (READLINE)
- +-# include "bashline.h"
- +-# include <readline/readline.h>
- +-#else
- +-# include <tilde/tilde.h>
- +-#endif
- +-
- +-#if defined (HISTORY)
- +-# include "bashhist.h"
- +-# include <readline/history.h>
- +-#endif /* HISTORY */
- +-
- +-#if defined (PROGRAMMABLE_COMPLETION)
- +-# include "pcomplete.h"
- +-#endif
- +-
- +-#define TEMPENV_HASH_BUCKETS 4 /* must be power of two */
- +-
- +-#define ifsname(s) ((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0')
- +-
- +-#define BASHFUNC_PREFIX "BASH_FUNC_"
- +-#define BASHFUNC_PREFLEN 10 /* == strlen(BASHFUNC_PREFIX */
- +-#define BASHFUNC_SUFFIX "%%"
- +-#define BASHFUNC_SUFFLEN 2 /* == strlen(BASHFUNC_SUFFIX) */
- +-
- +-extern char **environ;
- +-
- +-/* Variables used here and defined in other files. */
- +-extern int posixly_correct;
- +-extern int line_number, line_number_base;
- +-extern int subshell_environment, indirection_level, subshell_level;
- +-extern int build_version, patch_level;
- +-extern int expanding_redir;
- +-extern int last_command_exit_value;
- +-extern char *dist_version, *release_status;
- +-extern char *shell_name;
- +-extern char *primary_prompt, *secondary_prompt;
- +-extern char *current_host_name;
- +-extern sh_builtin_func_t *this_shell_builtin;
- +-extern SHELL_VAR *this_shell_function;
- +-extern char *the_printed_command_except_trap;
- +-extern char *this_command_name;
- +-extern char *command_execution_string;
- +-extern time_t shell_start_time;
- +-extern int assigning_in_environment;
- +-extern int executing_builtin;
- +-extern int funcnest_max;
- +-
- +-#if defined (READLINE)
- +-extern int no_line_editing;
- +-extern int perform_hostname_completion;
- +-#endif
- +-
- +-/* The list of shell variables that the user has created at the global
- +- scope, or that came from the environment. */
- +-VAR_CONTEXT *global_variables = (VAR_CONTEXT *)NULL;
- +-
- +-/* The current list of shell variables, including function scopes */
- +-VAR_CONTEXT *shell_variables = (VAR_CONTEXT *)NULL;
- +-
- +-/* The list of shell functions that the user has created, or that came from
- +- the environment. */
- +-HASH_TABLE *shell_functions = (HASH_TABLE *)NULL;
- +-
- +-#if defined (DEBUGGER)
- +-/* The table of shell function definitions that the user defined or that
- +- came from the environment. */
- +-HASH_TABLE *shell_function_defs = (HASH_TABLE *)NULL;
- +-#endif
- +-
- +-/* The current variable context. This is really a count of how deep into
- +- executing functions we are. */
- +-int variable_context = 0;
- +-
- +-/* The set of shell assignments which are made only in the environment
- +- for a single command. */
- +-HASH_TABLE *temporary_env = (HASH_TABLE *)NULL;
- +-
- +-/* Set to non-zero if an assignment error occurs while putting variables
- +- into the temporary environment. */
- +-int tempenv_assign_error;
- +-
- +-/* Some funky variables which are known about specially. Here is where
- +- "$*", "$1", and all the cruft is kept. */
- +-char *dollar_vars[10];
- +-WORD_LIST *rest_of_args = (WORD_LIST *)NULL;
- +-
- +-/* The value of $$. */
- +-pid_t dollar_dollar_pid;
- +-
- +-/* Non-zero means that we have to remake EXPORT_ENV. */
- +-int array_needs_making = 1;
- +-
- +-/* The number of times BASH has been executed. This is set
- +- by initialize_variables (). */
- +-int shell_level = 0;
- +-
- +-/* An array which is passed to commands as their environment. It is
- +- manufactured from the union of the initial environment and the
- +- shell variables that are marked for export. */
- +-char **export_env = (char **)NULL;
- +-static int export_env_index;
- +-static int export_env_size;
- +-
- +-#if defined (READLINE)
- +-static int winsize_assignment; /* currently assigning to LINES or COLUMNS */
- +-#endif
- +-
- +-static HASH_TABLE *last_table_searched; /* hash_lookup sets this */
- +-
- +-/* Some forward declarations. */
- +-static void create_variable_tables __P((void));
- +-
- +-static void set_machine_vars __P((void));
- +-static void set_home_var __P((void));
- +-static void set_shell_var __P((void));
- +-static char *get_bash_name __P((void));
- +-static void initialize_shell_level __P((void));
- +-static void uidset __P((void));
- +-#if defined (ARRAY_VARS)
- +-static void make_vers_array __P((void));
- +-#endif
- +-
- +-static SHELL_VAR *null_assign __P((SHELL_VAR *, char *, arrayind_t, char *));
- +-#if defined (ARRAY_VARS)
- +-static SHELL_VAR *null_array_assign __P((SHELL_VAR *, char *, arrayind_t, char *));
- +-#endif
- +-static SHELL_VAR *get_self __P((SHELL_VAR *));
- +-
- +-#if defined (ARRAY_VARS)
- +-static SHELL_VAR *init_dynamic_array_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int));
- +-static SHELL_VAR *init_dynamic_assoc_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int));
- +-#endif
- +-
- +-static SHELL_VAR *assign_seconds __P((SHELL_VAR *, char *, arrayind_t, char *));
- +-static SHELL_VAR *get_seconds __P((SHELL_VAR *));
- +-static SHELL_VAR *init_seconds_var __P((void));
- +-
- +-static int brand __P((void));
- +-static void sbrand __P((unsigned long)); /* set bash random number generator. */
- +-static void seedrand __P((void)); /* seed generator randomly */
- +-static SHELL_VAR *assign_random __P((SHELL_VAR *, char *, arrayind_t, char *));
- +-static SHELL_VAR *get_random __P((SHELL_VAR *));
- +-
- +-static SHELL_VAR *assign_lineno __P((SHELL_VAR *, char *, arrayind_t, char *));
- +-static SHELL_VAR *get_lineno __P((SHELL_VAR *));
- +-
- +-static SHELL_VAR *assign_subshell __P((SHELL_VAR *, char *, arrayind_t, char *));
- +-static SHELL_VAR *get_subshell __P((SHELL_VAR *));
- +-
- +-static SHELL_VAR *get_bashpid __P((SHELL_VAR *));
- +-
- +-#if defined (HISTORY)
- +-static SHELL_VAR *get_histcmd __P((SHELL_VAR *));
- +-#endif
- +-
- +-#if defined (READLINE)
- +-static SHELL_VAR *get_comp_wordbreaks __P((SHELL_VAR *));
- +-static SHELL_VAR *assign_comp_wordbreaks __P((SHELL_VAR *, char *, arrayind_t, char *));
- +-#endif
- +-
- +-#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
- +-static SHELL_VAR *assign_dirstack __P((SHELL_VAR *, char *, arrayind_t, char *));
- +-static SHELL_VAR *get_dirstack __P((SHELL_VAR *));
- +-#endif
- +-
- +-#if defined (ARRAY_VARS)
- +-static SHELL_VAR *get_groupset __P((SHELL_VAR *));
- +-
- +-static SHELL_VAR *build_hashcmd __P((SHELL_VAR *));
- +-static SHELL_VAR *get_hashcmd __P((SHELL_VAR *));
- +-static SHELL_VAR *assign_hashcmd __P((SHELL_VAR *, char *, arrayind_t, char *));
- +-# if defined (ALIAS)
- +-static SHELL_VAR *build_aliasvar __P((SHELL_VAR *));
- +-static SHELL_VAR *get_aliasvar __P((SHELL_VAR *));
- +-static SHELL_VAR *assign_aliasvar __P((SHELL_VAR *, char *, arrayind_t, char *));
- +-# endif
- +-#endif
- +-
- +-static SHELL_VAR *get_funcname __P((SHELL_VAR *));
- +-static SHELL_VAR *init_funcname_var __P((void));
- +-
- +-static void initialize_dynamic_variables __P((void));
- +-
- +-static SHELL_VAR *hash_lookup __P((const char *, HASH_TABLE *));
- +-static SHELL_VAR *new_shell_variable __P((const char *));
- +-static SHELL_VAR *make_new_variable __P((const char *, HASH_TABLE *));
- +-static SHELL_VAR *bind_variable_internal __P((const char *, char *, HASH_TABLE *, int, int));
- +-
- +-static void dispose_variable_value __P((SHELL_VAR *));
- +-static void free_variable_hash_data __P((PTR_T));
- +-
- +-static VARLIST *vlist_alloc __P((int));
- +-static VARLIST *vlist_realloc __P((VARLIST *, int));
- +-static void vlist_add __P((VARLIST *, SHELL_VAR *, int));
- +-
- +-static void flatten __P((HASH_TABLE *, sh_var_map_func_t *, VARLIST *, int));
- +-
- +-static int qsort_var_comp __P((SHELL_VAR **, SHELL_VAR **));
- +-
- +-static SHELL_VAR **vapply __P((sh_var_map_func_t *));
- +-static SHELL_VAR **fapply __P((sh_var_map_func_t *));
- +-
- +-static int visible_var __P((SHELL_VAR *));
- +-static int visible_and_exported __P((SHELL_VAR *));
- +-static int export_environment_candidate __P((SHELL_VAR *));
- +-static int local_and_exported __P((SHELL_VAR *));
- +-static int variable_in_context __P((SHELL_VAR *));
- +-#if defined (ARRAY_VARS)
- +-static int visible_array_vars __P((SHELL_VAR *));
- +-#endif
- +-
- +-static SHELL_VAR *find_nameref_at_context __P((SHELL_VAR *, VAR_CONTEXT *));
- +-static SHELL_VAR *find_variable_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **));
- +-static SHELL_VAR *find_variable_last_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **));
- +-
- +-static SHELL_VAR *bind_tempenv_variable __P((const char *, char *));
- +-static void push_temp_var __P((PTR_T));
- +-static void propagate_temp_var __P((PTR_T));
- +-static void dispose_temporary_env __P((sh_free_func_t *));
- +-
- +-static inline char *mk_env_string __P((const char *, const char *, int));
- +-static char **make_env_array_from_var_list __P((SHELL_VAR **));
- +-static char **make_var_export_array __P((VAR_CONTEXT *));
- +-static char **make_func_export_array __P((void));
- +-static void add_temp_array_to_env __P((char **, int, int));
- +-
- +-static int n_shell_variables __P((void));
- +-static int set_context __P((SHELL_VAR *));
- +-
- +-static void push_func_var __P((PTR_T));
- +-static void push_exported_var __P((PTR_T));
- +-
- +-static inline int find_special_var __P((const char *));
- +-
- +-static void
- +-create_variable_tables ()
- +-{
- +- if (shell_variables == 0)
- +- {
- +- shell_variables = global_variables = new_var_context ((char *)NULL, 0);
- +- shell_variables->scope = 0;
- +- shell_variables->table = hash_create (0);
- +- }
- +-
- +- if (shell_functions == 0)
- +- shell_functions = hash_create (0);
- +-
- +-#if defined (DEBUGGER)
- +- if (shell_function_defs == 0)
- +- shell_function_defs = hash_create (0);
- +-#endif
- +-}
- +-
- +-/* Initialize the shell variables from the current environment.
- +- If PRIVMODE is nonzero, don't import functions from ENV or
- +- parse $SHELLOPTS. */
- +-void
- +-initialize_shell_variables (env, privmode)
- +- char **env;
- +- int privmode;
- +-{
- +- char *name, *string, *temp_string;
- +- int c, char_index, string_index, string_length, ro;
- +- SHELL_VAR *temp_var;
- +-
- +- create_variable_tables ();
- +-
- +- for (string_index = 0; string = env[string_index++]; )
- +- {
- +- char_index = 0;
- +- name = string;
- +- while ((c = *string++) && c != '=')
- +- ;
- +- if (string[-1] == '=')
- +- char_index = string - name - 1;
- +-
- +- /* If there are weird things in the environment, like `=xxx' or a
- +- string without an `=', just skip them. */
- +- if (char_index == 0)
- +- continue;
- +-
- +- /* ASSERT(name[char_index] == '=') */
- +- name[char_index] = '\0';
- +- /* Now, name = env variable name, string = env variable value, and
- +- char_index == strlen (name) */
- +-
- +- temp_var = (SHELL_VAR *)NULL;
- +-
- +- /* If exported function, define it now. Don't import functions from
- +- the environment in privileged mode. */
- +- if (privmode == 0 && read_but_dont_execute == 0 &&
- +- STREQN (BASHFUNC_PREFIX, name, BASHFUNC_PREFLEN) &&
- +- STREQ (BASHFUNC_SUFFIX, name + char_index - BASHFUNC_SUFFLEN) &&
- +- STREQN ("() {", string, 4))
- +- {
- +- size_t namelen;
- +- char *tname; /* desired imported function name */
- +-
- +- namelen = char_index - BASHFUNC_PREFLEN - BASHFUNC_SUFFLEN;
- +-
- +- tname = name + BASHFUNC_PREFLEN; /* start of func name */
- +- tname[namelen] = '\0'; /* now tname == func name */
- +-
- +- string_length = strlen (string);
- +- temp_string = (char *)xmalloc (namelen + string_length + 2);
- +-
- +- memcpy (temp_string, tname, namelen);
- +- temp_string[namelen] = ' ';
- +- memcpy (temp_string + namelen + 1, string, string_length + 1);
- +-
- +- /* Don't import function names that are invalid identifiers from the
- +- environment, though we still allow them to be defined as shell
- +- variables. */
- +- if (absolute_program (tname) == 0 && (posixly_correct == 0 || legal_identifier (tname)))
- +- parse_and_execute (temp_string, tname, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
- +-
- +- if (temp_var = find_function (tname))
- +- {
- +- VSETATTR (temp_var, (att_exported|att_imported));
- +- array_needs_making = 1;
- +- }
- +- else
- +- {
- +- if (temp_var = bind_variable (name, string, 0))
- +- {
- +- VSETATTR (temp_var, (att_exported | att_imported | att_invisible));
- +- array_needs_making = 1;
- +- }
- +- last_command_exit_value = 1;
- +- report_error (_("error importing function definition for `%s'"), tname);
- +- }
- +-
- +- /* Restore original suffix */
- +- tname[namelen] = BASHFUNC_SUFFIX[0];
- +- }
- +-#if defined (ARRAY_VARS)
- +-# if ARRAY_EXPORT
- +- /* Array variables may not yet be exported. */
- +- else if (*string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')')
- +- {
- +- string_length = 1;
- +- temp_string = extract_array_assignment_list (string, &string_length);
- +- temp_var = assign_array_from_string (name, temp_string);
- +- FREE (temp_string);
- +- VSETATTR (temp_var, (att_exported | att_imported));
- +- array_needs_making = 1;
- +- }
- +-# endif /* ARRAY_EXPORT */
- +-#endif
- +-#if 0
- +- else if (legal_identifier (name))
- +-#else
- +- else
- +-#endif
- +- {
- +- ro = 0;
- +- if (posixly_correct && STREQ (name, "SHELLOPTS"))
- +- {
- +- temp_var = find_variable ("SHELLOPTS");
- +- ro = temp_var && readonly_p (temp_var);
- +- if (temp_var)
- +- VUNSETATTR (temp_var, att_readonly);
- +- }
- +- temp_var = bind_variable (name, string, 0);
- +- if (temp_var)
- +- {
- +- if (legal_identifier (name))
- +- VSETATTR (temp_var, (att_exported | att_imported));
- +- else
- +- VSETATTR (temp_var, (att_exported | att_imported | att_invisible));
- +- if (ro)
- +- VSETATTR (temp_var, att_readonly);
- +- array_needs_making = 1;
- +- }
- +- }
- +-
- +- name[char_index] = '=';
- +- /* temp_var can be NULL if it was an exported function with a syntax
- +- error (a different bug, but it still shouldn't dump core). */
- +- if (temp_var && function_p (temp_var) == 0) /* XXX not yet */
- +- {
- +- CACHE_IMPORTSTR (temp_var, name);
- +- }
- +- }
- +-
- +- set_pwd ();
- +-
- +- /* Set up initial value of $_ */
- +- temp_var = set_if_not ("_", dollar_vars[0]);
- +-
- +- /* Remember this pid. */
- +- dollar_dollar_pid = getpid ();
- +-
- +- /* Now make our own defaults in case the vars that we think are
- +- important are missing. */
- +- temp_var = set_if_not ("PATH", DEFAULT_PATH_VALUE);
- +-#if 0
- +- set_auto_export (temp_var); /* XXX */
- +-#endif
- +-
- +- temp_var = set_if_not ("TERM", "dumb");
- +-#if 0
- +- set_auto_export (temp_var); /* XXX */
- +-#endif
- +-
- +-#if defined (__QNX__)
- +- /* set node id -- don't import it from the environment */
- +- {
- +- char node_name[22];
- +-# if defined (__QNXNTO__)
- +- netmgr_ndtostr(ND2S_LOCAL_STR, ND_LOCAL_NODE, node_name, sizeof(node_name));
- +-# else
- +- qnx_nidtostr (getnid (), node_name, sizeof (node_name));
- +-# endif
- +- temp_var = bind_variable ("NODE", node_name, 0);
- +- set_auto_export (temp_var);
- +- }
- +-#endif
- +-
- +- /* set up the prompts. */
- +- if (interactive_shell)
- +- {
- +-#if defined (PROMPT_STRING_DECODE)
- +- set_if_not ("PS1", primary_prompt);
- +-#else
- +- if (current_user.uid == -1)
- +- get_current_user_info ();
- +- set_if_not ("PS1", current_user.euid == 0 ? "# " : primary_prompt);
- +-#endif
- +- set_if_not ("PS2", secondary_prompt);
- +- }
- +- set_if_not ("PS4", "+ ");
- +-
- +- /* Don't allow IFS to be imported from the environment. */
- +- temp_var = bind_variable ("IFS", " \t\n", 0);
- +- setifs (temp_var);
- +-
- +- /* Magic machine types. Pretty convenient. */
- +- set_machine_vars ();
- +-
- +- /* Default MAILCHECK for interactive shells. Defer the creation of a
- +- default MAILPATH until the startup files are read, because MAIL
- +- names a mail file if MAILPATH is not set, and we should provide a
- +- default only if neither is set. */
- +- if (interactive_shell)
- +- {
- +- temp_var = set_if_not ("MAILCHECK", posixly_correct ? "600" : "60");
- +- VSETATTR (temp_var, att_integer);
- +- }
- +-
- +- /* Do some things with shell level. */
- +- initialize_shell_level ();
- +-
- +- set_ppid ();
- +-
- +- /* Initialize the `getopts' stuff. */
- +- temp_var = bind_variable ("OPTIND", "1", 0);
- +- VSETATTR (temp_var, att_integer);
- +- getopts_reset (0);
- +- bind_variable ("OPTERR", "1", 0);
- +- sh_opterr = 1;
- +-
- +- if (login_shell == 1 && posixly_correct == 0)
- +- set_home_var ();
- +-
- +- /* Get the full pathname to THIS shell, and set the BASH variable
- +- to it. */
- +- name = get_bash_name ();
- +- temp_var = bind_variable ("BASH", name, 0);
- +- free (name);
- +-
- +- /* Make the exported environment variable SHELL be the user's login
- +- shell. Note that the `tset' command looks at this variable
- +- to determine what style of commands to output; if it ends in "csh",
- +- then C-shell commands are output, else Bourne shell commands. */
- +- set_shell_var ();
- +-
- +- /* Make a variable called BASH_VERSION which contains the version info. */
- +- bind_variable ("BASH_VERSION", shell_version_string (), 0);
- +-#if defined (ARRAY_VARS)
- +- make_vers_array ();
- +-#endif
- +-
- +- if (command_execution_string)
- +- bind_variable ("BASH_EXECUTION_STRING", command_execution_string, 0);
- +-
- +- /* Find out if we're supposed to be in Posix.2 mode via an
- +- environment variable. */
- +- temp_var = find_variable ("POSIXLY_CORRECT");
- +- if (!temp_var)
- +- temp_var = find_variable ("POSIX_PEDANTIC");
- +- if (temp_var && imported_p (temp_var))
- +- sv_strict_posix (temp_var->name);
- +-
- +-#if defined (HISTORY)
- +- /* Set history variables to defaults, and then do whatever we would
- +- do if the variable had just been set. Do this only in the case
- +- that we are remembering commands on the history list. */
- +- if (remember_on_history)
- +- {
- +- name = bash_tilde_expand (posixly_correct ? "~/.sh_history" : "~/.bash_history", 0);
- +-
- +- set_if_not ("HISTFILE", name);
- +- free (name);
- +- }
- +-#endif /* HISTORY */
- +-
- +- /* Seed the random number generator. */
- +- seedrand ();
- +-
- +- /* Handle some "special" variables that we may have inherited from a
- +- parent shell. */
- +- if (interactive_shell)
- +- {
- +- temp_var = find_variable ("IGNOREEOF");
- +- if (!temp_var)
- +- temp_var = find_variable ("ignoreeof");
- +- if (temp_var && imported_p (temp_var))
- +- sv_ignoreeof (temp_var->name);
- +- }
- +-
- +-#if defined (HISTORY)
- +- if (interactive_shell && remember_on_history)
- +- {
- +- sv_history_control ("HISTCONTROL");
- +- sv_histignore ("HISTIGNORE");
- +- sv_histtimefmt ("HISTTIMEFORMAT");
- +- }
- +-#endif /* HISTORY */
- +-
- +-#if defined (READLINE) && defined (STRICT_POSIX)
- +- /* POSIXLY_CORRECT will only be 1 here if the shell was compiled
- +- -DSTRICT_POSIX */
- +- if (interactive_shell && posixly_correct && no_line_editing == 0)
- +- rl_prefer_env_winsize = 1;
- +-#endif /* READLINE && STRICT_POSIX */
- +-
- +- /*
- +- * 24 October 2001
- +- *
- +- * I'm tired of the arguing and bug reports. Bash now leaves SSH_CLIENT
- +- * and SSH2_CLIENT alone. I'm going to rely on the shell_level check in
- +- * isnetconn() to avoid running the startup files more often than wanted.
- +- * That will, of course, only work if the user's login shell is bash, so
- +- * I've made that behavior conditional on SSH_SOURCE_BASHRC being defined
- +- * in config-top.h.
- +- */
- +-#if 0
- +- temp_var = find_variable ("SSH_CLIENT");
- +- if (temp_var && imported_p (temp_var))
- +- {
- +- VUNSETATTR (temp_var, att_exported);
- +- array_needs_making = 1;
- +- }
- +- temp_var = find_variable ("SSH2_CLIENT");
- +- if (temp_var && imported_p (temp_var))
- +- {
- +- VUNSETATTR (temp_var, att_exported);
- +- array_needs_making = 1;
- +- }
- +-#endif
- +-
- +- /* Get the user's real and effective user ids. */
- +- uidset ();
- +-
- +- temp_var = find_variable ("BASH_XTRACEFD");
- +- if (temp_var && imported_p (temp_var))
- +- sv_xtracefd (temp_var->name);
- +-
- +- /* Initialize the dynamic variables, and seed their values. */
- +- initialize_dynamic_variables ();
- +-}
- +-
- +-/* **************************************************************** */
- +-/* */
- +-/* Setting values for special shell variables */
- +-/* */
- +-/* **************************************************************** */
- +-
- +-static void
- +-set_machine_vars ()
- +-{
- +- SHELL_VAR *temp_var;
- +-
- +- temp_var = set_if_not ("HOSTTYPE", HOSTTYPE);
- +- temp_var = set_if_not ("OSTYPE", OSTYPE);
- +- temp_var = set_if_not ("MACHTYPE", MACHTYPE);
- +-
- +- temp_var = set_if_not ("HOSTNAME", current_host_name);
- +-}
- +-
- +-/* Set $HOME to the information in the password file if we didn't get
- +- it from the environment. */
- +-
- +-/* This function is not static so the tilde and readline libraries can
- +- use it. */
- +-char *
- +-sh_get_home_dir ()
- +-{
- +- if (current_user.home_dir == 0)
- +- get_current_user_info ();
- +- return current_user.home_dir;
- +-}
- +-
- +-static void
- +-set_home_var ()
- +-{
- +- SHELL_VAR *temp_var;
- +-
- +- temp_var = find_variable ("HOME");
- +- if (temp_var == 0)
- +- temp_var = bind_variable ("HOME", sh_get_home_dir (), 0);
- +-#if 0
- +- VSETATTR (temp_var, att_exported);
- +-#endif
- +-}
- +-
- +-/* Set $SHELL to the user's login shell if it is not already set. Call
- +- get_current_user_info if we haven't already fetched the shell. */
- +-static void
- +-set_shell_var ()
- +-{
- +- SHELL_VAR *temp_var;
- +-
- +- temp_var = find_variable ("SHELL");
- +- if (temp_var == 0)
- +- {
- +- if (current_user.shell == 0)
- +- get_current_user_info ();
- +- temp_var = bind_variable ("SHELL", current_user.shell, 0);
- +- }
- +-#if 0
- +- VSETATTR (temp_var, att_exported);
- +-#endif
- +-}
- +-
- +-static char *
- +-get_bash_name ()
- +-{
- +- char *name;
- +-
- +- if ((login_shell == 1) && RELPATH(shell_name))
- +- {
- +- if (current_user.shell == 0)
- +- get_current_user_info ();
- +- name = savestring (current_user.shell);
- +- }
- +- else if (ABSPATH(shell_name))
- +- name = savestring (shell_name);
- +- else if (shell_name[0] == '.' && shell_name[1] == '/')
- +- {
- +- /* Fast path for common case. */
- +- char *cdir;
- +- int len;
- +-
- +- cdir = get_string_value ("PWD");
- +- if (cdir)
- +- {
- +- len = strlen (cdir);
- +- name = (char *)xmalloc (len + strlen (shell_name) + 1);
- +- strcpy (name, cdir);
- +- strcpy (name + len, shell_name + 1);
- +- }
- +- else
- +- name = savestring (shell_name);
- +- }
- +- else
- +- {
- +- char *tname;
- +- int s;
- +-
- +- tname = find_user_command (shell_name);
- +-
- +- if (tname == 0)
- +- {
- +- /* Try the current directory. If there is not an executable
- +- there, just punt and use the login shell. */
- +- s = file_status (shell_name);
- +- if (s & FS_EXECABLE)
- +- {
- +- tname = make_absolute (shell_name, get_string_value ("PWD"));
- +- if (*shell_name == '.')
- +- {
- +- name = sh_canonpath (tname, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
- +- if (name == 0)
- +- name = tname;
- +- else
- +- free (tname);
- +- }
- +- else
- +- name = tname;
- +- }
- +- else
- +- {
- +- if (current_user.shell == 0)
- +- get_current_user_info ();
- +- name = savestring (current_user.shell);
- +- }
- +- }
- +- else
- +- {
- +- name = full_pathname (tname);
- +- free (tname);
- +- }
- +- }
- +-
- +- return (name);
- +-}
- +-
- +-void
- +-adjust_shell_level (change)
- +- int change;
- +-{
- +- char new_level[5], *old_SHLVL;
- +- intmax_t old_level;
- +- SHELL_VAR *temp_var;
- +-
- +- old_SHLVL = get_string_value ("SHLVL");
- +- if (old_SHLVL == 0 || *old_SHLVL == '\0' || legal_number (old_SHLVL, &old_level) == 0)
- +- old_level = 0;
- +-
- +- shell_level = old_level + change;
- +- if (shell_level < 0)
- +- shell_level = 0;
- +- else if (shell_level > 1000)
- +- {
- +- internal_warning (_("shell level (%d) too high, resetting to 1"), shell_level);
- +- shell_level = 1;
- +- }
- +-
- +- /* We don't need the full generality of itos here. */
- +- if (shell_level < 10)
- +- {
- +- new_level[0] = shell_level + '0';
- +- new_level[1] = '\0';
- +- }
- +- else if (shell_level < 100)
- +- {
- +- new_level[0] = (shell_level / 10) + '0';
- +- new_level[1] = (shell_level % 10) + '0';
- +- new_level[2] = '\0';
- +- }
- +- else if (shell_level < 1000)
- +- {
- +- new_level[0] = (shell_level / 100) + '0';
- +- old_level = shell_level % 100;
- +- new_level[1] = (old_level / 10) + '0';
- +- new_level[2] = (old_level % 10) + '0';
- +- new_level[3] = '\0';
- +- }
- +-
- +- temp_var = bind_variable ("SHLVL", new_level, 0);
- +- set_auto_export (temp_var);
- +-}
- +-
- +-static void
- +-initialize_shell_level ()
- +-{
- +- adjust_shell_level (1);
- +-}
- +-
- +-/* If we got PWD from the environment, update our idea of the current
- +- working directory. In any case, make sure that PWD exists before
- +- checking it. It is possible for getcwd () to fail on shell startup,
- +- and in that case, PWD would be undefined. If this is an interactive
- +- login shell, see if $HOME is the current working directory, and if
- +- that's not the same string as $PWD, set PWD=$HOME. */
- +-
- +-void
- +-set_pwd ()
- +-{
- +- SHELL_VAR *temp_var, *home_var;
- +- char *temp_string, *home_string;
- +-
- +- home_var = find_variable ("HOME");
- +- home_string = home_var ? value_cell (home_var) : (char *)NULL;
- +-
- +- temp_var = find_variable ("PWD");
- +- if (temp_var && imported_p (temp_var) &&
- +- (temp_string = value_cell (temp_var)) &&
- +- same_file (temp_string, ".", (struct stat *)NULL, (struct stat *)NULL))
- +- set_working_directory (temp_string);
- +- else if (home_string && interactive_shell && login_shell &&
- +- same_file (home_string, ".", (struct stat *)NULL, (struct stat *)NULL))
- +- {
- +- set_working_directory (home_string);
- +- temp_var = bind_variable ("PWD", home_string, 0);
- +- set_auto_export (temp_var);
- +- }
- +- else
- +- {
- +- temp_string = get_working_directory ("shell-init");
- +- if (temp_string)
- +- {
- +- temp_var = bind_variable ("PWD", temp_string, 0);
- +- set_auto_export (temp_var);
- +- free (temp_string);
- +- }
- +- }
- +-
- +- /* According to the Single Unix Specification, v2, $OLDPWD is an
- +- `environment variable' and therefore should be auto-exported.
- +- Make a dummy invisible variable for OLDPWD, and mark it as exported. */
- +- temp_var = bind_variable ("OLDPWD", (char *)NULL, 0);
- +- VSETATTR (temp_var, (att_exported | att_invisible));
- +-}
- +-
- +-/* Make a variable $PPID, which holds the pid of the shell's parent. */
- +-void
- +-set_ppid ()
- +-{
- +- char namebuf[INT_STRLEN_BOUND(pid_t) + 1], *name;
- +- SHELL_VAR *temp_var;
- +-
- +- name = inttostr (getppid (), namebuf, sizeof(namebuf));
- +- temp_var = find_variable ("PPID");
- +- if (temp_var)
- +- VUNSETATTR (temp_var, (att_readonly | att_exported));
- +- temp_var = bind_variable ("PPID", name, 0);
- +- VSETATTR (temp_var, (att_readonly | att_integer));
- +-}
- +-
- +-static void
- +-uidset ()
- +-{
- +- char buff[INT_STRLEN_BOUND(uid_t) + 1], *b;
- +- register SHELL_VAR *v;
- +-
- +- b = inttostr (current_user.uid, buff, sizeof (buff));
- +- v = find_variable ("UID");
- +- if (v == 0)
- +- {
- +- v = bind_variable ("UID", b, 0);
- +- VSETATTR (v, (att_readonly | att_integer));
- +- }
- +-
- +- if (current_user.euid != current_user.uid)
- +- b = inttostr (current_user.euid, buff, sizeof (buff));
- +-
- +- v = find_variable ("EUID");
- +- if (v == 0)
- +- {
- +- v = bind_variable ("EUID", b, 0);
- +- VSETATTR (v, (att_readonly | att_integer));
- +- }
- +-}
- +-
- +-#if defined (ARRAY_VARS)
- +-static void
- +-make_vers_array ()
- +-{
- +- SHELL_VAR *vv;
- +- ARRAY *av;
- +- char *s, d[32], b[INT_STRLEN_BOUND(int) + 1];
- +-
- +- unbind_variable ("BASH_VERSINFO");
- +-
- +- vv = make_new_array_variable ("BASH_VERSINFO");
- +- av = array_cell (vv);
- +- strcpy (d, dist_version);
- +- s = strchr (d, '.');
- +- if (s)
- +- *s++ = '\0';
- +- array_insert (av, 0, d);
- +- array_insert (av, 1, s);
- +- s = inttostr (patch_level, b, sizeof (b));
- +- array_insert (av, 2, s);
- +- s = inttostr (build_version, b, sizeof (b));
- +- array_insert (av, 3, s);
- +- array_insert (av, 4, release_status);
- +- array_insert (av, 5, MACHTYPE);
- +-
- +- VSETATTR (vv, att_readonly);
- +-}
- +-#endif /* ARRAY_VARS */
- +-
- +-/* Set the environment variables $LINES and $COLUMNS in response to
- +- a window size change. */
- +-void
- +-sh_set_lines_and_columns (lines, cols)
- +- int lines, cols;
- +-{
- +- char val[INT_STRLEN_BOUND(int) + 1], *v;
- +-
- +-#if defined (READLINE)
- +- /* If we are currently assigning to LINES or COLUMNS, don't do anything. */
- +- if (winsize_assignment)
- +- return;
- +-#endif
- +-
- +- v = inttostr (lines, val, sizeof (val));
- +- bind_variable ("LINES", v, 0);
- +-
- +- v = inttostr (cols, val, sizeof (val));
- +- bind_variable ("COLUMNS", v, 0);
- +-}
- +-
- +-/* **************************************************************** */
- +-/* */
- +-/* Printing variables and values */
- +-/* */
- +-/* **************************************************************** */
- +-
- +-/* Print LIST (a list of shell variables) to stdout in such a way that
- +- they can be read back in. */
- +-void
- +-print_var_list (list)
- +- register SHELL_VAR **list;
- +-{
- +- register int i;
- +- register SHELL_VAR *var;
- +-
- +- for (i = 0; list && (var = list[i]); i++)
- +- if (invisible_p (var) == 0)
- +- print_assignment (var);
- +-}
- +-
- +-/* Print LIST (a list of shell functions) to stdout in such a way that
- +- they can be read back in. */
- +-void
- +-print_func_list (list)
- +- register SHELL_VAR **list;
- +-{
- +- register int i;
- +- register SHELL_VAR *var;
- +-
- +- for (i = 0; list && (var = list[i]); i++)
- +- {
- +- printf ("%s ", var->name);
- +- print_var_function (var);
- +- printf ("\n");
- +- }
- +-}
- +-
- +-/* Print the value of a single SHELL_VAR. No newline is
- +- output, but the variable is printed in such a way that
- +- it can be read back in. */
- +-void
- +-print_assignment (var)
- +- SHELL_VAR *var;
- +-{
- +- if (var_isset (var) == 0)
- +- return;
- +-
- +- if (function_p (var))
- +- {
- +- printf ("%s", var->name);
- +- print_var_function (var);
- +- printf ("\n");
- +- }
- +-#if defined (ARRAY_VARS)
- +- else if (array_p (var))
- +- print_array_assignment (var, 0);
- +- else if (assoc_p (var))
- +- print_assoc_assignment (var, 0);
- +-#endif /* ARRAY_VARS */
- +- else
- +- {
- +- printf ("%s=", var->name);
- +- print_var_value (var, 1);
- +- printf ("\n");
- +- }
- +-}
- +-
- +-/* Print the value cell of VAR, a shell variable. Do not print
- +- the name, nor leading/trailing newline. If QUOTE is non-zero,
- +- and the value contains shell metacharacters, quote the value
- +- in such a way that it can be read back in. */
- +-void
- +-print_var_value (var, quote)
- +- SHELL_VAR *var;
- +- int quote;
- +-{
- +- char *t;
- +-
- +- if (var_isset (var) == 0)
- +- return;
- +-
- +- if (quote && posixly_correct == 0 && ansic_shouldquote (value_cell (var)))
- +- {
- +- t = ansic_quote (value_cell (var), 0, (int *)0);
- +- printf ("%s", t);
- +- free (t);
- +- }
- +- else if (quote && sh_contains_shell_metas (value_cell (var)))
- +- {
- +- t = sh_single_quote (value_cell (var));
- +- printf ("%s", t);
- +- free (t);
- +- }
- +- else
- +- printf ("%s", value_cell (var));
- +-}
- +-
- +-/* Print the function cell of VAR, a shell variable. Do not
- +- print the name, nor leading/trailing newline. */
- +-void
- +-print_var_function (var)
- +- SHELL_VAR *var;
- +-{
- +- char *x;
- +-
- +- if (function_p (var) && var_isset (var))
- +- {
- +- x = named_function_string ((char *)NULL, function_cell(var), FUNC_MULTILINE|FUNC_EXTERNAL);
- +- printf ("%s", x);
- +- }
- +-}
- +-
- +-/* **************************************************************** */
- +-/* */
- +-/* Dynamic Variables */
- +-/* */
- +-/* **************************************************************** */
- +-
- +-/* DYNAMIC VARIABLES
- +-
- +- These are variables whose values are generated anew each time they are
- +- referenced. These are implemented using a pair of function pointers
- +- in the struct variable: assign_func, which is called from bind_variable
- +- and, if arrays are compiled into the shell, some of the functions in
- +- arrayfunc.c, and dynamic_value, which is called from find_variable.
- +-
- +- assign_func is called from bind_variable_internal, if
- +- bind_variable_internal discovers that the variable being assigned to
- +- has such a function. The function is called as
- +- SHELL_VAR *temp = (*(entry->assign_func)) (entry, value, ind)
- +- and the (SHELL_VAR *)temp is returned as the value of bind_variable. It
- +- is usually ENTRY (self). IND is an index for an array variable, and
- +- unused otherwise.
- +-
- +- dynamic_value is called from find_variable_internal to return a `new'
- +- value for the specified dynamic varible. If this function is NULL,
- +- the variable is treated as a `normal' shell variable. If it is not,
- +- however, then this function is called like this:
- +- tempvar = (*(var->dynamic_value)) (var);
- +-
- +- Sometimes `tempvar' will replace the value of `var'. Other times, the
- +- shell will simply use the string value. Pretty object-oriented, huh?
- +-
- +- Be warned, though: if you `unset' a special variable, it loses its
- +- special meaning, even if you subsequently set it.
- +-
- +- The special assignment code would probably have been better put in
- +- subst.c: do_assignment_internal, in the same style as
- +- stupidly_hack_special_variables, but I wanted the changes as
- +- localized as possible. */
- +-
- +-#define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \
- +- do \
- +- { \
- +- v = bind_variable (var, (val), 0); \
- +- v->dynamic_value = gfunc; \
- +- v->assign_func = afunc; \
- +- } \
- +- while (0)
- +-
- +-#define INIT_DYNAMIC_ARRAY_VAR(var, gfunc, afunc) \
- +- do \
- +- { \
- +- v = make_new_array_variable (var); \
- +- v->dynamic_value = gfunc; \
- +- v->assign_func = afunc; \
- +- } \
- +- while (0)
- +-
- +-#define INIT_DYNAMIC_ASSOC_VAR(var, gfunc, afunc) \
- +- do \
- +- { \
- +- v = make_new_assoc_variable (var); \
- +- v->dynamic_value = gfunc; \
- +- v->assign_func = afunc; \
- +- } \
- +- while (0)
- +-
- +-static SHELL_VAR *
- +-null_assign (self, value, unused, key)
- +- SHELL_VAR *self;
- +- char *value;
- +- arrayind_t unused;
- +- char *key;
- +-{
- +- return (self);
- +-}
- +-
- +-#if defined (ARRAY_VARS)
- +-static SHELL_VAR *
- +-null_array_assign (self, value, ind, key)
- +- SHELL_VAR *self;
- +- char *value;
- +- arrayind_t ind;
- +- char *key;
- +-{
- +- return (self);
- +-}
- +-#endif
- +-
- +-/* Degenerate `dynamic_value' function; just returns what's passed without
- +- manipulation. */
- +-static SHELL_VAR *
- +-get_self (self)
- +- SHELL_VAR *self;
- +-{
- +- return (self);
- +-}
- +-
- +-#if defined (ARRAY_VARS)
- +-/* A generic dynamic array variable initializer. Initialize array variable
- +- NAME with dynamic value function GETFUNC and assignment function SETFUNC. */
- +-static SHELL_VAR *
- +-init_dynamic_array_var (name, getfunc, setfunc, attrs)
- +- char *name;
- +- sh_var_value_func_t *getfunc;
- +- sh_var_assign_func_t *setfunc;
- +- int attrs;
- +-{
- +- SHELL_VAR *v;
- +-
- +- v = find_variable (name);
- +- if (v)
- +- return (v);
- +- INIT_DYNAMIC_ARRAY_VAR (name, getfunc, setfunc);
- +- if (attrs)
- +- VSETATTR (v, attrs);
- +- return v;
- +-}
- +-
- +-static SHELL_VAR *
- +-init_dynamic_assoc_var (name, getfunc, setfunc, attrs)
- +- char *name;
- +- sh_var_value_func_t *getfunc;
- +- sh_var_assign_func_t *setfunc;
- +- int attrs;
- +-{
- +- SHELL_VAR *v;
- +-
- +- v = find_variable (name);
- +- if (v)
- +- return (v);
- +- INIT_DYNAMIC_ASSOC_VAR (name, getfunc, setfunc);
- +- if (attrs)
- +- VSETATTR (v, attrs);
- +- return v;
- +-}
- +-#endif
- +-
- +-/* The value of $SECONDS. This is the number of seconds since shell
- +- invocation, or, the number of seconds since the last assignment + the
- +- value of the last assignment. */
- +-static intmax_t seconds_value_assigned;
- +-
- +-static SHELL_VAR *
- +-assign_seconds (self, value, unused, key)
- +- SHELL_VAR *self;
- +- char *value;
- +- arrayind_t unused;
- +- char *key;
- +-{
- +- if (legal_number (value, &seconds_value_assigned) == 0)
- +- seconds_value_assigned = 0;
- +- shell_start_time = NOW;
- +- return (self);
- +-}
- +-
- +-static SHELL_VAR *
- +-get_seconds (var)
- +- SHELL_VAR *var;
- +-{
- +- time_t time_since_start;
- +- char *p;
- +-
- +- time_since_start = NOW - shell_start_time;
- +- p = itos(seconds_value_assigned + time_since_start);
- +-
- +- FREE (value_cell (var));
- +-
- +- VSETATTR (var, att_integer);
- +- var_setvalue (var, p);
- +- return (var);
- +-}
- +-
- +-static SHELL_VAR *
- +-init_seconds_var ()
- +-{
- +- SHELL_VAR *v;
- +-
- +- v = find_variable ("SECONDS");
- +- if (v)
- +- {
- +- if (legal_number (value_cell(v), &seconds_value_assigned) == 0)
- +- seconds_value_assigned = 0;
- +- }
- +- INIT_DYNAMIC_VAR ("SECONDS", (v ? value_cell (v) : (char *)NULL), get_seconds, assign_seconds);
- +- return v;
- +-}
- +-
- +-/* The random number seed. You can change this by setting RANDOM. */
- +-static unsigned long rseed = 1;
- +-static int last_random_value;
- +-static int seeded_subshell = 0;
- +-
- +-/* A linear congruential random number generator based on the example
- +- one in the ANSI C standard. This one isn't very good, but a more
- +- complicated one is overkill. */
- +-
- +-/* Returns a pseudo-random number between 0 and 32767. */
- +-static int
- +-brand ()
- +-{
- +- /* From "Random number generators: good ones are hard to find",
- +- Park and Miller, Communications of the ACM, vol. 31, no. 10,
- +- October 1988, p. 1195. filtered through FreeBSD */
- +- long h, l;
- +-
- +- /* Can't seed with 0. */
- +- if (rseed == 0)
- +- rseed = 123459876;
- +- h = rseed / 127773;
- +- l = rseed % 127773;
- +- rseed = 16807 * l - 2836 * h;
- +-#if 0
- +- if (rseed < 0)
- +- rseed += 0x7fffffff;
- +-#endif
- +- return ((unsigned int)(rseed & 32767)); /* was % 32768 */
- +-}
- +-
- +-/* Set the random number generator seed to SEED. */
- +-static void
- +-sbrand (seed)
- +- unsigned long seed;
- +-{
- +- rseed = seed;
- +- last_random_value = 0;
- +-}
- +-
- +-static void
- +-seedrand ()
- +-{
- +- struct timeval tv;
- +-
- +- gettimeofday (&tv, NULL);
- +- sbrand (tv.tv_sec ^ tv.tv_usec ^ getpid ());
- +-}
- +-
- +-static SHELL_VAR *
- +-assign_random (self, value, unused, key)
- +- SHELL_VAR *self;
- +- char *value;
- +- arrayind_t unused;
- +- char *key;
- +-{
- +- sbrand (strtoul (value, (char **)NULL, 10));
- +- if (subshell_environment)
- +- seeded_subshell = getpid ();
- +- return (self);
- +-}
- +-
- +-int
- +-get_random_number ()
- +-{
- +- int rv, pid;
- +-
- +- /* Reset for command and process substitution. */
- +- pid = getpid ();
- +- if (subshell_environment && seeded_subshell != pid)
- +- {
- +- seedrand ();
- +- seeded_subshell = pid;
- +- }
- +-
- +- do
- +- rv = brand ();
- +- while (rv == last_random_value);
- +- return rv;
- +-}
- +-
- +-static SHELL_VAR *
- +-get_random (var)
- +- SHELL_VAR *var;
- +-{
- +- int rv;
- +- char *p;
- +-
- +- rv = get_random_number ();
- +- last_random_value = rv;
- +- p = itos (rv);
- +-
- +- FREE (value_cell (var));
- +-
- +- VSETATTR (var, att_integer);
- +- var_setvalue (var, p);
- +- return (var);
- +-}
- +-
- +-static SHELL_VAR *
- +-assign_lineno (var, value, unused, key)
- +- SHELL_VAR *var;
- +- char *value;
- +- arrayind_t unused;
- +- char *key;
- +-{
- +- intmax_t new_value;
- +-
- +- if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0)
- +- new_value = 0;
- +- line_number = line_number_base = new_value;
- +- return var;
- +-}
- +-
- +-/* Function which returns the current line number. */
- +-static SHELL_VAR *
- +-get_lineno (var)
- +- SHELL_VAR *var;
- +-{
- +- char *p;
- +- int ln;
- +-
- +- ln = executing_line_number ();
- +- p = itos (ln);
- +- FREE (value_cell (var));
- +- var_setvalue (var, p);
- +- return (var);
- +-}
- +-
- +-static SHELL_VAR *
- +-assign_subshell (var, value, unused, key)
- +- SHELL_VAR *var;
- +- char *value;
- +- arrayind_t unused;
- +- char *key;
- +-{
- +- intmax_t new_value;
- +-
- +- if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0)
- +- new_value = 0;
- +- subshell_level = new_value;
- +- return var;
- +-}
- +-
- +-static SHELL_VAR *
- +-get_subshell (var)
- +- SHELL_VAR *var;
- +-{
- +- char *p;
- +-
- +- p = itos (subshell_level);
- +- FREE (value_cell (var));
- +- var_setvalue (var, p);
- +- return (var);
- +-}
- +-
- +-static SHELL_VAR *
- +-get_bashpid (var)
- +- SHELL_VAR *var;
- +-{
- +- int pid;
- +- char *p;
- +-
- +- pid = getpid ();
- +- p = itos (pid);
- +-
- +- FREE (value_cell (var));
- +- VSETATTR (var, att_integer|att_readonly);
- +- var_setvalue (var, p);
- +- return (var);
- +-}
- +-
- +-static SHELL_VAR *
- +-get_bash_command (var)
- +- SHELL_VAR *var;
- +-{
- +- char *p;
- +-
- +- if (the_printed_command_except_trap)
- +- p = savestring (the_printed_command_except_trap);
- +- else
- +- {
- +- p = (char *)xmalloc (1);
- +- p[0] = '\0';
- +- }
- +- FREE (value_cell (var));
- +- var_setvalue (var, p);
- +- return (var);
- +-}
- +-
- +-#if defined (HISTORY)
- +-static SHELL_VAR *
- +-get_histcmd (var)
- +- SHELL_VAR *var;
- +-{
- +- char *p;
- +-
- +- p = itos (history_number ());
- +- FREE (value_cell (var));
- +- var_setvalue (var, p);
- +- return (var);
- +-}
- +-#endif
- +-
- +-#if defined (READLINE)
- +-/* When this function returns, VAR->value points to malloced memory. */
- +-static SHELL_VAR *
- +-get_comp_wordbreaks (var)
- +- SHELL_VAR *var;
- +-{
- +- /* If we don't have anything yet, assign a default value. */
- +- if (rl_completer_word_break_characters == 0 && bash_readline_initialized == 0)
- +- enable_hostname_completion (perform_hostname_completion);
- +-
- +- FREE (value_cell (var));
- +- var_setvalue (var, savestring (rl_completer_word_break_characters));
- +-
- +- return (var);
- +-}
- +-
- +-/* When this function returns, rl_completer_word_break_characters points to
- +- malloced memory. */
- +-static SHELL_VAR *
- +-assign_comp_wordbreaks (self, value, unused, key)
- +- SHELL_VAR *self;
- +- char *value;
- +- arrayind_t unused;
- +- char *key;
- +-{
- +- if (rl_completer_word_break_characters &&
- +- rl_completer_word_break_characters != rl_basic_word_break_characters)
- +- free (rl_completer_word_break_characters);
- +-
- +- rl_completer_word_break_characters = savestring (value);
- +- return self;
- +-}
- +-#endif /* READLINE */
- +-
- +-#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
- +-static SHELL_VAR *
- +-assign_dirstack (self, value, ind, key)
- +- SHELL_VAR *self;
- +- char *value;
- +- arrayind_t ind;
- +- char *key;
- +-{
- +- set_dirstack_element (ind, 1, value);
- +- return self;
- +-}
- +-
- +-static SHELL_VAR *
- +-get_dirstack (self)
- +- SHELL_VAR *self;
- +-{
- +- ARRAY *a;
- +- WORD_LIST *l;
- +-
- +- l = get_directory_stack (0);
- +- a = array_from_word_list (l);
- +- array_dispose (array_cell (self));
- +- dispose_words (l);
- +- var_setarray (self, a);
- +- return self;
- +-}
- +-#endif /* PUSHD AND POPD && ARRAY_VARS */
- +-
- +-#if defined (ARRAY_VARS)
- +-/* We don't want to initialize the group set with a call to getgroups()
- +- unless we're asked to, but we only want to do it once. */
- +-static SHELL_VAR *
- +-get_groupset (self)
- +- SHELL_VAR *self;
- +-{
- +- register int i;
- +- int ng;
- +- ARRAY *a;
- +- static char **group_set = (char **)NULL;
- +-
- +- if (group_set == 0)
- +- {
- +- group_set = get_group_list (&ng);
- +- a = array_cell (self);
- +- for (i = 0; i < ng; i++)
- +- array_insert (a, i, group_set[i]);
- +- }
- +- return (self);
- +-}
- +-
- +-static SHELL_VAR *
- +-build_hashcmd (self)
- +- SHELL_VAR *self;
- +-{
- +- HASH_TABLE *h;
- +- int i;
- +- char *k, *v;
- +- BUCKET_CONTENTS *item;
- +-
- +- h = assoc_cell (self);
- +- if (h)
- +- assoc_dispose (h);
- +-
- +- if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0)
- +- {
- +- var_setvalue (self, (char *)NULL);
- +- return self;
- +- }
- +-
- +- h = assoc_create (hashed_filenames->nbuckets);
- +- for (i = 0; i < hashed_filenames->nbuckets; i++)
- +- {
- +- for (item = hash_items (i, hashed_filenames); item; item = item->next)
- +- {
- +- k = savestring (item->key);
- +- v = pathdata(item)->path;
- +- assoc_insert (h, k, v);
- +- }
- +- }
- +-
- +- var_setvalue (self, (char *)h);
- +- return self;
- +-}
- +-
- +-static SHELL_VAR *
- +-get_hashcmd (self)
- +- SHELL_VAR *self;
- +-{
- +- build_hashcmd (self);
- +- return (self);
- +-}
- +-
- +-static SHELL_VAR *
- +-assign_hashcmd (self, value, ind, key)
- +- SHELL_VAR *self;
- +- char *value;
- +- arrayind_t ind;
- +- char *key;
- +-{
- +- phash_insert (key, value, 0, 0);
- +- return (build_hashcmd (self));
- +-}
- +-
- +-#if defined (ALIAS)
- +-static SHELL_VAR *
- +-build_aliasvar (self)
- +- SHELL_VAR *self;
- +-{
- +- HASH_TABLE *h;
- +- int i;
- +- char *k, *v;
- +- BUCKET_CONTENTS *item;
- +-
- +- h = assoc_cell (self);
- +- if (h)
- +- assoc_dispose (h);
- +-
- +- if (aliases == 0 || HASH_ENTRIES (aliases) == 0)
- +- {
- +- var_setvalue (self, (char *)NULL);
- +- return self;
- +- }
- +-
- +- h = assoc_create (aliases->nbuckets);
- +- for (i = 0; i < aliases->nbuckets; i++)
- +- {
- +- for (item = hash_items (i, aliases); item; item = item->next)
- +- {
- +- k = savestring (item->key);
- +- v = ((alias_t *)(item->data))->value;
- +- assoc_insert (h, k, v);
- +- }
- +- }
- +-
- +- var_setvalue (self, (char *)h);
- +- return self;
- +-}
- +-
- +-static SHELL_VAR *
- +-get_aliasvar (self)
- +- SHELL_VAR *self;
- +-{
- +- build_aliasvar (self);
- +- return (self);
- +-}
- +-
- +-static SHELL_VAR *
- +-assign_aliasvar (self, value, ind, key)
- +- SHELL_VAR *self;
- +- char *value;
- +- arrayind_t ind;
- +- char *key;
- +-{
- +- add_alias (key, value);
- +- return (build_aliasvar (self));
- +-}
- +-#endif /* ALIAS */
- +-
- +-#endif /* ARRAY_VARS */
- +-
- +-/* If ARRAY_VARS is not defined, this just returns the name of any
- +- currently-executing function. If we have arrays, it's a call stack. */
- +-static SHELL_VAR *
- +-get_funcname (self)
- +- SHELL_VAR *self;
- +-{
- +-#if ! defined (ARRAY_VARS)
- +- char *t;
- +- if (variable_context && this_shell_function)
- +- {
- +- FREE (value_cell (self));
- +- t = savestring (this_shell_function->name);
- +- var_setvalue (self, t);
- +- }
- +-#endif
- +- return (self);
- +-}
- +-
- +-void
- +-make_funcname_visible (on_or_off)
- +- int on_or_off;
- +-{
- +- SHELL_VAR *v;
- +-
- +- v = find_variable ("FUNCNAME");
- +- if (v == 0 || v->dynamic_value == 0)
- +- return;
- +-
- +- if (on_or_off)
- +- VUNSETATTR (v, att_invisible);
- +- else
- +- VSETATTR (v, att_invisible);
- +-}
- +-
- +-static SHELL_VAR *
- +-init_funcname_var ()
- +-{
- +- SHELL_VAR *v;
- +-
- +- v = find_variable ("FUNCNAME");
- +- if (v)
- +- return v;
- +-#if defined (ARRAY_VARS)
- +- INIT_DYNAMIC_ARRAY_VAR ("FUNCNAME", get_funcname, null_array_assign);
- +-#else
- +- INIT_DYNAMIC_VAR ("FUNCNAME", (char *)NULL, get_funcname, null_assign);
- +-#endif
- +- VSETATTR (v, att_invisible|att_noassign);
- +- return v;
- +-}
- +-
- +-static void
- +-initialize_dynamic_variables ()
- +-{
- +- SHELL_VAR *v;
- +-
- +- v = init_seconds_var ();
- +-
- +- INIT_DYNAMIC_VAR ("BASH_COMMAND", (char *)NULL, get_bash_command, (sh_var_assign_func_t *)NULL);
- +- INIT_DYNAMIC_VAR ("BASH_SUBSHELL", (char *)NULL, get_subshell, assign_subshell);
- +-
- +- INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random);
- +- VSETATTR (v, att_integer);
- +- INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno);
- +- VSETATTR (v, att_integer);
- +-
- +- INIT_DYNAMIC_VAR ("BASHPID", (char *)NULL, get_bashpid, null_assign);
- +- VSETATTR (v, att_integer|att_readonly);
- +-
- +-#if defined (HISTORY)
- +- INIT_DYNAMIC_VAR ("HISTCMD", (char *)NULL, get_histcmd, (sh_var_assign_func_t *)NULL);
- +- VSETATTR (v, att_integer);
- +-#endif
- +-
- +-#if defined (READLINE)
- +- INIT_DYNAMIC_VAR ("COMP_WORDBREAKS", (char *)NULL, get_comp_wordbreaks, assign_comp_wordbreaks);
- +-#endif
- +-
- +-#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
- +- v = init_dynamic_array_var ("DIRSTACK", get_dirstack, assign_dirstack, 0);
- +-#endif /* PUSHD_AND_POPD && ARRAY_VARS */
- +-
- +-#if defined (ARRAY_VARS)
- +- v = init_dynamic_array_var ("GROUPS", get_groupset, null_array_assign, att_noassign);
- +-
- +-# if defined (DEBUGGER)
- +- v = init_dynamic_array_var ("BASH_ARGC", get_self, null_array_assign, att_noassign|att_nounset);
- +- v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, att_noassign|att_nounset);
- +-# endif /* DEBUGGER */
- +- v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, att_noassign|att_nounset);
- +- v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, att_noassign|att_nounset);
- +-
- +- v = init_dynamic_assoc_var ("BASH_CMDS", get_hashcmd, assign_hashcmd, att_nofree);
- +-# if defined (ALIAS)
- +- v = init_dynamic_assoc_var ("BASH_ALIASES", get_aliasvar, assign_aliasvar, att_nofree);
- +-# endif
- +-#endif
- +-
- +- v = init_funcname_var ();
- +-}
- +-
- +-/* **************************************************************** */
- +-/* */
- +-/* Retrieving variables and values */
- +-/* */
- +-/* **************************************************************** */
- +-
- +-/* How to get a pointer to the shell variable or function named NAME.
- +- HASHED_VARS is a pointer to the hash table containing the list
- +- of interest (either variables or functions). */
- +-
- +-static SHELL_VAR *
- +-hash_lookup (name, hashed_vars)
- +- const char *name;
- +- HASH_TABLE *hashed_vars;
- +-{
- +- BUCKET_CONTENTS *bucket;
- +-
- +- bucket = hash_search (name, hashed_vars, 0);
- +- /* If we find the name in HASHED_VARS, set LAST_TABLE_SEARCHED to that
- +- table. */
- +- if (bucket)
- +- last_table_searched = hashed_vars;
- +- return (bucket ? (SHELL_VAR *)bucket->data : (SHELL_VAR *)NULL);
- +-}
- +-
- +-SHELL_VAR *
- +-var_lookup (name, vcontext)
- +- const char *name;
- +- VAR_CONTEXT *vcontext;
- +-{
- +- VAR_CONTEXT *vc;
- +- SHELL_VAR *v;
- +-
- +- v = (SHELL_VAR *)NULL;
- +- for (vc = vcontext; vc; vc = vc->down)
- +- if (v = hash_lookup (name, vc->table))
- +- break;
- +-
- +- return v;
- +-}
- +-
- +-/* Look up the variable entry named NAME. If SEARCH_TEMPENV is non-zero,
- +- then also search the temporarily built list of exported variables.
- +- The lookup order is:
- +- temporary_env
- +- shell_variables list
- +-*/
- +-
- +-SHELL_VAR *
- +-find_variable_internal (name, force_tempenv)
- +- const char *name;
- +- int force_tempenv;
- +-{
- +- SHELL_VAR *var;
- +- int search_tempenv;
- +- VAR_CONTEXT *vc;
- +-
- +- var = (SHELL_VAR *)NULL;
- +-
- +- /* If explicitly requested, first look in the temporary environment for
- +- the variable. This allows constructs such as "foo=x eval 'echo $foo'"
- +- to get the `exported' value of $foo. This happens if we are executing
- +- a function or builtin, or if we are looking up a variable in a
- +- "subshell environment". */
- +- search_tempenv = force_tempenv || (expanding_redir == 0 && subshell_environment);
- +-
- +- if (search_tempenv && temporary_env)
- +- var = hash_lookup (name, temporary_env);
- +-
- +- vc = shell_variables;
- +-#if 0
- +-if (search_tempenv == 0 && /* (subshell_environment & SUBSHELL_COMSUB) && */
- +- expanding_redir &&
- +- (this_shell_builtin == eval_builtin || this_shell_builtin == command_builtin))
- +- {
- +- itrace("find_variable_internal: search_tempenv == 0: skipping VC_BLTNENV");
- +- while (vc && (vc->flags & VC_BLTNENV))
- +- vc = vc->down;
- +- if (vc == 0)
- +- vc = shell_variables;
- +- }
- +-#endif
- +-
- +- if (var == 0)
- +- var = var_lookup (name, vc);
- +-
- +- if (var == 0)
- +- return ((SHELL_VAR *)NULL);
- +-
- +- return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
- +-}
- +-
- +-/* Look up and resolve the chain of nameref variables starting at V all the
- +- way to NULL or non-nameref. */
- +-SHELL_VAR *
- +-find_variable_nameref (v)
- +- SHELL_VAR *v;
- +-{
- +- int level;
- +- char *newname;
- +- SHELL_VAR *orig, *oldv;
- +-
- +- level = 0;
- +- orig = v;
- +- while (v && nameref_p (v))
- +- {
- +- level++;
- +- if (level > NAMEREF_MAX)
- +- return ((SHELL_VAR *)0); /* error message here? */
- +- newname = nameref_cell (v);
- +- if (newname == 0 || *newname == '\0')
- +- return ((SHELL_VAR *)0);
- +- oldv = v;
- +- v = find_variable_internal (newname, (expanding_redir == 0 && (assigning_in_environment || executing_builtin)));
- +- if (v == orig || v == oldv)
- +- {
- +- internal_warning (_("%s: circular name reference"), orig->name);
- +- return ((SHELL_VAR *)0);
- +- }
- +- }
- +- return v;
- +-}
- +-
- +-/* Resolve the chain of nameref variables for NAME. XXX - could change later */
- +-SHELL_VAR *
- +-find_variable_last_nameref (name)
- +- const char *name;
- +-{
- +- SHELL_VAR *v, *nv;
- +- char *newname;
- +- int level;
- +-
- +- nv = v = find_variable_noref (name);
- +- level = 0;
- +- while (v && nameref_p (v))
- +- {
- +- level++;
- +- if (level > NAMEREF_MAX)
- +- return ((SHELL_VAR *)0); /* error message here? */
- +- newname = nameref_cell (v);
- +- if (newname == 0 || *newname == '\0')
- +- return ((SHELL_VAR *)0);
- +- nv = v;
- +- v = find_variable_internal (newname, (expanding_redir == 0 && (assigning_in_environment || executing_builtin)));
- +- }
- +- return nv;
- +-}
- +-
- +-/* Resolve the chain of nameref variables for NAME. XXX - could change later */
- +-SHELL_VAR *
- +-find_global_variable_last_nameref (name)
- +- const char *name;
- +-{
- +- SHELL_VAR *v, *nv;
- +- char *newname;
- +- int level;
- +-
- +- nv = v = find_global_variable_noref (name);
- +- level = 0;
- +- while (v && nameref_p (v))
- +- {
- +- level++;
- +- if (level > NAMEREF_MAX)
- +- return ((SHELL_VAR *)0); /* error message here? */
- +- newname = nameref_cell (v);
- +- if (newname == 0 || *newname == '\0')
- +- return ((SHELL_VAR *)0);
- +- nv = v;
- +- v = find_global_variable_noref (newname);
- +- }
- +- return nv;
- +-}
- +-
- +-static SHELL_VAR *
- +-find_nameref_at_context (v, vc)
- +- SHELL_VAR *v;
- +- VAR_CONTEXT *vc;
- +-{
- +- SHELL_VAR *nv, *nv2;
- +- VAR_CONTEXT *nvc;
- +- char *newname;
- +- int level;
- +-
- +- nv = v;
- +- level = 1;
- +- while (nv && nameref_p (nv))
- +- {
- +- level++;
- +- if (level > NAMEREF_MAX)
- +- return ((SHELL_VAR *)NULL);
- +- newname = nameref_cell (nv);
- +- if (newname == 0 || *newname == '\0')
- +- return ((SHELL_VAR *)NULL);
- +- nv2 = hash_lookup (newname, vc->table);
- +- if (nv2 == 0)
- +- break;
- +- nv = nv2;
- +- }
- +- return nv;
- +-}
- +-
- +-/* Do nameref resolution from the VC, which is the local context for some
- +- function or builtin, `up' the chain to the global variables context. If
- +- NVCP is not NULL, return the variable context where we finally ended the
- +- nameref resolution (so the bind_variable_internal can use the correct
- +- variable context and hash table). */
- +-static SHELL_VAR *
- +-find_variable_nameref_context (v, vc, nvcp)
- +- SHELL_VAR *v;
- +- VAR_CONTEXT *vc;
- +- VAR_CONTEXT **nvcp;
- +-{
- +- SHELL_VAR *nv, *nv2;
- +- VAR_CONTEXT *nvc;
- +-
- +- /* Look starting at the current context all the way `up' */
- +- for (nv = v, nvc = vc; nvc; nvc = nvc->down)
- +- {
- +- nv2 = find_nameref_at_context (nv, nvc);
- +- if (nv2 == 0)
- +- continue;
- +- nv = nv2;
- +- if (*nvcp)
- +- *nvcp = nvc;
- +- if (nameref_p (nv) == 0)
- +- break;
- +- }
- +- return (nameref_p (nv) ? (SHELL_VAR *)NULL : nv);
- +-}
- +-
- +-/* Do nameref resolution from the VC, which is the local context for some
- +- function or builtin, `up' the chain to the global variables context. If
- +- NVCP is not NULL, return the variable context where we finally ended the
- +- nameref resolution (so the bind_variable_internal can use the correct
- +- variable context and hash table). */
- +-static SHELL_VAR *
- +-find_variable_last_nameref_context (v, vc, nvcp)
- +- SHELL_VAR *v;
- +- VAR_CONTEXT *vc;
- +- VAR_CONTEXT **nvcp;
- +-{
- +- SHELL_VAR *nv, *nv2;
- +- VAR_CONTEXT *nvc;
- +-
- +- /* Look starting at the current context all the way `up' */
- +- for (nv = v, nvc = vc; nvc; nvc = nvc->down)
- +- {
- +- nv2 = find_nameref_at_context (nv, nvc);
- +- if (nv2 == 0)
- +- continue;
- +- nv = nv2;
- +- if (*nvcp)
- +- *nvcp = nvc;
- +- }
- +- return (nameref_p (nv) ? nv : (SHELL_VAR *)NULL);
- +-}
- +-
- +-/* Find a variable, forcing a search of the temporary environment first */
- +-SHELL_VAR *
- +-find_variable_tempenv (name)
- +- const char *name;
- +-{
- +- SHELL_VAR *var;
- +-
- +- var = find_variable_internal (name, 1);
- +- if (var && nameref_p (var))
- +- var = find_variable_nameref (var);
- +- return (var);
- +-}
- +-
- +-/* Find a variable, not forcing a search of the temporary environment first */
- +-SHELL_VAR *
- +-find_variable_notempenv (name)
- +- const char *name;
- +-{
- +- SHELL_VAR *var;
- +-
- +- var = find_variable_internal (name, 0);
- +- if (var && nameref_p (var))
- +- var = find_variable_nameref (var);
- +- return (var);
- +-}
- +-
- +-SHELL_VAR *
- +-find_global_variable (name)
- +- const char *name;
- +-{
- +- SHELL_VAR *var;
- +-
- +- var = var_lookup (name, global_variables);
- +- if (var && nameref_p (var))
- +- var = find_variable_nameref (var);
- +-
- +- if (var == 0)
- +- return ((SHELL_VAR *)NULL);
- +-
- +- return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
- +-}
- +-
- +-SHELL_VAR *
- +-find_global_variable_noref (name)
- +- const char *name;
- +-{
- +- SHELL_VAR *var;
- +-
- +- var = var_lookup (name, global_variables);
- +-
- +- if (var == 0)
- +- return ((SHELL_VAR *)NULL);
- +-
- +- return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
- +-}
- +-
- +-SHELL_VAR *
- +-find_shell_variable (name)
- +- const char *name;
- +-{
- +- SHELL_VAR *var;
- +-
- +- var = var_lookup (name, shell_variables);
- +- if (var && nameref_p (var))
- +- var = find_variable_nameref (var);
- +-
- +- if (var == 0)
- +- return ((SHELL_VAR *)NULL);
- +-
- +- return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
- +-}
- +-
- +-/* Look up the variable entry named NAME. Returns the entry or NULL. */
- +-SHELL_VAR *
- +-find_variable (name)
- +- const char *name;
- +-{
- +- SHELL_VAR *v;
- +-
- +- last_table_searched = 0;
- +- v = find_variable_internal (name, (expanding_redir == 0 && (assigning_in_environment || executing_builtin)));
- +- if (v && nameref_p (v))
- +- v = find_variable_nameref (v);
- +- return v;
- +-}
- +-
- +-SHELL_VAR *
- +-find_variable_noref (name)
- +- const char *name;
- +-{
- +- SHELL_VAR *v;
- +-
- +- v = find_variable_internal (name, (expanding_redir == 0 && (assigning_in_environment || executing_builtin)));
- +- return v;
- +-}
- +-
- +-/* Look up the function entry whose name matches STRING.
- +- Returns the entry or NULL. */
- +-SHELL_VAR *
- +-find_function (name)
- +- const char *name;
- +-{
- +- return (hash_lookup (name, shell_functions));
- +-}
- +-
- +-/* Find the function definition for the shell function named NAME. Returns
- +- the entry or NULL. */
- +-FUNCTION_DEF *
- +-find_function_def (name)
- +- const char *name;
- +-{
- +-#if defined (DEBUGGER)
- +- return ((FUNCTION_DEF *)hash_lookup (name, shell_function_defs));
- +-#else
- +- return ((FUNCTION_DEF *)0);
- +-#endif
- +-}
- +-
- +-/* Return the value of VAR. VAR is assumed to have been the result of a
- +- lookup without any subscript, if arrays are compiled into the shell. */
- +-char *
- +-get_variable_value (var)
- +- SHELL_VAR *var;
- +-{
- +- if (var == 0)
- +- return ((char *)NULL);
- +-#if defined (ARRAY_VARS)
- +- else if (array_p (var))
- +- return (array_reference (array_cell (var), 0));
- +- else if (assoc_p (var))
- +- return (assoc_reference (assoc_cell (var), "0"));
- +-#endif
- +- else
- +- return (value_cell (var));
- +-}
- +-
- +-/* Return the string value of a variable. Return NULL if the variable
- +- doesn't exist. Don't cons a new string. This is a potential memory
- +- leak if the variable is found in the temporary environment. Since
- +- functions and variables have separate name spaces, returns NULL if
- +- var_name is a shell function only. */
- +-char *
- +-get_string_value (var_name)
- +- const char *var_name;
- +-{
- +- SHELL_VAR *var;
- +-
- +- var = find_variable (var_name);
- +- return ((var) ? get_variable_value (var) : (char *)NULL);
- +-}
- +-
- +-/* This is present for use by the tilde and readline libraries. */
- +-char *
- +-sh_get_env_value (v)
- +- const char *v;
- +-{
- +- return get_string_value (v);
- +-}
- +-
- +-/* **************************************************************** */
- +-/* */
- +-/* Creating and setting variables */
- +-/* */
- +-/* **************************************************************** */
- +-
- +-/* Set NAME to VALUE if NAME has no value. */
- +-SHELL_VAR *
- +-set_if_not (name, value)
- +- char *name, *value;
- +-{
- +- SHELL_VAR *v;
- +-
- +- if (shell_variables == 0)
- +- create_variable_tables ();
- +-
- +- v = find_variable (name);
- +- if (v == 0)
- +- v = bind_variable_internal (name, value, global_variables->table, HASH_NOSRCH, 0);
- +- return (v);
- +-}
- +-
- +-/* Create a local variable referenced by NAME. */
- +-SHELL_VAR *
- +-make_local_variable (name)
- +- const char *name;
- +-{
- +- SHELL_VAR *new_var, *old_var;
- +- VAR_CONTEXT *vc;
- +- int was_tmpvar;
- +- char *tmp_value;
- +-
- +- /* local foo; local foo; is a no-op. */
- +- old_var = find_variable (name);
- +- if (old_var && local_p (old_var) && old_var->context == variable_context)
- +- return (old_var);
- +-
- +- was_tmpvar = old_var && tempvar_p (old_var);
- +- /* If we're making a local variable in a shell function, the temporary env
- +- has already been merged into the function's variable context stack. We
- +- can assume that a temporary var in the same context appears in the same
- +- VAR_CONTEXT and can safely be returned without creating a new variable
- +- (which results in duplicate names in the same VAR_CONTEXT->table */
- +- /* We can't just test tmpvar_p because variables in the temporary env given
- +- to a shell function appear in the function's local variable VAR_CONTEXT
- +- but retain their tempvar attribute. We want temporary variables that are
- +- found in temporary_env, hence the test for last_table_searched, which is
- +- set in hash_lookup and only (so far) checked here. */
- +- if (was_tmpvar && old_var->context == variable_context && last_table_searched != temporary_env)
- +- {
- +- VUNSETATTR (old_var, att_invisible);
- +- return (old_var);
- +- }
- +- if (was_tmpvar)
- +- tmp_value = value_cell (old_var);
- +-
- +- for (vc = shell_variables; vc; vc = vc->down)
- +- if (vc_isfuncenv (vc) && vc->scope == variable_context)
- +- break;
- +-
- +- if (vc == 0)
- +- {
- +- internal_error (_("make_local_variable: no function context at current scope"));
- +- return ((SHELL_VAR *)NULL);
- +- }
- +- else if (vc->table == 0)
- +- vc->table = hash_create (TEMPENV_HASH_BUCKETS);
- +-
- +- /* Since this is called only from the local/declare/typeset code, we can
- +- call builtin_error here without worry (of course, it will also work
- +- for anything that sets this_command_name). Variables with the `noassign'
- +- attribute may not be made local. The test against old_var's context
- +- level is to disallow local copies of readonly global variables (since I
- +- believe that this could be a security hole). Readonly copies of calling
- +- function local variables are OK. */
- +- if (old_var && (noassign_p (old_var) ||
- +- (readonly_p (old_var) && old_var->context == 0)))
- +- {
- +- if (readonly_p (old_var))
- +- sh_readonly (name);
- +- else if (noassign_p (old_var))
- +- builtin_error (_("%s: variable may not be assigned value"), name);
- +-#if 0
- +- /* Let noassign variables through with a warning */
- +- if (readonly_p (old_var))
- +-#endif
- +- return ((SHELL_VAR *)NULL);
- +- }
- +-
- +- if (old_var == 0)
- +- new_var = make_new_variable (name, vc->table);
- +- else
- +- {
- +- new_var = make_new_variable (name, vc->table);
- +-
- +- /* If we found this variable in one of the temporary environments,
- +- inherit its value. Watch to see if this causes problems with
- +- things like `x=4 local x'. XXX - see above for temporary env
- +- variables with the same context level as variable_context */
- +- /* XXX - we should only do this if the variable is not an array. */
- +- if (was_tmpvar)
- +- var_setvalue (new_var, savestring (tmp_value));
- +-
- +- new_var->attributes = exported_p (old_var) ? att_exported : 0;
- +- }
- +-
- +- vc->flags |= VC_HASLOCAL;
- +-
- +- new_var->context = variable_context;
- +- VSETATTR (new_var, att_local);
- +-
- +- if (ifsname (name))
- +- setifs (new_var);
- +-
- +- if (was_tmpvar == 0)
- +- VSETATTR (new_var, att_invisible); /* XXX */
- +- return (new_var);
- +-}
- +-
- +-/* Create a new shell variable with name NAME. */
- +-static SHELL_VAR *
- +-new_shell_variable (name)
- +- const char *name;
- +-{
- +- SHELL_VAR *entry;
- +-
- +- entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
- +-
- +- entry->name = savestring (name);
- +- var_setvalue (entry, (char *)NULL);
- +- CLEAR_EXPORTSTR (entry);
- +-
- +- entry->dynamic_value = (sh_var_value_func_t *)NULL;
- +- entry->assign_func = (sh_var_assign_func_t *)NULL;
- +-
- +- entry->attributes = 0;
- +-
- +- /* Always assume variables are to be made at toplevel!
- +- make_local_variable has the responsibility of changing the
- +- variable context. */
- +- entry->context = 0;
- +-
- +- return (entry);
- +-}
- +-
- +-/* Create a new shell variable with name NAME and add it to the hash table
- +- TABLE. */
- +-static SHELL_VAR *
- +-make_new_variable (name, table)
- +- const char *name;
- +- HASH_TABLE *table;
- +-{
- +- SHELL_VAR *entry;
- +- BUCKET_CONTENTS *elt;
- +-
- +- entry = new_shell_variable (name);
- +-
- +- /* Make sure we have a shell_variables hash table to add to. */
- +- if (shell_variables == 0)
- +- create_variable_tables ();
- +-
- +- elt = hash_insert (savestring (name), table, HASH_NOSRCH);
- +- elt->data = (PTR_T)entry;
- +-
- +- return entry;
- +-}
- +-
- +-#if defined (ARRAY_VARS)
- +-SHELL_VAR *
- +-make_new_array_variable (name)
- +- char *name;
- +-{
- +- SHELL_VAR *entry;
- +- ARRAY *array;
- +-
- +- entry = make_new_variable (name, global_variables->table);
- +- array = array_create ();
- +-
- +- var_setarray (entry, array);
- +- VSETATTR (entry, att_array);
- +- return entry;
- +-}
- +-
- +-SHELL_VAR *
- +-make_local_array_variable (name, assoc_ok)
- +- char *name;
- +- int assoc_ok;
- +-{
- +- SHELL_VAR *var;
- +- ARRAY *array;
- +-
- +- var = make_local_variable (name);
- +- if (var == 0 || array_p (var) || (assoc_ok && assoc_p (var)))
- +- return var;
- +-
- +- array = array_create ();
- +-
- +- dispose_variable_value (var);
- +- var_setarray (var, array);
- +- VSETATTR (var, att_array);
- +- return var;
- +-}
- +-
- +-SHELL_VAR *
- +-make_new_assoc_variable (name)
- +- char *name;
- +-{
- +- SHELL_VAR *entry;
- +- HASH_TABLE *hash;
- +-
- +- entry = make_new_variable (name, global_variables->table);
- +- hash = assoc_create (0);
- +-
- +- var_setassoc (entry, hash);
- +- VSETATTR (entry, att_assoc);
- +- return entry;
- +-}
- +-
- +-SHELL_VAR *
- +-make_local_assoc_variable (name)
- +- char *name;
- +-{
- +- SHELL_VAR *var;
- +- HASH_TABLE *hash;
- +-
- +- var = make_local_variable (name);
- +- if (var == 0 || assoc_p (var))
- +- return var;
- +-
- +- dispose_variable_value (var);
- +- hash = assoc_create (0);
- +-
- +- var_setassoc (var, hash);
- +- VSETATTR (var, att_assoc);
- +- return var;
- +-}
- +-#endif
- +-
- +-char *
- +-make_variable_value (var, value, flags)
- +- SHELL_VAR *var;
- +- char *value;
- +- int flags;
- +-{
- +- char *retval, *oval;
- +- intmax_t lval, rval;
- +- int expok, olen, op;
- +-
- +- /* If this variable has had its type set to integer (via `declare -i'),
- +- then do expression evaluation on it and store the result. The
- +- functions in expr.c (evalexp()) and bind_int_variable() are responsible
- +- for turning off the integer flag if they don't want further
- +- evaluation done. */
- +- if (integer_p (var))
- +- {
- +- if (flags & ASS_APPEND)
- +- {
- +- oval = value_cell (var);
- +- lval = evalexp (oval, &expok); /* ksh93 seems to do this */
- +- if (expok == 0)
- +- {
- +- top_level_cleanup ();
- +- jump_to_top_level (DISCARD);
- +- }
- +- }
- +- rval = evalexp (value, &expok);
- +- if (expok == 0)
- +- {
- +- top_level_cleanup ();
- +- jump_to_top_level (DISCARD);
- +- }
- +- /* This can be fooled if the variable's value changes while evaluating
- +- `rval'. We can change it if we move the evaluation of lval to here. */
- +- if (flags & ASS_APPEND)
- +- rval += lval;
- +- retval = itos (rval);
- +- }
- +-#if defined (CASEMOD_ATTRS)
- +- else if (capcase_p (var) || uppercase_p (var) || lowercase_p (var))
- +- {
- +- if (flags & ASS_APPEND)
- +- {
- +- oval = get_variable_value (var);
- +- if (oval == 0) /* paranoia */
- +- oval = "";
- +- olen = STRLEN (oval);
- +- retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1);
- +- strcpy (retval, oval);
- +- if (value)
- +- strcpy (retval+olen, value);
- +- }
- +- else if (*value)
- +- retval = savestring (value);
- +- else
- +- {
- +- retval = (char *)xmalloc (1);
- +- retval[0] = '\0';
- +- }
- +- op = capcase_p (var) ? CASE_CAPITALIZE
- +- : (uppercase_p (var) ? CASE_UPPER : CASE_LOWER);
- +- oval = sh_modcase (retval, (char *)0, op);
- +- free (retval);
- +- retval = oval;
- +- }
- +-#endif /* CASEMOD_ATTRS */
- +- else if (value)
- +- {
- +- if (flags & ASS_APPEND)
- +- {
- +- oval = get_variable_value (var);
- +- if (oval == 0) /* paranoia */
- +- oval = "";
- +- olen = STRLEN (oval);
- +- retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1);
- +- strcpy (retval, oval);
- +- if (value)
- +- strcpy (retval+olen, value);
- +- }
- +- else if (*value)
- +- retval = savestring (value);
- +- else
- +- {
- +- retval = (char *)xmalloc (1);
- +- retval[0] = '\0';
- +- }
- +- }
- +- else
- +- retval = (char *)NULL;
- +-
- +- return retval;
- +-}
- +-
- +-/* Bind a variable NAME to VALUE in the HASH_TABLE TABLE, which may be the
- +- temporary environment (but usually is not). */
- +-static SHELL_VAR *
- +-bind_variable_internal (name, value, table, hflags, aflags)
- +- const char *name;
- +- char *value;
- +- HASH_TABLE *table;
- +- int hflags, aflags;
- +-{
- +- char *newval;
- +- SHELL_VAR *entry;
- +-
- +- entry = (hflags & HASH_NOSRCH) ? (SHELL_VAR *)NULL : hash_lookup (name, table);
- +- /* Follow the nameref chain here if this is the global variables table */
- +- if (entry && nameref_p (entry) && (invisible_p (entry) == 0) && table == global_variables->table)
- +- {
- +- entry = find_global_variable (entry->name);
- +- /* Let's see if we have a nameref referencing a variable that hasn't yet
- +- been created. */
- +- if (entry == 0)
- +- entry = find_variable_last_nameref (name); /* XXX */
- +- if (entry == 0) /* just in case */
- +- return (entry);
- +- }
- +-
- +- /* The first clause handles `declare -n ref; ref=x;' */
- +- if (entry && invisible_p (entry) && nameref_p (entry))
- +- goto assign_value;
- +- else if (entry && nameref_p (entry))
- +- {
- +- newval = nameref_cell (entry);
- +-#if defined (ARRAY_VARS)
- +- /* declare -n foo=x[2] */
- +- if (valid_array_reference (newval))
- +- /* XXX - should it be aflags? */
- +- entry = assign_array_element (newval, make_variable_value (entry, value, 0), aflags);
- +- else
- +-#endif
- +- {
- +- entry = make_new_variable (newval, table);
- +- var_setvalue (entry, make_variable_value (entry, value, 0));
- +- }
- +- }
- +- else if (entry == 0)
- +- {
- +- entry = make_new_variable (name, table);
- +- var_setvalue (entry, make_variable_value (entry, value, 0)); /* XXX */
- +- }
- +- else if (entry->assign_func) /* array vars have assign functions now */
- +- {
- +- INVALIDATE_EXPORTSTR (entry);
- +- newval = (aflags & ASS_APPEND) ? make_variable_value (entry, value, aflags) : value;
- +- if (assoc_p (entry))
- +- entry = (*(entry->assign_func)) (entry, newval, -1, savestring ("0"));
- +- else if (array_p (entry))
- +- entry = (*(entry->assign_func)) (entry, newval, 0, 0);
- +- else
- +- entry = (*(entry->assign_func)) (entry, newval, -1, 0);
- +- if (newval != value)
- +- free (newval);
- +- return (entry);
- +- }
- +- else
- +- {
- +-assign_value:
- +- if (readonly_p (entry) || noassign_p (entry))
- +- {
- +- if (readonly_p (entry))
- +- err_readonly (name);
- +- return (entry);
- +- }
- +-
- +- /* Variables which are bound are visible. */
- +- VUNSETATTR (entry, att_invisible);
- +-
- +-#if defined (ARRAY_VARS)
- +- if (assoc_p (entry) || array_p (entry))
- +- newval = make_array_variable_value (entry, 0, "0", value, aflags);
- +- else
- +-#endif
- +-
- +- newval = make_variable_value (entry, value, aflags); /* XXX */
- +-
- +- /* Invalidate any cached export string */
- +- INVALIDATE_EXPORTSTR (entry);
- +-
- +-#if defined (ARRAY_VARS)
- +- /* XXX -- this bears looking at again -- XXX */
- +- /* If an existing array variable x is being assigned to with x=b or
- +- `read x' or something of that nature, silently convert it to
- +- x[0]=b or `read x[0]'. */
- +- if (assoc_p (entry))
- +- {
- +- assoc_insert (assoc_cell (entry), savestring ("0"), newval);
- +- free (newval);
- +- }
- +- else if (array_p (entry))
- +- {
- +- array_insert (array_cell (entry), 0, newval);
- +- free (newval);
- +- }
- +- else
- +-#endif
- +- {
- +- FREE (value_cell (entry));
- +- var_setvalue (entry, newval);
- +- }
- +- }
- +-
- +- if (mark_modified_vars)
- +- VSETATTR (entry, att_exported);
- +-
- +- if (exported_p (entry))
- +- array_needs_making = 1;
- +-
- +- return (entry);
- +-}
- +-
- +-/* Bind a variable NAME to VALUE. This conses up the name
- +- and value strings. If we have a temporary environment, we bind there
- +- first, then we bind into shell_variables. */
- +-
- +-SHELL_VAR *
- +-bind_variable (name, value, flags)
- +- const char *name;
- +- char *value;
- +- int flags;
- +-{
- +- SHELL_VAR *v, *nv;
- +- VAR_CONTEXT *vc, *nvc;
- +- int level;
- +-
- +- if (shell_variables == 0)
- +- create_variable_tables ();
- +-
- +- /* If we have a temporary environment, look there first for the variable,
- +- and, if found, modify the value there before modifying it in the
- +- shell_variables table. This allows sourced scripts to modify values
- +- given to them in a temporary environment while modifying the variable
- +- value that the caller sees. */
- +- if (temporary_env)
- +- bind_tempenv_variable (name, value);
- +-
- +- /* XXX -- handle local variables here. */
- +- for (vc = shell_variables; vc; vc = vc->down)
- +- {
- +- if (vc_isfuncenv (vc) || vc_isbltnenv (vc))
- +- {
- +- v = hash_lookup (name, vc->table);
- +- nvc = vc;
- +- if (v && nameref_p (v))
- +- {
- +- nv = find_variable_nameref_context (v, vc, &nvc);
- +- if (nv == 0)
- +- {
- +- nv = find_variable_last_nameref_context (v, vc, &nvc);
- +- if (nv && nameref_p (nv))
- +- {
- +- /* If this nameref variable doesn't have a value yet,
- +- set the value. Otherwise, assign using the value as
- +- normal. */
- +- if (nameref_cell (nv) == 0)
- +- return (bind_variable_internal (nv->name, value, nvc->table, 0, flags));
- +- return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags));
- +- }
- +- else
- +- v = nv;
- +- }
- +- else
- +- v = nv;
- +- }
- +- if (v)
- +- return (bind_variable_internal (v->name, value, nvc->table, 0, flags));
- +- }
- +- }
- +- /* bind_variable_internal will handle nameref resolution in this case */
- +- return (bind_variable_internal (name, value, global_variables->table, 0, flags));
- +-}
- +-
- +-SHELL_VAR *
- +-bind_global_variable (name, value, flags)
- +- const char *name;
- +- char *value;
- +- int flags;
- +-{
- +- SHELL_VAR *v, *nv;
- +- VAR_CONTEXT *vc, *nvc;
- +- int level;
- +-
- +- if (shell_variables == 0)
- +- create_variable_tables ();
- +-
- +- /* bind_variable_internal will handle nameref resolution in this case */
- +- return (bind_variable_internal (name, value, global_variables->table, 0, flags));
- +-}
- +-
- +-/* Make VAR, a simple shell variable, have value VALUE. Once assigned a
- +- value, variables are no longer invisible. This is a duplicate of part
- +- of the internals of bind_variable. If the variable is exported, or
- +- all modified variables should be exported, mark the variable for export
- +- and note that the export environment needs to be recreated. */
- +-SHELL_VAR *
- +-bind_variable_value (var, value, aflags)
- +- SHELL_VAR *var;
- +- char *value;
- +- int aflags;
- +-{
- +- char *t;
- +- int invis;
- +-
- +- invis = invisible_p (var);
- +- VUNSETATTR (var, att_invisible);
- +-
- +- if (var->assign_func)
- +- {
- +- /* If we're appending, we need the old value, so use
- +- make_variable_value */
- +- t = (aflags & ASS_APPEND) ? make_variable_value (var, value, aflags) : value;
- +- (*(var->assign_func)) (var, t, -1, 0);
- +- if (t != value && t)
- +- free (t);
- +- }
- +- else
- +- {
- +- t = make_variable_value (var, value, aflags);
- +-#if defined (ARRAY_VARS)
- +- if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || (legal_identifier (t) == 0 && valid_array_reference (t) == 0)))
- +-#else
- +- if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || legal_identifier (t) == 0))
- +-#endif
- +- {
- +- free (t);
- +- if (invis)
- +- VSETATTR (var, att_invisible); /* XXX */
- +- return ((SHELL_VAR *)NULL);
- +- }
- +- FREE (value_cell (var));
- +- var_setvalue (var, t);
- +- }
- +-
- +- INVALIDATE_EXPORTSTR (var);
- +-
- +- if (mark_modified_vars)
- +- VSETATTR (var, att_exported);
- +-
- +- if (exported_p (var))
- +- array_needs_making = 1;
- +-
- +- return (var);
- +-}
- +-
- +-/* Bind/create a shell variable with the name LHS to the RHS.
- +- This creates or modifies a variable such that it is an integer.
- +-
- +- This used to be in expr.c, but it is here so that all of the
- +- variable binding stuff is localized. Since we don't want any
- +- recursive evaluation from bind_variable() (possible without this code,
- +- since bind_variable() calls the evaluator for variables with the integer
- +- attribute set), we temporarily turn off the integer attribute for each
- +- variable we set here, then turn it back on after binding as necessary. */
- +-
- +-SHELL_VAR *
- +-bind_int_variable (lhs, rhs)
- +- char *lhs, *rhs;
- +-{
- +- register SHELL_VAR *v;
- +- int isint, isarr, implicitarray;
- +-
- +- isint = isarr = implicitarray = 0;
- +-#if defined (ARRAY_VARS)
- +- if (valid_array_reference (lhs))
- +- {
- +- isarr = 1;
- +- v = array_variable_part (lhs, (char **)0, (int *)0);
- +- }
- +- else
- +-#endif
- +- v = find_variable (lhs);
- +-
- +- if (v)
- +- {
- +- isint = integer_p (v);
- +- VUNSETATTR (v, att_integer);
- +-#if defined (ARRAY_VARS)
- +- if (array_p (v) && isarr == 0)
- +- implicitarray = 1;
- +-#endif
- +- }
- +-
- +-#if defined (ARRAY_VARS)
- +- if (isarr)
- +- v = assign_array_element (lhs, rhs, 0);
- +- else if (implicitarray)
- +- v = bind_array_variable (lhs, 0, rhs, 0);
- +- else
- +-#endif
- +- v = bind_variable (lhs, rhs, 0);
- +-
- +- if (v && isint)
- +- VSETATTR (v, att_integer);
- +-
- +- VUNSETATTR (v, att_invisible);
- +-
- +- return (v);
- +-}
- +-
- +-SHELL_VAR *
- +-bind_var_to_int (var, val)
- +- char *var;
- +- intmax_t val;
- +-{
- +- char ibuf[INT_STRLEN_BOUND (intmax_t) + 1], *p;
- +-
- +- p = fmtulong (val, 10, ibuf, sizeof (ibuf), 0);
- +- return (bind_int_variable (var, p));
- +-}
- +-
- +-/* Do a function binding to a variable. You pass the name and
- +- the command to bind to. This conses the name and command. */
- +-SHELL_VAR *
- +-bind_function (name, value)
- +- const char *name;
- +- COMMAND *value;
- +-{
- +- SHELL_VAR *entry;
- +-
- +- entry = find_function (name);
- +- if (entry == 0)
- +- {
- +- BUCKET_CONTENTS *elt;
- +-
- +- elt = hash_insert (savestring (name), shell_functions, HASH_NOSRCH);
- +- entry = new_shell_variable (name);
- +- elt->data = (PTR_T)entry;
- +- }
- +- else
- +- INVALIDATE_EXPORTSTR (entry);
- +-
- +- if (var_isset (entry))
- +- dispose_command (function_cell (entry));
- +-
- +- if (value)
- +- var_setfunc (entry, copy_command (value));
- +- else
- +- var_setfunc (entry, 0);
- +-
- +- VSETATTR (entry, att_function);
- +-
- +- if (mark_modified_vars)
- +- VSETATTR (entry, att_exported);
- +-
- +- VUNSETATTR (entry, att_invisible); /* Just to be sure */
- +-
- +- if (exported_p (entry))
- +- array_needs_making = 1;
- +-
- +-#if defined (PROGRAMMABLE_COMPLETION)
- +- set_itemlist_dirty (&it_functions);
- +-#endif
- +-
- +- return (entry);
- +-}
- +-
- +-#if defined (DEBUGGER)
- +-/* Bind a function definition, which includes source file and line number
- +- information in addition to the command, into the FUNCTION_DEF hash table.*/
- +-void
- +-bind_function_def (name, value)
- +- const char *name;
- +- FUNCTION_DEF *value;
- +-{
- +- FUNCTION_DEF *entry;
- +- BUCKET_CONTENTS *elt;
- +- COMMAND *cmd;
- +-
- +- entry = find_function_def (name);
- +- if (entry)
- +- {
- +- dispose_function_def_contents (entry);
- +- entry = copy_function_def_contents (value, entry);
- +- }
- +- else
- +- {
- +- cmd = value->command;
- +- value->command = 0;
- +- entry = copy_function_def (value);
- +- value->command = cmd;
- +-
- +- elt = hash_insert (savestring (name), shell_function_defs, HASH_NOSRCH);
- +- elt->data = (PTR_T *)entry;
- +- }
- +-}
- +-#endif /* DEBUGGER */
- +-
- +-/* Add STRING, which is of the form foo=bar, to the temporary environment
- +- HASH_TABLE (temporary_env). The functions in execute_cmd.c are
- +- responsible for moving the main temporary env to one of the other
- +- temporary environments. The expansion code in subst.c calls this. */
- +-int
- +-assign_in_env (word, flags)
- +- WORD_DESC *word;
- +- int flags;
- +-{
- +- int offset, aflags;
- +- char *name, *temp, *value;
- +- SHELL_VAR *var;
- +- const char *string;
- +-
- +- string = word->word;
- +-
- +- aflags = 0;
- +- offset = assignment (string, 0);
- +- name = savestring (string);
- +- value = (char *)NULL;
- +-
- +- if (name[offset] == '=')
- +- {
- +- name[offset] = 0;
- +-
- +- /* don't ignore the `+' when assigning temporary environment */
- +- if (name[offset - 1] == '+')
- +- {
- +- name[offset - 1] = '\0';
- +- aflags |= ASS_APPEND;
- +- }
- +-
- +- var = find_variable (name);
- +- if (var && (readonly_p (var) || noassign_p (var)))
- +- {
- +- if (readonly_p (var))
- +- err_readonly (name);
- +- free (name);
- +- return (0);
- +- }
- +-
- +- temp = name + offset + 1;
- +- value = expand_assignment_string_to_string (temp, 0);
- +-
- +- if (var && (aflags & ASS_APPEND))
- +- {
- +- temp = make_variable_value (var, value, aflags);
- +- FREE (value);
- +- value = temp;
- +- }
- +- }
- +-
- +- if (temporary_env == 0)
- +- temporary_env = hash_create (TEMPENV_HASH_BUCKETS);
- +-
- +- var = hash_lookup (name, temporary_env);
- +- if (var == 0)
- +- var = make_new_variable (name, temporary_env);
- +- else
- +- FREE (value_cell (var));
- +-
- +- if (value == 0)
- +- {
- +- value = (char *)xmalloc (1); /* like do_assignment_internal */
- +- value[0] = '\0';
- +- }
- +-
- +- var_setvalue (var, value);
- +- var->attributes |= (att_exported|att_tempvar);
- +- var->context = variable_context; /* XXX */
- +-
- +- INVALIDATE_EXPORTSTR (var);
- +- var->exportstr = mk_env_string (name, value, 0);
- +-
- +- array_needs_making = 1;
- +-
- +- if (flags)
- +- stupidly_hack_special_variables (name);
- +-
- +- if (echo_command_at_execute)
- +- /* The Korn shell prints the `+ ' in front of assignment statements,
- +- so we do too. */
- +- xtrace_print_assignment (name, value, 0, 1);
- +-
- +- free (name);
- +- return 1;
- +-}
- +-
- +-/* **************************************************************** */
- +-/* */
- +-/* Copying variables */
- +-/* */
- +-/* **************************************************************** */
- +-
- +-#ifdef INCLUDE_UNUSED
- +-/* Copy VAR to a new data structure and return that structure. */
- +-SHELL_VAR *
- +-copy_variable (var)
- +- SHELL_VAR *var;
- +-{
- +- SHELL_VAR *copy = (SHELL_VAR *)NULL;
- +-
- +- if (var)
- +- {
- +- copy = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
- +-
- +- copy->attributes = var->attributes;
- +- copy->name = savestring (var->name);
- +-
- +- if (function_p (var))
- +- var_setfunc (copy, copy_command (function_cell (var)));
- +-#if defined (ARRAY_VARS)
- +- else if (array_p (var))
- +- var_setarray (copy, array_copy (array_cell (var)));
- +- else if (assoc_p (var))
- +- var_setassoc (copy, assoc_copy (assoc_cell (var)));
- +-#endif
- +- else if (nameref_cell (var)) /* XXX - nameref */
- +- var_setref (copy, savestring (nameref_cell (var)));
- +- else if (value_cell (var)) /* XXX - nameref */
- +- var_setvalue (copy, savestring (value_cell (var)));
- +- else
- +- var_setvalue (copy, (char *)NULL);
- +-
- +- copy->dynamic_value = var->dynamic_value;
- +- copy->assign_func = var->assign_func;
- +-
- +- copy->exportstr = COPY_EXPORTSTR (var);
- +-
- +- copy->context = var->context;
- +- }
- +- return (copy);
- +-}
- +-#endif
- +-
- +-/* **************************************************************** */
- +-/* */
- +-/* Deleting and unsetting variables */
- +-/* */
- +-/* **************************************************************** */
- +-
- +-/* Dispose of the information attached to VAR. */
- +-static void
- +-dispose_variable_value (var)
- +- SHELL_VAR *var;
- +-{
- +- if (function_p (var))
- +- dispose_command (function_cell (var));
- +-#if defined (ARRAY_VARS)
- +- else if (array_p (var))
- +- array_dispose (array_cell (var));
- +- else if (assoc_p (var))
- +- assoc_dispose (assoc_cell (var));
- +-#endif
- +- else if (nameref_p (var))
- +- FREE (nameref_cell (var));
- +- else
- +- FREE (value_cell (var));
- +-}
- +-
- +-void
- +-dispose_variable (var)
- +- SHELL_VAR *var;
- +-{
- +- if (var == 0)
- +- return;
- +-
- +- if (nofree_p (var) == 0)
- +- dispose_variable_value (var);
- +-
- +- FREE_EXPORTSTR (var);
- +-
- +- free (var->name);
- +-
- +- if (exported_p (var))
- +- array_needs_making = 1;
- +-
- +- free (var);
- +-}
- +-
- +-/* Unset the shell variable referenced by NAME. Unsetting a nameref variable
- +- unsets the variable it resolves to but leaves the nameref alone. */
- +-int
- +-unbind_variable (name)
- +- const char *name;
- +-{
- +- SHELL_VAR *v, *nv;
- +- int r;
- +-
- +- v = var_lookup (name, shell_variables);
- +- nv = (v && nameref_p (v)) ? find_variable_nameref (v) : (SHELL_VAR *)NULL;
- +-
- +- r = nv ? makunbound (nv->name, shell_variables) : makunbound (name, shell_variables);
- +- return r;
- +-}
- +-
- +-/* Unbind NAME, where NAME is assumed to be a nameref variable */
- +-int
- +-unbind_nameref (name)
- +- const char *name;
- +-{
- +- SHELL_VAR *v;
- +-
- +- v = var_lookup (name, shell_variables);
- +- if (v && nameref_p (v))
- +- return makunbound (name, shell_variables);
- +- return 0;
- +-}
- +-
- +-/* Unset the shell function named NAME. */
- +-int
- +-unbind_func (name)
- +- const char *name;
- +-{
- +- BUCKET_CONTENTS *elt;
- +- SHELL_VAR *func;
- +-
- +- elt = hash_remove (name, shell_functions, 0);
- +-
- +- if (elt == 0)
- +- return -1;
- +-
- +-#if defined (PROGRAMMABLE_COMPLETION)
- +- set_itemlist_dirty (&it_functions);
- +-#endif
- +-
- +- func = (SHELL_VAR *)elt->data;
- +- if (func)
- +- {
- +- if (exported_p (func))
- +- array_needs_making++;
- +- dispose_variable (func);
- +- }
- +-
- +- free (elt->key);
- +- free (elt);
- +-
- +- return 0;
- +-}
- +-
- +-#if defined (DEBUGGER)
- +-int
- +-unbind_function_def (name)
- +- const char *name;
- +-{
- +- BUCKET_CONTENTS *elt;
- +- FUNCTION_DEF *funcdef;
- +-
- +- elt = hash_remove (name, shell_function_defs, 0);
- +-
- +- if (elt == 0)
- +- return -1;
- +-
- +- funcdef = (FUNCTION_DEF *)elt->data;
- +- if (funcdef)
- +- dispose_function_def (funcdef);
- +-
- +- free (elt->key);
- +- free (elt);
- +-
- +- return 0;
- +-}
- +-#endif /* DEBUGGER */
- +-
- +-int
- +-delete_var (name, vc)
- +- const char *name;
- +- VAR_CONTEXT *vc;
- +-{
- +- BUCKET_CONTENTS *elt;
- +- SHELL_VAR *old_var;
- +- VAR_CONTEXT *v;
- +-
- +- for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down)
- +- if (elt = hash_remove (name, v->table, 0))
- +- break;
- +-
- +- if (elt == 0)
- +- return (-1);
- +-
- +- old_var = (SHELL_VAR *)elt->data;
- +- free (elt->key);
- +- free (elt);
- +-
- +- dispose_variable (old_var);
- +- return (0);
- +-}
- +-
- +-/* Make the variable associated with NAME go away. HASH_LIST is the
- +- hash table from which this variable should be deleted (either
- +- shell_variables or shell_functions).
- +- Returns non-zero if the variable couldn't be found. */
- +-int
- +-makunbound (name, vc)
- +- const char *name;
- +- VAR_CONTEXT *vc;
- +-{
- +- BUCKET_CONTENTS *elt, *new_elt;
- +- SHELL_VAR *old_var;
- +- VAR_CONTEXT *v;
- +- char *t;
- +-
- +- for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down)
- +- if (elt = hash_remove (name, v->table, 0))
- +- break;
- +-
- +- if (elt == 0)
- +- return (-1);
- +-
- +- old_var = (SHELL_VAR *)elt->data;
- +-
- +- if (old_var && exported_p (old_var))
- +- array_needs_making++;
- +-
- +- /* If we're unsetting a local variable and we're still executing inside
- +- the function, just mark the variable as invisible. The function
- +- eventually called by pop_var_context() will clean it up later. This
- +- must be done so that if the variable is subsequently assigned a new
- +- value inside the function, the `local' attribute is still present.
- +- We also need to add it back into the correct hash table. */
- +- if (old_var && local_p (old_var) && variable_context == old_var->context)
- +- {
- +- if (nofree_p (old_var))
- +- var_setvalue (old_var, (char *)NULL);
- +-#if defined (ARRAY_VARS)
- +- else if (array_p (old_var))
- +- array_dispose (array_cell (old_var));
- +- else if (assoc_p (old_var))
- +- assoc_dispose (assoc_cell (old_var));
- +-#endif
- +- else if (nameref_p (old_var))
- +- FREE (nameref_cell (old_var));
- +- else
- +- FREE (value_cell (old_var));
- +- /* Reset the attributes. Preserve the export attribute if the variable
- +- came from a temporary environment. Make sure it stays local, and
- +- make it invisible. */
- +- old_var->attributes = (exported_p (old_var) && tempvar_p (old_var)) ? att_exported : 0;
- +- VSETATTR (old_var, att_local);
- +- VSETATTR (old_var, att_invisible);
- +- var_setvalue (old_var, (char *)NULL);
- +- INVALIDATE_EXPORTSTR (old_var);
- +-
- +- new_elt = hash_insert (savestring (old_var->name), v->table, 0);
- +- new_elt->data = (PTR_T)old_var;
- +- stupidly_hack_special_variables (old_var->name);
- +-
- +- free (elt->key);
- +- free (elt);
- +- return (0);
- +- }
- +-
- +- /* Have to save a copy of name here, because it might refer to
- +- old_var->name. If so, stupidly_hack_special_variables will
- +- reference freed memory. */
- +- t = savestring (name);
- +-
- +- free (elt->key);
- +- free (elt);
- +-
- +- dispose_variable (old_var);
- +- stupidly_hack_special_variables (t);
- +- free (t);
- +-
- +- return (0);
- +-}
- +-
- +-/* Get rid of all of the variables in the current context. */
- +-void
- +-kill_all_local_variables ()
- +-{
- +- VAR_CONTEXT *vc;
- +-
- +- for (vc = shell_variables; vc; vc = vc->down)
- +- if (vc_isfuncenv (vc) && vc->scope == variable_context)
- +- break;
- +- if (vc == 0)
- +- return; /* XXX */
- +-
- +- if (vc->table && vc_haslocals (vc))
- +- {
- +- delete_all_variables (vc->table);
- +- hash_dispose (vc->table);
- +- }
- +- vc->table = (HASH_TABLE *)NULL;
- +-}
- +-
- +-static void
- +-free_variable_hash_data (data)
- +- PTR_T data;
- +-{
- +- SHELL_VAR *var;
- +-
- +- var = (SHELL_VAR *)data;
- +- dispose_variable (var);
- +-}
- +-
- +-/* Delete the entire contents of the hash table. */
- +-void
- +-delete_all_variables (hashed_vars)
- +- HASH_TABLE *hashed_vars;
- +-{
- +- hash_flush (hashed_vars, free_variable_hash_data);
- +-}
- +-
- +-/* **************************************************************** */
- +-/* */
- +-/* Setting variable attributes */
- +-/* */
- +-/* **************************************************************** */
- +-
- +-#define FIND_OR_MAKE_VARIABLE(name, entry) \
- +- do \
- +- { \
- +- entry = find_variable (name); \
- +- if (!entry) \
- +- { \
- +- entry = bind_variable (name, "", 0); \
- +- if (!no_invisible_vars && entry) entry->attributes |= att_invisible; \
- +- } \
- +- } \
- +- while (0)
- +-
- +-/* Make the variable associated with NAME be readonly.
- +- If NAME does not exist yet, create it. */
- +-void
- +-set_var_read_only (name)
- +- char *name;
- +-{
- +- SHELL_VAR *entry;
- +-
- +- FIND_OR_MAKE_VARIABLE (name, entry);
- +- VSETATTR (entry, att_readonly);
- +-}
- +-
- +-#ifdef INCLUDE_UNUSED
- +-/* Make the function associated with NAME be readonly.
- +- If NAME does not exist, we just punt, like auto_export code below. */
- +-void
- +-set_func_read_only (name)
- +- const char *name;
- +-{
- +- SHELL_VAR *entry;
- +-
- +- entry = find_function (name);
- +- if (entry)
- +- VSETATTR (entry, att_readonly);
- +-}
- +-
- +-/* Make the variable associated with NAME be auto-exported.
- +- If NAME does not exist yet, create it. */
- +-void
- +-set_var_auto_export (name)
- +- char *name;
- +-{
- +- SHELL_VAR *entry;
- +-
- +- FIND_OR_MAKE_VARIABLE (name, entry);
- +- set_auto_export (entry);
- +-}
- +-
- +-/* Make the function associated with NAME be auto-exported. */
- +-void
- +-set_func_auto_export (name)
- +- const char *name;
- +-{
- +- SHELL_VAR *entry;
- +-
- +- entry = find_function (name);
- +- if (entry)
- +- set_auto_export (entry);
- +-}
- +-#endif
- +-
- +-/* **************************************************************** */
- +-/* */
- +-/* Creating lists of variables */
- +-/* */
- +-/* **************************************************************** */
- +-
- +-static VARLIST *
- +-vlist_alloc (nentries)
- +- int nentries;
- +-{
- +- VARLIST *vlist;
- +-
- +- vlist = (VARLIST *)xmalloc (sizeof (VARLIST));
- +- vlist->list = (SHELL_VAR **)xmalloc ((nentries + 1) * sizeof (SHELL_VAR *));
- +- vlist->list_size = nentries;
- +- vlist->list_len = 0;
- +- vlist->list[0] = (SHELL_VAR *)NULL;
- +-
- +- return vlist;
- +-}
- +-
- +-static VARLIST *
- +-vlist_realloc (vlist, n)
- +- VARLIST *vlist;
- +- int n;
- +-{
- +- if (vlist == 0)
- +- return (vlist = vlist_alloc (n));
- +- if (n > vlist->list_size)
- +- {
- +- vlist->list_size = n;
- +- vlist->list = (SHELL_VAR **)xrealloc (vlist->list, (vlist->list_size + 1) * sizeof (SHELL_VAR *));
- +- }
- +- return vlist;
- +-}
- +-
- +-static void
- +-vlist_add (vlist, var, flags)
- +- VARLIST *vlist;
- +- SHELL_VAR *var;
- +- int flags;
- +-{
- +- register int i;
- +-
- +- for (i = 0; i < vlist->list_len; i++)
- +- if (STREQ (var->name, vlist->list[i]->name))
- +- break;
- +- if (i < vlist->list_len)
- +- return;
- +-
- +- if (i >= vlist->list_size)
- +- vlist = vlist_realloc (vlist, vlist->list_size + 16);
- +-
- +- vlist->list[vlist->list_len++] = var;
- +- vlist->list[vlist->list_len] = (SHELL_VAR *)NULL;
- +-}
- +-
- +-/* Map FUNCTION over the variables in VAR_HASH_TABLE. Return an array of the
- +- variables for which FUNCTION returns a non-zero value. A NULL value
- +- for FUNCTION means to use all variables. */
- +-SHELL_VAR **
- +-map_over (function, vc)
- +- sh_var_map_func_t *function;
- +- VAR_CONTEXT *vc;
- +-{
- +- VAR_CONTEXT *v;
- +- VARLIST *vlist;
- +- SHELL_VAR **ret;
- +- int nentries;
- +-
- +- for (nentries = 0, v = vc; v; v = v->down)
- +- nentries += HASH_ENTRIES (v->table);
- +-
- +- if (nentries == 0)
- +- return (SHELL_VAR **)NULL;
- +-
- +- vlist = vlist_alloc (nentries);
- +-
- +- for (v = vc; v; v = v->down)
- +- flatten (v->table, function, vlist, 0);
- +-
- +- ret = vlist->list;
- +- free (vlist);
- +- return ret;
- +-}
- +-
- +-SHELL_VAR **
- +-map_over_funcs (function)
- +- sh_var_map_func_t *function;
- +-{
- +- VARLIST *vlist;
- +- SHELL_VAR **ret;
- +-
- +- if (shell_functions == 0 || HASH_ENTRIES (shell_functions) == 0)
- +- return ((SHELL_VAR **)NULL);
- +-
- +- vlist = vlist_alloc (HASH_ENTRIES (shell_functions));
- +-
- +- flatten (shell_functions, function, vlist, 0);
- +-
- +- ret = vlist->list;
- +- free (vlist);
- +- return ret;
- +-}
- +-
- +-/* Flatten VAR_HASH_TABLE, applying FUNC to each member and adding those
- +- elements for which FUNC succeeds to VLIST->list. FLAGS is reserved
- +- for future use. Only unique names are added to VLIST. If FUNC is
- +- NULL, each variable in VAR_HASH_TABLE is added to VLIST. If VLIST is
- +- NULL, FUNC is applied to each SHELL_VAR in VAR_HASH_TABLE. If VLIST
- +- and FUNC are both NULL, nothing happens. */
- +-static void
- +-flatten (var_hash_table, func, vlist, flags)
- +- HASH_TABLE *var_hash_table;
- +- sh_var_map_func_t *func;
- +- VARLIST *vlist;
- +- int flags;
- +-{
- +- register int i;
- +- register BUCKET_CONTENTS *tlist;
- +- int r;
- +- SHELL_VAR *var;
- +-
- +- if (var_hash_table == 0 || (HASH_ENTRIES (var_hash_table) == 0) || (vlist == 0 && func == 0))
- +- return;
- +-
- +- for (i = 0; i < var_hash_table->nbuckets; i++)
- +- {
- +- for (tlist = hash_items (i, var_hash_table); tlist; tlist = tlist->next)
- +- {
- +- var = (SHELL_VAR *)tlist->data;
- +-
- +- r = func ? (*func) (var) : 1;
- +- if (r && vlist)
- +- vlist_add (vlist, var, flags);
- +- }
- +- }
- +-}
- +-
- +-void
- +-sort_variables (array)
- +- SHELL_VAR **array;
- +-{
- +- qsort (array, strvec_len ((char **)array), sizeof (SHELL_VAR *), (QSFUNC *)qsort_var_comp);
- +-}
- +-
- +-static int
- +-qsort_var_comp (var1, var2)
- +- SHELL_VAR **var1, **var2;
- +-{
- +- int result;
- +-
- +- if ((result = (*var1)->name[0] - (*var2)->name[0]) == 0)
- +- result = strcmp ((*var1)->name, (*var2)->name);
- +-
- +- return (result);
- +-}
- +-
- +-/* Apply FUNC to each variable in SHELL_VARIABLES, adding each one for
- +- which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */
- +-static SHELL_VAR **
- +-vapply (func)
- +- sh_var_map_func_t *func;
- +-{
- +- SHELL_VAR **list;
- +-
- +- list = map_over (func, shell_variables);
- +- if (list /* && posixly_correct */)
- +- sort_variables (list);
- +- return (list);
- +-}
- +-
- +-/* Apply FUNC to each variable in SHELL_FUNCTIONS, adding each one for
- +- which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */
- +-static SHELL_VAR **
- +-fapply (func)
- +- sh_var_map_func_t *func;
- +-{
- +- SHELL_VAR **list;
- +-
- +- list = map_over_funcs (func);
- +- if (list /* && posixly_correct */)
- +- sort_variables (list);
- +- return (list);
- +-}
- +-
- +-/* Create a NULL terminated array of all the shell variables. */
- +-SHELL_VAR **
- +-all_shell_variables ()
- +-{
- +- return (vapply ((sh_var_map_func_t *)NULL));
- +-}
- +-
- +-/* Create a NULL terminated array of all the shell functions. */
- +-SHELL_VAR **
- +-all_shell_functions ()
- +-{
- +- return (fapply ((sh_var_map_func_t *)NULL));
- +-}
- +-
- +-static int
- +-visible_var (var)
- +- SHELL_VAR *var;
- +-{
- +- return (invisible_p (var) == 0);
- +-}
- +-
- +-SHELL_VAR **
- +-all_visible_functions ()
- +-{
- +- return (fapply (visible_var));
- +-}
- +-
- +-SHELL_VAR **
- +-all_visible_variables ()
- +-{
- +- return (vapply (visible_var));
- +-}
- +-
- +-/* Return non-zero if the variable VAR is visible and exported. Array
- +- variables cannot be exported. */
- +-static int
- +-visible_and_exported (var)
- +- SHELL_VAR *var;
- +-{
- +- return (invisible_p (var) == 0 && exported_p (var));
- +-}
- +-
- +-/* Candidate variables for the export environment are either valid variables
- +- with the export attribute or invalid variables inherited from the initial
- +- environment and simply passed through. */
- +-static int
- +-export_environment_candidate (var)
- +- SHELL_VAR *var;
- +-{
- +- return (exported_p (var) && (invisible_p (var) == 0 || imported_p (var)));
- +-}
- +-
- +-/* Return non-zero if VAR is a local variable in the current context and
- +- is exported. */
- +-static int
- +-local_and_exported (var)
- +- SHELL_VAR *var;
- +-{
- +- return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context && exported_p (var));
- +-}
- +-
- +-SHELL_VAR **
- +-all_exported_variables ()
- +-{
- +- return (vapply (visible_and_exported));
- +-}
- +-
- +-SHELL_VAR **
- +-local_exported_variables ()
- +-{
- +- return (vapply (local_and_exported));
- +-}
- +-
- +-static int
- +-variable_in_context (var)
- +- SHELL_VAR *var;
- +-{
- +- return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context);
- +-}
- +-
- +-SHELL_VAR **
- +-all_local_variables ()
- +-{
- +- VARLIST *vlist;
- +- SHELL_VAR **ret;
- +- VAR_CONTEXT *vc;
- +-
- +- vc = shell_variables;
- +- for (vc = shell_variables; vc; vc = vc->down)
- +- if (vc_isfuncenv (vc) && vc->scope == variable_context)
- +- break;
- +-
- +- if (vc == 0)
- +- {
- +- internal_error (_("all_local_variables: no function context at current scope"));
- +- return (SHELL_VAR **)NULL;
- +- }
- +- if (vc->table == 0 || HASH_ENTRIES (vc->table) == 0 || vc_haslocals (vc) == 0)
- +- return (SHELL_VAR **)NULL;
- +-
- +- vlist = vlist_alloc (HASH_ENTRIES (vc->table));
- +-
- +- flatten (vc->table, variable_in_context, vlist, 0);
- +-
- +- ret = vlist->list;
- +- free (vlist);
- +- if (ret)
- +- sort_variables (ret);
- +- return ret;
- +-}
- +-
- +-#if defined (ARRAY_VARS)
- +-/* Return non-zero if the variable VAR is visible and an array. */
- +-static int
- +-visible_array_vars (var)
- +- SHELL_VAR *var;
- +-{
- +- return (invisible_p (var) == 0 && array_p (var));
- +-}
- +-
- +-SHELL_VAR **
- +-all_array_variables ()
- +-{
- +- return (vapply (visible_array_vars));
- +-}
- +-#endif /* ARRAY_VARS */
- +-
- +-char **
- +-all_variables_matching_prefix (prefix)
- +- const char *prefix;
- +-{
- +- SHELL_VAR **varlist;
- +- char **rlist;
- +- int vind, rind, plen;
- +-
- +- plen = STRLEN (prefix);
- +- varlist = all_visible_variables ();
- +- for (vind = 0; varlist && varlist[vind]; vind++)
- +- ;
- +- if (varlist == 0 || vind == 0)
- +- return ((char **)NULL);
- +- rlist = strvec_create (vind + 1);
- +- for (vind = rind = 0; varlist[vind]; vind++)
- +- {
- +- if (plen == 0 || STREQN (prefix, varlist[vind]->name, plen))
- +- rlist[rind++] = savestring (varlist[vind]->name);
- +- }
- +- rlist[rind] = (char *)0;
- +- free (varlist);
- +-
- +- return rlist;
- +-}
- +-
- +-/* **************************************************************** */
- +-/* */
- +-/* Managing temporary variable scopes */
- +-/* */
- +-/* **************************************************************** */
- +-
- +-/* Make variable NAME have VALUE in the temporary environment. */
- +-static SHELL_VAR *
- +-bind_tempenv_variable (name, value)
- +- const char *name;
- +- char *value;
- +-{
- +- SHELL_VAR *var;
- +-
- +- var = temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL;
- +-
- +- if (var)
- +- {
- +- FREE (value_cell (var));
- +- var_setvalue (var, savestring (value));
- +- INVALIDATE_EXPORTSTR (var);
- +- }
- +-
- +- return (var);
- +-}
- +-
- +-/* Find a variable in the temporary environment that is named NAME.
- +- Return the SHELL_VAR *, or NULL if not found. */
- +-SHELL_VAR *
- +-find_tempenv_variable (name)
- +- const char *name;
- +-{
- +- return (temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL);
- +-}
- +-
- +-char **tempvar_list;
- +-int tvlist_ind;
- +-
- +-/* Push the variable described by (SHELL_VAR *)DATA down to the next
- +- variable context from the temporary environment. */
- +-static void
- +-push_temp_var (data)
- +- PTR_T data;
- +-{
- +- SHELL_VAR *var, *v;
- +- HASH_TABLE *binding_table;
- +-
- +- var = (SHELL_VAR *)data;
- +-
- +- binding_table = shell_variables->table;
- +- if (binding_table == 0)
- +- {
- +- if (shell_variables == global_variables)
- +- /* shouldn't happen */
- +- binding_table = shell_variables->table = global_variables->table = hash_create (0);
- +- else
- +- binding_table = shell_variables->table = hash_create (TEMPENV_HASH_BUCKETS);
- +- }
- +-
- +- v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, 0);
- +-
- +- /* XXX - should we set the context here? It shouldn't matter because of how
- +- assign_in_env works, but might want to check. */
- +- if (binding_table == global_variables->table) /* XXX */
- +- var->attributes &= ~(att_tempvar|att_propagate);
- +- else
- +- {
- +- var->attributes |= att_propagate;
- +- if (binding_table == shell_variables->table)
- +- shell_variables->flags |= VC_HASTMPVAR;
- +- }
- +- v->attributes |= var->attributes;
- +-
- +- if (find_special_var (var->name) >= 0)
- +- tempvar_list[tvlist_ind++] = savestring (var->name);
- +-
- +- dispose_variable (var);
- +-}
- +-
- +-static void
- +-propagate_temp_var (data)
- +- PTR_T data;
- +-{
- +- SHELL_VAR *var;
- +-
- +- var = (SHELL_VAR *)data;
- +- if (tempvar_p (var) && (var->attributes & att_propagate))
- +- push_temp_var (data);
- +- else
- +- {
- +- if (find_special_var (var->name) >= 0)
- +- tempvar_list[tvlist_ind++] = savestring (var->name);
- +- dispose_variable (var);
- +- }
- +-}
- +-
- +-/* Free the storage used in the hash table for temporary
- +- environment variables. PUSHF is a function to be called
- +- to free each hash table entry. It takes care of pushing variables
- +- to previous scopes if appropriate. PUSHF stores names of variables
- +- that require special handling (e.g., IFS) on tempvar_list, so this
- +- function can call stupidly_hack_special_variables on all the
- +- variables in the list when the temporary hash table is destroyed. */
- +-static void
- +-dispose_temporary_env (pushf)
- +- sh_free_func_t *pushf;
- +-{
- +- int i;
- +-
- +- tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1);
- +- tempvar_list[tvlist_ind = 0] = 0;
- +-
- +- hash_flush (temporary_env, pushf);
- +- hash_dispose (temporary_env);
- +- temporary_env = (HASH_TABLE *)NULL;
- +-
- +- tempvar_list[tvlist_ind] = 0;
- +-
- +- array_needs_making = 1;
- +-
- +-#if 0
- +- sv_ifs ("IFS"); /* XXX here for now -- check setifs in assign_in_env */
- +-#endif
- +- for (i = 0; i < tvlist_ind; i++)
- +- stupidly_hack_special_variables (tempvar_list[i]);
- +-
- +- strvec_dispose (tempvar_list);
- +- tempvar_list = 0;
- +- tvlist_ind = 0;
- +-}
- +-
- +-void
- +-dispose_used_env_vars ()
- +-{
- +- if (temporary_env)
- +- {
- +- dispose_temporary_env (propagate_temp_var);
- +- maybe_make_export_env ();
- +- }
- +-}
- +-
- +-/* Take all of the shell variables in the temporary environment HASH_TABLE
- +- and make shell variables from them at the current variable context. */
- +-void
- +-merge_temporary_env ()
- +-{
- +- if (temporary_env)
- +- dispose_temporary_env (push_temp_var);
- +-}
- +-
- +-/* **************************************************************** */
- +-/* */
- +-/* Creating and manipulating the environment */
- +-/* */
- +-/* **************************************************************** */
- +-
- +-static inline char *
- +-mk_env_string (name, value, isfunc)
- +- const char *name, *value;
- +- int isfunc;
- +-{
- +- size_t name_len, value_len;
- +- char *p, *q;
- +-
- +- name_len = strlen (name);
- +- value_len = STRLEN (value);
- +-
- +- /* If we are exporting a shell function, construct the encoded function
- +- name. */
- +- if (isfunc && value)
- +- {
- +- p = (char *)xmalloc (BASHFUNC_PREFLEN + name_len + BASHFUNC_SUFFLEN + value_len + 2);
- +- q = p;
- +- memcpy (q, BASHFUNC_PREFIX, BASHFUNC_PREFLEN);
- +- q += BASHFUNC_PREFLEN;
- +- memcpy (q, name, name_len);
- +- q += name_len;
- +- memcpy (q, BASHFUNC_SUFFIX, BASHFUNC_SUFFLEN);
- +- q += BASHFUNC_SUFFLEN;
- +- }
- +- else
- +- {
- +- p = (char *)xmalloc (2 + name_len + value_len);
- +- memcpy (p, name, name_len);
- +- q = p + name_len;
- +- }
- +-
- +- q[0] = '=';
- +- if (value && *value)
- +- memcpy (q + 1, value, value_len + 1);
- +- else
- +- q[1] = '\0';
- +-
- +- return (p);
- +-}
- +-
- +-#ifdef DEBUG
- +-/* Debugging */
- +-static int
- +-valid_exportstr (v)
- +- SHELL_VAR *v;
- +-{
- +- char *s;
- +-
- +- s = v->exportstr;
- +- if (s == 0)
- +- {
- +- internal_error (_("%s has null exportstr"), v->name);
- +- return (0);
- +- }
- +- if (legal_variable_starter ((unsigned char)*s) == 0)
- +- {
- +- internal_error (_("invalid character %d in exportstr for %s"), *s, v->name);
- +- return (0);
- +- }
- +- for (s = v->exportstr + 1; s && *s; s++)
- +- {
- +- if (*s == '=')
- +- break;
- +- if (legal_variable_char ((unsigned char)*s) == 0)
- +- {
- +- internal_error (_("invalid character %d in exportstr for %s"), *s, v->name);
- +- return (0);
- +- }
- +- }
- +- if (*s != '=')
- +- {
- +- internal_error (_("no `=' in exportstr for %s"), v->name);
- +- return (0);
- +- }
- +- return (1);
- +-}
- +-#endif
- +-
- +-static char **
- +-make_env_array_from_var_list (vars)
- +- SHELL_VAR **vars;
- +-{
- +- register int i, list_index;
- +- register SHELL_VAR *var;
- +- char **list, *value;
- +-
- +- list = strvec_create ((1 + strvec_len ((char **)vars)));
- +-
- +-#define USE_EXPORTSTR (value == var->exportstr)
- +-
- +- for (i = 0, list_index = 0; var = vars[i]; i++)
- +- {
- +-#if defined (__CYGWIN__)
- +- /* We don't use the exportstr stuff on Cygwin at all. */
- +- INVALIDATE_EXPORTSTR (var);
- +-#endif
- +- if (var->exportstr)
- +- value = var->exportstr;
- +- else if (function_p (var))
- +- value = named_function_string ((char *)NULL, function_cell (var), 0);
- +-#if defined (ARRAY_VARS)
- +- else if (array_p (var))
- +-# if ARRAY_EXPORT
- +- value = array_to_assignment_string (array_cell (var));
- +-# else
- +- continue; /* XXX array vars cannot yet be exported */
- +-# endif /* ARRAY_EXPORT */
- +- else if (assoc_p (var))
- +-# if 0
- +- value = assoc_to_assignment_string (assoc_cell (var));
- +-# else
- +- continue; /* XXX associative array vars cannot yet be exported */
- +-# endif
- +-#endif
- +- else
- +- value = value_cell (var);
- +-
- +- if (value)
- +- {
- +- /* Gee, I'd like to get away with not using savestring() if we're
- +- using the cached exportstr... */
- +- list[list_index] = USE_EXPORTSTR ? savestring (value)
- +- : mk_env_string (var->name, value, function_p (var));
- +-
- +- if (USE_EXPORTSTR == 0)
- +- SAVE_EXPORTSTR (var, list[list_index]);
- +-
- +- list_index++;
- +-#undef USE_EXPORTSTR
- +-
- +-#if 0 /* not yet */
- +-#if defined (ARRAY_VARS)
- +- if (array_p (var) || assoc_p (var))
- +- free (value);
- +-#endif
- +-#endif
- +- }
- +- }
- +-
- +- list[list_index] = (char *)NULL;
- +- return (list);
- +-}
- +-
- +-/* Make an array of assignment statements from the hash table
- +- HASHED_VARS which contains SHELL_VARs. Only visible, exported
- +- variables are eligible. */
- +-static char **
- +-make_var_export_array (vcxt)
- +- VAR_CONTEXT *vcxt;
- +-{
- +- char **list;
- +- SHELL_VAR **vars;
- +-
- +-#if 0
- +- vars = map_over (visible_and_exported, vcxt);
- +-#else
- +- vars = map_over (export_environment_candidate, vcxt);
- +-#endif
- +-
- +- if (vars == 0)
- +- return (char **)NULL;
- +-
- +- list = make_env_array_from_var_list (vars);
- +-
- +- free (vars);
- +- return (list);
- +-}
- +-
- +-static char **
- +-make_func_export_array ()
- +-{
- +- char **list;
- +- SHELL_VAR **vars;
- +-
- +- vars = map_over_funcs (visible_and_exported);
- +- if (vars == 0)
- +- return (char **)NULL;
- +-
- +- list = make_env_array_from_var_list (vars);
- +-
- +- free (vars);
- +- return (list);
- +-}
- +-
- +-/* Add ENVSTR to the end of the exported environment, EXPORT_ENV. */
- +-#define add_to_export_env(envstr,do_alloc) \
- +-do \
- +- { \
- +- if (export_env_index >= (export_env_size - 1)) \
- +- { \
- +- export_env_size += 16; \
- +- export_env = strvec_resize (export_env, export_env_size); \
- +- environ = export_env; \
- +- } \
- +- export_env[export_env_index++] = (do_alloc) ? savestring (envstr) : envstr; \
- +- export_env[export_env_index] = (char *)NULL; \
- +- } while (0)
- +-
- +-/* Add ASSIGN to EXPORT_ENV, or supercede a previous assignment in the
- +- array with the same left-hand side. Return the new EXPORT_ENV. */
- +-char **
- +-add_or_supercede_exported_var (assign, do_alloc)
- +- char *assign;
- +- int do_alloc;
- +-{
- +- register int i;
- +- int equal_offset;
- +-
- +- equal_offset = assignment (assign, 0);
- +- if (equal_offset == 0)
- +- return (export_env);
- +-
- +- /* If this is a function, then only supersede the function definition.
- +- We do this by including the `=() {' in the comparison, like
- +- initialize_shell_variables does. */
- +- if (assign[equal_offset + 1] == '(' &&
- +- strncmp (assign + equal_offset + 2, ") {", 3) == 0) /* } */
- +- equal_offset += 4;
- +-
- +- for (i = 0; i < export_env_index; i++)
- +- {
- +- if (STREQN (assign, export_env[i], equal_offset + 1))
- +- {
- +- free (export_env[i]);
- +- export_env[i] = do_alloc ? savestring (assign) : assign;
- +- return (export_env);
- +- }
- +- }
- +- add_to_export_env (assign, do_alloc);
- +- return (export_env);
- +-}
- +-
- +-static void
- +-add_temp_array_to_env (temp_array, do_alloc, do_supercede)
- +- char **temp_array;
- +- int do_alloc, do_supercede;
- +-{
- +- register int i;
- +-
- +- if (temp_array == 0)
- +- return;
- +-
- +- for (i = 0; temp_array[i]; i++)
- +- {
- +- if (do_supercede)
- +- export_env = add_or_supercede_exported_var (temp_array[i], do_alloc);
- +- else
- +- add_to_export_env (temp_array[i], do_alloc);
- +- }
- +-
- +- free (temp_array);
- +-}
- +-
- +-/* Make the environment array for the command about to be executed, if the
- +- array needs making. Otherwise, do nothing. If a shell action could
- +- change the array that commands receive for their environment, then the
- +- code should `array_needs_making++'.
- +-
- +- The order to add to the array is:
- +- temporary_env
- +- list of var contexts whose head is shell_variables
- +- shell_functions
- +-
- +- This is the shell variable lookup order. We add only new variable
- +- names at each step, which allows local variables and variables in
- +- the temporary environments to shadow variables in the global (or
- +- any previous) scope.
- +-*/
- +-
- +-static int
- +-n_shell_variables ()
- +-{
- +- VAR_CONTEXT *vc;
- +- int n;
- +-
- +- for (n = 0, vc = shell_variables; vc; vc = vc->down)
- +- n += HASH_ENTRIES (vc->table);
- +- return n;
- +-}
- +-
- +-int
- +-chkexport (name)
- +- char *name;
- +-{
- +- SHELL_VAR *v;
- +-
- +- v = find_variable (name);
- +- if (v && exported_p (v))
- +- {
- +- array_needs_making = 1;
- +- maybe_make_export_env ();
- +- return 1;
- +- }
- +- return 0;
- +-}
- +-
- +-void
- +-maybe_make_export_env ()
- +-{
- +- register char **temp_array;
- +- int new_size;
- +- VAR_CONTEXT *tcxt;
- +-
- +- if (array_needs_making)
- +- {
- +- if (export_env)
- +- strvec_flush (export_env);
- +-
- +- /* Make a guess based on how many shell variables and functions we
- +- have. Since there will always be array variables, and array
- +- variables are not (yet) exported, this will always be big enough
- +- for the exported variables and functions. */
- +- new_size = n_shell_variables () + HASH_ENTRIES (shell_functions) + 1 +
- +- HASH_ENTRIES (temporary_env);
- +- if (new_size > export_env_size)
- +- {
- +- export_env_size = new_size;
- +- export_env = strvec_resize (export_env, export_env_size);
- +- environ = export_env;
- +- }
- +- export_env[export_env_index = 0] = (char *)NULL;
- +-
- +- /* Make a dummy variable context from the temporary_env, stick it on
- +- the front of shell_variables, call make_var_export_array on the
- +- whole thing to flatten it, and convert the list of SHELL_VAR *s
- +- to the form needed by the environment. */
- +- if (temporary_env)
- +- {
- +- tcxt = new_var_context ((char *)NULL, 0);
- +- tcxt->table = temporary_env;
- +- tcxt->down = shell_variables;
- +- }
- +- else
- +- tcxt = shell_variables;
- +-
- +- temp_array = make_var_export_array (tcxt);
- +- if (temp_array)
- +- add_temp_array_to_env (temp_array, 0, 0);
- +-
- +- if (tcxt != shell_variables)
- +- free (tcxt);
- +-
- +-#if defined (RESTRICTED_SHELL)
- +- /* Restricted shells may not export shell functions. */
- +- temp_array = restricted ? (char **)0 : make_func_export_array ();
- +-#else
- +- temp_array = make_func_export_array ();
- +-#endif
- +- if (temp_array)
- +- add_temp_array_to_env (temp_array, 0, 0);
- +-
- +- array_needs_making = 0;
- +- }
- +-}
- +-
- +-/* This is an efficiency hack. PWD and OLDPWD are auto-exported, so
- +- we will need to remake the exported environment every time we
- +- change directories. `_' is always put into the environment for
- +- every external command, so without special treatment it will always
- +- cause the environment to be remade.
- +-
- +- If there is no other reason to make the exported environment, we can
- +- just update the variables in place and mark the exported environment
- +- as no longer needing a remake. */
- +-void
- +-update_export_env_inplace (env_prefix, preflen, value)
- +- char *env_prefix;
- +- int preflen;
- +- char *value;
- +-{
- +- char *evar;
- +-
- +- evar = (char *)xmalloc (STRLEN (value) + preflen + 1);
- +- strcpy (evar, env_prefix);
- +- if (value)
- +- strcpy (evar + preflen, value);
- +- export_env = add_or_supercede_exported_var (evar, 0);
- +-}
- +-
- +-/* We always put _ in the environment as the name of this command. */
- +-void
- +-put_command_name_into_env (command_name)
- +- char *command_name;
- +-{
- +- update_export_env_inplace ("_=", 2, command_name);
- +-}
- +-
- +-/* **************************************************************** */
- +-/* */
- +-/* Managing variable contexts */
- +-/* */
- +-/* **************************************************************** */
- +-
- +-/* Allocate and return a new variable context with NAME and FLAGS.
- +- NAME can be NULL. */
- +-
- +-VAR_CONTEXT *
- +-new_var_context (name, flags)
- +- char *name;
- +- int flags;
- +-{
- +- VAR_CONTEXT *vc;
- +-
- +- vc = (VAR_CONTEXT *)xmalloc (sizeof (VAR_CONTEXT));
- +- vc->name = name ? savestring (name) : (char *)NULL;
- +- vc->scope = variable_context;
- +- vc->flags = flags;
- +-
- +- vc->up = vc->down = (VAR_CONTEXT *)NULL;
- +- vc->table = (HASH_TABLE *)NULL;
- +-
- +- return vc;
- +-}
- +-
- +-/* Free a variable context and its data, including the hash table. Dispose
- +- all of the variables. */
- +-void
- +-dispose_var_context (vc)
- +- VAR_CONTEXT *vc;
- +-{
- +- FREE (vc->name);
- +-
- +- if (vc->table)
- +- {
- +- delete_all_variables (vc->table);
- +- hash_dispose (vc->table);
- +- }
- +-
- +- free (vc);
- +-}
- +-
- +-/* Set VAR's scope level to the current variable context. */
- +-static int
- +-set_context (var)
- +- SHELL_VAR *var;
- +-{
- +- return (var->context = variable_context);
- +-}
- +-
- +-/* Make a new variable context with NAME and FLAGS and a HASH_TABLE of
- +- temporary variables, and push it onto shell_variables. This is
- +- for shell functions. */
- +-VAR_CONTEXT *
- +-push_var_context (name, flags, tempvars)
- +- char *name;
- +- int flags;
- +- HASH_TABLE *tempvars;
- +-{
- +- VAR_CONTEXT *vc;
- +-
- +- vc = new_var_context (name, flags);
- +- vc->table = tempvars;
- +- if (tempvars)
- +- {
- +- /* Have to do this because the temp environment was created before
- +- variable_context was incremented. */
- +- flatten (tempvars, set_context, (VARLIST *)NULL, 0);
- +- vc->flags |= VC_HASTMPVAR;
- +- }
- +- vc->down = shell_variables;
- +- shell_variables->up = vc;
- +-
- +- return (shell_variables = vc);
- +-}
- +-
- +-static void
- +-push_func_var (data)
- +- PTR_T data;
- +-{
- +- SHELL_VAR *var, *v;
- +-
- +- var = (SHELL_VAR *)data;
- +-
- +- if (tempvar_p (var) && (posixly_correct || (var->attributes & att_propagate)))
- +- {
- +- /* Make sure we have a hash table to store the variable in while it is
- +- being propagated down to the global variables table. Create one if
- +- we have to */
- +- if ((vc_isfuncenv (shell_variables) || vc_istempenv (shell_variables)) && shell_variables->table == 0)
- +- shell_variables->table = hash_create (0);
- +- /* XXX - should we set v->context here? */
- +- v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);
- +- if (shell_variables == global_variables)
- +- var->attributes &= ~(att_tempvar|att_propagate);
- +- else
- +- shell_variables->flags |= VC_HASTMPVAR;
- +- v->attributes |= var->attributes;
- +- }
- +- else
- +- stupidly_hack_special_variables (var->name); /* XXX */
- +-
- +- dispose_variable (var);
- +-}
- +-
- +-/* Pop the top context off of VCXT and dispose of it, returning the rest of
- +- the stack. */
- +-void
- +-pop_var_context ()
- +-{
- +- VAR_CONTEXT *ret, *vcxt;
- +-
- +- vcxt = shell_variables;
- +- if (vc_isfuncenv (vcxt) == 0)
- +- {
- +- internal_error (_("pop_var_context: head of shell_variables not a function context"));
- +- return;
- +- }
- +-
- +- if (ret = vcxt->down)
- +- {
- +- ret->up = (VAR_CONTEXT *)NULL;
- +- shell_variables = ret;
- +- if (vcxt->table)
- +- hash_flush (vcxt->table, push_func_var);
- +- dispose_var_context (vcxt);
- +- }
- +- else
- +- internal_error (_("pop_var_context: no global_variables context"));
- +-}
- +-
- +-/* Delete the HASH_TABLEs for all variable contexts beginning at VCXT, and
- +- all of the VAR_CONTEXTs except GLOBAL_VARIABLES. */
- +-void
- +-delete_all_contexts (vcxt)
- +- VAR_CONTEXT *vcxt;
- +-{
- +- VAR_CONTEXT *v, *t;
- +-
- +- for (v = vcxt; v != global_variables; v = t)
- +- {
- +- t = v->down;
- +- dispose_var_context (v);
- +- }
- +-
- +- delete_all_variables (global_variables->table);
- +- shell_variables = global_variables;
- +-}
- +-
- +-/* **************************************************************** */
- +-/* */
- +-/* Pushing and Popping temporary variable scopes */
- +-/* */
- +-/* **************************************************************** */
- +-
- +-VAR_CONTEXT *
- +-push_scope (flags, tmpvars)
- +- int flags;
- +- HASH_TABLE *tmpvars;
- +-{
- +- return (push_var_context ((char *)NULL, flags, tmpvars));
- +-}
- +-
- +-static void
- +-push_exported_var (data)
- +- PTR_T data;
- +-{
- +- SHELL_VAR *var, *v;
- +-
- +- var = (SHELL_VAR *)data;
- +-
- +- /* If a temp var had its export attribute set, or it's marked to be
- +- propagated, bind it in the previous scope before disposing it. */
- +- /* XXX - This isn't exactly right, because all tempenv variables have the
- +- export attribute set. */
- +-#if 0
- +- if (exported_p (var) || (var->attributes & att_propagate))
- +-#else
- +- if (tempvar_p (var) && exported_p (var) && (var->attributes & att_propagate))
- +-#endif
- +- {
- +- var->attributes &= ~att_tempvar; /* XXX */
- +- v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);
- +- if (shell_variables == global_variables)
- +- var->attributes &= ~att_propagate;
- +- v->attributes |= var->attributes;
- +- }
- +- else
- +- stupidly_hack_special_variables (var->name); /* XXX */
- +-
- +- dispose_variable (var);
- +-}
- +-
- +-void
- +-pop_scope (is_special)
- +- int is_special;
- +-{
- +- VAR_CONTEXT *vcxt, *ret;
- +-
- +- vcxt = shell_variables;
- +- if (vc_istempscope (vcxt) == 0)
- +- {
- +- internal_error (_("pop_scope: head of shell_variables not a temporary environment scope"));
- +- return;
- +- }
- +-
- +- ret = vcxt->down;
- +- if (ret)
- +- ret->up = (VAR_CONTEXT *)NULL;
- +-
- +- shell_variables = ret;
- +-
- +- /* Now we can take care of merging variables in VCXT into set of scopes
- +- whose head is RET (shell_variables). */
- +- FREE (vcxt->name);
- +- if (vcxt->table)
- +- {
- +- if (is_special)
- +- hash_flush (vcxt->table, push_func_var);
- +- else
- +- hash_flush (vcxt->table, push_exported_var);
- +- hash_dispose (vcxt->table);
- +- }
- +- free (vcxt);
- +-
- +- sv_ifs ("IFS"); /* XXX here for now */
- +-}
- +-
- +-/* **************************************************************** */
- +-/* */
- +-/* Pushing and Popping function contexts */
- +-/* */
- +-/* **************************************************************** */
- +-
- +-static WORD_LIST **dollar_arg_stack = (WORD_LIST **)NULL;
- +-static int dollar_arg_stack_slots;
- +-static int dollar_arg_stack_index;
- +-
- +-/* XXX - we might want to consider pushing and popping the `getopts' state
- +- when we modify the positional parameters. */
- +-void
- +-push_context (name, is_subshell, tempvars)
- +- char *name; /* function name */
- +- int is_subshell;
- +- HASH_TABLE *tempvars;
- +-{
- +- if (is_subshell == 0)
- +- push_dollar_vars ();
- +- variable_context++;
- +- push_var_context (name, VC_FUNCENV, tempvars);
- +-}
- +-
- +-/* Only called when subshell == 0, so we don't need to check, and can
- +- unconditionally pop the dollar vars off the stack. */
- +-void
- +-pop_context ()
- +-{
- +- pop_dollar_vars ();
- +- variable_context--;
- +- pop_var_context ();
- +-
- +- sv_ifs ("IFS"); /* XXX here for now */
- +-}
- +-
- +-/* Save the existing positional parameters on a stack. */
- +-void
- +-push_dollar_vars ()
- +-{
- +- if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots)
- +- {
- +- dollar_arg_stack = (WORD_LIST **)
- +- xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10)
- +- * sizeof (WORD_LIST *));
- +- }
- +- dollar_arg_stack[dollar_arg_stack_index++] = list_rest_of_args ();
- +- dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
- +-}
- +-
- +-/* Restore the positional parameters from our stack. */
- +-void
- +-pop_dollar_vars ()
- +-{
- +- if (!dollar_arg_stack || dollar_arg_stack_index == 0)
- +- return;
- +-
- +- remember_args (dollar_arg_stack[--dollar_arg_stack_index], 1);
- +- dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
- +- dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
- +- set_dollar_vars_unchanged ();
- +-}
- +-
- +-void
- +-dispose_saved_dollar_vars ()
- +-{
- +- if (!dollar_arg_stack || dollar_arg_stack_index == 0)
- +- return;
- +-
- +- dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
- +- dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
- +-}
- +-
- +-/* Manipulate the special BASH_ARGV and BASH_ARGC variables. */
- +-
- +-void
- +-push_args (list)
- +- WORD_LIST *list;
- +-{
- +-#if defined (ARRAY_VARS) && defined (DEBUGGER)
- +- SHELL_VAR *bash_argv_v, *bash_argc_v;
- +- ARRAY *bash_argv_a, *bash_argc_a;
- +- WORD_LIST *l;
- +- arrayind_t i;
- +- char *t;
- +-
- +- GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
- +- GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
- +-
- +- for (l = list, i = 0; l; l = l->next, i++)
- +- array_push (bash_argv_a, l->word->word);
- +-
- +- t = itos (i);
- +- array_push (bash_argc_a, t);
- +- free (t);
- +-#endif /* ARRAY_VARS && DEBUGGER */
- +-}
- +-
- +-/* Remove arguments from BASH_ARGV array. Pop top element off BASH_ARGC
- +- array and use that value as the count of elements to remove from
- +- BASH_ARGV. */
- +-void
- +-pop_args ()
- +-{
- +-#if defined (ARRAY_VARS) && defined (DEBUGGER)
- +- SHELL_VAR *bash_argv_v, *bash_argc_v;
- +- ARRAY *bash_argv_a, *bash_argc_a;
- +- ARRAY_ELEMENT *ce;
- +- intmax_t i;
- +-
- +- GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
- +- GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
- +-
- +- ce = array_shift (bash_argc_a, 1, 0);
- +- if (ce == 0 || legal_number (element_value (ce), &i) == 0)
- +- i = 0;
- +-
- +- for ( ; i > 0; i--)
- +- array_pop (bash_argv_a);
- +- array_dispose_element (ce);
- +-#endif /* ARRAY_VARS && DEBUGGER */
- +-}
- +-
- +-/*************************************************
- +- * *
- +- * Functions to manage special variables *
- +- * *
- +- *************************************************/
- +-
- +-/* Extern declarations for variables this code has to manage. */
- +-extern int eof_encountered, eof_encountered_limit, ignoreeof;
- +-
- +-#if defined (READLINE)
- +-extern int hostname_list_initialized;
- +-#endif
- +-
- +-/* An alist of name.function for each special variable. Most of the
- +- functions don't do much, and in fact, this would be faster with a
- +- switch statement, but by the end of this file, I am sick of switch
- +- statements. */
- +-
- +-#define SET_INT_VAR(name, intvar) intvar = find_variable (name) != 0
- +-
- +-/* This table will be sorted with qsort() the first time it's accessed. */
- +-struct name_and_function {
- +- char *name;
- +- sh_sv_func_t *function;
- +-};
- +-
- +-static struct name_and_function special_vars[] = {
- +- { "BASH_COMPAT", sv_shcompat },
- +- { "BASH_XTRACEFD", sv_xtracefd },
- +-
- +-#if defined (JOB_CONTROL)
- +- { "CHILD_MAX", sv_childmax },
- +-#endif
- +-
- +-#if defined (READLINE)
- +-# if defined (STRICT_POSIX)
- +- { "COLUMNS", sv_winsize },
- +-# endif
- +- { "COMP_WORDBREAKS", sv_comp_wordbreaks },
- +-#endif
- +-
- +- { "FUNCNEST", sv_funcnest },
- +-
- +- { "GLOBIGNORE", sv_globignore },
- +-
- +-#if defined (HISTORY)
- +- { "HISTCONTROL", sv_history_control },
- +- { "HISTFILESIZE", sv_histsize },
- +- { "HISTIGNORE", sv_histignore },
- +- { "HISTSIZE", sv_histsize },
- +- { "HISTTIMEFORMAT", sv_histtimefmt },
- +-#endif
- +-
- +-#if defined (__CYGWIN__)
- +- { "HOME", sv_home },
- +-#endif
- +-
- +-#if defined (READLINE)
- +- { "HOSTFILE", sv_hostfile },
- +-#endif
- +-
- +- { "IFS", sv_ifs },
- +- { "IGNOREEOF", sv_ignoreeof },
- +-
- +- { "LANG", sv_locale },
- +- { "LC_ALL", sv_locale },
- +- { "LC_COLLATE", sv_locale },
- +- { "LC_CTYPE", sv_locale },
- +- { "LC_MESSAGES", sv_locale },
- +- { "LC_NUMERIC", sv_locale },
- +- { "LC_TIME", sv_locale },
- +-
- +-#if defined (READLINE) && defined (STRICT_POSIX)
- +- { "LINES", sv_winsize },
- +-#endif
- +-
- +- { "MAIL", sv_mail },
- +- { "MAILCHECK", sv_mail },
- +- { "MAILPATH", sv_mail },
- +-
- +- { "OPTERR", sv_opterr },
- +- { "OPTIND", sv_optind },
- +-
- +- { "PATH", sv_path },
- +- { "POSIXLY_CORRECT", sv_strict_posix },
- +-
- +-#if defined (READLINE)
- +- { "TERM", sv_terminal },
- +- { "TERMCAP", sv_terminal },
- +- { "TERMINFO", sv_terminal },
- +-#endif /* READLINE */
- +-
- +- { "TEXTDOMAIN", sv_locale },
- +- { "TEXTDOMAINDIR", sv_locale },
- +-
- +-#if defined (HAVE_TZSET)
- +- { "TZ", sv_tz },
- +-#endif
- +-
- +-#if defined (HISTORY) && defined (BANG_HISTORY)
- +- { "histchars", sv_histchars },
- +-#endif /* HISTORY && BANG_HISTORY */
- +-
- +- { "ignoreeof", sv_ignoreeof },
- +-
- +- { (char *)0, (sh_sv_func_t *)0 }
- +-};
- +-
- +-#define N_SPECIAL_VARS (sizeof (special_vars) / sizeof (special_vars[0]) - 1)
- +-
- +-static int
- +-sv_compare (sv1, sv2)
- +- struct name_and_function *sv1, *sv2;
- +-{
- +- int r;
- +-
- +- if ((r = sv1->name[0] - sv2->name[0]) == 0)
- +- r = strcmp (sv1->name, sv2->name);
- +- return r;
- +-}
- +-
- +-static inline int
- +-find_special_var (name)
- +- const char *name;
- +-{
- +- register int i, r;
- +-
- +- for (i = 0; special_vars[i].name; i++)
- +- {
- +- r = special_vars[i].name[0] - name[0];
- +- if (r == 0)
- +- r = strcmp (special_vars[i].name, name);
- +- if (r == 0)
- +- return i;
- +- else if (r > 0)
- +- /* Can't match any of rest of elements in sorted list. Take this out
- +- if it causes problems in certain environments. */
- +- break;
- +- }
- +- return -1;
- +-}
- +-
- +-/* The variable in NAME has just had its state changed. Check to see if it
- +- is one of the special ones where something special happens. */
- +-void
- +-stupidly_hack_special_variables (name)
- +- char *name;
- +-{
- +- static int sv_sorted = 0;
- +- int i;
- +-
- +- if (sv_sorted == 0) /* shouldn't need, but it's fairly cheap. */
- +- {
- +- qsort (special_vars, N_SPECIAL_VARS, sizeof (special_vars[0]),
- +- (QSFUNC *)sv_compare);
- +- sv_sorted = 1;
- +- }
- +-
- +- i = find_special_var (name);
- +- if (i != -1)
- +- (*(special_vars[i].function)) (name);
- +-}
- +-
- +-/* Special variables that need hooks to be run when they are unset as part
- +- of shell reinitialization should have their sv_ functions run here. */
- +-void
- +-reinit_special_variables ()
- +-{
- +-#if defined (READLINE)
- +- sv_comp_wordbreaks ("COMP_WORDBREAKS");
- +-#endif
- +- sv_globignore ("GLOBIGNORE");
- +- sv_opterr ("OPTERR");
- +-}
- +-
- +-void
- +-sv_ifs (name)
- +- char *name;
- +-{
- +- SHELL_VAR *v;
- +-
- +- v = find_variable ("IFS");
- +- setifs (v);
- +-}
- +-
- +-/* What to do just after the PATH variable has changed. */
- +-void
- +-sv_path (name)
- +- char *name;
- +-{
- +- /* hash -r */
- +- phash_flush ();
- +-}
- +-
- +-/* What to do just after one of the MAILxxxx variables has changed. NAME
- +- is the name of the variable. This is called with NAME set to one of
- +- MAIL, MAILCHECK, or MAILPATH. */
- +-void
- +-sv_mail (name)
- +- char *name;
- +-{
- +- /* If the time interval for checking the files has changed, then
- +- reset the mail timer. Otherwise, one of the pathname vars
- +- to the users mailbox has changed, so rebuild the array of
- +- filenames. */
- +- if (name[4] == 'C') /* if (strcmp (name, "MAILCHECK") == 0) */
- +- reset_mail_timer ();
- +- else
- +- {
- +- free_mail_files ();
- +- remember_mail_dates ();
- +- }
- +-}
- +-
- +-void
- +-sv_funcnest (name)
- +- char *name;
- +-{
- +- SHELL_VAR *v;
- +- intmax_t num;
- +-
- +- v = find_variable (name);
- +- if (v == 0)
- +- funcnest_max = 0;
- +- else if (legal_number (value_cell (v), &num) == 0)
- +- funcnest_max = 0;
- +- else
- +- funcnest_max = num;
- +-}
- +-
- +-/* What to do when GLOBIGNORE changes. */
- +-void
- +-sv_globignore (name)
- +- char *name;
- +-{
- +- if (privileged_mode == 0)
- +- setup_glob_ignore (name);
- +-}
- +-
- +-#if defined (READLINE)
- +-void
- +-sv_comp_wordbreaks (name)
- +- char *name;
- +-{
- +- SHELL_VAR *sv;
- +-
- +- sv = find_variable (name);
- +- if (sv == 0)
- +- reset_completer_word_break_chars ();
- +-}
- +-
- +-/* What to do just after one of the TERMxxx variables has changed.
- +- If we are an interactive shell, then try to reset the terminal
- +- information in readline. */
- +-void
- +-sv_terminal (name)
- +- char *name;
- +-{
- +- if (interactive_shell && no_line_editing == 0)
- +- rl_reset_terminal (get_string_value ("TERM"));
- +-}
- +-
- +-void
- +-sv_hostfile (name)
- +- char *name;
- +-{
- +- SHELL_VAR *v;
- +-
- +- v = find_variable (name);
- +- if (v == 0)
- +- clear_hostname_list ();
- +- else
- +- hostname_list_initialized = 0;
- +-}
- +-
- +-#if defined (STRICT_POSIX)
- +-/* In strict posix mode, we allow assignments to LINES and COLUMNS (and values
- +- found in the initial environment) to override the terminal size reported by
- +- the kernel. */
- +-void
- +-sv_winsize (name)
- +- char *name;
- +-{
- +- SHELL_VAR *v;
- +- intmax_t xd;
- +- int d;
- +-
- +- if (posixly_correct == 0 || interactive_shell == 0 || no_line_editing)
- +- return;
- +-
- +- v = find_variable (name);
- +- if (v == 0 || var_isnull (v))
- +- rl_reset_screen_size ();
- +- else
- +- {
- +- if (legal_number (value_cell (v), &xd) == 0)
- +- return;
- +- winsize_assignment = 1;
- +- d = xd; /* truncate */
- +- if (name[0] == 'L') /* LINES */
- +- rl_set_screen_size (d, -1);
- +- else /* COLUMNS */
- +- rl_set_screen_size (-1, d);
- +- winsize_assignment = 0;
- +- }
- +-}
- +-#endif /* STRICT_POSIX */
- +-#endif /* READLINE */
- +-
- +-/* Update the value of HOME in the export environment so tilde expansion will
- +- work on cygwin. */
- +-#if defined (__CYGWIN__)
- +-sv_home (name)
- +- char *name;
- +-{
- +- array_needs_making = 1;
- +- maybe_make_export_env ();
- +-}
- +-#endif
- +-
- +-#if defined (HISTORY)
- +-/* What to do after the HISTSIZE or HISTFILESIZE variables change.
- +- If there is a value for this HISTSIZE (and it is numeric), then stifle
- +- the history. Otherwise, if there is NO value for this variable,
- +- unstifle the history. If name is HISTFILESIZE, and its value is
- +- numeric, truncate the history file to hold no more than that many
- +- lines. */
- +-void
- +-sv_histsize (name)
- +- char *name;
- +-{
- +- char *temp;
- +- intmax_t num;
- +- int hmax;
- +-
- +- temp = get_string_value (name);
- +-
- +- if (temp && *temp)
- +- {
- +- if (legal_number (temp, &num))
- +- {
- +- hmax = num;
- +- if (hmax < 0 && name[4] == 'S')
- +- unstifle_history (); /* unstifle history if HISTSIZE < 0 */
- +- else if (name[4] == 'S')
- +- {
- +- stifle_history (hmax);
- +- hmax = where_history ();
- +- if (history_lines_this_session > hmax)
- +- history_lines_this_session = hmax;
- +- }
- +- else if (hmax >= 0) /* truncate HISTFILE if HISTFILESIZE >= 0 */
- +- {
- +- history_truncate_file (get_string_value ("HISTFILE"), hmax);
- +- if (hmax <= history_lines_in_file)
- +- history_lines_in_file = hmax;
- +- }
- +- }
- +- }
- +- else if (name[4] == 'S')
- +- unstifle_history ();
- +-}
- +-
- +-/* What to do after the HISTIGNORE variable changes. */
- +-void
- +-sv_histignore (name)
- +- char *name;
- +-{
- +- setup_history_ignore (name);
- +-}
- +-
- +-/* What to do after the HISTCONTROL variable changes. */
- +-void
- +-sv_history_control (name)
- +- char *name;
- +-{
- +- char *temp;
- +- char *val;
- +- int tptr;
- +-
- +- history_control = 0;
- +- temp = get_string_value (name);
- +-
- +- if (temp == 0 || *temp == 0)
- +- return;
- +-
- +- tptr = 0;
- +- while (val = extract_colon_unit (temp, &tptr))
- +- {
- +- if (STREQ (val, "ignorespace"))
- +- history_control |= HC_IGNSPACE;
- +- else if (STREQ (val, "ignoredups"))
- +- history_control |= HC_IGNDUPS;
- +- else if (STREQ (val, "ignoreboth"))
- +- history_control |= HC_IGNBOTH;
- +- else if (STREQ (val, "erasedups"))
- +- history_control |= HC_ERASEDUPS;
- +-
- +- free (val);
- +- }
- +-}
- +-
- +-#if defined (BANG_HISTORY)
- +-/* Setting/unsetting of the history expansion character. */
- +-void
- +-sv_histchars (name)
- +- char *name;
- +-{
- +- char *temp;
- +-
- +- temp = get_string_value (name);
- +- if (temp)
- +- {
- +- history_expansion_char = *temp;
- +- if (temp[0] && temp[1])
- +- {
- +- history_subst_char = temp[1];
- +- if (temp[2])
- +- history_comment_char = temp[2];
- +- }
- +- }
- +- else
- +- {
- +- history_expansion_char = '!';
- +- history_subst_char = '^';
- +- history_comment_char = '#';
- +- }
- +-}
- +-#endif /* BANG_HISTORY */
- +-
- +-void
- +-sv_histtimefmt (name)
- +- char *name;
- +-{
- +- SHELL_VAR *v;
- +-
- +- if (v = find_variable (name))
- +- {
- +- if (history_comment_char == 0)
- +- history_comment_char = '#';
- +- }
- +- history_write_timestamps = (v != 0);
- +-}
- +-#endif /* HISTORY */
- +-
- +-#if defined (HAVE_TZSET)
- +-void
- +-sv_tz (name)
- +- char *name;
- +-{
- +- if (chkexport (name))
- +- tzset ();
- +-}
- +-#endif
- +-
- +-/* If the variable exists, then the value of it can be the number
- +- of times we actually ignore the EOF. The default is small,
- +- (smaller than csh, anyway). */
- +-void
- +-sv_ignoreeof (name)
- +- char *name;
- +-{
- +- SHELL_VAR *tmp_var;
- +- char *temp;
- +-
- +- eof_encountered = 0;
- +-
- +- tmp_var = find_variable (name);
- +- ignoreeof = tmp_var != 0;
- +- temp = tmp_var ? value_cell (tmp_var) : (char *)NULL;
- +- if (temp)
- +- eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10;
- +- set_shellopts (); /* make sure `ignoreeof' is/is not in $SHELLOPTS */
- +-}
- +-
- +-void
- +-sv_optind (name)
- +- char *name;
- +-{
- +- char *tt;
- +- int s;
- +-
- +- tt = get_string_value ("OPTIND");
- +- if (tt && *tt)
- +- {
- +- s = atoi (tt);
- +-
- +- /* According to POSIX, setting OPTIND=1 resets the internal state
- +- of getopt (). */
- +- if (s < 0 || s == 1)
- +- s = 0;
- +- }
- +- else
- +- s = 0;
- +- getopts_reset (s);
- +-}
- +-
- +-void
- +-sv_opterr (name)
- +- char *name;
- +-{
- +- char *tt;
- +-
- +- tt = get_string_value ("OPTERR");
- +- sh_opterr = (tt && *tt) ? atoi (tt) : 1;
- +-}
- +-
- +-void
- +-sv_strict_posix (name)
- +- char *name;
- +-{
- +- SET_INT_VAR (name, posixly_correct);
- +- posix_initialize (posixly_correct);
- +-#if defined (READLINE)
- +- if (interactive_shell)
- +- posix_readline_initialize (posixly_correct);
- +-#endif /* READLINE */
- +- set_shellopts (); /* make sure `posix' is/is not in $SHELLOPTS */
- +-}
- +-
- +-void
- +-sv_locale (name)
- +- char *name;
- +-{
- +- char *v;
- +- int r;
- +-
- +- v = get_string_value (name);
- +- if (name[0] == 'L' && name[1] == 'A') /* LANG */
- +- r = set_lang (name, v);
- +- else
- +- r = set_locale_var (name, v); /* LC_*, TEXTDOMAIN* */
- +-
- +-#if 1
- +- if (r == 0 && posixly_correct)
- +- last_command_exit_value = 1;
- +-#endif
- +-}
- +-
- +-#if defined (ARRAY_VARS)
- +-void
- +-set_pipestatus_array (ps, nproc)
- +- int *ps;
- +- int nproc;
- +-{
- +- SHELL_VAR *v;
- +- ARRAY *a;
- +- ARRAY_ELEMENT *ae;
- +- register int i;
- +- char *t, tbuf[INT_STRLEN_BOUND(int) + 1];
- +-
- +- v = find_variable ("PIPESTATUS");
- +- if (v == 0)
- +- v = make_new_array_variable ("PIPESTATUS");
- +- if (array_p (v) == 0)
- +- return; /* Do nothing if not an array variable. */
- +- a = array_cell (v);
- +-
- +- if (a == 0 || array_num_elements (a) == 0)
- +- {
- +- for (i = 0; i < nproc; i++) /* was ps[i] != -1, not i < nproc */
- +- {
- +- t = inttostr (ps[i], tbuf, sizeof (tbuf));
- +- array_insert (a, i, t);
- +- }
- +- return;
- +- }
- +-
- +- /* Fast case */
- +- if (array_num_elements (a) == nproc && nproc == 1)
- +- {
- +- ae = element_forw (a->head);
- +- free (element_value (ae));
- +- ae->value = itos (ps[0]);
- +- }
- +- else if (array_num_elements (a) <= nproc)
- +- {
- +- /* modify in array_num_elements members in place, then add */
- +- ae = a->head;
- +- for (i = 0; i < array_num_elements (a); i++)
- +- {
- +- ae = element_forw (ae);
- +- free (element_value (ae));
- +- ae->value = itos (ps[i]);
- +- }
- +- /* add any more */
- +- for ( ; i < nproc; i++)
- +- {
- +- t = inttostr (ps[i], tbuf, sizeof (tbuf));
- +- array_insert (a, i, t);
- +- }
- +- }
- +- else
- +- {
- +- /* deleting elements. it's faster to rebuild the array. */
- +- array_flush (a);
- +- for (i = 0; ps[i] != -1; i++)
- +- {
- +- t = inttostr (ps[i], tbuf, sizeof (tbuf));
- +- array_insert (a, i, t);
- +- }
- +- }
- +-}
- +-
- +-ARRAY *
- +-save_pipestatus_array ()
- +-{
- +- SHELL_VAR *v;
- +- ARRAY *a, *a2;
- +-
- +- v = find_variable ("PIPESTATUS");
- +- if (v == 0 || array_p (v) == 0 || array_cell (v) == 0)
- +- return ((ARRAY *)NULL);
- +-
- +- a = array_cell (v);
- +- a2 = array_copy (array_cell (v));
- +-
- +- return a2;
- +-}
- +-
- +-void
- +-restore_pipestatus_array (a)
- +- ARRAY *a;
- +-{
- +- SHELL_VAR *v;
- +- ARRAY *a2;
- +-
- +- v = find_variable ("PIPESTATUS");
- +- /* XXX - should we still assign even if existing value is NULL? */
- +- if (v == 0 || array_p (v) == 0 || array_cell (v) == 0)
- +- return;
- +-
- +- a2 = array_cell (v);
- +- var_setarray (v, a);
- +-
- +- array_dispose (a2);
- +-}
- +-#endif
- +-
- +-void
- +-set_pipestatus_from_exit (s)
- +- int s;
- +-{
- +-#if defined (ARRAY_VARS)
- +- static int v[2] = { 0, -1 };
- +-
- +- v[0] = s;
- +- set_pipestatus_array (v, 1);
- +-#endif
- +-}
- +-
- +-void
- +-sv_xtracefd (name)
- +- char *name;
- +-{
- +- SHELL_VAR *v;
- +- char *t, *e;
- +- int fd;
- +- FILE *fp;
- +-
- +- v = find_variable (name);
- +- if (v == 0)
- +- {
- +- xtrace_reset ();
- +- return;
- +- }
- +-
- +- t = value_cell (v);
- +- if (t == 0 || *t == 0)
- +- xtrace_reset ();
- +- else
- +- {
- +- fd = (int)strtol (t, &e, 10);
- +- if (e != t && *e == '\0' && sh_validfd (fd))
- +- {
- +- fp = fdopen (fd, "w");
- +- if (fp == 0)
- +- internal_error (_("%s: %s: cannot open as FILE"), name, value_cell (v));
- +- else
- +- xtrace_set (fd, fp);
- +- }
- +- else
- +- internal_error (_("%s: %s: invalid value for trace file descriptor"), name, value_cell (v));
- +- }
- +-}
- +-
- +-#define MIN_COMPAT_LEVEL 31
- +-
- +-void
- +-sv_shcompat (name)
- +- char *name;
- +-{
- +- SHELL_VAR *v;
- +- char *val;
- +- int tens, ones, compatval;
- +-
- +- v = find_variable (name);
- +- if (v == 0)
- +- {
- +- shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
- +- set_compatibility_opts ();
- +- return;
- +- }
- +- val = value_cell (v);
- +- if (val == 0 || *val == '\0')
- +- {
- +- shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
- +- set_compatibility_opts ();
- +- return;
- +- }
- +- /* Handle decimal-like compatibility version specifications: 4.2 */
- +- if (isdigit (val[0]) && val[1] == '.' && isdigit (val[2]) && val[3] == 0)
- +- {
- +- tens = val[0] - '0';
- +- ones = val[2] - '0';
- +- compatval = tens*10 + ones;
- +- }
- +- /* Handle integer-like compatibility version specifications: 42 */
- +- else if (isdigit (val[0]) && isdigit (val[1]) && val[2] == 0)
- +- {
- +- tens = val[0] - '0';
- +- ones = val[1] - '0';
- +- compatval = tens*10 + ones;
- +- }
- +- else
- +- {
- +-compat_error:
- +- internal_error (_("%s: %s: compatibility value out of range"), name, val);
- +- shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
- +- set_compatibility_opts ();
- +- return;
- +- }
- +-
- +- if (compatval < MIN_COMPAT_LEVEL || compatval > DEFAULT_COMPAT_LEVEL)
- +- goto compat_error;
- +-
- +- shell_compatibility_level = compatval;
- +- set_compatibility_opts ();
- +-}
- +-
- +-#if defined (JOB_CONTROL)
- +-void
- +-sv_childmax (name)
- +- char *name;
- +-{
- +- char *tt;
- +- int s;
- +-
- +- tt = get_string_value (name);
- +- s = (tt && *tt) ? atoi (tt) : 0;
- +- set_maxchild (s);
- +-}
- +-#endif
- diff --git a/ptxdist/patches/bash-4.3.30/0003-Bash-4.3-patch-33.patch b/ptxdist/patches/bash-4.3.30/0003-Bash-4.3-patch-33.patch
- new file mode 100644
- index 0000000..cda1797
- --- /dev/null
- +++ b/ptxdist/patches/bash-4.3.30/0003-Bash-4.3-patch-33.patch
- @@ -0,0 +1,204 @@
- +From: Chet Ramey <chet.ramey@case.edu>
- +Date: Thu, 15 Jan 2015 10:21:08 -0500
- +Subject: [PATCH] Bash-4.3 patch 33
- +
- +---
- + bashline.c | 6 ++++--
- + builtins/common.h | 4 ++++
- + builtins/read.def | 31 ++++++++++++++++++++++++++++---
- + patchlevel.h | 2 +-
- + shell.c | 9 +++++++++
- + sig.c | 6 ++++--
- + 6 files changed, 50 insertions(+), 8 deletions(-)
- +
- +diff --git a/bashline.c b/bashline.c
- +index 77ca033f2cc8..c87415171a4a 100644
- +--- a/bashline.c
- ++++ b/bashline.c
- +@@ -202,6 +202,7 @@ extern int current_command_line_count, saved_command_line_count;
- + extern int last_command_exit_value;
- + extern int array_needs_making;
- + extern int posixly_correct, no_symbolic_links;
- ++extern int sigalrm_seen;
- + extern char *current_prompt_string, *ps1_prompt;
- + extern STRING_INT_ALIST word_token_alist[];
- + extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin;
- +@@ -4208,8 +4209,9 @@ bash_event_hook ()
- + {
- + /* If we're going to longjmp to top_level, make sure we clean up readline.
- + check_signals will call QUIT, which will eventually longjmp to top_level,
- +- calling run_interrupt_trap along the way. */
- +- if (interrupt_state)
- ++ calling run_interrupt_trap along the way. The check for sigalrm_seen is
- ++ to clean up the read builtin's state. */
- ++ if (terminating_signal || interrupt_state || sigalrm_seen)
- + rl_cleanup_after_signal ();
- + bashline_reset_event_hook ();
- + check_signals_and_traps (); /* XXX */
- +diff --git a/builtins/common.h b/builtins/common.h
- +index cae16b10fb65..a1298cb9c84a 100644
- +--- a/builtins/common.h
- ++++ b/builtins/common.h
- +@@ -122,6 +122,10 @@ extern void bash_logout __P((void));
- + /* Functions from getopts.def */
- + extern void getopts_reset __P((int));
- +
- ++/* Functions from read.def */
- ++extern void read_tty_cleanup __P((void));
- ++extern int read_tty_modified __P((void));
- ++
- + /* Functions from set.def */
- + extern int minus_o_option_value __P((char *));
- + extern void list_minus_o_opts __P((int, int));
- +diff --git a/builtins/read.def b/builtins/read.def
- +index 43971544d081..56c23010bbe8 100644
- +--- a/builtins/read.def
- ++++ b/builtins/read.def
- +@@ -140,10 +140,12 @@ static void reset_alarm __P((void));
- + procenv_t alrmbuf;
- + int sigalrm_seen;
- +
- +-static int reading;
- ++static int reading, tty_modified;
- + static SigHandler *old_alrm;
- + static unsigned char delim;
- +
- ++static struct ttsave termsave;
- ++
- + /* In all cases, SIGALRM just sets a flag that we check periodically. This
- + avoids problems with the semi-tricky stuff we do with the xfree of
- + input_string at the top of the unwind-protect list (see below). */
- +@@ -188,7 +190,6 @@ read_builtin (list)
- + struct stat tsb;
- + SHELL_VAR *var;
- + TTYSTRUCT ttattrs, ttset;
- +- struct ttsave termsave;
- + #if defined (ARRAY_VARS)
- + WORD_LIST *alist;
- + #endif
- +@@ -221,7 +222,7 @@ read_builtin (list)
- + USE_VAR(ps2);
- + USE_VAR(lastsig);
- +
- +- sigalrm_seen = reading = 0;
- ++ sigalrm_seen = reading = tty_modified = 0;
- +
- + i = 0; /* Index into the string that we are reading. */
- + raw = edit = 0; /* Not reading raw input by default. */
- +@@ -438,6 +439,8 @@ read_builtin (list)
- + retval = 128+SIGALRM;
- + goto assign_vars;
- + }
- ++ if (interactive_shell == 0)
- ++ initialize_terminating_signals ();
- + old_alrm = set_signal_handler (SIGALRM, sigalrm);
- + add_unwind_protect (reset_alarm, (char *)NULL);
- + #if defined (READLINE)
- +@@ -482,7 +485,10 @@ read_builtin (list)
- + i = silent ? ttfd_cbreak (fd, &ttset) : ttfd_onechar (fd, &ttset);
- + if (i < 0)
- + sh_ttyerror (1);
- ++ tty_modified = 1;
- + add_unwind_protect ((Function *)ttyrestore, (char *)&termsave);
- ++ if (interactive_shell == 0)
- ++ initialize_terminating_signals ();
- + }
- + }
- + else if (silent) /* turn off echo but leave term in canonical mode */
- +@@ -497,7 +503,10 @@ read_builtin (list)
- + if (i < 0)
- + sh_ttyerror (1);
- +
- ++ tty_modified = 1;
- + add_unwind_protect ((Function *)ttyrestore, (char *)&termsave);
- ++ if (interactive_shell == 0)
- ++ initialize_terminating_signals ();
- + }
- +
- + /* This *must* be the top unwind-protect on the stack, so the manipulation
- +@@ -588,6 +597,8 @@ read_builtin (list)
- + }
- + else
- + lastsig = 0;
- ++ if (terminating_signal && tty_modified)
- ++ ttyrestore (&termsave); /* fix terminal before exiting */
- + CHECK_TERMSIG;
- + eof = 1;
- + break;
- +@@ -978,6 +989,20 @@ ttyrestore (ttp)
- + struct ttsave *ttp;
- + {
- + ttsetattr (ttp->fd, ttp->attrs);
- ++ tty_modified = 0;
- ++}
- ++
- ++void
- ++read_tty_cleanup ()
- ++{
- ++ if (tty_modified)
- ++ ttyrestore (&termsave);
- ++}
- ++
- ++int
- ++read_tty_modified ()
- ++{
- ++ return (tty_modified);
- + }
- +
- + #if defined (READLINE)
- +diff --git a/patchlevel.h b/patchlevel.h
- +index b8bf38704ed2..cefe6bdd3a13 100644
- +--- a/patchlevel.h
- ++++ b/patchlevel.h
- +@@ -25,6 +25,6 @@
- + regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
- + looks for to find the patch level (for the sccs version string). */
- +
- +-#define PATCHLEVEL 32
- ++#define PATCHLEVEL 33
- +
- + #endif /* _PATCHLEVEL_H_ */
- +diff --git a/shell.c b/shell.c
- +index bbc8a66cc2eb..2fd8179ba10d 100644
- +--- a/shell.c
- ++++ b/shell.c
- +@@ -73,6 +73,7 @@
- + #endif
- +
- + #if defined (READLINE)
- ++# include <readline/readline.h>
- + # include "bashline.h"
- + #endif
- +
- +@@ -909,6 +910,14 @@ exit_shell (s)
- + fflush (stdout); /* XXX */
- + fflush (stderr);
- +
- ++ /* Clean up the terminal if we are in a state where it's been modified. */
- ++#if defined (READLINE)
- ++ if (RL_ISSTATE (RL_STATE_TERMPREPPED) && rl_deprep_term_function)
- ++ (*rl_deprep_term_function) ();
- ++#endif
- ++ if (read_tty_modified ())
- ++ read_tty_cleanup ();
- ++
- + /* Do trap[0] if defined. Allow it to override the exit status
- + passed to us. */
- + if (signal_is_trapped (0))
- +diff --git a/sig.c b/sig.c
- +index 3b62ea5d7c5d..8bc45c17f478 100644
- +--- a/sig.c
- ++++ b/sig.c
- +@@ -532,8 +532,10 @@ termsig_sighandler (sig)
- + #if defined (READLINE)
- + /* Set the event hook so readline will call it after the signal handlers
- + finish executing, so if this interrupted character input we can get
- +- quick response. */
- +- if (interactive_shell && interactive && no_line_editing == 0)
- ++ quick response. If readline is active or has modified the terminal we
- ++ need to set this no matter what the signal is, though the check for
- ++ RL_STATE_TERMPREPPED is possibly redundant. */
- ++ if (RL_ISSTATE (RL_STATE_SIGHANDLER) || RL_ISSTATE (RL_STATE_TERMPREPPED))
- + bashline_set_event_hook ();
- + #endif
- +
- diff --git a/ptxdist/patches/bash-4.3.30/0101-etc_bashrc_bashlogout.patch b/ptxdist/patches/bash-4.3.30/0101-etc_bashrc_bashlogout.patch
- new file mode 100644
- index 0000000..5154683
- --- /dev/null
- +++ b/ptxdist/patches/bash-4.3.30/0101-etc_bashrc_bashlogout.patch
- @@ -0,0 +1,22 @@
- +diff --git a/config-top.h b/config-top.h
- +index 7a90b16..52d582a 100644
- +--- a/config-top.h
- ++++ b/config-top.h
- +@@ -73,14 +73,14 @@
- + #define KSH_COMPATIBLE_SELECT
- +
- + /* System-wide .bashrc file for interactive shells. */
- +-/* #define SYS_BASHRC "/etc/bash.bashrc" */
- ++#define SYS_BASHRC "/etc/bash.bashrc"
- +
- + /* System-wide .bash_logout for login shells. */
- +-/* #define SYS_BASH_LOGOUT "/etc/bash.bash_logout" */
- ++#define SYS_BASH_LOGOUT "/etc/bash.bash_logout"
- +
- + /* Define this to make non-interactive shells begun with argv[0][0] == '-'
- + run the startup files when not in posix mode. */
- +-/* #define NON_INTERACTIVE_LOGIN_SHELLS */
- ++#define NON_INTERACTIVE_LOGIN_SHELLS 1
- +
- + /* Define this if you want bash to try to check whether it's being run by
- + sshd and source the .bashrc if so (like the rshd behavior). */
- diff --git a/ptxdist/patches/bash-4.3.30/series b/ptxdist/patches/bash-4.3.30/series
- new file mode 100644
- index 0000000..ed42ce1
- --- /dev/null
- +++ b/ptxdist/patches/bash-4.3.30/series
- @@ -0,0 +1,4 @@
- +0001-Bash-4.3-patch-31.patch
- +0002-Bash-4.3-patch-32.patch
- +0003-Bash-4.3-patch-33.patch
- +0101-etc_bashrc_bashlogout.patch
- diff --git a/ptxdist/projectroot/etc/passwd b/ptxdist/projectroot/etc/passwd
- index 5df5a35..1d394b8 100644
- --- a/ptxdist/projectroot/etc/passwd
- +++ b/ptxdist/projectroot/etc/passwd
- @@ -1,4 +1,4 @@
- -root:x:0:0:root:/home:/bin/sh
- +root:x:0:0:root:/home:/bin/bash
- daemon:x:1:1:daemon:/usr/sbin:/bin/sh
- ftp:x:11:101:ftp user:/home:/bin/false
- www:x:12:102:www user:/home:/bin/false
- diff --git a/ptxdist/projectroot/etc/profile.environment b/ptxdist/projectroot/etc/profile.environment
- index e4b85cc..cb47464 100644
- --- a/ptxdist/projectroot/etc/profile.environment
- +++ b/ptxdist/projectroot/etc/profile.environment
- @@ -1,13 +1,11 @@
- -# /etc/profile.environment - config for sub-shells
- -#PS1="\\u@\\h:\\w "
- -PS1='\u \t : \w # '
- -PS2=" >"
- -PS4="+ "
- +#
- +# /etc/profile.environment
- +#
- +
- +# do not set interactive shell properties like HISTFILE, PS1, PS2,
- +# ..., or aliases here.
- +# Such stuff belongs into the startup files for *interactive* shell
- +# sessions/etc/bash.bashrc or /etc/ksh.kshrc
- +
- +# EOF.
- -alias vim='vi'
- -alias l='ls -l'
- -alias ll='ls -al'
- -alias ..='cd ..'
- -alias ...='cd ../..'
- -alias md='mkdir'
- -alias rd='rmdir'
- diff --git a/ptxdist/rules/bash.in b/ptxdist/rules/bash.in
- new file mode 100644
- index 0000000..183c751
- --- /dev/null
- +++ b/ptxdist/rules/bash.in
- @@ -0,0 +1,269 @@
- +## SECTION=shell_and_console
- +menuconfig BASH
- + tristate "bash "
- + select LIBC_DL
- + select GCCLIBS_GCC_S
- + select NCURSES if BASH_CURSES
- + select TERMCAP if !BASH_CURSES
- + help
- + The GNU Bourne Again SHell
- + Bash is an sh-compatible command language interpreter that executes
- + commands read from the standard input or from a file. Bash also
- + incorporates useful features from the Korn and C shells (ksh and csh).
- +
- + Bash is ultimately intended to be a conformant implementation of the
- + IEEE POSIX Shell and Tools specification (IEEE Working Group 1003.2).
- +
- + Included in the bash package is the Programmable Completion Code,
- + by Ian Macdonald.
- +
- + http://www.gnu.org/software/bash/
- +
- +if BASH
- +
- +config BASH_SHLIKE
- + bool
- + prompt "Enable minimal sh like configuration"
- + help
- + This produces a shell with minimal features, close to the
- + historical Bourne shell.
- +
- +comment ""
- + depends on INVISIBLE
- +
- +if !BASH_SHLIKE
- +
- +config BASH_ALIASES
- + bool
- + prompt "Enable aliases"
- + default y
- + help
- + Aliases allow a string to be substituted for a word
- + when it is used as the first word of a simple command.
- + The shell maintains a list of aliases that may be
- + set and unset with the alias and unalias builtin commands
- +
- +config BASH_ARITHMETIC_FOR
- + bool
- + prompt "Enable arithmetic for command"
- + help
- + Include support for the alternate form of the for command that
- + behaves like the C language for statement.
- + This does not work properly in bash-2.05b!
- +
- +config BASH_ARRAY
- + bool
- + prompt "Include shell array variables"
- + default y
- +
- +config BASH_HISTORY
- + bool
- + prompt "Turn on csh-style history substitution"
- + default y
- + help
- + The bash shell supports a history expansion feature
- + that is similar to the history expansion in csh.
- +
- +config BASH_BRACE
- + bool
- + prompt "Include brace expansion"
- + default y
- + help
- + Brace expansion is a mechanism by which arbitrary
- + strings may be generated. This mechanism is similar
- + to pathname expansion, but the filenames generated
- + need not exist.
- +
- +config BASH_CASEMODATTR
- + bool
- + prompt "include case-modifying variable attributes"
- +
- +config BASH_CASEMODEXP
- + bool
- + prompt "include case-modifying word expansions"
- +
- +config BASH_CMDTIMING
- + bool
- + prompt "enable the time reserved word and command timing"
- +
- +config BASH_CONDITIONAL
- + bool
- + default y
- + prompt "Enable the conditional command"
- +
- +config BASH_CONDITIONAL_REGEX
- + bool
- + prompt "enable extended regular expression matching in conditional commands"
- + depends on BASH_CONDITIONAL
- +
- +config BASH_COPROCESSES
- + bool
- + default y
- + prompt "enable coprocess support and the coproc reserved word"
- +
- +config BASH_DEBUGGER
- + bool
- + prompt "enable support for bash debugger"
- +
- +config BASH_DIREXPDEFLT
- + bool
- + prompt "enable the direxpand shell option by default"
- +
- +config BASH_DIRSTACK
- + bool
- + prompt "Enable builtins pushd/popd/dirs"
- + default y
- + help
- + Without options, "dirs" displays the list of
- + currently remembered directories. The default
- + display is on a single line with directory
- + names separated by spaces. Directories are
- + added to the list with the pushd command;
- + the popd command removes entries from the list.
- +
- +config BASH_DISABLED_BUILDINS
- + bool
- + prompt "Allow disabled builtins to still be invoked"
- +
- +config BASH_DPARAN_ARITH
- + bool
- + prompt "include ((...)) command"
- + default y
- +
- +config BASH_EXTPATTERN
- + bool
- + default y
- + # fails to build without this in 4.3.30
- + prompt "Include ksh-style extended pattern matching" if BROKEN
- +
- +config BASH_EXTPATTERN_DEFLT
- + bool
- + prompt "force extended pattern matching to be enabled by default"
- +
- +config BASH_GLOB_ASCIIRANGE_DEFLT
- + bool
- + prompt "bracket range pattern matching uses C locale"
- + help
- + force bracket range expressions in pattern matching to use the C
- + locale by default
- +
- +config BASH_HELP
- + bool
- + prompt "Include the help builtin"
- + help
- + This builtin supports minimal help features inside bash
- +
- +config BASH_CMDHISTORY
- + bool
- + prompt "Turn on command history"
- + default y
- + help
- + This enables command history features. The shell
- + buffers commands in a ringbuffer, which can be listed,
- + searched and accessed by various commands and magic
- + shell expansion features.
- +
- +config BASH_JOBS
- + bool
- + prompt "Enable job control features"
- + default y
- + help
- + This enables support for background jobs in bash.
- + You can list the actual managed jobs by the "jobs" command.
- +
- +config BASH_MULTIBYTE
- + bool
- + prompt "Enable multibyte characters"
- + default y
- + help
- + Enable multibyte characters if OS supports them.
- +
- +config BASH_PROCSUBST
- + bool
- + prompt "Enable process substitution"
- + default y
- + help
- + This enables process substitution if the operating system
- + provides the necessary support.
- + Process substitution is supported on systems that support
- + named pipes (FIFOs) or the '/dev/fd' method of naming open
- + files. It takes the form of <(list) or >(list).
- +
- +config BASH_BASHCOMPLETION
- + bool
- + prompt "Enable programmable completion"
- + help
- + Enable the programmable completion facilities.
- + When word completion is attempted for an argument to a
- + command for which a completion specification (a compspec) has
- + been defined using the complete builtin, the programmable
- + completion facilities are invoked.
- + If Readline is not enabled, this option has no effect.
- +
- +config BASH_ESC
- + bool
- + prompt "Turn on escape character decoding in prompts"
- + default y
- + help
- + Turn on the interpretation of a number of backslash-escaped
- + characters in the $PS1, $PS2, $PS3, and $PS4 prompt strings.
- +
- +config BASH_EDIT
- + bool
- +# prompt "Turn on command line editing"
- + default y
- + help
- + Include support for command-line editing and history with
- + the Bash version of the Readline library.
- +
- +config BASH_RESTRICTED
- + bool
- + prompt "Enable a restricted shell"
- + help
- + Include support for a restricted shell. If this is enabled,
- + Bash enters a restricted mode, when called as rbash or invoked
- + with the `--restricted' or `-r' option.
- + A restricted shell is used to set up an environment
- + more controlled than the standard shell.
- +
- +config BASH_SELECT
- + bool
- + prompt "Include select command"
- + help
- + Include the select builtin, which allows the generation of
- + simple menus.
- +
- +config BASH_SEP_HELPFILES
- + bool
- + depends on BROKEN
- + prompt "use external files for help builtin documentation"
- +
- +config BASH_SINGLE_HELPLINE
- + bool
- + prompt "store help documentation as a single string to ease translation"
- +
- +endif
- +
- +config BASH_GPROF
- + bool
- + prompt "Allow profiling with gprof"
- + help
- + This builds a Bash binary that produces profiling information
- + to be processed by gprof each time it is executed.
- +
- +config BASH_STATIC
- + bool
- + prompt "Link bash statically"
- + help
- + This causes Bash to be linked statically, if gcc is being used.
- + This could be used to build a version to use as root's shell.
- +
- +config BASH_CURSES
- + bool
- + prompt "Use libcurses instead of libtermcap"
- +
- +config BASH_SH
- + bool
- + default BUSYBOX = n || BUSYBOX_SH_IS_NONE
- +
- +endif
- diff --git a/ptxdist/rules/bash.make b/ptxdist/rules/bash.make
- new file mode 100644
- index 0000000..6a1e5d7
- --- /dev/null
- +++ b/ptxdist/rules/bash.make
- @@ -0,0 +1,111 @@
- +# -*-makefile-*-
- +#
- +# Copyright (C) 2003-2009 by Pengutronix e.K., Hildesheim, Germany
- +# For further information about the PTXdist project and license conditions
- +# see the README file.
- +#
- +
- +#
- +# We provide this package
- +#
- +PACKAGES-$(PTXCONF_BASH) += bash
- +
- +#
- +# Paths and names
- +#
- +BASH_VERSION := 4.3.30
- +BASH_MD5 := a27b3ee9be83bd3ba448c0ff52b28447
- +BASH := bash-$(BASH_VERSION)
- +BASH_SUFFIX := tar.gz
- +BASH_URL := $(call ptx/mirror, GNU, bash/$(BASH).$(BASH_SUFFIX))
- +BASH_SOURCE := $(SRCDIR)/$(BASH).$(BASH_SUFFIX)
- +BASH_DIR := $(BUILDDIR)/$(BASH)
- +BASH_MAKE_PAR := NO
- +BASH_LICENSE := GPL-3.0-or-later
- +BASH_LICENSE_FILES := \
- + file://COPYING;md5=d32239bcb673463ab874e80d47fae504 \
- + file://general.c;startline=1;endline=19;md5=c018785d21f8c206ca7a13fa7d027568
- +
- +# ----------------------------------------------------------------------------
- +# Prepare
- +# ----------------------------------------------------------------------------
- +
- +BASH_PATH := PATH=$(CROSS_PATH)
- +BASH_ENV := \
- + $(CROSS_ENV) \
- + bash_cv_job_control_missing=$(call ptx/ifdef, PTXCONF_BASH_JOBS, present, missing) \
- + bash_cv_termcap_lib=$(call ptx/ifdef, PTXCONF_BASH_CURSES, libncurses, libtermcap)
- +
- +BASH_AUTOCONF := \
- + $(CROSS_AUTOCONF_USR) \
- + $(GLOBAL_LARGE_FILE_OPTION) \
- + --without-bash-malloc \
- + --$(call ptx/endis, PTXCONF_BASH_SHLIKE)-minimal-config \
- + --$(call ptx/endis, PTXCONF_BASH_ALIASES)-alias \
- + --$(call ptx/endis, PTXCONF_BASH_ARITHMETIC_FOR)-arith-for-command \
- + --$(call ptx/endis, PTXCONF_BASH_ARRAY)-array-variables \
- + --$(call ptx/endis, PTXCONF_BASH_HISTORY)-bang-history \
- + --$(call ptx/endis, PTXCONF_BASH_BRACE)-brace-expansion \
- + --$(call ptx/endis, PTXCONF_BASH_CASEMODATTR)-casemod-attributes \
- + --$(call ptx/endis, PTXCONF_BASH_CASEMODEXP)-casemod-expansions \
- + --$(call ptx/endis, PTXCONF_BASH_CMDTIMING)-command-timing \
- + --$(call ptx/endis, PTXCONF_BASH_CONDITIONAL)-cond-command \
- + --$(call ptx/endis, PTXCONF_BASH_CONDITIONAL_REGEX)-cond-regexp \
- + --$(call ptx/endis, PTXCONF_BASH_COPROCESSES)-coprocesses \
- + --$(call ptx/endis, PTXCONF_BASH_DEBUGGER)-debugger \
- + --$(call ptx/endis, PTXCONF_BASH_DIREXPDEFLT)-direxpand-default \
- + --$(call ptx/endis, PTXCONF_BASH_DIRSTACK)-directory-stack \
- + --$(call ptx/endis, PTXCONF_BASH_DISABLED_BUILDINS)-disabled-builtins \
- + --$(call ptx/endis, PTXCONF_BASH_DPARAN_ARITH)-dparen-arithmetic \
- + --$(call ptx/endis, PTXCONF_BASH_EXTPATTERN)-extended-glob \
- + --$(call ptx/endis, PTXCONF_BASH_EXTPATTERN_DEFLT)-extended-glob-default \
- + --$(call ptx/endis, PTXCONF_BASH_GLOB_ASCIIRANGE_DEFLT)-glob-asciiranges-default \
- + --$(call ptx/endis, PTXCONF_BASH_HELP)-help-builtin \
- + --$(call ptx/endis, PTXCONF_BASH_CMDHISTORY)-history \
- + --$(call ptx/endis, PTXCONF_BASH_JOBS)-job-control \
- + --$(call ptx/endis, PTXCONF_BASH_MULTIBYTE)-multibyte \
- + --$(call ptx/endis, PTXCONF_BASH_PROCSUBST)-process-substitution \
- + --$(call ptx/endis, PTXCONF_BASH_BASHCOMPLETION)-progcomp \
- + --$(call ptx/endis, PTXCONF_BASH_ESC)-prompt-string-decoding \
- + --$(call ptx/endis, PTXCONF_BASH_EDIT)-readline \
- + --$(call ptx/endis, PTXCONF_BASH_RESTRICTED)-restricted \
- + --$(call ptx/endis, PTXCONF_BASH_SELECT)-select \
- + --$(call ptx/endis, PTXCONF_BASH_SEP_HELPFILES)-separate-helpfiles \
- + --$(call ptx/endis, PTXCONF_BASH_SINGLE_HELPLINE)-single-help-strings \
- + --$(call ptx/endis, PTXCONF_BASH_GPROF)-profiling \
- + --$(call ptx/endis, PTXCONF_BASH_STATIC)-static-link \
- + --$(call ptx/wwo, PTXCONF_BASH_CURSES)-curses \
- + --enable-xpg-echo-default
- +
- +# ----------------------------------------------------------------------------
- +# Target-Install
- +# ----------------------------------------------------------------------------
- +
- +$(STATEDIR)/bash.targetinstall:
- + @$(call targetinfo)
- +
- + @$(call install_init, bash)
- + @$(call install_fixup, bash,PRIORITY,optional)
- + @$(call install_fixup, bash,SECTION,base)
- + @$(call install_fixup, bash,AUTHOR,"Robert Schwebel <r.schwebel@pengutronix.de>")
- + @$(call install_fixup, bash,DESCRIPTION,missing)
- +
- +# this is reverse from UNIX tradition: /usr should depend on rootfs
- +# not rootfs depend on /usr
- + @$(call install_copy, bash, 0, 0, 0755, -, /usr/bin/bash)
- + @$(call install_link, bash, bash, /usr/bin/sh)
- + @$(call install_link, bash, ../usr/bin/bash, /bin/sh)
- + @$(call install_link, bash, ../usr/bin/bash, /bin/bash)
- +
- +# this would be the correct solution, but for some cursed issue
- +# this does not work (yet)
- +# @$(call install_copy, bash, 0, 0, 0755, -, /bin/bash)
- +# @$(call install_link, bash, ./bash, /bin/sh)
- +# @$(call install_link, bash, ../../bin/bash, /usr/bin/sh)
- +# @$(call install_link, bash, ../../bin/bash, /usr/bin/bash)
- +
- + @$(call install_finish, bash)
- +
- + @$(call touch)
- +
- +# vim: syntax=make
- diff --git a/ptxdist/rules/ecu01-basicsys.make b/ptxdist/rules/ecu01-basicsys.make
- index 7e948b3..944432b 100644
- --- a/ptxdist/rules/ecu01-basicsys.make
- +++ b/ptxdist/rules/ecu01-basicsys.make
- @@ -210,9 +210,10 @@ $(STATEDIR)/ecu01-basicsys.targetinstall:
- #fonts
- @$(call install_tree, ecu01-basicsys, 0, 0, $(ECU01_BASICSYS_DIR)/usr/lib/fonts, /usr/lib/fonts)
- - #local environment
- - @$(call install_copy, ecu01-basicsys, 0, 0, 0755, $(ECU01_BASICSYS_DIR)/etc/profile.local, \
- - /etc/profile.local)
- + #environment
- + @$(call install_copy, ecu01-basicsys, 0, 0, 0644, $(ECU01_BASICSYS_DIR)/etc/bash.bashrc, /etc/bash.bashrc)
- + @$(call install_copy, ecu01-basicsys, 0, 0, 0644, $(ECU01_BASICSYS_DIR)/etc/profile, /etc/profile)
- + @$(call install_copy, ecu01-basicsys, 0, 0, 0644, $(ECU01_BASICSYS_DIR)/etc/profile.local, /etc/profile.local)
- # SSH Key, Passphrase quantron-a
- @$(call install_copy, ecu01-basicsys, 0, 0, 0600, $(ECU01_BASICSYS_DIR)/etc/ssh/ecu_unix_rsa, /etc/ssh/ecu_unix_rsa)
quantron: Fix shell/bash environment with sane defaults
Posted by Anonymous on Mon 18th Nov 2019 10:52
raw | new post
Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.