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