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