]> git.ipfire.org Git - thirdparty/bash.git/blame - variables.c
Imported from ../bash-2.02.tar.gz.
[thirdparty/bash.git] / variables.c
CommitLineData
726f6388
JA
1/* variables.c -- Functions for hacking shell variables. */
2
3/* Copyright (C) 1987,1989 Free Software Foundation, Inc.
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
9 the Free Software Foundation; either version 1, or (at your option)
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
19 Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20
ccc6cda3
JA
21#include "config.h"
22
726f6388
JA
23#include "bashtypes.h"
24#include "posixstat.h"
ccc6cda3 25
d166f048
JA
26#if defined (qnx)
27# include <sys/vc.h>
28#endif
29
ccc6cda3
JA
30#if defined (HAVE_UNISTD_H)
31# include <unistd.h>
32#endif
33
34#include <stdio.h>
726f6388
JA
35#include <ctype.h>
36#include <pwd.h>
726f6388 37#include "bashansi.h"
ccc6cda3 38
726f6388 39#include "shell.h"
726f6388
JA
40#include "flags.h"
41#include "execute_cmd.h"
cce855bc 42#include "findcmd.h"
ccc6cda3
JA
43#include "mailcheck.h"
44#include "input.h"
726f6388 45
d166f048 46#include "builtins/getopt.h"
726f6388 47#include "builtins/common.h"
cce855bc
JA
48
49#if defined (READLINE)
50# include "bashline.h"
51# include <readline/readline.h>
52#else
53# include <tilde/tilde.h>
54#endif
726f6388 55
ccc6cda3
JA
56#if defined (HISTORY)
57# include "bashhist.h"
cce855bc 58# include <readline/history.h>
ccc6cda3
JA
59#endif /* HISTORY */
60
726f6388
JA
61/* Variables used here and defined in other files. */
62extern int posixly_correct;
63extern int variable_context, line_number;
ccc6cda3
JA
64extern int interactive, interactive_shell, login_shell;
65extern int subshell_environment, indirection_level;
66extern int build_version, patch_level;
67extern char *dist_version, *release_status;
726f6388
JA
68extern char *shell_name;
69extern char *primary_prompt, *secondary_prompt;
ccc6cda3 70extern char *current_host_name;
726f6388 71extern Function *this_shell_builtin;
ccc6cda3 72extern char *this_command_name;
726f6388
JA
73extern time_t shell_start_time;
74
75/* The list of shell variables that the user has created, or that came from
76 the environment. */
77HASH_TABLE *shell_variables = (HASH_TABLE *)NULL;
78
79/* The list of shell functions that the user has created, or that came from
80 the environment. */
81HASH_TABLE *shell_functions = (HASH_TABLE *)NULL;
82
83/* The current variable context. This is really a count of how deep into
84 executing functions we are. */
85int variable_context = 0;
86
87/* The array of shell assignments which are made only in the environment
88 for a single command. */
89char **temporary_env = (char **)NULL;
90
91/* The array of shell assignments which are in the environment for the
92 execution of a shell function. */
93char **function_env = (char **)NULL;
94
95/* The array of shell assignments which are made only in the environment
96 for the execution of a shell builtin command which may cause more than
97 one command to be executed (e.g., "source"). */
98char **builtin_env = (char **)NULL;
99
100/* Some funky variables which are known about specially. Here is where
101 "$*", "$1", and all the cruft is kept. */
102char *dollar_vars[10];
103WORD_LIST *rest_of_args = (WORD_LIST *)NULL;
104
105/* The value of $$. */
106int dollar_dollar_pid;
107
108/* An array which is passed to commands as their environment. It is
d166f048 109 manufactured from the union of the initial environment and the
726f6388
JA
110 shell variables that are marked for export. */
111char **export_env = (char **)NULL;
d166f048
JA
112static int export_env_index;
113static int export_env_size;
726f6388
JA
114
115/* Non-zero means that we have to remake EXPORT_ENV. */
116int array_needs_making = 1;
117
ccc6cda3
JA
118/* The number of times BASH has been executed. This is set
119 by initialize_variables (). */
120int shell_level = 0;
726f6388 121
ccc6cda3
JA
122static char *have_local_variables;
123static int local_variable_stack_size;
726f6388
JA
124
125/* Some forward declarations. */
d166f048
JA
126static void set_home_var ();
127static void set_shell_var ();
128static char *get_bash_name ();
129static void initialize_shell_level ();
ccc6cda3 130static void uidset ();
726f6388 131static void initialize_dynamic_variables ();
ccc6cda3 132static void make_vers_array ();
726f6388
JA
133static void sbrand (); /* set bash random number generator. */
134static int qsort_var_comp ();
135
136/* Make VAR be auto-exported. VAR is a pointer to a SHELL_VAR. */
137#define set_auto_export(var) \
138 do { var->attributes |= att_exported; array_needs_making = 1; } while (0)
139
cce855bc
JA
140/* Initialize the shell variables from the current environment.
141 If PRIVMODE is nonzero, don't import functions from ENV or
142 parse $SHELLOPTS. */
726f6388 143void
cce855bc 144initialize_shell_variables (env, privmode)
726f6388 145 char **env;
cce855bc 146 int privmode;
726f6388 147{
ccc6cda3
JA
148 char *name, *string, *temp_string;
149 int c, char_index, string_index, string_length;
726f6388
JA
150 SHELL_VAR *temp_var;
151
cce855bc 152 if (shell_variables == 0)
726f6388
JA
153 shell_variables = make_hash_table (0);
154
cce855bc 155 if (shell_functions == 0)
726f6388
JA
156 shell_functions = make_hash_table (0);
157
ccc6cda3 158 for (string_index = 0; string = env[string_index++]; )
726f6388 159 {
726f6388 160 char_index = 0;
d166f048 161 name = string;
726f6388 162 while ((c = *string++) && c != '=')
d166f048
JA
163 ;
164 if (string[-1] == '=')
165 char_index = string - name - 1;
726f6388 166
d166f048
JA
167 /* If there are weird things in the environment, like `=xxx' or a
168 string without an `=', just skip them. */
169 if (char_index == 0)
170 continue;
171
172 /* ASSERT(name[char_index] == '=') */
726f6388 173 name[char_index] = '\0';
d166f048
JA
174 /* Now, name = env variable name, string = env variable value, and
175 char_index == strlen (name) */
726f6388
JA
176
177 /* If exported function, define it now. */
cce855bc 178 if (privmode == 0 && STREQN ("() {", string, 4))
726f6388 179 {
d166f048
JA
180 string_length = strlen (string);
181 temp_string = xmalloc (3 + string_length + char_index);
182#if 1
183 strcpy (temp_string, name);
184 temp_string[char_index] = ' ';
185 strcpy (temp_string + char_index + 1, string);
186#else
ccc6cda3 187 sprintf (temp_string, "%s %s", name, string);
d166f048 188#endif
726f6388 189
d166f048 190 parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST);
726f6388 191
d166f048
JA
192 /* Ancient backwards compatibility. Old versions of bash exported
193 functions like name()=() {...} */
194 if (name[char_index - 1] == ')' && name[char_index - 2] == '(')
726f6388
JA
195 name[char_index - 2] = '\0';
196
ccc6cda3 197 if (temp_var = find_function (name))
726f6388 198 {
ccc6cda3 199 temp_var->attributes |= (att_exported | att_imported);
726f6388
JA
200 array_needs_making = 1;
201 }
202 else
203 report_error ("error importing function definition for `%s'", name);
d166f048
JA
204
205 if (name[char_index - 1] == ')' && name[char_index - 2] == '\0')
206 name[char_index - 2] = '(';
726f6388 207 }
ccc6cda3
JA
208#if defined (ARRAY_VARS)
209# if 0
210 /* Array variables may not yet be exported. */
211 else if (*string == '(' && string[1] == '[' && strchr (string, ')'))
212 {
213 string_length = 1;
214 temp_string = extract_array_assignment_list (string, &string_length);
215 temp_var = assign_array_from_string (name, temp_string);
216 FREE (temp_string);
217 temp_var->attributes |= (att_exported | att_imported);
218 array_needs_making = 1;
219 }
220# endif
221#endif
726f6388
JA
222 else
223 {
ccc6cda3
JA
224 temp_var = bind_variable (name, string);
225 temp_var->attributes |= (att_exported | att_imported);
726f6388
JA
226 array_needs_making = 1;
227 }
d166f048
JA
228
229 name[char_index] = '=';
726f6388
JA
230 }
231
232 /* If we got PWD from the environment, update our idea of the current
233 working directory. In any case, make sure that PWD exists before
ccc6cda3 234 checking it. It is possible for getcwd () to fail on shell startup,
726f6388
JA
235 and in that case, PWD would be undefined. */
236 temp_var = find_variable ("PWD");
237 if (temp_var && imported_p (temp_var) &&
ccc6cda3
JA
238 (temp_string = value_cell (temp_var)) &&
239 same_file (temp_string, ".", (struct stat *)NULL, (struct stat *)NULL))
240 set_working_directory (temp_string);
726f6388
JA
241 else
242 {
ccc6cda3
JA
243 temp_string = get_working_directory ("shell-init");
244 if (temp_string)
245 {
cce855bc
JA
246 temp_var = bind_variable ("PWD", temp_string);
247 set_auto_export (temp_var);
ccc6cda3
JA
248 free (temp_string);
249 }
726f6388
JA
250 }
251
ccc6cda3
JA
252 /* Set up initial value of $_ */
253 temp_var = bind_variable ("_", dollar_vars[0]);
254
726f6388
JA
255 /* Remember this pid. */
256 dollar_dollar_pid = (int)getpid ();
257
258 /* Now make our own defaults in case the vars that we think are
259 important are missing. */
260 temp_var = set_if_not ("PATH", DEFAULT_PATH_VALUE);
261 set_auto_export (temp_var);
262
263 temp_var = set_if_not ("TERM", "dumb");
264 set_auto_export (temp_var);
265
d166f048
JA
266#if defined (qnx)
267 /* set node id -- don't import it from the environment */
268 {
269 char node_name[22];
270 qnx_nidtostr (getnid (), node_name, sizeof (node_name));
271 temp_var = bind_variable ("NODE", node_name);
272 set_auto_export (temp_var);
273 }
274#endif
275
ccc6cda3 276 /* set up the prompts. */
726f6388
JA
277 if (interactive_shell)
278 {
279 set_if_not ("PS1", primary_prompt);
280 set_if_not ("PS2", secondary_prompt);
281 }
282 set_if_not ("PS4", "+ ");
283
ccc6cda3
JA
284 /* Don't allow IFS to be imported from the environment. */
285 temp_var = bind_variable ("IFS", " \t\n");
726f6388
JA
286
287 /* Magic machine types. Pretty convenient. */
ccc6cda3 288 temp_var = bind_variable ("HOSTTYPE", HOSTTYPE);
726f6388 289 set_auto_export (temp_var);
ccc6cda3
JA
290 temp_var = bind_variable ("OSTYPE", OSTYPE);
291 set_auto_export (temp_var);
292 temp_var = bind_variable ("MACHTYPE", MACHTYPE);
293 set_auto_export (temp_var);
294 temp_var = bind_variable ("HOSTNAME", current_host_name);
726f6388
JA
295 set_auto_export (temp_var);
296
ccc6cda3
JA
297 /* Default MAILCHECK for interactive shells. Defer the creation of a
298 default MAILPATH until the startup files are read, because MAIL
299 names a mail file if MAILCHECK is not set, and we should provide a
300 default only if neither is set. */
726f6388
JA
301 if (interactive_shell)
302 set_if_not ("MAILCHECK", "60");
303
304 /* Do some things with shell level. */
d166f048 305 initialize_shell_level ();
726f6388
JA
306
307 /* Make a variable $PPID, which holds the pid of the shell's parent. */
ccc6cda3
JA
308 name = itos ((int) getppid ());
309 temp_var = find_variable ("PPID");
310 if (temp_var)
311 temp_var->attributes &= ~(att_readonly | att_exported);
312 temp_var = bind_variable ("PPID", name);
313 temp_var->attributes |= (att_readonly | att_integer);
314 free (name);
726f6388 315
726f6388
JA
316 /* Initialize the `getopts' stuff. */
317 bind_variable ("OPTIND", "1");
d166f048 318 getopts_reset (0);
726f6388 319 bind_variable ("OPTERR", "1");
d166f048
JA
320 sh_opterr = 1;
321
322 if (login_shell == 1)
323 set_home_var ();
726f6388
JA
324
325 /* Get the full pathname to THIS shell, and set the BASH variable
326 to it. */
d166f048 327 name = get_bash_name ();
ccc6cda3
JA
328 temp_var = bind_variable ("BASH", name);
329 free (name);
330
331 /* Make the exported environment variable SHELL be the user's login
332 shell. Note that the `tset' command looks at this variable
333 to determine what style of commands to output; if it ends in "csh",
334 then C-shell commands are output, else Bourne shell commands. */
d166f048 335 set_shell_var ();
726f6388
JA
336
337 /* Make a variable called BASH_VERSION which contains the version info. */
338 bind_variable ("BASH_VERSION", shell_version_string ());
ccc6cda3
JA
339#if defined (ARRAY_VARS)
340 make_vers_array ();
341#endif
726f6388
JA
342
343 /* Find out if we're supposed to be in Posix.2 mode via an
344 environment variable. */
345 temp_var = find_variable ("POSIXLY_CORRECT");
346 if (!temp_var)
347 temp_var = find_variable ("POSIX_PEDANTIC");
348 if (temp_var && imported_p (temp_var))
349 sv_strict_posix (temp_var->name);
350
351#if defined (HISTORY)
352 /* Set history variables to defaults, and then do whatever we would
353 do if the variable had just been set. Do this only in the case
354 that we are remembering commands on the history list. */
355 if (remember_on_history)
356 {
ccc6cda3 357 name = bash_tilde_expand (posixly_correct ? "~/.sh_history" : "~/.bash_history");
726f6388
JA
358
359 set_if_not ("HISTFILE", name);
360 free (name);
361
362 set_if_not ("HISTSIZE", "500");
363 sv_histsize ("HISTSIZE");
364 }
365#endif /* HISTORY */
366
367 /* Seed the random number generator. */
ccc6cda3 368 sbrand (dollar_dollar_pid + (long)shell_start_time);
726f6388
JA
369
370 /* Handle some "special" variables that we may have inherited from a
371 parent shell. */
d166f048
JA
372 if (interactive_shell)
373 {
374 temp_var = find_variable ("IGNOREEOF");
375 if (!temp_var)
376 temp_var = find_variable ("ignoreeof");
377 if (temp_var && imported_p (temp_var))
378 sv_ignoreeof (temp_var->name);
379 }
726f6388
JA
380
381#if defined (HISTORY)
382 if (interactive_shell && remember_on_history)
383 {
ccc6cda3
JA
384 sv_history_control ("HISTCONTROL");
385 sv_histignore ("HISTIGNORE");
726f6388
JA
386 }
387#endif /* HISTORY */
388
ccc6cda3
JA
389 /* Get the user's real and effective user ids. */
390 uidset ();
391
726f6388
JA
392 /* Initialize the dynamic variables, and seed their values. */
393 initialize_dynamic_variables ();
726f6388
JA
394}
395
d166f048
JA
396/* Set $HOME to the information in the password file if we didn't get
397 it from the environment. */
398static void
399set_home_var ()
400{
401 SHELL_VAR *temp_var;
402
403 temp_var = find_variable ("HOME");
404 if (temp_var == 0)
405 {
406 if (current_user.home_dir == 0)
407 get_current_user_info ();
408 temp_var = bind_variable ("HOME", current_user.home_dir);
409 }
410 temp_var->attributes |= att_exported;
411}
412
413/* Set $SHELL to the user's login shell if it is not already set. Call
414 get_current_user_info if we haven't already fetched the shell. */
415static void
416set_shell_var ()
417{
418 SHELL_VAR *temp_var;
419
420 temp_var = find_variable ("SHELL");
421 if (temp_var == 0)
422 {
423 if (current_user.shell == 0)
424 get_current_user_info ();
425 temp_var = bind_variable ("SHELL", current_user.shell);
426 }
427 temp_var->attributes |= att_exported;
428}
429
430static char *
431get_bash_name ()
432{
433 char *name;
434
435 if ((login_shell == 1) && (*shell_name != '/'))
436 {
437 if (current_user.shell == 0)
438 get_current_user_info ();
439 name = savestring (current_user.shell);
440 }
441 else if (*shell_name == '/')
442 name = savestring (shell_name);
443 else if (shell_name[0] == '.' && shell_name[1] == '/')
444 {
445 /* Fast path for common case. */
446 char *cdir;
447 int len;
448
449 cdir = get_string_value ("PWD");
450 len = strlen (cdir);
451 name = xmalloc (len + strlen (shell_name) + 1);
452 strcpy (name, cdir);
453 strcpy (name + len, shell_name + 1);
454 }
455 else
456 {
457 char *tname;
458 int s;
459
460 tname = find_user_command (shell_name);
461
462 if (tname == 0)
463 {
464 /* Try the current directory. If there is not an executable
465 there, just punt and use the login shell. */
466 s = file_status (shell_name);
467 if (s & FS_EXECABLE)
468 {
469 tname = make_absolute (shell_name, get_string_value ("PWD"));
470 if (*shell_name == '.')
471 {
472 name = canonicalize_pathname (tname);
473 if (name == 0)
474 name = tname;
475 else
476 free (tname);
477 }
478 else
479 name = tname;
480 }
481 else
482 {
483 if (current_user.shell == 0)
484 get_current_user_info ();
485 name = savestring (current_user.shell);
486 }
487 }
488 else
489 {
490 name = full_pathname (tname);
491 free (tname);
492 }
493 }
494
495 return (name);
496}
497
726f6388
JA
498void
499adjust_shell_level (change)
500 int change;
501{
d166f048 502 char new_level[5], *old_SHLVL;
726f6388 503 int old_level;
d166f048 504 SHELL_VAR *temp_var;
726f6388
JA
505
506 old_SHLVL = get_string_value ("SHLVL");
d166f048 507 old_level = old_SHLVL ? atoi (old_SHLVL) : 0;
726f6388
JA
508
509 shell_level = old_level + change;
510 if (shell_level < 0)
511 shell_level = 0;
d166f048
JA
512 else if (shell_level > 1000)
513 {
cce855bc 514 internal_warning ("shell level (%d) too high, resetting to 1", shell_level);
d166f048
JA
515 shell_level = 1;
516 }
517
518 /* We don't need the full generality of itos here. */
519 if (shell_level < 10)
520 {
521 new_level[0] = shell_level + '0';
522 new_level[1] = '\0';
523 }
524 else if (shell_level < 100)
525 {
526 new_level[0] = (shell_level / 10) + '0';
527 new_level[1] = (shell_level % 10) + '0';
528 new_level[2] = '\0';
529 }
530 else if (shell_level < 1000)
531 {
532 new_level[0] = (shell_level / 100) + '0';
533 old_level = shell_level % 100;
534 new_level[1] = (old_level / 10) + '0';
535 new_level[2] = (old_level % 10) + '0';
536 new_level[3] = '\0';
537 }
538
539 temp_var = bind_variable ("SHLVL", new_level);
540 set_auto_export (temp_var);
541}
542
543static void
544initialize_shell_level ()
545{
546#if 0
547 SHELL_VAR *temp_var;
548
549 temp_var = set_if_not ("SHLVL", "0");
550 set_auto_export (temp_var);
551#endif
552 adjust_shell_level (1);
726f6388
JA
553}
554
ccc6cda3
JA
555static void
556uidset ()
726f6388 557{
ccc6cda3
JA
558 char *buff;
559 register SHELL_VAR *v;
560
561 buff = itos (current_user.uid);
562 v = find_variable ("UID");
563 if (v)
564 v->attributes &= ~att_readonly;
565
566 v = bind_variable ("UID", buff);
567 v->attributes |= (att_readonly | att_integer);
726f6388 568
ccc6cda3 569 if (current_user.euid != current_user.uid)
726f6388 570 {
ccc6cda3
JA
571 free (buff);
572 buff = itos (current_user.euid);
726f6388
JA
573 }
574
ccc6cda3
JA
575 v = find_variable ("EUID");
576 if (v)
577 v->attributes &= ~att_readonly;
726f6388 578
ccc6cda3
JA
579 v = bind_variable ("EUID", buff);
580 v->attributes |= (att_readonly | att_integer);
581 free (buff);
582}
583
584#if defined (ARRAY_VARS)
585static void
586make_vers_array ()
587{
588 SHELL_VAR *vv;
589 ARRAY *av;
590 char *s, d[16];
591
592 makunbound ("BASH_VERSINFO", shell_variables);
593
594 vv = make_new_array_variable ("BASH_VERSINFO");
595 av = array_cell (vv);
596 strcpy (d, dist_version);
597 s = strchr (d, '.');
598 if (s)
599 *s++ = '\0';
600 array_add_element (av, 0, d);
601 array_add_element (av, 1, s);
602 s = itos (patch_level);
603 array_add_element (av, 2, s);
604 free (s);
605 s = itos (build_version);
606 array_add_element (av, 3, s);
607 free (s);
608 array_add_element (av, 4, release_status);
609 array_add_element (av, 5, MACHTYPE);
610
611 vv->attributes |= att_readonly;
612}
613#endif /* ARRAY_VARS */
614
615/* Set the environment variables $LINES and $COLUMNS in response to
616 a window size change. */
617void
618set_lines_and_columns (lines, cols)
619 int lines, cols;
620{
621 char *val;
622
623 val = itos (lines);
624 bind_variable ("LINES", val);
625 free (val);
626
627 val = itos (cols);
628 bind_variable ("COLUMNS", val);
629 free (val);
726f6388
JA
630}
631
632/* Set NAME to VALUE if NAME has no value. */
633SHELL_VAR *
634set_if_not (name, value)
635 char *name, *value;
636{
ccc6cda3 637 SHELL_VAR *v;
726f6388 638
ccc6cda3 639 v = find_variable (name);
cce855bc 640 if (v == 0)
726f6388
JA
641 v = bind_variable (name, value);
642 return (v);
643}
644
645/* Map FUNCTION over the variables in VARIABLES. Return an array of the
d166f048
JA
646 variables for which FUNCTION returns a non-zero value. A NULL value
647 for FUNCTION means to use all variables. */
726f6388
JA
648SHELL_VAR **
649map_over (function, var_hash_table)
650 Function *function;
651 HASH_TABLE* var_hash_table;
652{
653 register int i;
654 register BUCKET_CONTENTS *tlist;
d166f048
JA
655 SHELL_VAR *var, **list;
656 int list_index, list_size;
726f6388 657
d166f048
JA
658 list = (SHELL_VAR **)NULL;
659 for (i = list_index = list_size = 0; i < var_hash_table->nbuckets; i++)
726f6388
JA
660 {
661 tlist = get_hash_bucket (i, var_hash_table);
662
663 while (tlist)
664 {
665 var = (SHELL_VAR *)tlist->data;
666
667 if (!function || (*function) (var))
668 {
669 if (list_index + 1 >= list_size)
670 list = (SHELL_VAR **)
671 xrealloc (list, (list_size += 20) * sizeof (SHELL_VAR *));
672
673 list[list_index++] = var;
674 list[list_index] = (SHELL_VAR *)NULL;
675 }
676 tlist = tlist->next;
677 }
678 }
679 return (list);
680}
681
682void
683sort_variables (array)
684 SHELL_VAR **array;
685{
686 qsort (array, array_len ((char **)array), sizeof (SHELL_VAR *), qsort_var_comp);
687}
688
689static int
690qsort_var_comp (var1, var2)
691 SHELL_VAR **var1, **var2;
692{
693 int result;
694
695 if ((result = (*var1)->name[0] - (*var2)->name[0]) == 0)
696 result = strcmp ((*var1)->name, (*var2)->name);
697
698 return (result);
699}
700
701/* Create a NULL terminated array of all the shell variables in TABLE. */
702static SHELL_VAR **
703all_vars (table)
704 HASH_TABLE *table;
705{
706 SHELL_VAR **list;
707
708 list = map_over ((Function *)NULL, table);
d166f048 709 if (list /* && posixly_correct */)
726f6388
JA
710 sort_variables (list);
711 return (list);
712}
713
714/* Create a NULL terminated array of all the shell variables. */
715SHELL_VAR **
716all_shell_variables ()
717{
718 return (all_vars (shell_variables));
719}
720
721/* Create a NULL terminated array of all the shell functions. */
722SHELL_VAR **
723all_shell_functions ()
724{
725 return (all_vars (shell_functions));
726}
727
728/* Print VARS to stdout in such a way that they can be read back in. */
729void
730print_var_list (list)
731 register SHELL_VAR **list;
732{
733 register int i;
734 register SHELL_VAR *var;
735
736 for (i = 0; list && (var = list[i]); i++)
737 if (!invisible_p (var))
738 print_assignment (var);
739}
740
741#if defined (NOTDEF)
742/* Print LIST (a linked list of shell variables) to stdout
743 by printing the names, without the values. Used to support the
744 `set +' command. */
ccc6cda3 745void
726f6388
JA
746print_vars_no_values (list)
747 register SHELL_VAR **list;
748{
749 register int i;
750 register SHELL_VAR *var;
751
752 for (i = 0; list && (var = list[i]); i++)
753 if (!invisible_p (var))
754 printf ("%s\n", var->name);
755}
756#endif
757
758/* Print the value of a single SHELL_VAR. No newline is
759 output, but the variable is printed in such a way that
760 it can be read back in. */
761void
762print_assignment (var)
763 SHELL_VAR *var;
764{
765 if (function_p (var) && var->value)
766 {
767 printf ("%s=", var->name);
768 print_var_function (var);
769 printf ("\n");
770 }
ccc6cda3
JA
771#if defined (ARRAY_VARS)
772 else if (array_p (var) && var->value)
773 print_array_assignment (var, 0);
774#endif /* ARRAY_VARS */
726f6388
JA
775 else if (var->value)
776 {
777 printf ("%s=", var->name);
ccc6cda3 778 print_var_value (var, 1);
726f6388
JA
779 printf ("\n");
780 }
781}
782
783/* Print the value cell of VAR, a shell variable. Do not print
ccc6cda3
JA
784 the name, nor leading/trailing newline. If QUOTE is non-zero,
785 and the value contains shell metacharacters, quote the value
786 in such a way that it can be read back in. */
726f6388 787void
ccc6cda3 788print_var_value (var, quote)
726f6388 789 SHELL_VAR *var;
ccc6cda3 790 int quote;
726f6388 791{
ccc6cda3
JA
792 char *t;
793
726f6388 794 if (var->value)
ccc6cda3
JA
795 {
796 if (quote && contains_shell_metas (var->value))
797 {
798 t = single_quote (var->value);
799 printf ("%s", t);
800 free (t);
801 }
802 else
803 printf ("%s", var->value);
804 }
726f6388
JA
805}
806
807/* Print the function cell of VAR, a shell variable. Do not
808 print the name, nor leading/trailing newline. */
809void
810print_var_function (var)
811 SHELL_VAR *var;
812{
813 if (function_p (var) && var->value)
814 printf ("%s", named_function_string ((char *)NULL, function_cell(var), 1));
815}
816
ccc6cda3
JA
817#if defined (ARRAY_VARS)
818void
819print_array_assignment (var, quoted)
820 SHELL_VAR *var;
821 int quoted;
822{
823 char *vstr;
824
825 if (quoted)
826 vstr = quoted_array_assignment_string (array_cell (var));
827 else
828 vstr = array_to_assignment_string (array_cell (var));
829
830 if (vstr == 0)
831 printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
832 else
833 {
834 printf ("%s=%s\n", var->name, vstr);
835 free (vstr);
836 }
837}
838#endif /* ARRAY_VARS */
839
726f6388 840/* **************************************************************** */
ccc6cda3
JA
841/* */
842/* Dynamic Variable Extension */
843/* */
726f6388
JA
844/* **************************************************************** */
845
846/* DYNAMIC VARIABLES
ccc6cda3 847
726f6388
JA
848 These are variables whose values are generated anew each time they are
849 referenced. These are implemented using a pair of function pointers
850 in the struct variable: assign_func, which is called from bind_variable,
851 and dynamic_value, which is called from find_variable.
ccc6cda3 852
726f6388
JA
853 assign_func is called from bind_variable, if bind_variable discovers
854 that the variable being assigned to has such a function. The function
855 is called as
856 SHELL_VAR *temp = (*(entry->assign_func)) (entry, value)
857 and the (SHELL_VAR *)temp is returned as the value of bind_variable. It
858 is usually ENTRY (self).
ccc6cda3 859
726f6388
JA
860 dynamic_value is called from find_variable to return a `new' value for
861 the specified dynamic varible. If this function is NULL, the variable
862 is treated as a `normal' shell variable. If it is not, however, then
863 this function is called like this:
864 tempvar = (*(var->dynamic_value)) (var);
ccc6cda3 865
726f6388
JA
866 Sometimes `tempvar' will replace the value of `var'. Other times, the
867 shell will simply use the string value. Pretty object-oriented, huh?
ccc6cda3 868
726f6388
JA
869 Be warned, though: if you `unset' a special variable, it loses its
870 special meaning, even if you subsequently set it.
ccc6cda3 871
726f6388
JA
872 The special assignment code would probably have been better put in
873 subst.c: do_assignment, in the same style as
874 stupidly_hack_special_variables, but I wanted the changes as
875 localized as possible. */
876
877/* The value of $SECONDS. This is the number of seconds since shell
878 invocation, or, the number of seconds since the last assignment + the
879 value of the last assignment. */
ccc6cda3 880static long seconds_value_assigned;
726f6388
JA
881
882static SHELL_VAR *
883assign_seconds (self, value)
884 SHELL_VAR *self;
885 char *value;
886{
cce855bc 887 seconds_value_assigned = strtol (value, (char **)NULL, 10);
726f6388
JA
888 shell_start_time = NOW;
889 return (self);
890}
891
892static SHELL_VAR *
893get_seconds (var)
894 SHELL_VAR *var;
895{
896 time_t time_since_start;
897 char *p;
898
899 time_since_start = NOW - shell_start_time;
900 p = itos((int) seconds_value_assigned + time_since_start);
901
902 FREE (var->value);
903
904 var->attributes |= att_integer;
905 var->value = p;
906 return (var);
907}
908
909/* The random number seed. You can change this by setting RANDOM. */
910static unsigned long rseed = 1;
ccc6cda3 911static unsigned long last_random_value;
726f6388
JA
912
913/* A linear congruential random number generator based on the ANSI
cce855bc
JA
914 C standard. This one isn't very good (the values are alternately
915 odd and even, for example), but a more complicated one is overkill. */
726f6388
JA
916
917/* Returns a pseudo-random number between 0 and 32767. */
918static int
919brand ()
920{
921 rseed = rseed * 1103515245 + 12345;
cce855bc 922 return ((unsigned int)(rseed & 32767)); /* was % 32768 */
726f6388
JA
923}
924
925/* Set the random number generator seed to SEED. */
926static void
927sbrand (seed)
928 int seed;
929{
930 rseed = seed;
e8ce775d 931 last_random_value = 0;
726f6388
JA
932}
933
934static SHELL_VAR *
935assign_random (self, value)
936 SHELL_VAR *self;
937 char *value;
938{
ccc6cda3 939 sbrand (atoi (value));
726f6388
JA
940 return (self);
941}
942
943static SHELL_VAR *
944get_random (var)
945 SHELL_VAR *var;
946{
947 int rv;
948 char *p;
949
ccc6cda3
JA
950 /* Reset for command and process substitution. */
951 if (subshell_environment)
e8ce775d 952 sbrand (rseed + (int)(getpid() + NOW));
ccc6cda3
JA
953
954 do
955 rv = brand ();
956 while (rv == (int)last_random_value);
957
958 last_random_value = rv;
726f6388
JA
959 p = itos ((int)rv);
960
961 FREE (var->value);
962
963 var->attributes |= att_integer;
964 var->value = p;
965 return (var);
966}
967
968/* Function which returns the current line number. */
969static SHELL_VAR *
970get_lineno (var)
971 SHELL_VAR *var;
972{
973 char *p;
ccc6cda3 974 int ln;
726f6388 975
ccc6cda3
JA
976 ln = executing_line_number ();
977 p = itos (ln);
726f6388
JA
978 FREE (var->value);
979 var->value = p;
980 return (var);
981}
982
ccc6cda3
JA
983static SHELL_VAR *
984assign_lineno (var, value)
985 SHELL_VAR *var;
986 char *value;
987{
988 line_number = atoi (value);
989 return var;
990}
991
726f6388
JA
992#if defined (HISTORY)
993static SHELL_VAR *
994get_histcmd (var)
995 SHELL_VAR *var;
996{
997 char *p;
998
999 p = itos (history_number ());
1000 FREE (var->value);
1001 var->value = p;
1002 return (var);
1003}
1004#endif
1005
ccc6cda3
JA
1006#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
1007static SHELL_VAR *
1008get_dirstack (self)
1009 SHELL_VAR *self;
1010{
1011 ARRAY *a;
1012 WORD_LIST *l;
1013
1014 l = get_directory_stack ();
1015 a = word_list_to_array (l);
1016 dispose_array (array_cell (self));
d166f048 1017 dispose_words (l);
ccc6cda3
JA
1018 self->value = (char *)a;
1019 return self;
1020}
1021
1022static SHELL_VAR *
1023assign_dirstack (self, ind, value)
1024 SHELL_VAR *self;
1025 int ind;
1026 char *value;
1027{
1028 set_dirstack_element (ind, 1, value);
1029 return self;
1030}
1031#endif /* PUSHD AND POPD && ARRAY_VARS */
1032
d166f048
JA
1033#if defined (ARRAY_VARS)
1034/* We don't want to initialize the group set with a call to getgroups()
1035 unless we're asked to, but we only want to do it once. */
1036static SHELL_VAR *
1037get_groupset (self)
1038 SHELL_VAR *self;
1039{
1040 register int i;
1041 int ng;
1042 ARRAY *a;
1043 static char **group_set = (char **)NULL;
1044
1045 if (group_set == 0)
1046 {
1047 group_set = get_group_list (&ng);
1048 a = array_cell (self);
1049 for (i = 0; i < ng; i++)
1050 array_add_element (a, i, group_set[i]);
1051 }
1052 return (self);
1053}
1054#endif /* ARRAY_VARS */
1055
726f6388
JA
1056static void
1057initialize_dynamic_variables ()
1058{
1059 SHELL_VAR *v;
1060
1061 v = bind_variable ("SECONDS", (char *)NULL);
1062 v->dynamic_value = get_seconds;
1063 v->assign_func = assign_seconds;
1064
1065 v = bind_variable ("RANDOM", (char *)NULL);
1066 v->dynamic_value = get_random;
1067 v->assign_func = assign_random;
1068
1069 v = bind_variable ("LINENO", (char *)NULL);
1070 v->dynamic_value = get_lineno;
ccc6cda3 1071 v->assign_func = assign_lineno;
726f6388
JA
1072
1073#if defined (HISTORY)
1074 v = bind_variable ("HISTCMD", (char *)NULL);
1075 v->dynamic_value = get_histcmd;
1076 v->assign_func = (DYNAMIC_FUNC *)NULL;
1077#endif
ccc6cda3
JA
1078
1079#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
1080 v = make_new_array_variable ("DIRSTACK");
1081 v->dynamic_value = get_dirstack;
1082 v->assign_func = assign_dirstack;
1083#endif /* PUSHD_AND_POPD && ARRAY_VARS */
d166f048
JA
1084
1085#if defined (ARRAY_VARS)
1086 v = make_new_array_variable ("GROUPS");
1087 v->dynamic_value = get_groupset;
1088 v->assign_func = (DYNAMIC_FUNC *)NULL;
1089 v->attributes |= att_readonly;
1090#endif
726f6388
JA
1091}
1092
1093/* How to get a pointer to the shell variable or function named NAME.
1094 HASHED_VARS is a pointer to the hash table containing the list
1095 of interest (either variables or functions). */
1096SHELL_VAR *
1097var_lookup (name, hashed_vars)
1098 char *name;
1099 HASH_TABLE *hashed_vars;
1100{
1101 BUCKET_CONTENTS *bucket;
1102
1103 bucket = find_hash_item (name, hashed_vars);
ccc6cda3 1104 return (bucket ? (SHELL_VAR *)bucket->data : (SHELL_VAR *)NULL);
726f6388
JA
1105}
1106
1107/* Look up the variable entry named NAME. If SEARCH_TEMPENV is non-zero,
1108 then also search the temporarily built list of exported variables. */
1109SHELL_VAR *
1110find_variable_internal (name, search_tempenv)
1111 char *name;
1112 int search_tempenv;
1113{
1114 SHELL_VAR *var = (SHELL_VAR *)NULL;
1115
1116 /* If explicitly requested, first look in the temporary environment for
1117 the variable. This allows constructs such as "foo=x eval 'echo $foo'"
1118 to get the `exported' value of $foo. This happens if we are executing
1119 a function or builtin, or if we are looking up a variable in a
1120 "subshell environment". */
1121 if ((search_tempenv || subshell_environment) &&
1122 (temporary_env || builtin_env || function_env))
1123 var = find_tempenv_variable (name);
1124
1125 if (!var)
1126 var = var_lookup (name, shell_variables);
1127
1128 if (!var)
1129 return ((SHELL_VAR *)NULL);
1130
ccc6cda3 1131 return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
726f6388
JA
1132}
1133
1134/* Look up the variable entry named NAME. Returns the entry or NULL. */
1135SHELL_VAR *
1136find_variable (name)
1137 char *name;
1138{
1139 return (find_variable_internal
1140 (name, (variable_context || this_shell_builtin || builtin_env)));
1141}
1142
1143/* Look up the function entry whose name matches STRING.
1144 Returns the entry or NULL. */
1145SHELL_VAR *
1146find_function (name)
1147 char *name;
1148{
1149 return (var_lookup (name, shell_functions));
1150}
1151
1152/* Return the string value of a variable. Return NULL if the variable
1153 doesn't exist, or only has a function as a value. Don't cons a new
cce855bc
JA
1154 string. This is a potential memory leak if the variable is found
1155 in the temporary environment. */
726f6388
JA
1156char *
1157get_string_value (var_name)
1158 char *var_name;
1159{
d166f048
JA
1160 SHELL_VAR *var;
1161
1162 var = find_variable (var_name);
726f6388
JA
1163
1164 if (!var)
1165 return (char *)NULL;
ccc6cda3
JA
1166#if defined (ARRAY_VARS)
1167 else if (array_p (var))
1168 return (array_reference (array_cell (var), 0));
1169#endif
726f6388
JA
1170 else
1171 return (var->value);
1172}
1173
1174/* Create a local variable referenced by NAME. */
1175SHELL_VAR *
1176make_local_variable (name)
1177 char *name;
1178{
1179 SHELL_VAR *new_var, *old_var;
1180 BUCKET_CONTENTS *elt;
1181
1182 /* local foo; local foo; is a no-op. */
1183 old_var = find_variable (name);
1184 if (old_var && old_var->context == variable_context)
1185 return (old_var);
1186
1187 elt = remove_hash_item (name, shell_variables);
1188 if (elt)
1189 {
1190 old_var = (SHELL_VAR *)elt->data;
1191 free (elt->key);
1192 free (elt);
1193 }
1194 else
1195 old_var = (SHELL_VAR *)NULL;
1196
1197 /* If a variable does not already exist with this name, then
1198 just make a new one. */
d166f048
JA
1199 if (old_var == 0)
1200 new_var = bind_variable (name, "");
726f6388
JA
1201 else
1202 {
1203 new_var = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
1204
1205 new_var->name = savestring (name);
ccc6cda3
JA
1206 new_var->value = xmalloc (1);
1207 new_var->value[0] = '\0';
726f6388
JA
1208
1209 new_var->dynamic_value = (DYNAMIC_FUNC *)NULL;
1210 new_var->assign_func = (DYNAMIC_FUNC *)NULL;
1211
ccc6cda3 1212 new_var->attributes = exported_p (old_var) ? att_exported : 0;
726f6388
JA
1213
1214 new_var->prev_context = old_var;
1215 elt = add_hash_item (savestring (name), shell_variables);
1216 elt->data = (char *)new_var;
1217 }
1218
1219 new_var->context = variable_context;
ccc6cda3 1220 new_var->attributes |= att_local;
726f6388
JA
1221
1222 /* XXX */
ccc6cda3 1223 if (variable_context >= local_variable_stack_size)
726f6388
JA
1224 {
1225 int old_size = local_variable_stack_size;
ccc6cda3
JA
1226 RESIZE_MALLOCED_BUFFER (have_local_variables, variable_context, 1,
1227 local_variable_stack_size, 8);
726f6388
JA
1228 bzero ((char *)have_local_variables + old_size,
1229 local_variable_stack_size - old_size);
1230 }
1231 have_local_variables[variable_context] = 1; /* XXX */
1232
1233 return (new_var);
1234}
1235
ccc6cda3 1236#if defined (ARRAY_VARS)
726f6388 1237SHELL_VAR *
ccc6cda3
JA
1238make_local_array_variable (name)
1239 char *name;
1240{
1241 SHELL_VAR *var;
1242 ARRAY *array;
1243
1244 var = make_local_variable (name);
1245 array = new_array ();
1246
1247 FREE (value_cell(var));
1248 var->value = (char *)array;
1249 var->attributes |= att_array;
1250 return var;
1251}
1252#endif /* ARRAY_VARS */
1253
1254/* Create a new shell variable with name NAME and add it to the hash table
1255 of shell variables. */
1256static
1257SHELL_VAR *
1258make_new_variable (name)
1259 char *name;
726f6388 1260{
ccc6cda3 1261 SHELL_VAR *entry;
726f6388
JA
1262 BUCKET_CONTENTS *elt;
1263
ccc6cda3 1264 entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
726f6388 1265
ccc6cda3
JA
1266 entry->attributes = 0;
1267 entry->name = savestring (name);
1268 entry->value = (char *)NULL;
726f6388 1269
ccc6cda3
JA
1270 entry->dynamic_value = (DYNAMIC_FUNC *)NULL;
1271 entry->assign_func = (DYNAMIC_FUNC *)NULL;
1272
1273 /* Always assume variables are to be made at toplevel!
1274 make_local_variable has the responsibilty of changing the
1275 variable context. */
1276 entry->context = 0;
1277 entry->prev_context = (SHELL_VAR *)NULL;
1278
1279 elt = add_hash_item (savestring (name), shell_variables);
1280 elt->data = (char *)entry;
1281
1282 return entry;
1283}
1284
1285#if defined (ARRAY_VARS)
1286SHELL_VAR *
1287make_new_array_variable (name)
1288 char *name;
1289{
1290 SHELL_VAR *entry;
1291 ARRAY *array;
1292
1293 entry = make_new_variable (name);
1294 array = new_array ();
1295 entry->value = (char *)array;
1296 entry->attributes |= att_array;
1297 return entry;
1298}
1299#endif
1300
1301char *
1302make_variable_value (var, value)
1303 SHELL_VAR *var;
1304 char *value;
1305{
1306 char *retval;
1307 long lval;
d166f048 1308 int expok;
ccc6cda3
JA
1309
1310 /* If this variable has had its type set to integer (via `declare -i'),
1311 then do expression evaluation on it and store the result. The
1312 functions in expr.c (evalexp and bind_int_variable) are responsible
1313 for turning off the integer flag if they don't want further
1314 evaluation done. */
1315 if (integer_p (var))
1316 {
d166f048
JA
1317 lval = evalexp (value, &expok);
1318 if (expok == 0)
1319 jump_to_top_level (DISCARD);
ccc6cda3
JA
1320 retval = itos (lval);
1321 }
1322 else if (value)
1323 {
1324 if (*value)
1325 retval = savestring (value);
1326 else
726f6388 1327 {
ccc6cda3
JA
1328 retval = xmalloc (1);
1329 retval[0] = '\0';
726f6388 1330 }
ccc6cda3
JA
1331 }
1332 else
1333 retval = (char *)NULL;
726f6388 1334
ccc6cda3
JA
1335 return retval;
1336}
726f6388 1337
ccc6cda3
JA
1338/* Bind a variable NAME to VALUE. This conses up the name
1339 and value strings. */
1340SHELL_VAR *
1341bind_variable (name, value)
1342 char *name, *value;
1343{
1344 char *newval;
1345 SHELL_VAR *entry;
726f6388 1346
ccc6cda3
JA
1347 entry = var_lookup (name, shell_variables);
1348
1349 if (entry == 0)
1350 {
1351 entry = make_new_variable (name);
1352 entry->value = make_variable_value (entry, value);
726f6388 1353 }
ccc6cda3
JA
1354#if defined (ARRAY_VARS)
1355 else if (entry->assign_func && array_p (entry) == 0)
1356#else
726f6388 1357 else if (entry->assign_func)
ccc6cda3 1358#endif
726f6388
JA
1359 return ((*(entry->assign_func)) (entry, value));
1360 else
1361 {
1362 if (readonly_p (entry))
1363 {
ccc6cda3 1364 report_error ("%s: readonly variable", name);
726f6388
JA
1365 return (entry);
1366 }
1367
1368 /* Variables which are bound are visible. */
1369 entry->attributes &= ~att_invisible;
1370
ccc6cda3 1371 newval = make_variable_value (entry, value);
726f6388 1372
ccc6cda3
JA
1373#if defined (ARRAY_VARS)
1374 /* XXX -- this bears looking at again -- XXX */
1375 /* If an existing array variable x is being assigned to with x=b or
1376 `read x' or something of that nature, silently convert it to
1377 x[0]=b or `read x[0]'. */
1378 if (array_p (entry))
d166f048
JA
1379 {
1380 array_add_element (array_cell (entry), 0, newval);
1381 free (newval);
1382 }
726f6388
JA
1383 else
1384 {
1385 FREE (entry->value);
ccc6cda3 1386 entry->value = newval;
726f6388 1387 }
ccc6cda3
JA
1388#else
1389 FREE (entry->value);
1390 entry->value = newval;
1391#endif
726f6388
JA
1392 }
1393
1394 if (mark_modified_vars)
1395 entry->attributes |= att_exported;
1396
1397 if (exported_p (entry))
1398 array_needs_making = 1;
1399
1400 return (entry);
1401}
1402
ccc6cda3
JA
1403#if defined (ARRAY_VARS)
1404/* Convert a shell variable to an array variable. The original value is
1405 saved as array[0]. */
1406SHELL_VAR *
1407convert_var_to_array (var)
1408 SHELL_VAR *var;
1409{
1410 char *oldval;
1411 ARRAY *array;
1412
1413 oldval = value_cell (var);
1414 array = new_array ();
1415 array_add_element (array, 0, oldval);
1416 FREE (value_cell (var));
1417 var->value = (char *)array;
1418 var->attributes |= att_array;
1419 var->attributes &= ~att_invisible;
1420
1421 return var;
1422}
1423
1424/* Perform an array assignment name[ind]=value. If NAME already exists and
1425 is not an array, and IND is 0, perform name=value instead. If NAME exists
1426 and is not an array, and IND is not 0, convert it into an array with the
1427 existing value as name[0].
1428
1429 If NAME does not exist, just create an array variable, no matter what
1430 IND's value may be. */
1431SHELL_VAR *
1432bind_array_variable (name, ind, value)
1433 char *name;
1434 int ind;
1435 char *value;
1436{
1437 SHELL_VAR *entry;
1438 char *newval;
1439
1440 entry = var_lookup (name, shell_variables);
1441
1442 if (entry == (SHELL_VAR *) 0)
1443 entry = make_new_array_variable (name);
1444 else if (readonly_p (entry))
1445 {
1446 report_error ("%s: readonly variable", name);
1447 return (entry);
1448 }
1449 else if (array_p (entry) == 0)
1450 entry = convert_var_to_array (entry);
1451
1452 /* ENTRY is an array variable, and ARRAY points to the value. */
1453 newval = make_variable_value (entry, value);
1454 if (entry->assign_func)
1455 (*entry->assign_func) (entry, ind, newval);
1456 else
1457 array_add_element (array_cell (entry), ind, newval);
1458 FREE (newval);
1459
1460 return (entry);
1461}
1462
cce855bc
JA
1463/* Perform a compound assignment statement for array NAME, where VALUE is
1464 the text between the parens: NAME=( VALUE ) */
ccc6cda3
JA
1465SHELL_VAR *
1466assign_array_from_string (name, value)
1467 char *name, *value;
1468{
1469 SHELL_VAR *var;
1470
1471 var = find_variable (name);
1472 if (var == 0)
1473 var = make_new_array_variable (name);
d166f048
JA
1474 else if (readonly_p (var))
1475 {
1476 report_error ("%s: readonly variable", name);
1477 return ((SHELL_VAR *)NULL);
1478 }
ccc6cda3
JA
1479 else if (array_p (var) == 0)
1480 var = convert_var_to_array (var);
1481
1482 return (assign_array_var_from_string (var, value));
1483}
1484
1485SHELL_VAR *
1486assign_array_var_from_word_list (var, list)
1487 SHELL_VAR *var;
1488 WORD_LIST *list;
1489{
1490 register int i;
1491 register WORD_LIST *l;
1492 ARRAY *a;
1493
1494 for (a = array_cell (var), l = list, i = 0; l; l = l->next, i++)
1495 if (var->assign_func)
1496 (*var->assign_func) (var, i, l->word->word);
1497 else
1498 array_add_element (a, i, l->word->word);
1499 return var;
1500}
1501
cce855bc
JA
1502/* Perform a compound array assignment: VAR->name=( VALUE ). The
1503 VALUE has already had the parentheses stripped. */
ccc6cda3
JA
1504SHELL_VAR *
1505assign_array_var_from_string (var, value)
1506 SHELL_VAR *var;
1507 char *value;
1508{
1509 ARRAY *a;
1510 WORD_LIST *list, *nlist;
1511 char *w, *val, *nval;
1512 int ni, len, ind, last_ind;
1513
cce855bc
JA
1514 if (value == 0)
1515 return var;
ccc6cda3 1516
cce855bc
JA
1517 /* If this is called from declare_builtin, value[0] == '(' and
1518 strchr(value, ')') != 0. In this case, we need to extract
1519 the value from between the parens before going on. */
1520 if (*value == '(') /*)*/
ccc6cda3
JA
1521 {
1522 ni = 1;
1523 val = extract_array_assignment_list (value, &ni);
1524 if (val == 0)
cce855bc 1525 return var;
ccc6cda3
JA
1526 }
1527 else
cce855bc 1528 val = value;
ccc6cda3 1529
cce855bc
JA
1530 /* Expand the value string into a list of words, performing all the
1531 shell expansions including word splitting. */
e8ce775d 1532#if 1
cce855bc
JA
1533 /* First we split the string on whitespace, using the shell parser
1534 (ksh93 seems to do this). */
1535 list = parse_string_to_word_list (val, "array assign");
1536 /* Now that we've split it, perform the shell expansions on each
1537 word in the list. */
1538 nlist = list ? expand_words_shellexp (list) : (WORD_LIST *)NULL;
1539 dispose_words (list);
1540#else
1541 nlist = expand_string (val, 0);
1542#endif
1543
1544 if (val != value)
1545 free (val);
1546
1547 a = array_cell (var);
1548
e8ce775d
JA
1549 /* Now that we are ready to assign values to the array, kill the existing
1550 value. */
1551 if (a)
1552 empty_array (a);
e8ce775d 1553
ccc6cda3
JA
1554 for (last_ind = 0, list = nlist; list; list = list->next)
1555 {
1556 w = list->word->word;
1557
1558 /* We have a word of the form [ind]=value */
1559 if (w[0] == '[')
1560 {
1561 len = skipsubscript (w, 0);
1562
1563 if (w[len] != ']' || w[len+1] != '=')
1564 {
1565 nval = make_variable_value (var, w);
1566 if (var->assign_func)
1567 (*var->assign_func) (var, last_ind, nval);
1568 else
1569 array_add_element (a, last_ind, nval);
1570 FREE (nval);
1571 last_ind++;
1572 continue;
1573 }
1574
1575 if (len == 1)
1576 {
1577 report_error ("%s: bad array subscript", w);
1578 continue;
1579 }
1580
1581 if (ALL_ELEMENT_SUB (w[1]) && len == 2)
1582 {
1583 report_error ("%s: cannot assign to non-numeric index", w);
1584 continue;
1585 }
1586
1587 ind = array_expand_index (w + 1, len);
1588 if (ind < 0)
1589 {
1590 report_error ("%s: bad array subscript", w);
1591 continue;
1592 }
1593 last_ind = ind;
1594 val = w + len + 2;
1595 }
1596 else /* No [ind]=value, just a stray `=' */
1597 {
1598 ind = last_ind;
1599 val = w;
1600 }
1601
1602 if (integer_p (var))
1603 this_command_name = (char *)NULL; /* no command name for errors */
1604 nval = make_variable_value (var, val);
1605 if (var->assign_func)
1606 (*var->assign_func) (var, ind, nval);
1607 else
1608 array_add_element (a, ind, nval);
1609 FREE (nval);
1610 last_ind++;
1611 }
1612
1613 dispose_words (nlist);
1614 return (var);
1615}
1616#endif /* ARRAY_VARS */
1617
726f6388
JA
1618/* Dispose of the information attached to VAR. */
1619void
1620dispose_variable (var)
1621 SHELL_VAR *var;
1622{
1623 if (!var)
1624 return;
1625
1626 if (function_p (var))
ccc6cda3
JA
1627 dispose_command (function_cell (var));
1628#if defined (ARRAY_VARS)
1629 else if (array_p (var))
1630 dispose_array (array_cell (var));
1631#endif
1632 else
1633 FREE (value_cell (var));
726f6388
JA
1634
1635 free (var->name);
1636
1637 if (exported_p (var))
1638 array_needs_making = 1;
1639
1640 free (var);
1641}
1642
ccc6cda3
JA
1643#if defined (ARRAY_VARS)
1644/* This function is called with SUB pointing to just after the beginning
1645 `[' of an array subscript. */
1646int
1647unbind_array_element (var, sub)
1648 SHELL_VAR *var;
1649 char *sub;
1650{
1651 int len, ind;
1652 ARRAY_ELEMENT *ae;
1653
1654 len = skipsubscript (sub, 0);
1655 if (sub[len] != ']' || len == 0)
1656 {
1657 builtin_error ("%s[%s: bad array subscript", var->name, sub);
1658 return -1;
1659 }
1660 sub[len] = '\0';
1661
1662 if (ALL_ELEMENT_SUB (sub[0]) && sub[1] == 0)
1663 {
1664 makunbound (var->name, shell_variables);
1665 return (0);
1666 }
1667 ind = array_expand_index (sub, len+1);
1668 if (ind < 0)
1669 {
d166f048 1670 builtin_error ("[%s]: bad array subscript", sub);
ccc6cda3
JA
1671 return -1;
1672 }
1673 ae = array_delete_element (array_cell (var), ind);
1674 if (ae)
1675 destroy_array_element (ae);
1676 return 0;
1677}
1678#endif
1679
726f6388 1680/* Unset the variable referenced by NAME. */
ccc6cda3 1681int
726f6388
JA
1682unbind_variable (name)
1683 char *name;
1684{
cce855bc 1685 SHELL_VAR *var;
726f6388 1686
cce855bc 1687 var = find_variable (name);
726f6388
JA
1688 if (!var)
1689 return (-1);
1690
ccc6cda3
JA
1691 /* This function should never be called with an array variable name. */
1692#if defined (ARRAY_VARS)
1693 if (array_p (var) == 0 && var->value)
1694#else
726f6388 1695 if (var->value)
ccc6cda3 1696#endif
726f6388
JA
1697 {
1698 free (var->value);
1699 var->value = (char *)NULL;
1700 }
1701
1702 makunbound (name, shell_variables);
1703
1704 return (0);
1705}
1706
1707/* Make the variable associated with NAME go away. HASH_LIST is the
1708 hash table from which this variable should be deleted (either
1709 shell_variables or shell_functions).
1710 Returns non-zero if the variable couldn't be found. */
ccc6cda3 1711int
726f6388
JA
1712makunbound (name, hash_list)
1713 char *name;
1714 HASH_TABLE *hash_list;
1715{
d166f048 1716 BUCKET_CONTENTS *elt, *new_elt;
726f6388
JA
1717 SHELL_VAR *old_var, *new_var;
1718 char *t;
1719
1720 elt = remove_hash_item (name, hash_list);
1721
d166f048 1722 if (elt == 0)
726f6388
JA
1723 return (-1);
1724
1725 old_var = (SHELL_VAR *)elt->data;
1726 new_var = old_var->prev_context;
1727
1728 if (old_var && exported_p (old_var))
1729 array_needs_making++;
1730
ccc6cda3
JA
1731 /* If we're unsetting a local variable and we're still executing inside
1732 the function, just mark the variable as invisible.
1733 kill_all_local_variables will clean it up later. This must be done
1734 so that if the variable is subsequently assigned a new value inside
1735 the function, the `local' attribute is still present. We also need
1736 to add it back into the correct hash table. */
1737 if (old_var && local_p (old_var) && variable_context == old_var->context)
1738 {
1739 old_var->attributes |= att_invisible;
d166f048
JA
1740 new_elt = add_hash_item (savestring (old_var->name), hash_list);
1741 new_elt->data = (char *)old_var;
ccc6cda3 1742 stupidly_hack_special_variables (old_var->name);
d166f048
JA
1743 free (elt->key);
1744 free (elt);
ccc6cda3
JA
1745 return (0);
1746 }
1747
726f6388
JA
1748 if (new_var)
1749 {
1750 /* Has to be a variable, functions don't have previous contexts. */
726f6388
JA
1751 new_elt = add_hash_item (savestring (new_var->name), hash_list);
1752 new_elt->data = (char *)new_var;
1753
1754 if (exported_p (new_var))
ccc6cda3 1755 set_auto_export (new_var);
726f6388
JA
1756 }
1757
1758 /* Have to save a copy of name here, because it might refer to
1759 old_var->name. If so, stupidly_hack_special_variables will
1760 reference freed memory. */
1761 t = savestring (name);
1762
1763 free (elt->key);
1764 free (elt);
1765
1766 dispose_variable (old_var);
1767 stupidly_hack_special_variables (t);
1768 free (t);
1769 return (0);
1770}
1771
d166f048 1772#ifdef INCLUDE_UNUSED
726f6388
JA
1773/* Remove the variable with NAME if it is a local variable in the
1774 current context. */
ccc6cda3 1775int
726f6388
JA
1776kill_local_variable (name)
1777 char *name;
1778{
d166f048 1779 SHELL_VAR *temp;
726f6388 1780
d166f048 1781 temp = find_variable (name);
ccc6cda3 1782 if (temp && temp->context == variable_context)
726f6388
JA
1783 {
1784 makunbound (name, shell_variables);
1785 return (0);
1786 }
1787 return (-1);
1788}
d166f048 1789#endif
726f6388
JA
1790
1791/* Get rid of all of the variables in the current context. */
1792int
1793variable_in_context (var)
1794 SHELL_VAR *var;
1795{
1796 return (var && var->context == variable_context);
1797}
1798
1799void
1800kill_all_local_variables ()
1801{
1802 register int i, pass;
1803 register SHELL_VAR *var, **list;
1804 HASH_TABLE *varlist;
1805
ccc6cda3
JA
1806 /* If HAVE_LOCAL_VARIABLES == 0, it means that we don't have any local
1807 variables at all. If VARIABLE_CONTEXT >= LOCAL_VARIABLE_STACK_SIZE,
1808 it means that we have some local variables, but not in this variable
1809 context (level of function nesting). Also, if
1810 HAVE_LOCAL_VARIABLES[VARIABLE_CONTEXT] == 0, we have no local variables
1811 at this context. */
1812 if (have_local_variables == 0 ||
1813 variable_context >= local_variable_stack_size ||
1814 have_local_variables[variable_context] == 0)
726f6388
JA
1815 return;
1816
1817 for (pass = 0; pass < 2; pass++)
1818 {
1819 varlist = pass ? shell_functions : shell_variables;
1820
1821 list = map_over (variable_in_context, varlist);
1822
1823 if (list)
1824 {
1825 for (i = 0; var = list[i]; i++)
ccc6cda3
JA
1826 {
1827 var->attributes &= ~att_local;
1828 makunbound (var->name, varlist);
1829 }
726f6388
JA
1830 free (list);
1831 }
1832 }
1833
1834 have_local_variables[variable_context] = 0; /* XXX */
1835}
1836
ccc6cda3
JA
1837static void
1838free_variable_hash_data (data)
1839 char *data;
1840{
1841 SHELL_VAR *var, *prev;
1842
1843 var = (SHELL_VAR *)data;
1844 while (var)
1845 {
1846 prev = var->prev_context;
1847 dispose_variable (var);
1848 var = prev;
1849 }
1850}
1851
726f6388
JA
1852/* Delete the entire contents of the hash table. */
1853void
1854delete_all_variables (hashed_vars)
1855 HASH_TABLE *hashed_vars;
1856{
ccc6cda3 1857 flush_hash_table (hashed_vars, free_variable_hash_data);
726f6388
JA
1858}
1859
1860static SHELL_VAR *
1861new_shell_variable (name)
1862 char *name;
1863{
1864 SHELL_VAR *var;
1865
1866 var = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
1867
1868 bzero ((char *)var, sizeof (SHELL_VAR));
1869 var->name = savestring (name);
1870 return (var);
1871}
1872
1873/* Do a function binding to a variable. You pass the name and
1874 the command to bind to. This conses the name and command. */
1875SHELL_VAR *
1876bind_function (name, value)
1877 char *name;
1878 COMMAND *value;
1879{
ccc6cda3 1880 SHELL_VAR *entry;
726f6388 1881
ccc6cda3 1882 entry = find_function (name);
726f6388
JA
1883 if (!entry)
1884 {
1885 BUCKET_CONTENTS *elt;
1886
1887 elt = add_hash_item (savestring (name), shell_functions);
1888
1889 elt->data = (char *)new_shell_variable (name);
1890 entry = (SHELL_VAR *)elt->data;
ccc6cda3 1891 entry->dynamic_value = entry->assign_func = (DYNAMIC_FUNC *)NULL;
726f6388
JA
1892
1893 /* Functions are always made at the top level. This allows a
1894 function to define another function (like autoload). */
1895 entry->context = 0;
1896 }
1897
1898 if (entry->value)
1899 dispose_command ((COMMAND *)entry->value);
1900
ccc6cda3 1901 entry->value = value ? (char *)copy_command (value) : (char *)NULL;
726f6388
JA
1902 entry->attributes |= att_function;
1903
1904 if (mark_modified_vars)
1905 entry->attributes |= att_exported;
1906
1907 entry->attributes &= ~att_invisible; /* Just to be sure */
1908
ccc6cda3
JA
1909 if (exported_p (entry))
1910 array_needs_making = 1;
726f6388
JA
1911
1912 return (entry);
1913}
1914
d166f048 1915#ifdef INCLUDE_UNUSED
726f6388
JA
1916/* Copy VAR to a new data structure and return that structure. */
1917SHELL_VAR *
1918copy_variable (var)
1919 SHELL_VAR *var;
1920{
1921 SHELL_VAR *copy = (SHELL_VAR *)NULL;
1922
1923 if (var)
1924 {
1925 copy = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
1926
1927 copy->attributes = var->attributes;
1928 copy->name = savestring (var->name);
1929
1930 if (function_p (var))
ccc6cda3
JA
1931 copy->value = (char *)copy_command (function_cell (var));
1932#if defined (ARRAY_VARS)
1933 else if (array_p (var))
1934 copy->value = (char *)dup_array (array_cell (var));
1935#endif
1936 else if (value_cell (var))
1937 copy->value = savestring (value_cell (var));
726f6388
JA
1938 else
1939 copy->value = (char *)NULL;
1940
1941 copy->dynamic_value = var->dynamic_value;
1942 copy->assign_func = var->assign_func;
1943
1944 copy->context = var->context;
1945
1946 /* Don't bother copying previous contexts along with this variable. */
1947 copy->prev_context = (SHELL_VAR *)NULL;
1948 }
1949 return (copy);
1950}
d166f048 1951#endif
726f6388 1952
ccc6cda3
JA
1953#define FIND_OR_MAKE_VARIABLE(name, entry) \
1954 do \
1955 { \
1956 entry = find_variable (name); \
1957 if (!entry) \
1958 { \
1959 entry = bind_variable (name, ""); \
1960 if (!no_invisible_vars) entry->attributes |= att_invisible; \
1961 } \
1962 } \
1963 while (0)
1964
1965/* Make the variable associated with NAME be readonly.
726f6388
JA
1966 If NAME does not exist yet, create it. */
1967void
1968set_var_read_only (name)
1969 char *name;
1970{
ccc6cda3 1971 SHELL_VAR *entry;
726f6388 1972
ccc6cda3 1973 FIND_OR_MAKE_VARIABLE (name, entry);
726f6388
JA
1974 entry->attributes |= att_readonly;
1975}
1976
cce855bc 1977#ifdef INCLUDE_UNUSED
ccc6cda3 1978/* Make the function associated with NAME be readonly.
726f6388
JA
1979 If NAME does not exist, we just punt, like auto_export code below. */
1980void
1981set_func_read_only (name)
1982 char *name;
1983{
d166f048 1984 SHELL_VAR *entry;
726f6388 1985
d166f048 1986 entry = find_function (name);
726f6388
JA
1987 if (entry)
1988 entry->attributes |= att_readonly;
1989}
1990
1991/* Make the variable associated with NAME be auto-exported.
1992 If NAME does not exist yet, create it. */
1993void
1994set_var_auto_export (name)
1995 char *name;
1996{
ccc6cda3 1997 SHELL_VAR *entry;
726f6388 1998
ccc6cda3 1999 FIND_OR_MAKE_VARIABLE (name, entry);
726f6388
JA
2000 set_auto_export (entry);
2001}
2002
2003/* Make the function associated with NAME be auto-exported. */
2004void
2005set_func_auto_export (name)
2006 char *name;
2007{
ccc6cda3 2008 SHELL_VAR *entry;
726f6388 2009
ccc6cda3 2010 entry = find_function (name);
726f6388 2011 if (entry)
ccc6cda3
JA
2012 set_auto_export (entry);
2013}
cce855bc 2014#endif
ccc6cda3
JA
2015
2016#if defined (ARRAY_VARS)
2017/* This function assumes s[i] == '['; returns with s[ret] == ']' if
2018 an array subscript is correctly parsed. */
2019int
2020skipsubscript (s, i)
2021 char *s;
2022 int i;
2023{
2024 int count, c;
2025
2026 for (count = 1; count && (c = s[++i]); )
726f6388 2027 {
ccc6cda3
JA
2028 if (c == '[')
2029 count++;
2030 else if (c == ']')
2031 count--;
726f6388 2032 }
ccc6cda3 2033 return i;
726f6388 2034}
ccc6cda3 2035#endif /* ARRAY_VARS */
726f6388
JA
2036
2037/* Returns non-zero if STRING is an assignment statement. The returned value
2038 is the index of the `=' sign. */
ccc6cda3 2039int
726f6388
JA
2040assignment (string)
2041 char *string;
2042{
ccc6cda3 2043 register int c, newi, indx;
726f6388 2044
ccc6cda3 2045 c = string[indx = 0];
726f6388 2046
ccc6cda3 2047 if (legal_variable_starter (c) == 0)
726f6388
JA
2048 return (0);
2049
2050 while (c = string[indx])
2051 {
2052 /* The following is safe. Note that '=' at the start of a word
2053 is not an assignment statement. */
2054 if (c == '=')
2055 return (indx);
2056
ccc6cda3
JA
2057#if defined (ARRAY_VARS)
2058 if (c == '[')
2059 {
2060 newi = skipsubscript (string, indx);
2061 if (string[newi++] != ']')
2062 return (0);
2063 return ((string[newi] == '=') ? newi : 0);
2064 }
2065#endif /* ARRAY_VARS */
2066
2067 /* Variable names in assignment statements may contain only letters,
2068 digits, and `_'. */
2069 if (legal_variable_char (c) == 0)
726f6388
JA
2070 return (0);
2071
2072 indx++;
2073 }
2074 return (0);
2075}
2076
cce855bc
JA
2077#ifdef READLINE
2078
726f6388
JA
2079static int
2080visible_var (var)
2081 SHELL_VAR *var;
2082{
ccc6cda3 2083 return (invisible_p (var) == 0);
726f6388
JA
2084}
2085
ccc6cda3
JA
2086static SHELL_VAR **
2087_visible_names (table)
2088 HASH_TABLE *table;
726f6388
JA
2089{
2090 SHELL_VAR **list;
2091
ccc6cda3 2092 list = map_over (visible_var, table);
726f6388 2093
d166f048 2094 if (list /* && posixly_correct */)
726f6388
JA
2095 sort_variables (list);
2096
2097 return (list);
2098}
2099
2100SHELL_VAR **
ccc6cda3 2101all_visible_variables ()
726f6388 2102{
ccc6cda3
JA
2103 return (_visible_names (shell_variables));
2104}
726f6388 2105
ccc6cda3
JA
2106SHELL_VAR **
2107all_visible_functions ()
2108{
2109 return (_visible_names (shell_functions));
726f6388
JA
2110}
2111
cce855bc
JA
2112#endif /* READLINE */
2113
ccc6cda3
JA
2114/* Return non-zero if the variable VAR is visible and exported. Array
2115 variables cannot be exported. */
726f6388
JA
2116static int
2117visible_and_exported (var)
2118 SHELL_VAR *var;
2119{
ccc6cda3 2120 return (invisible_p (var) == 0 && exported_p (var));
726f6388
JA
2121}
2122
2123/* Make an array of assignment statements from the hash table
2124 HASHED_VARS which contains SHELL_VARs. Only visible, exported
2125 variables are eligible. */
2126char **
2127make_var_array (hashed_vars)
2128 HASH_TABLE *hashed_vars;
2129{
2130 register int i, list_index;
2131 register SHELL_VAR *var;
ccc6cda3 2132 char **list, *value;
726f6388
JA
2133 SHELL_VAR **vars;
2134
2135 vars = map_over (visible_and_exported, hashed_vars);
2136
d166f048 2137 if (vars == 0)
726f6388
JA
2138 return (char **)NULL;
2139
2140 list = (char **)xmalloc ((1 + array_len ((char **)vars)) * sizeof (char *));
2141
2142 for (i = 0, list_index = 0; var = vars[i]; i++)
2143 {
726f6388 2144 if (function_p (var))
ccc6cda3
JA
2145 value = named_function_string ((char *)NULL, function_cell (var), 0);
2146#if defined (ARRAY_VARS)
2147 else if (array_p (var))
2148# if 0
2149 value = array_to_assignment_string (array_cell (var));
2150# else
2151 continue; /* XXX array vars cannot yet be exported */
2152# endif
2153#endif
726f6388
JA
2154 else
2155 value = value_cell (var);
2156
2157 if (value)
2158 {
ccc6cda3 2159 int name_len, value_len;
726f6388
JA
2160 char *p;
2161
ccc6cda3
JA
2162 name_len = strlen (var->name);
2163 value_len = strlen (value);
726f6388
JA
2164 p = list[list_index] = xmalloc (2 + name_len + value_len);
2165 strcpy (p, var->name);
2166 p[name_len] = '=';
2167 strcpy (p + name_len + 1, value);
2168 list_index++;
ccc6cda3
JA
2169#if defined (ARRAY_VARS)
2170 if (array_p (var))
2171 free (value);
2172#endif
726f6388
JA
2173 }
2174 }
2175
2176 free (vars);
2177 list[list_index] = (char *)NULL;
2178 return (list);
2179}
2180
2181/* Add STRING to the array of foo=bar strings that we already
2182 have to add to the environment. */
ccc6cda3 2183int
726f6388
JA
2184assign_in_env (string)
2185 char *string;
2186{
ccc6cda3
JA
2187 int size, offset;
2188 char *name, *temp, *value;
726f6388 2189 int nlen, vlen;
ccc6cda3
JA
2190 WORD_LIST *list;
2191 SHELL_VAR *var;
2192
2193 offset = assignment (string);
2194 name = savestring (string);
2195 value = (char *)NULL;
726f6388
JA
2196
2197 if (name[offset] == '=')
2198 {
726f6388 2199 name[offset] = 0;
ccc6cda3
JA
2200
2201 var = find_variable (name);
2202 if (var && readonly_p (var))
2203 {
2204 report_error ("%s: readonly variable", name);
d166f048 2205 free (name);
ccc6cda3
JA
2206 return (0);
2207 }
726f6388 2208 temp = name + offset + 1;
cce855bc 2209 temp = (strchr (temp, '~') != 0) ? bash_tilde_expand (temp) : savestring (temp);
726f6388
JA
2210
2211 list = expand_string_unsplit (temp, 0);
2212 value = string_list (list);
2213
2214 if (list)
2215 dispose_words (list);
2216
cce855bc 2217 free (temp);
726f6388 2218 }
726f6388
JA
2219
2220 nlen = strlen (name);
ccc6cda3 2221 vlen = value ? strlen (value) : 0;
726f6388
JA
2222 temp = xmalloc (2 + nlen + vlen);
2223 strcpy (temp, name);
2224 temp[nlen] = '=';
ccc6cda3
JA
2225 temp[nlen + 1] = '\0';
2226 if (value)
2227 {
2228 if (*value)
2229 strcpy (temp + nlen + 1, value);
2230 free (value);
2231 }
726f6388 2232 free (name);
726f6388 2233
ccc6cda3 2234 if (temporary_env == 0)
726f6388
JA
2235 {
2236 temporary_env = (char **)xmalloc (sizeof (char *));
2237 temporary_env [0] = (char *)NULL;
2238 }
2239
2240 size = array_len (temporary_env);
2241 temporary_env = (char **)
2242 xrealloc (temporary_env, (size + 2) * (sizeof (char *)));
2243
ccc6cda3 2244 temporary_env[size] = temp;
726f6388
JA
2245 temporary_env[size + 1] = (char *)NULL;
2246 array_needs_making = 1;
2247
2248 if (echo_command_at_execute)
2249 {
ccc6cda3 2250 /* The Korn shell prints the `+ ' in front of assignment statements,
726f6388
JA
2251 so we do too. */
2252 fprintf (stderr, "%s%s\n", indirection_level_string (), temp);
2253 fflush (stderr);
2254 }
2255
2256 return 1;
2257}
2258
2259/* Search for NAME in ARRAY, an array of strings in the same format as the
2260 environment array (i.e, name=value). If NAME is present, make a new
2261 variable and return it. Otherwise, return NULL. */
2262static SHELL_VAR *
2263find_name_in_env_array (name, array)
2264 char *name;
2265 char **array;
2266{
ccc6cda3 2267 register int i, l;
726f6388 2268
ccc6cda3 2269 if (array == 0)
726f6388
JA
2270 return ((SHELL_VAR *)NULL);
2271
ccc6cda3 2272 for (i = 0, l = strlen (name); array[i]; i++)
726f6388
JA
2273 {
2274 if (STREQN (array[i], name, l) && array[i][l] == '=')
2275 {
2276 SHELL_VAR *temp;
ccc6cda3 2277 char *w;
726f6388 2278
cce855bc
JA
2279 /* This is a potential memory leak. The code should really save
2280 the created variables in some auxiliary data structure, which
2281 can be disposed of at the appropriate time. */
2282 temp = new_shell_variable (name);
ccc6cda3 2283 w = array[i] + l + 1;
726f6388 2284
ccc6cda3 2285 temp->value = *w ? savestring (w) : (char *)NULL;
726f6388 2286
cce855bc 2287 temp->attributes = att_exported|att_tempvar;
726f6388
JA
2288 temp->context = 0;
2289 temp->prev_context = (SHELL_VAR *)NULL;
2290
ccc6cda3 2291 temp->dynamic_value = temp->assign_func = (DYNAMIC_FUNC *)NULL;
726f6388
JA
2292
2293 return (temp);
2294 }
2295 }
2296 return ((SHELL_VAR *)NULL);
2297}
2298
2299/* Find a variable in the temporary environment that is named NAME.
2300 The temporary environment can be either the environment provided
2301 to a simple command, or the environment provided to a shell function.
2302 We only search the function environment if we are currently executing
2303 a shell function body (variable_context > 0). Return a consed variable,
2304 or NULL if not found. */
2305SHELL_VAR *
2306find_tempenv_variable (name)
2307 char *name;
2308{
cce855bc
JA
2309 SHELL_VAR *var;
2310
2311 var = (SHELL_VAR *)NULL;
726f6388
JA
2312
2313 if (temporary_env)
2314 var = find_name_in_env_array (name, temporary_env);
2315
2316 /* We don't check this_shell_builtin because the command that needs the
2317 value from builtin_env may be a disk command run inside a script run
2318 with `.' and a temporary env. */
2319 if (!var && builtin_env)
2320 var = find_name_in_env_array (name, builtin_env);
2321
2322 if (!var && variable_context && function_env)
2323 var = find_name_in_env_array (name, function_env);
2324
2325 return (var);
2326}
2327
2328/* Free the storage allocated to the string array pointed to by ARRAYP, and
2329 make that variable have a null pointer as a value. */
2330static void
2331dispose_temporary_vars (arrayp)
2332 char ***arrayp;
2333{
2334 if (!*arrayp)
2335 return;
2336
2337 free_array (*arrayp);
2338 *arrayp = (char **)NULL;
2339 array_needs_making = 1;
2340}
2341
2342/* Free the storage used in the variable array for temporary
2343 environment variables. */
2344void
2345dispose_used_env_vars ()
2346{
2347 dispose_temporary_vars (&temporary_env);
2348}
2349
2350/* Free the storage used for temporary environment variables given to
2351 commands when executing inside of a function body. */
2352void
2353dispose_function_env ()
2354{
2355 dispose_temporary_vars (&function_env);
2356}
2357
2358/* Free the storage used for temporary environment variables given to
2359 commands when executing a builtin command such as "source". */
2360void
2361dispose_builtin_env ()
2362{
2363 dispose_temporary_vars (&builtin_env);
2364}
2365
ccc6cda3
JA
2366/* Take all of the shell variables in ENV_ARRAY and make shell variables
2367 from them at the current variable context. */
2368static void
2369merge_env_array (env_array)
2370 char **env_array;
2371{
2372 register int i, l;
2373 SHELL_VAR *temp;
d166f048 2374 char *val, *name;
ccc6cda3
JA
2375
2376 if (env_array == 0)
2377 return;
2378
2379 for (i = 0; env_array[i]; i++)
2380 {
2381 l = assignment (env_array[i]);
2382 name = env_array[i];
d166f048 2383 val = env_array[i] + l + 1;
ccc6cda3 2384 name[l] = '\0';
d166f048 2385 temp = bind_variable (name, val);
ccc6cda3
JA
2386 name[l] = '=';
2387 }
2388}
2389
726f6388 2390void
ccc6cda3 2391merge_temporary_env ()
726f6388 2392{
ccc6cda3
JA
2393 merge_env_array (temporary_env);
2394}
2395
2396void
2397merge_builtin_env ()
2398{
2399 merge_env_array (builtin_env);
726f6388
JA
2400}
2401
d166f048
JA
2402/* Add ENVSTR to the end of the exported environment, EXPORT_ENV. */
2403#define add_to_export_env(envstr,do_alloc) \
2404do \
2405 { \
2406 if (export_env_index >= (export_env_size - 1)) \
2407 { \
2408 export_env_size += 16; \
2409 export_env = (char **)xrealloc (export_env, export_env_size * sizeof (char *)); \
2410 } \
2411 export_env[export_env_index++] = (do_alloc) ? savestring (envstr) : envstr; \
2412 export_env[export_env_index] = (char *)NULL; \
2413 } while (0)
2414
cce855bc 2415#define ISFUNCTION(s, o) ((s[o + 1] == '(') && (s[o + 2] == ')'))
726f6388 2416
d166f048
JA
2417/* Add ASSIGN to EXPORT_ENV, or supercede a previous assignment in the
2418 array with the same left-hand side. Return the new EXPORT_ENV. */
726f6388 2419char **
d166f048 2420add_or_supercede_exported_var (assign, do_alloc)
726f6388 2421 char *assign;
d166f048 2422 int do_alloc;
726f6388
JA
2423{
2424 register int i;
d166f048 2425 int equal_offset;
726f6388 2426
d166f048
JA
2427 equal_offset = assignment (assign);
2428 if (equal_offset == 0)
2429 return (export_env);
726f6388
JA
2430
2431 /* If this is a function, then only supercede the function definition.
2432 We do this by including the `=(' in the comparison. */
2433 if (assign[equal_offset + 1] == '(')
2434 equal_offset++;
2435
d166f048 2436 for (i = 0; i < export_env_index; i++)
726f6388 2437 {
d166f048 2438 if (STREQN (assign, export_env[i], equal_offset + 1))
726f6388 2439 {
d166f048
JA
2440 free (export_env[i]);
2441 export_env[i] = do_alloc ? savestring (assign) : assign;
2442 return (export_env);
726f6388
JA
2443 }
2444 }
d166f048
JA
2445 add_to_export_env (assign, do_alloc);
2446 return (export_env);
726f6388
JA
2447}
2448
d166f048 2449/* Make the environment array for the command about to be executed, if the
726f6388
JA
2450 array needs making. Otherwise, do nothing. If a shell action could
2451 change the array that commands receive for their environment, then the
2452 code should `array_needs_making++'. */
2453void
2454maybe_make_export_env ()
2455{
2456 register int i;
2457 register char **temp_array;
d166f048 2458 int new_size;
726f6388
JA
2459
2460 if (array_needs_making)
2461 {
2462 if (export_env)
d166f048
JA
2463 free_array_members (export_env);
2464
2465 /* Make a guess based on how many shell variables and functions we
2466 have. Since there will always be array variables, and array
2467 variables are not (yet) exported, this will always be big enough
2468 for the exported variables and functions, without any temporary
2469 or function environments. */
2470 new_size = shell_variables->nentries + shell_functions->nentries + 1;
2471 if (new_size > export_env_size)
2472 {
2473 export_env_size = new_size;
2474 export_env = (char **)xrealloc (export_env, export_env_size * sizeof (char *));
2475 }
2476 export_env[export_env_index = 0] = (char *)NULL;
726f6388 2477
726f6388 2478 temp_array = make_var_array (shell_variables);
d166f048
JA
2479 if (temp_array)
2480 {
2481 for (i = 0; temp_array[i]; i++)
2482 add_to_export_env (temp_array[i], 0);
2483 free (temp_array);
2484 }
726f6388
JA
2485
2486 temp_array = make_var_array (shell_functions);
d166f048
JA
2487 if (temp_array)
2488 {
2489 for (i = 0; temp_array[i]; i++)
2490 add_to_export_env (temp_array[i], 0);
2491 free (temp_array);
2492 }
726f6388
JA
2493
2494 if (function_env)
2495 for (i = 0; function_env[i]; i++)
d166f048 2496 export_env = add_or_supercede_exported_var (function_env[i], 1);
726f6388
JA
2497
2498 if (temporary_env)
2499 for (i = 0; temporary_env[i]; i++)
d166f048 2500 export_env = add_or_supercede_exported_var (temporary_env[i], 1);
726f6388 2501
ccc6cda3 2502#if 0
726f6388 2503 /* If we changed the array, then sort it alphabetically. */
ccc6cda3 2504 if (posixly_correct == 0 && (temporary_env || function_env))
726f6388 2505 sort_char_array (export_env);
ccc6cda3 2506#endif
726f6388
JA
2507
2508 array_needs_making = 0;
2509 }
2510}
2511
2512/* We always put _ in the environment as the name of this command. */
2513void
2514put_command_name_into_env (command_name)
2515 char *command_name;
2516{
2517 char *dummy;
2518
2519 dummy = xmalloc (4 + strlen (command_name));
2520
2521 /* These three statements replace a call to sprintf */
2522 dummy[0] = '_';
2523 dummy[1] = '=';
2524 strcpy (dummy + 2, command_name);
d166f048 2525 export_env = add_or_supercede_exported_var (dummy, 0);
726f6388
JA
2526}
2527
cce855bc 2528#if 0 /* UNUSED -- it caused too many problems */
ccc6cda3
JA
2529void
2530put_gnu_argv_flags_into_env (pid, flags_string)
2531 int pid;
2532 char *flags_string;
2533{
2534 char *dummy, *pbuf;
2535 int l, fl;
2536
2537 pbuf = itos (pid);
2538 l = strlen (pbuf);
2539
2540 fl = strlen (flags_string);
2541
2542 dummy = xmalloc (l + fl + 30);
2543 dummy[0] = '_';
2544 strcpy (dummy + 1, pbuf);
2545 strcpy (dummy + 1 + l, "_GNU_nonoption_argv_flags_");
2546 dummy[l + 27] = '=';
2547 strcpy (dummy + l + 28, flags_string);
2548
2549 free (pbuf);
2550
d166f048 2551 export_env = add_or_supercede_exported_var (dummy, 0);
ccc6cda3 2552}
cce855bc 2553#endif
726f6388 2554
ccc6cda3
JA
2555/* Return a string denoting what our indirection level is. */
2556static char indirection_string[100];
726f6388
JA
2557
2558char *
ccc6cda3 2559indirection_level_string ()
726f6388 2560{
ccc6cda3
JA
2561 register int i, j;
2562 char *ps4;
726f6388 2563
ccc6cda3
JA
2564 indirection_string[0] = '\0';
2565 ps4 = get_string_value ("PS4");
726f6388 2566
ccc6cda3
JA
2567 if (ps4 == 0 || *ps4 == '\0')
2568 return (indirection_string);
726f6388 2569
ccc6cda3 2570 ps4 = decode_prompt_string (ps4);
726f6388 2571
ccc6cda3
JA
2572 for (i = 0; *ps4 && i < indirection_level && i < 99; i++)
2573 indirection_string[i] = *ps4;
2574
2575 for (j = 1; *ps4 && ps4[j] && i < 99; i++, j++)
2576 indirection_string[i] = ps4[j];
726f6388 2577
ccc6cda3
JA
2578 indirection_string[i] = '\0';
2579 free (ps4);
2580 return (indirection_string);
726f6388 2581}
cce855bc
JA
2582
2583/*************************************************
2584 * *
2585 * Functions to manage special variables *
2586 * *
2587 *************************************************/
2588
2589/* Extern declarations for variables this code has to manage. */
2590extern int eof_encountered, eof_encountered_limit, ignoreeof;
2591
2592#if defined (READLINE)
2593extern int no_line_editing;
2594extern int hostname_list_initialized;
2595#endif
2596
2597/* An alist of name.function for each special variable. Most of the
2598 functions don't do much, and in fact, this would be faster with a
2599 switch statement, but by the end of this file, I am sick of switch
2600 statements. */
2601
2602#define SET_INT_VAR(name, intvar) intvar = find_variable (name) != 0
2603
2604struct name_and_function {
2605 char *name;
2606 VFunction *function;
2607} special_vars[] = {
2608 { "PATH", sv_path },
2609 { "MAIL", sv_mail },
2610 { "MAILPATH", sv_mail },
2611 { "MAILCHECK", sv_mail },
2612
2613 { "POSIXLY_CORRECT", sv_strict_posix },
2614 { "GLOBIGNORE", sv_globignore },
2615
2616 /* Variables which only do something special when READLINE is defined. */
2617#if defined (READLINE)
2618 { "TERM", sv_terminal },
2619 { "TERMCAP", sv_terminal },
2620 { "TERMINFO", sv_terminal },
2621 { "HOSTFILE", sv_hostfile },
2622#endif /* READLINE */
2623
2624 /* Variables which only do something special when HISTORY is defined. */
2625#if defined (HISTORY)
2626 { "HISTIGNORE", sv_histignore },
2627 { "HISTSIZE", sv_histsize },
2628 { "HISTFILESIZE", sv_histsize },
2629 { "HISTCONTROL", sv_history_control },
2630# if defined (BANG_HISTORY)
2631 { "histchars", sv_histchars },
2632# endif /* BANG_HISTORY */
2633#endif /* HISTORY */
2634
2635 { "IGNOREEOF", sv_ignoreeof },
2636 { "ignoreeof", sv_ignoreeof },
2637
2638 { "OPTIND", sv_optind },
2639 { "OPTERR", sv_opterr },
2640
2641 { "TEXTDOMAIN", sv_locale },
2642 { "TEXTDOMAINDIR", sv_locale },
2643 { "LC_ALL", sv_locale },
2644 { "LC_COLLATE", sv_locale },
2645 { "LC_CTYPE", sv_locale },
2646 { "LC_MESSAGES", sv_locale },
2647 { "LANG", sv_locale },
2648
2649#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE)
2650 { "TZ", sv_tz },
2651#endif
2652
2653 { (char *)0, (VFunction *)0 }
2654};
2655
2656/* The variable in NAME has just had its state changed. Check to see if it
2657 is one of the special ones where something special happens. */
2658void
2659stupidly_hack_special_variables (name)
2660 char *name;
2661{
2662 int i;
2663
2664 for (i = 0; special_vars[i].name; i++)
2665 {
2666 if (STREQ (special_vars[i].name, name))
2667 {
2668 (*(special_vars[i].function)) (name);
2669 return;
2670 }
2671 }
2672}
2673
2674/* What to do just after the PATH variable has changed. */
2675void
2676sv_path (name)
2677 char *name;
2678{
2679 /* hash -r */
2680 flush_hashed_filenames ();
2681}
2682
2683/* What to do just after one of the MAILxxxx variables has changed. NAME
2684 is the name of the variable. This is called with NAME set to one of
2685 MAIL, MAILCHECK, or MAILPATH. */
2686void
2687sv_mail (name)
2688 char *name;
2689{
2690 /* If the time interval for checking the files has changed, then
2691 reset the mail timer. Otherwise, one of the pathname vars
2692 to the users mailbox has changed, so rebuild the array of
2693 filenames. */
2694 if (name[4] == 'C') /* if (strcmp (name, "MAILCHECK") == 0) */
2695 reset_mail_timer ();
2696 else
2697 {
2698 free_mail_files ();
2699 remember_mail_dates ();
2700 }
2701}
2702
2703/* What to do when GLOBIGNORE changes. */
2704void
2705sv_globignore (name)
2706 char *name;
2707{
2708 setup_glob_ignore (name);
2709}
2710
2711#if defined (READLINE)
2712/* What to do just after one of the TERMxxx variables has changed.
2713 If we are an interactive shell, then try to reset the terminal
2714 information in readline. */
2715void
2716sv_terminal (name)
2717 char *name;
2718{
2719 if (interactive_shell && no_line_editing == 0)
2720 rl_reset_terminal (get_string_value ("TERM"));
2721}
2722
2723void
2724sv_hostfile (name)
2725 char *name;
2726{
2727 hostname_list_initialized = 0;
2728}
2729#endif /* READLINE */
2730
2731#if defined (HISTORY)
2732/* What to do after the HISTSIZE or HISTFILESIZE variables change.
2733 If there is a value for this HISTSIZE (and it is numeric), then stifle
2734 the history. Otherwise, if there is NO value for this variable,
2735 unstifle the history. If name is HISTFILESIZE, and its value is
2736 numeric, truncate the history file to hold no more than that many
2737 lines. */
2738void
2739sv_histsize (name)
2740 char *name;
2741{
2742 char *temp;
2743 long num;
2744
2745 temp = get_string_value (name);
2746
2747 if (temp && *temp)
2748 {
2749 if (legal_number (temp, &num))
2750 {
2751 if (name[4] == 'S')
2752 {
2753 stifle_history (num);
2754 num = where_history ();
2755 if (history_lines_this_session > num)
2756 history_lines_this_session = num;
2757 }
2758 else
2759 {
2760 history_truncate_file (get_string_value ("HISTFILE"), (int)num);
2761 if (num <= history_lines_in_file)
2762 history_lines_in_file = num;
2763 }
2764 }
2765 }
2766 else if (name[4] == 'S')
2767 unstifle_history ();
2768}
2769
2770/* What to do after the HISTIGNORE variable changes. */
2771void
2772sv_histignore (name)
2773 char *name;
2774{
2775 setup_history_ignore (name);
2776}
2777
2778/* What to do after the HISTCONTROL variable changes. */
2779void
2780sv_history_control (name)
2781 char *name;
2782{
2783 char *temp;
2784
2785 history_control = 0;
2786 temp = get_string_value (name);
2787
2788 if (temp && *temp && STREQN (temp, "ignore", 6))
2789 {
2790 if (temp[6] == 's') /* ignorespace */
2791 history_control = 1;
2792 else if (temp[6] == 'd') /* ignoredups */
2793 history_control = 2;
2794 else if (temp[6] == 'b') /* ignoreboth */
2795 history_control = 3;
2796 }
2797}
2798
2799#if defined (BANG_HISTORY)
2800/* Setting/unsetting of the history expansion character. */
2801void
2802sv_histchars (name)
2803 char *name;
2804{
2805 char *temp;
2806
2807 temp = get_string_value (name);
2808 if (temp)
2809 {
2810 history_expansion_char = *temp;
2811 if (temp[0] && temp[1])
2812 {
2813 history_subst_char = temp[1];
2814 if (temp[2])
2815 history_comment_char = temp[2];
2816 }
2817 }
2818 else
2819 {
2820 history_expansion_char = '!';
2821 history_subst_char = '^';
2822 history_comment_char = '#';
2823 }
2824}
2825#endif /* BANG_HISTORY */
2826#endif /* HISTORY */
2827
2828#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE)
2829void
2830sv_tz (name)
2831 char *name;
2832{
2833 tzset ();
2834}
2835#endif
2836
2837/* If the variable exists, then the value of it can be the number
2838 of times we actually ignore the EOF. The default is small,
2839 (smaller than csh, anyway). */
2840void
2841sv_ignoreeof (name)
2842 char *name;
2843{
2844 SHELL_VAR *tmp_var;
2845 char *temp;
2846
2847 eof_encountered = 0;
2848
2849 tmp_var = find_variable (name);
2850 ignoreeof = tmp_var != 0;
2851 temp = tmp_var ? value_cell (tmp_var) : (char *)NULL;
2852 if (temp)
2853 eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10;
2854 set_shellopts (); /* make sure `ignoreeof' is/is not in $SHELLOPTS */
2855}
2856
2857void
2858sv_optind (name)
2859 char *name;
2860{
2861 char *tt;
2862 int s;
2863
2864 tt = get_string_value ("OPTIND");
2865 if (tt && *tt)
2866 {
2867 s = atoi (tt);
2868
2869 /* According to POSIX, setting OPTIND=1 resets the internal state
2870 of getopt (). */
2871 if (s < 0 || s == 1)
2872 s = 0;
2873 }
2874 else
2875 s = 0;
2876 getopts_reset (s);
2877}
2878
2879void
2880sv_opterr (name)
2881 char *name;
2882{
2883 char *tt;
2884
2885 tt = get_string_value ("OPTERR");
2886 sh_opterr = (tt && *tt) ? atoi (tt) : 1;
2887}
2888
2889void
2890sv_strict_posix (name)
2891 char *name;
2892{
2893 SET_INT_VAR (name, posixly_correct);
2894 posix_initialize (posixly_correct);
2895#if defined (READLINE)
2896 if (interactive_shell)
2897 posix_readline_initialize (posixly_correct);
2898#endif /* READLINE */
2899 set_shellopts (); /* make sure `posix' is/is not in $SHELLOPTS */
2900}
2901
2902void
2903sv_locale (name)
2904 char *name;
2905{
2906 char *v;
2907
2908 v = get_string_value (name);
2909 if (name[0] == 'L' && name[1] == 'A') /* LANG */
2910 set_lang (name, v);
2911 else
2912 set_locale_var (name, v); /* LC_*, TEXTDOMAIN* */
2913}
2914
2915#if defined (ARRAY_VARS)
2916void
2917set_pipestatus_array (ps)
2918 int *ps;
2919{
2920 SHELL_VAR *v;
2921 ARRAY *a;
2922 register int i;
2923 char *t;
2924
2925 v = find_variable ("PIPESTATUS");
2926 if (v == 0)
2927 v = make_new_array_variable ("PIPESTATUS");
2928 if (array_p (v) == 0)
2929 return; /* Do nothing if not an array variable. */
2930 a = array_cell (v);
2931 if (a)
2932 empty_array (a);
2933 for (i = 0; ps[i] != -1; i++)
2934 {
2935 t = itos (ps[i]);
2936 array_add_element (a, i, t);
2937 free (t);
2938 }
2939}
2940#endif
2941
2942void
2943set_pipestatus_from_exit (s)
2944 int s;
2945{
2946#if defined (ARRAY_VARS)
2947 static int v[2] = { 0, -1 };
2948
2949 v[0] = s;
2950 set_pipestatus_array (v);
2951#endif
2952}