diff options
| author | Jari Aalto <jari.aalto@cante.net> | 2004-07-27 13:29:18 +0000 |
|---|---|---|
| committer | Jari Aalto <jari.aalto@cante.net> | 2009-09-12 16:46:56 +0000 |
| commit | b80f6443b6b7b620c7272664c66ecb0b120a0998 (patch) | |
| tree | 9f71c98d8fe8fa0f41d95e1eb4227f32a09d43ca /variables.c | |
| parent | 7117c2d221b2aed4ede8600f6a36b7c1454b4f55 (diff) | |
Imported from ../bash-3.0.tar.gz.
Diffstat (limited to 'variables.c')
| -rw-r--r-- | variables.c | 406 |
1 files changed, 344 insertions, 62 deletions
diff --git a/variables.c b/variables.c index 1f9180e..dc876de 100644 --- a/variables.c +++ b/variables.c @@ -1,6 +1,6 @@ /* variables.c -- Functions for hacking shell variables. */ -/* Copyright (C) 1987-2002 Free Software Foundation, Inc. +/* Copyright (C) 1987-2004 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -36,6 +36,7 @@ #include "chartypes.h" #include <pwd.h> #include "bashansi.h" +#include "bashintl.h" #include "shell.h" #include "flags.h" @@ -72,17 +73,24 @@ /* Variables used here and defined in other files. */ extern int posixly_correct; extern int line_number; -extern int subshell_environment, indirection_level; +extern int subshell_environment, indirection_level, subshell_level; extern int build_version, patch_level; +extern int expanding_redir; extern char *dist_version, *release_status; extern char *shell_name; extern char *primary_prompt, *secondary_prompt; extern char *current_host_name; extern sh_builtin_func_t *this_shell_builtin; extern SHELL_VAR *this_shell_function; +extern char *the_printed_command_except_trap; extern char *this_command_name; +extern char *command_execution_string; extern time_t shell_start_time; +#if defined (READLINE) +extern int perform_hostname_completion; +#endif + /* The list of shell variables that the user has created at the global scope, or that came from the environment. */ VAR_CONTEXT *global_variables = (VAR_CONTEXT *)NULL; @@ -94,6 +102,12 @@ VAR_CONTEXT *shell_variables = (VAR_CONTEXT *)NULL; the environment. */ HASH_TABLE *shell_functions = (HASH_TABLE *)NULL; +#if defined (DEBUGGER) +/* The table of shell function definitions that the user defined or that + came from the environment. */ +HASH_TABLE *shell_function_defs = (HASH_TABLE *)NULL; +#endif + /* The current variable context. This is really a count of how deep into executing functions we are. */ int variable_context = 0; @@ -102,6 +116,10 @@ int variable_context = 0; for a single command. */ HASH_TABLE *temporary_env = (HASH_TABLE *)NULL; +/* Set to non-zero if an assignment error occurs while putting variables + into the temporary environment. */ +int tempenv_assign_error; + /* Some funky variables which are known about specially. Here is where "$*", "$1", and all the cruft is kept. */ char *dollar_vars[10]; @@ -139,6 +157,11 @@ static SHELL_VAR *null_assign __P((SHELL_VAR *, char *, arrayind_t)); #if defined (ARRAY_VARS) static SHELL_VAR *null_array_assign __P((SHELL_VAR *, char *, arrayind_t)); #endif +static SHELL_VAR *get_self __P((SHELL_VAR *)); + +#if defined (ARRAY_VARS) +static SHELL_VAR *init_dynamic_array_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int)); +#endif static SHELL_VAR *assign_seconds __P((SHELL_VAR *, char *, arrayind_t)); static SHELL_VAR *get_seconds __P((SHELL_VAR *)); @@ -152,6 +175,9 @@ static SHELL_VAR *get_random __P((SHELL_VAR *)); static SHELL_VAR *assign_lineno __P((SHELL_VAR *, char *, arrayind_t)); static SHELL_VAR *get_lineno __P((SHELL_VAR *)); +static SHELL_VAR *assign_subshell __P((SHELL_VAR *, char *, arrayind_t)); +static SHELL_VAR *get_subshell __P((SHELL_VAR *)); + #if defined (HISTORY) static SHELL_VAR *get_histcmd __P((SHELL_VAR *)); #endif @@ -159,12 +185,10 @@ static SHELL_VAR *get_histcmd __P((SHELL_VAR *)); #if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) static SHELL_VAR *assign_dirstack __P((SHELL_VAR *, char *, arrayind_t)); static SHELL_VAR *get_dirstack __P((SHELL_VAR *)); -static SHELL_VAR *init_dirstack_var __P((void)); #endif #if defined (ARRAY_VARS) static SHELL_VAR *get_groupset __P((SHELL_VAR *)); -static SHELL_VAR *init_groups_var __P((void)); #endif static SHELL_VAR *get_funcname __P((SHELL_VAR *)); @@ -239,6 +263,11 @@ initialize_shell_variables (env, privmode) if (shell_functions == 0) shell_functions = hash_create (0); +#if defined (DEBUGGER) + if (shell_function_defs == 0) + shell_function_defs = hash_create (0); +#endif + for (string_index = 0; string = env[string_index++]; ) { char_index = 0; @@ -282,7 +311,7 @@ initialize_shell_variables (env, privmode) array_needs_making = 1; } else - report_error ("error importing function definition for `%s'", name); + report_error (_("error importing function definition for `%s'"), name); /* ( */ if (name[char_index - 1] == ')' && name[char_index - 2] == '\0') @@ -408,6 +437,9 @@ initialize_shell_variables (env, privmode) make_vers_array (); #endif + if (command_execution_string) + bind_variable ("BASH_EXECUTION_STRING", command_execution_string); + /* Find out if we're supposed to be in Posix.2 mode via an environment variable. */ temp_var = find_variable ("POSIXLY_CORRECT"); @@ -639,7 +671,7 @@ adjust_shell_level (change) shell_level = 0; else if (shell_level > 1000) { - internal_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; } @@ -986,6 +1018,38 @@ null_array_assign (self, value, ind) } #endif +/* Degenerate `dynamic_value' function; just returns what's passed without + manipulation. */ +static SHELL_VAR * +get_self (self) + SHELL_VAR *self; +{ + return (self); +} + +#if defined (ARRAY_VARS) +/* A generic dynamic array variable initializer. Intialize array variable + NAME with dynamic value function GETFUNC and assignment function SETFUNC. */ +static SHELL_VAR * +init_dynamic_array_var (name, getfunc, setfunc, attrs) + char *name; + sh_var_value_func_t *getfunc; + sh_var_assign_func_t *setfunc; + int attrs; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v) + return (v); + INIT_DYNAMIC_ARRAY_VAR (name, getfunc, setfunc); + if (attrs) + VSETATTR (v, attrs); + return v; +} +#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. */ @@ -1132,6 +1196,44 @@ get_lineno (var) return (var); } +static SHELL_VAR * +assign_subshell (var, value, unused) + SHELL_VAR *var; + char *value; + arrayind_t unused; +{ + intmax_t new_value; + + if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0) + new_value = 0; + subshell_level = new_value; + return var; +} + +static SHELL_VAR * +get_subshell (var) + SHELL_VAR *var; +{ + char *p; + + p = itos (subshell_level); + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +get_bash_command (var) + SHELL_VAR *var; +{ + char *p; + + p = savestring (the_printed_command_except_trap); + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + #if defined (HISTORY) static SHELL_VAR * get_histcmd (var) @@ -1146,8 +1248,49 @@ get_histcmd (var) } #endif +#if defined (READLINE) +/* When this function returns, VAR->value points to malloced memory. */ +static SHELL_VAR * +get_comp_wordbreaks (var) + SHELL_VAR *var; +{ + char *p; + + /* If we don't have anything yet, assign a default value. */ + if (rl_completer_word_break_characters == 0 && bash_readline_initialized == 0) + enable_hostname_completion (perform_hostname_completion); + +#if 0 + FREE (value_cell (var)); + p = savestring (rl_completer_word_break_characters); + + var_setvalue (var, p); +#else + var_setvalue (var, rl_completer_word_break_characters); +#endif + + return (var); +} + +/* When this function returns, rl_completer_word_break_characters points to + malloced memory. */ +static SHELL_VAR * +assign_comp_wordbreaks (self, value, unused) + SHELL_VAR *self; + char *value; + arrayind_t unused; +{ + if (rl_completer_word_break_characters && + rl_completer_word_break_characters != rl_basic_word_break_characters) + free (rl_completer_word_break_characters); + + rl_completer_word_break_characters = savestring (value); + return self; +} +#endif /* READLINE */ + #if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) -static SHELL_VAR * +static SHELL_VAR * assign_dirstack (self, value, ind) SHELL_VAR *self; char *value; @@ -1171,18 +1314,6 @@ get_dirstack (self) var_setarray (self, a); return self; } - -static SHELL_VAR * -init_dirstack_var () -{ - SHELL_VAR *v; - - v = find_variable ("DIRSTACK"); - if (v) - return v; - INIT_DYNAMIC_ARRAY_VAR ("DIRSTACK", get_dirstack, assign_dirstack); - return v; -} #endif /* PUSHD AND POPD && ARRAY_VARS */ #if defined (ARRAY_VARS) @@ -1206,25 +1337,15 @@ get_groupset (self) } return (self); } - -static SHELL_VAR * -init_groups_var () -{ - SHELL_VAR *v; - - v = find_variable ("GROUPS"); - if (v) - return (v); - INIT_DYNAMIC_ARRAY_VAR ("GROUPS", get_groupset, null_array_assign); - VSETATTR (v, att_noassign); - return v; -} #endif /* ARRAY_VARS */ +/* If ARRAY_VARS is not defined, this just returns the name of any + currently-executing function. If we have arrays, it's a call stack. */ static SHELL_VAR * get_funcname (self) SHELL_VAR *self; { +#if ! defined (ARRAY_VARS) char *t; if (variable_context && this_shell_function) { @@ -1232,6 +1353,7 @@ get_funcname (self) t = savestring (this_shell_function->name); var_setvalue (self, t); } +#endif return (self); } @@ -1259,7 +1381,11 @@ init_funcname_var () v = find_variable ("FUNCNAME"); if (v) return v; +#if defined (ARRAY_VARS) + INIT_DYNAMIC_ARRAY_VAR ("FUNCNAME", get_funcname, null_array_assign); +#else INIT_DYNAMIC_VAR ("FUNCNAME", (char *)NULL, get_funcname, null_assign); +#endif VSETATTR (v, att_invisible|att_noassign); return v; } @@ -1271,6 +1397,9 @@ initialize_dynamic_variables () v = init_seconds_var (); + INIT_DYNAMIC_VAR ("BASH_COMMAND", (char *)NULL, get_bash_command, (sh_var_assign_func_t *)NULL); + INIT_DYNAMIC_VAR ("BASH_SUBSHELL", (char *)NULL, get_subshell, assign_subshell); + INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random); INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno); @@ -1278,12 +1407,23 @@ initialize_dynamic_variables () INIT_DYNAMIC_VAR ("HISTCMD", (char *)NULL, get_histcmd, (sh_var_assign_func_t *)NULL); #endif +#if defined (READLINE) + INIT_DYNAMIC_VAR ("COMP_WORDBREAKS", (char *)NULL, get_comp_wordbreaks, assign_comp_wordbreaks); +#endif + #if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) - v = init_dirstack_var (); + v = init_dynamic_array_var ("DIRSTACK", get_dirstack, assign_dirstack, 0); #endif /* PUSHD_AND_POPD && ARRAY_VARS */ #if defined (ARRAY_VARS) - v = init_groups_var (); + v = init_dynamic_array_var ("GROUPS", get_groupset, null_array_assign, att_noassign); + +# if defined (DEBUGGER) + v = init_dynamic_array_var ("BASH_ARGC", get_self, null_array_assign, (att_invisible|att_noassign)); + v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, (att_invisible|att_noassign)); +# endif /* DEBUGGER */ + v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, (att_invisible|att_noassign)); + v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, (att_invisible|att_noassign)); #endif v = init_funcname_var (); @@ -1334,11 +1474,12 @@ var_lookup (name, vcontext) */ SHELL_VAR * -find_variable_internal (name, search_tempenv) +find_variable_internal (name, force_tempenv) const char *name; - int search_tempenv; + int force_tempenv; { SHELL_VAR *var; + int search_tempenv; var = (SHELL_VAR *)NULL; @@ -1347,7 +1488,9 @@ find_variable_internal (name, search_tempenv) to get the `exported' value of $foo. This happens if we are executing a function or builtin, or if we are looking up a variable in a "subshell environment". */ - if ((search_tempenv || subshell_environment) && temporary_env) + search_tempenv = force_tempenv || (expanding_redir == 0 && subshell_environment); + + if (search_tempenv && temporary_env) var = hash_lookup (name, temporary_env); if (var == 0) @@ -1364,7 +1507,7 @@ SHELL_VAR * find_variable (name) const char *name; { - return (find_variable_internal (name, this_shell_builtin != 0)); + return (find_variable_internal (name, (expanding_redir == 0 && this_shell_builtin != 0))); } /* Look up the function entry whose name matches STRING. @@ -1376,6 +1519,15 @@ find_function (name) return (hash_lookup (name, shell_functions)); } +/* Find the function definition for the shell function named NAME. Returns + the entry or NULL. */ +FUNCTION_DEF * +find_function_def (name) + const char *name; +{ + return ((FUNCTION_DEF *)hash_lookup (name, shell_function_defs)); +} + /* Return the value of VAR. VAR is assumed to have been the result of a lookup without any subscript, if arrays are compiled into the shell. */ char * @@ -1459,7 +1611,7 @@ make_local_variable (name) if (vc == 0) { - internal_error ("make_local_variable: no function context at current scope found"); + internal_error (_("make_local_variable: no function context at current scope")); return ((SHELL_VAR *)NULL); } else if (vc->table == 0) @@ -1515,8 +1667,9 @@ make_local_array_variable (name) ARRAY *array; var = make_local_variable (name); - if (var == 0) + if (var == 0 || array_p (var)) return var; + array = array_create (); FREE (value_cell(var)); @@ -1788,7 +1941,11 @@ bind_int_variable (lhs, rhs) isint = isarr = 0; #if defined (ARRAY_VARS) +# if 0 if (t = xstrchr (lhs, '[')) /*]*/ +# else + if (valid_array_reference (lhs)) +# endif { isarr = 1; v = array_variable_part (lhs, (char **)0, (int *)0); @@ -1873,6 +2030,35 @@ bind_function (name, value) return (entry); } +/* Bind a function definition, which includes source file and line number + information in addition to the command, into the FUNCTION_DEF hash table.*/ +void +bind_function_def (name, value) + const char *name; + FUNCTION_DEF *value; +{ + FUNCTION_DEF *entry; + BUCKET_CONTENTS *elt; + COMMAND *cmd; + + entry = find_function_def (name); + if (entry) + { + dispose_function_def_contents (entry); + entry = copy_function_def_contents (value, entry); + } + else + { + cmd = value->command; + value->command = 0; + entry = copy_function_def (value); + value->command = cmd; + + elt = hash_insert (savestring (name), shell_function_defs, HASH_NOSRCH); + elt->data = (PTR_T *)entry; + } +} + /* Add STRING, which is of the form foo=bar, to the temporary environment HASH_TABLE (temporary_env). The functions in execute_cmd.c are responsible for moving the main temporary env to one of the other @@ -1885,7 +2071,7 @@ assign_in_env (string) char *name, *temp, *value; SHELL_VAR *var; - offset = assignment (string); + offset = assignment (string, 0); name = savestring (string); value = (char *)NULL; @@ -1937,13 +2123,11 @@ assign_in_env (string) setifs (var); if (echo_command_at_execute) - { - /* The Korn shell prints the `+ ' in front of assignment statements, - so we do too. */ - fprintf (stderr, "%s%s=%s\n", indirection_level_string (), name, value); - fflush (stderr); - } + /* The Korn shell prints the `+ ' in front of assignment statements, + so we do too. */ + xtrace_print_assignment (name, value, 0, 1); + free (name); return 1; } @@ -2062,6 +2246,28 @@ unbind_func (name) return 0; } +int +unbind_function_def (name) + const char *name; +{ + BUCKET_CONTENTS *elt; + FUNCTION_DEF *funcdef; + + elt = hash_remove (name, shell_function_defs, 0); + + if (elt == 0) + return -1; + + funcdef = (FUNCTION_DEF *)elt->data; + if (funcdef) + dispose_function_def (funcdef); + + free (elt->key); + free (elt); + + return 0; +} + /* Make the variable associated with NAME go away. HASH_LIST is the hash table from which this variable should be deleted (either shell_variables or shell_functions). @@ -2096,6 +2302,11 @@ makunbound (name, vc) We also need to add it back into the correct hash table. */ if (old_var && local_p (old_var) && variable_context == old_var->context) { + /* Reset the attributes. Preserve the export attribute if the variable + came from a temporary environment. Make sure it stays local, and + make it invisible. */ + old_var->attributes = (exported_p (old_var) && tempvar_p (old_var)) ? att_exported : 0; + VSETATTR (old_var, att_local); VSETATTR (old_var, att_invisible); FREE (value_cell (old_var)); var_setvalue (old_var, (char *)NULL); @@ -2502,7 +2713,7 @@ all_local_variables () if (vc == 0) { - internal_error ("all_local_variables: no function context at current scope found"); + internal_error (_("all_local_variables: no function context at current scope")); return (SHELL_VAR **)NULL; } if (vc->table == 0 || HASH_ENTRIES (vc->table) == 0 || vc_haslocals (vc) == 0) @@ -2716,7 +2927,7 @@ valid_exportstr (v) s = v->exportstr; if (legal_variable_starter ((unsigned char)*s) == 0) { - internal_error ("invalid character %d in exportstr for %s", *s, v->name); + internal_error (_("invalid character %d in exportstr for %s"), *s, v->name); return (0); } for (s = v->exportstr + 1; s && *s; s++) @@ -2725,13 +2936,13 @@ valid_exportstr (v) break; if (legal_variable_char ((unsigned char)*s) == 0) { - internal_error ("invalid character %d in exportstr for %s", *s, v->name); + 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); + internal_error (_("no `=' in exportstr for %s"), v->name); return (0); } return (1); @@ -2857,7 +3068,7 @@ add_or_supercede_exported_var (assign, do_alloc) register int i; int equal_offset; - equal_offset = assignment (assign); + equal_offset = assignment (assign, 0); if (equal_offset == 0) return (export_env); @@ -3156,7 +3367,7 @@ pop_var_context () vcxt = shell_variables; if (vc_isfuncenv (vcxt) == 0) { - internal_error ("pop_var_context: head of shell_variables not a function context"); + internal_error (_("pop_var_context: head of shell_variables not a function context")); return; } @@ -3169,7 +3380,7 @@ pop_var_context () dispose_var_context (vcxt); } else - internal_error ("pop_var_context: no global_variables context"); + internal_error (_("pop_var_context: no global_variables context")); } /* Delete the HASH_TABLEs for all variable contexts beginning at VCXT, and @@ -3235,7 +3446,7 @@ pop_scope (is_special) vcxt = shell_variables; if (vc_istempscope (vcxt) == 0) { - internal_error ("pop_scope: head of shell_variables not a temporary environment scope"); + internal_error (_("pop_scope: head of shell_variables not a temporary environment scope")); return; } @@ -3334,6 +3545,56 @@ dispose_saved_dollar_vars () dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL; } +/* Manipulate the special BASH_ARGV and BASH_ARGC variables. */ + +void +push_args (list) + WORD_LIST *list; +{ +#if defined (ARRAY_VARS) && defined (DEBUGGER) + SHELL_VAR *bash_argv_v, *bash_argc_v; + ARRAY *bash_argv_a, *bash_argc_a; + WORD_LIST *l; + arrayind_t i; + char *t; + + GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a); + GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a); + + for (l = list, i = 0; l; l = l->next, i++) + array_push (bash_argv_a, l->word->word); + + t = itos (i); + array_push (bash_argc_a, t); + free (t); +#endif /* ARRAY_VARS && DEBUGGER */ +} + +/* Remove arguments from BASH_ARGV array. Pop top element off BASH_ARGC + array and use that value as the count of elements to remove from + BASH_ARGV. */ +void +pop_args () +{ +#if defined (ARRAY_VARS) && defined (DEBUGGER) + SHELL_VAR *bash_argv_v, *bash_argc_v; + ARRAY *bash_argv_a, *bash_argc_a; + ARRAY_ELEMENT *ce; + intmax_t i; + + GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a); + GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a); + + ce = array_shift (bash_argc_a, 1, 0); + if (ce == 0 || legal_number (element_value (ce), &i) == 0) + i = 0; + + for ( ; i > 0; i--) + array_pop (bash_argv_a); + array_dispose_element (ce); +#endif /* ARRAY_VARS && DEBUGGER */ +} + /************************************************* * * * Functions to manage special variables * @@ -3369,6 +3630,7 @@ static struct name_and_function special_vars[] = { { "HISTFILESIZE", sv_histsize }, { "HISTIGNORE", sv_histignore }, { "HISTSIZE", sv_histsize }, + { "HISTTIMEFORMAT", sv_histtimefmt }, #endif #if defined (READLINE) @@ -3598,18 +3860,28 @@ sv_history_control (name) char *name; { char *temp; + char *val; + int tptr; history_control = 0; temp = get_string_value (name); - if (temp && *temp && STREQN (temp, "ignore", 6)) + if (temp == 0 || *temp == 0) + return; + + tptr = 0; + while (val = extract_colon_unit (temp, &tptr)) { - 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 (STREQ (val, "ignorespace")) + history_control |= HC_IGNSPACE; + else if (STREQ (val, "ignoredups")) + history_control |= HC_IGNDUPS; + else if (STREQ (val, "ignoreboth")) + history_control |= HC_IGNBOTH; + else if (STREQ (val, "erasedups")) + history_control |= HC_ERASEDUPS; + + free (val); } } @@ -3640,6 +3912,16 @@ sv_histchars (name) } } #endif /* BANG_HISTORY */ + +void +sv_histtimefmt (name) + char *name; +{ + SHELL_VAR *v; + + v = find_variable (name); + history_write_timestamps = (v != 0); +} #endif /* HISTORY */ #if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE) |
