LCOV - code coverage report
Current view: top level - bash-4.4.23 - variables.c (source / functions) Hit Total Coverage
Test: cov-sh.info Lines: 997 2073 48.1 %
Date: 2020-10-29 14:49:55 Functions: 103 187 55.1 %

          Line data    Source code
       1             : /* variables.c -- Functions for hacking shell variables. */
       2             : 
       3             : /* Copyright (C) 1987-2016 Free Software Foundation, Inc.
       4             : 
       5             :    This file is part of GNU Bash, the Bourne Again SHell.
       6             : 
       7             :    Bash is free software: you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation, either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    Bash is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include "config.h"
      22             : 
      23             : #include "bashtypes.h"
      24             : #include "posixstat.h"
      25             : #include "posixtime.h"
      26             : 
      27             : #if defined (__QNX__)
      28             : #  if defined (__QNXNTO__)
      29             : #    include <sys/netmgr.h>
      30             : #  else
      31             : #    include <sys/vc.h>
      32             : #  endif /* !__QNXNTO__ */
      33             : #endif /* __QNX__ */
      34             : 
      35             : #if defined (HAVE_UNISTD_H)
      36             : #  include <unistd.h>
      37             : #endif
      38             : 
      39             : #include <stdio.h>
      40             : #include "chartypes.h"
      41             : #if defined (HAVE_PWD_H)
      42             : #  include <pwd.h>
      43             : #endif
      44             : #include "bashansi.h"
      45             : #include "bashintl.h"
      46             : 
      47             : #define NEED_XTRACE_SET_DECL
      48             : 
      49             : #include "shell.h"
      50             : #include "flags.h"
      51             : #include "execute_cmd.h"
      52             : #include "findcmd.h"
      53             : #include "mailcheck.h"
      54             : #include "input.h"
      55             : #include "hashcmd.h"
      56             : #include "pathexp.h"
      57             : #include "alias.h"
      58             : #include "jobs.h"
      59             : 
      60             : #include "version.h"
      61             : 
      62             : #include "builtins/getopt.h"
      63             : #include "builtins/common.h"
      64             : #include "builtins/builtext.h"
      65             : 
      66             : #if defined (READLINE)
      67             : #  include "bashline.h"
      68             : #  include <readline/readline.h>
      69             : #else
      70             : #  include <tilde/tilde.h>
      71             : #endif
      72             : 
      73             : #if defined (HISTORY)
      74             : #  include "bashhist.h"
      75             : #  include <readline/history.h>
      76             : #endif /* HISTORY */
      77             : 
      78             : #if defined (PROGRAMMABLE_COMPLETION)
      79             : #  include "pcomplete.h"
      80             : #endif
      81             : 
      82             : #define VARIABLES_HASH_BUCKETS  1024    /* must be power of two */
      83             : #define FUNCTIONS_HASH_BUCKETS  512
      84             : #define TEMPENV_HASH_BUCKETS    4       /* must be power of two */
      85             : 
      86             : #define BASHFUNC_PREFIX         "BASH_FUNC_"
      87             : #define BASHFUNC_PREFLEN        10      /* == strlen(BASHFUNC_PREFIX */
      88             : #define BASHFUNC_SUFFIX         "%%"
      89             : #define BASHFUNC_SUFFLEN        2       /* == strlen(BASHFUNC_SUFFIX) */
      90             : 
      91             : /* flags for find_variable_internal */
      92             : 
      93             : #define FV_FORCETEMPENV         0x01
      94             : #define FV_SKIPINVISIBLE        0x02
      95             : 
      96             : extern char **environ;
      97             : 
      98             : /* Variables used here and defined in other files. */
      99             : extern int posixly_correct;
     100             : extern int line_number, line_number_base;
     101             : extern int subshell_environment, indirection_level, subshell_level;
     102             : extern int build_version, patch_level;
     103             : extern int expanding_redir;
     104             : extern int last_command_exit_value;
     105             : extern char *dist_version, *release_status;
     106             : extern char *shell_name;
     107             : extern char *primary_prompt, *secondary_prompt;
     108             : extern char *current_host_name;
     109             : extern sh_builtin_func_t *this_shell_builtin;
     110             : extern SHELL_VAR *this_shell_function;
     111             : extern char *the_printed_command_except_trap;
     112             : extern char *this_command_name;
     113             : extern char *command_execution_string;
     114             : extern time_t shell_start_time;
     115             : extern int assigning_in_environment;
     116             : extern int executing_builtin;
     117             : extern int funcnest_max;
     118             : 
     119             : #if defined (READLINE)
     120             : extern int no_line_editing;
     121             : extern int perform_hostname_completion;
     122             : #endif
     123             : 
     124             : /* The list of shell variables that the user has created at the global
     125             :    scope, or that came from the environment. */
     126             : VAR_CONTEXT *global_variables = (VAR_CONTEXT *)NULL;
     127             : 
     128             : /* The current list of shell variables, including function scopes */
     129             : VAR_CONTEXT *shell_variables = (VAR_CONTEXT *)NULL;
     130             : 
     131             : /* The list of shell functions that the user has created, or that came from
     132             :    the environment. */
     133             : HASH_TABLE *shell_functions = (HASH_TABLE *)NULL;
     134             : 
     135             : #if defined (DEBUGGER)
     136             : /* The table of shell function definitions that the user defined or that
     137             :    came from the environment. */
     138             : HASH_TABLE *shell_function_defs = (HASH_TABLE *)NULL;
     139             : #endif
     140             : 
     141             : /* The current variable context.  This is really a count of how deep into
     142             :    executing functions we are. */
     143             : int variable_context = 0;
     144             : 
     145             : /* The set of shell assignments which are made only in the environment
     146             :    for a single command. */
     147             : HASH_TABLE *temporary_env = (HASH_TABLE *)NULL;
     148             : 
     149             : /* Set to non-zero if an assignment error occurs while putting variables
     150             :    into the temporary environment. */
     151             : int tempenv_assign_error;
     152             : 
     153             : /* Some funky variables which are known about specially.  Here is where
     154             :    "$*", "$1", and all the cruft is kept. */
     155             : char *dollar_vars[10];
     156             : WORD_LIST *rest_of_args = (WORD_LIST *)NULL;
     157             : 
     158             : /* The value of $$. */
     159             : pid_t dollar_dollar_pid;
     160             : 
     161             : /* Non-zero means that we have to remake EXPORT_ENV. */
     162             : int array_needs_making = 1;
     163             : 
     164             : /* The number of times BASH has been executed.  This is set
     165             :    by initialize_variables (). */
     166             : int shell_level = 0;
     167             : 
     168             : /* An array which is passed to commands as their environment.  It is
     169             :    manufactured from the union of the initial environment and the
     170             :    shell variables that are marked for export. */
     171             : char **export_env = (char **)NULL;
     172             : static int export_env_index;
     173             : static int export_env_size;
     174             : 
     175             : #if defined (READLINE)
     176             : static int winsize_assignment;          /* currently assigning to LINES or COLUMNS */
     177             : #endif
     178             : 
     179             : SHELL_VAR nameref_invalid_value;
     180             : static SHELL_VAR nameref_maxloop_value;
     181             : 
     182             : static HASH_TABLE *last_table_searched; /* hash_lookup sets this */
     183             : 
     184             : /* Some forward declarations. */
     185             : static void create_variable_tables __P((void));
     186             : 
     187             : static void set_machine_vars __P((void));
     188             : static void set_home_var __P((void));
     189             : static void set_shell_var __P((void));
     190             : static char *get_bash_name __P((void));
     191             : static void initialize_shell_level __P((void));
     192             : static void uidset __P((void));
     193             : #if defined (ARRAY_VARS)
     194             : static void make_vers_array __P((void));
     195             : #endif
     196             : 
     197             : static SHELL_VAR *null_assign __P((SHELL_VAR *, char *, arrayind_t, char *));
     198             : #if defined (ARRAY_VARS)
     199             : static SHELL_VAR *null_array_assign __P((SHELL_VAR *, char *, arrayind_t, char *));
     200             : #endif
     201             : static SHELL_VAR *get_self __P((SHELL_VAR *));
     202             : 
     203             : #if defined (ARRAY_VARS)
     204             : static SHELL_VAR *init_dynamic_array_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int));
     205             : static SHELL_VAR *init_dynamic_assoc_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int));
     206             : #endif
     207             : 
     208             : static SHELL_VAR *assign_seconds __P((SHELL_VAR *, char *, arrayind_t, char *));
     209             : static SHELL_VAR *get_seconds __P((SHELL_VAR *));
     210             : static SHELL_VAR *init_seconds_var __P((void));
     211             : 
     212             : static int brand __P((void));
     213             : static void sbrand __P((unsigned long));                /* set bash random number generator. */
     214             : static void seedrand __P((void));                       /* seed generator randomly */
     215             : static SHELL_VAR *assign_random __P((SHELL_VAR *, char *, arrayind_t, char *));
     216             : static SHELL_VAR *get_random __P((SHELL_VAR *));
     217             : 
     218             : static SHELL_VAR *assign_lineno __P((SHELL_VAR *, char *, arrayind_t, char *));
     219             : static SHELL_VAR *get_lineno __P((SHELL_VAR *));
     220             : 
     221             : static SHELL_VAR *assign_subshell __P((SHELL_VAR *, char *, arrayind_t, char *));
     222             : static SHELL_VAR *get_subshell __P((SHELL_VAR *));
     223             : 
     224             : static SHELL_VAR *get_bashpid __P((SHELL_VAR *));
     225             : 
     226             : #if defined (HISTORY)
     227             : static SHELL_VAR *get_histcmd __P((SHELL_VAR *));
     228             : #endif
     229             : 
     230             : #if defined (READLINE)
     231             : static SHELL_VAR *get_comp_wordbreaks __P((SHELL_VAR *));
     232             : static SHELL_VAR *assign_comp_wordbreaks __P((SHELL_VAR *, char *, arrayind_t, char *));
     233             : #endif
     234             : 
     235             : #if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
     236             : static SHELL_VAR *assign_dirstack __P((SHELL_VAR *, char *, arrayind_t, char *));
     237             : static SHELL_VAR *get_dirstack __P((SHELL_VAR *));
     238             : #endif
     239             : 
     240             : #if defined (ARRAY_VARS)
     241             : static SHELL_VAR *get_groupset __P((SHELL_VAR *));
     242             : 
     243             : static SHELL_VAR *build_hashcmd __P((SHELL_VAR *));
     244             : static SHELL_VAR *get_hashcmd __P((SHELL_VAR *));
     245             : static SHELL_VAR *assign_hashcmd __P((SHELL_VAR *,  char *, arrayind_t, char *));
     246             : #  if defined (ALIAS)
     247             : static SHELL_VAR *build_aliasvar __P((SHELL_VAR *));
     248             : static SHELL_VAR *get_aliasvar __P((SHELL_VAR *));
     249             : static SHELL_VAR *assign_aliasvar __P((SHELL_VAR *,  char *, arrayind_t, char *));
     250             : #  endif
     251             : #endif
     252             : 
     253             : static SHELL_VAR *get_funcname __P((SHELL_VAR *));
     254             : static SHELL_VAR *init_funcname_var __P((void));
     255             : 
     256             : static void initialize_dynamic_variables __P((void));
     257             : 
     258             : static SHELL_VAR *hash_lookup __P((const char *, HASH_TABLE *));
     259             : static SHELL_VAR *new_shell_variable __P((const char *));
     260             : static SHELL_VAR *make_new_variable __P((const char *, HASH_TABLE *));
     261             : static SHELL_VAR *bind_variable_internal __P((const char *, char *, HASH_TABLE *, int, int));
     262             : 
     263             : static void dispose_variable_value __P((SHELL_VAR *));
     264             : static void free_variable_hash_data __P((PTR_T));
     265             : 
     266             : static VARLIST *vlist_alloc __P((int));
     267             : static VARLIST *vlist_realloc __P((VARLIST *, int));
     268             : static void vlist_add __P((VARLIST *, SHELL_VAR *, int));
     269             : 
     270             : static void flatten __P((HASH_TABLE *, sh_var_map_func_t *, VARLIST *, int));
     271             : 
     272             : static int qsort_var_comp __P((SHELL_VAR **, SHELL_VAR **));
     273             : 
     274             : static SHELL_VAR **vapply __P((sh_var_map_func_t *));
     275             : static SHELL_VAR **fapply __P((sh_var_map_func_t *));
     276             : 
     277             : static int visible_var __P((SHELL_VAR *));
     278             : static int visible_and_exported __P((SHELL_VAR *));
     279             : static int export_environment_candidate __P((SHELL_VAR *));
     280             : static int local_and_exported __P((SHELL_VAR *));
     281             : static int variable_in_context __P((SHELL_VAR *));
     282             : #if defined (ARRAY_VARS)
     283             : static int visible_array_vars __P((SHELL_VAR *));
     284             : #endif
     285             : 
     286             : static SHELL_VAR *find_variable_internal __P((const char *, int));
     287             : 
     288             : static SHELL_VAR *find_nameref_at_context __P((SHELL_VAR *, VAR_CONTEXT *));
     289             : static SHELL_VAR *find_variable_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **));
     290             : static SHELL_VAR *find_variable_last_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **));
     291             : 
     292             : static SHELL_VAR *bind_tempenv_variable __P((const char *, char *));
     293             : static void push_temp_var __P((PTR_T));
     294             : static void propagate_temp_var __P((PTR_T));
     295             : static void dispose_temporary_env __P((sh_free_func_t *));     
     296             : 
     297             : static inline char *mk_env_string __P((const char *, const char *, int));
     298             : static char **make_env_array_from_var_list __P((SHELL_VAR **));
     299             : static char **make_var_export_array __P((VAR_CONTEXT *));
     300             : static char **make_func_export_array __P((void));
     301             : static void add_temp_array_to_env __P((char **, int, int));
     302             : 
     303             : static int n_shell_variables __P((void));
     304             : static int set_context __P((SHELL_VAR *));
     305             : 
     306             : static void push_func_var __P((PTR_T));
     307             : static void push_exported_var __P((PTR_T));
     308             : 
     309             : static inline int find_special_var __P((const char *));
     310             : 
     311             : static void
     312     9542884 : create_variable_tables ()
     313             : {
     314     9542884 :   if (shell_variables == 0)
     315             :     {
     316     9542884 :       shell_variables = global_variables = new_var_context ((char *)NULL, 0);
     317     9542884 :       shell_variables->scope = 0;
     318     9542884 :       shell_variables->table = hash_create (VARIABLES_HASH_BUCKETS);
     319             :     }
     320             : 
     321     9542884 :   if (shell_functions == 0)
     322     9542884 :     shell_functions = hash_create (FUNCTIONS_HASH_BUCKETS);
     323             : 
     324             : #if defined (DEBUGGER)
     325     9542884 :   if (shell_function_defs == 0)
     326     9542884 :     shell_function_defs = hash_create (FUNCTIONS_HASH_BUCKETS);
     327             : #endif
     328     9542884 : }
     329             : 
     330             : /* Initialize the shell variables from the current environment.
     331             :    If PRIVMODE is nonzero, don't import functions from ENV or
     332             :    parse $SHELLOPTS. */
     333             : void
     334     9542884 : initialize_shell_variables (env, privmode)
     335             :      char **env;
     336             :      int privmode;
     337             : {
     338     9542884 :   char *name, *string, *temp_string;
     339     9542884 :   int c, char_index, string_index, string_length, ro;
     340     9542884 :   SHELL_VAR *temp_var;
     341             : 
     342     9542884 :   create_variable_tables ();
     343             : 
     344   362629594 :   for (string_index = 0; env && (string = env[string_index++]); )
     345             :     {
     346             :       char_index = 0;
     347             :       name = string;
     348  3607210166 :       while ((c = *string++) && c != '=')
     349  3607210166 :         ;
     350   353086710 :       if (string[-1] == '=')
     351   353086710 :         char_index = string - name - 1;
     352             : 
     353             :       /* If there are weird things in the environment, like `=xxx' or a
     354             :          string without an `=', just skip them. */
     355   353086710 :       if (char_index == 0)
     356             :         continue;
     357             : 
     358             :       /* ASSERT(name[char_index] == '=') */
     359   353086710 :       name[char_index] = '\0';
     360             :       /* Now, name = env variable name, string = env variable value, and
     361             :          char_index == strlen (name) */
     362             : 
     363   353086710 :       temp_var = (SHELL_VAR *)NULL;
     364             : 
     365             : #if defined (FUNCTION_IMPORT)
     366             :       /* If exported function, define it now.  Don't import functions from
     367             :          the environment in privileged mode. */
     368   353086710 :       if (privmode == 0 && read_but_dont_execute == 0 && 
     369   353086710 :           STREQN (BASHFUNC_PREFIX, name, BASHFUNC_PREFLEN) &&
     370           0 :           STREQ (BASHFUNC_SUFFIX, name + char_index - BASHFUNC_SUFFLEN) &&
     371           0 :           STREQN ("() {", string, 4))
     372           0 :         {
     373           0 :           size_t namelen;
     374           0 :           char *tname;          /* desired imported function name */
     375             : 
     376           0 :           namelen = char_index - BASHFUNC_PREFLEN - BASHFUNC_SUFFLEN;
     377             : 
     378           0 :           tname = name + BASHFUNC_PREFLEN;      /* start of func name */
     379           0 :           tname[namelen] = '\0';                /* now tname == func name */
     380             : 
     381           0 :           string_length = strlen (string);
     382           0 :           temp_string = (char *)xmalloc (namelen + string_length + 2);
     383             : 
     384           0 :           memcpy (temp_string, tname, namelen);
     385           0 :           temp_string[namelen] = ' ';
     386           0 :           memcpy (temp_string + namelen + 1, string, string_length + 1);
     387             : 
     388             :           /* Don't import function names that are invalid identifiers from the
     389             :              environment in posix mode, though we still allow them to be defined as
     390             :              shell variables. */
     391           0 :           if (absolute_program (tname) == 0 && (posixly_correct == 0 || legal_identifier (tname)))
     392           0 :             parse_and_execute (temp_string, tname, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
     393             :           else
     394           0 :             free (temp_string);         /* parse_and_execute does this */
     395             : 
     396           0 :           if (temp_var = find_function (tname))
     397             :             {
     398           0 :               VSETATTR (temp_var, (att_exported|att_imported));
     399           0 :               array_needs_making = 1;
     400             :             }
     401             :           else
     402             :             {
     403           0 :               if (temp_var = bind_variable (name, string, 0))
     404             :                 {
     405           0 :                   VSETATTR (temp_var, (att_exported | att_imported | att_invisible));
     406           0 :                   array_needs_making = 1;
     407             :                 }
     408           0 :               last_command_exit_value = 1;
     409           0 :               report_error (_("error importing function definition for `%s'"), tname);
     410             :             }
     411             : 
     412             :           /* Restore original suffix */
     413           0 :           tname[namelen] = BASHFUNC_SUFFIX[0];
     414             :         }
     415             :       else
     416             : #endif /* FUNCTION_IMPORT */
     417             : #if defined (ARRAY_VARS)
     418             : #  if ARRAY_EXPORT
     419             :       /* Array variables may not yet be exported. */
     420             :       if (*string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')')
     421             :         {
     422             :           string_length = 1;
     423             :           temp_string = extract_array_assignment_list (string, &string_length);
     424             :           temp_var = assign_array_from_string (name, temp_string, 0);
     425             :           FREE (temp_string);
     426             :           VSETATTR (temp_var, (att_exported | att_imported));
     427             :           array_needs_making = 1;
     428             :         }
     429             :       else
     430             : #  endif /* ARRAY_EXPORT */
     431             : #endif
     432             :         {
     433   353086710 :           ro = 0;
     434   353086710 :           if (posixly_correct && STREQ (name, "SHELLOPTS"))
     435             :             {
     436           0 :               temp_var = find_variable ("SHELLOPTS");
     437           0 :               ro = temp_var && readonly_p (temp_var);
     438           0 :               if (temp_var)
     439           0 :                 VUNSETATTR (temp_var, att_readonly);
     440             :             }
     441   353086710 :           temp_var = bind_variable (name, string, 0);
     442   353086710 :           if (temp_var)
     443             :             {
     444   353086710 :               if (legal_identifier (name))
     445   353086710 :                 VSETATTR (temp_var, (att_exported | att_imported));
     446             :               else
     447           0 :                 VSETATTR (temp_var, (att_exported | att_imported | att_invisible));
     448   353086710 :               if (ro)
     449           0 :                 VSETATTR (temp_var, att_readonly);
     450   353086710 :               array_needs_making = 1;
     451             :             }
     452             :         }
     453             : 
     454   353086710 :       name[char_index] = '=';
     455             :       /* temp_var can be NULL if it was an exported function with a syntax
     456             :          error (a different bug, but it still shouldn't dump core). */
     457   353086710 :       if (temp_var && function_p (temp_var) == 0)       /* XXX not yet */
     458             :         {
     459   353086710 :           CACHE_IMPORTSTR (temp_var, name);
     460             :         }
     461             :     }
     462             : 
     463     9542884 :   set_pwd ();
     464             : 
     465             :   /* Set up initial value of $_ */
     466     9542884 :   temp_var = set_if_not ("_", dollar_vars[0]);
     467             : 
     468             :   /* Remember this pid. */
     469     9542884 :   dollar_dollar_pid = getpid ();
     470             : 
     471             :   /* Now make our own defaults in case the vars that we think are
     472             :      important are missing. */
     473     9542884 :   temp_var = set_if_not ("PATH", DEFAULT_PATH_VALUE);
     474             : #if 0
     475             :   set_auto_export (temp_var);   /* XXX */
     476             : #endif
     477             : 
     478     9542884 :   temp_var = set_if_not ("TERM", "dumb");
     479             : #if 0
     480             :   set_auto_export (temp_var);   /* XXX */
     481             : #endif
     482             : 
     483             : #if defined (__QNX__)
     484             :   /* set node id -- don't import it from the environment */
     485             :   {
     486             :     char node_name[22];
     487             : #  if defined (__QNXNTO__)
     488             :     netmgr_ndtostr(ND2S_LOCAL_STR, ND_LOCAL_NODE, node_name, sizeof(node_name));
     489             : #  else
     490             :     qnx_nidtostr (getnid (), node_name, sizeof (node_name));
     491             : #  endif
     492             :     temp_var = bind_variable ("NODE", node_name, 0);
     493             :     if (temp_var)
     494             :       set_auto_export (temp_var);
     495             :   }
     496             : #endif
     497             : 
     498             :   /* set up the prompts. */
     499     9542884 :   if (interactive_shell)
     500             :     {
     501             : #if defined (PROMPT_STRING_DECODE)
     502           0 :       set_if_not ("PS1", primary_prompt);
     503             : #else
     504             :       if (current_user.uid == -1)
     505             :         get_current_user_info ();
     506             :       set_if_not ("PS1", current_user.euid == 0 ? "# " : primary_prompt);
     507             : #endif
     508           0 :       set_if_not ("PS2", secondary_prompt);
     509             :     }
     510             : 
     511     9542884 :   if (current_user.euid == 0)
     512           0 :     bind_variable ("PS4", "+ ", 0);
     513             :   else
     514     9542884 :     set_if_not ("PS4", "+ ");
     515             : 
     516             :   /* Don't allow IFS to be imported from the environment. */
     517     9542884 :   temp_var = bind_variable ("IFS", " \t\n", 0);
     518     9542884 :   setifs (temp_var);
     519             : 
     520             :   /* Magic machine types.  Pretty convenient. */
     521     9542884 :   set_machine_vars ();
     522             : 
     523             :   /* Default MAILCHECK for interactive shells.  Defer the creation of a
     524             :      default MAILPATH until the startup files are read, because MAIL
     525             :      names a mail file if MAILPATH is not set, and we should provide a
     526             :      default only if neither is set. */
     527     9542884 :   if (interactive_shell)
     528             :     {
     529           0 :       temp_var = set_if_not ("MAILCHECK", posixly_correct ? "600" : "60");
     530           0 :       VSETATTR (temp_var, att_integer);
     531             :     }
     532             : 
     533             :   /* Do some things with shell level. */
     534     9542884 :   initialize_shell_level ();
     535             : 
     536     9542884 :   set_ppid ();
     537             : 
     538             :   /* Initialize the `getopts' stuff. */
     539     9542884 :   temp_var = bind_variable ("OPTIND", "1", 0);
     540     9542884 :   VSETATTR (temp_var, att_integer);
     541     9542884 :   getopts_reset (0);
     542     9542884 :   bind_variable ("OPTERR", "1", 0);
     543     9542884 :   sh_opterr = 1;
     544             : 
     545     9542884 :   if (login_shell == 1 && posixly_correct == 0)
     546           0 :     set_home_var ();
     547             : 
     548             :   /* Get the full pathname to THIS shell, and set the BASH variable
     549             :      to it. */
     550     9542884 :   name = get_bash_name ();
     551     9542884 :   temp_var = bind_variable ("BASH", name, 0);
     552     9542884 :   free (name);
     553             : 
     554             :   /* Make the exported environment variable SHELL be the user's login
     555             :      shell.  Note that the `tset' command looks at this variable
     556             :      to determine what style of commands to output; if it ends in "csh",
     557             :      then C-shell commands are output, else Bourne shell commands. */
     558     9542884 :   set_shell_var ();
     559             : 
     560             :   /* Make a variable called BASH_VERSION which contains the version info. */
     561     9542884 :   bind_variable ("BASH_VERSION", shell_version_string (), 0);
     562             : #if defined (ARRAY_VARS)
     563     9542884 :   make_vers_array ();
     564             : #endif
     565             : 
     566     9542884 :   if (command_execution_string)
     567           0 :     bind_variable ("BASH_EXECUTION_STRING", command_execution_string, 0);
     568             : 
     569             :   /* Find out if we're supposed to be in Posix.2 mode via an
     570             :      environment variable. */
     571     9542884 :   temp_var = find_variable ("POSIXLY_CORRECT");
     572     9542884 :   if (!temp_var)
     573     9542884 :     temp_var = find_variable ("POSIX_PEDANTIC");
     574     9542884 :   if (temp_var && imported_p (temp_var))
     575           0 :     sv_strict_posix (temp_var->name);
     576             : 
     577             : #if defined (HISTORY)
     578             :   /* Set history variables to defaults, and then do whatever we would
     579             :      do if the variable had just been set.  Do this only in the case
     580             :      that we are remembering commands on the history list. */
     581             :   if (remember_on_history)
     582             :     {
     583             :       name = bash_tilde_expand (posixly_correct ? "~/.sh_history" : "~/.bash_history", 0);
     584             : 
     585             :       set_if_not ("HISTFILE", name);
     586             :       free (name);
     587             :     }
     588             : #endif /* HISTORY */
     589             : 
     590             :   /* Seed the random number generator. */
     591     9542884 :   seedrand ();
     592             : 
     593             :   /* Handle some "special" variables that we may have inherited from a
     594             :      parent shell. */
     595     9542884 :   if (interactive_shell)
     596             :     {
     597           0 :       temp_var = find_variable ("IGNOREEOF");
     598           0 :       if (!temp_var)
     599           0 :         temp_var = find_variable ("ignoreeof");
     600           0 :       if (temp_var && imported_p (temp_var))
     601           0 :         sv_ignoreeof (temp_var->name);
     602             :     }
     603             : 
     604             : #if defined (HISTORY)
     605             :   if (interactive_shell && remember_on_history)
     606             :     {
     607             :       sv_history_control ("HISTCONTROL");
     608             :       sv_histignore ("HISTIGNORE");
     609             :       sv_histtimefmt ("HISTTIMEFORMAT");
     610             :     }
     611             : #endif /* HISTORY */
     612             : 
     613             : #if defined (READLINE) && defined (STRICT_POSIX)
     614             :   /* POSIXLY_CORRECT will only be 1 here if the shell was compiled
     615             :      -DSTRICT_POSIX */
     616             :   if (interactive_shell && posixly_correct && no_line_editing == 0)
     617             :     rl_prefer_env_winsize = 1;
     618             : #endif /* READLINE && STRICT_POSIX */
     619             : 
     620             :      /*
     621             :       * 24 October 2001
     622             :       *
     623             :       * I'm tired of the arguing and bug reports.  Bash now leaves SSH_CLIENT
     624             :       * and SSH2_CLIENT alone.  I'm going to rely on the shell_level check in
     625             :       * isnetconn() to avoid running the startup files more often than wanted.
     626             :       * That will, of course, only work if the user's login shell is bash, so
     627             :       * I've made that behavior conditional on SSH_SOURCE_BASHRC being defined
     628             :       * in config-top.h.
     629             :       */
     630             : #if 0
     631             :   temp_var = find_variable ("SSH_CLIENT");
     632             :   if (temp_var && imported_p (temp_var))
     633             :     {
     634             :       VUNSETATTR (temp_var, att_exported);
     635             :       array_needs_making = 1;
     636             :     }
     637             :   temp_var = find_variable ("SSH2_CLIENT");
     638             :   if (temp_var && imported_p (temp_var))
     639             :     {
     640             :       VUNSETATTR (temp_var, att_exported);
     641             :       array_needs_making = 1;
     642             :     }
     643             : #endif
     644             : 
     645             :   /* Get the user's real and effective user ids. */
     646     9542884 :   uidset ();
     647             : 
     648     9542884 :   temp_var = find_variable ("BASH_XTRACEFD");
     649     9542884 :   if (temp_var && imported_p (temp_var))
     650           0 :     sv_xtracefd (temp_var->name);
     651             : 
     652     9542884 :   sv_shcompat ("BASH_COMPAT");
     653             : 
     654             :   /* Allow FUNCNEST to be inherited from the environment. */
     655     9542884 :   sv_funcnest ("FUNCNEST");
     656             : 
     657             :   /* Initialize the dynamic variables, and seed their values. */
     658     9542884 :   initialize_dynamic_variables ();
     659     9542884 : }
     660             : 
     661             : /* **************************************************************** */
     662             : /*                                                                  */
     663             : /*           Setting values for special shell variables             */
     664             : /*                                                                  */
     665             : /* **************************************************************** */
     666             : 
     667             : static void
     668     9542884 : set_machine_vars ()
     669             : {
     670     9542884 :   set_if_not ("HOSTTYPE", HOSTTYPE);
     671     9542884 :   set_if_not ("OSTYPE", OSTYPE);
     672     9542884 :   set_if_not ("MACHTYPE", MACHTYPE);
     673             : 
     674     9542884 :   set_if_not ("HOSTNAME", current_host_name);
     675     9542884 : }
     676             : 
     677             : /* Set $HOME to the information in the password file if we didn't get
     678             :    it from the environment. */
     679             : 
     680             : /* This function is not static so the tilde and readline libraries can
     681             :    use it. */
     682             : char *
     683           0 : sh_get_home_dir ()
     684             : {
     685           0 :   if (current_user.home_dir == 0)
     686           0 :     get_current_user_info ();
     687           0 :   return current_user.home_dir;
     688             : }
     689             : 
     690             : static void
     691           0 : set_home_var ()
     692             : {
     693           0 :   SHELL_VAR *temp_var;
     694             : 
     695           0 :   temp_var = find_variable ("HOME");
     696           0 :   if (temp_var == 0)
     697           0 :     temp_var = bind_variable ("HOME", sh_get_home_dir (), 0);
     698             : #if 0
     699             :   VSETATTR (temp_var, att_exported);
     700             : #endif
     701           0 : }
     702             : 
     703             : /* Set $SHELL to the user's login shell if it is not already set.  Call
     704             :    get_current_user_info if we haven't already fetched the shell. */
     705             : static void
     706     9542884 : set_shell_var ()
     707             : {
     708     9542884 :   SHELL_VAR *temp_var;
     709             : 
     710     9542884 :   temp_var = find_variable ("SHELL");
     711     9542884 :   if (temp_var == 0)
     712             :     {
     713           0 :       if (current_user.shell == 0)
     714           0 :         get_current_user_info ();
     715           0 :       temp_var = bind_variable ("SHELL", current_user.shell, 0);
     716             :     }
     717             : #if 0
     718             :   VSETATTR (temp_var, att_exported);
     719             : #endif
     720     9542884 : }
     721             : 
     722             : static char *
     723     9542884 : get_bash_name ()
     724             : {
     725     9542884 :   char *name;
     726             : 
     727     9542884 :   if ((login_shell == 1) && RELPATH(shell_name))
     728             :     {
     729           0 :       if (current_user.shell == 0)
     730           0 :         get_current_user_info ();
     731           0 :       name = savestring (current_user.shell);
     732             :     }
     733     9542884 :   else if (ABSPATH(shell_name))
     734     9542884 :     name = savestring (shell_name);
     735           0 :   else if (shell_name[0] == '.' && shell_name[1] == '/')
     736             :     {
     737             :       /* Fast path for common case. */
     738           0 :       char *cdir;
     739           0 :       int len;
     740             : 
     741           0 :       cdir = get_string_value ("PWD");
     742           0 :       if (cdir)
     743             :         {
     744           0 :           len = strlen (cdir);
     745           0 :           name = (char *)xmalloc (len + strlen (shell_name) + 1);
     746           0 :           strcpy (name, cdir);
     747           0 :           strcpy (name + len, shell_name + 1);
     748             :         }
     749             :       else
     750           0 :         name = savestring (shell_name);
     751             :     }
     752             :   else
     753             :     {
     754           0 :       char *tname;
     755           0 :       int s;
     756             : 
     757           0 :       tname = find_user_command (shell_name);
     758             : 
     759           0 :       if (tname == 0)
     760             :         {
     761             :           /* Try the current directory.  If there is not an executable
     762             :              there, just punt and use the login shell. */
     763           0 :           s = file_status (shell_name);
     764           0 :           if (s & FS_EXECABLE)
     765             :             {
     766           0 :               tname = make_absolute (shell_name, get_string_value ("PWD"));
     767           0 :               if (*shell_name == '.')
     768             :                 {
     769           0 :                   name = sh_canonpath (tname, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
     770           0 :                   if (name == 0)
     771             :                     name = tname;
     772             :                   else
     773           0 :                     free (tname);
     774             :                 }
     775             :              else
     776             :                 name = tname;
     777             :             }
     778             :           else
     779             :             {
     780           0 :               if (current_user.shell == 0)
     781           0 :                 get_current_user_info ();
     782           0 :               name = savestring (current_user.shell);
     783             :             }
     784             :         }
     785             :       else
     786             :         {
     787           0 :           name = full_pathname (tname);
     788           0 :           free (tname);
     789             :         }
     790             :     }
     791             : 
     792     9542884 :   return (name);
     793             : }
     794             : 
     795             : void
     796     9542884 : adjust_shell_level (change)
     797             :      int change;
     798             : {
     799     9542884 :   char new_level[5], *old_SHLVL;
     800     9542884 :   intmax_t old_level;
     801     9542884 :   SHELL_VAR *temp_var;
     802             : 
     803     9542884 :   old_SHLVL = get_string_value ("SHLVL");
     804     9542884 :   if (old_SHLVL == 0 || *old_SHLVL == '\0' || legal_number (old_SHLVL, &old_level) == 0)
     805           0 :     old_level = 0;
     806             : 
     807     9542884 :   shell_level = old_level + change;
     808     9542884 :   if (shell_level < 0)
     809           0 :     shell_level = 0;
     810     9542884 :   else if (shell_level >= 1000)
     811             :     {
     812           0 :       internal_warning (_("shell level (%d) too high, resetting to 1"), shell_level);
     813           0 :       shell_level = 1;
     814             :     }
     815             : 
     816             :   /* We don't need the full generality of itos here. */
     817     9542884 :   if (shell_level < 10)
     818             :     {
     819     9542884 :       new_level[0] = shell_level + '0';
     820     9542884 :       new_level[1] = '\0';
     821             :     }
     822           0 :   else if (shell_level < 100)
     823             :     {
     824           0 :       new_level[0] = (shell_level / 10) + '0';
     825           0 :       new_level[1] = (shell_level % 10) + '0';
     826           0 :       new_level[2] = '\0';
     827             :     }
     828           0 :   else if (shell_level < 1000)
     829             :     {
     830           0 :       new_level[0] = (shell_level / 100) + '0';
     831           0 :       old_level = shell_level % 100;
     832           0 :       new_level[1] = (old_level / 10) + '0';
     833           0 :       new_level[2] = (old_level % 10) + '0';
     834           0 :       new_level[3] = '\0';
     835             :     }
     836             : 
     837     9542884 :   temp_var = bind_variable ("SHLVL", new_level, 0);
     838     9542884 :   set_auto_export (temp_var);
     839     9542884 : }
     840             : 
     841             : static void
     842             : initialize_shell_level ()
     843             : {
     844     9542884 :   adjust_shell_level (1);
     845             : }
     846             : 
     847             : /* If we got PWD from the environment, update our idea of the current
     848             :    working directory.  In any case, make sure that PWD exists before
     849             :    checking it.  It is possible for getcwd () to fail on shell startup,
     850             :    and in that case, PWD would be undefined.  If this is an interactive
     851             :    login shell, see if $HOME is the current working directory, and if
     852             :    that's not the same string as $PWD, set PWD=$HOME. */
     853             : 
     854             : void
     855     9542884 : set_pwd ()
     856             : {
     857     9542884 :   SHELL_VAR *temp_var, *home_var;
     858     9542884 :   char *temp_string, *home_string, *current_dir;
     859             : 
     860     9542884 :   home_var = find_variable ("HOME");
     861     9542884 :   home_string = home_var ? value_cell (home_var) : (char *)NULL;
     862             : 
     863     9542884 :   temp_var = find_variable ("PWD");
     864             :   /* Follow posix rules for importing PWD */
     865     9542884 :   if (temp_var && imported_p (temp_var) &&
     866     9542884 :       (temp_string = value_cell (temp_var)) &&
     867    19085768 :       temp_string[0] == '/' &&
     868     9542884 :       same_file (temp_string, ".", (struct stat *)NULL, (struct stat *)NULL))
     869             :     {
     870     9542884 :       current_dir = sh_canonpath (temp_string, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
     871     9542884 :       if (current_dir == 0)
     872           0 :         current_dir = get_working_directory ("shell_init");
     873             :       else 
     874     9542884 :         set_working_directory (current_dir);
     875     9542884 :       free (current_dir);
     876             :     }
     877           0 :   else if (home_string && interactive_shell && login_shell &&
     878           0 :            same_file (home_string, ".", (struct stat *)NULL, (struct stat *)NULL))
     879             :     {
     880           0 :       set_working_directory (home_string);
     881           0 :       temp_var = bind_variable ("PWD", home_string, 0);
     882           0 :       set_auto_export (temp_var);
     883             :     }
     884             :   else
     885             :     {
     886           0 :       temp_string = get_working_directory ("shell-init");
     887           0 :       if (temp_string)
     888             :         {
     889           0 :           temp_var = bind_variable ("PWD", temp_string, 0);
     890           0 :           set_auto_export (temp_var);
     891           0 :           free (temp_string);
     892             :         }
     893             :     }
     894             : 
     895             :   /* According to the Single Unix Specification, v2, $OLDPWD is an
     896             :      `environment variable' and therefore should be auto-exported.  If we
     897             :      don't find OLDPWD in the environment, or it doesn't name a directory,
     898             :      make a dummy invisible variable for OLDPWD, and mark it as exported. */
     899     9542884 :   temp_var = find_variable ("OLDPWD");
     900     9542884 :   if (temp_var == 0 || value_cell (temp_var) == 0 || file_isdir (value_cell (temp_var)) == 0)
     901             :     {
     902           0 :       temp_var = bind_variable ("OLDPWD", (char *)NULL, 0);
     903           0 :       VSETATTR (temp_var, (att_exported | att_invisible));
     904             :     }
     905     9542884 : }
     906             : 
     907             : /* Make a variable $PPID, which holds the pid of the shell's parent.  */
     908             : void
     909     9542884 : set_ppid ()
     910             : {
     911     9542884 :   char namebuf[INT_STRLEN_BOUND(pid_t) + 1], *name;
     912     9542884 :   SHELL_VAR *temp_var;
     913             : 
     914     9542884 :   name = inttostr (getppid (), namebuf, sizeof(namebuf));
     915     9542884 :   temp_var = find_variable ("PPID");
     916     9542884 :   if (temp_var)
     917           0 :     VUNSETATTR (temp_var, (att_readonly | att_exported));
     918     9542884 :   temp_var = bind_variable ("PPID", name, 0);
     919     9542884 :   VSETATTR (temp_var, (att_readonly | att_integer));
     920     9542884 : }
     921             : 
     922             : static void
     923     9542884 : uidset ()
     924             : {
     925     9542884 :   char buff[INT_STRLEN_BOUND(uid_t) + 1], *b;
     926     9542884 :   register SHELL_VAR *v;
     927             : 
     928     9542884 :   b = inttostr (current_user.uid, buff, sizeof (buff));
     929     9542884 :   v = find_variable ("UID");
     930     9542884 :   if (v == 0)
     931             :     {
     932     9542884 :       v = bind_variable ("UID", b, 0);
     933     9542884 :       VSETATTR (v, (att_readonly | att_integer));
     934             :     }
     935             : 
     936     9542884 :   if (current_user.euid != current_user.uid)
     937           0 :     b = inttostr (current_user.euid, buff, sizeof (buff));
     938             : 
     939     9542884 :   v = find_variable ("EUID");
     940     9542884 :   if (v == 0)
     941             :     {
     942     9542884 :       v = bind_variable ("EUID", b, 0);
     943     9542884 :       VSETATTR (v, (att_readonly | att_integer));
     944             :     }
     945     9542884 : }
     946             : 
     947             : #if defined (ARRAY_VARS)
     948             : static void
     949     9542884 : make_vers_array ()
     950             : {
     951     9542884 :   SHELL_VAR *vv;
     952     9542884 :   ARRAY *av;
     953     9542884 :   char *s, d[32], b[INT_STRLEN_BOUND(int) + 1];
     954             : 
     955     9542884 :   unbind_variable_noref ("BASH_VERSINFO");
     956             : 
     957     9542884 :   vv = make_new_array_variable ("BASH_VERSINFO");
     958     9542884 :   av = array_cell (vv);
     959     9542884 :   strcpy (d, dist_version);
     960     9542884 :   s = strchr (d, '.');
     961     9542884 :   if (s)
     962     9542884 :     *s++ = '\0';
     963     9542884 :   array_insert (av, 0, d);
     964     9542884 :   array_insert (av, 1, s);
     965     9542884 :   s = inttostr (patch_level, b, sizeof (b));
     966     9542884 :   array_insert (av, 2, s);
     967     9542884 :   s = inttostr (build_version, b, sizeof (b));
     968     9542884 :   array_insert (av, 3, s);
     969     9542884 :   array_insert (av, 4, release_status);
     970     9542884 :   array_insert (av, 5, MACHTYPE);
     971             : 
     972     9542884 :   VSETATTR (vv, att_readonly);
     973     9542884 : }
     974             : #endif /* ARRAY_VARS */
     975             : 
     976             : /* Set the environment variables $LINES and $COLUMNS in response to
     977             :    a window size change. */
     978             : void
     979           0 : sh_set_lines_and_columns (lines, cols)
     980             :      int lines, cols;
     981             : {
     982           0 :   char val[INT_STRLEN_BOUND(int) + 1], *v;
     983             : 
     984             : #if defined (READLINE)
     985             :   /* If we are currently assigning to LINES or COLUMNS, don't do anything. */
     986             :   if (winsize_assignment)
     987             :     return;
     988             : #endif
     989             : 
     990           0 :   v = inttostr (lines, val, sizeof (val));
     991           0 :   bind_variable ("LINES", v, 0);
     992             : 
     993           0 :   v = inttostr (cols, val, sizeof (val));
     994           0 :   bind_variable ("COLUMNS", v, 0);
     995           0 : }
     996             : 
     997             : /* **************************************************************** */
     998             : /*                                                                  */
     999             : /*                 Printing variables and values                    */
    1000             : /*                                                                  */
    1001             : /* **************************************************************** */
    1002             : 
    1003             : /* Print LIST (a list of shell variables) to stdout in such a way that
    1004             :    they can be read back in. */
    1005             : void
    1006         157 : print_var_list (list)
    1007             :      register SHELL_VAR **list;
    1008             : {
    1009         157 :   register int i;
    1010         157 :   register SHELL_VAR *var;
    1011             : 
    1012       11109 :   for (i = 0; list && (var = list[i]); i++)
    1013       10952 :     if (invisible_p (var) == 0)
    1014       10795 :       print_assignment (var);
    1015         157 : }
    1016             : 
    1017             : /* Print LIST (a list of shell functions) to stdout in such a way that
    1018             :    they can be read back in. */
    1019             : void
    1020          64 : print_func_list (list)
    1021             :      register SHELL_VAR **list;
    1022             : {
    1023          64 :   register int i;
    1024          64 :   register SHELL_VAR *var;
    1025             : 
    1026         207 :   for (i = 0; list && (var = list[i]); i++)
    1027             :     {
    1028         143 :       printf ("%s ", var->name);
    1029         143 :       print_var_function (var);
    1030         143 :       printf ("\n");
    1031             :     }
    1032          64 : }
    1033             :       
    1034             : /* Print the value of a single SHELL_VAR.  No newline is
    1035             :    output, but the variable is printed in such a way that
    1036             :    it can be read back in. */
    1037             : void
    1038       10795 : print_assignment (var)
    1039             :      SHELL_VAR *var;
    1040             : {
    1041       10795 :   if (var_isset (var) == 0)
    1042             :     return;
    1043             : 
    1044        9853 :   if (function_p (var))
    1045             :     {
    1046           0 :       printf ("%s", var->name);
    1047           0 :       print_var_function (var);
    1048           0 :       printf ("\n");
    1049             :     }
    1050             : #if defined (ARRAY_VARS)
    1051        9853 :   else if (array_p (var))
    1052        1256 :     print_array_assignment (var, 0);
    1053        8597 :   else if (assoc_p (var))
    1054         314 :     print_assoc_assignment (var, 0);
    1055             : #endif /* ARRAY_VARS */
    1056             :   else
    1057             :     {
    1058        8283 :       printf ("%s=", var->name);
    1059        8283 :       print_var_value (var, 1);
    1060        8283 :       printf ("\n");
    1061             :     }
    1062             : }
    1063             : 
    1064             : /* Print the value cell of VAR, a shell variable.  Do not print
    1065             :    the name, nor leading/trailing newline.  If QUOTE is non-zero,
    1066             :    and the value contains shell metacharacters, quote the value
    1067             :    in such a way that it can be read back in. */
    1068             : void
    1069        8283 : print_var_value (var, quote)
    1070             :      SHELL_VAR *var;
    1071             :      int quote;
    1072             : {
    1073        8283 :   char *t;
    1074             : 
    1075        8283 :   if (var_isset (var) == 0)
    1076             :     return;
    1077             : 
    1078        8283 :   if (quote && posixly_correct == 0 && ansic_shouldquote (value_cell (var)))
    1079             :     {
    1080         157 :       t = ansic_quote (value_cell (var), 0, (int *)0);
    1081         157 :       printf ("%s", t);
    1082         157 :       free (t);
    1083             :     }
    1084        8126 :   else if (quote && sh_contains_shell_metas (value_cell (var)))
    1085             :     {
    1086        1110 :       t = sh_single_quote (value_cell (var));
    1087        1110 :       printf ("%s", t);
    1088        1110 :       free (t);
    1089             :     }
    1090             :   else
    1091        7016 :     printf ("%s", value_cell (var));
    1092             : }
    1093             : 
    1094             : /* Print the function cell of VAR, a shell variable.  Do not
    1095             :    print the name, nor leading/trailing newline. */
    1096             : void
    1097         143 : print_var_function (var)
    1098             :      SHELL_VAR *var;
    1099             : {
    1100         143 :   char *x;
    1101             : 
    1102         143 :   if (function_p (var) && var_isset (var))
    1103             :     {
    1104         143 :       x = named_function_string ((char *)NULL, function_cell(var), FUNC_MULTILINE|FUNC_EXTERNAL);
    1105         143 :       printf ("%s", x);
    1106             :     }
    1107         143 : }
    1108             : 
    1109             : /* **************************************************************** */
    1110             : /*                                                                  */
    1111             : /*                      Dynamic Variables                           */
    1112             : /*                                                                  */
    1113             : /* **************************************************************** */
    1114             : 
    1115             : /* DYNAMIC VARIABLES
    1116             : 
    1117             :    These are variables whose values are generated anew each time they are
    1118             :    referenced.  These are implemented using a pair of function pointers
    1119             :    in the struct variable: assign_func, which is called from bind_variable
    1120             :    and, if arrays are compiled into the shell, some of the functions in
    1121             :    arrayfunc.c, and dynamic_value, which is called from find_variable.
    1122             : 
    1123             :    assign_func is called from bind_variable_internal, if
    1124             :    bind_variable_internal discovers that the variable being assigned to
    1125             :    has such a function.  The function is called as
    1126             :         SHELL_VAR *temp = (*(entry->assign_func)) (entry, value, ind)
    1127             :    and the (SHELL_VAR *)temp is returned as the value of bind_variable.  It
    1128             :    is usually ENTRY (self).  IND is an index for an array variable, and
    1129             :    unused otherwise.
    1130             : 
    1131             :    dynamic_value is called from find_variable_internal to return a `new'
    1132             :    value for the specified dynamic varible.  If this function is NULL,
    1133             :    the variable is treated as a `normal' shell variable.  If it is not,
    1134             :    however, then this function is called like this:
    1135             :         tempvar = (*(var->dynamic_value)) (var);
    1136             : 
    1137             :    Sometimes `tempvar' will replace the value of `var'.  Other times, the
    1138             :    shell will simply use the string value.  Pretty object-oriented, huh?
    1139             : 
    1140             :    Be warned, though: if you `unset' a special variable, it loses its
    1141             :    special meaning, even if you subsequently set it.
    1142             : 
    1143             :    The special assignment code would probably have been better put in
    1144             :    subst.c: do_assignment_internal, in the same style as
    1145             :    stupidly_hack_special_variables, but I wanted the changes as
    1146             :    localized as possible.  */
    1147             : 
    1148             : #define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \
    1149             :   do \
    1150             :     { \
    1151             :       v = bind_variable (var, (val), 0); \
    1152             :       v->dynamic_value = gfunc; \
    1153             :       v->assign_func = afunc; \
    1154             :     } \
    1155             :   while (0)
    1156             : 
    1157             : #define INIT_DYNAMIC_ARRAY_VAR(var, gfunc, afunc) \
    1158             :   do \
    1159             :     { \
    1160             :       v = make_new_array_variable (var); \
    1161             :       v->dynamic_value = gfunc; \
    1162             :       v->assign_func = afunc; \
    1163             :     } \
    1164             :   while (0)
    1165             : 
    1166             : #define INIT_DYNAMIC_ASSOC_VAR(var, gfunc, afunc) \
    1167             :   do \
    1168             :     { \
    1169             :       v = make_new_assoc_variable (var); \
    1170             :       v->dynamic_value = gfunc; \
    1171             :       v->assign_func = afunc; \
    1172             :     } \
    1173             :   while (0)
    1174             : 
    1175             : static SHELL_VAR *
    1176           0 : null_assign (self, value, unused, key)
    1177             :      SHELL_VAR *self;
    1178             :      char *value;
    1179             :      arrayind_t unused;
    1180             :      char *key;
    1181             : {
    1182           0 :   return (self);
    1183             : }
    1184             : 
    1185             : #if defined (ARRAY_VARS)
    1186             : static SHELL_VAR *
    1187           0 : null_array_assign (self, value, ind, key)
    1188             :      SHELL_VAR *self;
    1189             :      char *value;
    1190             :      arrayind_t ind;
    1191             :      char *key;
    1192             : {
    1193           0 :   return (self);
    1194             : }
    1195             : #endif
    1196             : 
    1197             : /* Degenerate `dynamic_value' function; just returns what's passed without
    1198             :    manipulation. */
    1199             : static SHELL_VAR *
    1200   159697131 : get_self (self)
    1201             :      SHELL_VAR *self;
    1202             : {
    1203   159697131 :   return (self);
    1204             : }
    1205             : 
    1206             : #if defined (ARRAY_VARS)
    1207             : /* A generic dynamic array variable initializer.  Initialize array variable
    1208             :    NAME with dynamic value function GETFUNC and assignment function SETFUNC. */
    1209             : static SHELL_VAR *
    1210    47714420 : init_dynamic_array_var (name, getfunc, setfunc, attrs)
    1211             :      char *name;
    1212             :      sh_var_value_func_t *getfunc;
    1213             :      sh_var_assign_func_t *setfunc;
    1214             :      int attrs;
    1215             : {
    1216    57257304 :   SHELL_VAR *v;
    1217             : 
    1218    47714420 :   v = find_variable (name);
    1219    57257304 :   if (v)
    1220             :     return (v);
    1221    57257304 :   INIT_DYNAMIC_ARRAY_VAR (name, getfunc, setfunc);
    1222    57257304 :   if (attrs)
    1223    47714420 :     VSETATTR (v, attrs);
    1224             :   return v;
    1225             : }
    1226             : 
    1227             : static SHELL_VAR *
    1228    19085768 : init_dynamic_assoc_var (name, getfunc, setfunc, attrs)
    1229             :      char *name;
    1230             :      sh_var_value_func_t *getfunc;
    1231             :      sh_var_assign_func_t *setfunc;
    1232             :      int attrs;
    1233             : {
    1234    19085768 :   SHELL_VAR *v;
    1235             : 
    1236    19085768 :   v = find_variable (name);
    1237    19085768 :   if (v)
    1238             :     return (v);
    1239    19085768 :   INIT_DYNAMIC_ASSOC_VAR (name, getfunc, setfunc);
    1240    19085768 :   if (attrs)
    1241    19085768 :     VSETATTR (v, attrs);
    1242             :   return v;
    1243             : }
    1244             : #endif
    1245             : 
    1246             : /* The value of $SECONDS.  This is the number of seconds since shell
    1247             :    invocation, or, the number of seconds since the last assignment + the
    1248             :    value of the last assignment. */
    1249             : static intmax_t seconds_value_assigned;
    1250             : 
    1251             : static SHELL_VAR *
    1252           0 : assign_seconds (self, value, unused, key)
    1253             :      SHELL_VAR *self;
    1254             :      char *value;
    1255             :      arrayind_t unused;
    1256             :      char *key;
    1257             : {
    1258           0 :   if (legal_number (value, &seconds_value_assigned) == 0)
    1259           0 :     seconds_value_assigned = 0;
    1260           0 :   shell_start_time = NOW;
    1261           0 :   return (self);
    1262             : }
    1263             : 
    1264             : static SHELL_VAR *
    1265           0 : get_seconds (var)
    1266             :      SHELL_VAR *var;
    1267             : {
    1268           0 :   time_t time_since_start;
    1269           0 :   char *p;
    1270             : 
    1271           0 :   time_since_start = NOW - shell_start_time;
    1272           0 :   p = itos(seconds_value_assigned + time_since_start);
    1273             : 
    1274           0 :   FREE (value_cell (var));
    1275             : 
    1276           0 :   VSETATTR (var, att_integer);
    1277           0 :   var_setvalue (var, p);
    1278           0 :   return (var);
    1279             : }
    1280             : 
    1281             : static SHELL_VAR *
    1282     9542884 : init_seconds_var ()
    1283             : {
    1284     9542884 :   SHELL_VAR *v;
    1285             : 
    1286     9542884 :   v = find_variable ("SECONDS");
    1287     9542884 :   if (v)
    1288             :     {
    1289           0 :       if (legal_number (value_cell(v), &seconds_value_assigned) == 0)
    1290           0 :         seconds_value_assigned = 0;
    1291             :     }
    1292     9542884 :   INIT_DYNAMIC_VAR ("SECONDS", (v ? value_cell (v) : (char *)NULL), get_seconds, assign_seconds);
    1293     9542884 :   return v;      
    1294             : }
    1295             :      
    1296             : /* The random number seed.  You can change this by setting RANDOM. */
    1297             : static unsigned long rseed = 1;
    1298             : static int last_random_value;
    1299             : static int seeded_subshell = 0;
    1300             : 
    1301             : /* A linear congruential random number generator based on the example
    1302             :    one in the ANSI C standard.  This one isn't very good, but a more
    1303             :    complicated one is overkill. */
    1304             : 
    1305             : /* Returns a pseudo-random number between 0 and 32767. */
    1306             : static int
    1307             : brand ()
    1308             : {
    1309             :   /* From "Random number generators: good ones are hard to find",
    1310             :      Park and Miller, Communications of the ACM, vol. 31, no. 10,
    1311             :      October 1988, p. 1195. filtered through FreeBSD */
    1312           0 :   long h, l;
    1313             : 
    1314             :   /* Can't seed with 0. */
    1315           0 :   if (rseed == 0)
    1316           0 :     rseed = 123459876;
    1317           0 :   h = rseed / 127773;
    1318           0 :   l = rseed % 127773;
    1319           0 :   rseed = 16807 * l - 2836 * h;
    1320             : #if 0
    1321             :   if (rseed < 0)
    1322             :     rseed += 0x7fffffff;
    1323             : #endif
    1324           0 :   return ((unsigned int)(rseed & 32767));   /* was % 32768 */
    1325             : }
    1326             : 
    1327             : /* Set the random number generator seed to SEED. */
    1328             : static void
    1329             : sbrand (seed)
    1330             :      unsigned long seed;
    1331             : {
    1332     9542884 :   rseed = seed;
    1333     9542884 :   last_random_value = 0;
    1334             : }
    1335             : 
    1336             : static void
    1337     9542884 : seedrand ()
    1338             : {
    1339     9542884 :   struct timeval tv;
    1340             : 
    1341     9542884 :   gettimeofday (&tv, NULL);
    1342     9542884 :   sbrand (tv.tv_sec ^ tv.tv_usec ^ getpid ());
    1343     9542884 : }
    1344             : 
    1345             : static SHELL_VAR *
    1346           0 : assign_random (self, value, unused, key)
    1347             :      SHELL_VAR *self;
    1348             :      char *value;
    1349             :      arrayind_t unused;
    1350             :      char *key;
    1351             : {
    1352           0 :   sbrand (strtoul (value, (char **)NULL, 10));
    1353           0 :   if (subshell_environment)
    1354           0 :     seeded_subshell = getpid ();
    1355           0 :   return (self);
    1356             : }
    1357             : 
    1358             : int
    1359           0 : get_random_number ()
    1360             : {
    1361           0 :   int rv, pid;
    1362             : 
    1363             :   /* Reset for command and process substitution. */
    1364           0 :   pid = getpid ();
    1365           0 :   if (subshell_environment && seeded_subshell != pid)
    1366             :     {
    1367           0 :       seedrand ();
    1368           0 :       seeded_subshell = pid;
    1369             :     }
    1370             : 
    1371           0 :   do
    1372           0 :     rv = brand ();
    1373           0 :   while (rv == last_random_value);
    1374           0 :   return rv;
    1375             : }
    1376             : 
    1377             : static SHELL_VAR *
    1378           0 : get_random (var)
    1379             :      SHELL_VAR *var;
    1380             : {
    1381           0 :   int rv;
    1382           0 :   char *p;
    1383             : 
    1384           0 :   rv = get_random_number ();
    1385           0 :   last_random_value = rv;
    1386           0 :   p = itos (rv);
    1387             : 
    1388           0 :   FREE (value_cell (var));
    1389             : 
    1390           0 :   VSETATTR (var, att_integer);
    1391           0 :   var_setvalue (var, p);
    1392           0 :   return (var);
    1393             : }
    1394             : 
    1395             : static SHELL_VAR *
    1396           0 : assign_lineno (var, value, unused, key)
    1397             :      SHELL_VAR *var;
    1398             :      char *value;
    1399             :      arrayind_t unused;
    1400             :      char *key;
    1401             : {
    1402           0 :   intmax_t new_value;
    1403             : 
    1404           0 :   if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0)
    1405           0 :     new_value = 0;
    1406           0 :   line_number = line_number_base = new_value;
    1407           0 :   return var;
    1408             : }
    1409             : 
    1410             : /* Function which returns the current line number. */
    1411             : static SHELL_VAR *
    1412           0 : get_lineno (var)
    1413             :      SHELL_VAR *var;
    1414             : {
    1415           0 :   char *p;
    1416           0 :   int ln;
    1417             : 
    1418           0 :   ln = executing_line_number ();
    1419           0 :   p = itos (ln);
    1420           0 :   FREE (value_cell (var));
    1421           0 :   var_setvalue (var, p);
    1422           0 :   return (var);
    1423             : }
    1424             : 
    1425             : static SHELL_VAR *
    1426           0 : assign_subshell (var, value, unused, key)
    1427             :      SHELL_VAR *var;
    1428             :      char *value;
    1429             :      arrayind_t unused;
    1430             :      char *key;
    1431             : {
    1432           0 :   intmax_t new_value;
    1433             : 
    1434           0 :   if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0)
    1435           0 :     new_value = 0;
    1436           0 :   subshell_level = new_value;
    1437           0 :   return var;
    1438             : }
    1439             : 
    1440             : static SHELL_VAR *
    1441           0 : get_subshell (var)
    1442             :      SHELL_VAR *var;
    1443             : {
    1444           0 :   char *p;
    1445             : 
    1446           0 :   p = itos (subshell_level);
    1447           0 :   FREE (value_cell (var));
    1448           0 :   var_setvalue (var, p);
    1449           0 :   return (var);
    1450             : }
    1451             : 
    1452             : static SHELL_VAR *
    1453           0 : get_bashpid (var)
    1454             :      SHELL_VAR *var;
    1455             : {
    1456           0 :   int pid;
    1457           0 :   char *p;
    1458             : 
    1459           0 :   pid = getpid ();
    1460           0 :   p = itos (pid);
    1461             : 
    1462           0 :   FREE (value_cell (var));
    1463           0 :   VSETATTR (var, att_integer|att_readonly);
    1464           0 :   var_setvalue (var, p);
    1465           0 :   return (var);
    1466             : }
    1467             : 
    1468             : static SHELL_VAR *
    1469           0 : get_bash_command (var)
    1470             :      SHELL_VAR *var;
    1471             : {
    1472           0 :   char *p;
    1473             : 
    1474           0 :   if (the_printed_command_except_trap)
    1475           0 :     p = savestring (the_printed_command_except_trap);
    1476             :   else
    1477             :     {
    1478           0 :       p = (char *)xmalloc (1);
    1479           0 :       p[0] = '\0';
    1480             :     }
    1481           0 :   FREE (value_cell (var));
    1482           0 :   var_setvalue (var, p);
    1483           0 :   return (var);
    1484             : }
    1485             : 
    1486             : #if defined (HISTORY)
    1487             : static SHELL_VAR *
    1488             : get_histcmd (var)
    1489             :      SHELL_VAR *var;
    1490             : {
    1491             :   char *p;
    1492             : 
    1493             :   p = itos (history_number ());
    1494             :   FREE (value_cell (var));
    1495             :   var_setvalue (var, p);
    1496             :   return (var);
    1497             : }
    1498             : #endif
    1499             : 
    1500             : #if defined (READLINE)
    1501             : /* When this function returns, VAR->value points to malloced memory. */
    1502             : static SHELL_VAR *
    1503             : get_comp_wordbreaks (var)
    1504             :      SHELL_VAR *var;
    1505             : {
    1506             :   /* If we don't have anything yet, assign a default value. */
    1507             :   if (rl_completer_word_break_characters == 0 && bash_readline_initialized == 0)
    1508             :     enable_hostname_completion (perform_hostname_completion);
    1509             : 
    1510             :   FREE (value_cell (var));
    1511             :   var_setvalue (var, savestring (rl_completer_word_break_characters));
    1512             : 
    1513             :   return (var);
    1514             : }
    1515             : 
    1516             : /* When this function returns, rl_completer_word_break_characters points to
    1517             :    malloced memory. */
    1518             : static SHELL_VAR *
    1519             : assign_comp_wordbreaks (self, value, unused, key)
    1520             :      SHELL_VAR *self;
    1521             :      char *value;
    1522             :      arrayind_t unused;
    1523             :      char *key;
    1524             : {
    1525             :   if (rl_completer_word_break_characters &&
    1526             :       rl_completer_word_break_characters != rl_basic_word_break_characters)
    1527             :     free (rl_completer_word_break_characters);
    1528             : 
    1529             :   rl_completer_word_break_characters = savestring (value);
    1530             :   return self;
    1531             : }
    1532             : #endif /* READLINE */
    1533             : 
    1534             : #if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
    1535             : static SHELL_VAR *
    1536           0 : assign_dirstack (self, value, ind, key)
    1537             :      SHELL_VAR *self;
    1538             :      char *value;
    1539             :      arrayind_t ind;
    1540             :      char *key;
    1541             : {
    1542           0 :   set_dirstack_element (ind, 1, value);
    1543           0 :   return self;
    1544             : }
    1545             : 
    1546             : static SHELL_VAR *
    1547           0 : get_dirstack (self)
    1548             :      SHELL_VAR *self;
    1549             : {
    1550           0 :   ARRAY *a;
    1551           0 :   WORD_LIST *l;
    1552             : 
    1553           0 :   l = get_directory_stack (0);
    1554           0 :   a = array_from_word_list (l);
    1555           0 :   array_dispose (array_cell (self));
    1556           0 :   dispose_words (l);
    1557           0 :   var_setarray (self, a);
    1558           0 :   return self;
    1559             : }
    1560             : #endif /* PUSHD AND POPD && ARRAY_VARS */
    1561             : 
    1562             : #if defined (ARRAY_VARS)
    1563             : /* We don't want to initialize the group set with a call to getgroups()
    1564             :    unless we're asked to, but we only want to do it once. */
    1565             : static SHELL_VAR *
    1566           0 : get_groupset (self)
    1567             :      SHELL_VAR *self;
    1568             : {
    1569           0 :   register int i;
    1570           0 :   int ng;
    1571           0 :   ARRAY *a;
    1572           0 :   static char **group_set = (char **)NULL;
    1573             : 
    1574           0 :   if (group_set == 0)
    1575             :     {
    1576           0 :       group_set = get_group_list (&ng);
    1577           0 :       a = array_cell (self);
    1578           0 :       for (i = 0; i < ng; i++)
    1579           0 :         array_insert (a, i, group_set[i]);
    1580             :     }
    1581           0 :   return (self);
    1582             : }
    1583             : 
    1584             : static SHELL_VAR *
    1585           0 : build_hashcmd (self)
    1586             :      SHELL_VAR *self;
    1587             : {
    1588           0 :   HASH_TABLE *h;
    1589           0 :   int i;
    1590           0 :   char *k, *v;
    1591           0 :   BUCKET_CONTENTS *item;
    1592             : 
    1593           0 :   h = assoc_cell (self);
    1594           0 :   if (h)
    1595           0 :     assoc_dispose (h);
    1596             : 
    1597           0 :   if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0)
    1598             :     {
    1599           0 :       var_setvalue (self, (char *)NULL);
    1600           0 :       return self;
    1601             :     }
    1602             : 
    1603           0 :   h = assoc_create (hashed_filenames->nbuckets);
    1604           0 :   for (i = 0; i < hashed_filenames->nbuckets; i++)
    1605             :     {
    1606           0 :       for (item = hash_items (i, hashed_filenames); item; item = item->next)
    1607             :         {
    1608           0 :           k = savestring (item->key);
    1609           0 :           v = pathdata(item)->path;
    1610           0 :           assoc_insert (h, k, v);
    1611             :         }
    1612             :     }
    1613             : 
    1614           0 :   var_setvalue (self, (char *)h);
    1615           0 :   return self;
    1616             : }
    1617             : 
    1618             : static SHELL_VAR *
    1619           0 : get_hashcmd (self)
    1620             :      SHELL_VAR *self;
    1621             : {
    1622           0 :   build_hashcmd (self);
    1623           0 :   return (self);
    1624             : }
    1625             : 
    1626             : static SHELL_VAR *
    1627           0 : assign_hashcmd (self, value, ind, key)
    1628             :      SHELL_VAR *self;
    1629             :      char *value;
    1630             :      arrayind_t ind;
    1631             :      char *key;
    1632             : {
    1633             : #if defined (RESTRICTED_SHELL)
    1634             :   if (restricted && strchr (value, '/'))
    1635             :     {
    1636             :       sh_restricted (value);
    1637             :       return (SHELL_VAR *)NULL;
    1638             :     }
    1639             : #endif
    1640           0 :   phash_insert (key, value, 0, 0);
    1641           0 :   return (build_hashcmd (self));
    1642             : }
    1643             : 
    1644             : #if defined (ALIAS)
    1645             : static SHELL_VAR *
    1646           0 : build_aliasvar (self)
    1647             :      SHELL_VAR *self;
    1648             : {
    1649           0 :   HASH_TABLE *h;
    1650           0 :   int i;
    1651           0 :   char *k, *v;
    1652           0 :   BUCKET_CONTENTS *item;
    1653             : 
    1654           0 :   h = assoc_cell (self);
    1655           0 :   if (h)
    1656           0 :     assoc_dispose (h);
    1657             : 
    1658           0 :   if (aliases == 0 || HASH_ENTRIES (aliases) == 0)
    1659             :     {
    1660           0 :       var_setvalue (self, (char *)NULL);
    1661           0 :       return self;
    1662             :     }
    1663             : 
    1664           0 :   h = assoc_create (aliases->nbuckets);
    1665           0 :   for (i = 0; i < aliases->nbuckets; i++)
    1666             :     {
    1667           0 :       for (item = hash_items (i, aliases); item; item = item->next)
    1668             :         {
    1669           0 :           k = savestring (item->key);
    1670           0 :           v = ((alias_t *)(item->data))->value;
    1671           0 :           assoc_insert (h, k, v);
    1672             :         }
    1673             :     }
    1674             : 
    1675           0 :   var_setvalue (self, (char *)h);
    1676           0 :   return self;
    1677             : }
    1678             : 
    1679             : static SHELL_VAR *
    1680           0 : get_aliasvar (self)
    1681             :      SHELL_VAR *self;
    1682             : {
    1683           0 :   build_aliasvar (self);
    1684           0 :   return (self);
    1685             : }
    1686             : 
    1687             : static SHELL_VAR *
    1688           0 : assign_aliasvar (self, value, ind, key)
    1689             :      SHELL_VAR *self;
    1690             :      char *value;
    1691             :      arrayind_t ind;
    1692             :      char *key;
    1693             : {
    1694           0 :   add_alias (key, value);
    1695           0 :   return (build_aliasvar (self));
    1696             : }
    1697             : #endif /* ALIAS */
    1698             : 
    1699             : #endif /* ARRAY_VARS */
    1700             : 
    1701             : /* If ARRAY_VARS is not defined, this just returns the name of any
    1702             :    currently-executing function.  If we have arrays, it's a call stack. */
    1703             : static SHELL_VAR *
    1704    46462085 : get_funcname (self)
    1705             :      SHELL_VAR *self;
    1706             : {
    1707             : #if ! defined (ARRAY_VARS)
    1708             :   char *t;
    1709             :   if (variable_context && this_shell_function)
    1710             :     {
    1711             :       FREE (value_cell (self));
    1712             :       t = savestring (this_shell_function->name);
    1713             :       var_setvalue (self, t);
    1714             :     }
    1715             : #endif
    1716    46462085 :   return (self);
    1717             : }
    1718             : 
    1719             : void
    1720       17534 : make_funcname_visible (on_or_off)
    1721             :      int on_or_off;
    1722             : {
    1723       17534 :   SHELL_VAR *v;
    1724             : 
    1725       17534 :   v = find_variable ("FUNCNAME");
    1726       17534 :   if (v == 0 || v->dynamic_value == 0)
    1727             :     return;
    1728             : 
    1729       17534 :   if (on_or_off)
    1730       10077 :     VUNSETATTR (v, att_invisible);
    1731             :   else
    1732        7457 :     VSETATTR (v, att_invisible);
    1733             : }
    1734             : 
    1735             : static SHELL_VAR *
    1736     9542884 : init_funcname_var ()
    1737             : {
    1738     9542884 :   SHELL_VAR *v;
    1739             : 
    1740     9542884 :   v = find_variable ("FUNCNAME");
    1741     9542884 :   if (v)
    1742             :     return v;
    1743             : #if defined (ARRAY_VARS)
    1744     9542884 :   INIT_DYNAMIC_ARRAY_VAR ("FUNCNAME", get_funcname, null_array_assign);
    1745             : #else
    1746             :   INIT_DYNAMIC_VAR ("FUNCNAME", (char *)NULL, get_funcname, null_assign);
    1747             : #endif
    1748     9542884 :   VSETATTR (v, att_invisible|att_noassign);
    1749     9542884 :   return v;
    1750             : }
    1751             : 
    1752             : static void
    1753     9542884 : initialize_dynamic_variables ()
    1754             : {
    1755     9542884 :   SHELL_VAR *v;
    1756             : 
    1757     9542884 :   v = init_seconds_var ();
    1758             : 
    1759     9542884 :   INIT_DYNAMIC_VAR ("BASH_COMMAND", (char *)NULL, get_bash_command, (sh_var_assign_func_t *)NULL);
    1760     9542884 :   INIT_DYNAMIC_VAR ("BASH_SUBSHELL", (char *)NULL, get_subshell, assign_subshell);
    1761             : 
    1762     9542884 :   INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random);
    1763     9542884 :   VSETATTR (v, att_integer);
    1764     9542884 :   INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno);
    1765     9542884 :   VSETATTR (v, att_integer);
    1766             : 
    1767     9542884 :   INIT_DYNAMIC_VAR ("BASHPID", (char *)NULL, get_bashpid, null_assign);
    1768     9542884 :   VSETATTR (v, att_integer|att_readonly);
    1769             : 
    1770             : #if defined (HISTORY)
    1771             :   INIT_DYNAMIC_VAR ("HISTCMD", (char *)NULL, get_histcmd, (sh_var_assign_func_t *)NULL);
    1772             :   VSETATTR (v, att_integer);
    1773             : #endif
    1774             : 
    1775             : #if defined (READLINE)
    1776             :   INIT_DYNAMIC_VAR ("COMP_WORDBREAKS", (char *)NULL, get_comp_wordbreaks, assign_comp_wordbreaks);
    1777             : #endif
    1778             : 
    1779             : #if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
    1780     9542884 :   v = init_dynamic_array_var ("DIRSTACK", get_dirstack, assign_dirstack, 0);
    1781             : #endif /* PUSHD_AND_POPD && ARRAY_VARS */
    1782             : 
    1783             : #if defined (ARRAY_VARS)
    1784     9542884 :   v = init_dynamic_array_var ("GROUPS", get_groupset, null_array_assign, att_noassign);
    1785             : 
    1786             : #  if defined (DEBUGGER)
    1787     9542884 :   v = init_dynamic_array_var ("BASH_ARGC", get_self, null_array_assign, att_noassign|att_nounset);
    1788     9542884 :   v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, att_noassign|att_nounset);
    1789             : #  endif /* DEBUGGER */
    1790     9542884 :   v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, att_noassign|att_nounset);
    1791     9542884 :   v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, att_noassign|att_nounset);
    1792             : 
    1793     9542884 :   v = init_dynamic_assoc_var ("BASH_CMDS", get_hashcmd, assign_hashcmd, att_nofree);
    1794             : #  if defined (ALIAS)
    1795     9542884 :   v = init_dynamic_assoc_var ("BASH_ALIASES", get_aliasvar, assign_aliasvar, att_nofree);
    1796             : #  endif
    1797             : #endif
    1798             : 
    1799     9542884 :   v = init_funcname_var ();
    1800     9542884 : }
    1801             : 
    1802             : /* **************************************************************** */
    1803             : /*                                                                  */
    1804             : /*              Retrieving variables and values                     */
    1805             : /*                                                                  */
    1806             : /* **************************************************************** */
    1807             : 
    1808             : /* How to get a pointer to the shell variable or function named NAME.
    1809             :    HASHED_VARS is a pointer to the hash table containing the list
    1810             :    of interest (either variables or functions). */
    1811             : 
    1812             : static SHELL_VAR *
    1813             : hash_lookup (name, hashed_vars)
    1814             :      const char *name;
    1815             :      HASH_TABLE *hashed_vars;
    1816             : {
    1817  1670675902 :   BUCKET_CONTENTS *bucket;
    1818             : 
    1819  3341351804 :   bucket = hash_search (name, hashed_vars, 0);
    1820             :   /* If we find the name in HASHED_VARS, set LAST_TABLE_SEARCHED to that
    1821             :      table. */
    1822  1670675902 :   if (bucket)
    1823   518580409 :     last_table_searched = hashed_vars;
    1824  1670675902 :   return (bucket ? (SHELL_VAR *)bucket->data : (SHELL_VAR *)NULL);
    1825             : }
    1826             : 
    1827             : SHELL_VAR *
    1828   894384283 : var_lookup (name, vcontext)
    1829             :      const char *name;
    1830             :      VAR_CONTEXT *vcontext;
    1831             : {
    1832   894384283 :   VAR_CONTEXT *vc;
    1833   894384283 :   SHELL_VAR *v;
    1834             : 
    1835   894384283 :   v = (SHELL_VAR *)NULL;
    1836  1393742723 :   for (vc = vcontext; vc; vc = vc->down)
    1837  1310964286 :     if (v = hash_lookup (name, vc->table))
    1838             :       break;
    1839             : 
    1840   894384283 :   return v;
    1841             : }
    1842             : 
    1843             : /* Look up the variable entry named NAME.  If SEARCH_TEMPENV is non-zero,
    1844             :    then also search the temporarily built list of exported variables.
    1845             :    The lookup order is:
    1846             :         temporary_env
    1847             :         shell_variables list
    1848             : */
    1849             : 
    1850             : SHELL_VAR *
    1851   865755595 : find_variable_internal (name, flags)
    1852             :      const char *name;
    1853             :      int flags;
    1854             : {
    1855   865755595 :   SHELL_VAR *var;
    1856   865755595 :   int search_tempenv, force_tempenv;
    1857   865755595 :   VAR_CONTEXT *vc;
    1858             : 
    1859   865755595 :   var = (SHELL_VAR *)NULL;
    1860             : 
    1861   865755595 :   force_tempenv = (flags & FV_FORCETEMPENV);
    1862             : 
    1863             :   /* If explicitly requested, first look in the temporary environment for
    1864             :      the variable.  This allows constructs such as "foo=x eval 'echo $foo'"
    1865             :      to get the `exported' value of $foo.  This happens if we are executing
    1866             :      a function or builtin, or if we are looking up a variable in a
    1867             :      "subshell environment". */
    1868   865755595 :   search_tempenv = force_tempenv || (expanding_redir == 0 && subshell_environment);
    1869             : 
    1870   199483299 :   if (search_tempenv && temporary_env)          
    1871       14605 :     var = hash_lookup (name, temporary_env);
    1872             : 
    1873          12 :   if (var == 0)
    1874             :     {
    1875   865755583 :       if ((flags & FV_SKIPINVISIBLE) == 0)
    1876   865755583 :         var = var_lookup (name, shell_variables);
    1877             :       else
    1878             :         {
    1879             :           /* essentially var_lookup expanded inline so we can check for
    1880             :              att_invisible */
    1881           0 :           for (vc = shell_variables; vc; vc = vc->down)
    1882             :             {
    1883           0 :               var = hash_lookup (name, vc->table);
    1884           0 :               if (var && invisible_p (var))
    1885             :                 var = 0;
    1886           0 :               if (var)
    1887             :                 break;
    1888             :             }
    1889             :         }
    1890             :     }
    1891             : 
    1892   865755595 :   if (var == 0)
    1893             :     return ((SHELL_VAR *)NULL);
    1894             : 
    1895   405802935 :   return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
    1896             : }
    1897             : 
    1898             : /* Look up and resolve the chain of nameref variables starting at V all the
    1899             :    way to NULL or non-nameref. */
    1900             : SHELL_VAR *
    1901           0 : find_variable_nameref (v)
    1902             :      SHELL_VAR *v;
    1903             : {
    1904           0 :   int level, flags;
    1905           0 :   char *newname;
    1906           0 :   SHELL_VAR *orig, *oldv;
    1907             : 
    1908           0 :   level = 0;
    1909           0 :   orig = v;
    1910           0 :   while (v && nameref_p (v))
    1911             :     {
    1912           0 :       level++;
    1913           0 :       if (level > NAMEREF_MAX)
    1914             :         return ((SHELL_VAR *)0);        /* error message here? */
    1915           0 :       newname = nameref_cell (v);
    1916           0 :       if (newname == 0 || *newname == '\0')
    1917             :         return ((SHELL_VAR *)0);
    1918           0 :       oldv = v;
    1919           0 :       flags = 0;
    1920           0 :       if (expanding_redir == 0 && (assigning_in_environment || executing_builtin))
    1921           0 :         flags |= FV_FORCETEMPENV;
    1922             :       /* We don't handle array subscripts here. */
    1923           0 :       v = find_variable_internal (newname, flags);
    1924           0 :       if (v == orig || v == oldv)
    1925             :         {
    1926           0 :           internal_warning (_("%s: circular name reference"), orig->name);
    1927           0 :           return ((SHELL_VAR *)0);
    1928             :         }
    1929             :     }
    1930             :   return v;
    1931             : }
    1932             : 
    1933             : /* Resolve the chain of nameref variables for NAME.  XXX - could change later */
    1934             : SHELL_VAR *
    1935       94845 : find_variable_last_nameref (name, vflags)
    1936             :      const char *name;
    1937             :      int vflags;
    1938             : {
    1939       94845 :   SHELL_VAR *v, *nv;
    1940       94845 :   char *newname;
    1941       94845 :   int level, flags;
    1942             : 
    1943       94845 :   nv = v = find_variable_noref (name);
    1944       94845 :   level = 0;
    1945       94845 :   while (v && nameref_p (v))
    1946             :     {
    1947           0 :       level++;
    1948           0 :       if (level > NAMEREF_MAX)
    1949             :         return ((SHELL_VAR *)0);        /* error message here? */
    1950           0 :       newname = nameref_cell (v);
    1951           0 :       if (newname == 0 || *newname == '\0')
    1952           0 :         return ((vflags && invisible_p (v)) ? v : (SHELL_VAR *)0);
    1953           0 :       nv = v;
    1954           0 :       flags = 0;
    1955           0 :       if (expanding_redir == 0 && (assigning_in_environment || executing_builtin))
    1956           0 :         flags |= FV_FORCETEMPENV;
    1957             :       /* We don't accommodate array subscripts here. */
    1958           0 :       v = find_variable_internal (newname, flags);
    1959             :     }
    1960             :   return nv;
    1961             : }
    1962             : 
    1963             : /* Resolve the chain of nameref variables for NAME.  XXX - could change later */
    1964             : SHELL_VAR *
    1965           0 : find_global_variable_last_nameref (name, vflags)
    1966             :      const char *name;
    1967             :      int vflags;
    1968             : {
    1969           0 :   SHELL_VAR *v, *nv;
    1970           0 :   char *newname;
    1971           0 :   int level;
    1972             : 
    1973           0 :   nv = v = find_global_variable_noref (name);
    1974           0 :   level = 0;
    1975           0 :   while (v && nameref_p (v))
    1976             :     {
    1977           0 :       level++;
    1978           0 :       if (level > NAMEREF_MAX)
    1979             :         return ((SHELL_VAR *)0);        /* error message here? */
    1980           0 :       newname = nameref_cell (v);
    1981           0 :       if (newname == 0 || *newname == '\0')
    1982           0 :         return ((vflags && invisible_p (v)) ? v : (SHELL_VAR *)0);
    1983           0 :       nv = v;
    1984             :       /* We don't accommodate array subscripts here. */
    1985           0 :       v = find_global_variable_noref (newname);
    1986             :     }
    1987             :   return nv;
    1988             : }
    1989             : 
    1990             : static SHELL_VAR *
    1991           0 : find_nameref_at_context (v, vc)
    1992             :      SHELL_VAR *v;
    1993             :      VAR_CONTEXT *vc;
    1994             : {
    1995           0 :   SHELL_VAR *nv, *nv2;
    1996           0 :   char *newname;
    1997           0 :   int level;
    1998             : 
    1999           0 :   nv = v;
    2000           0 :   level = 1;
    2001           0 :   while (nv && nameref_p (nv))
    2002             :     {
    2003           0 :       level++;
    2004           0 :       if (level > NAMEREF_MAX)
    2005           0 :         return (&nameref_maxloop_value);
    2006           0 :       newname = nameref_cell (nv);
    2007           0 :       if (newname == 0 || *newname == '\0')
    2008           0 :         return ((SHELL_VAR *)NULL);      
    2009           0 :       nv2 = hash_lookup (newname, vc->table);
    2010           0 :       if (nv2 == 0)
    2011             :         break;
    2012             :       nv = nv2;
    2013             :     }
    2014             :   return nv;
    2015             : }
    2016             : 
    2017             : /* Do nameref resolution from the VC, which is the local context for some
    2018             :    function or builtin, `up' the chain to the global variables context.  If
    2019             :    NVCP is not NULL, return the variable context where we finally ended the
    2020             :    nameref resolution (so the bind_variable_internal can use the correct
    2021             :    variable context and hash table). */
    2022             : static SHELL_VAR *
    2023           0 : find_variable_nameref_context (v, vc, nvcp)
    2024             :      SHELL_VAR *v;
    2025             :      VAR_CONTEXT *vc;
    2026             :      VAR_CONTEXT **nvcp;
    2027             : {
    2028           0 :   SHELL_VAR *nv, *nv2;
    2029           0 :   VAR_CONTEXT *nvc;
    2030             : 
    2031             :   /* Look starting at the current context all the way `up' */
    2032           0 :   for (nv = v, nvc = vc; nvc; nvc = nvc->down)
    2033             :     {
    2034           0 :       nv2 = find_nameref_at_context (nv, nvc);
    2035           0 :       if (nv2 == &nameref_maxloop_value)
    2036             :         return (nv2);                   /* XXX */
    2037           0 :       if (nv2 == 0)
    2038             :         continue;
    2039           0 :       nv = nv2;
    2040           0 :       if (*nvcp)
    2041           0 :         *nvcp = nvc;
    2042           0 :       if (nameref_p (nv) == 0)
    2043             :         break;
    2044             :     }
    2045           0 :   return (nameref_p (nv) ? (SHELL_VAR *)NULL : nv);
    2046             : }
    2047             : 
    2048             : /* Do nameref resolution from the VC, which is the local context for some
    2049             :    function or builtin, `up' the chain to the global variables context.  If
    2050             :    NVCP is not NULL, return the variable context where we finally ended the
    2051             :    nameref resolution (so the bind_variable_internal can use the correct
    2052             :    variable context and hash table). */
    2053             : static SHELL_VAR *
    2054           0 : find_variable_last_nameref_context (v, vc, nvcp)
    2055             :      SHELL_VAR *v;
    2056             :      VAR_CONTEXT *vc;
    2057             :      VAR_CONTEXT **nvcp;
    2058             : {
    2059           0 :   SHELL_VAR *nv, *nv2;
    2060           0 :   VAR_CONTEXT *nvc;
    2061             : 
    2062             :   /* Look starting at the current context all the way `up' */
    2063           0 :   for (nv = v, nvc = vc; nvc; nvc = nvc->down)
    2064             :     {
    2065           0 :       nv2 = find_nameref_at_context (nv, nvc);
    2066           0 :       if (nv2 == &nameref_maxloop_value)
    2067             :         return (nv2);                   /* XXX */
    2068           0 :       if (nv2 == 0)
    2069             :         continue;
    2070           0 :       nv = nv2;
    2071           0 :       if (*nvcp)
    2072           0 :         *nvcp = nvc;
    2073             :     }
    2074           0 :   return (nameref_p (nv) ? nv : (SHELL_VAR *)NULL);
    2075             : }
    2076             : 
    2077             : SHELL_VAR *
    2078          54 : find_variable_nameref_for_create (name, flags)
    2079             :      const char *name;
    2080             :      int flags;
    2081             : {
    2082          54 :   SHELL_VAR *var;
    2083             : 
    2084             :   /* See if we have a nameref pointing to a variable that hasn't been
    2085             :      created yet. */
    2086          54 :   var = find_variable_last_nameref (name, 1);
    2087          54 :   if ((flags&1) && var && nameref_p (var) && invisible_p (var))
    2088             :     {
    2089           0 :       internal_warning (_("%s: removing nameref attribute"), name);
    2090           0 :       VUNSETATTR (var, att_nameref);
    2091             :     }
    2092          54 :   if (var && nameref_p (var))
    2093             :     {
    2094           0 :       if (legal_identifier (nameref_cell (var)) == 0)
    2095             :         {
    2096           0 :           sh_invalidid (nameref_cell (var) ? nameref_cell (var) : "");
    2097           0 :           return ((SHELL_VAR *)INVALID_NAMEREF_VALUE);
    2098             :         }
    2099             :     }
    2100             :   return (var);
    2101             : }
    2102             : 
    2103             : SHELL_VAR *
    2104           0 : find_variable_nameref_for_assignment (name, flags)
    2105             :      const char *name;
    2106             :      int flags;
    2107             : {
    2108           0 :   SHELL_VAR *var;
    2109             : 
    2110             :   /* See if we have a nameref pointing to a variable that hasn't been
    2111             :      created yet. */
    2112           0 :   var = find_variable_last_nameref (name, 1);
    2113           0 :   if (var && nameref_p (var) && invisible_p (var))      /* XXX - flags */
    2114             :     {
    2115           0 :       internal_warning (_("%s: removing nameref attribute"), name);
    2116           0 :       VUNSETATTR (var, att_nameref);
    2117             :     }
    2118           0 :   if (var && nameref_p (var))
    2119             :     {
    2120           0 :       if (valid_nameref_value (nameref_cell (var), 1) == 0)
    2121             :         {
    2122           0 :           sh_invalidid (nameref_cell (var) ? nameref_cell (var) : "");
    2123           0 :           return ((SHELL_VAR *)INVALID_NAMEREF_VALUE);
    2124             :         }
    2125             :     }
    2126             :   return (var);
    2127             : }
    2128             : 
    2129             : /* Find a variable, forcing a search of the temporary environment first */
    2130             : SHELL_VAR *
    2131     9469569 : find_variable_tempenv (name)
    2132             :      const char *name;
    2133             : {
    2134     9469569 :   SHELL_VAR *var;
    2135             : 
    2136     9469569 :   var = find_variable_internal (name, FV_FORCETEMPENV);
    2137     9469569 :   if (var && nameref_p (var))
    2138           0 :     var = find_variable_nameref (var);
    2139     9469569 :   return (var);
    2140             : }
    2141             : 
    2142             : /* Find a variable, not forcing a search of the temporary environment first */
    2143             : SHELL_VAR *
    2144          70 : find_variable_notempenv (name)
    2145             :      const char *name;
    2146             : {
    2147          70 :   SHELL_VAR *var;
    2148             : 
    2149          70 :   var = find_variable_internal (name, 0);
    2150          70 :   if (var && nameref_p (var))
    2151           0 :     var = find_variable_nameref (var);
    2152          70 :   return (var);
    2153             : }
    2154             : 
    2155             : SHELL_VAR *
    2156           0 : find_global_variable (name)
    2157             :      const char *name;
    2158             : {
    2159           0 :   SHELL_VAR *var;
    2160             : 
    2161           0 :   var = var_lookup (name, global_variables);
    2162           0 :   if (var && nameref_p (var))
    2163           0 :     var = find_variable_nameref (var);
    2164             : 
    2165           0 :   if (var == 0)
    2166             :     return ((SHELL_VAR *)NULL);
    2167             : 
    2168           0 :   return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
    2169             : }
    2170             : 
    2171             : SHELL_VAR *
    2172           0 : find_global_variable_noref (name)
    2173             :      const char *name;
    2174             : {
    2175           0 :   SHELL_VAR *var;
    2176             : 
    2177           0 :   var = var_lookup (name, global_variables);
    2178             : 
    2179           0 :   if (var == 0)
    2180             :     return ((SHELL_VAR *)NULL);
    2181             : 
    2182           0 :   return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
    2183             : }
    2184             : 
    2185             : SHELL_VAR *
    2186           0 : find_shell_variable (name)
    2187             :      const char *name;
    2188             : {
    2189           0 :   SHELL_VAR *var;
    2190             : 
    2191           0 :   var = var_lookup (name, shell_variables);
    2192           0 :   if (var && nameref_p (var))
    2193           0 :     var = find_variable_nameref (var);
    2194             : 
    2195           0 :   if (var == 0)
    2196             :     return ((SHELL_VAR *)NULL);
    2197             : 
    2198           0 :   return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
    2199             : }
    2200             : 
    2201             : /* Look up the variable entry named NAME.  Returns the entry or NULL. */
    2202             : SHELL_VAR *
    2203   856191098 : find_variable (name)
    2204             :      const char *name;
    2205             : {
    2206   856191098 :   SHELL_VAR *v;
    2207   856191098 :   int flags;
    2208             : 
    2209   856191098 :   last_table_searched = 0;
    2210   856191098 :   flags = 0;
    2211   856191098 :   if (expanding_redir == 0 && (assigning_in_environment || executing_builtin))
    2212   181947173 :     flags |= FV_FORCETEMPENV;
    2213   856191098 :   v = find_variable_internal (name, flags);
    2214   856191098 :   if (v && nameref_p (v))
    2215           0 :     v = find_variable_nameref (v);
    2216   856191098 :   return v;
    2217             : }
    2218             : 
    2219             : /* Find the first instance of NAME in the variable context chain; return first
    2220             :    one found without att_invisible set; return 0 if no non-invisible instances
    2221             :    found. */
    2222             : SHELL_VAR *
    2223           0 : find_variable_no_invisible (name)
    2224             :      const char *name;
    2225             : {
    2226           0 :   SHELL_VAR *v;
    2227           0 :   int flags;
    2228             : 
    2229           0 :   last_table_searched = 0;
    2230           0 :   flags = FV_SKIPINVISIBLE;
    2231           0 :   if (expanding_redir == 0 && (assigning_in_environment || executing_builtin))
    2232           0 :     flags |= FV_FORCETEMPENV;
    2233           0 :   v = find_variable_internal (name, flags);
    2234           0 :   if (v && nameref_p (v))
    2235           0 :     v = find_variable_nameref (v);
    2236           0 :   return v;
    2237             : }
    2238             : 
    2239             : /* Find the first instance of NAME in the variable context chain; return first
    2240             :    one found even if att_invisible set. */
    2241             : SHELL_VAR *
    2242           0 : find_variable_for_assignment (name)
    2243             :      const char *name;
    2244             : {
    2245           0 :   SHELL_VAR *v;
    2246           0 :   int flags;
    2247             : 
    2248           0 :   last_table_searched = 0;
    2249           0 :   flags = 0;
    2250           0 :   if (expanding_redir == 0 && (assigning_in_environment || executing_builtin))
    2251           0 :     flags |= FV_FORCETEMPENV;
    2252           0 :   v = find_variable_internal (name, flags);
    2253           0 :   if (v && nameref_p (v))
    2254           0 :     v = find_variable_nameref (v);
    2255           0 :   return v;
    2256             : }
    2257             : 
    2258             : SHELL_VAR *
    2259       94858 : find_variable_noref (name)
    2260             :      const char *name;
    2261             : {
    2262       94858 :   SHELL_VAR *v;
    2263       94858 :   int flags;
    2264             : 
    2265       94858 :   flags = 0;
    2266       94858 :   if (expanding_redir == 0 && (assigning_in_environment || executing_builtin))
    2267        7725 :     flags |= FV_FORCETEMPENV;
    2268       94858 :   v = find_variable_internal (name, flags);
    2269       94858 :   return v;
    2270             : }
    2271             : 
    2272             : /* Look up the function entry whose name matches STRING.
    2273             :    Returns the entry or NULL. */
    2274             : SHELL_VAR *
    2275   106551796 : find_function (name)
    2276             :      const char *name;
    2277             : {
    2278   106551796 :   return (hash_lookup (name, shell_functions));
    2279             : }
    2280             : 
    2281             : /* Find the function definition for the shell function named NAME.  Returns
    2282             :    the entry or NULL. */
    2283             : FUNCTION_DEF *
    2284    37477146 : find_function_def (name)
    2285             :      const char *name;
    2286             : {
    2287             : #if defined (DEBUGGER)
    2288    37477146 :   return ((FUNCTION_DEF *)hash_lookup (name, shell_function_defs));
    2289             : #else
    2290             :   return ((FUNCTION_DEF *)0);
    2291             : #endif
    2292             : }
    2293             : 
    2294             : /* Return the value of VAR.  VAR is assumed to have been the result of a
    2295             :    lookup without any subscript, if arrays are compiled into the shell. */
    2296             : char *
    2297    38068894 : get_variable_value (var)
    2298             :      SHELL_VAR *var;
    2299             : {
    2300    38068894 :   if (var == 0)
    2301             :     return ((char *)NULL);
    2302             : #if defined (ARRAY_VARS)
    2303    38068782 :   else if (array_p (var))
    2304           0 :     return (array_reference (array_cell (var), 0));
    2305    38068782 :   else if (assoc_p (var))
    2306           0 :     return (assoc_reference (assoc_cell (var), "0"));
    2307             : #endif
    2308             :   else
    2309    38068782 :     return (value_cell (var));
    2310             : }
    2311             : 
    2312             : /* Return the string value of a variable.  Return NULL if the variable
    2313             :    doesn't exist.  Don't cons a new string.  This is a potential memory
    2314             :    leak if the variable is found in the temporary environment, but doesn't
    2315             :    leak in practice.  Since    functions and variables have separate name
    2316             :    spaces, returns NULL if var_name is a shell function only. */
    2317             : char *
    2318   209861397 : get_string_value (var_name)
    2319             :      const char *var_name;
    2320             : {
    2321   209861397 :   SHELL_VAR *var;
    2322             : 
    2323   209861397 :   var = find_variable (var_name);
    2324   209861397 :   return ((var) ? get_variable_value (var) : (char *)NULL);
    2325             : }
    2326             : 
    2327             : /* This is present for use by the tilde and readline libraries. */
    2328             : char *
    2329         183 : sh_get_env_value (v)
    2330             :      const char *v;
    2331             : {
    2332         183 :   return get_string_value (v);
    2333             : }
    2334             : 
    2335             : /* **************************************************************** */
    2336             : /*                                                                  */
    2337             : /*                Creating and setting variables                    */
    2338             : /*                                                                  */
    2339             : /* **************************************************************** */
    2340             : 
    2341             : /* Set NAME to VALUE if NAME has no value. */
    2342             : SHELL_VAR *
    2343    76343072 : set_if_not (name, value)
    2344             :      char *name, *value;
    2345             : {
    2346    76343072 :   SHELL_VAR *v;
    2347             : 
    2348    76343072 :   if (shell_variables == 0)
    2349           0 :     create_variable_tables ();
    2350             : 
    2351    76343072 :   v = find_variable (name);
    2352    76343072 :   if (v == 0)
    2353    38171536 :     v = bind_variable_internal (name, value, global_variables->table, HASH_NOSRCH, 0);
    2354    76343072 :   return (v);
    2355             : }
    2356             : 
    2357             : /* Create a local variable referenced by NAME. */
    2358             : SHELL_VAR *
    2359           0 : make_local_variable (name)
    2360             :      const char *name;
    2361             : {
    2362           0 :   SHELL_VAR *new_var, *old_var, *old_ref;
    2363           0 :   VAR_CONTEXT *vc;
    2364           0 :   int was_tmpvar;
    2365           0 :   char *tmp_value;
    2366             : 
    2367             :   /* We don't want to follow the nameref chain when making local variables; we
    2368             :      just want to create them. */
    2369           0 :   old_ref = find_variable_noref (name);
    2370           0 :   if (old_ref && nameref_p (old_ref) == 0)
    2371           0 :     old_ref = 0;
    2372             :   /* local foo; local foo;  is a no-op. */
    2373           0 :   old_var = find_variable (name);
    2374           0 :   if (old_ref == 0 && old_var && local_p (old_var) && old_var->context == variable_context)
    2375             :     return (old_var);
    2376             : 
    2377             :   /* local -n foo; local -n foo;  is a no-op. */
    2378           0 :   if (old_ref && local_p (old_ref) && old_ref->context == variable_context)
    2379             :     return (old_ref);
    2380             : 
    2381             :   /* From here on, we want to use the refvar, not the variable it references */
    2382           0 :   if (old_ref)
    2383           0 :     old_var = old_ref;
    2384             : 
    2385           0 :   was_tmpvar = old_var && tempvar_p (old_var);
    2386             :   /* If we're making a local variable in a shell function, the temporary env
    2387             :      has already been merged into the function's variable context stack.  We
    2388             :      can assume that a temporary var in the same context appears in the same
    2389             :      VAR_CONTEXT and can safely be returned without creating a new variable
    2390             :      (which results in duplicate names in the same VAR_CONTEXT->table */
    2391             :   /* We can't just test tmpvar_p because variables in the temporary env given
    2392             :      to a shell function appear in the function's local variable VAR_CONTEXT
    2393             :      but retain their tempvar attribute.  We want temporary variables that are
    2394             :      found in temporary_env, hence the test for last_table_searched, which is
    2395             :      set in hash_lookup and only (so far) checked here. */
    2396           0 :   if (was_tmpvar && old_var->context == variable_context && last_table_searched != temporary_env)
    2397             :     {
    2398           0 :       VUNSETATTR (old_var, att_invisible);      /* XXX */
    2399           0 :       return (old_var);
    2400             :     }
    2401           0 :   if (was_tmpvar)
    2402           0 :     tmp_value = value_cell (old_var);
    2403             : 
    2404           0 :   for (vc = shell_variables; vc; vc = vc->down)
    2405           0 :     if (vc_isfuncenv (vc) && vc->scope == variable_context)
    2406             :       break;
    2407             : 
    2408           0 :   if (vc == 0)
    2409             :     {
    2410           0 :       internal_error (_("make_local_variable: no function context at current scope"));
    2411           0 :       return ((SHELL_VAR *)NULL);
    2412             :     }
    2413           0 :   else if (vc->table == 0)
    2414           0 :     vc->table = hash_create (TEMPENV_HASH_BUCKETS);
    2415             : 
    2416             :   /* Since this is called only from the local/declare/typeset code, we can
    2417             :      call builtin_error here without worry (of course, it will also work
    2418             :      for anything that sets this_command_name).  Variables with the `noassign'
    2419             :      attribute may not be made local.  The test against old_var's context
    2420             :      level is to disallow local copies of readonly global variables (since I
    2421             :      believe that this could be a security hole).  Readonly copies of calling
    2422             :      function local variables are OK. */
    2423           0 :   if (old_var && (noassign_p (old_var) ||
    2424           0 :                  (readonly_p (old_var) && old_var->context == 0)))
    2425             :     {
    2426           0 :       if (readonly_p (old_var))
    2427           0 :         sh_readonly (name);
    2428           0 :       else if (noassign_p (old_var))
    2429           0 :         builtin_error (_("%s: variable may not be assigned value"), name);
    2430             : #if 0
    2431             :       /* Let noassign variables through with a warning */
    2432             :       if (readonly_p (old_var))
    2433             : #endif
    2434           0 :         return ((SHELL_VAR *)NULL);
    2435             :     }
    2436             : 
    2437           0 :   if (old_var == 0)
    2438           0 :     new_var = make_new_variable (name, vc->table);
    2439             :   else
    2440             :     {
    2441           0 :       new_var = make_new_variable (name, vc->table);
    2442             : 
    2443             :       /* If we found this variable in one of the temporary environments,
    2444             :          inherit its value.  Watch to see if this causes problems with
    2445             :          things like `x=4 local x'. XXX - see above for temporary env
    2446             :          variables with the same context level as variable_context */
    2447             :       /* XXX - we should only do this if the variable is not an array. */
    2448           0 :       if (was_tmpvar)
    2449           0 :         var_setvalue (new_var, savestring (tmp_value));
    2450             : 
    2451           0 :       new_var->attributes = exported_p (old_var) ? att_exported : 0;
    2452             :     }
    2453             : 
    2454           0 :   vc->flags |= VC_HASLOCAL;
    2455             : 
    2456           0 :   new_var->context = variable_context;
    2457           0 :   VSETATTR (new_var, att_local);
    2458             : 
    2459           0 :   if (ifsname (name))
    2460           0 :     setifs (new_var);
    2461             : 
    2462           0 :   if (was_tmpvar == 0 && no_invisible_vars == 0)
    2463           0 :     VSETATTR (new_var, att_invisible);  /* XXX */
    2464             :   return (new_var);
    2465             : }
    2466             : 
    2467             : /* Create a new shell variable with name NAME. */
    2468             : static SHELL_VAR *
    2469   686973945 : new_shell_variable (name)
    2470             :      const char *name;
    2471             : {
    2472   686973945 :   SHELL_VAR *entry;
    2473             : 
    2474   686973945 :   entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
    2475             : 
    2476   686973945 :   entry->name = savestring (name);
    2477   686973945 :   var_setvalue (entry, (char *)NULL);
    2478   686973945 :   CLEAR_EXPORTSTR (entry);
    2479             : 
    2480   686973945 :   entry->dynamic_value = (sh_var_value_func_t *)NULL;
    2481   686973945 :   entry->assign_func = (sh_var_assign_func_t *)NULL;
    2482             : 
    2483   686973945 :   entry->attributes = 0;
    2484             : 
    2485             :   /* Always assume variables are to be made at toplevel!
    2486             :      make_local_variable has the responsibility of changing the
    2487             :      variable context. */
    2488   686973945 :   entry->context = 0;
    2489             : 
    2490   686973945 :   return (entry);
    2491             : }
    2492             : 
    2493             : /* Create a new shell variable with name NAME and add it to the hash table
    2494             :    TABLE. */
    2495             : static SHELL_VAR *
    2496   668270747 : make_new_variable (name, table)
    2497             :      const char *name;
    2498             :      HASH_TABLE *table;
    2499             : {
    2500   668270747 :   SHELL_VAR *entry;
    2501   668270747 :   BUCKET_CONTENTS *elt;
    2502             : 
    2503   668270747 :   entry = new_shell_variable (name);
    2504             : 
    2505             :   /* Make sure we have a shell_variables hash table to add to. */
    2506   668270747 :   if (shell_variables == 0)
    2507           0 :     create_variable_tables ();
    2508             : 
    2509   668270747 :   elt = hash_insert (savestring (name), table, HASH_NOSRCH);
    2510   668270747 :   elt->data = (PTR_T)entry;
    2511             : 
    2512   668270747 :   return entry;
    2513             : }
    2514             : 
    2515             : #if defined (ARRAY_VARS)
    2516             : SHELL_VAR *
    2517    85885984 : make_new_array_variable (name)
    2518             :      char *name;
    2519             : {
    2520    85885984 :   SHELL_VAR *entry;
    2521    85885984 :   ARRAY *array;
    2522             : 
    2523    85885984 :   entry = make_new_variable (name, global_variables->table);
    2524    85885984 :   array = array_create ();
    2525             : 
    2526    85885984 :   var_setarray (entry, array);
    2527    85885984 :   VSETATTR (entry, att_array);
    2528    85885984 :   return entry;
    2529             : }
    2530             : 
    2531             : SHELL_VAR *
    2532           0 : make_local_array_variable (name, assoc_ok)
    2533             :      char *name;
    2534             :      int assoc_ok;
    2535             : {
    2536           0 :   SHELL_VAR *var;
    2537           0 :   ARRAY *array;
    2538             : 
    2539           0 :   var = make_local_variable (name);
    2540           0 :   if (var == 0 || array_p (var) || (assoc_ok && assoc_p (var)))
    2541             :     return var;
    2542             : 
    2543           0 :   array = array_create ();
    2544             : 
    2545           0 :   dispose_variable_value (var);
    2546           0 :   var_setarray (var, array);
    2547           0 :   VSETATTR (var, att_array);
    2548           0 :   return var;
    2549             : }
    2550             : 
    2551             : SHELL_VAR *
    2552    19085768 : make_new_assoc_variable (name)
    2553             :      char *name;
    2554             : {
    2555    19085768 :   SHELL_VAR *entry;
    2556    19085768 :   HASH_TABLE *hash;
    2557             : 
    2558    19085768 :   entry = make_new_variable (name, global_variables->table);
    2559    19085768 :   hash = assoc_create (0);
    2560             : 
    2561    19085768 :   var_setassoc (entry, hash);
    2562    19085768 :   VSETATTR (entry, att_assoc);
    2563    19085768 :   return entry;
    2564             : }
    2565             : 
    2566             : SHELL_VAR *
    2567           0 : make_local_assoc_variable (name)
    2568             :      char *name;
    2569             : {
    2570           0 :   SHELL_VAR *var;
    2571           0 :   HASH_TABLE *hash;
    2572             : 
    2573           0 :   var = make_local_variable (name);
    2574           0 :   if (var == 0 || assoc_p (var))
    2575             :     return var;
    2576             : 
    2577           0 :   dispose_variable_value (var);
    2578           0 :   hash = assoc_create (0);
    2579             : 
    2580           0 :   var_setassoc (var, hash);
    2581           0 :   VSETATTR (var, att_assoc);
    2582           0 :   return var;
    2583             : }
    2584             : #endif
    2585             : 
    2586             : char *
    2587   657345383 : make_variable_value (var, value, flags)
    2588             :      SHELL_VAR *var;
    2589             :      char *value;
    2590             :      int flags;
    2591             : {
    2592   657345383 :   char *retval, *oval;
    2593   657345383 :   intmax_t lval, rval;
    2594   657345383 :   int expok, olen, op;
    2595             : 
    2596             :   /* If this variable has had its type set to integer (via `declare -i'),
    2597             :      then do expression evaluation on it and store the result.  The
    2598             :      functions in expr.c (evalexp()) and bind_int_variable() are responsible
    2599             :      for turning off the integer flag if they don't want further
    2600             :      evaluation done. */
    2601   657345383 :   if (integer_p (var))
    2602             :     {
    2603           0 :       if (flags & ASS_APPEND)
    2604             :         {
    2605           0 :           oval = value_cell (var);
    2606           0 :           lval = evalexp (oval, &expok);    /* ksh93 seems to do this */
    2607           0 :           if (expok == 0)
    2608             :             {
    2609           0 :               top_level_cleanup ();
    2610           0 :               jump_to_top_level (DISCARD);
    2611             :             }
    2612             :         }
    2613           0 :       rval = evalexp (value, &expok);
    2614           0 :       if (expok == 0)
    2615             :         {
    2616           0 :           top_level_cleanup ();
    2617           0 :           jump_to_top_level (DISCARD);
    2618             :         }
    2619             :       /* This can be fooled if the variable's value changes while evaluating
    2620             :          `rval'.  We can change it if we move the evaluation of lval to here. */
    2621           0 :       if (flags & ASS_APPEND)
    2622           0 :         rval += lval;
    2623           0 :       retval = itos (rval);
    2624             :     }
    2625             : #if defined (CASEMOD_ATTRS)
    2626   657345383 :   else if (capcase_p (var) || uppercase_p (var) || lowercase_p (var))
    2627             :     {
    2628           0 :       if (flags & ASS_APPEND)
    2629             :         {
    2630           0 :           oval = get_variable_value (var);
    2631           0 :           if (oval == 0)        /* paranoia */
    2632           0 :             oval = "";
    2633           0 :           olen = STRLEN (oval);
    2634           0 :           retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1);
    2635           0 :           strcpy (retval, oval);
    2636           0 :           if (value)
    2637           0 :             strcpy (retval+olen, value);
    2638             :         }
    2639           0 :       else if (*value)
    2640           0 :         retval = savestring (value);
    2641             :       else
    2642             :         {
    2643           0 :           retval = (char *)xmalloc (1);
    2644           0 :           retval[0] = '\0';
    2645             :         }
    2646           0 :       op = capcase_p (var) ? CASE_CAPITALIZE
    2647           0 :                          : (uppercase_p (var) ? CASE_UPPER : CASE_LOWER);
    2648           0 :       oval = sh_modcase (retval, (char *)0, op);
    2649           0 :       free (retval);
    2650           0 :       retval = oval;
    2651             :     }
    2652             : #endif /* CASEMOD_ATTRS */
    2653   657345383 :   else if (value)
    2654             :     {
    2655   600088012 :       if (flags & ASS_APPEND)
    2656             :         {
    2657           0 :           oval = get_variable_value (var);
    2658           0 :           if (oval == 0)        /* paranoia */
    2659           0 :             oval = "";
    2660           0 :           olen = STRLEN (oval);
    2661           0 :           retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1);
    2662           0 :           strcpy (retval, oval);
    2663           0 :           if (value)
    2664           0 :             strcpy (retval+olen, value);
    2665             :         }
    2666   600088012 :       else if (*value)
    2667   575151214 :         retval = savestring (value);
    2668             :       else
    2669             :         {
    2670    24936798 :           retval = (char *)xmalloc (1);
    2671    24936798 :           retval[0] = '\0';
    2672             :         }
    2673             :     }
    2674             :   else
    2675             :     retval = (char *)NULL;
    2676             : 
    2677   657345383 :   return retval;
    2678             : }
    2679             : 
    2680             : /* Bind a variable NAME to VALUE in the HASH_TABLE TABLE, which may be the
    2681             :    temporary environment (but usually is not). */
    2682             : static SHELL_VAR *
    2683   657345371 : bind_variable_internal (name, value, table, hflags, aflags)
    2684             :      const char *name;
    2685             :      char *value;
    2686             :      HASH_TABLE *table;
    2687             :      int hflags, aflags;
    2688             : {
    2689   657345371 :   char *newval, *tname;
    2690   657345371 :   SHELL_VAR *entry, *tentry;
    2691             : 
    2692   657345371 :   entry = (hflags & HASH_NOSRCH) ? (SHELL_VAR *)NULL : hash_lookup (name, table);
    2693             :   /* Follow the nameref chain here if this is the global variables table */
    2694    94053574 :   if (entry && nameref_p (entry) && (invisible_p (entry) == 0) && table == global_variables->table)
    2695             :     {
    2696           0 :       entry = find_global_variable (entry->name);
    2697             :       /* Let's see if we have a nameref referencing a variable that hasn't yet
    2698             :          been created. */
    2699           0 :       if (entry == 0)
    2700           0 :         entry = find_variable_last_nameref (name, 0);   /* XXX */
    2701           0 :       if (entry == 0)                                   /* just in case */
    2702             :         return (entry);
    2703             :     }
    2704             : 
    2705             :   /* The first clause handles `declare -n ref; ref=x;' or `declare -n ref;
    2706             :      declare -n ref' */
    2707   657345371 :   if (entry && invisible_p (entry) && nameref_p (entry))
    2708             :     {
    2709           0 :       if ((aflags & ASS_FORCE) == 0 && value && valid_nameref_value (value, 0) == 0)
    2710             :         {
    2711           0 :           sh_invalidid (value);
    2712           0 :           return ((SHELL_VAR *)NULL);
    2713             :         }
    2714           0 :       goto assign_value;
    2715             :     }
    2716   657345371 :   else if (entry && nameref_p (entry))
    2717             :     {
    2718           0 :       newval = nameref_cell (entry);
    2719             : #if defined (ARRAY_VARS)
    2720             :       /* declare -n foo=x[2] ; foo=bar */
    2721           0 :       if (valid_array_reference (newval, 0))
    2722             :         {
    2723           0 :           tname = array_variable_name (newval, (char **)0, (int *)0);
    2724           0 :           if (tname && (tentry = find_variable_noref (tname)) && nameref_p (tentry))
    2725             :             {
    2726             :               /* nameref variables can't be arrays */
    2727           0 :               internal_warning (_("%s: removing nameref attribute"), name_cell (tentry));
    2728           0 :               FREE (value_cell (tentry));               /* XXX - bash-4.3 compat */
    2729           0 :               var_setvalue (tentry, (char *)NULL);
    2730           0 :               VUNSETATTR (tentry, att_nameref);
    2731             :             }
    2732           0 :           free (tname);
    2733             :           /* XXX - should it be aflags? */
    2734           0 :           entry = assign_array_element (newval, make_variable_value (entry, value, 0), aflags|ASS_NAMEREF);
    2735           0 :           if (entry == 0)
    2736             :             return entry;
    2737             :         }
    2738             :       else
    2739             : #endif
    2740             :       {
    2741           0 :       entry = make_new_variable (newval, table);
    2742           0 :       var_setvalue (entry, make_variable_value (entry, value, 0));
    2743             :       }
    2744             :     }
    2745   657345371 :   else if (entry == 0)
    2746             :     {
    2747   563291797 :       entry = make_new_variable (name, table);
    2748   563291797 :       var_setvalue (entry, make_variable_value (entry, value, 0)); /* XXX */
    2749             :     }
    2750    94053574 :   else if (entry->assign_func)       /* array vars have assign functions now */
    2751             :     {
    2752           0 :       INVALIDATE_EXPORTSTR (entry);
    2753           0 :       newval = (aflags & ASS_APPEND) ? make_variable_value (entry, value, aflags) : value;
    2754           0 :       if (assoc_p (entry))
    2755           0 :         entry = (*(entry->assign_func)) (entry, newval, -1, savestring ("0"));
    2756           0 :       else if (array_p (entry))
    2757           0 :         entry = (*(entry->assign_func)) (entry, newval, 0, 0);
    2758             :       else
    2759           0 :         entry = (*(entry->assign_func)) (entry, newval, -1, 0);
    2760           0 :       if (newval != value)
    2761           0 :         free (newval);
    2762           0 :       return (entry);
    2763             :     }
    2764             :   else
    2765             :     {
    2766    94053574 : assign_value:
    2767    94053574 :       if ((readonly_p (entry) && (aflags & ASS_FORCE) == 0) || noassign_p (entry))
    2768             :         {
    2769           0 :           if (readonly_p (entry))
    2770           0 :             err_readonly (name_cell (entry));
    2771           0 :           return (entry);
    2772             :         }
    2773             : 
    2774             :       /* Variables which are bound are visible. */
    2775    94053574 :       VUNSETATTR (entry, att_invisible);
    2776             : 
    2777             : #if defined (ARRAY_VARS)
    2778    94053574 :       if (assoc_p (entry) || array_p (entry))
    2779           9 :         newval = make_array_variable_value (entry, 0, "0", value, aflags);
    2780             :       else
    2781             : #endif
    2782             : 
    2783    94053565 :       newval = make_variable_value (entry, value, aflags);      /* XXX */
    2784             : 
    2785             :       /* Invalidate any cached export string */
    2786    94053574 :       INVALIDATE_EXPORTSTR (entry);
    2787             : 
    2788             : #if defined (ARRAY_VARS)
    2789             :       /* XXX -- this bears looking at again -- XXX */
    2790             :       /* If an existing array variable x is being assigned to with x=b or
    2791             :          `read x' or something of that nature, silently convert it to
    2792             :          x[0]=b or `read x[0]'. */
    2793    94053574 :       if (assoc_p (entry))
    2794             :         {
    2795           0 :           assoc_insert (assoc_cell (entry), savestring ("0"), newval);
    2796           0 :           free (newval);
    2797             :         }
    2798    94053574 :       else if (array_p (entry))
    2799             :         {
    2800           9 :           array_insert (array_cell (entry), 0, newval);
    2801           9 :           free (newval);
    2802             :         }
    2803             :       else
    2804             : #endif
    2805             :         {
    2806    94053565 :           FREE (value_cell (entry));
    2807    94053565 :           var_setvalue (entry, newval);
    2808             :         }
    2809             :     }
    2810             : 
    2811   657345371 :   if (mark_modified_vars)
    2812           0 :     VSETATTR (entry, att_exported);
    2813             : 
    2814   657345371 :   if (exported_p (entry))
    2815    19085786 :     array_needs_making = 1;
    2816             : 
    2817             :   return (entry);
    2818             : }
    2819             :         
    2820             : /* Bind a variable NAME to VALUE.  This conses up the name
    2821             :    and value strings.  If we have a temporary environment, we bind there
    2822             :    first, then we bind into shell_variables. */
    2823             : 
    2824             : SHELL_VAR *
    2825   619173835 : bind_variable (name, value, flags)
    2826             :      const char *name;
    2827             :      char *value;
    2828             :      int flags;
    2829             : {
    2830   619173835 :   SHELL_VAR *v, *nv;
    2831   619173835 :   VAR_CONTEXT *vc, *nvc;
    2832             : 
    2833   619173835 :   if (shell_variables == 0)
    2834           0 :     create_variable_tables ();
    2835             : 
    2836             :   /* If we have a temporary environment, look there first for the variable,
    2837             :      and, if found, modify the value there before modifying it in the
    2838             :      shell_variables table.  This allows sourced scripts to modify values
    2839             :      given to them in a temporary environment while modifying the variable
    2840             :      value that the caller sees. */
    2841   619173835 :   if (temporary_env && value)           /* XXX - can value be null here? */
    2842        6961 :     bind_tempenv_variable (name, value);
    2843             : 
    2844             :   /* XXX -- handle local variables here. */
    2845  1240630668 :   for (vc = shell_variables; vc; vc = vc->down)
    2846             :     {
    2847   621456833 :       if (vc_isfuncenv (vc) || vc_isbltnenv (vc))
    2848             :         {
    2849     2282998 :           v = hash_lookup (name, vc->table);
    2850     2282998 :           nvc = vc;
    2851     2282998 :           if (v && nameref_p (v))
    2852             :             {
    2853           0 :               nv = find_variable_nameref_context (v, vc, &nvc);
    2854           0 :               if (nv == 0)
    2855             :                 {
    2856           0 :                   nv = find_variable_last_nameref_context (v, vc, &nvc);
    2857           0 :                   if (nv && nameref_p (nv))
    2858             :                     {
    2859             :                       /* If this nameref variable doesn't have a value yet,
    2860             :                          set the value.  Otherwise, assign using the value as
    2861             :                          normal. */
    2862           0 :                       if (nameref_cell (nv) == 0)
    2863           0 :                         return (bind_variable_internal (nv->name, value, nvc->table, 0, flags));
    2864             : #if defined (ARRAY_VARS)
    2865           0 :                       else if (valid_array_reference (nameref_cell (nv), 0))
    2866           0 :                         return (assign_array_element (nameref_cell (nv), value, flags));
    2867             :                       else
    2868             : #endif
    2869           0 :                       return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags));
    2870             :                     }
    2871           0 :                   else if (nv == &nameref_maxloop_value)
    2872             :                     {
    2873           0 :                       internal_warning (_("%s: circular name reference"), v->name);
    2874             : #if 0
    2875             :                       return (bind_variable_value (v, value, flags|ASS_NAMEREF));
    2876             : #else
    2877           0 :                       v = 0;    /* backwards compat */
    2878             : #endif
    2879             :                     }
    2880             :                   else
    2881             :                     v = nv;
    2882             :                 }
    2883           0 :               else if (nv == &nameref_maxloop_value)
    2884             :                 {
    2885           0 :                   internal_warning (_("%s: circular name reference"), v->name);
    2886             : #if 0
    2887             :                   return (bind_variable_value (v, value, flags|ASS_NAMEREF));
    2888             : #else
    2889           0 :                   v = 0;        /* backwards compat */
    2890             : #endif
    2891             :                 }
    2892             :               else
    2893             :                 v = nv;
    2894             :             }
    2895     2282998 :           if (v)
    2896           0 :             return (bind_variable_internal (v->name, value, nvc->table, 0, flags));
    2897             :         }
    2898             :     }
    2899             :   /* bind_variable_internal will handle nameref resolution in this case */
    2900   619173835 :   return (bind_variable_internal (name, value, global_variables->table, 0, flags));
    2901             : }
    2902             : 
    2903             : SHELL_VAR *
    2904           0 : bind_global_variable (name, value, flags)
    2905             :      const char *name;
    2906             :      char *value;
    2907             :      int flags;
    2908             : {
    2909           0 :   if (shell_variables == 0)
    2910           0 :     create_variable_tables ();
    2911             : 
    2912             :   /* bind_variable_internal will handle nameref resolution in this case */
    2913           0 :   return (bind_variable_internal (name, value, global_variables->table, 0, flags));
    2914             : }
    2915             : 
    2916             : /* Make VAR, a simple shell variable, have value VALUE.  Once assigned a
    2917             :    value, variables are no longer invisible.  This is a duplicate of part
    2918             :    of the internals of bind_variable.  If the variable is exported, or
    2919             :    all modified variables should be exported, mark the variable for export
    2920             :    and note that the export environment needs to be recreated. */
    2921             : SHELL_VAR *
    2922          12 : bind_variable_value (var, value, aflags)
    2923             :      SHELL_VAR *var;
    2924             :      char *value;
    2925             :      int aflags;
    2926             : {
    2927          12 :   char *t;
    2928          12 :   int invis;
    2929             : 
    2930          12 :   invis = invisible_p (var);
    2931          12 :   VUNSETATTR (var, att_invisible);
    2932             : 
    2933          12 :   if (var->assign_func)
    2934             :     {
    2935             :       /* If we're appending, we need the old value, so use
    2936             :          make_variable_value */
    2937           0 :       t = (aflags & ASS_APPEND) ? make_variable_value (var, value, aflags) : value;
    2938           0 :       (*(var->assign_func)) (var, t, -1, 0);
    2939           0 :       if (t != value && t)
    2940           0 :         free (t);      
    2941             :     }
    2942             :   else
    2943             :     {
    2944          12 :       t = make_variable_value (var, value, aflags);
    2945          12 :       if ((aflags & (ASS_NAMEREF|ASS_FORCE)) == ASS_NAMEREF && check_selfref (name_cell (var), t, 0))
    2946             :         {
    2947           0 :           if (variable_context)
    2948           0 :             internal_warning (_("%s: circular name reference"), name_cell (var));
    2949             :           else
    2950             :             {
    2951           0 :               internal_error (_("%s: nameref variable self references not allowed"), name_cell (var));
    2952           0 :               free (t);
    2953           0 :               if (invis)
    2954           0 :                 VSETATTR (var, att_invisible);  /* XXX */
    2955           0 :               return ((SHELL_VAR *)NULL);
    2956             :             }
    2957             :         }
    2958          12 :       if ((aflags & ASS_NAMEREF) && (valid_nameref_value (t, 0) == 0))
    2959             :         {
    2960           0 :           free (t);
    2961           0 :           if (invis)
    2962           0 :             VSETATTR (var, att_invisible);      /* XXX */
    2963           0 :           return ((SHELL_VAR *)NULL);
    2964             :         }
    2965          12 :       FREE (value_cell (var));
    2966          12 :       var_setvalue (var, t);
    2967             :     }
    2968             : 
    2969          12 :   INVALIDATE_EXPORTSTR (var);
    2970             : 
    2971          12 :   if (mark_modified_vars)
    2972           0 :     VSETATTR (var, att_exported);
    2973             : 
    2974          12 :   if (exported_p (var))
    2975           0 :     array_needs_making = 1;
    2976             : 
    2977             :   return (var);
    2978             : }
    2979             : 
    2980             : /* Bind/create a shell variable with the name LHS to the RHS.
    2981             :    This creates or modifies a variable such that it is an integer.
    2982             : 
    2983             :    This used to be in expr.c, but it is here so that all of the
    2984             :    variable binding stuff is localized.  Since we don't want any
    2985             :    recursive evaluation from bind_variable() (possible without this code,
    2986             :    since bind_variable() calls the evaluator for variables with the integer
    2987             :    attribute set), we temporarily turn off the integer attribute for each
    2988             :    variable we set here, then turn it back on after binding as necessary. */
    2989             : 
    2990             : SHELL_VAR *
    2991           0 : bind_int_variable (lhs, rhs)
    2992             :      char *lhs, *rhs;
    2993             : {
    2994           0 :   register SHELL_VAR *v;
    2995           0 :   int isint, isarr, implicitarray;
    2996             : 
    2997           0 :   isint = isarr = implicitarray = 0;
    2998             : #if defined (ARRAY_VARS)
    2999           0 :   if (valid_array_reference (lhs, 0))
    3000             :     {
    3001           0 :       isarr = 1;
    3002           0 :       v = array_variable_part (lhs, (char **)0, (int *)0);
    3003             :     }
    3004             :   else
    3005             : #endif
    3006           0 :     v = find_variable (lhs);
    3007             : 
    3008           0 :   if (v)
    3009             :     {
    3010           0 :       isint = integer_p (v);
    3011           0 :       VUNSETATTR (v, att_integer);
    3012             : #if defined (ARRAY_VARS)
    3013           0 :       if (array_p (v) && isarr == 0)
    3014           0 :         implicitarray = 1;
    3015             : #endif
    3016             :     }
    3017             : 
    3018             : #if defined (ARRAY_VARS)
    3019           0 :   if (isarr)
    3020           0 :     v = assign_array_element (lhs, rhs, 0);
    3021           0 :   else if (implicitarray)
    3022           0 :     v = bind_array_variable (lhs, 0, rhs, 0);
    3023             :   else
    3024             : #endif
    3025           0 :     v = bind_variable (lhs, rhs, 0);
    3026             : 
    3027           0 :   if (v)
    3028             :     {
    3029           0 :       if (isint)
    3030           0 :         VSETATTR (v, att_integer);
    3031           0 :       VUNSETATTR (v, att_invisible);
    3032             :     }
    3033             : 
    3034           0 :   if (v && nameref_p (v))
    3035           0 :     internal_warning (_("%s: assigning integer to name reference"), lhs);
    3036             :      
    3037           0 :   return (v);
    3038             : }
    3039             : 
    3040             : SHELL_VAR *
    3041           0 : bind_var_to_int (var, val)
    3042             :      char *var;
    3043             :      intmax_t val;
    3044             : {
    3045           0 :   char ibuf[INT_STRLEN_BOUND (intmax_t) + 1], *p;
    3046             : 
    3047           0 :   p = fmtulong (val, 10, ibuf, sizeof (ibuf), 0);
    3048           0 :   return (bind_int_variable (var, p));
    3049             : }
    3050             : 
    3051             : /* Do a function binding to a variable.  You pass the name and
    3052             :    the command to bind to.  This conses the name and command. */
    3053             : SHELL_VAR *
    3054    18703313 : bind_function (name, value)
    3055             :      const char *name;
    3056             :      COMMAND *value;
    3057             : {
    3058    18703313 :   SHELL_VAR *entry;
    3059             : 
    3060    18703313 :   entry = find_function (name);
    3061    18703313 :   if (entry == 0)
    3062             :     {
    3063    18703198 :       BUCKET_CONTENTS *elt;
    3064             : 
    3065    18703198 :       elt = hash_insert (savestring (name), shell_functions, HASH_NOSRCH);
    3066    18703198 :       entry = new_shell_variable (name);
    3067    18703198 :       elt->data = (PTR_T)entry;
    3068             :     }
    3069             :   else
    3070         115 :     INVALIDATE_EXPORTSTR (entry);
    3071             : 
    3072    18703313 :   if (var_isset (entry))
    3073         115 :     dispose_command (function_cell (entry));
    3074             : 
    3075    18703313 :   if (value)
    3076    18703313 :     var_setfunc (entry, copy_command (value));
    3077             :   else
    3078           0 :     var_setfunc (entry, 0);
    3079             : 
    3080    18703313 :   VSETATTR (entry, att_function);
    3081             : 
    3082    18703313 :   if (mark_modified_vars)
    3083           0 :     VSETATTR (entry, att_exported);
    3084             : 
    3085    18703313 :   VUNSETATTR (entry, att_invisible);            /* Just to be sure */
    3086             : 
    3087    18703313 :   if (exported_p (entry))
    3088           0 :     array_needs_making = 1;
    3089             : 
    3090             : #if defined (PROGRAMMABLE_COMPLETION)
    3091             :   set_itemlist_dirty (&it_functions);
    3092             : #endif
    3093             : 
    3094    18703313 :   return (entry);
    3095             : }
    3096             : 
    3097             : #if defined (DEBUGGER)
    3098             : /* Bind a function definition, which includes source file and line number
    3099             :    information in addition to the command, into the FUNCTION_DEF hash table.*/
    3100             : void
    3101    37467069 : bind_function_def (name, value)
    3102             :      const char *name;
    3103             :      FUNCTION_DEF *value;
    3104             : {
    3105    37467069 :   FUNCTION_DEF *entry;
    3106    37467069 :   BUCKET_CONTENTS *elt;
    3107    37467069 :   COMMAND *cmd;
    3108             : 
    3109    37467069 :   entry = find_function_def (name);
    3110    37467069 :   if (entry)
    3111             :     {
    3112    18703507 :       dispose_function_def_contents (entry);
    3113    18703507 :       entry = copy_function_def_contents (value, entry);
    3114             :     }
    3115             :   else
    3116             :     {
    3117    18763562 :       cmd = value->command;
    3118    18763562 :       value->command = 0;
    3119    18763562 :       entry = copy_function_def (value);
    3120    18763562 :       value->command = cmd;
    3121             : 
    3122    18763562 :       elt = hash_insert (savestring (name), shell_function_defs, HASH_NOSRCH);
    3123    18763562 :       elt->data = (PTR_T *)entry;
    3124             :     }
    3125    37467069 : }
    3126             : #endif /* DEBUGGER */
    3127             : 
    3128             : /* Add STRING, which is of the form foo=bar, to the temporary environment
    3129             :    HASH_TABLE (temporary_env).  The functions in execute_cmd.c are
    3130             :    responsible for moving the main temporary env to one of the other
    3131             :    temporary environments.  The expansion code in subst.c calls this. */
    3132             : int
    3133        7199 : assign_in_env (word, flags)
    3134             :      WORD_DESC *word;
    3135             :      int flags;
    3136             : {
    3137        7199 :   int offset, aflags;
    3138        7199 :   char *name, *temp, *value, *newname;
    3139        7199 :   SHELL_VAR *var;
    3140        7199 :   const char *string;
    3141             : 
    3142        7199 :   string = word->word;
    3143             : 
    3144        7199 :   aflags = 0;
    3145        7199 :   offset = assignment (string, 0);
    3146        7199 :   newname = name = savestring (string);
    3147        7199 :   value = (char *)NULL;
    3148             : 
    3149        7199 :   if (name[offset] == '=')
    3150             :     {
    3151        7199 :       name[offset] = 0;
    3152             : 
    3153             :       /* don't ignore the `+' when assigning temporary environment */
    3154        7199 :       if (name[offset - 1] == '+')
    3155             :         {
    3156          19 :           name[offset - 1] = '\0';
    3157          19 :           aflags |= ASS_APPEND;
    3158             :         }
    3159             : 
    3160        7199 :       var = find_variable (name);
    3161        7199 :       if (var == 0)
    3162             :         {
    3163        7016 :           var = find_variable_last_nameref (name, 1);
    3164             :           /* If we're assigning a value to a nameref variable in the temp
    3165             :              environment, and the value of the nameref is valid for assignment,
    3166             :              but the variable does not already exist, assign to the nameref
    3167             :              target and add the target to the temporary environment.  This is
    3168             :              what ksh93 does */
    3169        7016 :           if (var && nameref_p (var) && valid_nameref_value (nameref_cell (var), 1))
    3170             :             {
    3171           0 :               newname = nameref_cell (var);
    3172           0 :               var = 0;          /* don't use it for append */
    3173             :             }
    3174             :         }
    3175             :       else
    3176         183 :         newname = name_cell (var);      /* no-op if not nameref */
    3177             :           
    3178        7199 :       if (var && (readonly_p (var) || noassign_p (var)))
    3179             :         {
    3180           0 :           if (readonly_p (var))
    3181           0 :             err_readonly (name);
    3182           0 :           free (name);
    3183           0 :           return (0);
    3184             :         }
    3185        7199 :       temp = name + offset + 1;
    3186             : 
    3187        7199 :       value = expand_assignment_string_to_string (temp, 0);
    3188             : 
    3189        7198 :       if (var && (aflags & ASS_APPEND))
    3190             :         {
    3191           0 :           if (value == 0)
    3192             :             {
    3193           0 :               value = (char *)xmalloc (1);      /* like do_assignment_internal */
    3194           0 :               value[0] = '\0';
    3195             :             }
    3196           0 :           temp = make_variable_value (var, value, aflags);
    3197           0 :           FREE (value);
    3198             :           value = temp;
    3199             :         }
    3200             :     }
    3201             : 
    3202        7198 :   if (temporary_env == 0)
    3203        7189 :     temporary_env = hash_create (TEMPENV_HASH_BUCKETS);
    3204             : 
    3205        7198 :   var = hash_lookup (newname, temporary_env);
    3206           0 :   if (var == 0)
    3207        7198 :     var = make_new_variable (newname, temporary_env);
    3208             :   else
    3209           0 :     FREE (value_cell (var));
    3210             : 
    3211        7198 :   if (value == 0)
    3212             :     {
    3213         313 :       value = (char *)xmalloc (1);      /* see above */
    3214         313 :       value[0] = '\0';
    3215             :     }
    3216             : 
    3217        7198 :   var_setvalue (var, value);
    3218        7198 :   var->attributes |= (att_exported|att_tempvar);
    3219        7198 :   var->context = variable_context;   /* XXX */
    3220             : 
    3221        7198 :   INVALIDATE_EXPORTSTR (var);
    3222        7198 :   var->exportstr = mk_env_string (newname, value, 0);
    3223             : 
    3224        7198 :   array_needs_making = 1;
    3225             : 
    3226        7198 :   if (flags)
    3227         144 :     stupidly_hack_special_variables (newname);
    3228             : 
    3229        7198 :   if (echo_command_at_execute)
    3230             :     /* The Korn shell prints the `+ ' in front of assignment statements,
    3231             :         so we do too. */
    3232           0 :     xtrace_print_assignment (name, value, 0, 1);
    3233             : 
    3234        7198 :   free (name);
    3235        7198 :   return 1;
    3236             : }
    3237             : 
    3238             : /* **************************************************************** */
    3239             : /*                                                                  */
    3240             : /*                      Copying variables                           */
    3241             : /*                                                                  */
    3242             : /* **************************************************************** */
    3243             : 
    3244             : #ifdef INCLUDE_UNUSED
    3245             : /* Copy VAR to a new data structure and return that structure. */
    3246             : SHELL_VAR *
    3247             : copy_variable (var)
    3248             :      SHELL_VAR *var;
    3249             : {
    3250             :   SHELL_VAR *copy = (SHELL_VAR *)NULL;
    3251             : 
    3252             :   if (var)
    3253             :     {
    3254             :       copy = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
    3255             : 
    3256             :       copy->attributes = var->attributes;
    3257             :       copy->name = savestring (var->name);
    3258             : 
    3259             :       if (function_p (var))
    3260             :         var_setfunc (copy, copy_command (function_cell (var)));
    3261             : #if defined (ARRAY_VARS)
    3262             :       else if (array_p (var))
    3263             :         var_setarray (copy, array_copy (array_cell (var)));
    3264             :       else if (assoc_p (var))
    3265             :         var_setassoc (copy, assoc_copy (assoc_cell (var)));
    3266             : #endif
    3267             :       else if (nameref_cell (var))      /* XXX - nameref */
    3268             :         var_setref (copy, savestring (nameref_cell (var)));
    3269             :       else if (value_cell (var))        /* XXX - nameref */
    3270             :         var_setvalue (copy, savestring (value_cell (var)));
    3271             :       else
    3272             :         var_setvalue (copy, (char *)NULL);
    3273             : 
    3274             :       copy->dynamic_value = var->dynamic_value;
    3275             :       copy->assign_func = var->assign_func;
    3276             : 
    3277             :       copy->exportstr = COPY_EXPORTSTR (var);
    3278             : 
    3279             :       copy->context = var->context;
    3280             :     }
    3281             :   return (copy);
    3282             : }
    3283             : #endif
    3284             : 
    3285             : /* **************************************************************** */
    3286             : /*                                                                  */
    3287             : /*                Deleting and unsetting variables                  */
    3288             : /*                                                                  */
    3289             : /* **************************************************************** */
    3290             : 
    3291             : /* Dispose of the information attached to VAR. */
    3292             : static void
    3293           0 : dispose_variable_value (var)
    3294             :      SHELL_VAR *var;
    3295             : {
    3296           0 :   if (function_p (var))
    3297           0 :     dispose_command (function_cell (var));
    3298             : #if defined (ARRAY_VARS)
    3299           0 :   else if (array_p (var))
    3300           0 :     array_dispose (array_cell (var));
    3301           0 :   else if (assoc_p (var))
    3302           0 :     assoc_dispose (assoc_cell (var));
    3303             : #endif
    3304           0 :   else if (nameref_p (var))
    3305           0 :     FREE (nameref_cell (var));
    3306             :   else
    3307           0 :     FREE (value_cell (var));
    3308           0 : }
    3309             : 
    3310             : void
    3311        6967 : dispose_variable (var)
    3312             :      SHELL_VAR *var;
    3313             : {
    3314        6967 :   if (var == 0)
    3315             :     return;
    3316             : 
    3317        6967 :   if (nofree_p (var) == 0)
    3318        6967 :     dispose_variable_value (var);
    3319             : 
    3320        6967 :   FREE_EXPORTSTR (var);
    3321             : 
    3322        6967 :   free (var->name);
    3323             : 
    3324        6967 :   if (exported_p (var))
    3325        6967 :     array_needs_making = 1;
    3326             : 
    3327        6967 :   free (var);
    3328             : }
    3329             : 
    3330             : /* Unset the shell variable referenced by NAME.  Unsetting a nameref variable
    3331             :    unsets the variable it resolves to but leaves the nameref alone. */
    3332             : int
    3333    19085816 : unbind_variable (name)
    3334             :      const char *name;
    3335             : {
    3336    19085816 :   SHELL_VAR *v, *nv;
    3337    19085816 :   int r;
    3338             : 
    3339    19085816 :   v = var_lookup (name, shell_variables);
    3340    19085816 :   nv = (v && nameref_p (v)) ? find_variable_nameref (v) : (SHELL_VAR *)NULL;
    3341             : 
    3342    19085816 :   r = nv ? makunbound (nv->name, shell_variables) : makunbound (name, shell_variables);
    3343    19085816 :   return r;
    3344             : }
    3345             : 
    3346             : /* Unbind NAME, where NAME is assumed to be a nameref variable */
    3347             : int
    3348           0 : unbind_nameref (name)
    3349             :      const char *name;
    3350             : {
    3351           0 :   SHELL_VAR *v;
    3352             : 
    3353           0 :   v = var_lookup (name, shell_variables);
    3354           0 :   if (v && nameref_p (v))
    3355           0 :     return makunbound (name, shell_variables);
    3356             :   return 0;
    3357             : }
    3358             : 
    3359             : /* Unbind the first instance of NAME, whether it's a nameref or not */
    3360             : int
    3361     9542884 : unbind_variable_noref (name)
    3362             :      const char *name;
    3363             : {
    3364     9542884 :   SHELL_VAR *v;
    3365             : 
    3366     9542884 :   v = var_lookup (name, shell_variables);
    3367     9542884 :   if (v)
    3368           0 :     return makunbound (name, shell_variables);
    3369             :   return 0;
    3370             : }
    3371             : 
    3372             : int
    3373           0 : check_unbind_variable (name)
    3374             :      const char *name;
    3375             : {
    3376           0 :   SHELL_VAR *v;
    3377             : 
    3378           0 :   v = find_variable (name);
    3379           0 :   if (v && readonly_p (v))
    3380             :     {
    3381           0 :       internal_error (_("%s: cannot unset: readonly %s"), name, "variable");
    3382           0 :       return -1;
    3383             :     }
    3384           0 :   return (unbind_variable (name));
    3385             : }
    3386             : 
    3387             : /* Unset the shell function named NAME. */
    3388             : int
    3389          48 : unbind_func (name)
    3390             :      const char *name;
    3391             : {
    3392          48 :   BUCKET_CONTENTS *elt;
    3393          48 :   SHELL_VAR *func;
    3394             : 
    3395          48 :   elt = hash_remove (name, shell_functions, 0);
    3396             : 
    3397          48 :   if (elt == 0)
    3398             :     return -1;
    3399             : 
    3400             : #if defined (PROGRAMMABLE_COMPLETION)
    3401             :   set_itemlist_dirty (&it_functions);
    3402             : #endif
    3403             : 
    3404           0 :   func = (SHELL_VAR *)elt->data;
    3405           0 :   if (func)
    3406             :     {
    3407           0 :       if (exported_p (func))
    3408           0 :         array_needs_making++;
    3409           0 :       dispose_variable (func);
    3410             :     }
    3411             : 
    3412           0 :   free (elt->key);
    3413           0 :   free (elt);
    3414             : 
    3415           0 :   return 0;  
    3416             : }
    3417             : 
    3418             : #if defined (DEBUGGER)
    3419             : int
    3420           0 : unbind_function_def (name)
    3421             :      const char *name;
    3422             : {
    3423           0 :   BUCKET_CONTENTS *elt;
    3424           0 :   FUNCTION_DEF *funcdef;
    3425             : 
    3426           0 :   elt = hash_remove (name, shell_function_defs, 0);
    3427             : 
    3428           0 :   if (elt == 0)
    3429             :     return -1;
    3430             : 
    3431           0 :   funcdef = (FUNCTION_DEF *)elt->data;
    3432           0 :   if (funcdef)
    3433           0 :     dispose_function_def (funcdef);
    3434             : 
    3435           0 :   free (elt->key);
    3436           0 :   free (elt);
    3437             : 
    3438           0 :   return 0;  
    3439             : }
    3440             : #endif /* DEBUGGER */
    3441             : 
    3442             : int
    3443           0 : delete_var (name, vc)
    3444             :      const char *name;
    3445             :      VAR_CONTEXT *vc;
    3446             : {
    3447           0 :   BUCKET_CONTENTS *elt;
    3448           0 :   SHELL_VAR *old_var;
    3449           0 :   VAR_CONTEXT *v;
    3450             : 
    3451           0 :   for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down)
    3452           0 :     if (elt = hash_remove (name, v->table, 0))
    3453             :       break;
    3454             : 
    3455           0 :   if (elt == 0)
    3456             :     return (-1);
    3457             : 
    3458           0 :   old_var = (SHELL_VAR *)elt->data;
    3459           0 :   free (elt->key);
    3460           0 :   free (elt);
    3461             : 
    3462           0 :   dispose_variable (old_var);
    3463           0 :   return (0);
    3464             : }
    3465             : 
    3466             : /* Make the variable associated with NAME go away.  HASH_LIST is the
    3467             :    hash table from which this variable should be deleted (either
    3468             :    shell_variables or shell_functions).
    3469             :    Returns non-zero if the variable couldn't be found. */
    3470             : int
    3471    19085816 : makunbound (name, vc)
    3472             :      const char *name;
    3473             :      VAR_CONTEXT *vc;
    3474             : {
    3475    19085816 :   BUCKET_CONTENTS *elt, *new_elt;
    3476    19085816 :   SHELL_VAR *old_var;
    3477    19085816 :   VAR_CONTEXT *v;
    3478    19085816 :   char *t;
    3479             : 
    3480    38171632 :   for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down)
    3481    19085816 :     if (elt = hash_remove (name, v->table, 0))
    3482             :       break;
    3483             : 
    3484    19085816 :   if (elt == 0)
    3485             :     return (-1);
    3486             : 
    3487           0 :   old_var = (SHELL_VAR *)elt->data;
    3488             : 
    3489           0 :   if (old_var && exported_p (old_var))
    3490           0 :     array_needs_making++;
    3491             : 
    3492             :   /* If we're unsetting a local variable and we're still executing inside
    3493             :      the function, just mark the variable as invisible.  The function
    3494             :      eventually called by pop_var_context() will clean it up later.  This
    3495             :      must be done so that if the variable is subsequently assigned a new
    3496             :      value inside the function, the `local' attribute is still present.
    3497             :      We also need to add it back into the correct hash table. */
    3498           0 :   if (old_var && local_p (old_var) && variable_context == old_var->context)
    3499             :     {
    3500           0 :       if (nofree_p (old_var))
    3501             :         var_setvalue (old_var, (char *)NULL);
    3502             : #if defined (ARRAY_VARS)
    3503           0 :       else if (array_p (old_var))
    3504           0 :         array_dispose (array_cell (old_var));
    3505           0 :       else if (assoc_p (old_var))
    3506           0 :         assoc_dispose (assoc_cell (old_var));
    3507             : #endif
    3508           0 :       else if (nameref_p (old_var))
    3509           0 :         FREE (nameref_cell (old_var));
    3510             :       else
    3511           0 :         FREE (value_cell (old_var));
    3512             :       /* Reset the attributes.  Preserve the export attribute if the variable
    3513             :          came from a temporary environment.  Make sure it stays local, and
    3514             :          make it invisible. */ 
    3515           0 :       old_var->attributes = (exported_p (old_var) && tempvar_p (old_var)) ? att_exported : 0;
    3516           0 :       VSETATTR (old_var, att_local);
    3517           0 :       VSETATTR (old_var, att_invisible);
    3518           0 :       var_setvalue (old_var, (char *)NULL);
    3519           0 :       INVALIDATE_EXPORTSTR (old_var);
    3520             : 
    3521           0 :       new_elt = hash_insert (savestring (old_var->name), v->table, 0);
    3522           0 :       new_elt->data = (PTR_T)old_var;
    3523           0 :       stupidly_hack_special_variables (old_var->name);
    3524             : 
    3525           0 :       free (elt->key);
    3526           0 :       free (elt);
    3527           0 :       return (0);
    3528             :     }
    3529             : 
    3530             :   /* Have to save a copy of name here, because it might refer to
    3531             :      old_var->name.  If so, stupidly_hack_special_variables will
    3532             :      reference freed memory. */
    3533           0 :   t = savestring (name);
    3534             : 
    3535           0 :   free (elt->key);
    3536           0 :   free (elt);
    3537             : 
    3538           0 :   dispose_variable (old_var);
    3539           0 :   stupidly_hack_special_variables (t);
    3540           0 :   free (t);
    3541             : 
    3542           0 :   return (0);
    3543             : }
    3544             : 
    3545             : /* Get rid of all of the variables in the current context. */
    3546             : void
    3547           0 : kill_all_local_variables ()
    3548             : {
    3549           0 :   VAR_CONTEXT *vc;
    3550             : 
    3551           0 :   for (vc = shell_variables; vc; vc = vc->down)
    3552           0 :     if (vc_isfuncenv (vc) && vc->scope == variable_context)
    3553             :       break;
    3554           0 :   if (vc == 0)
    3555             :     return;             /* XXX */
    3556             : 
    3557           0 :   if (vc->table && vc_haslocals (vc))
    3558             :     {
    3559           0 :       delete_all_variables (vc->table);
    3560           0 :       hash_dispose (vc->table);
    3561             :     }
    3562           0 :   vc->table = (HASH_TABLE *)NULL;
    3563             : }
    3564             : 
    3565             : static void
    3566           0 : free_variable_hash_data (data)
    3567             :      PTR_T data;
    3568             : {
    3569           0 :   SHELL_VAR *var;
    3570             : 
    3571           0 :   var = (SHELL_VAR *)data;
    3572           0 :   dispose_variable (var);
    3573           0 : }
    3574             : 
    3575             : /* Delete the entire contents of the hash table. */
    3576             : void
    3577           0 : delete_all_variables (hashed_vars)
    3578             :      HASH_TABLE *hashed_vars;
    3579             : {
    3580           0 :   hash_flush (hashed_vars, free_variable_hash_data);
    3581           0 : }
    3582             : 
    3583             : /* **************************************************************** */
    3584             : /*                                                                  */
    3585             : /*                   Setting variable attributes                    */
    3586             : /*                                                                  */
    3587             : /* **************************************************************** */
    3588             : 
    3589             : #define FIND_OR_MAKE_VARIABLE(name, entry) \
    3590             :   do \
    3591             :     { \
    3592             :       entry = find_variable (name); \
    3593             :       if (!entry) \
    3594             :         { \
    3595             :           entry = bind_variable (name, "", 0); \
    3596             :           if (!no_invisible_vars && entry) entry->attributes |= att_invisible; \
    3597             :         } \
    3598             :     } \
    3599             :   while (0)
    3600             : 
    3601             : /* Make the variable associated with NAME be readonly.
    3602             :    If NAME does not exist yet, create it. */
    3603             : void
    3604           0 : set_var_read_only (name)
    3605             :      char *name;
    3606             : {
    3607           0 :   SHELL_VAR *entry;
    3608             : 
    3609           0 :   FIND_OR_MAKE_VARIABLE (name, entry);
    3610           0 :   VSETATTR (entry, att_readonly);
    3611           0 : }
    3612             : 
    3613             : #ifdef INCLUDE_UNUSED
    3614             : /* Make the function associated with NAME be readonly.
    3615             :    If NAME does not exist, we just punt, like auto_export code below. */
    3616             : void
    3617             : set_func_read_only (name)
    3618             :      const char *name;
    3619             : {
    3620             :   SHELL_VAR *entry;
    3621             : 
    3622             :   entry = find_function (name);
    3623             :   if (entry)
    3624             :     VSETATTR (entry, att_readonly);
    3625             : }
    3626             : 
    3627             : /* Make the variable associated with NAME be auto-exported.
    3628             :    If NAME does not exist yet, create it. */
    3629             : void
    3630             : set_var_auto_export (name)
    3631             :      char *name;
    3632             : {
    3633             :   SHELL_VAR *entry;
    3634             : 
    3635             :   FIND_OR_MAKE_VARIABLE (name, entry);
    3636             :   set_auto_export (entry);
    3637             : }
    3638             : 
    3639             : /* Make the function associated with NAME be auto-exported. */
    3640             : void
    3641             : set_func_auto_export (name)
    3642             :      const char *name;
    3643             : {
    3644             :   SHELL_VAR *entry;
    3645             : 
    3646             :   entry = find_function (name);
    3647             :   if (entry)
    3648             :     set_auto_export (entry);
    3649             : }
    3650             : #endif
    3651             : 
    3652             : /* **************************************************************** */
    3653             : /*                                                                  */
    3654             : /*                   Creating lists of variables                    */
    3655             : /*                                                                  */
    3656             : /* **************************************************************** */
    3657             : 
    3658             : static VARLIST *
    3659    11230753 : vlist_alloc (nentries)
    3660             :      int nentries;
    3661             : {
    3662    11230753 :   VARLIST  *vlist;
    3663             : 
    3664    11230753 :   vlist = (VARLIST *)xmalloc (sizeof (VARLIST));
    3665    11230753 :   vlist->list = (SHELL_VAR **)xmalloc ((nentries + 1) * sizeof (SHELL_VAR *));
    3666    11230753 :   vlist->list_size = nentries;
    3667    11230753 :   vlist->list_len = 0;
    3668    11230753 :   vlist->list[0] = (SHELL_VAR *)NULL;
    3669             : 
    3670    11230753 :   return vlist;
    3671             : }
    3672             : 
    3673             : static VARLIST *
    3674           0 : vlist_realloc (vlist, n)
    3675             :      VARLIST *vlist;
    3676             :      int n;
    3677             : {
    3678           0 :   if (vlist == 0)
    3679           0 :     return (vlist = vlist_alloc (n));
    3680           0 :   if (n > vlist->list_size)
    3681             :     {
    3682           0 :       vlist->list_size = n;
    3683           0 :       vlist->list = (SHELL_VAR **)xrealloc (vlist->list, (vlist->list_size + 1) * sizeof (SHELL_VAR *));
    3684             :     }
    3685             :   return vlist;
    3686             : }
    3687             : 
    3688             : static void
    3689           0 : vlist_add (vlist, var, flags)
    3690             :      VARLIST *vlist;
    3691             :      SHELL_VAR *var;
    3692             :      int flags;
    3693             : {
    3694           0 :   register int i;
    3695             : 
    3696           0 :   for (i = 0; i < vlist->list_len; i++)
    3697           0 :     if (STREQ (var->name, vlist->list[i]->name))
    3698             :       break;
    3699           0 :   if (i < vlist->list_len)
    3700           0 :     return;
    3701             : 
    3702           0 :   if (i >= vlist->list_size)
    3703           0 :     vlist = vlist_realloc (vlist, vlist->list_size + 16);
    3704             : 
    3705           0 :   vlist->list[vlist->list_len++] = var;
    3706           0 :   vlist->list[vlist->list_len] = (SHELL_VAR *)NULL;
    3707             : }
    3708             : 
    3709             : /* Map FUNCTION over the variables in VAR_HASH_TABLE.  Return an array of the
    3710             :    variables for which FUNCTION returns a non-zero value.  A NULL value
    3711             :    for FUNCTION means to use all variables. */
    3712             : SHELL_VAR **
    3713    11225488 : map_over (function, vc)
    3714             :      sh_var_map_func_t *function;
    3715             :      VAR_CONTEXT *vc;
    3716             : {
    3717    11225488 :   VAR_CONTEXT *v;
    3718    11225488 :   VARLIST *vlist;
    3719    11225488 :   SHELL_VAR **ret;
    3720    11225488 :   int nentries;
    3721             : 
    3722    22453708 :   for (nentries = 0, v = vc; v; v = v->down)
    3723    11228220 :     nentries += HASH_ENTRIES (v->table);
    3724             : 
    3725    11225488 :   if (nentries == 0)
    3726             :     return (SHELL_VAR **)NULL;
    3727             : 
    3728    11225488 :   vlist = vlist_alloc (nentries);
    3729             : 
    3730    22453708 :   for (v = vc; v; v = v->down)
    3731    11228220 :     flatten (v->table, function, vlist, 0);
    3732             : 
    3733    11225488 :   ret = vlist->list;
    3734    11225488 :   free (vlist);
    3735    11225488 :   return ret;
    3736             : }
    3737             : 
    3738             : SHELL_VAR **
    3739    11225304 : map_over_funcs (function)
    3740             :      sh_var_map_func_t *function;
    3741             : {
    3742    11225304 :   VARLIST *vlist;
    3743    11225304 :   SHELL_VAR **ret;
    3744             : 
    3745    11225304 :   if (shell_functions == 0 || HASH_ENTRIES (shell_functions) == 0)
    3746             :     return ((SHELL_VAR **)NULL);
    3747             : 
    3748        5265 :   vlist = vlist_alloc (HASH_ENTRIES (shell_functions));
    3749             : 
    3750        5265 :   flatten (shell_functions, function, vlist, 0);
    3751             : 
    3752        5265 :   ret = vlist->list;
    3753        5265 :   free (vlist);
    3754        5265 :   return ret;
    3755             : }
    3756             : 
    3757             : /* Flatten VAR_HASH_TABLE, applying FUNC to each member and adding those
    3758             :    elements for which FUNC succeeds to VLIST->list.  FLAGS is reserved
    3759             :    for future use.  Only unique names are added to VLIST.  If FUNC is
    3760             :    NULL, each variable in VAR_HASH_TABLE is added to VLIST.  If VLIST is
    3761             :    NULL, FUNC is applied to each SHELL_VAR in VAR_HASH_TABLE.  If VLIST
    3762             :    and FUNC are both NULL, nothing happens. */
    3763             : static void
    3764           0 : flatten (var_hash_table, func, vlist, flags)
    3765             :      HASH_TABLE *var_hash_table;
    3766             :      sh_var_map_func_t *func;
    3767             :      VARLIST *vlist;
    3768             :      int flags;
    3769             : {
    3770           0 :   register int i;
    3771           0 :   register BUCKET_CONTENTS *tlist;
    3772           0 :   int r;
    3773           0 :   SHELL_VAR *var;
    3774             : 
    3775           0 :   if (var_hash_table == 0 || (HASH_ENTRIES (var_hash_table) == 0) || (vlist == 0 && func == 0))
    3776           0 :     return;
    3777             : 
    3778           0 :   for (i = 0; i < var_hash_table->nbuckets; i++)
    3779             :     {
    3780           0 :       for (tlist = hash_items (i, var_hash_table); tlist; tlist = tlist->next)
    3781             :         {
    3782           0 :           var = (SHELL_VAR *)tlist->data;
    3783             : 
    3784           0 :           r = func ? (*func) (var) : 1;
    3785           0 :           if (r && vlist)
    3786           0 :             vlist_add (vlist, var, flags);
    3787             :         }
    3788             :     }
    3789             : }
    3790             : 
    3791             : void
    3792         405 : sort_variables (array)
    3793             :      SHELL_VAR **array;
    3794             : {
    3795         405 :   qsort (array, strvec_len ((char **)array), sizeof (SHELL_VAR *), (QSFUNC *)qsort_var_comp);
    3796         405 : }
    3797             : 
    3798             : static int
    3799      118626 : qsort_var_comp (var1, var2)
    3800             :      SHELL_VAR **var1, **var2;
    3801             : {
    3802      118626 :   int result;
    3803             : 
    3804      118626 :   if ((result = (*var1)->name[0] - (*var2)->name[0]) == 0)
    3805       36471 :     result = strcmp ((*var1)->name, (*var2)->name);
    3806             : 
    3807      118626 :   return (result);
    3808             : }
    3809             : 
    3810             : /* Apply FUNC to each variable in SHELL_VARIABLES, adding each one for
    3811             :    which FUNC succeeds to an array of SHELL_VAR *s.  Returns the array. */
    3812             : static SHELL_VAR **
    3813         341 : vapply (func)
    3814             :      sh_var_map_func_t *func;
    3815             : {
    3816         341 :   SHELL_VAR **list;
    3817             : 
    3818         341 :   list = map_over (func, shell_variables);
    3819         341 :   if (list /* && posixly_correct */)
    3820         341 :     sort_variables (list);
    3821         341 :   return (list);
    3822             : }
    3823             : 
    3824             : /* Apply FUNC to each variable in SHELL_FUNCTIONS, adding each one for
    3825             :    which FUNC succeeds to an array of SHELL_VAR *s.  Returns the array. */
    3826             : static SHELL_VAR **
    3827             : fapply (func)
    3828             :      sh_var_map_func_t *func;
    3829             : {
    3830         157 :   SHELL_VAR **list;
    3831             : 
    3832         314 :   list = map_over_funcs (func);
    3833         157 :   if (list /* && posixly_correct */)
    3834          64 :     sort_variables (list);
    3835         157 :   return (list);
    3836             : }
    3837             : 
    3838             : /* Create a NULL terminated array of all the shell variables. */
    3839             : SHELL_VAR **
    3840         341 : all_shell_variables ()
    3841             : {
    3842         341 :   return (vapply ((sh_var_map_func_t *)NULL));
    3843             : }
    3844             : 
    3845             : /* Create a NULL terminated array of all the shell functions. */
    3846             : SHELL_VAR **
    3847         157 : all_shell_functions ()
    3848             : {
    3849         157 :   return (fapply ((sh_var_map_func_t *)NULL));
    3850             : }
    3851             : 
    3852             : static int
    3853           0 : visible_var (var)
    3854             :      SHELL_VAR *var;
    3855             : {
    3856           0 :   return (invisible_p (var) == 0);
    3857             : }
    3858             : 
    3859             : SHELL_VAR **
    3860           0 : all_visible_functions ()
    3861             : {
    3862           0 :   return (fapply (visible_var));
    3863             : }
    3864             : 
    3865             : SHELL_VAR **
    3866           0 : all_visible_variables ()
    3867             : {
    3868           0 :   return (vapply (visible_var));
    3869             : }
    3870             : 
    3871             : /* Return non-zero if the variable VAR is visible and exported.  Array
    3872             :    variables cannot be exported. */
    3873             : static int
    3874       11154 : visible_and_exported (var)
    3875             :      SHELL_VAR *var;
    3876             : {
    3877       11154 :   return (invisible_p (var) == 0 && exported_p (var));
    3878             : }
    3879             : 
    3880             : /* Candidate variables for the export environment are either valid variables
    3881             :    with the export attribute or invalid variables inherited from the initial
    3882             :    environment and simply passed through. */
    3883             : static int
    3884   755415881 : export_environment_candidate (var)
    3885             :      SHELL_VAR *var;
    3886             : {
    3887   755415881 :   return (exported_p (var) && (invisible_p (var) == 0 || imported_p (var)));
    3888             : }
    3889             : 
    3890             : /* Return non-zero if VAR is a local variable in the current context and
    3891             :    is exported. */
    3892             : static int
    3893           0 : local_and_exported (var)
    3894             :      SHELL_VAR *var;
    3895             : {
    3896           0 :   return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context && exported_p (var));
    3897             : }
    3898             : 
    3899             : SHELL_VAR **
    3900           0 : all_exported_variables ()
    3901             : {
    3902           0 :   return (vapply (visible_and_exported));
    3903             : }
    3904             : 
    3905             : SHELL_VAR **
    3906           0 : local_exported_variables ()
    3907             : {
    3908           0 :   return (vapply (local_and_exported));
    3909             : }
    3910             : 
    3911             : static int
    3912           0 : variable_in_context (var)
    3913             :      SHELL_VAR *var;
    3914             : {
    3915           0 :   return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context);
    3916             : }
    3917             : 
    3918             : SHELL_VAR **
    3919           0 : all_local_variables ()
    3920             : {
    3921           0 :   VARLIST *vlist;
    3922           0 :   SHELL_VAR **ret;
    3923           0 :   VAR_CONTEXT *vc;
    3924             : 
    3925           0 :   vc = shell_variables;
    3926           0 :   for (vc = shell_variables; vc; vc = vc->down)
    3927           0 :     if (vc_isfuncenv (vc) && vc->scope == variable_context)
    3928             :       break;
    3929             : 
    3930           0 :   if (vc == 0)
    3931             :     {
    3932           0 :       internal_error (_("all_local_variables: no function context at current scope"));
    3933           0 :       return (SHELL_VAR **)NULL;
    3934             :     }
    3935           0 :   if (vc->table == 0 || HASH_ENTRIES (vc->table) == 0 || vc_haslocals (vc) == 0)
    3936             :     return (SHELL_VAR **)NULL;
    3937             :     
    3938           0 :   vlist = vlist_alloc (HASH_ENTRIES (vc->table));
    3939             : 
    3940           0 :   flatten (vc->table, variable_in_context, vlist, 0);
    3941             : 
    3942           0 :   ret = vlist->list;
    3943           0 :   free (vlist);
    3944           0 :   if (ret)
    3945           0 :     sort_variables (ret);
    3946             :   return ret;
    3947             : }
    3948             : 
    3949             : #if defined (ARRAY_VARS)
    3950             : /* Return non-zero if the variable VAR is visible and an array. */
    3951             : static int
    3952           0 : visible_array_vars (var)
    3953             :      SHELL_VAR *var;
    3954             : {
    3955           0 :   return (invisible_p (var) == 0 && array_p (var));
    3956             : }
    3957             : 
    3958             : SHELL_VAR **
    3959           0 : all_array_variables ()
    3960             : {
    3961           0 :   return (vapply (visible_array_vars));
    3962             : }
    3963             : #endif /* ARRAY_VARS */
    3964             : 
    3965             : char **
    3966           0 : all_variables_matching_prefix (prefix)
    3967             :      const char *prefix;
    3968             : {
    3969           0 :   SHELL_VAR **varlist;
    3970           0 :   char **rlist;
    3971           0 :   int vind, rind, plen;
    3972             : 
    3973           0 :   plen = STRLEN (prefix);
    3974           0 :   varlist = all_visible_variables ();
    3975           0 :   for (vind = 0; varlist && varlist[vind]; vind++)
    3976           0 :     ;
    3977           0 :   if (varlist == 0 || vind == 0)
    3978             :     return ((char **)NULL);
    3979           0 :   rlist = strvec_create (vind + 1);
    3980           0 :   for (vind = rind = 0; varlist[vind]; vind++)
    3981             :     {
    3982           0 :       if (plen == 0 || STREQN (prefix, varlist[vind]->name, plen))
    3983           0 :         rlist[rind++] = savestring (varlist[vind]->name);
    3984             :     }
    3985           0 :   rlist[rind] = (char *)0;
    3986           0 :   free (varlist);
    3987             : 
    3988           0 :   return rlist;
    3989             : }
    3990             : 
    3991             : /* **************************************************************** */
    3992             : /*                                                                  */
    3993             : /*               Managing temporary variable scopes                 */
    3994             : /*                                                                  */
    3995             : /* **************************************************************** */
    3996             : 
    3997             : /* Make variable NAME have VALUE in the temporary environment. */
    3998             : static SHELL_VAR *
    3999        6961 : bind_tempenv_variable (name, value)
    4000             :      const char *name;
    4001             :      char *value;
    4002             : {
    4003        6961 :   SHELL_VAR *var;
    4004             : 
    4005        6961 :   var = temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL;
    4006             : 
    4007           0 :   if (var)
    4008             :     {
    4009           0 :       FREE (value_cell (var));
    4010           0 :       var_setvalue (var, savestring (value));
    4011           0 :       INVALIDATE_EXPORTSTR (var);
    4012             :     }
    4013             : 
    4014        6961 :   return (var);
    4015             : }
    4016             : 
    4017             : /* Find a variable in the temporary environment that is named NAME.
    4018             :    Return the SHELL_VAR *, or NULL if not found. */
    4019             : SHELL_VAR *
    4020          70 : find_tempenv_variable (name)
    4021             :      const char *name;
    4022             : {
    4023          70 :   return (temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL);
    4024             : }
    4025             : 
    4026             : char **tempvar_list;
    4027             : int tvlist_ind;
    4028             : 
    4029             : /* Push the variable described by (SHELL_VAR *)DATA down to the next
    4030             :    variable context from the temporary environment. */
    4031             : static void
    4032           0 : push_temp_var (data)
    4033             :      PTR_T data;
    4034             : {
    4035           0 :   SHELL_VAR *var, *v;
    4036           0 :   HASH_TABLE *binding_table;
    4037             : 
    4038           0 :   var = (SHELL_VAR *)data;
    4039             : 
    4040           0 :   binding_table = shell_variables->table;
    4041           0 :   if (binding_table == 0)
    4042             :     {
    4043           0 :       if (shell_variables == global_variables)
    4044             :         /* shouldn't happen */
    4045           0 :         binding_table = shell_variables->table = global_variables->table = hash_create (VARIABLES_HASH_BUCKETS);
    4046             :       else
    4047           0 :         binding_table = shell_variables->table = hash_create (TEMPENV_HASH_BUCKETS);
    4048             :     }
    4049             : 
    4050           0 :   v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, ASS_FORCE);
    4051             : 
    4052             :   /* XXX - should we set the context here?  It shouldn't matter because of how
    4053             :      assign_in_env works, but might want to check. */
    4054           0 :   if (binding_table == global_variables->table)              /* XXX */
    4055           0 :     var->attributes &= ~(att_tempvar|att_propagate);
    4056             :   else
    4057             :     {
    4058           0 :       var->attributes |= att_propagate;
    4059           0 :       if  (binding_table == shell_variables->table)
    4060           0 :         shell_variables->flags |= VC_HASTMPVAR;
    4061             :     }
    4062           0 :   if (v)
    4063           0 :     v->attributes |= var->attributes;
    4064             : 
    4065           0 :   if (find_special_var (var->name) >= 0)
    4066           0 :     tempvar_list[tvlist_ind++] = savestring (var->name);
    4067             : 
    4068           0 :   dispose_variable (var);
    4069           0 : }
    4070             : 
    4071             : static void
    4072        6949 : propagate_temp_var (data)
    4073             :      PTR_T data;
    4074             : {
    4075        6949 :   SHELL_VAR *var;
    4076             : 
    4077        6949 :   var = (SHELL_VAR *)data;
    4078        6949 :   if (tempvar_p (var) && (var->attributes & att_propagate))
    4079           0 :     push_temp_var (data);
    4080             :   else
    4081             :     {
    4082        6949 :       if (find_special_var (var->name) >= 0)
    4083          55 :         tempvar_list[tvlist_ind++] = savestring (var->name);
    4084        6949 :       dispose_variable (var);
    4085             :     }
    4086        6949 : }
    4087             : 
    4088             : /* Free the storage used in the hash table for temporary
    4089             :    environment variables.  PUSHF is a function to be called
    4090             :    to free each hash table entry.  It takes care of pushing variables
    4091             :    to previous scopes if appropriate.  PUSHF stores names of variables
    4092             :    that require special handling (e.g., IFS) on tempvar_list, so this
    4093             :    function can call stupidly_hack_special_variables on all the
    4094             :    variables in the list when the temporary hash table is destroyed. */
    4095             : static void
    4096        6949 : dispose_temporary_env (pushf)
    4097             :      sh_free_func_t *pushf;
    4098             : {
    4099        6949 :   int i;
    4100             : 
    4101        6949 :   tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1);
    4102        6949 :   tempvar_list[tvlist_ind = 0] = 0;
    4103             :     
    4104        6949 :   hash_flush (temporary_env, pushf);
    4105        6949 :   hash_dispose (temporary_env);
    4106        6949 :   temporary_env = (HASH_TABLE *)NULL;
    4107             : 
    4108        6949 :   tempvar_list[tvlist_ind] = 0;
    4109             : 
    4110        6949 :   array_needs_making = 1;
    4111             : 
    4112             : #if 0
    4113             :   sv_ifs ("IFS");             /* XXX here for now -- check setifs in assign_in_env */  
    4114             : #endif
    4115        7004 :   for (i = 0; i < tvlist_ind; i++)
    4116          55 :     stupidly_hack_special_variables (tempvar_list[i]);
    4117             : 
    4118        6949 :   strvec_dispose (tempvar_list);
    4119        6949 :   tempvar_list = 0;
    4120        6949 :   tvlist_ind = 0;
    4121        6949 : }
    4122             : 
    4123             : void
    4124    78954858 : dispose_used_env_vars ()
    4125             : {
    4126    78954858 :   if (temporary_env)
    4127             :     {
    4128        6949 :       dispose_temporary_env (propagate_temp_var);
    4129        6949 :       maybe_make_export_env ();
    4130             :     }
    4131    78954858 : }
    4132             : 
    4133             : /* Take all of the shell variables in the temporary environment HASH_TABLE
    4134             :    and make shell variables from them at the current variable context. */
    4135             : void
    4136           0 : merge_temporary_env ()
    4137             : {
    4138           0 :   if (temporary_env)
    4139           0 :     dispose_temporary_env (push_temp_var);
    4140           0 : }
    4141             : 
    4142             : void
    4143        1489 : flush_temporary_env ()
    4144             : {
    4145        1489 :   if (temporary_env)
    4146             :     {
    4147           0 :       hash_flush (temporary_env, free_variable_hash_data);
    4148           0 :       hash_dispose (temporary_env);
    4149           0 :       temporary_env = (HASH_TABLE *)NULL;
    4150             :     }
    4151        1489 : }
    4152             : 
    4153             : /* **************************************************************** */
    4154             : /*                                                                  */
    4155             : /*           Creating and manipulating the environment              */
    4156             : /*                                                                  */
    4157             : /* **************************************************************** */
    4158             : 
    4159             : static inline char *
    4160     9550082 : mk_env_string (name, value, isfunc)
    4161             :      const char *name, *value;
    4162             :      int isfunc;
    4163             : {
    4164     9550082 :   size_t name_len, value_len;
    4165     9550082 :   char  *p, *q;
    4166             : 
    4167     9550082 :   name_len = strlen (name);
    4168     9550082 :   value_len = STRLEN (value);
    4169             : 
    4170             :   /* If we are exporting a shell function, construct the encoded function
    4171             :      name. */
    4172     9550082 :   if (isfunc && value)
    4173             :     {
    4174           0 :       p = (char *)xmalloc (BASHFUNC_PREFLEN + name_len + BASHFUNC_SUFFLEN + value_len + 2);
    4175           0 :       q = p;
    4176           0 :       memcpy (q, BASHFUNC_PREFIX, BASHFUNC_PREFLEN);
    4177           0 :       q += BASHFUNC_PREFLEN;
    4178           0 :       memcpy (q, name, name_len);
    4179           0 :       q += name_len;
    4180           0 :       memcpy (q, BASHFUNC_SUFFIX, BASHFUNC_SUFFLEN);
    4181           0 :       q += BASHFUNC_SUFFLEN;
    4182             :     }
    4183             :   else
    4184             :     {
    4185     9550082 :       p = (char *)xmalloc (2 + name_len + value_len);
    4186     9550082 :       memcpy (p, name, name_len);
    4187     9550082 :       q = p + name_len;
    4188             :     }
    4189             : 
    4190     9550082 :   q[0] = '=';
    4191     9550082 :   if (value && *value)
    4192     9549757 :     memcpy (q + 1, value, value_len + 1);
    4193             :   else
    4194         325 :     q[1] = '\0';
    4195             : 
    4196     9550082 :   return (p);
    4197             : }
    4198             : 
    4199             : #ifdef DEBUG
    4200             : /* Debugging */
    4201             : static int
    4202             : valid_exportstr (v)
    4203             :      SHELL_VAR *v;
    4204             : {
    4205             :   char *s;
    4206             : 
    4207             :   s = v->exportstr;
    4208             :   if (s == 0)
    4209             :     {
    4210             :       internal_error (_("%s has null exportstr"), v->name);
    4211             :       return (0);
    4212             :     }
    4213             :   if (legal_variable_starter ((unsigned char)*s) == 0)
    4214             :     {
    4215             :       internal_error (_("invalid character %d in exportstr for %s"), *s, v->name);
    4216             :       return (0);
    4217             :     }
    4218             :   for (s = v->exportstr + 1; s && *s; s++)
    4219             :     {
    4220             :       if (*s == '=')
    4221             :         break;
    4222             :       if (legal_variable_char ((unsigned char)*s) == 0)
    4223             :         {
    4224             :           internal_error (_("invalid character %d in exportstr for %s"), *s, v->name);
    4225             :           return (0);
    4226             :         }
    4227             :     }
    4228             :   if (*s != '=')
    4229             :     {
    4230             :       internal_error (_("no `=' in exportstr for %s"), v->name);
    4231             :       return (0);
    4232             :     }
    4233             :   return (1);
    4234             : }
    4235             : #endif
    4236             : 
    4237             : static char **
    4238    11230348 : make_env_array_from_var_list (vars)
    4239             :      SHELL_VAR **vars;
    4240             : {
    4241    11230348 :   register int i, list_index;
    4242    11230348 :   register SHELL_VAR *var;
    4243    11230348 :   char **list, *value;
    4244             : 
    4245    11230348 :   list = strvec_create ((1 + strvec_len ((char **)vars)));
    4246             : 
    4247             : #define USE_EXPORTSTR (value == var->exportstr)
    4248             : 
    4249   424879815 :   for (i = 0, list_index = 0; var = vars[i]; i++)
    4250             :     {
    4251             : #if defined (__CYGWIN__)
    4252             :       /* We don't use the exportstr stuff on Cygwin at all. */
    4253             :       INVALIDATE_EXPORTSTR (var);
    4254             : #endif
    4255   413649467 :       if (var->exportstr)
    4256             :         value = var->exportstr;
    4257     9542884 :       else if (function_p (var))
    4258           0 :         value = named_function_string ((char *)NULL, function_cell (var), 0);
    4259             : #if defined (ARRAY_VARS)
    4260     9542884 :       else if (array_p (var))
    4261             : #  if ARRAY_EXPORT
    4262             :         value = array_to_assign (array_cell (var), 0);
    4263             : #  else
    4264             :         continue;       /* XXX array vars cannot yet be exported */
    4265             : #  endif /* ARRAY_EXPORT */
    4266     9542884 :       else if (assoc_p (var))
    4267             : #  if 0
    4268             :         value = assoc_to_assign (assoc_cell (var), 0);
    4269             : #  else
    4270             :         continue;       /* XXX associative array vars cannot yet be exported */
    4271             : #  endif
    4272             : #endif
    4273             :       else
    4274     9542884 :         value = value_cell (var);
    4275             : 
    4276   413649467 :       if (value)
    4277             :         {
    4278             :           /* Gee, I'd like to get away with not using savestring() if we're
    4279             :              using the cached exportstr... */
    4280   404106583 :           list[list_index] = USE_EXPORTSTR ? savestring (value)
    4281   413649467 :                                            : mk_env_string (var->name, value, function_p (var));
    4282             : 
    4283   413649467 :           if (USE_EXPORTSTR == 0)
    4284     9542884 :             SAVE_EXPORTSTR (var, list[list_index]);
    4285             : 
    4286   413649467 :           list_index++;
    4287             : #undef USE_EXPORTSTR
    4288             : 
    4289             : #if 0   /* not yet */
    4290             : #if defined (ARRAY_VARS)
    4291             :           if (array_p (var) || assoc_p (var))
    4292             :             free (value);
    4293             : #endif
    4294             : #endif
    4295             :         }
    4296             :     }
    4297             : 
    4298    11230348 :   list[list_index] = (char *)NULL;
    4299    11230348 :   return (list);
    4300             : }
    4301             : 
    4302             : /* Make an array of assignment statements from the hash table
    4303             :    HASHED_VARS which contains SHELL_VARs.  Only visible, exported
    4304             :    variables are eligible. */
    4305             : static char **
    4306    11225147 : make_var_export_array (vcxt)
    4307             :      VAR_CONTEXT *vcxt;
    4308             : {
    4309    11225147 :   char **list;
    4310    11225147 :   SHELL_VAR **vars;
    4311             : 
    4312             : #if 0
    4313             :   vars = map_over (visible_and_exported, vcxt);
    4314             : #else
    4315    11225147 :   vars = map_over (export_environment_candidate, vcxt);
    4316             : #endif
    4317             : 
    4318    11225147 :   if (vars == 0)
    4319             :     return (char **)NULL;
    4320             : 
    4321    11225147 :   list = make_env_array_from_var_list (vars);
    4322             : 
    4323    11225147 :   free (vars);
    4324    11225147 :   return (list);
    4325             : }
    4326             : 
    4327             : static char **
    4328    11225147 : make_func_export_array ()
    4329             : {
    4330    11225147 :   char **list;
    4331    11225147 :   SHELL_VAR **vars;
    4332             : 
    4333    11225147 :   vars = map_over_funcs (visible_and_exported);
    4334    11225147 :   if (vars == 0)
    4335             :     return (char **)NULL;
    4336             : 
    4337        5201 :   list = make_env_array_from_var_list (vars);
    4338             : 
    4339        5201 :   free (vars);
    4340        5201 :   return (list);
    4341             : }
    4342             : 
    4343             : /* Add ENVSTR to the end of the exported environment, EXPORT_ENV. */
    4344             : #define add_to_export_env(envstr,do_alloc) \
    4345             : do \
    4346             :   { \
    4347             :     if (export_env_index >= (export_env_size - 1)) \
    4348             :       { \
    4349             :         export_env_size += 16; \
    4350             :         export_env = strvec_resize (export_env, export_env_size); \
    4351             :         environ = export_env; \
    4352             :       } \
    4353             :     export_env[export_env_index++] = (do_alloc) ? savestring (envstr) : envstr; \
    4354             :     export_env[export_env_index] = (char *)NULL; \
    4355             :   } while (0)
    4356             : 
    4357             : /* Add ASSIGN to EXPORT_ENV, or supercede a previous assignment in the
    4358             :    array with the same left-hand side.  Return the new EXPORT_ENV. */
    4359             : char **
    4360     1716333 : add_or_supercede_exported_var (assign, do_alloc)
    4361             :      char *assign;
    4362             :      int do_alloc;
    4363             : {
    4364     1716333 :   register int i;
    4365     1716333 :   int equal_offset;
    4366             : 
    4367     1716333 :   equal_offset = assignment (assign, 0);
    4368     1716333 :   if (equal_offset == 0)
    4369           0 :     return (export_env);
    4370             : 
    4371             :   /* If this is a function, then only supersede the function definition.
    4372             :      We do this by including the `=() {' in the comparison, like
    4373             :      initialize_shell_variables does. */
    4374     1716333 :   if (assign[equal_offset + 1] == '(' &&
    4375           9 :      strncmp (assign + equal_offset + 2, ") {", 3) == 0)              /* } */
    4376           0 :     equal_offset += 4;
    4377             : 
    4378    63505106 :   for (i = 0; i < export_env_index; i++)
    4379             :     {
    4380    61847687 :       if (STREQN (assign, export_env[i], equal_offset + 1))
    4381             :         {
    4382       58914 :           free (export_env[i]);
    4383       58914 :           export_env[i] = do_alloc ? savestring (assign) : assign;
    4384       58914 :           return (export_env);
    4385             :         }
    4386             :     }
    4387     1657419 :   add_to_export_env (assign, do_alloc);
    4388     1657419 :   return (export_env);
    4389             : }
    4390             : 
    4391             : static void
    4392    11230348 : add_temp_array_to_env (temp_array, do_alloc, do_supercede)
    4393             :      char **temp_array;
    4394             :      int do_alloc, do_supercede;
    4395             : {
    4396    11230348 :   register int i;
    4397             : 
    4398    11230348 :   if (temp_array == 0)
    4399             :     return;
    4400             : 
    4401   424879815 :   for (i = 0; temp_array[i]; i++)
    4402             :     {
    4403   413649467 :       if (do_supercede)
    4404           0 :         export_env = add_or_supercede_exported_var (temp_array[i], do_alloc);
    4405             :       else
    4406   413649467 :         add_to_export_env (temp_array[i], do_alloc);
    4407             :     }
    4408             : 
    4409    11230348 :   free (temp_array);
    4410             : }
    4411             : 
    4412             : /* Make the environment array for the command about to be executed, if the
    4413             :    array needs making.  Otherwise, do nothing.  If a shell action could
    4414             :    change the array that commands receive for their environment, then the
    4415             :    code should `array_needs_making++'.
    4416             : 
    4417             :    The order to add to the array is:
    4418             :         temporary_env
    4419             :         list of var contexts whose head is shell_variables
    4420             :         shell_functions
    4421             : 
    4422             :   This is the shell variable lookup order.  We add only new variable
    4423             :   names at each step, which allows local variables and variables in
    4424             :   the temporary environments to shadow variables in the global (or
    4425             :   any previous) scope.
    4426             : */
    4427             : 
    4428             : static int
    4429             : n_shell_variables ()
    4430             : {
    4431    11225147 :   VAR_CONTEXT *vc;
    4432    11225147 :   int n;
    4433             : 
    4434    22451737 :   for (n = 0, vc = shell_variables; vc; vc = vc->down)
    4435    11226590 :     n += HASH_ENTRIES (vc->table);
    4436    11225147 :   return n;
    4437             : }
    4438             : 
    4439             : int
    4440           0 : chkexport (name)
    4441             :      char *name;
    4442             : {
    4443           0 :   SHELL_VAR *v;
    4444             : 
    4445           0 :   v = find_variable (name);
    4446           0 :   if (v && exported_p (v))
    4447             :     {
    4448           0 :       array_needs_making = 1;
    4449           0 :       maybe_make_export_env ();
    4450           0 :       return 1;
    4451             :     }
    4452             :   return 0;
    4453             : }
    4454             : 
    4455             : void
    4456    11348109 : maybe_make_export_env ()
    4457             : {
    4458    11348109 :   register char **temp_array;
    4459    11348109 :   int new_size;
    4460    11348109 :   VAR_CONTEXT *tcxt;
    4461             : 
    4462    11348109 :   if (array_needs_making)
    4463             :     {
    4464    11225147 :       if (export_env)
    4465     1682263 :         strvec_flush (export_env);
    4466             : 
    4467             :       /* Make a guess based on how many shell variables and functions we
    4468             :          have.  Since there will always be array variables, and array
    4469             :          variables are not (yet) exported, this will always be big enough
    4470             :          for the exported variables and functions. */
    4471    22450294 :       new_size = n_shell_variables () + HASH_ENTRIES (shell_functions) + 1 +
    4472    11225147 :                  HASH_ENTRIES (temporary_env);
    4473    11225147 :       if (new_size > export_env_size)
    4474             :         {
    4475    11223138 :           export_env_size = new_size;
    4476    11223138 :           export_env = strvec_resize (export_env, export_env_size);
    4477    11223138 :           environ = export_env;
    4478             :         }
    4479    11225147 :       export_env[export_env_index = 0] = (char *)NULL;
    4480             : 
    4481             :       /* Make a dummy variable context from the temporary_env, stick it on
    4482             :          the front of shell_variables, call make_var_export_array on the
    4483             :          whole thing to flatten it, and convert the list of SHELL_VAR *s
    4484             :          to the form needed by the environment. */
    4485    11225147 :       if (temporary_env)
    4486             :         {
    4487        1289 :           tcxt = new_var_context ((char *)NULL, 0);
    4488        1289 :           tcxt->table = temporary_env;
    4489        1289 :           tcxt->down = shell_variables;
    4490             :         }
    4491             :       else
    4492    11223858 :         tcxt = shell_variables;
    4493             :       
    4494    11225147 :       temp_array = make_var_export_array (tcxt);
    4495    11225147 :       if (temp_array)
    4496    11225147 :         add_temp_array_to_env (temp_array, 0, 0);
    4497             : 
    4498    11225147 :       if (tcxt != shell_variables)
    4499        1289 :         free (tcxt);
    4500             : 
    4501             : #if defined (RESTRICTED_SHELL)
    4502             :       /* Restricted shells may not export shell functions. */
    4503             :       temp_array = restricted ? (char **)0 : make_func_export_array ();
    4504             : #else
    4505    11225147 :       temp_array = make_func_export_array ();
    4506             : #endif
    4507    11225147 :       if (temp_array)
    4508        5201 :         add_temp_array_to_env (temp_array, 0, 0);
    4509             : 
    4510    11225147 :       array_needs_making = 0;
    4511             :     }
    4512    11348109 : }
    4513             : 
    4514             : /* This is an efficiency hack.  PWD and OLDPWD are auto-exported, so
    4515             :    we will need to remake the exported environment every time we
    4516             :    change directories.  `_' is always put into the environment for
    4517             :    every external command, so without special treatment it will always
    4518             :    cause the environment to be remade.
    4519             : 
    4520             :    If there is no other reason to make the exported environment, we can
    4521             :    just update the variables in place and mark the exported environment
    4522             :    as no longer needing a remake. */
    4523             : void
    4524     1716333 : update_export_env_inplace (env_prefix, preflen, value)
    4525             :      char *env_prefix;
    4526             :      int preflen;
    4527             :      char *value;
    4528             : {
    4529     1716333 :   char *evar;
    4530             : 
    4531     1716333 :   evar = (char *)xmalloc (STRLEN (value) + preflen + 1);
    4532     1716333 :   strcpy (evar, env_prefix);
    4533     1716333 :   if (value)
    4534     1716333 :     strcpy (evar + preflen, value);
    4535     1716333 :   export_env = add_or_supercede_exported_var (evar, 0);
    4536     1716333 : }
    4537             : 
    4538             : /* We always put _ in the environment as the name of this command. */
    4539             : void
    4540     1716315 : put_command_name_into_env (command_name)
    4541             :      char *command_name;
    4542             : {
    4543     1716315 :   update_export_env_inplace ("_=", 2, command_name);
    4544     1716315 : }
    4545             : 
    4546             : /* **************************************************************** */
    4547             : /*                                                                  */
    4548             : /*                    Managing variable contexts                    */
    4549             : /*                                                                  */
    4550             : /* **************************************************************** */
    4551             : 
    4552             : /* Allocate and return a new variable context with NAME and FLAGS.
    4553             :    NAME can be NULL. */
    4554             : 
    4555             : VAR_CONTEXT *
    4556     9554259 : new_var_context (name, flags)
    4557             :      char *name;
    4558             :      int flags;
    4559             : {
    4560     9554259 :   VAR_CONTEXT *vc;
    4561             : 
    4562     9554259 :   vc = (VAR_CONTEXT *)xmalloc (sizeof (VAR_CONTEXT));
    4563     9554259 :   vc->name = name ? savestring (name) : (char *)NULL;
    4564     9554259 :   vc->scope = variable_context;
    4565     9554259 :   vc->flags = flags;
    4566             : 
    4567     9554259 :   vc->up = vc->down = (VAR_CONTEXT *)NULL;
    4568     9554259 :   vc->table = (HASH_TABLE *)NULL;
    4569             : 
    4570     9554259 :   return vc;
    4571             : }
    4572             : 
    4573             : /* Free a variable context and its data, including the hash table.  Dispose
    4574             :    all of the variables. */
    4575             : void
    4576        8814 : dispose_var_context (vc)
    4577             :      VAR_CONTEXT *vc;
    4578             : {
    4579        8814 :   FREE (vc->name);
    4580             : 
    4581        8814 :   if (vc->table)
    4582             :     {
    4583           9 :       delete_all_variables (vc->table);
    4584           9 :       hash_dispose (vc->table);
    4585             :     }
    4586             : 
    4587        8814 :   free (vc);
    4588        8814 : }
    4589             : 
    4590             : /* Set VAR's scope level to the current variable context. */
    4591             : static int
    4592          18 : set_context (var)
    4593             :      SHELL_VAR *var;
    4594             : {
    4595          18 :   return (var->context = variable_context);
    4596             : }
    4597             : 
    4598             : /* Make a new variable context with NAME and FLAGS and a HASH_TABLE of
    4599             :    temporary variables, and push it onto shell_variables.  This is
    4600             :    for shell functions. */
    4601             : VAR_CONTEXT *
    4602       10086 : push_var_context (name, flags, tempvars)
    4603             :      char *name;
    4604             :      int flags;
    4605             :      HASH_TABLE *tempvars;
    4606             : {
    4607       10086 :   VAR_CONTEXT *vc;
    4608             : 
    4609       10086 :   vc = new_var_context (name, flags);
    4610       10086 :   vc->table = tempvars;
    4611       10086 :   if (tempvars)
    4612             :     {
    4613             :       /* Have to do this because the temp environment was created before
    4614             :          variable_context was incremented. */
    4615          18 :       flatten (tempvars, set_context, (VARLIST *)NULL, 0);
    4616          18 :       vc->flags |= VC_HASTMPVAR;
    4617             :     }
    4618       10086 :   vc->down = shell_variables;
    4619       10086 :   shell_variables->up = vc;
    4620             : 
    4621       10086 :   return (shell_variables = vc);
    4622             : }
    4623             : 
    4624             : static void
    4625          18 : push_func_var (data)
    4626             :      PTR_T data;
    4627             : {
    4628          18 :   SHELL_VAR *var, *v;
    4629             : 
    4630          18 :   var = (SHELL_VAR *)data;
    4631             : 
    4632          18 :   if (local_p (var) && STREQ (var->name, "-"))
    4633           0 :     set_current_options (value_cell (var));
    4634          18 :   else if (tempvar_p (var) && (posixly_correct || (var->attributes & att_propagate)))
    4635             :     {
    4636             :       /* Make sure we have a hash table to store the variable in while it is
    4637             :          being propagated down to the global variables table.  Create one if
    4638             :          we have to */
    4639           0 :       if ((vc_isfuncenv (shell_variables) || vc_istempenv (shell_variables)) && shell_variables->table == 0)
    4640           0 :         shell_variables->table = hash_create (VARIABLES_HASH_BUCKETS);
    4641             :       /* XXX - should we set v->context here? */
    4642           0 :       v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);
    4643             : #if defined (ARRAY_VARS)
    4644           0 :       if (array_p (var) || assoc_p (var))
    4645             :         {
    4646           0 :           FREE (value_cell (v));
    4647           0 :           if (array_p (var))
    4648           0 :             var_setarray (v, array_copy (array_cell (var)));
    4649             :           else
    4650           0 :             var_setassoc (v, assoc_copy (assoc_cell (var)));
    4651             :         }
    4652             : #endif    
    4653           0 :       if (shell_variables == global_variables)
    4654           0 :         var->attributes &= ~(att_tempvar|att_propagate);
    4655             :       else
    4656           0 :         shell_variables->flags |= VC_HASTMPVAR;
    4657           0 :       if (v)
    4658           0 :         v->attributes |= var->attributes;
    4659             :     }
    4660             :   else
    4661          18 :     stupidly_hack_special_variables (var->name);     /* XXX */
    4662             : 
    4663          18 :   dispose_variable (var);
    4664          18 : }
    4665             : 
    4666             : /* Pop the top context off of VCXT and dispose of it, returning the rest of
    4667             :    the stack. */
    4668             : void
    4669        8814 : pop_var_context ()
    4670             : {
    4671        8814 :   VAR_CONTEXT *ret, *vcxt;
    4672             : 
    4673        8814 :   vcxt = shell_variables;
    4674        8814 :   if (vc_isfuncenv (vcxt) == 0)
    4675             :     {
    4676           0 :       internal_error (_("pop_var_context: head of shell_variables not a function context"));
    4677           0 :       return;
    4678             :     }
    4679             : 
    4680        8814 :   if (ret = vcxt->down)
    4681             :     {
    4682        8814 :       ret->up = (VAR_CONTEXT *)NULL;
    4683        8814 :       shell_variables = ret;
    4684        8814 :       if (vcxt->table)
    4685           9 :         hash_flush (vcxt->table, push_func_var);
    4686        8814 :       dispose_var_context (vcxt);
    4687             :     }
    4688             :   else
    4689           0 :     internal_error (_("pop_var_context: no global_variables context"));
    4690             : }
    4691             : 
    4692             : /* Delete the HASH_TABLEs for all variable contexts beginning at VCXT, and
    4693             :    all of the VAR_CONTEXTs except GLOBAL_VARIABLES. */
    4694             : void
    4695           0 : delete_all_contexts (vcxt)
    4696             :      VAR_CONTEXT *vcxt;
    4697             : {
    4698           0 :   VAR_CONTEXT *v, *t;
    4699             : 
    4700           0 :   for (v = vcxt; v != global_variables; v = t)
    4701             :     {
    4702           0 :       t = v->down;
    4703           0 :       dispose_var_context (v);
    4704             :     }    
    4705             : 
    4706           0 :   delete_all_variables (global_variables->table);
    4707           0 :   shell_variables = global_variables;
    4708           0 : }
    4709             : 
    4710             : /* **************************************************************** */
    4711             : /*                                                                  */
    4712             : /*         Pushing and Popping temporary variable scopes            */
    4713             : /*                                                                  */
    4714             : /* **************************************************************** */
    4715             : 
    4716             : VAR_CONTEXT *
    4717           9 : push_scope (flags, tmpvars)
    4718             :      int flags;
    4719             :      HASH_TABLE *tmpvars;
    4720             : {
    4721           9 :   return (push_var_context ((char *)NULL, flags, tmpvars));
    4722             : }
    4723             : 
    4724             : static void
    4725           0 : push_exported_var (data)
    4726             :      PTR_T data;
    4727             : {
    4728           0 :   SHELL_VAR *var, *v;
    4729             : 
    4730           0 :   var = (SHELL_VAR *)data;
    4731             : 
    4732             :   /* If a temp var had its export attribute set, or it's marked to be
    4733             :      propagated, bind it in the previous scope before disposing it. */
    4734             :   /* XXX - This isn't exactly right, because all tempenv variables have the
    4735             :     export attribute set. */
    4736             : #if 0
    4737             :   if (exported_p (var) || (var->attributes & att_propagate))
    4738             : #else
    4739           0 :   if (tempvar_p (var) && exported_p (var) && (var->attributes & att_propagate))
    4740             : #endif
    4741             :     {
    4742           0 :       var->attributes &= ~att_tempvar;           /* XXX */
    4743           0 :       v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);
    4744           0 :       if (shell_variables == global_variables)
    4745           0 :         var->attributes &= ~att_propagate;
    4746           0 :       if (v)
    4747           0 :         v->attributes |= var->attributes;
    4748             :     }
    4749             :   else
    4750           0 :     stupidly_hack_special_variables (var->name);     /* XXX */
    4751             : 
    4752           0 :   dispose_variable (var);
    4753           0 : }
    4754             : 
    4755             : void
    4756           9 : pop_scope (is_special)
    4757             :      int is_special;
    4758             : {
    4759           9 :   VAR_CONTEXT *vcxt, *ret;
    4760             : 
    4761           9 :   vcxt = shell_variables;
    4762           9 :   if (vc_istempscope (vcxt) == 0)
    4763             :     {
    4764           0 :       internal_error (_("pop_scope: head of shell_variables not a temporary environment scope"));
    4765           0 :       return;
    4766             :     }
    4767             : 
    4768           9 :   ret = vcxt->down;
    4769           9 :   if (ret)
    4770           9 :     ret->up = (VAR_CONTEXT *)NULL;
    4771             : 
    4772           9 :   shell_variables = ret;
    4773             : 
    4774             :   /* Now we can take care of merging variables in VCXT into set of scopes
    4775             :      whose head is RET (shell_variables). */
    4776           9 :   FREE (vcxt->name);
    4777           9 :   if (vcxt->table)
    4778             :     {
    4779           9 :       if (is_special)
    4780           9 :         hash_flush (vcxt->table, push_func_var);
    4781             :       else
    4782           0 :         hash_flush (vcxt->table, push_exported_var);
    4783           9 :       hash_dispose (vcxt->table);
    4784             :     }
    4785           9 :   free (vcxt);
    4786             : 
    4787           9 :   sv_ifs ("IFS");     /* XXX here for now */
    4788             : }
    4789             : 
    4790             : /* **************************************************************** */
    4791             : /*                                                                  */
    4792             : /*               Pushing and Popping function contexts              */
    4793             : /*                                                                  */
    4794             : /* **************************************************************** */
    4795             : 
    4796             : static WORD_LIST **dollar_arg_stack = (WORD_LIST **)NULL;
    4797             : static int dollar_arg_stack_slots;
    4798             : static int dollar_arg_stack_index;
    4799             : 
    4800             : /* XXX - should always be followed by remember_args () */
    4801             : void
    4802       10077 : push_context (name, is_subshell, tempvars)
    4803             :      char *name;        /* function name */
    4804             :      int is_subshell;
    4805             :      HASH_TABLE *tempvars;
    4806             : {
    4807       10077 :   if (is_subshell == 0)
    4808        9870 :     push_dollar_vars ();
    4809       10077 :   variable_context++;
    4810       10077 :   push_var_context (name, VC_FUNCENV, tempvars);
    4811       10077 : }
    4812             : 
    4813             : /* Only called when subshell == 0, so we don't need to check, and can
    4814             :    unconditionally pop the dollar vars off the stack. */
    4815             : void
    4816        8814 : pop_context ()
    4817             : {
    4818        8814 :   pop_dollar_vars ();
    4819        8814 :   variable_context--;
    4820        8814 :   pop_var_context ();
    4821             : 
    4822       17628 :   sv_ifs ("IFS");             /* XXX here for now */
    4823        8814 : }
    4824             : 
    4825             : /* Save the existing positional parameters on a stack. */
    4826             : void
    4827       16962 : push_dollar_vars ()
    4828             : {
    4829       16962 :   if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots)
    4830             :     {
    4831       12154 :       dollar_arg_stack = (WORD_LIST **)
    4832       12154 :         xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10)
    4833             :                   * sizeof (WORD_LIST *));
    4834             :     }
    4835       16962 :   dollar_arg_stack[dollar_arg_stack_index++] = list_rest_of_args ();
    4836       16962 :   dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
    4837       16962 : }
    4838             : 
    4839             : /* Restore the positional parameters from our stack. */
    4840             : void
    4841       15888 : pop_dollar_vars ()
    4842             : {
    4843       15888 :   if (!dollar_arg_stack || dollar_arg_stack_index == 0)
    4844             :     return;
    4845             : 
    4846       15888 :   remember_args (dollar_arg_stack[--dollar_arg_stack_index], 1);
    4847       15888 :   dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
    4848       15888 :   dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
    4849       15888 :   set_dollar_vars_unchanged ();
    4850             : }
    4851             : 
    4852             : void
    4853           0 : dispose_saved_dollar_vars ()
    4854             : {
    4855           0 :   if (!dollar_arg_stack || dollar_arg_stack_index == 0)
    4856             :     return;
    4857             : 
    4858           0 :   dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
    4859           0 :   dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
    4860             : }
    4861             : 
    4862             : /* Manipulate the special BASH_ARGV and BASH_ARGC variables. */
    4863             : 
    4864             : void
    4865           0 : push_args (list)
    4866             :      WORD_LIST *list;
    4867             : {
    4868             : #if defined (ARRAY_VARS) && defined (DEBUGGER)
    4869           0 :   SHELL_VAR *bash_argv_v, *bash_argc_v;
    4870           0 :   ARRAY *bash_argv_a, *bash_argc_a;
    4871           0 :   WORD_LIST *l;
    4872           0 :   arrayind_t i;
    4873           0 :   char *t;
    4874             : 
    4875           0 :   GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
    4876           0 :   GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
    4877             : 
    4878           0 :   for (l = list, i = 0; l; l = l->next, i++)
    4879           0 :     array_push (bash_argv_a, l->word->word);
    4880             : 
    4881           0 :   t = itos (i);
    4882           0 :   array_push (bash_argc_a, t);
    4883           0 :   free (t);
    4884             : #endif /* ARRAY_VARS && DEBUGGER */
    4885           0 : }
    4886             : 
    4887             : /* Remove arguments from BASH_ARGV array.  Pop top element off BASH_ARGC
    4888             :    array and use that value as the count of elements to remove from
    4889             :    BASH_ARGV. */
    4890             : void
    4891     9542884 : pop_args ()
    4892             : {
    4893             : #if defined (ARRAY_VARS) && defined (DEBUGGER)
    4894     9542884 :   SHELL_VAR *bash_argv_v, *bash_argc_v;
    4895     9542884 :   ARRAY *bash_argv_a, *bash_argc_a;
    4896     9542884 :   ARRAY_ELEMENT *ce;
    4897     9542884 :   intmax_t i;
    4898             : 
    4899     9542884 :   GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
    4900     9542884 :   GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
    4901             : 
    4902     9542884 :   ce = array_shift (bash_argc_a, 1, 0);
    4903     9542884 :   if (ce == 0 || legal_number (element_value (ce), &i) == 0)
    4904           0 :     i = 0;
    4905             : 
    4906    19085768 :   for ( ; i > 0; i--)
    4907     9542884 :     array_pop (bash_argv_a);
    4908     9542884 :   array_dispose_element (ce);
    4909             : #endif /* ARRAY_VARS && DEBUGGER */
    4910     9542884 : }
    4911             : 
    4912             : /*************************************************
    4913             :  *                                               *
    4914             :  *      Functions to manage special variables    *
    4915             :  *                                               *
    4916             :  *************************************************/
    4917             : 
    4918             : /* Extern declarations for variables this code has to manage. */
    4919             : extern int eof_encountered, eof_encountered_limit, ignoreeof;
    4920             : 
    4921             : #if defined (READLINE)
    4922             : extern int hostname_list_initialized;
    4923             : #endif
    4924             : 
    4925             : /* An alist of name.function for each special variable.  Most of the
    4926             :    functions don't do much, and in fact, this would be faster with a
    4927             :    switch statement, but by the end of this file, I am sick of switch
    4928             :    statements. */
    4929             : 
    4930             : #define SET_INT_VAR(name, intvar)  intvar = find_variable (name) != 0
    4931             : 
    4932             : /* This table will be sorted with qsort() the first time it's accessed. */
    4933             : struct name_and_function {
    4934             :   char *name;
    4935             :   sh_sv_func_t *function;
    4936             : };
    4937             : 
    4938             : static struct name_and_function special_vars[] = {
    4939             :   { "BASH_COMPAT", sv_shcompat },
    4940             :   { "BASH_XTRACEFD", sv_xtracefd },
    4941             : 
    4942             : #if defined (JOB_CONTROL)
    4943             :   { "CHILD_MAX", sv_childmax },
    4944             : #endif
    4945             : 
    4946             : #if defined (READLINE)
    4947             : #  if defined (STRICT_POSIX)
    4948             :   { "COLUMNS", sv_winsize },
    4949             : #  endif
    4950             :   { "COMP_WORDBREAKS", sv_comp_wordbreaks },
    4951             : #endif
    4952             : 
    4953             :   { "EXECIGNORE", sv_execignore },
    4954             : 
    4955             :   { "FUNCNEST", sv_funcnest },
    4956             : 
    4957             :   { "GLOBIGNORE", sv_globignore },
    4958             : 
    4959             : #if defined (HISTORY)
    4960             :   { "HISTCONTROL", sv_history_control },
    4961             :   { "HISTFILESIZE", sv_histsize },
    4962             :   { "HISTIGNORE", sv_histignore },
    4963             :   { "HISTSIZE", sv_histsize },
    4964             :   { "HISTTIMEFORMAT", sv_histtimefmt },
    4965             : #endif
    4966             : 
    4967             : #if defined (__CYGWIN__)
    4968             :   { "HOME", sv_home },
    4969             : #endif
    4970             : 
    4971             : #if defined (READLINE)
    4972             :   { "HOSTFILE", sv_hostfile },
    4973             : #endif
    4974             : 
    4975             :   { "IFS", sv_ifs },
    4976             :   { "IGNOREEOF", sv_ignoreeof },
    4977             : 
    4978             :   { "LANG", sv_locale },
    4979             :   { "LC_ALL", sv_locale },
    4980             :   { "LC_COLLATE", sv_locale },
    4981             :   { "LC_CTYPE", sv_locale },
    4982             :   { "LC_MESSAGES", sv_locale },
    4983             :   { "LC_NUMERIC", sv_locale },
    4984             :   { "LC_TIME", sv_locale },
    4985             : 
    4986             : #if defined (READLINE) && defined (STRICT_POSIX)
    4987             :   { "LINES", sv_winsize },
    4988             : #endif
    4989             : 
    4990             :   { "MAIL", sv_mail },
    4991             :   { "MAILCHECK", sv_mail },
    4992             :   { "MAILPATH", sv_mail },
    4993             : 
    4994             :   { "OPTERR", sv_opterr },
    4995             :   { "OPTIND", sv_optind },
    4996             : 
    4997             :   { "PATH", sv_path },
    4998             :   { "POSIXLY_CORRECT", sv_strict_posix },
    4999             : 
    5000             : #if defined (READLINE)
    5001             :   { "TERM", sv_terminal },
    5002             :   { "TERMCAP", sv_terminal },
    5003             :   { "TERMINFO", sv_terminal },
    5004             : #endif /* READLINE */
    5005             : 
    5006             :   { "TEXTDOMAIN", sv_locale },
    5007             :   { "TEXTDOMAINDIR", sv_locale },
    5008             : 
    5009             : #if defined (HAVE_TZSET)
    5010             :   { "TZ", sv_tz },
    5011             : #endif
    5012             : 
    5013             : #if defined (HISTORY) && defined (BANG_HISTORY)
    5014             :   { "histchars", sv_histchars },
    5015             : #endif /* HISTORY && BANG_HISTORY */
    5016             : 
    5017             :   { "ignoreeof", sv_ignoreeof },
    5018             : 
    5019             :   { (char *)0, (sh_sv_func_t *)0 }
    5020             : };
    5021             : 
    5022             : #define N_SPECIAL_VARS  (sizeof (special_vars) / sizeof (special_vars[0]) - 1)
    5023             : 
    5024             : static int
    5025   471883221 : sv_compare (sv1, sv2)
    5026             :      struct name_and_function *sv1, *sv2;
    5027             : {
    5028   471883221 :   int r;
    5029             : 
    5030   471883221 :   if ((r = sv1->name[0] - sv2->name[0]) == 0)
    5031   165573060 :     r = strcmp (sv1->name, sv2->name);
    5032   471883221 :   return r;
    5033             : }
    5034             : 
    5035             : static inline int
    5036    24899817 : find_special_var (name)
    5037             :      const char *name;
    5038             : {
    5039    24899817 :   register int i, r;
    5040             : 
    5041   523277857 :   for (i = 0; special_vars[i].name; i++)
    5042             :     {
    5043   523242626 :       r = special_vars[i].name[0] - name[0];
    5044   523242626 :       if (r == 0)
    5045    31679903 :         r = strcmp (special_vars[i].name, name);
    5046   523242626 :       if (r == 0)
    5047         225 :         return i;
    5048   523242401 :       else if (r > 0)
    5049             :         /* Can't match any of rest of elements in sorted list.  Take this out
    5050             :            if it causes problems in certain environments. */
    5051             :         break;
    5052             :     }
    5053             :   return -1;
    5054             : }
    5055             : 
    5056             : /* The variable in NAME has just had its state changed.  Check to see if it
    5057             :    is one of the special ones where something special happens. */
    5058             : void
    5059    24892868 : stupidly_hack_special_variables (name)
    5060             :      char *name;
    5061             : {
    5062    24892868 :   static int sv_sorted = 0;
    5063    24892868 :   int i;
    5064             : 
    5065    24892868 :   if (sv_sorted == 0)   /* shouldn't need, but it's fairly cheap. */
    5066             :     {
    5067     8278653 :       qsort (special_vars, N_SPECIAL_VARS, sizeof (special_vars[0]),
    5068             :                 (QSFUNC *)sv_compare);
    5069     8278653 :       sv_sorted = 1;
    5070             :     }
    5071             : 
    5072    24892868 :   i = find_special_var (name);
    5073    24892868 :   if (i != -1)
    5074         170 :     (*(special_vars[i].function)) (name);
    5075    24892868 : }
    5076             : 
    5077             : /* Special variables that need hooks to be run when they are unset as part
    5078             :    of shell reinitialization should have their sv_ functions run here. */
    5079             : void
    5080           0 : reinit_special_variables ()
    5081             : {
    5082             : #if defined (READLINE)
    5083             :   sv_comp_wordbreaks ("COMP_WORDBREAKS");
    5084             : #endif
    5085           0 :   sv_globignore ("GLOBIGNORE");
    5086           0 :   sv_opterr ("OPTERR");
    5087           0 : }
    5088             : 
    5089             : void
    5090      581946 : sv_ifs (name)
    5091             :      char *name;
    5092             : {
    5093      590769 :   SHELL_VAR *v;
    5094             : 
    5095      590769 :   v = find_variable ("IFS");
    5096      590769 :   setifs (v);
    5097      581946 : }
    5098             : 
    5099             : /* What to do just after the PATH variable has changed. */
    5100             : void
    5101           0 : sv_path (name)
    5102             :      char *name;
    5103             : {
    5104             :   /* hash -r */
    5105           0 :   phash_flush ();
    5106           0 : }
    5107             : 
    5108             : /* What to do just after one of the MAILxxxx variables has changed.  NAME
    5109             :    is the name of the variable.  This is called with NAME set to one of
    5110             :    MAIL, MAILCHECK, or MAILPATH.  */
    5111             : void
    5112           0 : sv_mail (name)
    5113             :      char *name;
    5114             : {
    5115             :   /* If the time interval for checking the files has changed, then
    5116             :      reset the mail timer.  Otherwise, one of the pathname vars
    5117             :      to the users mailbox has changed, so rebuild the array of
    5118             :      filenames. */
    5119           0 :   if (name[4] == 'C')  /* if (strcmp (name, "MAILCHECK") == 0) */
    5120           0 :     reset_mail_timer ();
    5121             :   else
    5122             :     {
    5123           0 :       free_mail_files ();
    5124           0 :       remember_mail_dates ();
    5125             :     }
    5126           0 : }
    5127             : 
    5128             : void
    5129     9542884 : sv_funcnest (name)
    5130             :      char *name;
    5131             : {
    5132     9542884 :   SHELL_VAR *v;
    5133     9542884 :   intmax_t num;
    5134             : 
    5135     9542884 :   v = find_variable (name);
    5136     9542884 :   if (v == 0)
    5137     9542884 :     funcnest_max = 0;
    5138           0 :   else if (legal_number (value_cell (v), &num) == 0)
    5139           0 :     funcnest_max = 0;
    5140             :   else
    5141           0 :     funcnest_max = num;
    5142     9542884 : }
    5143             : 
    5144             : /* What to do when EXECIGNORE changes. */
    5145             : void
    5146           0 : sv_execignore (name)
    5147             :      char *name;
    5148             : {
    5149           0 :   setup_exec_ignore (name);
    5150           0 : }
    5151             : 
    5152             : /* What to do when GLOBIGNORE changes. */
    5153             : void
    5154           0 : sv_globignore (name)
    5155             :      char *name;
    5156             : {
    5157           0 :   if (privileged_mode == 0)
    5158           0 :     setup_glob_ignore (name);
    5159           0 : }
    5160             : 
    5161             : #if defined (READLINE)
    5162             : void
    5163             : sv_comp_wordbreaks (name)
    5164             :      char *name;
    5165             : {
    5166             :   SHELL_VAR *sv;
    5167             : 
    5168             :   sv = find_variable (name);
    5169             :   if (sv == 0)
    5170             :     reset_completer_word_break_chars ();
    5171             : }
    5172             : 
    5173             : /* What to do just after one of the TERMxxx variables has changed.
    5174             :    If we are an interactive shell, then try to reset the terminal
    5175             :    information in readline. */
    5176             : void
    5177             : sv_terminal (name)
    5178             :      char *name;
    5179             : {
    5180             :   if (interactive_shell && no_line_editing == 0)
    5181             :     rl_reset_terminal (get_string_value ("TERM"));
    5182             : }
    5183             : 
    5184             : void
    5185             : sv_hostfile (name)
    5186             :      char *name;
    5187             : {
    5188             :   SHELL_VAR *v;
    5189             : 
    5190             :   v = find_variable (name);
    5191             :   if (v == 0)
    5192             :     clear_hostname_list ();
    5193             :   else
    5194             :     hostname_list_initialized = 0;
    5195             : }
    5196             : 
    5197             : #if defined (STRICT_POSIX)
    5198             : /* In strict posix mode, we allow assignments to LINES and COLUMNS (and values
    5199             :    found in the initial environment) to override the terminal size reported by
    5200             :    the kernel. */
    5201             : void
    5202             : sv_winsize (name)
    5203             :      char *name;
    5204             : {
    5205             :   SHELL_VAR *v;
    5206             :   intmax_t xd;
    5207             :   int d;
    5208             : 
    5209             :   if (posixly_correct == 0 || interactive_shell == 0 || no_line_editing)
    5210             :     return;
    5211             : 
    5212             :   v = find_variable (name);
    5213             :   if (v == 0 || var_isset (v) == 0)
    5214             :     rl_reset_screen_size ();
    5215             :   else
    5216             :     {
    5217             :       if (legal_number (value_cell (v), &xd) == 0)
    5218             :         return;
    5219             :       winsize_assignment = 1;
    5220             :       d = xd;                   /* truncate */
    5221             :       if (name[0] == 'L')       /* LINES */
    5222             :         rl_set_screen_size (d, -1);
    5223             :       else                      /* COLUMNS */
    5224             :         rl_set_screen_size (-1, d);
    5225             :       winsize_assignment = 0;
    5226             :     }
    5227             : }
    5228             : #endif /* STRICT_POSIX */
    5229             : #endif /* READLINE */
    5230             : 
    5231             : /* Update the value of HOME in the export environment so tilde expansion will
    5232             :    work on cygwin. */
    5233             : #if defined (__CYGWIN__)
    5234             : sv_home (name)
    5235             :      char *name;
    5236             : {
    5237             :   array_needs_making = 1;
    5238             :   maybe_make_export_env ();
    5239             : }
    5240             : #endif
    5241             : 
    5242             : #if defined (HISTORY)
    5243             : /* What to do after the HISTSIZE or HISTFILESIZE variables change.
    5244             :    If there is a value for this HISTSIZE (and it is numeric), then stifle
    5245             :    the history.  Otherwise, if there is NO value for this variable,
    5246             :    unstifle the history.  If name is HISTFILESIZE, and its value is
    5247             :    numeric, truncate the history file to hold no more than that many
    5248             :    lines. */
    5249             : void
    5250             : sv_histsize (name)
    5251             :      char *name;
    5252             : {
    5253             :   char *temp;
    5254             :   intmax_t num;
    5255             :   int hmax;
    5256             : 
    5257             :   temp = get_string_value (name);
    5258             : 
    5259             :   if (temp && *temp)
    5260             :     {
    5261             :       if (legal_number (temp, &num))
    5262             :         {
    5263             :           hmax = num;
    5264             :           if (hmax < 0 && name[4] == 'S')
    5265             :             unstifle_history ();        /* unstifle history if HISTSIZE < 0 */
    5266             :           else if (name[4] == 'S')
    5267             :             {
    5268             :               stifle_history (hmax);
    5269             :               hmax = where_history ();
    5270             :               if (history_lines_this_session > hmax)
    5271             :                 history_lines_this_session = hmax;
    5272             :             }
    5273             :           else if (hmax >= 0)        /* truncate HISTFILE if HISTFILESIZE >= 0 */
    5274             :             {
    5275             :               history_truncate_file (get_string_value ("HISTFILE"), hmax);
    5276             :               /* If we just shrank the history file to fewer lines than we've
    5277             :                  already read, make sure we adjust our idea of how many lines
    5278             :                  we have read from the file. */
    5279             :               if (hmax < history_lines_in_file)
    5280             :                 history_lines_in_file = hmax;
    5281             :             }
    5282             :         }
    5283             :     }
    5284             :   else if (name[4] == 'S')
    5285             :     unstifle_history ();
    5286             : }
    5287             : 
    5288             : /* What to do after the HISTIGNORE variable changes. */
    5289             : void
    5290             : sv_histignore (name)
    5291             :      char *name;
    5292             : {
    5293             :   setup_history_ignore (name);
    5294             : }
    5295             : 
    5296             : /* What to do after the HISTCONTROL variable changes. */
    5297             : void
    5298             : sv_history_control (name)
    5299             :      char *name;
    5300             : {
    5301             :   char *temp;
    5302             :   char *val;
    5303             :   int tptr;
    5304             : 
    5305             :   history_control = 0;
    5306             :   temp = get_string_value (name);
    5307             : 
    5308             :   if (temp == 0 || *temp == 0)
    5309             :     return;
    5310             : 
    5311             :   tptr = 0;
    5312             :   while (val = extract_colon_unit (temp, &tptr))
    5313             :     {
    5314             :       if (STREQ (val, "ignorespace"))
    5315             :         history_control |= HC_IGNSPACE;
    5316             :       else if (STREQ (val, "ignoredups"))
    5317             :         history_control |= HC_IGNDUPS;
    5318             :       else if (STREQ (val, "ignoreboth"))
    5319             :         history_control |= HC_IGNBOTH;
    5320             :       else if (STREQ (val, "erasedups"))
    5321             :         history_control |= HC_ERASEDUPS;
    5322             : 
    5323             :       free (val);
    5324             :     }
    5325             : }
    5326             : 
    5327             : #if defined (BANG_HISTORY)
    5328             : /* Setting/unsetting of the history expansion character. */
    5329             : void
    5330             : sv_histchars (name)
    5331             :      char *name;
    5332             : {
    5333             :   char *temp;
    5334             : 
    5335             :   temp = get_string_value (name);
    5336             :   if (temp)
    5337             :     {
    5338             :       history_expansion_char = *temp;
    5339             :       if (temp[0] && temp[1])
    5340             :         {
    5341             :           history_subst_char = temp[1];
    5342             :           if (temp[2])
    5343             :               history_comment_char = temp[2];
    5344             :         }
    5345             :     }
    5346             :   else
    5347             :     {
    5348             :       history_expansion_char = '!';
    5349             :       history_subst_char = '^';
    5350             :       history_comment_char = '#';
    5351             :     }
    5352             : }
    5353             : #endif /* BANG_HISTORY */
    5354             : 
    5355             : void
    5356             : sv_histtimefmt (name)
    5357             :      char *name;
    5358             : {
    5359             :   SHELL_VAR *v;
    5360             : 
    5361             :   if (v = find_variable (name))
    5362             :     {
    5363             :       if (history_comment_char == 0)
    5364             :         history_comment_char = '#';
    5365             :     }
    5366             :   history_write_timestamps = (v != 0);
    5367             : }
    5368             : #endif /* HISTORY */
    5369             : 
    5370             : #if defined (HAVE_TZSET)
    5371             : void
    5372           0 : sv_tz (name)
    5373             :      char *name;
    5374             : {
    5375           0 :   if (chkexport (name))
    5376           0 :     tzset ();
    5377           0 : }
    5378             : #endif
    5379             : 
    5380             : /* If the variable exists, then the value of it can be the number
    5381             :    of times we actually ignore the EOF.  The default is small,
    5382             :    (smaller than csh, anyway). */
    5383             : void
    5384         170 : sv_ignoreeof (name)
    5385             :      char *name;
    5386             : {
    5387         170 :   SHELL_VAR *tmp_var;
    5388         170 :   char *temp;
    5389             : 
    5390         170 :   eof_encountered = 0;
    5391             : 
    5392         170 :   tmp_var = find_variable (name);
    5393         170 :   ignoreeof = tmp_var && var_isset (tmp_var);
    5394         170 :   temp = tmp_var ? value_cell (tmp_var) : (char *)NULL;
    5395         106 :   if (temp)
    5396         106 :     eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10;
    5397         170 :   set_shellopts ();     /* make sure `ignoreeof' is/is not in $SHELLOPTS */
    5398         170 : }
    5399             : 
    5400             : void
    5401           0 : sv_optind (name)
    5402             :      char *name;
    5403             : {
    5404           0 :   SHELL_VAR *var;
    5405           0 :   char *tt;
    5406           0 :   int s;
    5407             : 
    5408           0 :   var = find_variable ("OPTIND");
    5409           0 :   tt = var ? get_variable_value (var) : (char *)NULL;
    5410             : 
    5411             :   /* Assume that if var->context < variable_context and variable_context > 0
    5412             :      then we are restoring the variables's previous state while returning
    5413             :      from a function. */
    5414           0 :   if (tt && *tt)
    5415             :     {
    5416           0 :       s = atoi (tt);
    5417             : 
    5418             :       /* According to POSIX, setting OPTIND=1 resets the internal state
    5419             :          of getopt (). */
    5420           0 :       if (s < 0 || s == 1)
    5421           0 :         s = 0;
    5422             :     }
    5423             :   else
    5424             :     s = 0;
    5425           0 :   getopts_reset (s);
    5426           0 : }
    5427             : 
    5428             : void
    5429           0 : sv_opterr (name)
    5430             :      char *name;
    5431             : {
    5432           0 :   char *tt;
    5433             : 
    5434           0 :   tt = get_string_value ("OPTERR");
    5435           0 :   sh_opterr = (tt && *tt) ? atoi (tt) : 1;
    5436           0 : }
    5437             : 
    5438             : void
    5439           0 : sv_strict_posix (name)
    5440             :      char *name;
    5441             : {
    5442           0 :   SHELL_VAR *var;
    5443             : 
    5444           0 :   var = find_variable (name);
    5445           0 :   posixly_correct = var && var_isset (var);
    5446           0 :   posix_initialize (posixly_correct);
    5447             : #if defined (READLINE)
    5448             :   if (interactive_shell)
    5449             :     posix_readline_initialize (posixly_correct);
    5450             : #endif /* READLINE */
    5451           0 :   set_shellopts ();     /* make sure `posix' is/is not in $SHELLOPTS */
    5452           0 : }
    5453             : 
    5454             : void
    5455           0 : sv_locale (name)
    5456             :      char *name;
    5457             : {
    5458           0 :   char *v;
    5459           0 :   int r;
    5460             : 
    5461           0 :   v = get_string_value (name);
    5462           0 :   if (name[0] == 'L' && name[1] == 'A') /* LANG */
    5463           0 :     r = set_lang (name, v);
    5464             :   else
    5465           0 :     r = set_locale_var (name, v);               /* LC_*, TEXTDOMAIN* */
    5466             : 
    5467             : #if 1
    5468           0 :   if (r == 0 && posixly_correct)
    5469           0 :     last_command_exit_value = 1;
    5470             : #endif
    5471           0 : }
    5472             : 
    5473             : #if defined (ARRAY_VARS)
    5474             : void
    5475    78921139 : set_pipestatus_array (ps, nproc)
    5476             :      int *ps;
    5477             :      int nproc;
    5478             : {
    5479    78921139 :   SHELL_VAR *v;
    5480    78921139 :   ARRAY *a;
    5481    78921139 :   ARRAY_ELEMENT *ae;
    5482    78921139 :   register int i;
    5483    78921139 :   char *t, tbuf[INT_STRLEN_BOUND(int) + 1];
    5484             : 
    5485    78921139 :   v = find_variable ("PIPESTATUS");
    5486    78921139 :   if (v == 0)
    5487     9542884 :     v = make_new_array_variable ("PIPESTATUS");
    5488    78921139 :   if (array_p (v) == 0)
    5489     9542884 :     return;             /* Do nothing if not an array variable. */
    5490    78921139 :   a = array_cell (v);
    5491             : 
    5492    78921139 :   if (a == 0 || array_num_elements (a) == 0)
    5493             :     {
    5494    19085768 :       for (i = 0; i < nproc; i++)    /* was ps[i] != -1, not i < nproc */
    5495             :         {
    5496     9542884 :           t = inttostr (ps[i], tbuf, sizeof (tbuf));
    5497     9542884 :           array_insert (a, i, t);
    5498             :         }
    5499             :       return;
    5500             :     }
    5501             : 
    5502             :   /* Fast case */
    5503    69378255 :   if (array_num_elements (a) == nproc && nproc == 1)
    5504             :     {
    5505    69345856 :       ae = element_forw (a->head);
    5506    69345856 :       free (element_value (ae));
    5507    69345856 :       ae->value = itos (ps[0]);
    5508             :     }
    5509       32399 :   else if (array_num_elements (a) <= nproc)
    5510             :     {
    5511             :       /* modify in array_num_elements members in place, then add */
    5512       21523 :       ae = a->head;
    5513       43350 :       for (i = 0; i < array_num_elements (a); i++)
    5514             :         {
    5515       21827 :           ae = element_forw (ae);
    5516       21827 :           free (element_value (ae));
    5517       21827 :           ae->value = itos (ps[i]);
    5518             :         }
    5519             :       /* add any more */
    5520       49602 :       for ( ; i < nproc; i++)
    5521             :         {
    5522       28079 :           t = inttostr (ps[i], tbuf, sizeof (tbuf));
    5523       28079 :           array_insert (a, i, t);
    5524             :         }
    5525             :     }
    5526             :   else
    5527             :     {
    5528             :       /* deleting elements.  it's faster to rebuild the array. */         
    5529       10876 :       array_flush (a);
    5530       21799 :       for (i = 0; ps[i] != -1; i++)
    5531             :         {
    5532       10923 :           t = inttostr (ps[i], tbuf, sizeof (tbuf));
    5533       10923 :           array_insert (a, i, t);
    5534             :         }
    5535             :     }
    5536             : }
    5537             : 
    5538             : ARRAY *
    5539        8592 : save_pipestatus_array ()
    5540             : {
    5541        8592 :   SHELL_VAR *v;
    5542        8592 :   ARRAY *a2;
    5543             : 
    5544        8592 :   v = find_variable ("PIPESTATUS");
    5545        8592 :   if (v == 0 || array_p (v) == 0 || array_cell (v) == 0)
    5546             :     return ((ARRAY *)NULL);
    5547             :     
    5548        8592 :   a2 = array_copy (array_cell (v));
    5549             : 
    5550        8592 :   return a2;
    5551             : }
    5552             : 
    5553             : void
    5554        8583 : restore_pipestatus_array (a)
    5555             :      ARRAY *a;
    5556             : {
    5557        8583 :   SHELL_VAR *v;
    5558        8583 :   ARRAY *a2;
    5559             : 
    5560        8583 :   v = find_variable ("PIPESTATUS");
    5561             :   /* XXX - should we still assign even if existing value is NULL? */
    5562        8583 :   if (v == 0 || array_p (v) == 0 || array_cell (v) == 0)
    5563             :     return;
    5564             : 
    5565        8583 :   a2 = array_cell (v);
    5566        8583 :   var_setarray (v, a); 
    5567             : 
    5568        8583 :   array_dispose (a2);
    5569             : }
    5570             : #endif
    5571             : 
    5572             : void
    5573    69494705 : set_pipestatus_from_exit (s)
    5574             :      int s;
    5575             : {
    5576             : #if defined (ARRAY_VARS)
    5577    69494705 :   static int v[2] = { 0, -1 };
    5578             : 
    5579    69494705 :   v[0] = s;
    5580    69494705 :   set_pipestatus_array (v, 1);
    5581             : #endif
    5582    69494705 : }
    5583             : 
    5584             : void
    5585           0 : sv_xtracefd (name)
    5586             :      char *name;
    5587             : {
    5588           0 :   SHELL_VAR *v;
    5589           0 :   char *t, *e;
    5590           0 :   int fd;
    5591           0 :   FILE *fp;
    5592             : 
    5593           0 :   v = find_variable (name);
    5594           0 :   if (v == 0)
    5595             :     {
    5596           0 :       xtrace_reset ();
    5597           0 :       return;
    5598             :     }
    5599             : 
    5600           0 :   t = value_cell (v);
    5601           0 :   if (t == 0 || *t == 0)
    5602           0 :     xtrace_reset ();
    5603             :   else
    5604             :     {
    5605           0 :       fd = (int)strtol (t, &e, 10);
    5606           0 :       if (e != t && *e == '\0' && sh_validfd (fd))
    5607             :         {
    5608           0 :           fp = fdopen (fd, "w");
    5609           0 :           if (fp == 0)
    5610           0 :             internal_error (_("%s: %s: cannot open as FILE"), name, value_cell (v));
    5611             :           else
    5612           0 :             xtrace_set (fd, fp);
    5613             :         }
    5614             :       else
    5615           0 :         internal_error (_("%s: %s: invalid value for trace file descriptor"), name, value_cell (v));
    5616             :     }
    5617             : }
    5618             : 
    5619             : #define MIN_COMPAT_LEVEL 31
    5620             : 
    5621             : void
    5622     9542884 : sv_shcompat (name)
    5623             :      char *name;
    5624             : {
    5625     9542884 :   SHELL_VAR *v;
    5626     9542884 :   char *val;
    5627     9542884 :   int tens, ones, compatval;
    5628             : 
    5629     9542884 :   v = find_variable (name);
    5630     9542884 :   if (v == 0)
    5631             :     {
    5632     9542884 :       shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
    5633     9542884 :       set_compatibility_opts ();
    5634     9542884 :       return;
    5635             :     }
    5636           0 :   val = value_cell (v);
    5637           0 :   if (val == 0 || *val == '\0')
    5638             :     {
    5639           0 :       shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
    5640           0 :       set_compatibility_opts ();
    5641           0 :       return;
    5642             :     }
    5643             :   /* Handle decimal-like compatibility version specifications: 4.2 */
    5644           0 :   if (ISDIGIT (val[0]) && val[1] == '.' && ISDIGIT (val[2]) && val[3] == 0)
    5645             :     {
    5646           0 :       tens = val[0] - '0';
    5647           0 :       ones = val[2] - '0';
    5648           0 :       compatval = tens*10 + ones;
    5649             :     }
    5650             :   /* Handle integer-like compatibility version specifications: 42 */
    5651           0 :   else if (ISDIGIT (val[0]) && ISDIGIT (val[1]) && val[2] == 0)
    5652             :     {
    5653           0 :       tens = val[0] - '0';
    5654           0 :       ones = val[1] - '0';
    5655           0 :       compatval = tens*10 + ones;
    5656             :     }
    5657             :   else
    5658             :     {
    5659           0 : compat_error:
    5660           0 :       internal_error (_("%s: %s: compatibility value out of range"), name, val);
    5661           0 :       shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
    5662           0 :       set_compatibility_opts ();
    5663           0 :       return;
    5664             :     }
    5665             : 
    5666           0 :   if (compatval < MIN_COMPAT_LEVEL || compatval > DEFAULT_COMPAT_LEVEL)
    5667             :     goto compat_error;
    5668             : 
    5669           0 :   shell_compatibility_level = compatval;
    5670           0 :   set_compatibility_opts ();
    5671             : }
    5672             : 
    5673             : #if defined (JOB_CONTROL)
    5674             : void
    5675           0 : sv_childmax (name)
    5676             :      char *name;
    5677             : {
    5678           0 :   char *tt;
    5679           0 :   int s;
    5680             : 
    5681           0 :   tt = get_string_value (name);
    5682           0 :   s = (tt && *tt) ? atoi (tt) : 0;
    5683           0 :   set_maxchild (s);
    5684           0 : }
    5685             : #endif

Generated by: LCOV version 1.14.0.6.4058