Imported from ../bash-2.04.tar.gz.
This commit is contained in:
parent
b72432fdcc
commit
bb70624e96
387 changed files with 28522 additions and 9334 deletions
543
variables.c
543
variables.c
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
Bash is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Bash; see the file COPYING. If not, write to the Free
|
||||
Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
|
|
@ -58,6 +58,10 @@
|
|||
# include <readline/history.h>
|
||||
#endif /* HISTORY */
|
||||
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
# include "pcomplete.h"
|
||||
#endif
|
||||
|
||||
/* Variables used here and defined in other files. */
|
||||
extern int posixly_correct;
|
||||
extern int variable_context, line_number;
|
||||
|
|
@ -69,6 +73,7 @@ extern char *shell_name;
|
|||
extern char *primary_prompt, *secondary_prompt;
|
||||
extern char *current_host_name;
|
||||
extern Function *this_shell_builtin;
|
||||
extern SHELL_VAR *this_shell_function;
|
||||
extern char *this_command_name;
|
||||
extern time_t shell_start_time;
|
||||
|
||||
|
|
@ -175,17 +180,14 @@ initialize_shell_variables (env, privmode)
|
|||
char_index == strlen (name) */
|
||||
|
||||
/* If exported function, define it now. */
|
||||
if (privmode == 0 && STREQN ("() {", string, 4))
|
||||
if (privmode == 0 && read_but_dont_execute == 0 && STREQN ("() {", string, 4))
|
||||
{
|
||||
string_length = strlen (string);
|
||||
temp_string = xmalloc (3 + string_length + char_index);
|
||||
#if 1
|
||||
|
||||
strcpy (temp_string, name);
|
||||
temp_string[char_index] = ' ';
|
||||
strcpy (temp_string + char_index + 1, string);
|
||||
#else
|
||||
sprintf (temp_string, "%s %s", name, string);
|
||||
#endif
|
||||
|
||||
parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST);
|
||||
|
||||
|
|
@ -196,14 +198,15 @@ initialize_shell_variables (env, privmode)
|
|||
|
||||
if (temp_var = find_function (name))
|
||||
{
|
||||
temp_var->attributes |= (att_exported | att_imported);
|
||||
VSETATTR (temp_var, (att_exported|att_imported));
|
||||
array_needs_making = 1;
|
||||
}
|
||||
else
|
||||
report_error ("error importing function definition for `%s'", name);
|
||||
|
||||
/* ( */
|
||||
if (name[char_index - 1] == ')' && name[char_index - 2] == '\0')
|
||||
name[char_index - 2] = '(';
|
||||
name[char_index - 2] = '('; /* ) */
|
||||
}
|
||||
#if defined (ARRAY_VARS)
|
||||
# if 0
|
||||
|
|
@ -214,7 +217,7 @@ initialize_shell_variables (env, privmode)
|
|||
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);
|
||||
VSETATTR (temp_var, (att_exported | att_imported));
|
||||
array_needs_making = 1;
|
||||
}
|
||||
# endif
|
||||
|
|
@ -222,11 +225,17 @@ initialize_shell_variables (env, privmode)
|
|||
else
|
||||
{
|
||||
temp_var = bind_variable (name, string);
|
||||
temp_var->attributes |= (att_exported | att_imported);
|
||||
VSETATTR (temp_var, (att_exported | att_imported));
|
||||
array_needs_making = 1;
|
||||
}
|
||||
|
||||
name[char_index] = '=';
|
||||
/* temp_var can be NULL if it was an exported function with a syntax
|
||||
error (a different bug, but it still shouldn't dump core). */
|
||||
if (temp_var && function_p (temp_var) == 0) /* XXX not yet */
|
||||
{
|
||||
CACHE_IMPORTSTR (temp_var, name);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we got PWD from the environment, update our idea of the current
|
||||
|
|
@ -253,7 +262,7 @@ initialize_shell_variables (env, privmode)
|
|||
`environment variable' and therefore should be auto-exported.
|
||||
Make a dummy invisible variable for OLDPWD, and mark it as exported. */
|
||||
temp_var = bind_variable ("OLDPWD", (char *)NULL);
|
||||
temp_var->attributes |= (att_exported | att_invisible);
|
||||
VSETATTR (temp_var, (att_exported | att_invisible));
|
||||
|
||||
/* Set up initial value of $_ */
|
||||
temp_var = bind_variable ("_", dollar_vars[0]);
|
||||
|
|
@ -391,6 +400,13 @@ initialize_shell_variables (env, privmode)
|
|||
}
|
||||
#endif /* HISTORY */
|
||||
|
||||
temp_var = find_variable ("SSH_CLIENT");
|
||||
if (temp_var && imported_p (temp_var))
|
||||
{
|
||||
VUNSETATTR (temp_var, att_exported);
|
||||
array_needs_making = 1;
|
||||
}
|
||||
|
||||
/* Get the user's real and effective user ids. */
|
||||
uidset ();
|
||||
|
||||
|
|
@ -419,7 +435,7 @@ set_home_var ()
|
|||
temp_var = find_variable ("HOME");
|
||||
if (temp_var == 0)
|
||||
temp_var = bind_variable ("HOME", get_home_dir ());
|
||||
temp_var->attributes |= att_exported;
|
||||
VSETATTR (temp_var, att_exported);
|
||||
}
|
||||
|
||||
/* Set $SHELL to the user's login shell if it is not already set. Call
|
||||
|
|
@ -436,7 +452,7 @@ set_shell_var ()
|
|||
get_current_user_info ();
|
||||
temp_var = bind_variable ("SHELL", current_user.shell);
|
||||
}
|
||||
temp_var->attributes |= att_exported;
|
||||
VSETATTR (temp_var, att_exported);
|
||||
}
|
||||
|
||||
static char *
|
||||
|
|
@ -555,12 +571,6 @@ adjust_shell_level (change)
|
|||
static void
|
||||
initialize_shell_level ()
|
||||
{
|
||||
#if 0
|
||||
SHELL_VAR *temp_var;
|
||||
|
||||
temp_var = set_if_not ("SHLVL", "0");
|
||||
set_auto_export (temp_var);
|
||||
#endif
|
||||
adjust_shell_level (1);
|
||||
}
|
||||
|
||||
|
|
@ -574,9 +584,9 @@ set_ppid ()
|
|||
name = inttostr ((int) getppid (), namebuf, sizeof(namebuf));
|
||||
temp_var = find_variable ("PPID");
|
||||
if (temp_var)
|
||||
temp_var->attributes &= ~(att_readonly | att_exported);
|
||||
VUNSETATTR (temp_var, (att_readonly | att_exported));
|
||||
temp_var = bind_variable ("PPID", name);
|
||||
temp_var->attributes |= (att_readonly | att_integer);
|
||||
VSETATTR (temp_var, (att_readonly | att_integer));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -588,20 +598,20 @@ uidset ()
|
|||
b = inttostr (current_user.uid, buff, sizeof (buff));
|
||||
v = find_variable ("UID");
|
||||
if (v)
|
||||
v->attributes &= ~att_readonly;
|
||||
VUNSETATTR (v, att_readonly);
|
||||
|
||||
v = bind_variable ("UID", b);
|
||||
v->attributes |= (att_readonly | att_integer);
|
||||
VSETATTR (v, (att_readonly | att_integer));
|
||||
|
||||
if (current_user.euid != current_user.uid)
|
||||
b = inttostr (current_user.euid, buff, sizeof (buff));
|
||||
|
||||
v = find_variable ("EUID");
|
||||
if (v)
|
||||
v->attributes &= ~att_readonly;
|
||||
VUNSETATTR (v, att_readonly);
|
||||
|
||||
v = bind_variable ("EUID", b);
|
||||
v->attributes |= (att_readonly | att_integer);
|
||||
VSETATTR (v, (att_readonly | att_integer));
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
|
|
@ -629,7 +639,7 @@ make_vers_array ()
|
|||
array_add_element (av, 4, release_status);
|
||||
array_add_element (av, 5, MACHTYPE);
|
||||
|
||||
vv->attributes |= att_readonly;
|
||||
VSETATTR (vv, att_readonly);
|
||||
}
|
||||
#endif /* ARRAY_VARS */
|
||||
|
||||
|
|
@ -893,6 +903,25 @@ print_array_assignment (var, quoted)
|
|||
stupidly_hack_special_variables, but I wanted the changes as
|
||||
localized as possible. */
|
||||
|
||||
static SHELL_VAR *
|
||||
null_assign (self, value)
|
||||
SHELL_VAR *self;
|
||||
char *value;
|
||||
{
|
||||
return (self);
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
static SHELL_VAR *
|
||||
null_array_assign (self, ind, value)
|
||||
SHELL_VAR *self;
|
||||
int ind;
|
||||
char *value;
|
||||
{
|
||||
return (self);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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. */
|
||||
|
|
@ -920,7 +949,7 @@ get_seconds (var)
|
|||
|
||||
FREE (var->value);
|
||||
|
||||
var->attributes |= att_integer;
|
||||
VSETATTR (var, att_integer);
|
||||
var->value = p;
|
||||
return (var);
|
||||
}
|
||||
|
|
@ -979,7 +1008,7 @@ get_random (var)
|
|||
|
||||
FREE (var->value);
|
||||
|
||||
var->attributes |= att_integer;
|
||||
VSETATTR (var, att_integer);
|
||||
var->value = p;
|
||||
return (var);
|
||||
}
|
||||
|
|
@ -1071,42 +1100,74 @@ get_groupset (self)
|
|||
return (self);
|
||||
}
|
||||
#endif /* ARRAY_VARS */
|
||||
|
||||
|
||||
static SHELL_VAR *
|
||||
get_funcname (self)
|
||||
SHELL_VAR *self;
|
||||
{
|
||||
if (variable_context && this_shell_function)
|
||||
{
|
||||
FREE (self->value);
|
||||
self->value = savestring (this_shell_function->name);
|
||||
}
|
||||
return (self);
|
||||
}
|
||||
|
||||
void
|
||||
make_funcname_visible (on_or_off)
|
||||
int on_or_off;
|
||||
{
|
||||
SHELL_VAR *v;
|
||||
|
||||
v = find_variable ("FUNCNAME");
|
||||
if (v == 0 || v->dynamic_value == 0)
|
||||
return;
|
||||
|
||||
if (on_or_off)
|
||||
VUNSETATTR (v, att_invisible);
|
||||
else
|
||||
VSETATTR (v, att_invisible);
|
||||
}
|
||||
|
||||
#define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \
|
||||
do \
|
||||
{ \
|
||||
v = bind_variable (var, val); \
|
||||
v->dynamic_value = gfunc; \
|
||||
v->assign_func = afunc; \
|
||||
} while (0)
|
||||
|
||||
#define INIT_DYNAMIC_ARRAY_VAR(var, gfunc, afunc) \
|
||||
do \
|
||||
{ \
|
||||
v = make_new_array_variable (var); \
|
||||
v->dynamic_value = gfunc; \
|
||||
v->assign_func = afunc; \
|
||||
} while (0)
|
||||
|
||||
static void
|
||||
initialize_dynamic_variables ()
|
||||
{
|
||||
SHELL_VAR *v;
|
||||
|
||||
v = bind_variable ("SECONDS", (char *)NULL);
|
||||
v->dynamic_value = get_seconds;
|
||||
v->assign_func = assign_seconds;
|
||||
|
||||
v = bind_variable ("RANDOM", (char *)NULL);
|
||||
v->dynamic_value = get_random;
|
||||
v->assign_func = assign_random;
|
||||
|
||||
v = bind_variable ("LINENO", (char *)NULL);
|
||||
v->dynamic_value = get_lineno;
|
||||
v->assign_func = assign_lineno;
|
||||
INIT_DYNAMIC_VAR ("SECONDS", (char *)NULL, get_seconds, assign_seconds);
|
||||
INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random);
|
||||
INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno);
|
||||
|
||||
#if defined (HISTORY)
|
||||
v = bind_variable ("HISTCMD", (char *)NULL);
|
||||
v->dynamic_value = get_histcmd;
|
||||
v->assign_func = (DYNAMIC_FUNC *)NULL;
|
||||
INIT_DYNAMIC_VAR ("HISTCMD", (char *)NULL, get_histcmd, (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;
|
||||
INIT_DYNAMIC_ARRAY_VAR ("DIRSTACK", get_dirstack, assign_dirstack);
|
||||
#endif /* PUSHD_AND_POPD && ARRAY_VARS */
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
v = make_new_array_variable ("GROUPS");
|
||||
v->dynamic_value = get_groupset;
|
||||
v->assign_func = (DYNAMIC_FUNC *)NULL;
|
||||
v->attributes |= att_readonly;
|
||||
INIT_DYNAMIC_ARRAY_VAR ("GROUPS", get_groupset, null_array_assign);
|
||||
#endif
|
||||
|
||||
INIT_DYNAMIC_VAR ("FUNCNAME", (char *)NULL, get_funcname, null_assign);
|
||||
VSETATTR (v, att_invisible);
|
||||
}
|
||||
|
||||
/* How to get a pointer to the shell variable or function named NAME.
|
||||
|
|
@ -1211,6 +1272,15 @@ make_local_variable (name)
|
|||
if (old_var && old_var->context == variable_context)
|
||||
return (old_var);
|
||||
|
||||
/* Since this is called only from the local/declare/typeset code, we can
|
||||
call builtin_error here without worry (of course, it will also work
|
||||
for anything that sets this_command_name). */
|
||||
if (old_var && readonly_p (old_var))
|
||||
{
|
||||
builtin_error ("%s: readonly variable");
|
||||
return ((SHELL_VAR *)NULL);
|
||||
}
|
||||
|
||||
elt = remove_hash_item (name, shell_variables);
|
||||
if (elt)
|
||||
{
|
||||
|
|
@ -1233,6 +1303,8 @@ make_local_variable (name)
|
|||
new_var->value = xmalloc (1);
|
||||
new_var->value[0] = '\0';
|
||||
|
||||
CLEAR_EXPORTSTR (new_var);
|
||||
|
||||
new_var->dynamic_value = (DYNAMIC_FUNC *)NULL;
|
||||
new_var->assign_func = (DYNAMIC_FUNC *)NULL;
|
||||
|
||||
|
|
@ -1244,7 +1316,7 @@ make_local_variable (name)
|
|||
}
|
||||
|
||||
new_var->context = variable_context;
|
||||
new_var->attributes |= att_local;
|
||||
VSETATTR (new_var, att_local);
|
||||
|
||||
/* XXX */
|
||||
if (variable_context >= local_variable_stack_size)
|
||||
|
|
@ -1269,11 +1341,13 @@ make_local_array_variable (name)
|
|||
ARRAY *array;
|
||||
|
||||
var = make_local_variable (name);
|
||||
if (var == 0)
|
||||
return var;
|
||||
array = new_array ();
|
||||
|
||||
FREE (value_cell(var));
|
||||
var->value = (char *)array;
|
||||
var->attributes |= att_array;
|
||||
VSETATTR (var, att_array);
|
||||
return var;
|
||||
}
|
||||
#endif /* ARRAY_VARS */
|
||||
|
|
@ -1293,6 +1367,7 @@ make_new_variable (name)
|
|||
entry->attributes = 0;
|
||||
entry->name = savestring (name);
|
||||
entry->value = (char *)NULL;
|
||||
CLEAR_EXPORTSTR (entry);
|
||||
|
||||
entry->dynamic_value = (DYNAMIC_FUNC *)NULL;
|
||||
entry->assign_func = (DYNAMIC_FUNC *)NULL;
|
||||
|
|
@ -1320,7 +1395,7 @@ make_new_array_variable (name)
|
|||
entry = make_new_variable (name);
|
||||
array = new_array ();
|
||||
entry->value = (char *)array;
|
||||
entry->attributes |= att_array;
|
||||
VSETATTR (entry, att_array);
|
||||
return entry;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1383,7 +1458,10 @@ bind_variable (name, value)
|
|||
#else
|
||||
else if (entry->assign_func)
|
||||
#endif
|
||||
return ((*(entry->assign_func)) (entry, value));
|
||||
{
|
||||
INVALIDATE_EXPORTSTR (entry);
|
||||
return ((*(entry->assign_func)) (entry, value));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (readonly_p (entry))
|
||||
|
|
@ -1393,10 +1471,13 @@ bind_variable (name, value)
|
|||
}
|
||||
|
||||
/* Variables which are bound are visible. */
|
||||
entry->attributes &= ~att_invisible;
|
||||
VUNSETATTR (entry, att_invisible);
|
||||
|
||||
newval = make_variable_value (entry, value);
|
||||
|
||||
/* Invalidate any cached export string */
|
||||
INVALIDATE_EXPORTSTR (entry);
|
||||
|
||||
#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
|
||||
|
|
@ -1419,7 +1500,7 @@ bind_variable (name, value)
|
|||
}
|
||||
|
||||
if (mark_modified_vars)
|
||||
entry->attributes |= att_exported;
|
||||
VSETATTR (entry, att_exported);
|
||||
|
||||
if (exported_p (entry))
|
||||
array_needs_making = 1;
|
||||
|
|
@ -1427,6 +1508,67 @@ bind_variable (name, value)
|
|||
return (entry);
|
||||
}
|
||||
|
||||
/* Make VAR, a simple shell variable, have value VALUE. Once assigned a
|
||||
value, variables are no longer invisible. This is a duplicate of part
|
||||
of the internals of bind_variable. If the variable is exported, or
|
||||
all modified variables should be exported, mark the variable for export
|
||||
and note that the export environment needs to be recreated. */
|
||||
SHELL_VAR *
|
||||
bind_variable_value (var, value)
|
||||
SHELL_VAR *var;
|
||||
char *value;
|
||||
{
|
||||
char *t;
|
||||
|
||||
VUNSETATTR (var, att_invisible);
|
||||
|
||||
t = make_variable_value (var, value);
|
||||
FREE (var->value);
|
||||
var->value = t;
|
||||
|
||||
INVALIDATE_EXPORTSTR (var);
|
||||
|
||||
if (mark_modified_vars)
|
||||
VSETATTR (var, att_exported);
|
||||
|
||||
if (exported_p (var))
|
||||
array_needs_making = 1;
|
||||
|
||||
return (var);
|
||||
}
|
||||
|
||||
/* Bind/create a shell variable with the name LHS to the RHS.
|
||||
This creates or modifies a variable such that it is an integer.
|
||||
|
||||
This used to be in expr.c, but it is here so that all of the
|
||||
variable binding stuff is localized. Since we don't want any
|
||||
recursive evaluation from bind_variable() (possible without this code,
|
||||
since bind_variable() calls the evaluator for variables with the integer
|
||||
attribute set), we temporarily turn off the integer attribute for each
|
||||
variable we set here, then turn it back on after binding as necessary. */
|
||||
|
||||
SHELL_VAR *
|
||||
bind_int_variable (lhs, rhs)
|
||||
char *lhs, *rhs;
|
||||
{
|
||||
register SHELL_VAR *v;
|
||||
int isint;
|
||||
|
||||
isint = 0;
|
||||
v = find_variable (lhs);
|
||||
if (v)
|
||||
{
|
||||
isint = integer_p (v);
|
||||
VUNSETATTR (v, att_integer);
|
||||
}
|
||||
|
||||
v = bind_variable (lhs, rhs);
|
||||
if (isint)
|
||||
VSETATTR (v, att_integer);
|
||||
|
||||
return (v);
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
/* Convert a shell variable to an array variable. The original value is
|
||||
saved as array[0]. */
|
||||
|
|
@ -1440,10 +1582,14 @@ convert_var_to_array (var)
|
|||
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;
|
||||
|
||||
INVALIDATE_EXPORTSTR (var);
|
||||
|
||||
VSETATTR (var, att_array);
|
||||
VUNSETATTR (var, att_invisible);
|
||||
|
||||
return var;
|
||||
}
|
||||
|
|
@ -1526,6 +1672,40 @@ assign_array_var_from_word_list (var, list)
|
|||
return var;
|
||||
}
|
||||
|
||||
/* For each word in a compound array assignment, if the word looks like
|
||||
[ind]=value, quote the `[' and `]' before the `=' to protect them from
|
||||
unwanted filename expansion. */
|
||||
static void
|
||||
quote_array_assignment_chars (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *s, *t, *nword;
|
||||
int saw_eq;
|
||||
WORD_LIST *l;
|
||||
|
||||
for (l = list; l; l = l->next)
|
||||
{
|
||||
if (l->word == 0 || l->word->word == 0 || l->word->word[0] == '\0')
|
||||
continue; /* should not happen, but just in case... */
|
||||
/* Don't bother if it doesn't look like [ind]=value */
|
||||
if (l->word->word[0] != '[' || strchr (l->word->word, '=') == 0) /* ] */
|
||||
continue;
|
||||
s = nword = xmalloc (strlen (l->word->word) * 2 + 1);
|
||||
saw_eq = 0;
|
||||
for (t = l->word->word; *t; )
|
||||
{
|
||||
if (*t == '=')
|
||||
saw_eq = 1;
|
||||
if (saw_eq == 0 && (*t == '[' || *t == ']'))
|
||||
*s++ = '\\';
|
||||
*s++ = *t++;
|
||||
}
|
||||
*s = '\0';
|
||||
free (l->word->word);
|
||||
l->word->word = nword;
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform a compound array assignment: VAR->name=( VALUE ). The
|
||||
VALUE has already had the parentheses stripped. */
|
||||
SHELL_VAR *
|
||||
|
|
@ -1559,13 +1739,15 @@ assign_array_var_from_string (var, value)
|
|||
/* First we split the string on whitespace, using the shell parser
|
||||
(ksh93 seems to do this). */
|
||||
list = parse_string_to_word_list (val, "array assign");
|
||||
|
||||
/* If we're using [subscript]=value, we need to quote each [ and ] to
|
||||
prevent unwanted filename expansion. */
|
||||
if (list)
|
||||
quote_array_assignment_chars (list);
|
||||
|
||||
/* Now that we've split it, perform the shell expansions on each
|
||||
word in the list. */
|
||||
#if 0
|
||||
nlist = list ? expand_words_shellexp (list) : (WORD_LIST *)NULL;
|
||||
#else
|
||||
nlist = list ? expand_words_no_vars (list) : (WORD_LIST *)NULL;
|
||||
#endif
|
||||
|
||||
dispose_words (list);
|
||||
|
||||
|
|
@ -1660,6 +1842,8 @@ dispose_variable (var)
|
|||
else
|
||||
FREE (value_cell (var));
|
||||
|
||||
FREE_EXPORTSTR (var);
|
||||
|
||||
free (var->name);
|
||||
|
||||
if (exported_p (var))
|
||||
|
|
@ -1756,6 +1940,11 @@ makunbound (name, hash_list)
|
|||
if (old_var && exported_p (old_var))
|
||||
array_needs_making++;
|
||||
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
if (hash_list == shell_functions)
|
||||
set_itemlist_dirty (&it_functions);
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
|
|
@ -1764,7 +1953,8 @@ makunbound (name, hash_list)
|
|||
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;
|
||||
VSETATTR (old_var, att_invisible);
|
||||
INVALIDATE_EXPORTSTR (old_var);
|
||||
new_elt = add_hash_item (savestring (old_var->name), hash_list);
|
||||
new_elt->data = (char *)old_var;
|
||||
stupidly_hack_special_variables (old_var->name);
|
||||
|
|
@ -1852,7 +2042,7 @@ kill_all_local_variables ()
|
|||
{
|
||||
for (i = 0; var = list[i]; i++)
|
||||
{
|
||||
var->attributes &= ~att_local;
|
||||
VUNSETATTR (var, att_local);
|
||||
makunbound (var->name, varlist);
|
||||
}
|
||||
free (list);
|
||||
|
|
@ -1914,29 +2104,37 @@ bind_function (name, value)
|
|||
|
||||
elt = add_hash_item (savestring (name), shell_functions);
|
||||
|
||||
elt->data = (char *)new_shell_variable (name);
|
||||
entry = (SHELL_VAR *)elt->data;
|
||||
entry = new_shell_variable (name);
|
||||
entry->dynamic_value = entry->assign_func = (DYNAMIC_FUNC *)NULL;
|
||||
CLEAR_EXPORTSTR (entry);
|
||||
|
||||
/* Functions are always made at the top level. This allows a
|
||||
function to define another function (like autoload). */
|
||||
entry->context = 0;
|
||||
|
||||
elt->data = (char *)entry;
|
||||
}
|
||||
|
||||
INVALIDATE_EXPORTSTR (entry);
|
||||
|
||||
if (entry->value)
|
||||
dispose_command ((COMMAND *)entry->value);
|
||||
|
||||
entry->value = value ? (char *)copy_command (value) : (char *)NULL;
|
||||
entry->attributes |= att_function;
|
||||
VSETATTR (entry, att_function);
|
||||
|
||||
if (mark_modified_vars)
|
||||
entry->attributes |= att_exported;
|
||||
VSETATTR (entry, att_exported);
|
||||
|
||||
entry->attributes &= ~att_invisible; /* Just to be sure */
|
||||
VUNSETATTR (entry, att_invisible); /* Just to be sure */
|
||||
|
||||
if (exported_p (entry))
|
||||
array_needs_making = 1;
|
||||
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
set_itemlist_dirty (&it_functions);
|
||||
#endif
|
||||
|
||||
return (entry);
|
||||
}
|
||||
|
||||
|
|
@ -1969,6 +2167,8 @@ copy_variable (var)
|
|||
copy->dynamic_value = var->dynamic_value;
|
||||
copy->assign_func = var->assign_func;
|
||||
|
||||
copy->exportstr = COPY_EXPORTSTR (var);
|
||||
|
||||
copy->context = var->context;
|
||||
|
||||
/* Don't bother copying previous contexts along with this variable. */
|
||||
|
|
@ -1999,7 +2199,7 @@ set_var_read_only (name)
|
|||
SHELL_VAR *entry;
|
||||
|
||||
FIND_OR_MAKE_VARIABLE (name, entry);
|
||||
entry->attributes |= att_readonly;
|
||||
VSETATTR (entry, att_readonly);
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_UNUSED
|
||||
|
|
@ -2013,7 +2213,7 @@ set_func_read_only (name)
|
|||
|
||||
entry = find_function (name);
|
||||
if (entry)
|
||||
entry->attributes |= att_readonly;
|
||||
VSETATTR (entry, att_readonly);
|
||||
}
|
||||
|
||||
/* Make the variable associated with NAME be auto-exported.
|
||||
|
|
@ -2102,8 +2302,6 @@ assignment (string)
|
|||
return (0);
|
||||
}
|
||||
|
||||
#ifdef READLINE
|
||||
|
||||
static int
|
||||
visible_var (var)
|
||||
SHELL_VAR *var;
|
||||
|
|
@ -2125,19 +2323,17 @@ _visible_names (table)
|
|||
return (list);
|
||||
}
|
||||
|
||||
SHELL_VAR **
|
||||
all_visible_variables ()
|
||||
{
|
||||
return (_visible_names (shell_variables));
|
||||
}
|
||||
|
||||
SHELL_VAR **
|
||||
all_visible_functions ()
|
||||
{
|
||||
return (_visible_names (shell_functions));
|
||||
}
|
||||
|
||||
#endif /* READLINE */
|
||||
SHELL_VAR **
|
||||
all_visible_variables ()
|
||||
{
|
||||
return (_visible_names (shell_variables));
|
||||
}
|
||||
|
||||
/* Return non-zero if the variable VAR is visible and exported. Array
|
||||
variables cannot be exported. */
|
||||
|
|
@ -2148,6 +2344,114 @@ visible_and_exported (var)
|
|||
return (invisible_p (var) == 0 && exported_p (var));
|
||||
}
|
||||
|
||||
SHELL_VAR **
|
||||
all_exported_variables ()
|
||||
{
|
||||
SHELL_VAR **list;
|
||||
|
||||
list = map_over (visible_and_exported, shell_variables);
|
||||
if (list)
|
||||
sort_variables (list);
|
||||
return (list);
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
/* Return non-zero if the variable VAR is visible and an array. */
|
||||
static int
|
||||
visible_array_vars (var)
|
||||
SHELL_VAR *var;
|
||||
{
|
||||
return (invisible_p (var) == 0 && array_p (var));
|
||||
}
|
||||
|
||||
SHELL_VAR **
|
||||
all_array_variables ()
|
||||
{
|
||||
SHELL_VAR **list;
|
||||
|
||||
list = map_over (visible_array_vars, shell_variables);
|
||||
if (list)
|
||||
sort_variables (list);
|
||||
return (list);
|
||||
}
|
||||
#endif /* ARRAY_VARS */
|
||||
|
||||
char **
|
||||
all_variables_matching_prefix (prefix)
|
||||
char *prefix;
|
||||
{
|
||||
SHELL_VAR **varlist;
|
||||
char **rlist;
|
||||
int vind, rind, plen;
|
||||
|
||||
plen = STRLEN (prefix);
|
||||
varlist = all_visible_variables ();
|
||||
for (vind = 0; varlist && varlist[vind]; vind++)
|
||||
;
|
||||
if (varlist == 0 || vind == 0)
|
||||
return ((char **)NULL);
|
||||
rlist = alloc_array (vind + 1);
|
||||
for (vind = rind = 0; varlist[vind]; vind++)
|
||||
{
|
||||
if (plen == 0 || STREQN (prefix, varlist[vind]->name, plen))
|
||||
rlist[rind++] = savestring (varlist[vind]->name);
|
||||
}
|
||||
rlist[rind] = (char *)0;
|
||||
free (varlist);
|
||||
|
||||
return rlist;
|
||||
}
|
||||
|
||||
static inline char *
|
||||
mk_env_string (name, value)
|
||||
char *name, *value;
|
||||
{
|
||||
int name_len, value_len;
|
||||
char *p;
|
||||
|
||||
name_len = strlen (name);
|
||||
value_len = STRLEN (value);
|
||||
p = xmalloc (2 + name_len + value_len);
|
||||
strcpy (p, name);
|
||||
p[name_len] = '=';
|
||||
if (value && *value)
|
||||
strcpy (p + name_len + 1, value);
|
||||
else
|
||||
p[name_len + 1] = '\0';
|
||||
return (p);
|
||||
}
|
||||
|
||||
/* Debugging */
|
||||
static int
|
||||
valid_exportstr (v)
|
||||
SHELL_VAR *v;
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = v->exportstr;
|
||||
if (legal_variable_starter (*s) == 0)
|
||||
{
|
||||
internal_error ("invalid character %d in exportstr for %s", *s, v->name);
|
||||
return (0);
|
||||
}
|
||||
for (s = v->exportstr + 1; s && *s; s++)
|
||||
{
|
||||
if (*s == '=')
|
||||
break;
|
||||
if (legal_variable_char (*s) == 0)
|
||||
{
|
||||
internal_error ("invalid character %d in exportstr for %s", *s, v->name);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
if (*s != '=')
|
||||
{
|
||||
internal_error ("no `=' in exportstr for %s", v->name);
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Make an array of assignment statements from the hash table
|
||||
HASHED_VARS which contains SHELL_VARs. Only visible, exported
|
||||
variables are eligible. */
|
||||
|
|
@ -2165,11 +2469,32 @@ make_var_array (hashed_vars)
|
|||
if (vars == 0)
|
||||
return (char **)NULL;
|
||||
|
||||
list = (char **)xmalloc ((1 + array_len ((char **)vars)) * sizeof (char *));
|
||||
list = alloc_array ((1 + array_len ((char **)vars)));
|
||||
|
||||
#define USE_EXPORTSTR (value == var->exportstr)
|
||||
|
||||
for (i = 0, list_index = 0; var = vars[i]; i++)
|
||||
{
|
||||
if (function_p (var))
|
||||
if (var->exportstr)
|
||||
{
|
||||
#if defined(__CYGWIN__) || defined (__CYGWIN32__)
|
||||
INVALIDATE_EXPORTSTR (var);
|
||||
value = value_cell (var);
|
||||
#else
|
||||
/* XXX -- this test can go away in the next release, to be replaced
|
||||
by a simple `value = var->exportstr;', when the exportstr code
|
||||
is better-tested. Until then, don't do it for cygwin at all,
|
||||
since that system has some weird environment variables. */
|
||||
if (valid_exportstr (var))
|
||||
value = var->exportstr;
|
||||
else
|
||||
{
|
||||
INVALIDATE_EXPORTSTR (var);
|
||||
value = value_cell (var);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (function_p (var))
|
||||
value = named_function_string ((char *)NULL, function_cell (var), 0);
|
||||
#if defined (ARRAY_VARS)
|
||||
else if (array_p (var))
|
||||
|
|
@ -2184,19 +2509,23 @@ make_var_array (hashed_vars)
|
|||
|
||||
if (value)
|
||||
{
|
||||
int name_len, value_len;
|
||||
char *p;
|
||||
/* Gee, I'd like to get away with not using savestring() if we're
|
||||
using the cached exportstr... */
|
||||
list[list_index] = USE_EXPORTSTR ? savestring (value)
|
||||
: mk_env_string (var->name, value);
|
||||
|
||||
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);
|
||||
if (USE_EXPORTSTR == 0 && function_p (var))
|
||||
{
|
||||
SAVE_EXPORTSTR (var, list[list_index]);
|
||||
}
|
||||
list_index++;
|
||||
#undef USE_EXPORTSTR
|
||||
|
||||
#if 0 /* not yet */
|
||||
#if defined (ARRAY_VARS)
|
||||
if (array_p (var))
|
||||
free (value);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -2245,18 +2574,8 @@ assign_in_env (string)
|
|||
free (temp);
|
||||
}
|
||||
|
||||
nlen = strlen (name);
|
||||
vlen = value ? strlen (value) : 0;
|
||||
temp = xmalloc (2 + nlen + vlen);
|
||||
strcpy (temp, name);
|
||||
temp[nlen] = '=';
|
||||
temp[nlen + 1] = '\0';
|
||||
if (value)
|
||||
{
|
||||
if (*value)
|
||||
strcpy (temp + nlen + 1, value);
|
||||
free (value);
|
||||
}
|
||||
temp = mk_env_string (name, value);
|
||||
FREE (value);
|
||||
free (name);
|
||||
|
||||
if (temporary_env == 0)
|
||||
|
|
@ -2317,6 +2636,7 @@ find_name_in_env_array (name, array)
|
|||
temp->prev_context = (SHELL_VAR *)NULL;
|
||||
|
||||
temp->dynamic_value = temp->assign_func = (DYNAMIC_FUNC *)NULL;
|
||||
CLEAR_EXPORTSTR (temp);
|
||||
|
||||
return (temp);
|
||||
}
|
||||
|
|
@ -2427,6 +2747,12 @@ merge_builtin_env ()
|
|||
merge_env_array (builtin_env);
|
||||
}
|
||||
|
||||
int
|
||||
any_temporary_variables ()
|
||||
{
|
||||
return (temporary_env || function_env);
|
||||
}
|
||||
|
||||
/* Add ENVSTR to the end of the exported environment, EXPORT_ENV. */
|
||||
#define add_to_export_env(envstr,do_alloc) \
|
||||
do \
|
||||
|
|
@ -2495,7 +2821,7 @@ maybe_make_export_env ()
|
|||
variables are not (yet) exported, this will always be big enough
|
||||
for the exported variables and functions, without any temporary
|
||||
or function environments. */
|
||||
new_size = shell_variables->nentries + shell_functions->nentries + 1;
|
||||
new_size = HASH_ENTRIES (shell_variables) + HASH_ENTRIES (shell_functions) + 1;
|
||||
if (new_size > export_env_size)
|
||||
{
|
||||
export_env_size = new_size;
|
||||
|
|
@ -2688,6 +3014,7 @@ struct name_and_function {
|
|||
{ "LC_COLLATE", sv_locale },
|
||||
{ "LC_CTYPE", sv_locale },
|
||||
{ "LC_MESSAGES", sv_locale },
|
||||
{ "LC_NUMERIC", sv_locale },
|
||||
{ "LANG", sv_locale },
|
||||
|
||||
#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE)
|
||||
|
|
@ -2768,7 +3095,13 @@ void
|
|||
sv_hostfile (name)
|
||||
char *name;
|
||||
{
|
||||
hostname_list_initialized = 0;
|
||||
SHELL_VAR *v;
|
||||
|
||||
v = find_variable (name);
|
||||
if (v == 0)
|
||||
clear_hostname_list ();
|
||||
else
|
||||
hostname_list_initialized = 0;
|
||||
}
|
||||
#endif /* READLINE */
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue