diff options
| author | Jari Aalto <jari.aalto@cante.net> | 1996-12-23 17:02:34 +0000 |
|---|---|---|
| committer | Jari Aalto <jari.aalto@cante.net> | 2009-09-12 16:46:49 +0000 |
| commit | ccc6cda312fea9f0468ee65b8f368e9653e1380b (patch) | |
| tree | b059878adcfd876c4acb8030deda1eeb918c7e75 /variables.c | |
| parent | 726f63884db0132f01745f1fb4465e6621088ccf (diff) | |
Imported from ../bash-2.0.tar.gz.
Diffstat (limited to 'variables.c')
| -rw-r--r-- | variables.c | 1436 |
1 files changed, 975 insertions, 461 deletions
diff --git a/variables.c b/variables.c index 2c911c2..2c8b939 100644 --- a/variables.c +++ b/variables.c @@ -18,31 +18,45 @@ along with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <stdio.h> +#include "config.h" + #include "bashtypes.h" #include "posixstat.h" + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#include <stdio.h> #include <ctype.h> #include <pwd.h> - #include "bashansi.h" + #include "shell.h" -#include "hash.h" #include "flags.h" #include "execute_cmd.h" +#include "mailcheck.h" +#include "input.h" #include "builtins/common.h" #include <tilde/tilde.h> +#if defined (HISTORY) +# include "bashhist.h" +#endif /* HISTORY */ + /* Variables used here and defined in other files. */ extern int posixly_correct; extern int variable_context, line_number; -extern int interactive, interactive_shell, login_shell, shell_level; -extern int subshell_environment; -extern int build_version; -extern char *dist_version; +extern int interactive, interactive_shell, login_shell; +extern int subshell_environment, indirection_level; +extern int build_version, patch_level; +extern char *dist_version, *release_status; extern char *shell_name; extern char *primary_prompt, *secondary_prompt; +extern char *current_host_name; extern Function *this_shell_builtin; +extern char *this_command_name; extern time_t shell_start_time; /* The list of shell variables that the user has created, or that came from @@ -86,14 +100,17 @@ char **export_env = (char **)NULL; /* Non-zero means that we have to remake EXPORT_ENV. */ int array_needs_making = 1; -/* The list of variables that may not be unset in this shell. */ -char **non_unsettable_vars = (char **)NULL; +/* The number of times BASH has been executed. This is set + by initialize_variables (). */ +int shell_level = 0; -static char *have_local_variables; /* XXX */ -static int local_variable_stack_size = 0; /* XXX */ +static char *have_local_variables; +static int local_variable_stack_size; /* Some forward declarations. */ +static void uidset (); static void initialize_dynamic_variables (); +static void make_vers_array (); static void sbrand (); /* set bash random number generator. */ static int qsort_var_comp (); @@ -101,18 +118,14 @@ static int qsort_var_comp (); #define set_auto_export(var) \ do { var->attributes |= att_exported; array_needs_making = 1; } while (0) -#if defined (HISTORY) -# include "bashhist.h" -#endif /* HISTORY */ - /* Initialize the shell variables from the current environment. */ void -initialize_shell_variables (env) +initialize_shell_variables (env, no_functions) char **env; + int no_functions; /* If set, don't import functions from ENV. */ { - char *name, *string, *current_dir; - int c, char_index; - int string_index = 0; + char *name, *string, *temp_string; + int c, char_index, string_index, string_length; SHELL_VAR *temp_var; if (!shell_variables) @@ -121,10 +134,8 @@ initialize_shell_variables (env) if (!shell_functions) shell_functions = make_hash_table (0); - while (string = env[string_index++]) + for (string_index = 0; string = env[string_index++]; ) { - int string_length; - char_index = 0; string_length = strlen (string); @@ -136,33 +147,42 @@ initialize_shell_variables (env) name[char_index] = '\0'; /* If exported function, define it now. */ - if (!privileged_mode && STREQN ("() {", string, 4)) + if (no_functions == 0 && STREQN ("() {", string, 4)) { - SHELL_VAR *f; - char *eval_string; - - eval_string = xmalloc (3 + string_length + strlen (name)); - sprintf (eval_string, "%s %s", name, string); + temp_string = xmalloc (3 + string_length + strlen (name)); + sprintf (temp_string, "%s %s", name, string); - parse_and_execute (eval_string, name, 0); + parse_and_execute (temp_string, name, 0); if (name[char_index - 1] == ')') name[char_index - 2] = '\0'; - if (f = find_function (name)) + if (temp_var = find_function (name)) { - f->attributes |= (att_exported | att_imported); + temp_var->attributes |= (att_exported | att_imported); array_needs_making = 1; } else report_error ("error importing function definition for `%s'", name); } +#if defined (ARRAY_VARS) +# if 0 + /* Array variables may not yet be exported. */ + else if (*string == '(' && string[1] == '[' && strchr (string, ')')) + { + string_length = 1; + temp_string = extract_array_assignment_list (string, &string_length); + temp_var = assign_array_from_string (name, temp_string); + FREE (temp_string); + temp_var->attributes |= (att_exported | att_imported); + array_needs_making = 1; + } +# endif +#endif else { - SHELL_VAR *v; - - v = bind_variable (name, string); - v->attributes |= (att_exported | att_imported); + temp_var = bind_variable (name, string); + temp_var->attributes |= (att_exported | att_imported); array_needs_making = 1; } free (name); @@ -170,23 +190,26 @@ initialize_shell_variables (env) /* If we got PWD from the environment, update our idea of the current working directory. In any case, make sure that PWD exists before - checking it. It is possible for getwd () to fail on shell startup, + checking it. It is possible for getcwd () to fail on shell startup, and in that case, PWD would be undefined. */ temp_var = find_variable ("PWD"); if (temp_var && imported_p (temp_var) && - (current_dir = value_cell (temp_var)) && - same_file (current_dir, ".", (struct stat *)NULL, (struct stat *)NULL)) - set_working_directory (current_dir); + (temp_string = value_cell (temp_var)) && + same_file (temp_string, ".", (struct stat *)NULL, (struct stat *)NULL)) + set_working_directory (temp_string); else { - current_dir = get_working_directory ("shell-init"); - if (current_dir) - { - bind_variable ("PWD", current_dir); - free (current_dir); - } + temp_string = get_working_directory ("shell-init"); + if (temp_string) + { + bind_variable ("PWD", temp_string); + free (temp_string); + } } + /* Set up initial value of $_ */ + temp_var = bind_variable ("_", dollar_vars[0]); + /* Remember this pid. */ dollar_dollar_pid = (int)getpid (); @@ -198,6 +221,7 @@ initialize_shell_variables (env) temp_var = set_if_not ("TERM", "dumb"); set_auto_export (temp_var); + /* set up the prompts. */ if (interactive_shell) { set_if_not ("PS1", primary_prompt); @@ -205,19 +229,23 @@ initialize_shell_variables (env) } set_if_not ("PS4", "+ "); -#if defined (INSECURITY) - set_if_not ("IFS", " \t\n"); -#else - bind_variable ("IFS", " \t\n"); -#endif /* INSECURITY */ + /* Don't allow IFS to be imported from the environment. */ + temp_var = bind_variable ("IFS", " \t\n"); /* Magic machine types. Pretty convenient. */ - temp_var = set_if_not ("HOSTTYPE", HOSTTYPE); + temp_var = bind_variable ("HOSTTYPE", HOSTTYPE); set_auto_export (temp_var); - temp_var = set_if_not ("OSTYPE", OSTYPE); + temp_var = bind_variable ("OSTYPE", OSTYPE); + set_auto_export (temp_var); + temp_var = bind_variable ("MACHTYPE", MACHTYPE); + set_auto_export (temp_var); + temp_var = bind_variable ("HOSTNAME", current_host_name); set_auto_export (temp_var); - /* Default MAILCHECK for interactive shells. */ + /* Default MAILCHECK for interactive shells. Defer the creation of a + default MAILPATH until the startup files are read, because MAIL + names a mail file if MAILCHECK is not set, and we should provide a + default only if neither is set. */ if (interactive_shell) set_if_not ("MAILCHECK", "60"); @@ -227,90 +255,82 @@ initialize_shell_variables (env) adjust_shell_level (1); /* Make a variable $PPID, which holds the pid of the shell's parent. */ - { - char *ppid; - SHELL_VAR *v; - - ppid = itos ((int) getppid ()); - v = find_variable ("PPID"); - - if (v) - v->attributes &= ~(att_readonly | att_exported); - - v = bind_variable ("PPID", ppid); - v->attributes |= (att_readonly | att_integer); - - non_unsettable ("PPID"); - free (ppid); - } + name = itos ((int) getppid ()); + temp_var = find_variable ("PPID"); + if (temp_var) + temp_var->attributes &= ~(att_readonly | att_exported); + temp_var = bind_variable ("PPID", name); + temp_var->attributes |= (att_readonly | att_integer); + free (name); -#if defined (GETOPTS_BUILTIN) /* Initialize the `getopts' stuff. */ bind_variable ("OPTIND", "1"); + sv_optind ("OPTIND"); bind_variable ("OPTERR", "1"); -#endif /* GETOPTS_BUILTIN */ + sv_opterr ("OPTERR"); /* Get the full pathname to THIS shell, and set the BASH variable to it. */ - { - char *tname; - - if ((login_shell == 1) && (*shell_name != '/')) - { - /* If HOME doesn't exist, set it. */ - temp_var = set_if_not ("HOME", current_user.home_dir); - temp_var->attributes |= att_exported; - - name = savestring (current_user.shell); - } - else if (*shell_name == '/') - name = savestring (shell_name); - else - { - int s; - - tname = find_user_command (shell_name); - if (tname == 0) - { - /* Try the current directory. If there is not an executable - there, just punt and use the login shell. */ - s = file_status (shell_name); - if (s & FS_EXECABLE) - { - tname = make_absolute (shell_name, get_string_value ("PWD")); - if (*shell_name == '.') - { - name = canonicalize_pathname (tname); + if ((login_shell == 1) && (*shell_name != '/')) + { + /* If HOME doesn't exist, set it. */ + temp_var = set_if_not ("HOME", current_user.home_dir); + temp_var->attributes |= att_exported; + + name = savestring (current_user.shell); + } + else if (*shell_name == '/') + name = savestring (shell_name); + else + { + char *tname; + int s; + + tname = find_user_command (shell_name); + + if (tname == 0) + { + /* Try the current directory. If there is not an executable + there, just punt and use the login shell. */ + s = file_status (shell_name); + if (s & FS_EXECABLE) + { + tname = make_absolute (shell_name, get_string_value ("PWD")); + if (*shell_name == '.') + { + name = canonicalize_pathname (tname); + if (name == 0) + name = tname; + else free (tname); - } - else - name = tname; - } - else - name = savestring (current_user.shell); - } - else - { - name = full_pathname (tname); - free (tname); - } - } - - /* Make the exported environment variable SHELL be the user's login - shell. Note that the `tset' command looks at this variable - to determine what style of commands to output; if it ends in "csh", - then C-shell commands are output, else Bourne shell commands. */ - temp_var = set_if_not ("SHELL", current_user.shell); - set_auto_export (temp_var); - - /* Make a variable called BASH, which is the name of THIS shell. */ - temp_var = bind_variable ("BASH", name); - - free (name); - } + } + else + name = tname; + } + else + name = savestring (current_user.shell); + } + else + { + name = full_pathname (tname); + free (tname); + } + } + temp_var = bind_variable ("BASH", name); + free (name); + + /* Make the exported environment variable SHELL be the user's login + shell. Note that the `tset' command looks at this variable + to determine what style of commands to output; if it ends in "csh", + then C-shell commands are output, else Bourne shell commands. */ + temp_var = set_if_not ("SHELL", current_user.shell); + set_auto_export (temp_var); /* Make a variable called BASH_VERSION which contains the version info. */ bind_variable ("BASH_VERSION", shell_version_string ()); +#if defined (ARRAY_VARS) + make_vers_array (); +#endif /* Find out if we're supposed to be in Posix.2 mode via an environment variable. */ @@ -326,10 +346,7 @@ initialize_shell_variables (env) that we are remembering commands on the history list. */ if (remember_on_history) { - if (posixly_correct) - name = tilde_expand ("~/.sh_history"); - else - name = tilde_expand ("~/.bash_history"); + name = bash_tilde_expand (posixly_correct ? "~/.sh_history" : "~/.bash_history"); set_if_not ("HISTFILE", name); free (name); @@ -340,13 +357,11 @@ initialize_shell_variables (env) #endif /* HISTORY */ /* Seed the random number generator. */ - sbrand (dollar_dollar_pid); + sbrand (dollar_dollar_pid + (long)shell_start_time); /* Handle some "special" variables that we may have inherited from a parent shell. */ - noclobber = find_variable ("noclobber") != (SHELL_VAR *)NULL; - temp_var = find_variable ("IGNOREEOF"); if (!temp_var) temp_var = find_variable ("ignoreeof"); @@ -356,36 +371,16 @@ initialize_shell_variables (env) #if defined (HISTORY) if (interactive_shell && remember_on_history) { - sv_command_oriented_history ("command_oriented_history"); - if (find_variable ("history_control")) - sv_history_control ("history_control"); /* gone in next release */ - else - sv_history_control ("HISTCONTROL"); + sv_history_control ("HISTCONTROL"); + sv_histignore ("HISTIGNORE"); } #endif /* HISTORY */ + /* Get the user's real and effective user ids. */ + uidset (); + /* Initialize the dynamic variables, and seed their values. */ initialize_dynamic_variables (); - - non_unsettable ("PATH"); - non_unsettable ("IFS"); - - if (interactive_shell) - { - non_unsettable ("PS1"); - non_unsettable ("PS2"); - } - - /* Get the users real user id, and save that in a readonly variable. - To make the variable *really* readonly, we have added it to a special - list of vars. */ - - sv_uids (); - set_var_read_only ("UID"); - set_var_read_only ("EUID"); - - non_unsettable ("EUID"); - non_unsettable ("UID"); } void @@ -409,28 +404,81 @@ adjust_shell_level (change) free (new_level); } -/* Add NAME to the list of variables that cannot be unset - if it isn't already there. */ -void -non_unsettable (name) - char *name; +static void +uidset () { - register int i; + char *buff; + register SHELL_VAR *v; + + buff = itos (current_user.uid); + v = find_variable ("UID"); + if (v) + v->attributes &= ~att_readonly; + + v = bind_variable ("UID", buff); + v->attributes |= (att_readonly | att_integer); - if (!non_unsettable_vars) + if (current_user.euid != current_user.uid) { - non_unsettable_vars = (char **)xmalloc (1 * sizeof (char *)); - non_unsettable_vars[0] = (char *)NULL; + free (buff); + buff = itos (current_user.euid); } - for (i = 0; non_unsettable_vars[i]; i++) - if (STREQ (non_unsettable_vars[i], name)) - return; + v = find_variable ("EUID"); + if (v) + v->attributes &= ~att_readonly; - non_unsettable_vars = (char **) - xrealloc (non_unsettable_vars, (2 + i) * sizeof (char *)); - non_unsettable_vars[i] = savestring (name); - non_unsettable_vars[i + 1] = (char *)NULL; + v = bind_variable ("EUID", buff); + v->attributes |= (att_readonly | att_integer); + free (buff); +} + +#if defined (ARRAY_VARS) +static void +make_vers_array () +{ + SHELL_VAR *vv; + ARRAY *av; + char *s, d[16]; + + makunbound ("BASH_VERSINFO", shell_variables); + + vv = make_new_array_variable ("BASH_VERSINFO"); + av = array_cell (vv); + strcpy (d, dist_version); + s = strchr (d, '.'); + if (s) + *s++ = '\0'; + array_add_element (av, 0, d); + array_add_element (av, 1, s); + s = itos (patch_level); + array_add_element (av, 2, s); + free (s); + s = itos (build_version); + array_add_element (av, 3, s); + free (s); + array_add_element (av, 4, release_status); + array_add_element (av, 5, MACHTYPE); + + vv->attributes |= att_readonly; +} +#endif /* ARRAY_VARS */ + +/* Set the environment variables $LINES and $COLUMNS in response to + a window size change. */ +void +set_lines_and_columns (lines, cols) + int lines, cols; +{ + char *val; + + val = itos (lines); + bind_variable ("LINES", val); + free (val); + + val = itos (cols); + bind_variable ("COLUMNS", val); + free (val); } /* Set NAME to VALUE if NAME has no value. */ @@ -438,8 +486,9 @@ SHELL_VAR * set_if_not (name, value) char *name, *value; { - SHELL_VAR *v = find_variable (name); + SHELL_VAR *v; + v = find_variable (name); if (!v) v = bind_variable (name, value); return (v); @@ -509,7 +558,7 @@ all_vars (table) SHELL_VAR **list; list = map_over ((Function *)NULL, table); - if (list) + if (list && posixly_correct) sort_variables (list); return (list); } @@ -545,6 +594,7 @@ print_var_list (list) /* Print LIST (a linked list of shell variables) to stdout by printing the names, without the values. Used to support the `set +' command. */ +void print_vars_no_values (list) register SHELL_VAR **list; { @@ -570,22 +620,40 @@ print_assignment (var) print_var_function (var); printf ("\n"); } +#if defined (ARRAY_VARS) + else if (array_p (var) && var->value) + print_array_assignment (var, 0); +#endif /* ARRAY_VARS */ else if (var->value) { printf ("%s=", var->name); - print_var_value (var); + print_var_value (var, 1); printf ("\n"); } } /* Print the value cell of VAR, a shell variable. Do not print - the name, nor leading/trailing newline. */ + the name, nor leading/trailing newline. If QUOTE is non-zero, + and the value contains shell metacharacters, quote the value + in such a way that it can be read back in. */ void -print_var_value (var) +print_var_value (var, quote) SHELL_VAR *var; + int quote; { + char *t; + if (var->value) - printf ("%s", var->value); + { + if (quote && contains_shell_metas (var->value)) + { + t = single_quote (var->value); + printf ("%s", t); + free (t); + } + else + printf ("%s", var->value); + } } /* Print the function cell of VAR, a shell variable. Do not @@ -598,38 +666,61 @@ print_var_function (var) printf ("%s", named_function_string ((char *)NULL, function_cell(var), 1)); } +#if defined (ARRAY_VARS) +void +print_array_assignment (var, quoted) + SHELL_VAR *var; + int quoted; +{ + char *vstr; + + if (quoted) + vstr = quoted_array_assignment_string (array_cell (var)); + else + vstr = array_to_assignment_string (array_cell (var)); + + if (vstr == 0) + printf ("%s=%s\n", var->name, quoted ? "'()'" : "()"); + else + { + printf ("%s=%s\n", var->name, vstr); + free (vstr); + } +} +#endif /* ARRAY_VARS */ + /* **************************************************************** */ -/* */ -/* Dynamic Variable Extension */ -/* */ +/* */ +/* Dynamic Variable Extension */ +/* */ /* **************************************************************** */ /* DYNAMIC VARIABLES - + These are variables whose values are generated anew each time they are referenced. These are implemented using a pair of function pointers in the struct variable: assign_func, which is called from bind_variable, and dynamic_value, which is called from find_variable. - + assign_func is called from bind_variable, if bind_variable discovers that the variable being assigned to has such a function. The function is called as SHELL_VAR *temp = (*(entry->assign_func)) (entry, value) and the (SHELL_VAR *)temp is returned as the value of bind_variable. It is usually ENTRY (self). - + dynamic_value is called from find_variable to return a `new' value for the specified dynamic varible. If this function is NULL, the variable is treated as a `normal' shell variable. If it is not, however, then this function is called like this: tempvar = (*(var->dynamic_value)) (var); - + Sometimes `tempvar' will replace the value of `var'. Other times, the shell will simply use the string value. Pretty object-oriented, huh? - + Be warned, though: if you `unset' a special variable, it loses its special meaning, even if you subsequently set it. - + The special assignment code would probably have been better put in subst.c: do_assignment, in the same style as stupidly_hack_special_variables, but I wanted the changes as @@ -638,14 +729,14 @@ print_var_function (var) /* The value of $SECONDS. This is the number of seconds since shell invocation, or, the number of seconds since the last assignment + the value of the last assignment. */ -static long seconds_value_assigned = (long)0; +static long seconds_value_assigned; static SHELL_VAR * assign_seconds (self, value) SHELL_VAR *self; char *value; { - seconds_value_assigned = atol (value); + seconds_value_assigned = string_to_long (value); shell_start_time = NOW; return (self); } @@ -669,6 +760,7 @@ get_seconds (var) /* The random number seed. You can change this by setting RANDOM. */ static unsigned long rseed = 1; +static unsigned long last_random_value; /* A linear congruential random number generator based on the ANSI C standard. A more complicated one is overkill. */ @@ -694,9 +786,7 @@ assign_random (self, value) SHELL_VAR *self; char *value; { - int s = atoi (value); - - sbrand (s); + sbrand (atoi (value)); return (self); } @@ -707,7 +797,15 @@ get_random (var) int rv; char *p; - rv = brand (); + /* Reset for command and process substitution. */ + if (subshell_environment) + sbrand ((int)(getpid() + NOW)); + + do + rv = brand (); + while (rv == (int)last_random_value); + + last_random_value = rv; p = itos ((int)rv); FREE (var->value); @@ -723,13 +821,24 @@ get_lineno (var) SHELL_VAR *var; { char *p; + int ln; - p = itos (line_number); + ln = executing_line_number (); + p = itos (ln); FREE (var->value); var->value = p; return (var); } +static SHELL_VAR * +assign_lineno (var, value) + SHELL_VAR *var; + char *value; +{ + line_number = atoi (value); + return var; +} + #if defined (HISTORY) static SHELL_VAR * get_histcmd (var) @@ -744,6 +853,32 @@ get_histcmd (var) } #endif +#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) +static SHELL_VAR * +get_dirstack (self) + SHELL_VAR *self; +{ + ARRAY *a; + WORD_LIST *l; + + l = get_directory_stack (); + a = word_list_to_array (l); + dispose_array (array_cell (self)); + self->value = (char *)a; + return self; +} + +static SHELL_VAR * +assign_dirstack (self, ind, value) + SHELL_VAR *self; + int ind; + char *value; +{ + set_dirstack_element (ind, 1, value); + return self; +} +#endif /* PUSHD AND POPD && ARRAY_VARS */ + static void initialize_dynamic_variables () { @@ -759,13 +894,19 @@ initialize_dynamic_variables () v = bind_variable ("LINENO", (char *)NULL); v->dynamic_value = get_lineno; - v->assign_func = (DYNAMIC_FUNC *)NULL; + v->assign_func = assign_lineno; #if defined (HISTORY) v = bind_variable ("HISTCMD", (char *)NULL); v->dynamic_value = get_histcmd; v->assign_func = (DYNAMIC_FUNC *)NULL; #endif + +#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) + v = make_new_array_variable ("DIRSTACK"); + v->dynamic_value = get_dirstack; + v->assign_func = assign_dirstack; +#endif /* PUSHD_AND_POPD && ARRAY_VARS */ } /* How to get a pointer to the shell variable or function named NAME. @@ -779,11 +920,7 @@ var_lookup (name, hashed_vars) BUCKET_CONTENTS *bucket; bucket = find_hash_item (name, hashed_vars); - - if (bucket) - return ((SHELL_VAR *)bucket->data); - else - return ((SHELL_VAR *)NULL); + return (bucket ? (SHELL_VAR *)bucket->data : (SHELL_VAR *)NULL); } /* Look up the variable entry named NAME. If SEARCH_TEMPENV is non-zero, @@ -810,10 +947,7 @@ find_variable_internal (name, search_tempenv) if (!var) return ((SHELL_VAR *)NULL); - if (var->dynamic_value) - return ((*(var->dynamic_value)) (var)); - else - return (var); + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); } /* Look up the variable entry named NAME. Returns the entry or NULL. */ @@ -845,6 +979,10 @@ get_string_value (var_name) if (!var) return (char *)NULL; +#if defined (ARRAY_VARS) + else if (array_p (var)) + return (array_reference (array_cell (var), 0)); +#endif else return (var->value); } @@ -883,15 +1021,13 @@ make_local_variable (name) new_var = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); new_var->name = savestring (name); - new_var->value = savestring (""); + new_var->value = xmalloc (1); + new_var->value[0] = '\0'; new_var->dynamic_value = (DYNAMIC_FUNC *)NULL; new_var->assign_func = (DYNAMIC_FUNC *)NULL; - new_var->attributes = 0; - - if (exported_p (old_var)) - new_var->attributes |= att_exported; + new_var->attributes = exported_p (old_var) ? att_exported : 0; new_var->prev_context = old_var; elt = add_hash_item (savestring (name), shell_variables); @@ -899,15 +1035,14 @@ make_local_variable (name) } new_var->context = variable_context; + new_var->attributes |= att_local; /* XXX */ - if (local_variable_stack_size <= variable_context) + if (variable_context >= local_variable_stack_size) { int old_size = local_variable_stack_size; - while (local_variable_stack_size <= variable_context) - local_variable_stack_size += 8; - have_local_variables = - xrealloc (have_local_variables, local_variable_stack_size); + RESIZE_MALLOCED_BUFFER (have_local_variables, variable_context, 1, + local_variable_stack_size, 8); bzero ((char *)have_local_variables + old_size, local_variable_stack_size - old_size); } @@ -916,95 +1051,156 @@ make_local_variable (name) return (new_var); } -/* Bind a variable NAME to VALUE. This conses up the name - and value strings. */ +#if defined (ARRAY_VARS) SHELL_VAR * -bind_variable (name, value) - char *name, *value; +make_local_array_variable (name) + char *name; +{ + SHELL_VAR *var; + ARRAY *array; + + var = make_local_variable (name); + array = new_array (); + + FREE (value_cell(var)); + var->value = (char *)array; + var->attributes |= att_array; + return var; +} +#endif /* ARRAY_VARS */ + +/* Create a new shell variable with name NAME and add it to the hash table + of shell variables. */ +static +SHELL_VAR * +make_new_variable (name) + char *name; { - SHELL_VAR *entry = var_lookup (name, shell_variables); + SHELL_VAR *entry; BUCKET_CONTENTS *elt; - if (!entry) - { - /* Make a new entry for this variable. Then do the binding. */ - entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); + entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); - entry->attributes = 0; - entry->name = savestring (name); + entry->attributes = 0; + entry->name = savestring (name); + entry->value = (char *)NULL; - if (value) + entry->dynamic_value = (DYNAMIC_FUNC *)NULL; + entry->assign_func = (DYNAMIC_FUNC *)NULL; + + /* Always assume variables are to be made at toplevel! + make_local_variable has the responsibilty of changing the + variable context. */ + entry->context = 0; + entry->prev_context = (SHELL_VAR *)NULL; + + elt = add_hash_item (savestring (name), shell_variables); + elt->data = (char *)entry; + + return entry; +} + +#if defined (ARRAY_VARS) +SHELL_VAR * +make_new_array_variable (name) + char *name; +{ + SHELL_VAR *entry; + ARRAY *array; + + entry = make_new_variable (name); + array = new_array (); + entry->value = (char *)array; + entry->attributes |= att_array; + return entry; +} +#endif + +char * +make_variable_value (var, value) + SHELL_VAR *var; + char *value; +{ + char *retval; + long lval; + + /* If this variable has had its type set to integer (via `declare -i'), + then do expression evaluation on it and store the result. The + functions in expr.c (evalexp and bind_int_variable) are responsible + for turning off the integer flag if they don't want further + evaluation done. */ + if (integer_p (var)) + { + lval = evalexp (value); + retval = itos (lval); + } + else if (value) + { + if (*value) + retval = savestring (value); + else { - if (*value) - entry->value = savestring (value); - else - { - entry->value = xmalloc (1); - entry->value[0] = '\0'; - } + retval = xmalloc (1); + retval[0] = '\0'; } - else - entry->value = (char *)NULL; + } + else + retval = (char *)NULL; - entry->dynamic_value = (DYNAMIC_FUNC *)NULL; - entry->assign_func = (DYNAMIC_FUNC *)NULL; + return retval; +} - /* Always assume variables are to be made at toplevel! - make_local_variable has the responsibilty of changing the - variable context. */ - entry->context = 0; - entry->prev_context = (SHELL_VAR *)NULL; +/* Bind a variable NAME to VALUE. This conses up the name + and value strings. */ +SHELL_VAR * +bind_variable (name, value) + char *name, *value; +{ + char *newval; + SHELL_VAR *entry; - elt = add_hash_item (savestring (name), shell_variables); - elt->data = (char *)entry; + entry = var_lookup (name, shell_variables); + + if (entry == 0) + { + entry = make_new_variable (name); + entry->value = make_variable_value (entry, value); } +#if defined (ARRAY_VARS) + else if (entry->assign_func && array_p (entry) == 0) +#else else if (entry->assign_func) +#endif return ((*(entry->assign_func)) (entry, value)); else { if (readonly_p (entry)) { - report_error ("%s: read-only variable", name); + report_error ("%s: readonly variable", name); return (entry); } /* Variables which are bound are visible. */ entry->attributes &= ~att_invisible; - /* If this variable has had its type set to integer (via `declare -i'), - then do expression evaluation on it and store the result. The - functions in expr.c (evalexp and bind_int_variable) are responsible - for turning off the integer flag if they don't want further - evaluation done. */ - if (integer_p (entry)) - { - long val; + newval = make_variable_value (entry, value); - val = evalexp (value); - /* We cannot free () entry->value before this; what if the string - we are working is `even=even+2'? We need the original value - around while we are doing the evaluation to handle any possible - recursion. */ - FREE (entry->value); - entry->value = itos (val); - } +#if defined (ARRAY_VARS) + /* XXX -- this bears looking at again -- XXX */ + /* If an existing array variable x is being assigned to with x=b or + `read x' or something of that nature, silently convert it to + x[0]=b or `read x[0]'. */ + if (array_p (entry)) + array_add_element (array_cell (entry), 0, newval); else { FREE (entry->value); - - if (value) - { - if (*value) - entry->value = savestring (value); - else - { - entry->value = xmalloc (1); - entry->value[0] = '\0'; - } - } - else - entry->value = (char *)NULL; + entry->value = newval; } +#else + FREE (entry->value); + entry->value = newval; +#endif } if (mark_modified_vars) @@ -1016,6 +1212,188 @@ bind_variable (name, value) return (entry); } +#if defined (ARRAY_VARS) +/* Convert a shell variable to an array variable. The original value is + saved as array[0]. */ +SHELL_VAR * +convert_var_to_array (var) + SHELL_VAR *var; +{ + char *oldval; + ARRAY *array; + + oldval = value_cell (var); + array = new_array (); + array_add_element (array, 0, oldval); + FREE (value_cell (var)); + var->value = (char *)array; + var->attributes |= att_array; + var->attributes &= ~att_invisible; + + return var; +} + +/* Perform an array assignment name[ind]=value. If NAME already exists and + is not an array, and IND is 0, perform name=value instead. If NAME exists + and is not an array, and IND is not 0, convert it into an array with the + existing value as name[0]. + + If NAME does not exist, just create an array variable, no matter what + IND's value may be. */ +SHELL_VAR * +bind_array_variable (name, ind, value) + char *name; + int ind; + char *value; +{ + SHELL_VAR *entry; + char *newval; + + entry = var_lookup (name, shell_variables); + + if (entry == (SHELL_VAR *) 0) + entry = make_new_array_variable (name); + else if (readonly_p (entry)) + { + report_error ("%s: readonly variable", name); + return (entry); + } + else if (array_p (entry) == 0) + entry = convert_var_to_array (entry); + + /* ENTRY is an array variable, and ARRAY points to the value. */ + newval = make_variable_value (entry, value); + if (entry->assign_func) + (*entry->assign_func) (entry, ind, newval); + else + array_add_element (array_cell (entry), ind, newval); + FREE (newval); + + return (entry); +} + +SHELL_VAR * +assign_array_from_string (name, value) + char *name, *value; +{ + SHELL_VAR *var; + + var = find_variable (name); + if (var == 0) + var = make_new_array_variable (name); + else if (array_p (var) == 0) + var = convert_var_to_array (var); + + return (assign_array_var_from_string (var, value)); +} + +SHELL_VAR * +assign_array_var_from_word_list (var, list) + SHELL_VAR *var; + WORD_LIST *list; +{ + register int i; + register WORD_LIST *l; + ARRAY *a; + + for (a = array_cell (var), l = list, i = 0; l; l = l->next, i++) + if (var->assign_func) + (*var->assign_func) (var, i, l->word->word); + else + array_add_element (a, i, l->word->word); + return var; +} + +SHELL_VAR * +assign_array_var_from_string (var, value) + SHELL_VAR *var; + char *value; +{ + ARRAY *a; + WORD_LIST *list, *nlist; + char *w, *val, *nval; + int ni, len, ind, last_ind; + + a = array_cell (var); + + /* Expand the value string into a list of words, performing all the + shell expansions including word splitting. */ + if (*value == '(') + { + ni = 1; + val = extract_array_assignment_list (value, &ni); + if (val == 0) + return var; + nlist = expand_string (val, 0); + free (val); + } + else + nlist = expand_string (value, 0); + + for (last_ind = 0, list = nlist; list; list = list->next) + { + w = list->word->word; + + /* We have a word of the form [ind]=value */ + if (w[0] == '[') + { + len = skipsubscript (w, 0); + + if (w[len] != ']' || w[len+1] != '=') + { + nval = make_variable_value (var, w); + if (var->assign_func) + (*var->assign_func) (var, last_ind, nval); + else + array_add_element (a, last_ind, nval); + FREE (nval); + last_ind++; + continue; + } + + if (len == 1) + { + report_error ("%s: bad array subscript", w); + continue; + } + + if (ALL_ELEMENT_SUB (w[1]) && len == 2) + { + report_error ("%s: cannot assign to non-numeric index", w); + continue; + } + + ind = array_expand_index (w + 1, len); + if (ind < 0) + { + report_error ("%s: bad array subscript", w); + continue; + } + last_ind = ind; + val = w + len + 2; + } + else /* No [ind]=value, just a stray `=' */ + { + ind = last_ind; + val = w; + } + + if (integer_p (var)) + this_command_name = (char *)NULL; /* no command name for errors */ + nval = make_variable_value (var, val); + if (var->assign_func) + (*var->assign_func) (var, ind, nval); + else + array_add_element (a, ind, nval); + FREE (nval); + last_ind++; + } + + dispose_words (nlist); + return (var); +} +#endif /* ARRAY_VARS */ + /* Dispose of the information attached to VAR. */ void dispose_variable (var) @@ -1025,9 +1403,13 @@ dispose_variable (var) return; if (function_p (var)) - dispose_command ((COMMAND *)var->value); - else if (var->value) - free (var->value); + dispose_command (function_cell (var)); +#if defined (ARRAY_VARS) + else if (array_p (var)) + dispose_array (array_cell (var)); +#endif + else + FREE (value_cell (var)); free (var->name); @@ -1037,7 +1419,45 @@ dispose_variable (var) free (var); } +#if defined (ARRAY_VARS) +/* This function is called with SUB pointing to just after the beginning + `[' of an array subscript. */ +int +unbind_array_element (var, sub) + SHELL_VAR *var; + char *sub; +{ + int len, ind; + ARRAY_ELEMENT *ae; + + len = skipsubscript (sub, 0); + if (sub[len] != ']' || len == 0) + { + builtin_error ("%s[%s: bad array subscript", var->name, sub); + return -1; + } + sub[len] = '\0'; + + if (ALL_ELEMENT_SUB (sub[0]) && sub[1] == 0) + { + makunbound (var->name, shell_variables); + return (0); + } + ind = array_expand_index (sub, len+1); + if (ind < 0) + { + builtin_error ("[%s: bad array subscript", sub); + return -1; + } + ae = array_delete_element (array_cell (var), ind); + if (ae) + destroy_array_element (ae); + return 0; +} +#endif + /* Unset the variable referenced by NAME. */ +int unbind_variable (name) char *name; { @@ -1046,7 +1466,12 @@ unbind_variable (name) if (!var) return (-1); + /* This function should never be called with an array variable name. */ +#if defined (ARRAY_VARS) + if (array_p (var) == 0 && var->value) +#else if (var->value) +#endif { free (var->value); var->value = (char *)NULL; @@ -1061,6 +1486,7 @@ unbind_variable (name) hash table from which this variable should be deleted (either shell_variables or shell_functions). Returns non-zero if the variable couldn't be found. */ +int makunbound (name, hash_list) char *name; HASH_TABLE *hash_list; @@ -1080,6 +1506,21 @@ makunbound (name, hash_list) if (old_var && exported_p (old_var)) array_needs_making++; + /* If we're unsetting a local variable and we're still executing inside + the function, just mark the variable as invisible. + kill_all_local_variables will clean it up later. This must be done + so that if the variable is subsequently assigned a new value inside + the function, the `local' attribute is still present. We also need + to add it back into the correct hash table. */ + if (old_var && local_p (old_var) && variable_context == old_var->context) + { + old_var->attributes |= att_invisible; + elt = add_hash_item (savestring (old_var->name), hash_list); + elt->data = (char *)old_var; + stupidly_hack_special_variables (old_var->name); + return (0); + } + if (new_var) { /* Has to be a variable, functions don't have previous contexts. */ @@ -1089,7 +1530,7 @@ makunbound (name, hash_list) new_elt->data = (char *)new_var; if (exported_p (new_var)) - set_var_auto_export (new_var->name); + set_auto_export (new_var); } /* Have to save a copy of name here, because it might refer to @@ -1108,12 +1549,13 @@ makunbound (name, hash_list) /* Remove the variable with NAME if it is a local variable in the current context. */ +int kill_local_variable (name) char *name; { SHELL_VAR *temp = find_variable (name); - if (temp && (temp->context == variable_context)) + if (temp && temp->context == variable_context) { makunbound (name, shell_variables); return (0); @@ -1136,8 +1578,15 @@ kill_all_local_variables () register SHELL_VAR *var, **list; HASH_TABLE *varlist; - /* XXX */ - if (!have_local_variables || have_local_variables[variable_context] == 0) + /* If HAVE_LOCAL_VARIABLES == 0, it means that we don't have any local + variables at all. If VARIABLE_CONTEXT >= LOCAL_VARIABLE_STACK_SIZE, + it means that we have some local variables, but not in this variable + context (level of function nesting). Also, if + HAVE_LOCAL_VARIABLES[VARIABLE_CONTEXT] == 0, we have no local variables + at this context. */ + if (have_local_variables == 0 || + variable_context >= local_variable_stack_size || + have_local_variables[variable_context] == 0) return; for (pass = 0; pass < 2; pass++) @@ -1149,8 +1598,10 @@ kill_all_local_variables () if (list) { for (i = 0; var = list[i]; i++) - makunbound (var->name, varlist); - + { + var->attributes &= ~att_local; + makunbound (var->name, varlist); + } free (list); } } @@ -1158,40 +1609,27 @@ kill_all_local_variables () have_local_variables[variable_context] = 0; /* XXX */ } +static void +free_variable_hash_data (data) + char *data; +{ + SHELL_VAR *var, *prev; + + var = (SHELL_VAR *)data; + while (var) + { + prev = var->prev_context; + dispose_variable (var); + var = prev; + } +} + /* Delete the entire contents of the hash table. */ void delete_all_variables (hashed_vars) HASH_TABLE *hashed_vars; { - register int i; - register BUCKET_CONTENTS *bucket; - - for (i = 0; i < hashed_vars->nbuckets; i++) - { - bucket = hashed_vars->bucket_array[i]; - - while (bucket) - { - BUCKET_CONTENTS *temp = bucket; - SHELL_VAR *var, *prev; - - bucket = bucket->next; - - var = (SHELL_VAR *)temp->data; - - while (var) - { - prev = var->prev_context; - dispose_variable (var); - - var = prev; - } - - free (temp->key); - free (temp); - } - hashed_vars->bucket_array[i] = (BUCKET_CONTENTS *)NULL; - } + flush_hash_table (hashed_vars, free_variable_hash_data); } static SHELL_VAR * @@ -1214,8 +1652,9 @@ bind_function (name, value) char *name; COMMAND *value; { - SHELL_VAR *entry = find_function (name); + SHELL_VAR *entry; + entry = find_function (name); if (!entry) { BUCKET_CONTENTS *elt; @@ -1224,8 +1663,7 @@ bind_function (name, value) elt->data = (char *)new_shell_variable (name); entry = (SHELL_VAR *)elt->data; - entry->dynamic_value = (DYNAMIC_FUNC *)NULL; - entry->assign_func = (DYNAMIC_FUNC *)NULL; + entry->dynamic_value = entry->assign_func = (DYNAMIC_FUNC *)NULL; /* Functions are always made at the top level. This allows a function to define another function (like autoload). */ @@ -1235,11 +1673,7 @@ bind_function (name, value) if (entry->value) dispose_command ((COMMAND *)entry->value); - if (value) /* I don't think this can happen anymore */ - entry->value = (char *)copy_command (value); - else - entry->value = (char *)NULL; - + entry->value = value ? (char *)copy_command (value) : (char *)NULL; entry->attributes |= att_function; if (mark_modified_vars) @@ -1247,7 +1681,8 @@ bind_function (name, value) entry->attributes &= ~att_invisible; /* Just to be sure */ - array_needs_making = 1; + if (exported_p (entry)) + array_needs_making = 1; return (entry); } @@ -1267,9 +1702,13 @@ copy_variable (var) copy->name = savestring (var->name); if (function_p (var)) - copy->value = (char *)copy_command ((COMMAND *)var->value); - else if (var->value) - copy->value = savestring (var->value); + copy->value = (char *)copy_command (function_cell (var)); +#if defined (ARRAY_VARS) + else if (array_p (var)) + copy->value = (char *)dup_array (array_cell (var)); +#endif + else if (value_cell (var)) + copy->value = savestring (value_cell (var)); else copy->value = (char *)NULL; @@ -1284,24 +1723,31 @@ copy_variable (var) return (copy); } -/* Make the variable associated with NAME be read-only. +#define FIND_OR_MAKE_VARIABLE(name, entry) \ + do \ + { \ + entry = find_variable (name); \ + if (!entry) \ + { \ + entry = bind_variable (name, ""); \ + if (!no_invisible_vars) entry->attributes |= att_invisible; \ + } \ + } \ + while (0) + +/* Make the variable associated with NAME be readonly. If NAME does not exist yet, create it. */ void set_var_read_only (name) char *name; { - SHELL_VAR *entry = find_variable (name); + SHELL_VAR *entry; - if (!entry) - { - entry = bind_variable (name, ""); - if (!no_invisible_vars) - entry->attributes |= att_invisible; - } + FIND_OR_MAKE_VARIABLE (name, entry); entry->attributes |= att_readonly; } -/* Make the function associated with NAME be read-only. +/* Make the function associated with NAME be readonly. If NAME does not exist, we just punt, like auto_export code below. */ void set_func_read_only (name) @@ -1319,15 +1765,9 @@ void set_var_auto_export (name) char *name; { - SHELL_VAR *entry = find_variable (name); - - if (!entry) - { - entry = bind_variable (name, ""); - if (!no_invisible_vars) - entry->attributes |= att_invisible; - } + SHELL_VAR *entry; + FIND_OR_MAKE_VARIABLE (name, entry); set_auto_export (entry); } @@ -1336,25 +1776,45 @@ void set_func_auto_export (name) char *name; { - SHELL_VAR *entry = find_function (name); + SHELL_VAR *entry; + entry = find_function (name); if (entry) + set_auto_export (entry); +} + +#if defined (ARRAY_VARS) +/* This function assumes s[i] == '['; returns with s[ret] == ']' if + an array subscript is correctly parsed. */ +int +skipsubscript (s, i) + char *s; + int i; +{ + int count, c; + + for (count = 1; count && (c = s[++i]); ) { - entry->attributes |= att_exported; - array_needs_making = 1; + if (c == '[') + count++; + else if (c == ']') + count--; } + return i; } +#endif /* ARRAY_VARS */ /* Returns non-zero if STRING is an assignment statement. The returned value is the index of the `=' sign. */ +int assignment (string) char *string; { - register int c, indx = 0; + register int c, newi, indx; - c = string[indx]; + c = string[indx = 0]; - if (!isletter (c) && c != '_') + if (legal_variable_starter (c) == 0) return (0); while (c = string[indx]) @@ -1364,7 +1824,19 @@ assignment (string) if (c == '=') return (indx); - if (!isletter (c) && !digit (c) && c != '_') +#if defined (ARRAY_VARS) + if (c == '[') + { + newi = skipsubscript (string, indx); + if (string[newi++] != ']') + return (0); + return ((string[newi] == '=') ? newi : 0); + } +#endif /* ARRAY_VARS */ + + /* Variable names in assignment statements may contain only letters, + digits, and `_'. */ + if (legal_variable_char (c) == 0) return (0); indx++; @@ -1376,41 +1848,42 @@ static int visible_var (var) SHELL_VAR *var; { - return (!invisible_p (var)); + return (invisible_p (var) == 0); } -SHELL_VAR ** -all_visible_variables () +static SHELL_VAR ** +_visible_names (table) + HASH_TABLE *table; { SHELL_VAR **list; - list = map_over (visible_var, shell_variables); + list = map_over (visible_var, table); - if (list) + if (list && posixly_correct) sort_variables (list); return (list); } SHELL_VAR ** -all_visible_functions () +all_visible_variables () { - SHELL_VAR **list; - - list = map_over (visible_var, shell_functions); - - if (list) - sort_variables (list); + return (_visible_names (shell_variables)); +} - return (list); +SHELL_VAR ** +all_visible_functions () +{ + return (_visible_names (shell_functions)); } -/* Return non-zero if the variable VAR is visible and exported. */ +/* Return non-zero if the variable VAR is visible and exported. Array + variables cannot be exported. */ static int visible_and_exported (var) SHELL_VAR *var; { - return (!invisible_p (var) && exported_p (var)); + return (invisible_p (var) == 0 && exported_p (var)); } /* Make an array of assignment statements from the hash table @@ -1422,9 +1895,10 @@ make_var_array (hashed_vars) { register int i, list_index; register SHELL_VAR *var; - char **list = (char **)NULL; + char **list, *value; SHELL_VAR **vars; + list = (char **)NULL; vars = map_over (visible_and_exported, hashed_vars); if (!vars) @@ -1434,25 +1908,35 @@ make_var_array (hashed_vars) for (i = 0, list_index = 0; var = vars[i]; i++) { - char *value; - if (function_p (var)) - value = named_function_string - ((char *)NULL, (COMMAND *)function_cell (var), 0); + value = named_function_string ((char *)NULL, function_cell (var), 0); +#if defined (ARRAY_VARS) + else if (array_p (var)) +# if 0 + value = array_to_assignment_string (array_cell (var)); +# else + continue; /* XXX array vars cannot yet be exported */ +# endif +#endif else value = value_cell (var); if (value) { - int name_len = strlen (var->name); - int value_len = strlen (value); + int name_len, value_len; char *p; + name_len = strlen (var->name); + value_len = strlen (value); p = list[list_index] = xmalloc (2 + name_len + value_len); strcpy (p, var->name); p[name_len] = '='; strcpy (p + name_len + 1, value); list_index++; +#if defined (ARRAY_VARS) + if (array_p (var)) + free (value); +#endif } } @@ -1463,23 +1947,35 @@ make_var_array (hashed_vars) /* Add STRING to the array of foo=bar strings that we already have to add to the environment. */ +int assign_in_env (string) char *string; { - int size; - - int offset = assignment (string); - char *name = savestring (string); - char *temp, *value = (char *)NULL; + int size, offset; + char *name, *temp, *value; int nlen, vlen; + WORD_LIST *list; + SHELL_VAR *var; + + offset = assignment (string); + name = savestring (string); + value = (char *)NULL; +#define freetemp nlen if (name[offset] == '=') { - WORD_LIST *list; - name[offset] = 0; + + var = find_variable (name); + if (var && readonly_p (var)) + { + report_error ("%s: readonly variable", name); + return (0); + } temp = name + offset + 1; - temp = tilde_expand (temp); + freetemp = strchr (temp, '~') != 0; + if (freetemp) + temp = bash_tilde_expand (temp); list = expand_string_unsplit (temp, 0); value = string_list (list); @@ -1487,22 +1983,26 @@ assign_in_env (string) if (list) dispose_words (list); - free (temp); + if (freetemp) + free (temp); } - - if (!value) - value = savestring (""); +#undef freetemp nlen = strlen (name); - vlen = strlen (value); + vlen = value ? strlen (value) : 0; temp = xmalloc (2 + nlen + vlen); strcpy (temp, name); temp[nlen] = '='; - strcpy (temp + nlen + 1, value); + temp[nlen + 1] = '\0'; + if (value) + { + if (*value) + strcpy (temp + nlen + 1, value); + free (value); + } free (name); - free (value); - if (!temporary_env) + if (temporary_env == 0) { temporary_env = (char **)xmalloc (sizeof (char *)); temporary_env [0] = (char *)NULL; @@ -1512,13 +2012,13 @@ assign_in_env (string) temporary_env = (char **) xrealloc (temporary_env, (size + 2) * (sizeof (char *))); - temporary_env[size] = (temp); + temporary_env[size] = temp; temporary_env[size + 1] = (char *)NULL; array_needs_making = 1; if (echo_command_at_execute) { - /* The K*rn shell prints the `+ ' in front of assignment statements, + /* The Korn shell prints the `+ ' in front of assignment statements, so we do too. */ fprintf (stderr, "%s%s\n", indirection_level_string (), temp); fflush (stderr); @@ -1535,30 +2035,28 @@ find_name_in_env_array (name, array) char *name; char **array; { - register int i, l = strlen (name); + register int i, l; - if (!array) + if (array == 0) return ((SHELL_VAR *)NULL); - for (i = 0; array[i]; i++) + for (i = 0, l = strlen (name); array[i]; i++) { if (STREQN (array[i], name, l) && array[i][l] == '=') { SHELL_VAR *temp; + char *w; temp = new_shell_variable (name); + w = array[i] + l + 1; - if (array[i][l + 1]) - temp->value = savestring (&array[i][l + 1]); - else - temp->value = (char *) NULL; + temp->value = *w ? savestring (w) : (char *)NULL; temp->attributes = att_exported; temp->context = 0; temp->prev_context = (SHELL_VAR *)NULL; - temp->dynamic_value = (DYNAMIC_FUNC *)NULL; - temp->assign_func = (DYNAMIC_FUNC *)NULL; + temp->dynamic_value = temp->assign_func = (DYNAMIC_FUNC *)NULL; return (temp); } @@ -1631,13 +2129,40 @@ dispose_builtin_env () dispose_temporary_vars (&builtin_env); } -/* Sort ARRAY, a null terminated array of pointers to strings. */ +/* Take all of the shell variables in ENV_ARRAY and make shell variables + from them at the current variable context. */ +static void +merge_env_array (env_array) + char **env_array; +{ + register int i, l; + SHELL_VAR *temp; + char *w, *name; + + if (env_array == 0) + return; + + for (i = 0; env_array[i]; i++) + { + l = assignment (env_array[i]); + name = env_array[i]; + w = env_array[i] + l + 1; + name[l] = '\0'; + temp = bind_variable (name, w); + name[l] = '='; + } +} + void -sort_char_array (array) - char **array; +merge_temporary_env () { - qsort (array, array_len (array), sizeof (char *), - (Function *)qsort_string_compare); + merge_env_array (temporary_env); +} + +void +merge_builtin_env () +{ + merge_env_array (builtin_env); } #define ISFUNC(s, o) ((s[o + 1] == '(') && (s[o + 2] == ')')) @@ -1690,21 +2215,9 @@ maybe_make_export_env () if (export_env) free_array (export_env); -#ifdef SHADOWED_ENV - export_env = - (char **)xmalloc ((1 + array_len (shell_environment)) * sizeof (char *)); - - for (i = 0; shell_environment[i]; i++) - export_env[i] = savestring (shell_environment[i]); - export_env[i] = (char *)NULL; - -#else /* !SHADOWED_ENV */ - export_env = (char **)xmalloc (sizeof (char *)); export_env[0] = (char *)NULL; -#endif /* SHADOWED_ENV */ - temp_array = make_var_array (shell_variables); for (i = 0; temp_array && temp_array[i]; i++) export_env = add_or_supercede (temp_array[i], export_env); @@ -1723,9 +2236,11 @@ maybe_make_export_env () for (i = 0; temporary_env[i]; i++) export_env = add_or_supercede (temporary_env[i], export_env); +#if 0 /* If we changed the array, then sort it alphabetically. */ - if (temporary_env || function_env) + if (posixly_correct == 0 && (temporary_env || function_env)) sort_char_array (export_env); +#endif array_needs_making = 0; } @@ -1748,57 +2263,56 @@ put_command_name_into_env (command_name) free (dummy); } -/* We supply our own version of getenv () because we want library - routines to get the changed values of exported variables. */ +void +put_gnu_argv_flags_into_env (pid, flags_string) + int pid; + char *flags_string; +{ + char *dummy, *pbuf; + int l, fl; + + pbuf = itos (pid); + l = strlen (pbuf); + + fl = strlen (flags_string); + + dummy = xmalloc (l + fl + 30); + dummy[0] = '_'; + strcpy (dummy + 1, pbuf); + strcpy (dummy + 1 + l, "_GNU_nonoption_argv_flags_"); + dummy[l + 27] = '='; + strcpy (dummy + l + 28, flags_string); + + free (pbuf); + + export_env = add_or_supercede (dummy, export_env); + free (dummy); +} -/* The NeXT C library has getenv () defined and used in the same file. - This screws our scheme. However, Bash will run on the NeXT using - the C library getenv (), since right now the only environment variable - that we care about is HOME, and that is already defined. */ -#if !defined (NeXT) && !defined (HPOSF1) -static char *last_tempenv_value = (char *)NULL; -extern char **environ; +/* Return a string denoting what our indirection level is. */ +static char indirection_string[100]; char * -getenv (name) -#if defined (Linux) || defined (__bsdi__) || defined (convex) - const char *name; -#else - char const *name; -#endif /* !Linux */ +indirection_level_string () { - SHELL_VAR *var = find_tempenv_variable ((char *)name); + register int i, j; + char *ps4; - if (var) - { - FREE (last_tempenv_value); + indirection_string[0] = '\0'; + ps4 = get_string_value ("PS4"); - last_tempenv_value = savestring (value_cell (var)); - dispose_variable (var); - return (last_tempenv_value); - } - else if (shell_variables) - { - var = find_variable ((char *)name); - if (var && exported_p (var)) - return (value_cell (var)); - } - else - { - register int i, len = strlen (name); + if (ps4 == 0 || *ps4 == '\0') + return (indirection_string); - /* In some cases, s5r3 invokes getenv() before main(); BSD systems - using gprof also exhibit this behavior. This means that - shell_variables will be 0 when this is invoked. We look up the - variable in the real environment in that case. */ + ps4 = decode_prompt_string (ps4); - for (i = 0; environ[i]; i++) - { - if ((STREQN (environ[i], name, len)) && (environ[i][len] == '=')) - return (environ[i] + len + 1); - } - } + for (i = 0; *ps4 && i < indirection_level && i < 99; i++) + indirection_string[i] = *ps4; + + for (j = 1; *ps4 && ps4[j] && i < 99; i++, j++) + indirection_string[i] = ps4[j]; - return ((char *)NULL); + indirection_string[i] = '\0'; + free (ps4); + return (indirection_string); } -#endif /* !NeXT && !HPOSF1 */ |
