X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=variables.c;h=b72fc4f8428b409b74728abca74858cdc40abed8;hb=cce855bc5b117cb7ae70064131120687bc69fac0;hp=212724e911a1f68e5235d345fc109c541c127c04;hpb=e8ce775db824de329b81293b4e5d8fbd65624528;p=platform%2Fupstream%2Fbash.git 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 + +#if defined (READLINE) +# include "bashline.h" +# include +#else +# include +#endif #if defined (HISTORY) # include "bashhist.h" +# include #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 +}