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
/* 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 ();
#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)
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);
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);
/* 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 ();
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);
}
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");
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. */
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);
#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");
#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
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. */
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);
SHELL_VAR **list;
list = map_over ((Function *)NULL, table);
- if (list)
+ if (list && posixly_correct)
sort_variables (list);
return (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;
{
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
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
/* 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);
}
/* 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. */
SHELL_VAR *self;
char *value;
{
- int s = atoi (value);
-
- sbrand (s);
+ sbrand (atoi (value));
return (self);
}
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);
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)
}
#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 ()
{
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.
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,
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. */
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);
}
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);
}
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);
}
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)
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)
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);
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;
{
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;
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;
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. */
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
/* 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);
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++)
if (list)
{
for (i = 0; var = list[i]; i++)
- makunbound (var->name, varlist);
-
+ {
+ var->attributes &= ~att_local;
+ makunbound (var->name, varlist);
+ }
free (list);
}
}
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 *
char *name;
COMMAND *value;
{
- SHELL_VAR *entry = find_function (name);
+ SHELL_VAR *entry;
+ entry = find_function (name);
if (!entry)
{
BUCKET_CONTENTS *elt;
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). */
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)
entry->attributes &= ~att_invisible; /* Just to be sure */
- array_needs_making = 1;
+ if (exported_p (entry))
+ array_needs_making = 1;
return (entry);
}
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;
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)
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);
}
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])
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++;
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
{
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)
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
}
}
/* 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);
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;
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);
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);
}
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] == ')'))
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);
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;
}
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 */