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