]> git.ipfire.org Git - thirdparty/bash.git/blame - variables.c
Imported from ../bash-2.05b.tar.gz.
[thirdparty/bash.git] / variables.c
CommitLineData
726f6388
JA
1/* variables.c -- Functions for hacking shell variables. */
2
7117c2d2 3/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
726f6388
JA
4
5 This file is part of GNU Bash, the Bourne Again SHell.
6
7 Bash is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
bb70624e 9 the Free Software Foundation; either version 2, or (at your option)
726f6388
JA
10 any later version.
11
12 Bash is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Bash; see the file COPYING. If not, write to the Free
bb70624e 19 Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
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
d166f048
JA
27#if defined (qnx)
28# include <sys/vc.h>
29#endif
30
ccc6cda3
JA
31#if defined (HAVE_UNISTD_H)
32# include <unistd.h>
33#endif
34
35#include <stdio.h>
f73dda09 36#include "chartypes.h"
726f6388 37#include <pwd.h>
726f6388 38#include "bashansi.h"
ccc6cda3 39
726f6388 40#include "shell.h"
726f6388
JA
41#include "flags.h"
42#include "execute_cmd.h"
cce855bc 43#include "findcmd.h"
ccc6cda3
JA
44#include "mailcheck.h"
45#include "input.h"
f73dda09
JA
46#include "hashcmd.h"
47#include "pathexp.h"
726f6388 48
d166f048 49#include "builtins/getopt.h"
726f6388 50#include "builtins/common.h"
cce855bc
JA
51
52#if defined (READLINE)
53# include "bashline.h"
54# include <readline/readline.h>
55#else
56# include <tilde/tilde.h>
57#endif
726f6388 58
ccc6cda3
JA
59#if defined (HISTORY)
60# include "bashhist.h"
cce855bc 61# include <readline/history.h>
ccc6cda3
JA
62#endif /* HISTORY */
63
bb70624e
JA
64#if defined (PROGRAMMABLE_COMPLETION)
65# include "pcomplete.h"
66#endif
67
7117c2d2
JA
68#define TEMPENV_HASH_BUCKETS 4 /* must be power of two */
69
70#define ifsname(s) ((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0')
71
726f6388
JA
72/* Variables used here and defined in other files. */
73extern int posixly_correct;
f73dda09 74extern int line_number;
ccc6cda3
JA
75extern int subshell_environment, indirection_level;
76extern int build_version, patch_level;
77extern char *dist_version, *release_status;
726f6388
JA
78extern char *shell_name;
79extern char *primary_prompt, *secondary_prompt;
ccc6cda3 80extern char *current_host_name;
f73dda09 81extern sh_builtin_func_t *this_shell_builtin;
bb70624e 82extern SHELL_VAR *this_shell_function;
ccc6cda3 83extern char *this_command_name;
726f6388
JA
84extern time_t shell_start_time;
85
7117c2d2
JA
86/* The list of shell variables that the user has created at the global
87 scope, or that came from the environment. */
88VAR_CONTEXT *global_variables = (VAR_CONTEXT *)NULL;
89
90/* The current list of shell variables, including function scopes */
91VAR_CONTEXT *shell_variables = (VAR_CONTEXT *)NULL;
726f6388
JA
92
93/* The list of shell functions that the user has created, or that came from
94 the environment. */
95HASH_TABLE *shell_functions = (HASH_TABLE *)NULL;
96
97/* The current variable context. This is really a count of how deep into
98 executing functions we are. */
99int variable_context = 0;
100
7117c2d2 101/* The set of shell assignments which are made only in the environment
726f6388 102 for a single command. */
7117c2d2 103HASH_TABLE *temporary_env = (HASH_TABLE *)NULL;
726f6388
JA
104
105/* Some funky variables which are known about specially. Here is where
106 "$*", "$1", and all the cruft is kept. */
107char *dollar_vars[10];
108WORD_LIST *rest_of_args = (WORD_LIST *)NULL;
109
110/* The value of $$. */
f73dda09 111pid_t dollar_dollar_pid;
726f6388
JA
112
113/* An array which is passed to commands as their environment. It is
d166f048 114 manufactured from the union of the initial environment and the
726f6388
JA
115 shell variables that are marked for export. */
116char **export_env = (char **)NULL;
d166f048
JA
117static int export_env_index;
118static int export_env_size;
726f6388
JA
119
120/* Non-zero means that we have to remake EXPORT_ENV. */
121int array_needs_making = 1;
122
ccc6cda3
JA
123/* The number of times BASH has been executed. This is set
124 by initialize_variables (). */
125int shell_level = 0;
726f6388 126
726f6388 127/* Some forward declarations. */
f73dda09
JA
128static void set_machine_vars __P((void));
129static void set_home_var __P((void));
130static void set_shell_var __P((void));
131static char *get_bash_name __P((void));
132static void initialize_shell_level __P((void));
133static void uidset __P((void));
134#if defined (ARRAY_VARS)
135static void make_vers_array __P((void));
136#endif
f73dda09 137
7117c2d2
JA
138static SHELL_VAR *null_assign __P((SHELL_VAR *, char *, arrayind_t));
139#if defined (ARRAY_VARS)
140static SHELL_VAR *null_array_assign __P((SHELL_VAR *, char *, arrayind_t));
141#endif
142
143static SHELL_VAR *assign_seconds __P((SHELL_VAR *, char *, arrayind_t));
144static SHELL_VAR *get_seconds __P((SHELL_VAR *));
145static SHELL_VAR *init_seconds_var __P((void));
146
147static int brand __P((void));
f73dda09 148static void sbrand __P((unsigned long)); /* set bash random number generator. */
7117c2d2
JA
149static SHELL_VAR *assign_random __P((SHELL_VAR *, char *, arrayind_t));
150static SHELL_VAR *get_random __P((SHELL_VAR *));
f73dda09 151
7117c2d2
JA
152static SHELL_VAR *assign_lineno __P((SHELL_VAR *, char *, arrayind_t));
153static SHELL_VAR *get_lineno __P((SHELL_VAR *));
f73dda09 154
7117c2d2
JA
155#if defined (HISTORY)
156static SHELL_VAR *get_histcmd __P((SHELL_VAR *));
157#endif
158
159#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
160static SHELL_VAR *assign_dirstack __P((SHELL_VAR *, char *, arrayind_t));
161static SHELL_VAR *get_dirstack __P((SHELL_VAR *));
162static SHELL_VAR *init_dirstack_var __P((void));
163#endif
164
165#if defined (ARRAY_VARS)
166static SHELL_VAR *get_groupset __P((SHELL_VAR *));
167static SHELL_VAR *init_groups_var __P((void));
168#endif
169
170static SHELL_VAR *get_funcname __P((SHELL_VAR *));
171static SHELL_VAR *init_funcname_var __P((void));
172
173static void initialize_dynamic_variables __P((void));
174
175static SHELL_VAR *hash_lookup __P((const char *, HASH_TABLE *));
f73dda09 176static SHELL_VAR *new_shell_variable __P((const char *));
7117c2d2
JA
177static SHELL_VAR *make_new_variable __P((const char *, HASH_TABLE *));
178static SHELL_VAR *bind_variable_internal __P((const char *, char *, HASH_TABLE *, int));
179
180static void free_variable_hash_data __P((PTR_T));
181
182static VARLIST *vlist_alloc __P((int));
183static VARLIST *vlist_realloc __P((VARLIST *, int));
184static void vlist_add __P((VARLIST *, SHELL_VAR *, int));
185
186static void flatten __P((HASH_TABLE *, sh_var_map_func_t *, VARLIST *, int));
187
188static int qsort_var_comp __P((SHELL_VAR **, SHELL_VAR **));
f73dda09 189
7117c2d2
JA
190static SHELL_VAR **vapply __P((sh_var_map_func_t *));
191static SHELL_VAR **fapply __P((sh_var_map_func_t *));
f73dda09
JA
192
193static int visible_var __P((SHELL_VAR *));
f73dda09 194static int visible_and_exported __P((SHELL_VAR *));
7117c2d2
JA
195static int local_and_exported __P((SHELL_VAR *));
196static int variable_in_context __P((SHELL_VAR *));
f73dda09
JA
197#if defined (ARRAY_VARS)
198static int visible_array_vars __P((SHELL_VAR *));
199#endif
200
7117c2d2
JA
201static SHELL_VAR *bind_tempenv_variable __P((const char *, char *));
202static void push_temp_var __P((PTR_T));
203static void propagate_temp_var __P((PTR_T));
204static void dispose_temporary_env __P((sh_free_func_t *));
205
f73dda09 206static inline char *mk_env_string __P((const char *, const char *));
7117c2d2
JA
207static char **make_env_array_from_var_list __P((SHELL_VAR **));
208static char **make_var_export_array __P((VAR_CONTEXT *));
209static char **make_func_export_array __P((void));
210static void add_temp_array_to_env __P((char **, int, int));
f73dda09 211
7117c2d2
JA
212static int n_shell_variables __P((void));
213static int set_context __P((SHELL_VAR *));
726f6388 214
7117c2d2
JA
215static void push_func_var __P((PTR_T));
216static void push_exported_var __P((PTR_T));
726f6388 217
7117c2d2
JA
218static inline int find_special_var __P((const char *));
219
cce855bc
JA
220/* Initialize the shell variables from the current environment.
221 If PRIVMODE is nonzero, don't import functions from ENV or
222 parse $SHELLOPTS. */
726f6388 223void
cce855bc 224initialize_shell_variables (env, privmode)
726f6388 225 char **env;
cce855bc 226 int privmode;
726f6388 227{
ccc6cda3
JA
228 char *name, *string, *temp_string;
229 int c, char_index, string_index, string_length;
726f6388
JA
230 SHELL_VAR *temp_var;
231
cce855bc 232 if (shell_variables == 0)
7117c2d2
JA
233 {
234 shell_variables = global_variables = new_var_context ((char *)NULL, 0);
235 shell_variables->scope = 0;
236 shell_variables->table = hash_create (0);
237 }
726f6388 238
cce855bc 239 if (shell_functions == 0)
7117c2d2 240 shell_functions = hash_create (0);
726f6388 241
ccc6cda3 242 for (string_index = 0; string = env[string_index++]; )
726f6388 243 {
726f6388 244 char_index = 0;
d166f048 245 name = string;
726f6388 246 while ((c = *string++) && c != '=')
d166f048
JA
247 ;
248 if (string[-1] == '=')
28ef6c31 249 char_index = string - name - 1;
726f6388 250
d166f048
JA
251 /* If there are weird things in the environment, like `=xxx' or a
252 string without an `=', just skip them. */
253 if (char_index == 0)
28ef6c31 254 continue;
d166f048
JA
255
256 /* ASSERT(name[char_index] == '=') */
726f6388 257 name[char_index] = '\0';
d166f048 258 /* Now, name = env variable name, string = env variable value, and
28ef6c31 259 char_index == strlen (name) */
726f6388 260
f73dda09 261 /* If exported function, define it now. Don't import functions from
7117c2d2 262 the environment in privileged mode. */
bb70624e 263 if (privmode == 0 && read_but_dont_execute == 0 && STREQN ("() {", string, 4))
726f6388 264 {
d166f048 265 string_length = strlen (string);
f73dda09 266 temp_string = (char *)xmalloc (3 + string_length + char_index);
bb70624e 267
d166f048
JA
268 strcpy (temp_string, name);
269 temp_string[char_index] = ' ';
270 strcpy (temp_string + char_index + 1, string);
726f6388 271
d166f048 272 parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST);
726f6388 273
d166f048
JA
274 /* Ancient backwards compatibility. Old versions of bash exported
275 functions like name()=() {...} */
276 if (name[char_index - 1] == ')' && name[char_index - 2] == '(')
726f6388
JA
277 name[char_index - 2] = '\0';
278
ccc6cda3 279 if (temp_var = find_function (name))
726f6388 280 {
bb70624e 281 VSETATTR (temp_var, (att_exported|att_imported));
726f6388
JA
282 array_needs_making = 1;
283 }
284 else
285 report_error ("error importing function definition for `%s'", name);
d166f048 286
bb70624e 287 /* ( */
d166f048 288 if (name[char_index - 1] == ')' && name[char_index - 2] == '\0')
bb70624e 289 name[char_index - 2] = '('; /* ) */
726f6388 290 }
ccc6cda3
JA
291#if defined (ARRAY_VARS)
292# if 0
293 /* Array variables may not yet be exported. */
7117c2d2 294 else if (*string == '(' && string[1] == '[' && xstrchr (string, ')'))
ccc6cda3
JA
295 {
296 string_length = 1;
297 temp_string = extract_array_assignment_list (string, &string_length);
298 temp_var = assign_array_from_string (name, temp_string);
299 FREE (temp_string);
bb70624e 300 VSETATTR (temp_var, (att_exported | att_imported));
ccc6cda3
JA
301 array_needs_making = 1;
302 }
303# endif
304#endif
726f6388
JA
305 else
306 {
ccc6cda3 307 temp_var = bind_variable (name, string);
bb70624e 308 VSETATTR (temp_var, (att_exported | att_imported));
726f6388
JA
309 array_needs_making = 1;
310 }
d166f048
JA
311
312 name[char_index] = '=';
bb70624e 313 /* temp_var can be NULL if it was an exported function with a syntax
28ef6c31 314 error (a different bug, but it still shouldn't dump core). */
bb70624e
JA
315 if (temp_var && function_p (temp_var) == 0) /* XXX not yet */
316 {
317 CACHE_IMPORTSTR (temp_var, name);
318 }
726f6388
JA
319 }
320
28ef6c31 321 set_pwd ();
b72432fd 322
ccc6cda3
JA
323 /* Set up initial value of $_ */
324 temp_var = bind_variable ("_", dollar_vars[0]);
325
726f6388 326 /* Remember this pid. */
f73dda09 327 dollar_dollar_pid = getpid ();
726f6388
JA
328
329 /* Now make our own defaults in case the vars that we think are
330 important are missing. */
331 temp_var = set_if_not ("PATH", DEFAULT_PATH_VALUE);
f73dda09
JA
332#if 0
333 set_auto_export (temp_var); /* XXX */
334#endif
726f6388
JA
335
336 temp_var = set_if_not ("TERM", "dumb");
f73dda09
JA
337#if 0
338 set_auto_export (temp_var); /* XXX */
339#endif
726f6388 340
d166f048
JA
341#if defined (qnx)
342 /* set node id -- don't import it from the environment */
343 {
344 char node_name[22];
345 qnx_nidtostr (getnid (), node_name, sizeof (node_name));
346 temp_var = bind_variable ("NODE", node_name);
347 set_auto_export (temp_var);
348 }
349#endif
350
ccc6cda3 351 /* set up the prompts. */
726f6388
JA
352 if (interactive_shell)
353 {
b72432fd 354#if defined (PROMPT_STRING_DECODE)
726f6388 355 set_if_not ("PS1", primary_prompt);
b72432fd
JA
356#else
357 if (current_user.uid == -1)
358 get_current_user_info ();
359 set_if_not ("PS1", current_user.euid == 0 ? "# " : primary_prompt);
360#endif
726f6388
JA
361 set_if_not ("PS2", secondary_prompt);
362 }
363 set_if_not ("PS4", "+ ");
364
ccc6cda3
JA
365 /* Don't allow IFS to be imported from the environment. */
366 temp_var = bind_variable ("IFS", " \t\n");
7117c2d2 367 setifs (temp_var);
726f6388
JA
368
369 /* Magic machine types. Pretty convenient. */
f73dda09 370 set_machine_vars ();
726f6388 371
ccc6cda3
JA
372 /* Default MAILCHECK for interactive shells. Defer the creation of a
373 default MAILPATH until the startup files are read, because MAIL
f73dda09 374 names a mail file if MAILPATH is not set, and we should provide a
ccc6cda3 375 default only if neither is set. */
726f6388 376 if (interactive_shell)
f73dda09 377 set_if_not ("MAILCHECK", posixly_correct ? "600" : "60");
726f6388
JA
378
379 /* Do some things with shell level. */
d166f048 380 initialize_shell_level ();
726f6388 381
b72432fd 382 set_ppid ();
726f6388 383
726f6388
JA
384 /* Initialize the `getopts' stuff. */
385 bind_variable ("OPTIND", "1");
d166f048 386 getopts_reset (0);
726f6388 387 bind_variable ("OPTERR", "1");
d166f048
JA
388 sh_opterr = 1;
389
390 if (login_shell == 1)
391 set_home_var ();
726f6388
JA
392
393 /* Get the full pathname to THIS shell, and set the BASH variable
394 to it. */
d166f048 395 name = get_bash_name ();
ccc6cda3
JA
396 temp_var = bind_variable ("BASH", name);
397 free (name);
398
399 /* Make the exported environment variable SHELL be the user's login
400 shell. Note that the `tset' command looks at this variable
401 to determine what style of commands to output; if it ends in "csh",
402 then C-shell commands are output, else Bourne shell commands. */
d166f048 403 set_shell_var ();
726f6388
JA
404
405 /* Make a variable called BASH_VERSION which contains the version info. */
406 bind_variable ("BASH_VERSION", shell_version_string ());
ccc6cda3
JA
407#if defined (ARRAY_VARS)
408 make_vers_array ();
409#endif
726f6388
JA
410
411 /* Find out if we're supposed to be in Posix.2 mode via an
412 environment variable. */
413 temp_var = find_variable ("POSIXLY_CORRECT");
414 if (!temp_var)
415 temp_var = find_variable ("POSIX_PEDANTIC");
416 if (temp_var && imported_p (temp_var))
417 sv_strict_posix (temp_var->name);
418
419#if defined (HISTORY)
420 /* Set history variables to defaults, and then do whatever we would
421 do if the variable had just been set. Do this only in the case
422 that we are remembering commands on the history list. */
423 if (remember_on_history)
424 {
7117c2d2 425 name = bash_tilde_expand (posixly_correct ? "~/.sh_history" : "~/.bash_history", 0);
726f6388
JA
426
427 set_if_not ("HISTFILE", name);
428 free (name);
429
430 set_if_not ("HISTSIZE", "500");
431 sv_histsize ("HISTSIZE");
432 }
433#endif /* HISTORY */
434
435 /* Seed the random number generator. */
f73dda09 436 sbrand (dollar_dollar_pid + shell_start_time);
726f6388
JA
437
438 /* Handle some "special" variables that we may have inherited from a
439 parent shell. */
d166f048
JA
440 if (interactive_shell)
441 {
442 temp_var = find_variable ("IGNOREEOF");
443 if (!temp_var)
444 temp_var = find_variable ("ignoreeof");
445 if (temp_var && imported_p (temp_var))
446 sv_ignoreeof (temp_var->name);
447 }
726f6388
JA
448
449#if defined (HISTORY)
450 if (interactive_shell && remember_on_history)
451 {
ccc6cda3
JA
452 sv_history_control ("HISTCONTROL");
453 sv_histignore ("HISTIGNORE");
726f6388
JA
454 }
455#endif /* HISTORY */
456
f73dda09
JA
457 /*
458 * 24 October 2001
459 *
460 * I'm tired of the arguing and bug reports. Bash now leaves SSH_CLIENT
461 * and SSH2_CLIENT alone. I'm going to rely on the shell_level check in
462 * isnetconn() to avoid running the startup files more often than wanted.
463 * That will, of course, only work if the user's login shell is bash, so
464 * I've made that behavior conditional on SSH_SOURCE_BASHRC being defined
465 * in config-top.h.
466 */
467#if 0
bb70624e 468 temp_var = find_variable ("SSH_CLIENT");
28ef6c31
JA
469 if (temp_var && imported_p (temp_var))
470 {
471 VUNSETATTR (temp_var, att_exported);
472 array_needs_making = 1;
473 }
474 temp_var = find_variable ("SSH2_CLIENT");
bb70624e
JA
475 if (temp_var && imported_p (temp_var))
476 {
477 VUNSETATTR (temp_var, att_exported);
478 array_needs_making = 1;
479 }
f73dda09 480#endif
bb70624e 481
ccc6cda3
JA
482 /* Get the user's real and effective user ids. */
483 uidset ();
484
726f6388
JA
485 /* Initialize the dynamic variables, and seed their values. */
486 initialize_dynamic_variables ();
726f6388
JA
487}
488
7117c2d2
JA
489/* **************************************************************** */
490/* */
491/* Setting values for special shell variables */
492/* */
493/* **************************************************************** */
494
f73dda09
JA
495static void
496set_machine_vars ()
497{
498 SHELL_VAR *temp_var;
499
500 temp_var = set_if_not ("HOSTTYPE", HOSTTYPE);
501 temp_var = set_if_not ("OSTYPE", OSTYPE);
502 temp_var = set_if_not ("MACHTYPE", MACHTYPE);
503
504 temp_var = set_if_not ("HOSTNAME", current_host_name);
505}
506
d166f048
JA
507/* Set $HOME to the information in the password file if we didn't get
508 it from the environment. */
b72432fd
JA
509
510/* This function is not static so the tilde and readline libraries can
511 use it. */
512char *
28ef6c31 513sh_get_home_dir ()
b72432fd
JA
514{
515 if (current_user.home_dir == 0)
516 get_current_user_info ();
517 return current_user.home_dir;
518}
519
d166f048
JA
520static void
521set_home_var ()
522{
523 SHELL_VAR *temp_var;
524
525 temp_var = find_variable ("HOME");
526 if (temp_var == 0)
28ef6c31 527 temp_var = bind_variable ("HOME", sh_get_home_dir ());
f73dda09 528#if 0
bb70624e 529 VSETATTR (temp_var, att_exported);
f73dda09 530#endif
d166f048
JA
531}
532
533/* Set $SHELL to the user's login shell if it is not already set. Call
534 get_current_user_info if we haven't already fetched the shell. */
535static void
536set_shell_var ()
537{
538 SHELL_VAR *temp_var;
539
540 temp_var = find_variable ("SHELL");
541 if (temp_var == 0)
542 {
543 if (current_user.shell == 0)
544 get_current_user_info ();
545 temp_var = bind_variable ("SHELL", current_user.shell);
546 }
f73dda09 547#if 0
bb70624e 548 VSETATTR (temp_var, att_exported);
f73dda09 549#endif
d166f048
JA
550}
551
552static char *
553get_bash_name ()
554{
555 char *name;
556
28ef6c31 557 if ((login_shell == 1) && RELPATH(shell_name))
d166f048
JA
558 {
559 if (current_user.shell == 0)
28ef6c31 560 get_current_user_info ();
d166f048
JA
561 name = savestring (current_user.shell);
562 }
28ef6c31 563 else if (ABSPATH(shell_name))
d166f048
JA
564 name = savestring (shell_name);
565 else if (shell_name[0] == '.' && shell_name[1] == '/')
566 {
567 /* Fast path for common case. */
568 char *cdir;
569 int len;
570
571 cdir = get_string_value ("PWD");
28ef6c31
JA
572 if (cdir)
573 {
574 len = strlen (cdir);
f73dda09 575 name = (char *)xmalloc (len + strlen (shell_name) + 1);
28ef6c31
JA
576 strcpy (name, cdir);
577 strcpy (name + len, shell_name + 1);
578 }
579 else
580 name = savestring (shell_name);
d166f048
JA
581 }
582 else
583 {
584 char *tname;
585 int s;
586
587 tname = find_user_command (shell_name);
588
589 if (tname == 0)
590 {
591 /* Try the current directory. If there is not an executable
592 there, just punt and use the login shell. */
593 s = file_status (shell_name);
594 if (s & FS_EXECABLE)
595 {
596 tname = make_absolute (shell_name, get_string_value ("PWD"));
597 if (*shell_name == '.')
598 {
28ef6c31 599 name = sh_canonpath (tname, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
d166f048
JA
600 if (name == 0)
601 name = tname;
602 else
603 free (tname);
604 }
605 else
606 name = tname;
607 }
608 else
609 {
610 if (current_user.shell == 0)
611 get_current_user_info ();
612 name = savestring (current_user.shell);
613 }
614 }
615 else
616 {
617 name = full_pathname (tname);
618 free (tname);
619 }
620 }
621
622 return (name);
623}
624
726f6388
JA
625void
626adjust_shell_level (change)
627 int change;
628{
d166f048 629 char new_level[5], *old_SHLVL;
7117c2d2 630 intmax_t old_level;
d166f048 631 SHELL_VAR *temp_var;
726f6388
JA
632
633 old_SHLVL = get_string_value ("SHLVL");
f73dda09
JA
634 if (old_SHLVL == 0 || *old_SHLVL == '\0' || legal_number (old_SHLVL, &old_level) == 0)
635 old_level = 0;
726f6388
JA
636
637 shell_level = old_level + change;
638 if (shell_level < 0)
639 shell_level = 0;
d166f048
JA
640 else if (shell_level > 1000)
641 {
cce855bc 642 internal_warning ("shell level (%d) too high, resetting to 1", shell_level);
d166f048
JA
643 shell_level = 1;
644 }
645
646 /* We don't need the full generality of itos here. */
647 if (shell_level < 10)
648 {
649 new_level[0] = shell_level + '0';
650 new_level[1] = '\0';
651 }
652 else if (shell_level < 100)
653 {
654 new_level[0] = (shell_level / 10) + '0';
655 new_level[1] = (shell_level % 10) + '0';
656 new_level[2] = '\0';
657 }
658 else if (shell_level < 1000)
659 {
660 new_level[0] = (shell_level / 100) + '0';
661 old_level = shell_level % 100;
662 new_level[1] = (old_level / 10) + '0';
663 new_level[2] = (old_level % 10) + '0';
664 new_level[3] = '\0';
665 }
666
667 temp_var = bind_variable ("SHLVL", new_level);
668 set_auto_export (temp_var);
669}
670
671static void
672initialize_shell_level ()
673{
d166f048 674 adjust_shell_level (1);
726f6388
JA
675}
676
28ef6c31
JA
677/* If we got PWD from the environment, update our idea of the current
678 working directory. In any case, make sure that PWD exists before
679 checking it. It is possible for getcwd () to fail on shell startup,
680 and in that case, PWD would be undefined. If this is an interactive
681 login shell, see if $HOME is the current working directory, and if
682 that's not the same string as $PWD, set PWD=$HOME. */
683
684void
685set_pwd ()
686{
687 SHELL_VAR *temp_var, *home_var;
688 char *temp_string, *home_string;
689
690 home_var = find_variable ("HOME");
691 home_string = home_var ? value_cell (home_var) : (char *)NULL;
692
693 temp_var = find_variable ("PWD");
694 if (temp_var && imported_p (temp_var) &&
695 (temp_string = value_cell (temp_var)) &&
696 same_file (temp_string, ".", (struct stat *)NULL, (struct stat *)NULL))
697 set_working_directory (temp_string);
698 else if (home_string && interactive_shell && login_shell &&
699 same_file (home_string, ".", (struct stat *)NULL, (struct stat *)NULL))
700 {
701 set_working_directory (home_string);
702 temp_var = bind_variable ("PWD", home_string);
703 set_auto_export (temp_var);
704 }
705 else
706 {
707 temp_string = get_working_directory ("shell-init");
708 if (temp_string)
709 {
710 temp_var = bind_variable ("PWD", temp_string);
711 set_auto_export (temp_var);
712 free (temp_string);
713 }
714 }
715
716 /* According to the Single Unix Specification, v2, $OLDPWD is an
717 `environment variable' and therefore should be auto-exported.
718 Make a dummy invisible variable for OLDPWD, and mark it as exported. */
719 temp_var = bind_variable ("OLDPWD", (char *)NULL);
720 VSETATTR (temp_var, (att_exported | att_invisible));
721}
722
b72432fd
JA
723/* Make a variable $PPID, which holds the pid of the shell's parent. */
724void
725set_ppid ()
726{
f73dda09 727 char namebuf[INT_STRLEN_BOUND(pid_t) + 1], *name;
b72432fd
JA
728 SHELL_VAR *temp_var;
729
f73dda09 730 name = inttostr (getppid (), namebuf, sizeof(namebuf));
b72432fd
JA
731 temp_var = find_variable ("PPID");
732 if (temp_var)
bb70624e 733 VUNSETATTR (temp_var, (att_readonly | att_exported));
b72432fd 734 temp_var = bind_variable ("PPID", name);
bb70624e 735 VSETATTR (temp_var, (att_readonly | att_integer));
b72432fd
JA
736}
737
ccc6cda3
JA
738static void
739uidset ()
726f6388 740{
f73dda09 741 char buff[INT_STRLEN_BOUND(uid_t) + 1], *b;
ccc6cda3
JA
742 register SHELL_VAR *v;
743
b72432fd 744 b = inttostr (current_user.uid, buff, sizeof (buff));
ccc6cda3 745 v = find_variable ("UID");
28ef6c31
JA
746 if (v == 0)
747 {
748 v = bind_variable ("UID", b);
749 VSETATTR (v, (att_readonly | att_integer));
750 }
726f6388 751
ccc6cda3 752 if (current_user.euid != current_user.uid)
b72432fd 753 b = inttostr (current_user.euid, buff, sizeof (buff));
726f6388 754
ccc6cda3 755 v = find_variable ("EUID");
28ef6c31
JA
756 if (v == 0)
757 {
758 v = bind_variable ("EUID", b);
759 VSETATTR (v, (att_readonly | att_integer));
760 }
ccc6cda3
JA
761}
762
763#if defined (ARRAY_VARS)
764static void
765make_vers_array ()
766{
767 SHELL_VAR *vv;
768 ARRAY *av;
f73dda09 769 char *s, d[32], b[INT_STRLEN_BOUND(int) + 1];
ccc6cda3 770
7117c2d2 771 unbind_variable ("BASH_VERSINFO");
ccc6cda3
JA
772
773 vv = make_new_array_variable ("BASH_VERSINFO");
774 av = array_cell (vv);
775 strcpy (d, dist_version);
7117c2d2 776 s = xstrchr (d, '.');
ccc6cda3
JA
777 if (s)
778 *s++ = '\0';
7117c2d2
JA
779 array_insert (av, 0, d);
780 array_insert (av, 1, s);
f73dda09 781 s = inttostr (patch_level, b, sizeof (b));
7117c2d2 782 array_insert (av, 2, s);
f73dda09 783 s = inttostr (build_version, b, sizeof (b));
7117c2d2
JA
784 array_insert (av, 3, s);
785 array_insert (av, 4, release_status);
786 array_insert (av, 5, MACHTYPE);
ccc6cda3 787
bb70624e 788 VSETATTR (vv, att_readonly);
ccc6cda3
JA
789}
790#endif /* ARRAY_VARS */
791
792/* Set the environment variables $LINES and $COLUMNS in response to
793 a window size change. */
794void
28ef6c31 795sh_set_lines_and_columns (lines, cols)
ccc6cda3
JA
796 int lines, cols;
797{
f73dda09 798 char val[INT_STRLEN_BOUND(int) + 1], *v;
ccc6cda3 799
b72432fd
JA
800 v = inttostr (lines, val, sizeof (val));
801 bind_variable ("LINES", v);
ccc6cda3 802
b72432fd
JA
803 v = inttostr (cols, val, sizeof (val));
804 bind_variable ("COLUMNS", v);
726f6388
JA
805}
806
7117c2d2
JA
807/* **************************************************************** */
808/* */
809/* Printing variables and values */
810/* */
811/* **************************************************************** */
726f6388 812
28ef6c31
JA
813/* Print LIST (a list of shell variables) to stdout in such a way that
814 they can be read back in. */
726f6388
JA
815void
816print_var_list (list)
817 register SHELL_VAR **list;
818{
819 register int i;
820 register SHELL_VAR *var;
821
822 for (i = 0; list && (var = list[i]); i++)
7117c2d2 823 if (invisible_p (var) == 0)
726f6388
JA
824 print_assignment (var);
825}
826
28ef6c31
JA
827/* Print LIST (a list of shell functions) to stdout in such a way that
828 they can be read back in. */
829void
830print_func_list (list)
831 register SHELL_VAR **list;
832{
833 register int i;
834 register SHELL_VAR *var;
835
836 for (i = 0; list && (var = list[i]); i++)
837 {
838 printf ("%s ", var->name);
839 print_var_function (var);
840 printf ("\n");
841 }
842}
843
726f6388
JA
844/* Print the value of a single SHELL_VAR. No newline is
845 output, but the variable is printed in such a way that
846 it can be read back in. */
847void
848print_assignment (var)
849 SHELL_VAR *var;
850{
7117c2d2
JA
851 if (var_isset (var) == 0)
852 return;
853
854 if (function_p (var))
726f6388 855 {
28ef6c31 856 printf ("%s", var->name);
726f6388
JA
857 print_var_function (var);
858 printf ("\n");
859 }
ccc6cda3 860#if defined (ARRAY_VARS)
7117c2d2 861 else if (array_p (var))
ccc6cda3
JA
862 print_array_assignment (var, 0);
863#endif /* ARRAY_VARS */
7117c2d2 864 else
726f6388
JA
865 {
866 printf ("%s=", var->name);
ccc6cda3 867 print_var_value (var, 1);
726f6388
JA
868 printf ("\n");
869 }
870}
871
872/* Print the value cell of VAR, a shell variable. Do not print
ccc6cda3
JA
873 the name, nor leading/trailing newline. If QUOTE is non-zero,
874 and the value contains shell metacharacters, quote the value
875 in such a way that it can be read back in. */
726f6388 876void
ccc6cda3 877print_var_value (var, quote)
726f6388 878 SHELL_VAR *var;
ccc6cda3 879 int quote;
726f6388 880{
ccc6cda3
JA
881 char *t;
882
7117c2d2
JA
883 if (var_isset (var) == 0)
884 return;
885
886 if (quote && posixly_correct == 0 && ansic_shouldquote (value_cell (var)))
ccc6cda3 887 {
7117c2d2
JA
888 t = ansic_quote (value_cell (var), 0, (int *)0);
889 printf ("%s", t);
890 free (t);
891 }
892 else if (quote && sh_contains_shell_metas (value_cell (var)))
893 {
894 t = sh_single_quote (value_cell (var));
895 printf ("%s", t);
896 free (t);
ccc6cda3 897 }
7117c2d2
JA
898 else
899 printf ("%s", value_cell (var));
726f6388
JA
900}
901
902/* Print the function cell of VAR, a shell variable. Do not
903 print the name, nor leading/trailing newline. */
904void
905print_var_function (var)
906 SHELL_VAR *var;
907{
7117c2d2 908 if (function_p (var) && var_isset (var))
726f6388
JA
909 printf ("%s", named_function_string ((char *)NULL, function_cell(var), 1));
910}
911
912/* **************************************************************** */
ccc6cda3 913/* */
7117c2d2 914/* Dynamic Variables */
ccc6cda3 915/* */
726f6388
JA
916/* **************************************************************** */
917
918/* DYNAMIC VARIABLES
ccc6cda3 919
726f6388
JA
920 These are variables whose values are generated anew each time they are
921 referenced. These are implemented using a pair of function pointers
7117c2d2
JA
922 in the struct variable: assign_func, which is called from bind_variable
923 and, if arrays are compiled into the shell, some of the functions in
924 arrayfunc.c, and dynamic_value, which is called from find_variable.
925
926 assign_func is called from bind_variable_internal, if
927 bind_variable_internal discovers that the variable being assigned to
928 has such a function. The function is called as
929 SHELL_VAR *temp = (*(entry->assign_func)) (entry, value, ind)
726f6388 930 and the (SHELL_VAR *)temp is returned as the value of bind_variable. It
7117c2d2
JA
931 is usually ENTRY (self). IND is an index for an array variable, and
932 unused otherwise.
ccc6cda3 933
7117c2d2
JA
934 dynamic_value is called from find_variable_internal to return a `new'
935 value for the specified dynamic varible. If this function is NULL,
936 the variable is treated as a `normal' shell variable. If it is not,
937 however, then this function is called like this:
938 tempvar = (*(var->dynamic_value)) (var);
ccc6cda3 939
726f6388
JA
940 Sometimes `tempvar' will replace the value of `var'. Other times, the
941 shell will simply use the string value. Pretty object-oriented, huh?
ccc6cda3 942
726f6388
JA
943 Be warned, though: if you `unset' a special variable, it loses its
944 special meaning, even if you subsequently set it.
ccc6cda3 945
726f6388 946 The special assignment code would probably have been better put in
7117c2d2 947 subst.c: do_assignment_internal, in the same style as
726f6388
JA
948 stupidly_hack_special_variables, but I wanted the changes as
949 localized as possible. */
950
f73dda09
JA
951#define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \
952 do \
953 { \
954 v = bind_variable (var, (val)); \
955 v->dynamic_value = gfunc; \
956 v->assign_func = afunc; \
957 } \
958 while (0)
959
960#define INIT_DYNAMIC_ARRAY_VAR(var, gfunc, afunc) \
961 do \
962 { \
963 v = make_new_array_variable (var); \
964 v->dynamic_value = gfunc; \
965 v->assign_func = afunc; \
966 } \
967 while (0)
968
bb70624e 969static SHELL_VAR *
7117c2d2 970null_assign (self, value, unused)
bb70624e
JA
971 SHELL_VAR *self;
972 char *value;
7117c2d2 973 arrayind_t unused;
bb70624e
JA
974{
975 return (self);
976}
977
978#if defined (ARRAY_VARS)
979static SHELL_VAR *
7117c2d2 980null_array_assign (self, value, ind)
bb70624e 981 SHELL_VAR *self;
bb70624e 982 char *value;
7117c2d2 983 arrayind_t ind;
bb70624e
JA
984{
985 return (self);
986}
987#endif
988
726f6388
JA
989/* The value of $SECONDS. This is the number of seconds since shell
990 invocation, or, the number of seconds since the last assignment + the
991 value of the last assignment. */
7117c2d2 992static intmax_t seconds_value_assigned;
726f6388
JA
993
994static SHELL_VAR *
7117c2d2 995assign_seconds (self, value, unused)
726f6388
JA
996 SHELL_VAR *self;
997 char *value;
7117c2d2 998 arrayind_t unused;
726f6388 999{
f73dda09
JA
1000 if (legal_number (value, &seconds_value_assigned) == 0)
1001 seconds_value_assigned = 0;
726f6388
JA
1002 shell_start_time = NOW;
1003 return (self);
1004}
1005
1006static SHELL_VAR *
1007get_seconds (var)
1008 SHELL_VAR *var;
1009{
1010 time_t time_since_start;
1011 char *p;
1012
1013 time_since_start = NOW - shell_start_time;
f73dda09 1014 p = itos(seconds_value_assigned + time_since_start);
726f6388 1015
7117c2d2 1016 FREE (value_cell (var));
726f6388 1017
bb70624e 1018 VSETATTR (var, att_integer);
7117c2d2 1019 var_setvalue (var, p);
726f6388
JA
1020 return (var);
1021}
1022
f73dda09
JA
1023static SHELL_VAR *
1024init_seconds_var ()
1025{
1026 SHELL_VAR *v;
1027
1028 v = find_variable ("SECONDS");
1029 if (v)
1030 {
1031 if (legal_number (value_cell(v), &seconds_value_assigned) == 0)
1032 seconds_value_assigned = 0;
1033 }
7117c2d2 1034 INIT_DYNAMIC_VAR ("SECONDS", (v ? value_cell (v) : (char *)NULL), get_seconds, assign_seconds);
f73dda09
JA
1035 return v;
1036}
1037
726f6388
JA
1038/* The random number seed. You can change this by setting RANDOM. */
1039static unsigned long rseed = 1;
f73dda09 1040static int last_random_value;
726f6388 1041
f73dda09 1042/* A linear congruential random number generator based on the example
7117c2d2 1043 one in the ANSI C standard. This one isn't very good, but a more
f73dda09 1044 complicated one is overkill. */
726f6388
JA
1045
1046/* Returns a pseudo-random number between 0 and 32767. */
1047static int
1048brand ()
1049{
1050 rseed = rseed * 1103515245 + 12345;
f73dda09 1051 return ((unsigned int)((rseed >> 16) & 32767)); /* was % 32768 */
726f6388
JA
1052}
1053
1054/* Set the random number generator seed to SEED. */
1055static void
1056sbrand (seed)
f73dda09 1057 unsigned long seed;
726f6388
JA
1058{
1059 rseed = seed;
e8ce775d 1060 last_random_value = 0;
726f6388
JA
1061}
1062
1063static SHELL_VAR *
7117c2d2 1064assign_random (self, value, unused)
726f6388
JA
1065 SHELL_VAR *self;
1066 char *value;
7117c2d2 1067 arrayind_t unused;
726f6388 1068{
f73dda09 1069 sbrand (strtoul (value, (char **)NULL, 10));
726f6388
JA
1070 return (self);
1071}
1072
28ef6c31
JA
1073int
1074get_random_number ()
726f6388
JA
1075{
1076 int rv;
726f6388 1077
ccc6cda3
JA
1078 /* Reset for command and process substitution. */
1079 if (subshell_environment)
f73dda09 1080 sbrand (rseed + getpid() + NOW);
ccc6cda3
JA
1081
1082 do
1083 rv = brand ();
f73dda09 1084 while (rv == last_random_value);
28ef6c31
JA
1085 return rv;
1086}
ccc6cda3 1087
28ef6c31
JA
1088static SHELL_VAR *
1089get_random (var)
1090 SHELL_VAR *var;
1091{
1092 int rv;
1093 char *p;
1094
1095 rv = get_random_number ();
ccc6cda3 1096 last_random_value = rv;
f73dda09 1097 p = itos (rv);
726f6388 1098
7117c2d2 1099 FREE (value_cell (var));
726f6388 1100
bb70624e 1101 VSETATTR (var, att_integer);
7117c2d2 1102 var_setvalue (var, p);
726f6388
JA
1103 return (var);
1104}
1105
7117c2d2
JA
1106static SHELL_VAR *
1107assign_lineno (var, value, unused)
1108 SHELL_VAR *var;
1109 char *value;
1110 arrayind_t unused;
1111{
1112 intmax_t new_value;
1113
1114 if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0)
1115 new_value = 0;
1116 line_number = new_value;
1117 return var;
1118}
1119
726f6388
JA
1120/* Function which returns the current line number. */
1121static SHELL_VAR *
1122get_lineno (var)
1123 SHELL_VAR *var;
1124{
1125 char *p;
ccc6cda3 1126 int ln;
726f6388 1127
ccc6cda3
JA
1128 ln = executing_line_number ();
1129 p = itos (ln);
7117c2d2
JA
1130 FREE (value_cell (var));
1131 var_setvalue (var, p);
726f6388
JA
1132 return (var);
1133}
1134
1135#if defined (HISTORY)
1136static SHELL_VAR *
1137get_histcmd (var)
1138 SHELL_VAR *var;
1139{
1140 char *p;
1141
1142 p = itos (history_number ());
7117c2d2
JA
1143 FREE (value_cell (var));
1144 var_setvalue (var, p);
726f6388
JA
1145 return (var);
1146}
1147#endif
1148
ccc6cda3 1149#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
7117c2d2
JA
1150static SHELL_VAR *
1151assign_dirstack (self, value, ind)
1152 SHELL_VAR *self;
1153 char *value;
1154 arrayind_t ind;
1155{
1156 set_dirstack_element (ind, 1, value);
1157 return self;
1158}
1159
ccc6cda3
JA
1160static SHELL_VAR *
1161get_dirstack (self)
1162 SHELL_VAR *self;
1163{
1164 ARRAY *a;
1165 WORD_LIST *l;
1166
1167 l = get_directory_stack ();
7117c2d2
JA
1168 a = array_from_word_list (l);
1169 array_dispose (array_cell (self));
d166f048 1170 dispose_words (l);
7117c2d2 1171 var_setarray (self, a);
ccc6cda3
JA
1172 return self;
1173}
f73dda09
JA
1174
1175static SHELL_VAR *
1176init_dirstack_var ()
1177{
1178 SHELL_VAR *v;
1179
1180 v = find_variable ("DIRSTACK");
1181 if (v)
1182 return v;
1183 INIT_DYNAMIC_ARRAY_VAR ("DIRSTACK", get_dirstack, assign_dirstack);
1184 return v;
1185}
ccc6cda3
JA
1186#endif /* PUSHD AND POPD && ARRAY_VARS */
1187
d166f048
JA
1188#if defined (ARRAY_VARS)
1189/* We don't want to initialize the group set with a call to getgroups()
1190 unless we're asked to, but we only want to do it once. */
1191static SHELL_VAR *
1192get_groupset (self)
1193 SHELL_VAR *self;
1194{
1195 register int i;
1196 int ng;
1197 ARRAY *a;
1198 static char **group_set = (char **)NULL;
1199
1200 if (group_set == 0)
1201 {
1202 group_set = get_group_list (&ng);
1203 a = array_cell (self);
1204 for (i = 0; i < ng; i++)
7117c2d2 1205 array_insert (a, i, group_set[i]);
d166f048
JA
1206 }
1207 return (self);
1208}
f73dda09
JA
1209
1210static SHELL_VAR *
1211init_groups_var ()
1212{
1213 SHELL_VAR *v;
1214
1215 v = find_variable ("GROUPS");
1216 if (v)
1217 return (v);
1218 INIT_DYNAMIC_ARRAY_VAR ("GROUPS", get_groupset, null_array_assign);
1219 VSETATTR (v, att_noassign);
1220 return v;
1221}
d166f048 1222#endif /* ARRAY_VARS */
bb70624e
JA
1223
1224static SHELL_VAR *
1225get_funcname (self)
1226 SHELL_VAR *self;
1227{
7117c2d2 1228 char *t;
bb70624e
JA
1229 if (variable_context && this_shell_function)
1230 {
7117c2d2
JA
1231 FREE (value_cell (self));
1232 t = savestring (this_shell_function->name);
1233 var_setvalue (self, t);
bb70624e
JA
1234 }
1235 return (self);
1236}
1237
1238void
1239make_funcname_visible (on_or_off)
1240 int on_or_off;
726f6388
JA
1241{
1242 SHELL_VAR *v;
1243
bb70624e
JA
1244 v = find_variable ("FUNCNAME");
1245 if (v == 0 || v->dynamic_value == 0)
1246 return;
1247
1248 if (on_or_off)
1249 VUNSETATTR (v, att_invisible);
1250 else
1251 VSETATTR (v, att_invisible);
1252}
1253
f73dda09
JA
1254static SHELL_VAR *
1255init_funcname_var ()
1256{
1257 SHELL_VAR *v;
bb70624e 1258
f73dda09
JA
1259 v = find_variable ("FUNCNAME");
1260 if (v)
1261 return v;
1262 INIT_DYNAMIC_VAR ("FUNCNAME", (char *)NULL, get_funcname, null_assign);
1263 VSETATTR (v, att_invisible|att_noassign);
1264 return v;
1265}
726f6388 1266
bb70624e
JA
1267static void
1268initialize_dynamic_variables ()
1269{
1270 SHELL_VAR *v;
726f6388 1271
f73dda09
JA
1272 v = init_seconds_var ();
1273
bb70624e
JA
1274 INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random);
1275 INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno);
726f6388
JA
1276
1277#if defined (HISTORY)
7117c2d2 1278 INIT_DYNAMIC_VAR ("HISTCMD", (char *)NULL, get_histcmd, (sh_var_assign_func_t *)NULL);
726f6388 1279#endif
ccc6cda3
JA
1280
1281#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
f73dda09 1282 v = init_dirstack_var ();
ccc6cda3 1283#endif /* PUSHD_AND_POPD && ARRAY_VARS */
d166f048
JA
1284
1285#if defined (ARRAY_VARS)
f73dda09 1286 v = init_groups_var ();
d166f048 1287#endif
bb70624e 1288
f73dda09 1289 v = init_funcname_var ();
726f6388
JA
1290}
1291
7117c2d2
JA
1292/* **************************************************************** */
1293/* */
1294/* Retrieving variables and values */
1295/* */
1296/* **************************************************************** */
1297
726f6388
JA
1298/* How to get a pointer to the shell variable or function named NAME.
1299 HASHED_VARS is a pointer to the hash table containing the list
1300 of interest (either variables or functions). */
7117c2d2
JA
1301
1302static SHELL_VAR *
1303hash_lookup (name, hashed_vars)
f73dda09 1304 const char *name;
726f6388
JA
1305 HASH_TABLE *hashed_vars;
1306{
1307 BUCKET_CONTENTS *bucket;
1308
7117c2d2 1309 bucket = hash_search (name, hashed_vars, 0);
ccc6cda3 1310 return (bucket ? (SHELL_VAR *)bucket->data : (SHELL_VAR *)NULL);
726f6388
JA
1311}
1312
7117c2d2
JA
1313SHELL_VAR *
1314var_lookup (name, vcontext)
1315 const char *name;
1316 VAR_CONTEXT *vcontext;
1317{
1318 VAR_CONTEXT *vc;
1319 SHELL_VAR *v;
1320
1321 v = (SHELL_VAR *)NULL;
1322 for (vc = vcontext; vc; vc = vc->down)
1323 if (v = hash_lookup (name, vc->table))
1324 break;
1325
1326 return v;
1327}
1328
726f6388 1329/* Look up the variable entry named NAME. If SEARCH_TEMPENV is non-zero,
7117c2d2
JA
1330 then also search the temporarily built list of exported variables.
1331 The lookup order is:
1332 temporary_env
1333 shell_variables list
1334*/
1335
726f6388
JA
1336SHELL_VAR *
1337find_variable_internal (name, search_tempenv)
f73dda09 1338 const char *name;
726f6388
JA
1339 int search_tempenv;
1340{
28ef6c31
JA
1341 SHELL_VAR *var;
1342
1343 var = (SHELL_VAR *)NULL;
726f6388
JA
1344
1345 /* If explicitly requested, first look in the temporary environment for
1346 the variable. This allows constructs such as "foo=x eval 'echo $foo'"
1347 to get the `exported' value of $foo. This happens if we are executing
1348 a function or builtin, or if we are looking up a variable in a
1349 "subshell environment". */
7117c2d2
JA
1350 if ((search_tempenv || subshell_environment) && temporary_env)
1351 var = hash_lookup (name, temporary_env);
726f6388 1352
7117c2d2 1353 if (var == 0)
726f6388
JA
1354 var = var_lookup (name, shell_variables);
1355
7117c2d2 1356 if (var == 0)
726f6388
JA
1357 return ((SHELL_VAR *)NULL);
1358
ccc6cda3 1359 return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
726f6388
JA
1360}
1361
1362/* Look up the variable entry named NAME. Returns the entry or NULL. */
1363SHELL_VAR *
1364find_variable (name)
f73dda09 1365 const char *name;
726f6388 1366{
7117c2d2 1367 return (find_variable_internal (name, this_shell_builtin != 0));
726f6388
JA
1368}
1369
1370/* Look up the function entry whose name matches STRING.
1371 Returns the entry or NULL. */
1372SHELL_VAR *
1373find_function (name)
f73dda09 1374 const char *name;
726f6388 1375{
7117c2d2
JA
1376 return (hash_lookup (name, shell_functions));
1377}
1378
1379/* Return the value of VAR. VAR is assumed to have been the result of a
1380 lookup without any subscript, if arrays are compiled into the shell. */
1381char *
1382get_variable_value (var)
1383 SHELL_VAR *var;
1384{
1385 if (var == 0)
1386 return ((char *)NULL);
1387#if defined (ARRAY_VARS)
1388 else if (array_p (var))
1389 return (array_reference (array_cell (var), 0));
1390#endif
1391 else
1392 return (value_cell (var));
726f6388
JA
1393}
1394
1395/* Return the string value of a variable. Return NULL if the variable
7117c2d2
JA
1396 doesn't exist. Don't cons a new string. This is a potential memory
1397 leak if the variable is found in the temporary environment. Since
1398 functions and variables have separate name spaces, returns NULL if
1399 var_name is a shell function only. */
726f6388
JA
1400char *
1401get_string_value (var_name)
28ef6c31 1402 const char *var_name;
726f6388 1403{
d166f048
JA
1404 SHELL_VAR *var;
1405
f73dda09 1406 var = find_variable (var_name);
7117c2d2 1407 return ((var) ? get_variable_value (var) : (char *)NULL);
726f6388
JA
1408}
1409
b72432fd
JA
1410/* This is present for use by the tilde and readline libraries. */
1411char *
28ef6c31
JA
1412sh_get_env_value (v)
1413 const char *v;
b72432fd
JA
1414{
1415 return get_string_value (v);
1416}
1417
7117c2d2
JA
1418/* **************************************************************** */
1419/* */
1420/* Creating and setting variables */
1421/* */
1422/* **************************************************************** */
1423
1424/* Set NAME to VALUE if NAME has no value. */
1425SHELL_VAR *
1426set_if_not (name, value)
1427 char *name, *value;
1428{
1429 SHELL_VAR *v;
1430
1431 v = find_variable (name);
1432 if (v == 0)
1433 v = bind_variable_internal (name, value, global_variables->table, HASH_NOSRCH);
1434 return (v);
1435}
1436
726f6388
JA
1437/* Create a local variable referenced by NAME. */
1438SHELL_VAR *
1439make_local_variable (name)
f73dda09 1440 const char *name;
726f6388
JA
1441{
1442 SHELL_VAR *new_var, *old_var;
7117c2d2
JA
1443 VAR_CONTEXT *vc;
1444 int was_tmpvar;
1445 char *tmp_value;
726f6388
JA
1446
1447 /* local foo; local foo; is a no-op. */
1448 old_var = find_variable (name);
7117c2d2 1449 if (old_var && local_p (old_var) && old_var->context == variable_context)
726f6388
JA
1450 return (old_var);
1451
7117c2d2
JA
1452 was_tmpvar = old_var && tempvar_p (old_var);
1453 if (was_tmpvar)
1454 tmp_value = value_cell (old_var);
1455
1456 for (vc = shell_variables; vc; vc = vc->down)
1457 if (vc_isfuncenv (vc) && vc->scope == variable_context)
1458 break;
1459
1460 if (vc == 0)
1461 {
1462 internal_error ("make_local_variable: no function context at current scope found");
1463 return ((SHELL_VAR *)NULL);
1464 }
1465 else if (vc->table == 0)
1466 vc->table = hash_create (TEMPENV_HASH_BUCKETS);
1467
bb70624e
JA
1468 /* Since this is called only from the local/declare/typeset code, we can
1469 call builtin_error here without worry (of course, it will also work
28ef6c31
JA
1470 for anything that sets this_command_name). Variables with the `noassign'
1471 attribute may not be made local. The test against old_var's context
1472 level is to disallow local copies of readonly global variables (since I
1473 believe that this could be a security hole). Readonly copies of calling
1474 function local variables are OK. */
1475 if (old_var && (noassign_p (old_var) ||
1476 (readonly_p (old_var) && old_var->context == 0)))
1477 {
1478 if (readonly_p (old_var))
7117c2d2 1479 sh_readonly (name);
bb70624e
JA
1480 return ((SHELL_VAR *)NULL);
1481 }
1482
d166f048 1483 if (old_var == 0)
7117c2d2 1484 new_var = bind_variable_internal (name, "", vc->table, HASH_NOSRCH);
726f6388
JA
1485 else
1486 {
7117c2d2 1487 new_var = make_new_variable (name, vc->table);
726f6388 1488
7117c2d2
JA
1489 /* If we found this variable in one of the temporary environments,
1490 inherit its value. Watch to see if this causes problems with
1491 things like `x=4 local x'. */
1492 if (was_tmpvar)
1493 var_setvalue (new_var, savestring (tmp_value));
726f6388 1494
ccc6cda3 1495 new_var->attributes = exported_p (old_var) ? att_exported : 0;
726f6388
JA
1496 }
1497
7117c2d2
JA
1498 vc->flags |= VC_HASLOCAL;
1499
726f6388 1500 new_var->context = variable_context;
bb70624e 1501 VSETATTR (new_var, att_local);
726f6388 1502
7117c2d2
JA
1503 if (ifsname (name))
1504 setifs (new_var);
726f6388
JA
1505
1506 return (new_var);
1507}
1508
ccc6cda3 1509#if defined (ARRAY_VARS)
726f6388 1510SHELL_VAR *
ccc6cda3
JA
1511make_local_array_variable (name)
1512 char *name;
1513{
1514 SHELL_VAR *var;
1515 ARRAY *array;
1516
1517 var = make_local_variable (name);
bb70624e
JA
1518 if (var == 0)
1519 return var;
7117c2d2 1520 array = array_create ();
ccc6cda3
JA
1521
1522 FREE (value_cell(var));
7117c2d2 1523 var_setarray (var, array);
bb70624e 1524 VSETATTR (var, att_array);
ccc6cda3
JA
1525 return var;
1526}
1527#endif /* ARRAY_VARS */
1528
7117c2d2 1529/* Create a new shell variable with name NAME. */
f73dda09 1530static SHELL_VAR *
7117c2d2 1531new_shell_variable (name)
f73dda09 1532 const char *name;
726f6388 1533{
ccc6cda3 1534 SHELL_VAR *entry;
726f6388 1535
ccc6cda3 1536 entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
726f6388 1537
ccc6cda3 1538 entry->name = savestring (name);
7117c2d2 1539 var_setvalue (entry, (char *)NULL);
bb70624e 1540 CLEAR_EXPORTSTR (entry);
726f6388 1541
7117c2d2
JA
1542 entry->dynamic_value = (sh_var_value_func_t *)NULL;
1543 entry->assign_func = (sh_var_assign_func_t *)NULL;
1544
1545 entry->attributes = 0;
ccc6cda3
JA
1546
1547 /* Always assume variables are to be made at toplevel!
1548 make_local_variable has the responsibilty of changing the
1549 variable context. */
1550 entry->context = 0;
7117c2d2
JA
1551
1552 return (entry);
1553}
1554
1555/* Create a new shell variable with name NAME and add it to the hash table
1556 TABLE. */
1557static SHELL_VAR *
1558make_new_variable (name, table)
1559 const char *name;
1560 HASH_TABLE *table;
1561{
1562 SHELL_VAR *entry;
1563 BUCKET_CONTENTS *elt;
1564
1565 entry = new_shell_variable (name);
ccc6cda3 1566
28ef6c31
JA
1567 /* Make sure we have a shell_variables hash table to add to. */
1568 if (shell_variables == 0)
7117c2d2
JA
1569 {
1570 shell_variables = global_variables = new_var_context ((char *)NULL, 0);
1571 shell_variables->scope = 0;
1572 shell_variables->table = hash_create (0);
1573 }
28ef6c31 1574
7117c2d2
JA
1575 elt = hash_insert (savestring (name), table, HASH_NOSRCH);
1576 elt->data = (PTR_T)entry;
ccc6cda3
JA
1577
1578 return entry;
1579}
1580
1581#if defined (ARRAY_VARS)
1582SHELL_VAR *
1583make_new_array_variable (name)
1584 char *name;
1585{
1586 SHELL_VAR *entry;
1587 ARRAY *array;
1588
7117c2d2
JA
1589 entry = make_new_variable (name, global_variables->table);
1590 array = array_create ();
1591 var_setarray (entry, array);
bb70624e 1592 VSETATTR (entry, att_array);
ccc6cda3
JA
1593 return entry;
1594}
1595#endif
1596
1597char *
1598make_variable_value (var, value)
1599 SHELL_VAR *var;
1600 char *value;
1601{
1602 char *retval;
7117c2d2 1603 intmax_t lval;
d166f048 1604 int expok;
ccc6cda3
JA
1605
1606 /* If this variable has had its type set to integer (via `declare -i'),
1607 then do expression evaluation on it and store the result. The
7117c2d2 1608 functions in expr.c (evalexp()) and bind_int_variable() are responsible
ccc6cda3
JA
1609 for turning off the integer flag if they don't want further
1610 evaluation done. */
1611 if (integer_p (var))
1612 {
d166f048
JA
1613 lval = evalexp (value, &expok);
1614 if (expok == 0)
1615 jump_to_top_level (DISCARD);
ccc6cda3
JA
1616 retval = itos (lval);
1617 }
1618 else if (value)
1619 {
1620 if (*value)
1621 retval = savestring (value);
1622 else
726f6388 1623 {
f73dda09 1624 retval = (char *)xmalloc (1);
ccc6cda3 1625 retval[0] = '\0';
726f6388 1626 }
ccc6cda3
JA
1627 }
1628 else
1629 retval = (char *)NULL;
726f6388 1630
ccc6cda3
JA
1631 return retval;
1632}
726f6388 1633
7117c2d2
JA
1634/* Bind a variable NAME to VALUE in the HASH_TABLE TABLE, which may be the
1635 temporary environment (but usually is not). */
1636static SHELL_VAR *
1637bind_variable_internal (name, value, table, hflags)
f73dda09
JA
1638 const char *name;
1639 char *value;
7117c2d2
JA
1640 HASH_TABLE *table;
1641 int hflags;
ccc6cda3
JA
1642{
1643 char *newval;
7117c2d2 1644 SHELL_VAR *entry;
28ef6c31 1645
7117c2d2 1646 entry = (hflags & HASH_NOSRCH) ? (SHELL_VAR *)NULL : hash_lookup (name, table);
ccc6cda3
JA
1647
1648 if (entry == 0)
1649 {
7117c2d2
JA
1650 entry = make_new_variable (name, table);
1651 var_setvalue (entry, make_variable_value (entry, value));
726f6388 1652 }
28ef6c31 1653 else if (entry->assign_func) /* array vars have assign functions now */
bb70624e
JA
1654 {
1655 INVALIDATE_EXPORTSTR (entry);
7117c2d2 1656 return ((*(entry->assign_func)) (entry, value, -1));
bb70624e 1657 }
726f6388
JA
1658 else
1659 {
28ef6c31 1660 if (readonly_p (entry) || noassign_p (entry))
726f6388 1661 {
28ef6c31 1662 if (readonly_p (entry))
7117c2d2 1663 err_readonly (name);
726f6388
JA
1664 return (entry);
1665 }
1666
1667 /* Variables which are bound are visible. */
bb70624e 1668 VUNSETATTR (entry, att_invisible);
726f6388 1669
ccc6cda3 1670 newval = make_variable_value (entry, value);
726f6388 1671
bb70624e
JA
1672 /* Invalidate any cached export string */
1673 INVALIDATE_EXPORTSTR (entry);
1674
ccc6cda3
JA
1675#if defined (ARRAY_VARS)
1676 /* XXX -- this bears looking at again -- XXX */
1677 /* If an existing array variable x is being assigned to with x=b or
1678 `read x' or something of that nature, silently convert it to
1679 x[0]=b or `read x[0]'. */
1680 if (array_p (entry))
d166f048 1681 {
7117c2d2 1682 array_insert (array_cell (entry), 0, newval);
d166f048
JA
1683 free (newval);
1684 }
726f6388 1685 else
f73dda09 1686#endif
726f6388 1687 {
7117c2d2
JA
1688 FREE (value_cell (entry));
1689 var_setvalue (entry, newval);
726f6388
JA
1690 }
1691 }
1692
1693 if (mark_modified_vars)
bb70624e 1694 VSETATTR (entry, att_exported);
726f6388
JA
1695
1696 if (exported_p (entry))
1697 array_needs_making = 1;
1698
1699 return (entry);
1700}
7117c2d2
JA
1701
1702/* Bind a variable NAME to VALUE. This conses up the name
1703 and value strings. If we have a temporary environment, we bind there
1704 first, then we bind into shell_variables. */
1705
1706SHELL_VAR *
1707bind_variable (name, value)
1708 const char *name;
1709 char *value;
1710{
1711 SHELL_VAR *v;
1712 VAR_CONTEXT *vc;
1713
1714 if (shell_variables == 0)
1715 {
1716 shell_variables = global_variables = new_var_context ((char *)NULL, 0);
1717 shell_variables->scope = 0;
1718 shell_variables->table = hash_create (0);
1719 }
1720
1721 /* If we have a temporary environment, look there first for the variable,
1722 and, if found, modify the value there before modifying it in the
1723 shell_variables table. This allows sourced scripts to modify values
1724 given to them in a temporary environment while modifying the variable
1725 value that the caller sees. */
1726 if (temporary_env)
1727 bind_tempenv_variable (name, value);
1728
1729 /* XXX -- handle local variables here. */
1730 for (vc = shell_variables; vc; vc = vc->down)
1731 {
1732 if (vc_isfuncenv (vc) || vc_isbltnenv (vc))
1733 {
1734 v = hash_lookup (name, vc->table);
1735 if (v)
1736 return (bind_variable_internal (name, value, vc->table, 0));
1737 }
1738 }
1739 return (bind_variable_internal (name, value, global_variables->table, 0));
1740}
726f6388 1741
bb70624e
JA
1742/* Make VAR, a simple shell variable, have value VALUE. Once assigned a
1743 value, variables are no longer invisible. This is a duplicate of part
1744 of the internals of bind_variable. If the variable is exported, or
1745 all modified variables should be exported, mark the variable for export
1746 and note that the export environment needs to be recreated. */
1747SHELL_VAR *
1748bind_variable_value (var, value)
1749 SHELL_VAR *var;
1750 char *value;
1751{
1752 char *t;
1753
1754 VUNSETATTR (var, att_invisible);
1755
1756 t = make_variable_value (var, value);
7117c2d2
JA
1757 FREE (value_cell (var));
1758 var_setvalue (var, t);
bb70624e
JA
1759
1760 INVALIDATE_EXPORTSTR (var);
1761
1762 if (mark_modified_vars)
1763 VSETATTR (var, att_exported);
1764
1765 if (exported_p (var))
1766 array_needs_making = 1;
1767
1768 return (var);
1769}
1770
1771/* Bind/create a shell variable with the name LHS to the RHS.
1772 This creates or modifies a variable such that it is an integer.
1773
1774 This used to be in expr.c, but it is here so that all of the
1775 variable binding stuff is localized. Since we don't want any
1776 recursive evaluation from bind_variable() (possible without this code,
1777 since bind_variable() calls the evaluator for variables with the integer
1778 attribute set), we temporarily turn off the integer attribute for each
1779 variable we set here, then turn it back on after binding as necessary. */
1780
1781SHELL_VAR *
1782bind_int_variable (lhs, rhs)
1783 char *lhs, *rhs;
1784{
1785 register SHELL_VAR *v;
7117c2d2
JA
1786 char *t;
1787 int isint, isarr;
1788
1789 isint = isarr = 0;
1790#if defined (ARRAY_VARS)
1791 if (t = xstrchr (lhs, '[')) /*]*/
1792 {
1793 isarr = 1;
1794 v = array_variable_part (lhs, (char **)0, (int *)0);
1795 }
1796 else
1797#endif
1798 v = find_variable (lhs);
bb70624e 1799
bb70624e
JA
1800 if (v)
1801 {
1802 isint = integer_p (v);
1803 VUNSETATTR (v, att_integer);
1804 }
1805
7117c2d2
JA
1806#if defined (ARRAY_VARS)
1807 if (isarr)
1808 v = assign_array_element (lhs, rhs);
1809 else
1810#endif
1811 v = bind_variable (lhs, rhs);
1812
bb70624e
JA
1813 if (isint)
1814 VSETATTR (v, att_integer);
1815
1816 return (v);
1817}
1818
ccc6cda3 1819SHELL_VAR *
f73dda09
JA
1820bind_var_to_int (var, val)
1821 char *var;
7117c2d2 1822 intmax_t val;
ccc6cda3 1823{
7117c2d2 1824 char ibuf[INT_STRLEN_BOUND (intmax_t) + 1], *p;
ccc6cda3 1825
f73dda09
JA
1826 p = fmtulong (val, 10, ibuf, sizeof (ibuf), 0);
1827 return (bind_int_variable (var, p));
ccc6cda3
JA
1828}
1829
7117c2d2
JA
1830/* Do a function binding to a variable. You pass the name and
1831 the command to bind to. This conses the name and command. */
1832SHELL_VAR *
1833bind_function (name, value)
1834 const char *name;
1835 COMMAND *value;
1836{
1837 SHELL_VAR *entry;
1838
1839 entry = find_function (name);
1840 if (entry == 0)
1841 {
1842 BUCKET_CONTENTS *elt;
1843
1844 elt = hash_insert (savestring (name), shell_functions, HASH_NOSRCH);
1845 entry = new_shell_variable (name);
1846 elt->data = (PTR_T)entry;
1847 }
1848 else
1849 INVALIDATE_EXPORTSTR (entry);
1850
1851 if (var_isset (entry))
1852 dispose_command (function_cell (entry));
1853
1854 if (value)
1855 var_setfunc (entry, copy_command (value));
1856 else
1857 var_setfunc (entry, 0);
1858
1859 VSETATTR (entry, att_function);
1860
1861 if (mark_modified_vars)
1862 VSETATTR (entry, att_exported);
1863
1864 VUNSETATTR (entry, att_invisible); /* Just to be sure */
1865
1866 if (exported_p (entry))
1867 array_needs_making = 1;
1868
1869#if defined (PROGRAMMABLE_COMPLETION)
1870 set_itemlist_dirty (&it_functions);
1871#endif
1872
1873 return (entry);
1874}
1875
1876/* Add STRING, which is of the form foo=bar, to the temporary environment
1877 HASH_TABLE (temporary_env). The functions in execute_cmd.c are
1878 responsible for moving the main temporary env to one of the other
1879 temporary environments. The expansion code in subst.c calls this. */
1880int
1881assign_in_env (string)
1882 const char *string;
1883{
1884 int offset;
1885 char *name, *temp, *value;
1886 SHELL_VAR *var;
1887
1888 offset = assignment (string);
1889 name = savestring (string);
1890 value = (char *)NULL;
1891
1892 if (name[offset] == '=')
1893 {
1894 name[offset] = 0;
1895
1896 var = find_variable (name);
1897 if (var && (readonly_p (var) || noassign_p (var)))
1898 {
1899 if (readonly_p (var))
1900 err_readonly (name);
1901 free (name);
1902 return (0);
1903 }
1904
1905 temp = name + offset + 1;
1906 temp = (xstrchr (temp, '~') != 0) ? bash_tilde_expand (temp, 1) : savestring (temp);
1907
1908 value = expand_string_unsplit_to_string (temp, 0);
1909 free (temp);
1910 }
1911
1912 if (temporary_env == 0)
1913 temporary_env = hash_create (TEMPENV_HASH_BUCKETS);
1914
1915 var = hash_lookup (name, temporary_env);
1916 if (var == 0)
1917 var = make_new_variable (name, temporary_env);
1918 else
1919 FREE (value_cell (var));
1920
1921 if (value == 0)
1922 {
1923 value = (char *)xmalloc (1); /* like do_assignment_internal */
1924 value[0] = '\0';
1925 }
1926
1927 var_setvalue (var, value);
1928 var->attributes |= (att_exported|att_tempvar);
1929 var->context = variable_context; /* XXX */
1930
1931 INVALIDATE_EXPORTSTR (var);
1932 var->exportstr = mk_env_string (name, value);
1933
1934 array_needs_making = 1;
1935
1936 if (ifsname (name))
1937 setifs (var);
1938
1939 if (echo_command_at_execute)
1940 {
1941 /* The Korn shell prints the `+ ' in front of assignment statements,
1942 so we do too. */
1943 fprintf (stderr, "%s%s=%s\n", indirection_level_string (), name, value);
1944 fflush (stderr);
1945 }
1946
1947 return 1;
1948}
1949
1950/* **************************************************************** */
1951/* */
1952/* Copying variables */
1953/* */
1954/* **************************************************************** */
1955
1956#ifdef INCLUDE_UNUSED
1957/* Copy VAR to a new data structure and return that structure. */
1958SHELL_VAR *
1959copy_variable (var)
1960 SHELL_VAR *var;
1961{
1962 SHELL_VAR *copy = (SHELL_VAR *)NULL;
1963
1964 if (var)
1965 {
1966 copy = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
1967
1968 copy->attributes = var->attributes;
1969 copy->name = savestring (var->name);
1970
1971 if (function_p (var))
1972 var_setfunc (copy, copy_command (function_cell (var)));
1973#if defined (ARRAY_VARS)
1974 else if (array_p (var))
1975 var_setarray (copy, dup_array (array_cell (var)));
1976#endif
1977 else if (value_cell (var))
1978 var_setvalue (copy, savestring (value_cell (var)));
1979 else
1980 var_setvalue (copy, (char *)NULL);
1981
1982 copy->dynamic_value = var->dynamic_value;
1983 copy->assign_func = var->assign_func;
1984
1985 copy->exportstr = COPY_EXPORTSTR (var);
1986
1987 copy->context = var->context;
1988 }
1989 return (copy);
1990}
1991#endif
1992
1993/* **************************************************************** */
1994/* */
1995/* Deleting and unsetting variables */
1996/* */
1997/* **************************************************************** */
1998
726f6388
JA
1999/* Dispose of the information attached to VAR. */
2000void
2001dispose_variable (var)
2002 SHELL_VAR *var;
2003{
7117c2d2 2004 if (var == 0)
726f6388
JA
2005 return;
2006
2007 if (function_p (var))
ccc6cda3
JA
2008 dispose_command (function_cell (var));
2009#if defined (ARRAY_VARS)
2010 else if (array_p (var))
7117c2d2 2011 array_dispose (array_cell (var));
ccc6cda3
JA
2012#endif
2013 else
2014 FREE (value_cell (var));
726f6388 2015
bb70624e
JA
2016 FREE_EXPORTSTR (var);
2017
726f6388
JA
2018 free (var->name);
2019
2020 if (exported_p (var))
2021 array_needs_making = 1;
2022
2023 free (var);
2024}
2025
7117c2d2 2026/* Unset the shell variable referenced by NAME. */
ccc6cda3 2027int
726f6388 2028unbind_variable (name)
f73dda09 2029 const char *name;
726f6388 2030{
7117c2d2
JA
2031 return makunbound (name, shell_variables);
2032}
726f6388 2033
7117c2d2
JA
2034/* Unset the shell function named NAME. */
2035int
2036unbind_func (name)
2037 const char *name;
2038{
2039 BUCKET_CONTENTS *elt;
2040 SHELL_VAR *func;
726f6388 2041
7117c2d2
JA
2042 elt = hash_remove (name, shell_functions, 0);
2043
2044 if (elt == 0)
2045 return -1;
2046
2047#if defined (PROGRAMMABLE_COMPLETION)
2048 set_itemlist_dirty (&it_functions);
ccc6cda3 2049#endif
7117c2d2
JA
2050
2051 func = (SHELL_VAR *)elt->data;
2052 if (func)
726f6388 2053 {
7117c2d2
JA
2054 if (exported_p (func))
2055 array_needs_making++;
2056 dispose_variable (func);
726f6388
JA
2057 }
2058
7117c2d2
JA
2059 free (elt->key);
2060 free (elt);
726f6388 2061
7117c2d2 2062 return 0;
726f6388
JA
2063}
2064
2065/* Make the variable associated with NAME go away. HASH_LIST is the
2066 hash table from which this variable should be deleted (either
2067 shell_variables or shell_functions).
2068 Returns non-zero if the variable couldn't be found. */
ccc6cda3 2069int
7117c2d2 2070makunbound (name, vc)
f73dda09 2071 const char *name;
7117c2d2 2072 VAR_CONTEXT *vc;
726f6388 2073{
d166f048 2074 BUCKET_CONTENTS *elt, *new_elt;
7117c2d2
JA
2075 SHELL_VAR *old_var;
2076 VAR_CONTEXT *v;
726f6388
JA
2077 char *t;
2078
7117c2d2
JA
2079 for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down)
2080 if (elt = hash_remove (name, v->table, 0))
2081 break;
726f6388 2082
d166f048 2083 if (elt == 0)
726f6388
JA
2084 return (-1);
2085
2086 old_var = (SHELL_VAR *)elt->data;
726f6388
JA
2087
2088 if (old_var && exported_p (old_var))
2089 array_needs_making++;
2090
ccc6cda3 2091 /* If we're unsetting a local variable and we're still executing inside
7117c2d2
JA
2092 the function, just mark the variable as invisible. The function
2093 eventually called by pop_var_context() will clean it up later. This
2094 must be done so that if the variable is subsequently assigned a new
2095 value inside the function, the `local' attribute is still present.
2096 We also need to add it back into the correct hash table. */
ccc6cda3
JA
2097 if (old_var && local_p (old_var) && variable_context == old_var->context)
2098 {
bb70624e 2099 VSETATTR (old_var, att_invisible);
7117c2d2
JA
2100 FREE (value_cell (old_var));
2101 var_setvalue (old_var, (char *)NULL);
bb70624e 2102 INVALIDATE_EXPORTSTR (old_var);
7117c2d2
JA
2103
2104 new_elt = hash_insert (savestring (old_var->name), v->table, 0);
2105 new_elt->data = (PTR_T)old_var;
ccc6cda3 2106 stupidly_hack_special_variables (old_var->name);
7117c2d2 2107
d166f048
JA
2108 free (elt->key);
2109 free (elt);
ccc6cda3
JA
2110 return (0);
2111 }
2112
726f6388
JA
2113 /* Have to save a copy of name here, because it might refer to
2114 old_var->name. If so, stupidly_hack_special_variables will
2115 reference freed memory. */
2116 t = savestring (name);
2117
2118 free (elt->key);
2119 free (elt);
2120
2121 dispose_variable (old_var);
2122 stupidly_hack_special_variables (t);
2123 free (t);
7117c2d2 2124
726f6388
JA
2125 return (0);
2126}
2127
7117c2d2
JA
2128/* Get rid of all of the variables in the current context. */
2129void
2130kill_all_local_variables ()
726f6388 2131{
7117c2d2
JA
2132 VAR_CONTEXT *vc;
2133
2134 for (vc = shell_variables; vc; vc = vc->down)
2135 if (vc_isfuncenv (vc) && vc->scope == variable_context)
2136 break;
2137 if (vc == 0)
2138 return; /* XXX */
726f6388 2139
7117c2d2 2140 if (vc->table && vc_haslocals (vc))
726f6388 2141 {
7117c2d2
JA
2142 delete_all_variables (vc->table);
2143 hash_dispose (vc->table);
726f6388 2144 }
7117c2d2 2145 vc->table = (HASH_TABLE *)NULL;
726f6388
JA
2146}
2147
ccc6cda3
JA
2148static void
2149free_variable_hash_data (data)
f73dda09 2150 PTR_T data;
ccc6cda3 2151{
7117c2d2 2152 SHELL_VAR *var;
ccc6cda3
JA
2153
2154 var = (SHELL_VAR *)data;
7117c2d2 2155 dispose_variable (var);
ccc6cda3
JA
2156}
2157
726f6388
JA
2158/* Delete the entire contents of the hash table. */
2159void
2160delete_all_variables (hashed_vars)
2161 HASH_TABLE *hashed_vars;
2162{
7117c2d2 2163 hash_flush (hashed_vars, free_variable_hash_data);
726f6388
JA
2164}
2165
7117c2d2
JA
2166/* **************************************************************** */
2167/* */
2168/* Setting variable attributes */
2169/* */
2170/* **************************************************************** */
726f6388 2171
ccc6cda3
JA
2172#define FIND_OR_MAKE_VARIABLE(name, entry) \
2173 do \
2174 { \
2175 entry = find_variable (name); \
2176 if (!entry) \
2177 { \
2178 entry = bind_variable (name, ""); \
2179 if (!no_invisible_vars) entry->attributes |= att_invisible; \
2180 } \
2181 } \
2182 while (0)
2183
2184/* Make the variable associated with NAME be readonly.
726f6388
JA
2185 If NAME does not exist yet, create it. */
2186void
2187set_var_read_only (name)
2188 char *name;
2189{
ccc6cda3 2190 SHELL_VAR *entry;
726f6388 2191
ccc6cda3 2192 FIND_OR_MAKE_VARIABLE (name, entry);
bb70624e 2193 VSETATTR (entry, att_readonly);
726f6388
JA
2194}
2195
cce855bc 2196#ifdef INCLUDE_UNUSED
ccc6cda3 2197/* Make the function associated with NAME be readonly.
726f6388
JA
2198 If NAME does not exist, we just punt, like auto_export code below. */
2199void
2200set_func_read_only (name)
f73dda09 2201 const char *name;
726f6388 2202{
d166f048 2203 SHELL_VAR *entry;
726f6388 2204
d166f048 2205 entry = find_function (name);
726f6388 2206 if (entry)
bb70624e 2207 VSETATTR (entry, att_readonly);
726f6388
JA
2208}
2209
2210/* Make the variable associated with NAME be auto-exported.
2211 If NAME does not exist yet, create it. */
2212void
2213set_var_auto_export (name)
2214 char *name;
2215{
ccc6cda3 2216 SHELL_VAR *entry;
726f6388 2217
ccc6cda3 2218 FIND_OR_MAKE_VARIABLE (name, entry);
726f6388
JA
2219 set_auto_export (entry);
2220}
2221
2222/* Make the function associated with NAME be auto-exported. */
2223void
2224set_func_auto_export (name)
f73dda09 2225 const char *name;
726f6388 2226{
ccc6cda3 2227 SHELL_VAR *entry;
726f6388 2228
ccc6cda3 2229 entry = find_function (name);
726f6388 2230 if (entry)
ccc6cda3
JA
2231 set_auto_export (entry);
2232}
cce855bc 2233#endif
ccc6cda3 2234
7117c2d2
JA
2235/* **************************************************************** */
2236/* */
2237/* Creating lists of variables */
2238/* */
2239/* **************************************************************** */
2240
2241static VARLIST *
2242vlist_alloc (nentries)
2243 int nentries;
726f6388 2244{
7117c2d2 2245 VARLIST *vlist;
726f6388 2246
7117c2d2
JA
2247 vlist = (VARLIST *)xmalloc (sizeof (VARLIST));
2248 vlist->list = (SHELL_VAR **)xmalloc ((nentries + 1) * sizeof (SHELL_VAR *));
2249 vlist->list_size = nentries;
2250 vlist->list_len = 0;
2251 vlist->list[0] = (SHELL_VAR *)NULL;
726f6388 2252
7117c2d2
JA
2253 return vlist;
2254}
726f6388 2255
7117c2d2
JA
2256static VARLIST *
2257vlist_realloc (vlist, n)
2258 VARLIST *vlist;
2259 int n;
2260{
2261 if (vlist == 0)
2262 return (vlist = vlist_alloc (n));
2263 if (n > vlist->list_size)
726f6388 2264 {
7117c2d2
JA
2265 vlist->list_size = n;
2266 vlist->list = (SHELL_VAR **)xrealloc (vlist->list, (vlist->list_size + 1) * sizeof (SHELL_VAR *));
2267 }
2268 return vlist;
2269}
726f6388 2270
7117c2d2
JA
2271static void
2272vlist_add (vlist, var, flags)
2273 VARLIST *vlist;
2274 SHELL_VAR *var;
2275 int flags;
2276{
2277 register int i;
ccc6cda3 2278
7117c2d2
JA
2279 for (i = 0; i < vlist->list_len; i++)
2280 if (STREQ (var->name, vlist->list[i]->name))
2281 break;
2282 if (i < vlist->list_len)
2283 return;
2284
2285 if (i >= vlist->list_size)
2286 vlist = vlist_realloc (vlist, vlist->list_size + 16);
726f6388 2287
7117c2d2
JA
2288 vlist->list[vlist->list_len++] = var;
2289 vlist->list[vlist->list_len] = (SHELL_VAR *)NULL;
2290}
2291
2292/* Map FUNCTION over the variables in VAR_HASH_TABLE. Return an array of the
2293 variables for which FUNCTION returns a non-zero value. A NULL value
2294 for FUNCTION means to use all variables. */
2295SHELL_VAR **
2296map_over (function, vc)
2297 sh_var_map_func_t *function;
2298 VAR_CONTEXT *vc;
2299{
2300 VAR_CONTEXT *v;
2301 VARLIST *vlist;
2302 SHELL_VAR **ret;
2303 int nentries;
2304
2305 for (nentries = 0, v = vc; v; v = v->down)
2306 nentries += HASH_ENTRIES (v->table);
2307
2308 if (nentries == 0)
2309 return (SHELL_VAR **)NULL;
2310
2311 vlist = vlist_alloc (nentries);
2312
2313 for (v = vc; v; v = v->down)
2314 flatten (v->table, function, vlist, 0);
2315
2316 ret = vlist->list;
2317 free (vlist);
2318 return ret;
2319}
2320
2321SHELL_VAR **
2322map_over_funcs (function)
2323 sh_var_map_func_t *function;
2324{
2325 VARLIST *vlist;
2326 SHELL_VAR **ret;
2327
2328 if (shell_functions == 0 || HASH_ENTRIES (shell_functions) == 0)
2329 return ((SHELL_VAR **)NULL);
2330
2331 vlist = vlist_alloc (HASH_ENTRIES (shell_functions));
2332
2333 flatten (shell_functions, function, vlist, 0);
2334
2335 ret = vlist->list;
2336 free (vlist);
2337 return ret;
2338}
2339
2340/* Flatten VAR_HASH_TABLE, applying FUNC to each member and adding those
2341 elements for which FUNC succeeds to VLIST->list. FLAGS is reserved
2342 for future use. Only unique names are added to VLIST. If FUNC is
2343 NULL, each variable in VAR_HASH_TABLE is added to VLIST. If VLIST is
2344 NULL, FUNC is applied to each SHELL_VAR in VAR_HASH_TABLE. If VLIST
2345 and FUNC are both NULL, nothing happens. */
2346static void
2347flatten (var_hash_table, func, vlist, flags)
2348 HASH_TABLE *var_hash_table;
2349 sh_var_map_func_t *func;
2350 VARLIST *vlist;
2351 int flags;
2352{
2353 register int i;
2354 register BUCKET_CONTENTS *tlist;
2355 int r;
2356 SHELL_VAR *var;
2357
2358 if (var_hash_table == 0 || (HASH_ENTRIES (var_hash_table) == 0) || (vlist == 0 && func == 0))
2359 return;
2360
2361 for (i = 0; i < var_hash_table->nbuckets; i++)
2362 {
2363 for (tlist = hash_items (i, var_hash_table); tlist; tlist = tlist->next)
2364 {
2365 var = (SHELL_VAR *)tlist->data;
2366
2367 r = func ? (*func) (var) : 1;
2368 if (r && vlist)
2369 vlist_add (vlist, var, flags);
2370 }
726f6388 2371 }
7117c2d2
JA
2372}
2373
2374void
2375sort_variables (array)
2376 SHELL_VAR **array;
2377{
2378 qsort (array, strvec_len ((char **)array), sizeof (SHELL_VAR *), (QSFUNC *)qsort_var_comp);
726f6388
JA
2379}
2380
2381static int
7117c2d2
JA
2382qsort_var_comp (var1, var2)
2383 SHELL_VAR **var1, **var2;
726f6388 2384{
7117c2d2
JA
2385 int result;
2386
2387 if ((result = (*var1)->name[0] - (*var2)->name[0]) == 0)
2388 result = strcmp ((*var1)->name, (*var2)->name);
2389
2390 return (result);
726f6388
JA
2391}
2392
7117c2d2
JA
2393/* Apply FUNC to each variable in SHELL_VARIABLES, adding each one for
2394 which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */
ccc6cda3 2395static SHELL_VAR **
7117c2d2
JA
2396vapply (func)
2397 sh_var_map_func_t *func;
726f6388
JA
2398{
2399 SHELL_VAR **list;
2400
7117c2d2 2401 list = map_over (func, shell_variables);
d166f048 2402 if (list /* && posixly_correct */)
726f6388 2403 sort_variables (list);
7117c2d2
JA
2404 return (list);
2405}
726f6388 2406
7117c2d2
JA
2407/* Apply FUNC to each variable in SHELL_FUNCTIONS, adding each one for
2408 which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */
2409static SHELL_VAR **
2410fapply (func)
2411 sh_var_map_func_t *func;
2412{
2413 SHELL_VAR **list;
2414
2415 list = map_over_funcs (func);
2416 if (list /* && posixly_correct */)
2417 sort_variables (list);
726f6388
JA
2418 return (list);
2419}
2420
7117c2d2
JA
2421/* Create a NULL terminated array of all the shell variables. */
2422SHELL_VAR **
2423all_shell_variables ()
2424{
2425 return (vapply ((sh_var_map_func_t *)NULL));
2426}
2427
2428/* Create a NULL terminated array of all the shell functions. */
2429SHELL_VAR **
2430all_shell_functions ()
2431{
2432 return (fapply ((sh_var_map_func_t *)NULL));
2433}
2434
2435static int
2436visible_var (var)
2437 SHELL_VAR *var;
2438{
2439 return (invisible_p (var) == 0);
2440}
2441
726f6388 2442SHELL_VAR **
bb70624e 2443all_visible_functions ()
726f6388 2444{
7117c2d2 2445 return (fapply (visible_var));
ccc6cda3 2446}
726f6388 2447
ccc6cda3 2448SHELL_VAR **
bb70624e 2449all_visible_variables ()
ccc6cda3 2450{
7117c2d2 2451 return (vapply (visible_var));
726f6388
JA
2452}
2453
ccc6cda3
JA
2454/* Return non-zero if the variable VAR is visible and exported. Array
2455 variables cannot be exported. */
726f6388
JA
2456static int
2457visible_and_exported (var)
2458 SHELL_VAR *var;
2459{
ccc6cda3 2460 return (invisible_p (var) == 0 && exported_p (var));
726f6388
JA
2461}
2462
7117c2d2
JA
2463/* Return non-zero if VAR is a local variable in the current context and
2464 is exported. */
2465static int
2466local_and_exported (var)
2467 SHELL_VAR *var;
2468{
2469 return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context && exported_p (var));
2470}
2471
bb70624e
JA
2472SHELL_VAR **
2473all_exported_variables ()
2474{
7117c2d2
JA
2475 return (vapply (visible_and_exported));
2476}
bb70624e 2477
7117c2d2
JA
2478SHELL_VAR **
2479local_exported_variables ()
2480{
2481 return (vapply (local_and_exported));
2482}
2483
2484static int
2485variable_in_context (var)
2486 SHELL_VAR *var;
2487{
2488 return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context);
2489}
2490
2491SHELL_VAR **
2492all_local_variables ()
2493{
2494 VARLIST *vlist;
2495 SHELL_VAR **ret;
2496 VAR_CONTEXT *vc;
2497
2498 vc = shell_variables;
2499 for (vc = shell_variables; vc; vc = vc->down)
2500 if (vc_isfuncenv (vc) && vc->scope == variable_context)
2501 break;
2502
2503 if (vc == 0)
2504 {
2505 internal_error ("all_local_variables: no function context at current scope found");
2506 return (SHELL_VAR **)NULL;
2507 }
2508 if (vc->table == 0 || HASH_ENTRIES (vc->table) == 0 || vc_haslocals (vc) == 0)
2509 return (SHELL_VAR **)NULL;
2510
2511 vlist = vlist_alloc (HASH_ENTRIES (vc->table));
2512
2513 flatten (vc->table, variable_in_context, vlist, 0);
2514
2515 ret = vlist->list;
2516 free (vlist);
2517 if (ret)
2518 sort_variables (ret);
2519 return ret;
bb70624e
JA
2520}
2521
2522#if defined (ARRAY_VARS)
2523/* Return non-zero if the variable VAR is visible and an array. */
2524static int
2525visible_array_vars (var)
2526 SHELL_VAR *var;
2527{
2528 return (invisible_p (var) == 0 && array_p (var));
2529}
2530
2531SHELL_VAR **
2532all_array_variables ()
2533{
7117c2d2 2534 return (vapply (visible_array_vars));
bb70624e
JA
2535}
2536#endif /* ARRAY_VARS */
2537
2538char **
2539all_variables_matching_prefix (prefix)
f73dda09 2540 const char *prefix;
bb70624e
JA
2541{
2542 SHELL_VAR **varlist;
2543 char **rlist;
2544 int vind, rind, plen;
2545
2546 plen = STRLEN (prefix);
2547 varlist = all_visible_variables ();
2548 for (vind = 0; varlist && varlist[vind]; vind++)
2549 ;
2550 if (varlist == 0 || vind == 0)
2551 return ((char **)NULL);
7117c2d2 2552 rlist = strvec_create (vind + 1);
bb70624e
JA
2553 for (vind = rind = 0; varlist[vind]; vind++)
2554 {
2555 if (plen == 0 || STREQN (prefix, varlist[vind]->name, plen))
28ef6c31 2556 rlist[rind++] = savestring (varlist[vind]->name);
bb70624e
JA
2557 }
2558 rlist[rind] = (char *)0;
2559 free (varlist);
2560
2561 return rlist;
2562}
2563
7117c2d2
JA
2564/* **************************************************************** */
2565/* */
2566/* Managing temporary variable scopes */
2567/* */
2568/* **************************************************************** */
2569
2570/* Make variable NAME have VALUE in the temporary environment. */
2571static SHELL_VAR *
2572bind_tempenv_variable (name, value)
2573 const char *name;
2574 char *value;
2575{
2576 SHELL_VAR *var;
2577
2578 var = temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL;
2579
2580 if (var)
2581 {
2582 FREE (value_cell (var));
2583 var_setvalue (var, savestring (value));
2584 INVALIDATE_EXPORTSTR (var);
2585 }
2586
2587 return (var);
2588}
2589
2590/* Find a variable in the temporary environment that is named NAME.
2591 Return the SHELL_VAR *, or NULL if not found. */
2592SHELL_VAR *
2593find_tempenv_variable (name)
2594 const char *name;
2595{
2596 return (temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL);
2597}
2598
2599/* Push the variable described by (SHELL_VAR *)DATA down to the next
2600 variable context from the temporary environment. */
2601static void
2602push_temp_var (data)
2603 PTR_T data;
2604{
2605 SHELL_VAR *var, *v;
2606 HASH_TABLE *binding_table;
2607
2608 var = (SHELL_VAR *)data;
2609
2610 binding_table = shell_variables->table;
2611 if (binding_table == 0)
2612 {
2613 if (shell_variables == global_variables)
2614 /* shouldn't happen */
2615 binding_table = shell_variables->table = global_variables->table = hash_create (0);
2616 else
2617 binding_table = shell_variables->table = hash_create (TEMPENV_HASH_BUCKETS);
2618 }
2619
2620 v = bind_variable_internal (var->name, value_cell (var), binding_table, 0);
2621
2622 /* XXX - should we set the context here? It shouldn't matter because of how
2623 assign_in_env works, but might want to check. */
2624 if (binding_table == global_variables->table) /* XXX */
2625 var->attributes &= ~(att_tempvar|att_propagate);
2626 else
2627 {
2628 var->attributes |= att_propagate;
2629 if (binding_table == shell_variables->table)
2630 shell_variables->flags |= VC_HASTMPVAR;
2631 }
2632 v->attributes |= var->attributes;
2633
2634 dispose_variable (var);
2635}
2636
2637static void
2638propagate_temp_var (data)
2639 PTR_T data;
2640{
2641 SHELL_VAR *var;
2642
2643 var = (SHELL_VAR *)data;
2644 if (tempvar_p (var) && (var->attributes & att_propagate))
2645 push_temp_var (data);
2646 else
2647 dispose_variable (var);
2648}
2649
2650/* Free the storage used in the hash table for temporary
2651 environment variables. PUSHF is a function to be called
2652 to free each hash table entry. It takes care of pushing variables
2653 to previous scopes if appropriate. */
2654static void
2655dispose_temporary_env (pushf)
2656 sh_free_func_t *pushf;
2657{
2658 hash_flush (temporary_env, pushf);
2659 hash_dispose (temporary_env);
2660 temporary_env = (HASH_TABLE *)NULL;
2661
2662 array_needs_making = 1;
2663
2664 sv_ifs ("IFS"); /* XXX here for now */
2665}
2666
2667void
2668dispose_used_env_vars ()
2669{
2670 if (temporary_env)
2671 dispose_temporary_env (propagate_temp_var);
2672}
2673
2674/* Take all of the shell variables in the temporary environment HASH_TABLE
2675 and make shell variables from them at the current variable context. */
2676void
2677merge_temporary_env ()
2678{
2679 if (temporary_env)
2680 dispose_temporary_env (push_temp_var);
2681}
2682
2683/* **************************************************************** */
2684/* */
2685/* Creating and manipulating the environment */
2686/* */
2687/* **************************************************************** */
2688
bb70624e
JA
2689static inline char *
2690mk_env_string (name, value)
f73dda09 2691 const char *name, *value;
bb70624e
JA
2692{
2693 int name_len, value_len;
2694 char *p;
2695
2696 name_len = strlen (name);
2697 value_len = STRLEN (value);
f73dda09 2698 p = (char *)xmalloc (2 + name_len + value_len);
bb70624e
JA
2699 strcpy (p, name);
2700 p[name_len] = '=';
2701 if (value && *value)
2702 strcpy (p + name_len + 1, value);
2703 else
2704 p[name_len + 1] = '\0';
2705 return (p);
2706}
2707
f73dda09 2708#ifdef DEBUG
bb70624e
JA
2709/* Debugging */
2710static int
2711valid_exportstr (v)
2712 SHELL_VAR *v;
2713{
2714 char *s;
2715
2716 s = v->exportstr;
f73dda09 2717 if (legal_variable_starter ((unsigned char)*s) == 0)
bb70624e
JA
2718 {
2719 internal_error ("invalid character %d in exportstr for %s", *s, v->name);
2720 return (0);
2721 }
2722 for (s = v->exportstr + 1; s && *s; s++)
2723 {
2724 if (*s == '=')
28ef6c31 2725 break;
f73dda09 2726 if (legal_variable_char ((unsigned char)*s) == 0)
bb70624e
JA
2727 {
2728 internal_error ("invalid character %d in exportstr for %s", *s, v->name);
2729 return (0);
2730 }
2731 }
2732 if (*s != '=')
2733 {
2734 internal_error ("no `=' in exportstr for %s", v->name);
2735 return (0);
2736 }
2737 return (1);
2738}
f73dda09 2739#endif
bb70624e 2740
7117c2d2
JA
2741static char **
2742make_env_array_from_var_list (vars)
2743 SHELL_VAR **vars;
726f6388
JA
2744{
2745 register int i, list_index;
2746 register SHELL_VAR *var;
ccc6cda3 2747 char **list, *value;
726f6388 2748
7117c2d2 2749 list = strvec_create ((1 + strvec_len ((char **)vars)));
bb70624e
JA
2750
2751#define USE_EXPORTSTR (value == var->exportstr)
726f6388
JA
2752
2753 for (i = 0, list_index = 0; var = vars[i]; i++)
2754 {
28ef6c31
JA
2755#if defined (__CYGWIN__)
2756 /* We don't use the exportstr stuff on Cygwin at all. */
2757 INVALIDATE_EXPORTSTR (var);
bb70624e 2758#endif
28ef6c31
JA
2759 if (var->exportstr)
2760 value = var->exportstr;
bb70624e 2761 else if (function_p (var))
ccc6cda3
JA
2762 value = named_function_string ((char *)NULL, function_cell (var), 0);
2763#if defined (ARRAY_VARS)
2764 else if (array_p (var))
2765# if 0
2766 value = array_to_assignment_string (array_cell (var));
2767# else
2768 continue; /* XXX array vars cannot yet be exported */
2769# endif
2770#endif
726f6388
JA
2771 else
2772 value = value_cell (var);
2773
2774 if (value)
2775 {
bb70624e
JA
2776 /* Gee, I'd like to get away with not using savestring() if we're
2777 using the cached exportstr... */
2778 list[list_index] = USE_EXPORTSTR ? savestring (value)
2779 : mk_env_string (var->name, value);
2780
7117c2d2
JA
2781 if (USE_EXPORTSTR == 0)
2782 SAVE_EXPORTSTR (var, list[list_index]);
2783
726f6388 2784 list_index++;
bb70624e
JA
2785#undef USE_EXPORTSTR
2786
2787#if 0 /* not yet */
ccc6cda3
JA
2788#if defined (ARRAY_VARS)
2789 if (array_p (var))
2790 free (value);
bb70624e 2791#endif
ccc6cda3 2792#endif
726f6388
JA
2793 }
2794 }
2795
726f6388
JA
2796 list[list_index] = (char *)NULL;
2797 return (list);
2798}
2799
7117c2d2
JA
2800/* Make an array of assignment statements from the hash table
2801 HASHED_VARS which contains SHELL_VARs. Only visible, exported
2802 variables are eligible. */
2803static char **
2804make_var_export_array (vcxt)
2805 VAR_CONTEXT *vcxt;
726f6388 2806{
7117c2d2
JA
2807 char **list;
2808 SHELL_VAR **vars;
726f6388 2809
7117c2d2 2810 vars = map_over (visible_and_exported, vcxt);
726f6388 2811
7117c2d2
JA
2812 if (vars == 0)
2813 return (char **)NULL;
ccc6cda3 2814
7117c2d2 2815 list = make_env_array_from_var_list (vars);
ccc6cda3 2816
7117c2d2
JA
2817 free (vars);
2818 return (list);
ccc6cda3
JA
2819}
2820
7117c2d2
JA
2821static char **
2822make_func_export_array ()
726f6388 2823{
7117c2d2
JA
2824 char **list;
2825 SHELL_VAR **vars;
ccc6cda3 2826
7117c2d2
JA
2827 vars = map_over_funcs (visible_and_exported);
2828 if (vars == 0)
2829 return (char **)NULL;
726f6388 2830
7117c2d2 2831 list = make_env_array_from_var_list (vars);
28ef6c31 2832
7117c2d2
JA
2833 free (vars);
2834 return (list);
bb70624e
JA
2835}
2836
d166f048
JA
2837/* Add ENVSTR to the end of the exported environment, EXPORT_ENV. */
2838#define add_to_export_env(envstr,do_alloc) \
2839do \
2840 { \
2841 if (export_env_index >= (export_env_size - 1)) \
2842 { \
2843 export_env_size += 16; \
7117c2d2 2844 export_env = strvec_resize (export_env, export_env_size); \
d166f048
JA
2845 } \
2846 export_env[export_env_index++] = (do_alloc) ? savestring (envstr) : envstr; \
2847 export_env[export_env_index] = (char *)NULL; \
2848 } while (0)
2849
d166f048
JA
2850/* Add ASSIGN to EXPORT_ENV, or supercede a previous assignment in the
2851 array with the same left-hand side. Return the new EXPORT_ENV. */
726f6388 2852char **
d166f048 2853add_or_supercede_exported_var (assign, do_alloc)
726f6388 2854 char *assign;
d166f048 2855 int do_alloc;
726f6388
JA
2856{
2857 register int i;
d166f048 2858 int equal_offset;
726f6388 2859
d166f048
JA
2860 equal_offset = assignment (assign);
2861 if (equal_offset == 0)
2862 return (export_env);
726f6388 2863
7117c2d2
JA
2864 /* If this is a function, then only supersede the function definition.
2865 We do this by including the `=() {' in the comparison, like
2866 initialize_shell_variables does. */
2867 if (assign[equal_offset + 1] == '(' &&
2868 strncmp (assign + equal_offset + 2, ") {", 3) == 0) /* } */
2869 equal_offset += 4;
726f6388 2870
d166f048 2871 for (i = 0; i < export_env_index; i++)
726f6388 2872 {
d166f048 2873 if (STREQN (assign, export_env[i], equal_offset + 1))
726f6388 2874 {
d166f048
JA
2875 free (export_env[i]);
2876 export_env[i] = do_alloc ? savestring (assign) : assign;
2877 return (export_env);
726f6388
JA
2878 }
2879 }
d166f048
JA
2880 add_to_export_env (assign, do_alloc);
2881 return (export_env);
726f6388
JA
2882}
2883
7117c2d2
JA
2884static void
2885add_temp_array_to_env (temp_array, do_alloc, do_supercede)
2886 char **temp_array;
2887 int do_alloc, do_supercede;
2888{
2889 register int i;
2890
2891 if (temp_array == 0)
2892 return;
2893
2894 for (i = 0; temp_array[i]; i++)
2895 {
2896 if (do_supercede)
2897 export_env = add_or_supercede_exported_var (temp_array[i], do_alloc);
2898 else
2899 add_to_export_env (temp_array[i], do_alloc);
2900 }
2901
2902 free (temp_array);
2903}
2904
d166f048 2905/* Make the environment array for the command about to be executed, if the
726f6388
JA
2906 array needs making. Otherwise, do nothing. If a shell action could
2907 change the array that commands receive for their environment, then the
7117c2d2
JA
2908 code should `array_needs_making++'.
2909
2910 The order to add to the array is:
2911 temporary_env
2912 list of var contexts whose head is shell_variables
2913 shell_functions
2914
2915 This is the shell variable lookup order. We add only new variable
2916 names at each step, which allows local variables and variables in
2917 the temporary environments to shadow variables in the global (or
2918 any previous) scope.
2919*/
2920
2921static int
2922n_shell_variables ()
2923{
2924 VAR_CONTEXT *vc;
2925 int n;
2926
2927 for (n = 0, vc = shell_variables; vc; vc = vc->down)
2928 n += HASH_ENTRIES (vc->table);
2929 return n;
2930}
2931
726f6388
JA
2932void
2933maybe_make_export_env ()
2934{
726f6388 2935 register char **temp_array;
d166f048 2936 int new_size;
7117c2d2 2937 VAR_CONTEXT *tcxt;
726f6388
JA
2938
2939 if (array_needs_making)
2940 {
2941 if (export_env)
7117c2d2 2942 strvec_flush (export_env);
d166f048
JA
2943
2944 /* Make a guess based on how many shell variables and functions we
2945 have. Since there will always be array variables, and array
2946 variables are not (yet) exported, this will always be big enough
7117c2d2
JA
2947 for the exported variables and functions. */
2948 new_size = n_shell_variables () + HASH_ENTRIES (shell_functions) + 1 +
2949 HASH_ENTRIES (temporary_env);
d166f048
JA
2950 if (new_size > export_env_size)
2951 {
2952 export_env_size = new_size;
7117c2d2 2953 export_env = strvec_resize (export_env, export_env_size);
d166f048
JA
2954 }
2955 export_env[export_env_index = 0] = (char *)NULL;
726f6388 2956
7117c2d2
JA
2957 /* Make a dummy variable context from the temporary_env, stick it on
2958 the front of shell_variables, call make_var_export_array on the
2959 whole thing to flatten it, and convert the list of SHELL_VAR *s
2960 to the form needed by the environment. */
2961 if (temporary_env)
2962 {
2963 tcxt = new_var_context ((char *)NULL, 0);
2964 tcxt->table = temporary_env;
2965 tcxt->down = shell_variables;
2966 }
2967 else
2968 tcxt = shell_variables;
2969
2970 temp_array = make_var_export_array (tcxt);
d166f048 2971 if (temp_array)
7117c2d2
JA
2972 add_temp_array_to_env (temp_array, 0, 0);
2973
2974 if (tcxt != shell_variables)
2975 free (tcxt);
726f6388 2976
f73dda09
JA
2977#if defined (RESTRICTED_SHELL)
2978 /* Restricted shells may not export shell functions. */
7117c2d2 2979 temp_array = restricted ? (char **)0 : make_func_export_array ();
f73dda09 2980#else
7117c2d2 2981 temp_array = make_func_export_array ();
f73dda09 2982#endif
d166f048 2983 if (temp_array)
7117c2d2 2984 add_temp_array_to_env (temp_array, 0, 0);
726f6388
JA
2985
2986 array_needs_making = 0;
2987 }
2988}
2989
b72432fd
JA
2990/* This is an efficiency hack. PWD and OLDPWD are auto-exported, so
2991 we will need to remake the exported environment every time we
2992 change directories. `_' is always put into the environment for
2993 every external command, so without special treatment it will always
2994 cause the environment to be remade.
2995
2996 If there is no other reason to make the exported environment, we can
2997 just update the variables in place and mark the exported environment
2998 as no longer needing a remake. */
2999void
3000update_export_env_inplace (env_prefix, preflen, value)
3001 char *env_prefix;
3002 int preflen;
3003 char *value;
3004{
3005 char *evar;
3006
f73dda09 3007 evar = (char *)xmalloc (STRLEN (value) + preflen + 1);
b72432fd
JA
3008 strcpy (evar, env_prefix);
3009 if (value)
3010 strcpy (evar + preflen, value);
3011 export_env = add_or_supercede_exported_var (evar, 0);
3012}
3013
726f6388
JA
3014/* We always put _ in the environment as the name of this command. */
3015void
3016put_command_name_into_env (command_name)
3017 char *command_name;
3018{
b72432fd 3019 update_export_env_inplace ("_=", 2, command_name);
726f6388
JA
3020}
3021
cce855bc 3022#if 0 /* UNUSED -- it caused too many problems */
ccc6cda3
JA
3023void
3024put_gnu_argv_flags_into_env (pid, flags_string)
7117c2d2 3025 intmax_t pid;
ccc6cda3
JA
3026 char *flags_string;
3027{
3028 char *dummy, *pbuf;
3029 int l, fl;
3030
3031 pbuf = itos (pid);
3032 l = strlen (pbuf);
3033
3034 fl = strlen (flags_string);
3035
f73dda09 3036 dummy = (char *)xmalloc (l + fl + 30);
ccc6cda3
JA
3037 dummy[0] = '_';
3038 strcpy (dummy + 1, pbuf);
3039 strcpy (dummy + 1 + l, "_GNU_nonoption_argv_flags_");
3040 dummy[l + 27] = '=';
3041 strcpy (dummy + l + 28, flags_string);
3042
3043 free (pbuf);
3044
d166f048 3045 export_env = add_or_supercede_exported_var (dummy, 0);
ccc6cda3 3046}
cce855bc 3047#endif
726f6388 3048
7117c2d2
JA
3049/* **************************************************************** */
3050/* */
3051/* Managing variable contexts */
3052/* */
3053/* **************************************************************** */
3054
3055/* Allocate and return a new variable context with NAME and FLAGS.
3056 NAME can be NULL. */
726f6388 3057
7117c2d2
JA
3058VAR_CONTEXT *
3059new_var_context (name, flags)
3060 char *name;
3061 int flags;
3062{
3063 VAR_CONTEXT *vc;
3064
3065 vc = (VAR_CONTEXT *)xmalloc (sizeof (VAR_CONTEXT));
3066 vc->name = name ? savestring (name) : (char *)NULL;
3067 vc->scope = variable_context;
3068 vc->flags = flags;
3069
3070 vc->up = vc->down = (VAR_CONTEXT *)NULL;
3071 vc->table = (HASH_TABLE *)NULL;
3072
3073 return vc;
3074}
3075
3076/* Free a variable context and its data, including the hash table. Dispose
3077 all of the variables. */
3078void
3079dispose_var_context (vc)
3080 VAR_CONTEXT *vc;
3081{
3082 FREE (vc->name);
3083
3084 if (vc->table)
3085 {
3086 delete_all_variables (vc->table);
3087 hash_dispose (vc->table);
3088 }
3089
3090 free (vc);
3091}
3092
3093/* Set VAR's scope level to the current variable context. */
3094static int
3095set_context (var)
3096 SHELL_VAR *var;
3097{
3098 return (var->context = variable_context);
3099}
3100
3101/* Make a new variable context with NAME and FLAGS and a HASH_TABLE of
3102 temporary variables, and push it onto shell_variables. This is
3103 for shell functions. */
3104VAR_CONTEXT *
3105push_var_context (name, flags, tempvars)
3106 char *name;
3107 int flags;
3108 HASH_TABLE *tempvars;
3109{
3110 VAR_CONTEXT *vc;
3111
3112 vc = new_var_context (name, flags);
3113 vc->table = tempvars;
3114 if (tempvars)
3115 {
3116 /* Have to do this because the temp environment was created before
3117 variable_context was incremented. */
3118 flatten (tempvars, set_context, (VARLIST *)NULL, 0);
3119 vc->flags |= VC_HASTMPVAR;
3120 }
3121 vc->down = shell_variables;
3122 shell_variables->up = vc;
3123
3124 return (shell_variables = vc);
3125}
3126
3127static void
3128push_func_var (data)
3129 PTR_T data;
3130{
3131 SHELL_VAR *var, *v;
3132
3133 var = (SHELL_VAR *)data;
3134
3135 if (tempvar_p (var) && (posixly_correct || (var->attributes & att_propagate)))
3136 {
3137 /* XXX - should we set v->context here? */
3138 v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0);
3139 if (shell_variables == global_variables)
3140 var->attributes &= ~(att_tempvar|att_propagate);
3141 else
3142 shell_variables->flags |= VC_HASTMPVAR;
3143 v->attributes |= var->attributes;
3144 }
3145
3146 dispose_variable (var);
3147}
3148
3149/* Pop the top context off of VCXT and dispose of it, returning the rest of
3150 the stack. */
3151void
3152pop_var_context ()
3153{
3154 VAR_CONTEXT *ret, *vcxt;
3155
3156 vcxt = shell_variables;
3157 if (vc_isfuncenv (vcxt) == 0)
3158 {
3159 internal_error ("pop_var_context: head of shell_variables not a function context");
3160 return;
3161 }
3162
3163 if (ret = vcxt->down)
3164 {
3165 ret->up = (VAR_CONTEXT *)NULL;
3166 shell_variables = ret;
3167 if (vcxt->table)
3168 hash_flush (vcxt->table, push_func_var);
3169 dispose_var_context (vcxt);
3170 }
3171 else
3172 internal_error ("pop_var_context: no global_variables context");
3173}
3174
3175/* Delete the HASH_TABLEs for all variable contexts beginning at VCXT, and
3176 all of the VAR_CONTEXTs except GLOBAL_VARIABLES. */
3177void
3178delete_all_contexts (vcxt)
3179 VAR_CONTEXT *vcxt;
3180{
3181 VAR_CONTEXT *v, *t;
3182
3183 for (v = vcxt; v != global_variables; v = t)
3184 {
3185 t = v->down;
3186 dispose_var_context (v);
3187 }
3188
3189 delete_all_variables (global_variables->table);
3190 shell_variables = global_variables;
3191}
3192
3193/* **************************************************************** */
3194/* */
3195/* Pushing and Popping temporary variable scopes */
3196/* */
3197/* **************************************************************** */
3198
3199VAR_CONTEXT *
3200push_scope (flags, tmpvars)
3201 int flags;
3202 HASH_TABLE *tmpvars;
3203{
3204 return (push_var_context ((char *)NULL, flags, tmpvars));
3205}
3206
3207static void
3208push_exported_var (data)
3209 PTR_T data;
3210{
3211 SHELL_VAR *var, *v;
3212
3213 var = (SHELL_VAR *)data;
3214
3215 /* If a temp var had its export attribute set, or it's marked to be
3216 propagated, bind it in the previous scope before disposing it. */
3217 if (exported_p (var) || (var->attributes & att_propagate))
3218 {
3219 var->attributes &= ~att_tempvar; /* XXX */
3220 v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0);
3221 if (shell_variables == global_variables)
3222 var->attributes &= ~att_propagate;
3223 v->attributes |= var->attributes;
3224 }
3225
3226 dispose_variable (var);
3227}
3228
3229void
3230pop_scope (is_special)
3231 int is_special;
3232{
3233 VAR_CONTEXT *vcxt, *ret;
3234
3235 vcxt = shell_variables;
3236 if (vc_istempscope (vcxt) == 0)
3237 {
3238 internal_error ("pop_scope: head of shell_variables not a temporary environment scope");
3239 return;
3240 }
3241
3242 ret = vcxt->down;
3243 if (ret)
3244 ret->up = (VAR_CONTEXT *)NULL;
3245
3246 shell_variables = ret;
3247
3248 /* Now we can take care of merging variables in VCXT into set of scopes
3249 whose head is RET (shell_variables). */
3250 FREE (vcxt->name);
3251 if (vcxt->table)
3252 {
3253 if (is_special)
3254 hash_flush (vcxt->table, push_func_var);
3255 else
3256 hash_flush (vcxt->table, push_exported_var);
3257 hash_dispose (vcxt->table);
3258 }
3259 free (vcxt);
3260
3261 sv_ifs ("IFS"); /* XXX here for now */
3262}
3263
3264/* **************************************************************** */
3265/* */
3266/* Pushing and Popping function contexts */
3267/* */
3268/* **************************************************************** */
3269
3270static WORD_LIST **dollar_arg_stack = (WORD_LIST **)NULL;
3271static int dollar_arg_stack_slots;
3272static int dollar_arg_stack_index;
3273
3274/* XXX - we might want to consider pushing and popping the `getopts' state
3275 when we modify the positional parameters. */
3276void
3277push_context (name, is_subshell, tempvars)
3278 char *name; /* function name */
3279 int is_subshell;
3280 HASH_TABLE *tempvars;
3281{
3282 if (is_subshell == 0)
3283 push_dollar_vars ();
3284 variable_context++;
3285 push_var_context (name, VC_FUNCENV, tempvars);
3286}
3287
3288/* Only called when subshell == 0, so we don't need to check, and can
3289 unconditionally pop the dollar vars off the stack. */
3290void
3291pop_context ()
726f6388 3292{
7117c2d2
JA
3293 pop_dollar_vars ();
3294 variable_context--;
3295 pop_var_context ();
726f6388 3296
7117c2d2
JA
3297 sv_ifs ("IFS"); /* XXX here for now */
3298}
726f6388 3299
7117c2d2
JA
3300/* Save the existing positional parameters on a stack. */
3301void
3302push_dollar_vars ()
3303{
3304 if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots)
3305 {
3306 dollar_arg_stack = (WORD_LIST **)
3307 xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10)
3308 * sizeof (WORD_LIST **));
3309 }
3310 dollar_arg_stack[dollar_arg_stack_index++] = list_rest_of_args ();
3311 dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
3312}
726f6388 3313
7117c2d2
JA
3314/* Restore the positional parameters from our stack. */
3315void
3316pop_dollar_vars ()
3317{
3318 if (!dollar_arg_stack || dollar_arg_stack_index == 0)
3319 return;
726f6388 3320
7117c2d2
JA
3321 remember_args (dollar_arg_stack[--dollar_arg_stack_index], 1);
3322 dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
3323 dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
3324 set_dollar_vars_unchanged ();
3325}
ccc6cda3 3326
7117c2d2
JA
3327void
3328dispose_saved_dollar_vars ()
3329{
3330 if (!dollar_arg_stack || dollar_arg_stack_index == 0)
3331 return;
726f6388 3332
7117c2d2
JA
3333 dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
3334 dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
726f6388 3335}
cce855bc
JA
3336
3337/*************************************************
3338 * *
3339 * Functions to manage special variables *
3340 * *
3341 *************************************************/
3342
3343/* Extern declarations for variables this code has to manage. */
3344extern int eof_encountered, eof_encountered_limit, ignoreeof;
3345
3346#if defined (READLINE)
3347extern int no_line_editing;
3348extern int hostname_list_initialized;
3349#endif
3350
3351/* An alist of name.function for each special variable. Most of the
3352 functions don't do much, and in fact, this would be faster with a
3353 switch statement, but by the end of this file, I am sick of switch
3354 statements. */
3355
3356#define SET_INT_VAR(name, intvar) intvar = find_variable (name) != 0
3357
7117c2d2 3358/* This table will be sorted with qsort() the first time it's accessed. */
cce855bc
JA
3359struct name_and_function {
3360 char *name;
f73dda09 3361 sh_sv_func_t *function;
7117c2d2 3362};
cce855bc 3363
7117c2d2 3364static struct name_and_function special_vars[] = {
cce855bc
JA
3365 { "GLOBIGNORE", sv_globignore },
3366
cce855bc 3367#if defined (HISTORY)
7117c2d2
JA
3368 { "HISTCONTROL", sv_history_control },
3369 { "HISTFILESIZE", sv_histsize },
cce855bc
JA
3370 { "HISTIGNORE", sv_histignore },
3371 { "HISTSIZE", sv_histsize },
7117c2d2 3372#endif
cce855bc 3373
7117c2d2
JA
3374#if defined (READLINE)
3375 { "HOSTFILE", sv_hostfile },
3376#endif
cce855bc 3377
7117c2d2
JA
3378 { "IFS", sv_ifs },
3379 { "IGNOREEOF", sv_ignoreeof },
cce855bc 3380
7117c2d2 3381 { "LANG", sv_locale },
cce855bc
JA
3382 { "LC_ALL", sv_locale },
3383 { "LC_COLLATE", sv_locale },
3384 { "LC_CTYPE", sv_locale },
3385 { "LC_MESSAGES", sv_locale },
bb70624e 3386 { "LC_NUMERIC", sv_locale },
7117c2d2
JA
3387
3388 { "MAIL", sv_mail },
3389 { "MAILCHECK", sv_mail },
3390 { "MAILPATH", sv_mail },
3391
3392 { "OPTERR", sv_opterr },
3393 { "OPTIND", sv_optind },
3394
3395 { "PATH", sv_path },
3396 { "POSIXLY_CORRECT", sv_strict_posix },
3397
3398#if defined (READLINE)
3399 { "TERM", sv_terminal },
3400 { "TERMCAP", sv_terminal },
3401 { "TERMINFO", sv_terminal },
3402#endif /* READLINE */
3403
3404 { "TEXTDOMAIN", sv_locale },
3405 { "TEXTDOMAINDIR", sv_locale },
cce855bc
JA
3406
3407#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE)
3408 { "TZ", sv_tz },
3409#endif
3410
7117c2d2
JA
3411#if defined (HISTORY) && defined (BANG_HISTORY)
3412 { "histchars", sv_histchars },
3413#endif /* HISTORY && BANG_HISTORY */
3414
3415 { "ignoreeof", sv_ignoreeof },
3416
f73dda09 3417 { (char *)0, (sh_sv_func_t *)0 }
cce855bc
JA
3418};
3419
7117c2d2
JA
3420#define N_SPECIAL_VARS (sizeof (special_vars) / sizeof (special_vars[0]) - 1)
3421
3422static int
3423sv_compare (sv1, sv2)
3424 struct name_and_function *sv1, *sv2;
3425{
3426 int r;
3427
3428 if ((r = sv1->name[0] - sv2->name[0]) == 0)
3429 r = strcmp (sv1->name, sv2->name);
3430 return r;
3431}
3432
3433static inline int
3434find_special_var (name)
3435 const char *name;
3436{
3437 register int i, r;
3438
3439 for (i = 0; special_vars[i].name; i++)
3440 {
3441 r = special_vars[i].name[0] - name[0];
3442 if (r == 0)
3443 r = strcmp (special_vars[i].name, name);
3444 if (r == 0)
3445 return i;
3446 else if (r > 0)
3447 /* Can't match any of rest of elements in sorted list. Take this out
3448 if it causes problems in certain environments. */
3449 break;
3450 }
3451 return -1;
3452}
3453
cce855bc
JA
3454/* The variable in NAME has just had its state changed. Check to see if it
3455 is one of the special ones where something special happens. */
3456void
3457stupidly_hack_special_variables (name)
3458 char *name;
3459{
7117c2d2 3460 static int sv_sorted = 0;
cce855bc
JA
3461 int i;
3462
7117c2d2 3463 if (sv_sorted == 0) /* shouldn't need, but it's fairly cheap. */
cce855bc 3464 {
7117c2d2
JA
3465 qsort (special_vars, N_SPECIAL_VARS, sizeof (special_vars[0]),
3466 (QSFUNC *)sv_compare);
3467 sv_sorted = 1;
cce855bc 3468 }
7117c2d2
JA
3469
3470 i = find_special_var (name);
3471 if (i != -1)
3472 (*(special_vars[i].function)) (name);
3473}
3474
3475void
3476sv_ifs (name)
3477 char *name;
3478{
3479 SHELL_VAR *v;
3480
3481 v = find_variable ("IFS");
3482 setifs (v);
cce855bc
JA
3483}
3484
3485/* What to do just after the PATH variable has changed. */
3486void
3487sv_path (name)
3488 char *name;
3489{
3490 /* hash -r */
7117c2d2 3491 phash_flush ();
cce855bc
JA
3492}
3493
3494/* What to do just after one of the MAILxxxx variables has changed. NAME
3495 is the name of the variable. This is called with NAME set to one of
3496 MAIL, MAILCHECK, or MAILPATH. */
3497void
3498sv_mail (name)
3499 char *name;
3500{
3501 /* If the time interval for checking the files has changed, then
3502 reset the mail timer. Otherwise, one of the pathname vars
3503 to the users mailbox has changed, so rebuild the array of
3504 filenames. */
3505 if (name[4] == 'C') /* if (strcmp (name, "MAILCHECK") == 0) */
3506 reset_mail_timer ();
3507 else
3508 {
3509 free_mail_files ();
3510 remember_mail_dates ();
3511 }
3512}
3513
3514/* What to do when GLOBIGNORE changes. */
3515void
3516sv_globignore (name)
3517 char *name;
3518{
3519 setup_glob_ignore (name);
3520}
3521
3522#if defined (READLINE)
3523/* What to do just after one of the TERMxxx variables has changed.
3524 If we are an interactive shell, then try to reset the terminal
3525 information in readline. */
3526void
3527sv_terminal (name)
3528 char *name;
3529{
3530 if (interactive_shell && no_line_editing == 0)
3531 rl_reset_terminal (get_string_value ("TERM"));
3532}
3533
3534void
3535sv_hostfile (name)
3536 char *name;
3537{
bb70624e
JA
3538 SHELL_VAR *v;
3539
3540 v = find_variable (name);
3541 if (v == 0)
3542 clear_hostname_list ();
3543 else
3544 hostname_list_initialized = 0;
cce855bc
JA
3545}
3546#endif /* READLINE */
3547
3548#if defined (HISTORY)
3549/* What to do after the HISTSIZE or HISTFILESIZE variables change.
3550 If there is a value for this HISTSIZE (and it is numeric), then stifle
3551 the history. Otherwise, if there is NO value for this variable,
3552 unstifle the history. If name is HISTFILESIZE, and its value is
3553 numeric, truncate the history file to hold no more than that many
3554 lines. */
3555void
3556sv_histsize (name)
3557 char *name;
3558{
3559 char *temp;
7117c2d2 3560 intmax_t num;
cce855bc
JA
3561
3562 temp = get_string_value (name);
3563
3564 if (temp && *temp)
3565 {
3566 if (legal_number (temp, &num))
28ef6c31 3567 {
cce855bc
JA
3568 if (name[4] == 'S')
3569 {
3570 stifle_history (num);
3571 num = where_history ();
3572 if (history_lines_this_session > num)
3573 history_lines_this_session = num;
3574 }
3575 else
3576 {
3577 history_truncate_file (get_string_value ("HISTFILE"), (int)num);
3578 if (num <= history_lines_in_file)
3579 history_lines_in_file = num;
3580 }
3581 }
3582 }
3583 else if (name[4] == 'S')
3584 unstifle_history ();
3585}
3586
3587/* What to do after the HISTIGNORE variable changes. */
3588void
3589sv_histignore (name)
3590 char *name;
3591{
3592 setup_history_ignore (name);
3593}
3594
3595/* What to do after the HISTCONTROL variable changes. */
3596void
3597sv_history_control (name)
3598 char *name;
3599{
3600 char *temp;
3601
3602 history_control = 0;
3603 temp = get_string_value (name);
3604
3605 if (temp && *temp && STREQN (temp, "ignore", 6))
3606 {
3607 if (temp[6] == 's') /* ignorespace */
3608 history_control = 1;
3609 else if (temp[6] == 'd') /* ignoredups */
3610 history_control = 2;
3611 else if (temp[6] == 'b') /* ignoreboth */
3612 history_control = 3;
3613 }
3614}
3615
3616#if defined (BANG_HISTORY)
3617/* Setting/unsetting of the history expansion character. */
3618void
3619sv_histchars (name)
3620 char *name;
3621{
3622 char *temp;
3623
3624 temp = get_string_value (name);
3625 if (temp)
3626 {
3627 history_expansion_char = *temp;
3628 if (temp[0] && temp[1])
3629 {
3630 history_subst_char = temp[1];
3631 if (temp[2])
3632 history_comment_char = temp[2];
3633 }
3634 }
3635 else
3636 {
3637 history_expansion_char = '!';
3638 history_subst_char = '^';
3639 history_comment_char = '#';
3640 }
3641}
3642#endif /* BANG_HISTORY */
3643#endif /* HISTORY */
3644
3645#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE)
3646void
3647sv_tz (name)
3648 char *name;
3649{
3650 tzset ();
3651}
3652#endif
3653
3654/* If the variable exists, then the value of it can be the number
3655 of times we actually ignore the EOF. The default is small,
3656 (smaller than csh, anyway). */
3657void
3658sv_ignoreeof (name)
3659 char *name;
3660{
3661 SHELL_VAR *tmp_var;
3662 char *temp;
3663
3664 eof_encountered = 0;
3665
3666 tmp_var = find_variable (name);
3667 ignoreeof = tmp_var != 0;
3668 temp = tmp_var ? value_cell (tmp_var) : (char *)NULL;
3669 if (temp)
3670 eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10;
3671 set_shellopts (); /* make sure `ignoreeof' is/is not in $SHELLOPTS */
3672}
3673
3674void
3675sv_optind (name)
3676 char *name;
3677{
3678 char *tt;
3679 int s;
3680
3681 tt = get_string_value ("OPTIND");
3682 if (tt && *tt)
3683 {
3684 s = atoi (tt);
3685
3686 /* According to POSIX, setting OPTIND=1 resets the internal state
3687 of getopt (). */
3688 if (s < 0 || s == 1)
3689 s = 0;
3690 }
3691 else
3692 s = 0;
3693 getopts_reset (s);
3694}
3695
3696void
3697sv_opterr (name)
3698 char *name;
3699{
3700 char *tt;
3701
3702 tt = get_string_value ("OPTERR");
3703 sh_opterr = (tt && *tt) ? atoi (tt) : 1;
3704}
3705
3706void
3707sv_strict_posix (name)
3708 char *name;
3709{
3710 SET_INT_VAR (name, posixly_correct);
3711 posix_initialize (posixly_correct);
3712#if defined (READLINE)
3713 if (interactive_shell)
3714 posix_readline_initialize (posixly_correct);
3715#endif /* READLINE */
3716 set_shellopts (); /* make sure `posix' is/is not in $SHELLOPTS */
3717}
3718
3719void
3720sv_locale (name)
3721 char *name;
3722{
3723 char *v;
3724
3725 v = get_string_value (name);
3726 if (name[0] == 'L' && name[1] == 'A') /* LANG */
3727 set_lang (name, v);
3728 else
3729 set_locale_var (name, v); /* LC_*, TEXTDOMAIN* */
3730}
3731
3732#if defined (ARRAY_VARS)
3733void
7117c2d2 3734set_pipestatus_array (ps, nproc)
cce855bc 3735 int *ps;
7117c2d2 3736 int nproc;
cce855bc
JA
3737{
3738 SHELL_VAR *v;
3739 ARRAY *a;
7117c2d2 3740 ARRAY_ELEMENT *ae;
cce855bc 3741 register int i;
f73dda09 3742 char *t, tbuf[INT_STRLEN_BOUND(int) + 1];
cce855bc
JA
3743
3744 v = find_variable ("PIPESTATUS");
3745 if (v == 0)
3746 v = make_new_array_variable ("PIPESTATUS");
3747 if (array_p (v) == 0)
3748 return; /* Do nothing if not an array variable. */
3749 a = array_cell (v);
7117c2d2
JA
3750
3751 if (a == 0 || array_num_elements (a) == 0)
cce855bc 3752 {
7117c2d2
JA
3753 for (i = 0; i < nproc; i++) /* was ps[i] != -1, not i < nproc */
3754 {
3755 t = inttostr (ps[i], tbuf, sizeof (tbuf));
3756 array_insert (a, i, t);
3757 }
3758 return;
3759 }
3760
3761 /* Fast case */
3762 if (array_num_elements (a) == nproc && nproc == 1)
3763 {
3764 ae = element_forw (a->head);
3765 free (element_value (ae));
3766 ae->value = itos (ps[0]);
3767 }
3768 else if (array_num_elements (a) <= nproc)
3769 {
3770 /* modify in array_num_elements members in place, then add */
3771 ae = a->head;
3772 for (i = 0; i < array_num_elements (a); i++)
3773 {
3774 ae = element_forw (ae);
3775 free (element_value (ae));
3776 ae->value = itos (ps[i]);
3777 }
3778 /* add any more */
3779 for ( ; i < nproc; i++)
3780 {
3781 t = inttostr (ps[i], tbuf, sizeof (tbuf));
3782 array_insert (a, i, t);
3783 }
3784 }
3785 else
3786 {
3787 /* deleting elements. it's faster to rebuild the array. */
3788 array_flush (a);
3789 for (i = 0; ps[i] != -1; i++)
3790 {
3791 t = inttostr (ps[i], tbuf, sizeof (tbuf));
3792 array_insert (a, i, t);
3793 }
cce855bc
JA
3794 }
3795}
3796#endif
3797
3798void
3799set_pipestatus_from_exit (s)
3800 int s;
3801{
3802#if defined (ARRAY_VARS)
3803 static int v[2] = { 0, -1 };
3804
3805 v[0] = s;
7117c2d2 3806 set_pipestatus_array (v, 1);
cce855bc
JA
3807#endif
3808}