aboutsummaryrefslogtreecommitdiffstats
path: root/variables.c
diff options
context:
space:
mode:
authorJari Aalto <jari.aalto@cante.net>1998-04-17 19:52:44 +0000
committerJari Aalto <jari.aalto@cante.net>2009-09-12 16:46:51 +0000
commitcce855bc5b117cb7ae70064131120687bc69fac0 (patch)
tree39c7a4ec8f6d22ef03df74f2684e6a04fef10399 /variables.c
parente8ce775db824de329b81293b4e5d8fbd65624528 (diff)
downloadandroid_external_bash-cce855bc5b117cb7ae70064131120687bc69fac0.tar.gz
android_external_bash-cce855bc5b117cb7ae70064131120687bc69fac0.tar.bz2
android_external_bash-cce855bc5b117cb7ae70064131120687bc69fac0.zip
Imported from ../bash-2.02.tar.gz.
Diffstat (limited to 'variables.c')
-rw-r--r--variables.c492
1 files changed, 449 insertions, 43 deletions
diff --git a/variables.c b/variables.c
index 212724e..b72fc4f 100644
--- a/variables.c
+++ b/variables.c
@@ -39,15 +39,23 @@
#include "shell.h"
#include "flags.h"
#include "execute_cmd.h"
+#include "findcmd.h"
#include "mailcheck.h"
#include "input.h"
#include "builtins/getopt.h"
#include "builtins/common.h"
-#include <tilde/tilde.h>
+
+#if defined (READLINE)
+# include "bashline.h"
+# include <readline/readline.h>
+#else
+# include <tilde/tilde.h>
+#endif
#if defined (HISTORY)
# include "bashhist.h"
+# include <readline/history.h>
#endif /* HISTORY */
/* Variables used here and defined in other files. */
@@ -129,20 +137,22 @@ static int qsort_var_comp ();
#define set_auto_export(var) \
do { var->attributes |= att_exported; array_needs_making = 1; } while (0)
-/* Initialize the shell variables from the current environment. */
+/* Initialize the shell variables from the current environment.
+ If PRIVMODE is nonzero, don't import functions from ENV or
+ parse $SHELLOPTS. */
void
-initialize_shell_variables (env, no_functions)
+initialize_shell_variables (env, privmode)
char **env;
- int no_functions; /* If set, don't import functions from ENV. */
+ int privmode;
{
char *name, *string, *temp_string;
int c, char_index, string_index, string_length;
SHELL_VAR *temp_var;
- if (!shell_variables)
+ if (shell_variables == 0)
shell_variables = make_hash_table (0);
- if (!shell_functions)
+ if (shell_functions == 0)
shell_functions = make_hash_table (0);
for (string_index = 0; string = env[string_index++]; )
@@ -165,7 +175,7 @@ initialize_shell_variables (env, no_functions)
char_index == strlen (name) */
/* If exported function, define it now. */
- if (no_functions == 0 && STREQN ("() {", string, 4))
+ if (privmode == 0 && STREQN ("() {", string, 4))
{
string_length = strlen (string);
temp_string = xmalloc (3 + string_length + char_index);
@@ -233,7 +243,8 @@ initialize_shell_variables (env, no_functions)
temp_string = get_working_directory ("shell-init");
if (temp_string)
{
- bind_variable ("PWD", temp_string);
+ temp_var = bind_variable ("PWD", temp_string);
+ set_auto_export (temp_var);
free (temp_string);
}
}
@@ -500,7 +511,7 @@ adjust_shell_level (change)
shell_level = 0;
else if (shell_level > 1000)
{
- internal_error ("warning: shell level (%d) too high, resetting to 1", shell_level);
+ internal_warning ("shell level (%d) too high, resetting to 1", shell_level);
shell_level = 1;
}
@@ -626,7 +637,7 @@ set_if_not (name, value)
SHELL_VAR *v;
v = find_variable (name);
- if (!v)
+ if (v == 0)
v = bind_variable (name, value);
return (v);
}
@@ -873,7 +884,7 @@ assign_seconds (self, value)
SHELL_VAR *self;
char *value;
{
- seconds_value_assigned = string_to_long (value);
+ seconds_value_assigned = strtol (value, (char **)NULL, 10);
shell_start_time = NOW;
return (self);
}
@@ -900,18 +911,15 @@ 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. */
+ C standard. This one isn't very good (the values are alternately
+ odd and even, for example), but a more complicated one is overkill. */
/* Returns a pseudo-random number between 0 and 32767. */
static int
brand ()
{
rseed = rseed * 1103515245 + 12345;
-#if 0
- return ((unsigned int)(rseed / 65536) % 32768);
-#else
- return ((unsigned int)(rseed % 32768));
-#endif
+ return ((unsigned int)(rseed & 32767)); /* was % 32768 */
}
/* Set the random number generator seed to SEED. */
@@ -1143,7 +1151,8 @@ find_function (name)
/* Return the string value of a variable. Return NULL if the variable
doesn't exist, or only has a function as a value. Don't cons a new
- string. */
+ string. This is a potential memory leak if the variable is found
+ in the temporary environment. */
char *
get_string_value (var_name)
char *var_name;
@@ -1451,6 +1460,8 @@ bind_array_variable (name, ind, value)
return (entry);
}
+/* Perform a compound assignment statement for array NAME, where VALUE is
+ the text between the parens: NAME=( VALUE ) */
SHELL_VAR *
assign_array_from_string (name, value)
char *name, *value;
@@ -1467,10 +1478,6 @@ assign_array_from_string (name, value)
}
else if (array_p (var) == 0)
var = convert_var_to_array (var);
-#if 0
- else
- empty_array (array_cell (var));
-#endif
return (assign_array_var_from_string (var, value));
}
@@ -1492,6 +1499,8 @@ assign_array_var_from_word_list (var, list)
return var;
}
+/* Perform a compound array assignment: VAR->name=( VALUE ). The
+ VALUE has already had the parentheses stripped. */
SHELL_VAR *
assign_array_var_from_string (var, value)
SHELL_VAR *var;
@@ -1502,28 +1511,45 @@ assign_array_var_from_string (var, value)
char *w, *val, *nval;
int ni, len, ind, last_ind;
- a = array_cell (var);
+ if (value == 0)
+ return var;
- /* Expand the value string into a list of words, performing all the
- shell expansions including word splitting. */
- if (*value == '(')
+ /* If this is called from declare_builtin, value[0] == '(' and
+ strchr(value, ')') != 0. In this case, we need to extract
+ the value from between the parens before going on. */
+ if (*value == '(') /*)*/
{
ni = 1;
val = extract_array_assignment_list (value, &ni);
if (val == 0)
- return var;
- nlist = expand_string (val, 0);
- free (val);
+ return var;
}
else
- nlist = expand_string (value, 0);
+ val = value;
+ /* Expand the value string into a list of words, performing all the
+ shell expansions including word splitting. */
#if 1
+ /* 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");
+ /* Now that we've split it, perform the shell expansions on each
+ word in the list. */
+ nlist = list ? expand_words_shellexp (list) : (WORD_LIST *)NULL;
+ dispose_words (list);
+#else
+ nlist = expand_string (val, 0);
+#endif
+
+ if (val != value)
+ free (val);
+
+ a = array_cell (var);
+
/* Now that we are ready to assign values to the array, kill the existing
value. */
if (a)
empty_array (a);
-#endif
for (last_ind = 0, list = nlist; list; list = list->next)
{
@@ -1656,8 +1682,9 @@ int
unbind_variable (name)
char *name;
{
- SHELL_VAR *var = find_variable (name);
+ SHELL_VAR *var;
+ var = find_variable (name);
if (!var)
return (-1);
@@ -1947,6 +1974,7 @@ set_var_read_only (name)
entry->attributes |= att_readonly;
}
+#ifdef INCLUDE_UNUSED
/* Make the function associated with NAME be readonly.
If NAME does not exist, we just punt, like auto_export code below. */
void
@@ -1983,6 +2011,7 @@ set_func_auto_export (name)
if (entry)
set_auto_export (entry);
}
+#endif
#if defined (ARRAY_VARS)
/* This function assumes s[i] == '['; returns with s[ret] == ']' if
@@ -2045,6 +2074,8 @@ assignment (string)
return (0);
}
+#ifdef READLINE
+
static int
visible_var (var)
SHELL_VAR *var;
@@ -2078,6 +2109,8 @@ all_visible_functions ()
return (_visible_names (shell_functions));
}
+#endif /* READLINE */
+
/* Return non-zero if the variable VAR is visible and exported. Array
variables cannot be exported. */
static int
@@ -2161,7 +2194,6 @@ assign_in_env (string)
name = savestring (string);
value = (char *)NULL;
-#define freetemp nlen
if (name[offset] == '=')
{
name[offset] = 0;
@@ -2174,9 +2206,7 @@ assign_in_env (string)
return (0);
}
temp = name + offset + 1;
- freetemp = strchr (temp, '~') != 0;
- if (freetemp)
- temp = bash_tilde_expand (temp);
+ temp = (strchr (temp, '~') != 0) ? bash_tilde_expand (temp) : savestring (temp);
list = expand_string_unsplit (temp, 0);
value = string_list (list);
@@ -2184,10 +2214,8 @@ assign_in_env (string)
if (list)
dispose_words (list);
- if (freetemp)
- free (temp);
+ free (temp);
}
-#undef freetemp
nlen = strlen (name);
vlen = value ? strlen (value) : 0;
@@ -2248,12 +2276,15 @@ find_name_in_env_array (name, array)
SHELL_VAR *temp;
char *w;
- temp = new_shell_variable (name); /* XXX memory leak here */
+ /* This is a potential memory leak. The code should really save
+ the created variables in some auxiliary data structure, which
+ can be disposed of at the appropriate time. */
+ temp = new_shell_variable (name);
w = array[i] + l + 1;
temp->value = *w ? savestring (w) : (char *)NULL;
- temp->attributes = att_exported;
+ temp->attributes = att_exported|att_tempvar;
temp->context = 0;
temp->prev_context = (SHELL_VAR *)NULL;
@@ -2275,7 +2306,9 @@ SHELL_VAR *
find_tempenv_variable (name)
char *name;
{
- SHELL_VAR *var = (SHELL_VAR *)NULL;
+ SHELL_VAR *var;
+
+ var = (SHELL_VAR *)NULL;
if (temporary_env)
var = find_name_in_env_array (name, temporary_env);
@@ -2379,7 +2412,7 @@ do \
export_env[export_env_index] = (char *)NULL; \
} while (0)
-#define ISFUNC(s, o) ((s[o + 1] == '(') && (s[o + 2] == ')'))
+#define ISFUNCTION(s, o) ((s[o + 1] == '(') && (s[o + 2] == ')'))
/* Add ASSIGN to EXPORT_ENV, or supercede a previous assignment in the
array with the same left-hand side. Return the new EXPORT_ENV. */
@@ -2492,6 +2525,7 @@ put_command_name_into_env (command_name)
export_env = add_or_supercede_exported_var (dummy, 0);
}
+#if 0 /* UNUSED -- it caused too many problems */
void
put_gnu_argv_flags_into_env (pid, flags_string)
int pid;
@@ -2516,6 +2550,7 @@ put_gnu_argv_flags_into_env (pid, flags_string)
export_env = add_or_supercede_exported_var (dummy, 0);
}
+#endif
/* Return a string denoting what our indirection level is. */
static char indirection_string[100];
@@ -2544,3 +2579,374 @@ indirection_level_string ()
free (ps4);
return (indirection_string);
}
+
+/*************************************************
+ * *
+ * Functions to manage special variables *
+ * *
+ *************************************************/
+
+/* Extern declarations for variables this code has to manage. */
+extern int eof_encountered, eof_encountered_limit, ignoreeof;
+
+#if defined (READLINE)
+extern int no_line_editing;
+extern int hostname_list_initialized;
+#endif
+
+/* An alist of name.function for each special variable. Most of the
+ functions don't do much, and in fact, this would be faster with a
+ switch statement, but by the end of this file, I am sick of switch
+ statements. */
+
+#define SET_INT_VAR(name, intvar) intvar = find_variable (name) != 0
+
+struct name_and_function {
+ char *name;
+ VFunction *function;
+} special_vars[] = {
+ { "PATH", sv_path },
+ { "MAIL", sv_mail },
+ { "MAILPATH", sv_mail },
+ { "MAILCHECK", sv_mail },
+
+ { "POSIXLY_CORRECT", sv_strict_posix },
+ { "GLOBIGNORE", sv_globignore },
+
+ /* Variables which only do something special when READLINE is defined. */
+#if defined (READLINE)
+ { "TERM", sv_terminal },
+ { "TERMCAP", sv_terminal },
+ { "TERMINFO", sv_terminal },
+ { "HOSTFILE", sv_hostfile },
+#endif /* READLINE */
+
+ /* Variables which only do something special when HISTORY is defined. */
+#if defined (HISTORY)
+ { "HISTIGNORE", sv_histignore },
+ { "HISTSIZE", sv_histsize },
+ { "HISTFILESIZE", sv_histsize },
+ { "HISTCONTROL", sv_history_control },
+# if defined (BANG_HISTORY)
+ { "histchars", sv_histchars },
+# endif /* BANG_HISTORY */
+#endif /* HISTORY */
+
+ { "IGNOREEOF", sv_ignoreeof },
+ { "ignoreeof", sv_ignoreeof },
+
+ { "OPTIND", sv_optind },
+ { "OPTERR", sv_opterr },
+
+ { "TEXTDOMAIN", sv_locale },
+ { "TEXTDOMAINDIR", sv_locale },
+ { "LC_ALL", sv_locale },
+ { "LC_COLLATE", sv_locale },
+ { "LC_CTYPE", sv_locale },
+ { "LC_MESSAGES", sv_locale },
+ { "LANG", sv_locale },
+
+#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE)
+ { "TZ", sv_tz },
+#endif
+
+ { (char *)0, (VFunction *)0 }
+};
+
+/* The variable in NAME has just had its state changed. Check to see if it
+ is one of the special ones where something special happens. */
+void
+stupidly_hack_special_variables (name)
+ char *name;
+{
+ int i;
+
+ for (i = 0; special_vars[i].name; i++)
+ {
+ if (STREQ (special_vars[i].name, name))
+ {
+ (*(special_vars[i].function)) (name);
+ return;
+ }
+ }
+}
+
+/* What to do just after the PATH variable has changed. */
+void
+sv_path (name)
+ char *name;
+{
+ /* hash -r */
+ flush_hashed_filenames ();
+}
+
+/* What to do just after one of the MAILxxxx variables has changed. NAME
+ is the name of the variable. This is called with NAME set to one of
+ MAIL, MAILCHECK, or MAILPATH. */
+void
+sv_mail (name)
+ char *name;
+{
+ /* If the time interval for checking the files has changed, then
+ reset the mail timer. Otherwise, one of the pathname vars
+ to the users mailbox has changed, so rebuild the array of
+ filenames. */
+ if (name[4] == 'C') /* if (strcmp (name, "MAILCHECK") == 0) */
+ reset_mail_timer ();
+ else
+ {
+ free_mail_files ();
+ remember_mail_dates ();
+ }
+}
+
+/* What to do when GLOBIGNORE changes. */
+void
+sv_globignore (name)
+ char *name;
+{
+ setup_glob_ignore (name);
+}
+
+#if defined (READLINE)
+/* What to do just after one of the TERMxxx variables has changed.
+ If we are an interactive shell, then try to reset the terminal
+ information in readline. */
+void
+sv_terminal (name)
+ char *name;
+{
+ if (interactive_shell && no_line_editing == 0)
+ rl_reset_terminal (get_string_value ("TERM"));
+}
+
+void
+sv_hostfile (name)
+ char *name;
+{
+ hostname_list_initialized = 0;
+}
+#endif /* READLINE */
+
+#if defined (HISTORY)
+/* What to do after the HISTSIZE or HISTFILESIZE variables change.
+ If there is a value for this HISTSIZE (and it is numeric), then stifle
+ the history. Otherwise, if there is NO value for this variable,
+ unstifle the history. If name is HISTFILESIZE, and its value is
+ numeric, truncate the history file to hold no more than that many
+ lines. */
+void
+sv_histsize (name)
+ char *name;
+{
+ char *temp;
+ long num;
+
+ temp = get_string_value (name);
+
+ if (temp && *temp)
+ {
+ if (legal_number (temp, &num))
+ {
+ if (name[4] == 'S')
+ {
+ stifle_history (num);
+ num = where_history ();
+ if (history_lines_this_session > num)
+ history_lines_this_session = num;
+ }
+ else
+ {
+ history_truncate_file (get_string_value ("HISTFILE"), (int)num);
+ if (num <= history_lines_in_file)
+ history_lines_in_file = num;
+ }
+ }
+ }
+ else if (name[4] == 'S')
+ unstifle_history ();
+}
+
+/* What to do after the HISTIGNORE variable changes. */
+void
+sv_histignore (name)
+ char *name;
+{
+ setup_history_ignore (name);
+}
+
+/* What to do after the HISTCONTROL variable changes. */
+void
+sv_history_control (name)
+ char *name;
+{
+ char *temp;
+
+ history_control = 0;
+ temp = get_string_value (name);
+
+ if (temp && *temp && STREQN (temp, "ignore", 6))
+ {
+ if (temp[6] == 's') /* ignorespace */
+ history_control = 1;
+ else if (temp[6] == 'd') /* ignoredups */
+ history_control = 2;
+ else if (temp[6] == 'b') /* ignoreboth */
+ history_control = 3;
+ }
+}
+
+#if defined (BANG_HISTORY)
+/* Setting/unsetting of the history expansion character. */
+void
+sv_histchars (name)
+ char *name;
+{
+ char *temp;
+
+ temp = get_string_value (name);
+ if (temp)
+ {
+ history_expansion_char = *temp;
+ if (temp[0] && temp[1])
+ {
+ history_subst_char = temp[1];
+ if (temp[2])
+ history_comment_char = temp[2];
+ }
+ }
+ else
+ {
+ history_expansion_char = '!';
+ history_subst_char = '^';
+ history_comment_char = '#';
+ }
+}
+#endif /* BANG_HISTORY */
+#endif /* HISTORY */
+
+#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE)
+void
+sv_tz (name)
+ char *name;
+{
+ tzset ();
+}
+#endif
+
+/* If the variable exists, then the value of it can be the number
+ of times we actually ignore the EOF. The default is small,
+ (smaller than csh, anyway). */
+void
+sv_ignoreeof (name)
+ char *name;
+{
+ SHELL_VAR *tmp_var;
+ char *temp;
+
+ eof_encountered = 0;
+
+ tmp_var = find_variable (name);
+ ignoreeof = tmp_var != 0;
+ temp = tmp_var ? value_cell (tmp_var) : (char *)NULL;
+ if (temp)
+ eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10;
+ set_shellopts (); /* make sure `ignoreeof' is/is not in $SHELLOPTS */
+}
+
+void
+sv_optind (name)
+ char *name;
+{
+ char *tt;
+ int s;
+
+ tt = get_string_value ("OPTIND");
+ if (tt && *tt)
+ {
+ s = atoi (tt);
+
+ /* According to POSIX, setting OPTIND=1 resets the internal state
+ of getopt (). */
+ if (s < 0 || s == 1)
+ s = 0;
+ }
+ else
+ s = 0;
+ getopts_reset (s);
+}
+
+void
+sv_opterr (name)
+ char *name;
+{
+ char *tt;
+
+ tt = get_string_value ("OPTERR");
+ sh_opterr = (tt && *tt) ? atoi (tt) : 1;
+}
+
+void
+sv_strict_posix (name)
+ char *name;
+{
+ SET_INT_VAR (name, posixly_correct);
+ posix_initialize (posixly_correct);
+#if defined (READLINE)
+ if (interactive_shell)
+ posix_readline_initialize (posixly_correct);
+#endif /* READLINE */
+ set_shellopts (); /* make sure `posix' is/is not in $SHELLOPTS */
+}
+
+void
+sv_locale (name)
+ char *name;
+{
+ char *v;
+
+ v = get_string_value (name);
+ if (name[0] == 'L' && name[1] == 'A') /* LANG */
+ set_lang (name, v);
+ else
+ set_locale_var (name, v); /* LC_*, TEXTDOMAIN* */
+}
+
+#if defined (ARRAY_VARS)
+void
+set_pipestatus_array (ps)
+ int *ps;
+{
+ SHELL_VAR *v;
+ ARRAY *a;
+ register int i;
+ char *t;
+
+ v = find_variable ("PIPESTATUS");
+ if (v == 0)
+ v = make_new_array_variable ("PIPESTATUS");
+ if (array_p (v) == 0)
+ return; /* Do nothing if not an array variable. */
+ a = array_cell (v);
+ if (a)
+ empty_array (a);
+ for (i = 0; ps[i] != -1; i++)
+ {
+ t = itos (ps[i]);
+ array_add_element (a, i, t);
+ free (t);
+ }
+}
+#endif
+
+void
+set_pipestatus_from_exit (s)
+ int s;
+{
+#if defined (ARRAY_VARS)
+ static int v[2] = { 0, -1 };
+
+ v[0] = s;
+ set_pipestatus_array (v);
+#endif
+}