summaryrefslogtreecommitdiff
path: root/variables.c
diff options
context:
space:
mode:
authorJari Aalto <jari.aalto@cante.net>2000-03-17 21:46:59 +0000
committerJari Aalto <jari.aalto@cante.net>2009-09-12 16:46:53 +0000
commitbb70624e964126b7ac4ff085ba163a9c35ffa18f (patch)
treeba2dd4add13ada94b1899c6d4aca80195b80b74b /variables.c
parentb72432fdcc59300c6fe7c9d6c8a31ad3447933f5 (diff)
downloadbash-bb70624e964126b7ac4ff085ba163a9c35ffa18f.tar.gz
Imported from ../bash-2.04.tar.gz.
Diffstat (limited to 'variables.c')
-rw-r--r--variables.c543
1 files changed, 438 insertions, 105 deletions
diff --git a/variables.c b/variables.c
index 8f4bb420..615aacd1 100644
--- a/variables.c
+++ b/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 void
-initialize_dynamic_variables ()
+
+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 = bind_variable ("SECONDS", (char *)NULL);
- v->dynamic_value = get_seconds;
- v->assign_func = assign_seconds;
+ 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)
- v = bind_variable ("RANDOM", (char *)NULL);
- v->dynamic_value = get_random;
- v->assign_func = assign_random;
+static void
+initialize_dynamic_variables ()
+{
+ SHELL_VAR *v;
- 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;
@@ -2126,19 +2324,17 @@ _visible_names (table)
}
SHELL_VAR **
-all_visible_variables ()
+all_visible_functions ()
{
- return (_visible_names (shell_variables));
+ return (_visible_names (shell_functions));
}
SHELL_VAR **
-all_visible_functions ()
+all_visible_variables ()
{
- return (_visible_names (shell_functions));
+ return (_visible_names (shell_variables));
}
-#endif /* READLINE */
-
/* Return non-zero if the variable VAR is visible and exported. Array
variables cannot be exported. */
static int
@@ -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,20 +2509,24 @@ make_var_array (hashed_vars)
if (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);
+ /* 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);
+
+ 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 */