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