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