From aee3e5611a9bff915e46251df5f13384420cc3cf Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Thu, 2 Oct 2014 10:20:14 -0400 Subject: [PATCH] commit bash-20140829 snapshot --- CWRU/CWRU.chlog | 50 + CWRU/CWRU.chlog~ | 41 + CWRU/POSIX.NOTES.old | 82 + CWRU/old/set.def.save | 544 +++ CWRU/save/unwind_prot.h.save | 50 + MANIFEST | 4 + builtins/evalstring.c | 4 + cross-build/cygwin32.cache.old | 42 + doc/FAQ.orig | 1745 +++++++++ doc/aosa-bash.pdf.old | Bin 0 -> 153472 bytes doc/bash.1 | 12 +- doc/bashref.texi | 11 +- doc/version.texi | 7 +- examples/loadables/Makefile.in.save | 238 ++ execute_cmd.c | 22 +- lib/readline/doc/Makefile.old | 76 + lib/readline/history.c | 8 +- pcomplete.c | 4 + subst.h | 1 + subst.h~ | 320 ++ tests/misc/regress/log.orig | 50 + tests/misc/regress/shx.orig | 10 + tests/parser.right | 1 + tests/parser.tests | 4 + tests/parser1.sub | 1 + tests/run-parser | 2 + variables.c | 6 + variables.c~ | 5399 +++++++++++++++++++++++++++ 28 files changed, 8720 insertions(+), 14 deletions(-) create mode 100644 CWRU/POSIX.NOTES.old create mode 100644 CWRU/old/set.def.save create mode 100644 CWRU/save/unwind_prot.h.save create mode 100644 cross-build/cygwin32.cache.old create mode 100644 doc/FAQ.orig create mode 100644 doc/aosa-bash.pdf.old create mode 100644 examples/loadables/Makefile.in.save create mode 100644 lib/readline/doc/Makefile.old create mode 100644 subst.h~ create mode 100644 tests/misc/regress/log.orig create mode 100644 tests/misc/regress/shx.orig create mode 100644 tests/parser.right create mode 100644 tests/parser.tests create mode 100644 tests/parser1.sub create mode 100644 tests/run-parser create mode 100644 variables.c~ diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 4eb750c9..cc7ced6b 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -6477,6 +6477,8 @@ execute_cmd.c recursive `eval' calls; current max is 4096 - execute_builtin: unwind-protect value of evalnest around calls to eval builtin. Suggested by Oliver Morais + - {initialize_subshell,execute_subshell_builtin_or_function}: reset + evalnest to 0 in a subshell builtins/setattr.def - show_name_attributes: show a variable's attributes even if it's @@ -6565,3 +6567,51 @@ lib/readline/display.c - rl_message: call vsnprintf with full msg_bufsiz, since it counts one fewer than the buffer length passed as an argument. Bug report and fix from Dylan Cali + + 8/26 + ---- +builtins/evalstring.c + - evalstring: if CURRENT_TOKEN == yacc_EOF, reset it to newline. This is + instead of calling reset_parser(); that might still be needed. Fixes + bug with eval and a subsequent statement ending with EOF reported by + + +pcomplete.c + - filter_stringlist: when extglob is on, a leading ! in the filter + pattern should be left alone when it introduces a !(pat) pattern; + otherwise it messes up the pattern. Fixes bug reported by David + Korn + + 8/27 + ---- +doc/{bash.1,bashref.texi} + - clarify the behavior of bash when given the -c option, since $0 is + technically not a positional parameter. Bug reported by Stephane + Chazelas + + 8/28 + ---- +lib/readline/history.c + - add_history: use history_max_entries (if history is stifled) or + DEFAULT_HISTORY_INITIAL_SIZE if not (new define, defaults to 502) + to size the initial allocation of the history array. Assumption + is that this will reduce the number of allocations + + 8/29 + ---- +execute_command.c: + - sourcenest, sourcenest_max: new variables used to track level of + sourced files and (maybe) one day catch infinite source recursion + - execute_builtin: if current source level exceeds sourcenest_max, + trigger an error and jump back to the top level + - {initialize_subshell,execute_subshell_builtin_or_function}: reset + sourcenest to 0 in a subshell + + 9/2 + --- +variables.c + - bind_variable: if a nameref expands to an array reference, make + sure that assign_array_element gets called (maybe even + recursively) instead of bind_variable_internal, so invalid variable + names (like arr[0]) don't get created. Fixes bug reported by + diff --git a/CWRU/CWRU.chlog~ b/CWRU/CWRU.chlog~ index 4eb750c9..8ae78f5f 100644 --- a/CWRU/CWRU.chlog~ +++ b/CWRU/CWRU.chlog~ @@ -6477,6 +6477,8 @@ execute_cmd.c recursive `eval' calls; current max is 4096 - execute_builtin: unwind-protect value of evalnest around calls to eval builtin. Suggested by Oliver Morais + - {initialize_subshell,execute_subshell_builtin_or_function}: reset + evalnest to 0 in a subshell builtins/setattr.def - show_name_attributes: show a variable's attributes even if it's @@ -6565,3 +6567,42 @@ lib/readline/display.c - rl_message: call vsnprintf with full msg_bufsiz, since it counts one fewer than the buffer length passed as an argument. Bug report and fix from Dylan Cali + + 8/26 + ---- +builtins/evalstring.c + - evalstring: if CURRENT_TOKEN == yacc_EOF, reset it to newline. This is + instead of calling reset_parser(); that might still be needed. Fixes + bug with eval and a subsequent statement ending with EOF reported by + + +pcomplete.c + - filter_stringlist: when extglob is on, a leading ! in the filter + pattern should be left alone when it introduces a !(pat) pattern; + otherwise it messes up the pattern. Fixes bug reported by David + Korn + + 8/27 + ---- +doc/{bash.1,bashref.texi} + - clarify the behavior of bash when given the -c option, since $0 is + technically not a positional parameter. Bug reported by Stephane + Chazelas + + 8/28 + ---- +lib/readline/history.c + - add_history: use history_max_entries (if history is stifled) or + DEFAULT_HISTORY_INITIAL_SIZE if not (new define, defaults to 502) + to size the initial allocation of the history array. Assumption + is that this will reduce the number of allocations + + 8/29 + ---- +execute_command.c: + - sourcenest, sourcenest_max: new variables used to track level of + sourced files and (maybe) one day catch infinite source recursion + - execute_builtin: if current source level exceeds sourcenest_max, + trigger an error and jump back to the top level + - {initialize_subshell,execute_subshell_builtin_or_function}: reset + sourcenest to 0 in a subshell diff --git a/CWRU/POSIX.NOTES.old b/CWRU/POSIX.NOTES.old new file mode 100644 index 00000000..1707ab10 --- /dev/null +++ b/CWRU/POSIX.NOTES.old @@ -0,0 +1,82 @@ +Starting bash with the `--posix' command-line option or executing +`set -o posix' while bash is running will cause bash to conform more +closely to the Posix.2 standard by changing the behavior to match that +specified by Posix.2 in areas where the bash default differs. + +The following list is what's changed when `posix mode' is in effect: + +1. When a command in the hash table no longer exists, bash will re-search + $PATH to find the new location. This is also available with + `shopt -s checkhash'. + +2. The >& redirection does not redirect stdout and stderr. + +3. The message printed by the job control code and builtins when a job + exits with a non-zero status is `Done(status)'. + +4. Reserved words may not be aliased. + +5. The Posix.2 PS1 and PS2 expansions of `!' -> history number and + `!!' -> `!' are enabled, and parameter expansion is performed on + the value regardless of the setting of the `promptvars' option. + +6. Interactive comments are enabled by default. (Note that bash has + them on by default anyway.) + +7. The Posix.2 startup files are executed ($ENV) rather than the normal + bash files. + +8. Tilde expansion is only performed on assignments preceding a command + name, rather than on all assignment statements on the line. + +9. The default history file is ~/.sh_history (default value of $HISTFILE). + +10. The output of `kill -l' prints all the signal names on a single line, + separated by spaces. + +11. Non-interactive shells exit if `file' in `. file' is not found. + +12. Redirection operators do not perform pathname expansion on the word + in the redirection unless the shell is interactive + +13. Function names must be valid shell identifiers. That is, they may not + contain characters other than letters, digits, and underscores, and + may not start with a digit. Declaring a function with an illegal name + causes a fatal syntax error in non-interactive shells. + +14. Posix.2 `special' builtins are found before shell functions during command + lookup. + +15. If a Posix.2 special builtin returns an error status, a non-interactive + shell exits. The fatal errors are those listed in the POSIX.2 standard, + and include things like passing incorrect options, redirection errors, + variable assignment errors for assignments preceding the command name, + and so on. + +16. The environment passed to executed commands is not sorted. Neither is + the output of `set'. This is not strictly Posix.2 behavior, but sh + does it this way. Ksh does not. It's not necessary to sort the + environment; no program should rely on it being sorted. + +17. If the `cd' builtin finds a directory to change to using $CDPATH, the + value it assigns to $PWD does not contain any symbolic links, as if + `cd -P' had been executed. + +18. A non-interactive shell exits with an error status if a variable + assignment error occurs when no command name follows the assignment + statements. A variable assignment error occurs, for example, when + trying to assign a value to a read-only variable. + +19. A non-interactive shell exits with an error status if the iteration + variable in a for statement or the selection variable in a select + statement is a read-only variable. + +20. Process substitution is not available. + +21. Assignment statements preceding POSIX.2 `special' builtins persist in + the shell environment after the builtin completes. + +There is other Posix.2 behavior that bash does not implement. Specifically: + +1. Assignment statements affect the execution environment of all builtins, + not just special ones. diff --git a/CWRU/old/set.def.save b/CWRU/old/set.def.save new file mode 100644 index 00000000..87b78d7c --- /dev/null +++ b/CWRU/old/set.def.save @@ -0,0 +1,544 @@ +This file is set.def, from which is created set.c. +It implements the "set" and "unset" builtins in Bash. + +Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GNU Bash, the Bourne Again SHell. + +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) any later +version. + +Bash is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +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. + +$PRODUCES set.c + +#include +#include "../shell.h" +#include "../flags.h" + +#include "bashgetopt.h" + +extern int interactive; +extern int noclobber, posixly_correct; +#if defined (READLINE) +extern int rl_editing_mode, no_line_editing; +#endif /* READLINE */ + +$BUILTIN set +$FUNCTION set_builtin +$SHORT_DOC set [--abefhkmnptuvxldBCHP] [-o option] [arg ...] + -a Mark variables which are modified or created for export. + -b Notify of job termination immediately. + -e Exit immediately if a command exits with a non-zero status. + -f Disable file name generation (globbing). + -h Locate and remember function commands as functions are + defined. Function commands are normally looked up when + the function is executed. + -i Force the shell to be an "interactive" one. Interactive shells + always read `~/.bashrc' on startup. + -k All keyword arguments are placed in the environment for a + command, not just those that precede the command name. + -m Job control is enabled. + -n Read commands but do not execute them. + -o option-name + Set the variable corresponding to option-name: + allexport same as -a + braceexpand same as -B +#if defined (READLINE) + emacs use an emacs-style line editing interface +#endif /* READLINE */ + errexit same as -e + histexpand same as -H + ignoreeof the shell will not exit upon reading EOF + interactive-comments + allow comments to appear in interactive commands + monitor same as -m + noclobber disallow redirection to existing files + noexec same as -n + noglob same as -f + nohash same as -d + notify save as -b + nounset same as -u + physical same as -P + posix change the behavior of bash where the default + operation differs from the 1003.2 standard to + match the standard + privileged same as -p + verbose same as -v +#if defined (READLINE) + vi use a vi-style line editing interface +#endif /* READLINE */ + xtrace same as -x + -p Turned on whenever the real and effective user ids do not match. + Disables processing of the $ENV file and importing of shell + functions. Turning this option off causes the effective uid and + gid to be set to the real uid and gid. + -t Exit after reading and executing one command. + -u Treat unset variables as an error when substituting. + -v Print shell input lines as they are read. + -x Print commands and their arguments as they are executed. + -l Save and restore the binding of the NAME in a FOR command. + -d Disable the hashing of commands that are looked up for execution. + Normally, commands are remembered in a hash table, and once + found, do not have to be looked up again. +#if defined (BRACE_EXPANSION) + -B the shell will perform brace expansion +#endif /* BRACE_EXPANSION */ +#if defined (BANG_HISTORY) + -H Enable ! style history substitution. This flag is on + by default. +#endif /* BANG_HISTORY */ + -C If set, disallow existing regular files to be overwritten + by redirection of output. + -P If set, do not follow symbolic links when executing commands + such as cd which change the current directory. + +Using + rather than - causes these flags to be turned off. The +flags can also be used upon invocation of the shell. The current +set of flags may be found in $-. The remaining n ARGs are positional +parameters and are assigned, in order, to $1, $2, .. $n. If no +ARGs are given, all shell variables are printed. +$END + +/* An a-list used to match long options for set -o to the corresponding + option letter. */ +struct { + char *name; + int letter; +} o_options[] = { + { "allexport", 'a' }, +#if defined (BRACE_EXPANSION) + { "braceexpand",'B' }, +#endif + { "errexit", 'e' }, + { "histexpand", 'H' }, + { "monitor", 'm' }, + { "noexec", 'n' }, + { "noglob", 'f' }, + { "nohash", 'd' }, +#if defined (JOB_CONTROL) + { "notify", 'b' }, +#endif /* JOB_CONTROL */ + {"nounset", 'u' }, + {"physical", 'P' }, + {"privileged", 'p' }, + {"verbose", 'v' }, + {"xtrace", 'x' }, + {(char *)NULL, 0}, +}; + +#define MINUS_O_FORMAT "%-15s\t%s\n" + +void +list_minus_o_opts () +{ + register int i; + char *on = "on", *off = "off"; + + printf (MINUS_O_FORMAT, "noclobber", (noclobber == 1) ? on : off); + + if (find_variable ("ignoreeof") || find_variable ("IGNOREEOF")) + printf (MINUS_O_FORMAT, "ignoreeof", on); + else + printf (MINUS_O_FORMAT, "ignoreeof", off); + + printf (MINUS_O_FORMAT, "interactive-comments", + interactive_comments ? on : off); + + printf (MINUS_O_FORMAT, "posix", posixly_correct ? on : off); + +#if defined (READLINE) + if (no_line_editing) + { + printf (MINUS_O_FORMAT, "emacs", off); + printf (MINUS_O_FORMAT, "vi", off); + } + else + { + /* Magic. This code `knows' how readline handles rl_editing_mode. */ + printf (MINUS_O_FORMAT, "emacs", (rl_editing_mode == 1) ? on : off); + printf (MINUS_O_FORMAT, "vi", (rl_editing_mode == 0) ? on : off); + } +#endif /* READLINE */ + + for (i = 0; o_options[i].name; i++) + { + int *on_or_off, zero = 0; + + on_or_off = find_flag (o_options[i].letter); + if (on_or_off == FLAG_UNKNOWN) + on_or_off = &zero; + printf (MINUS_O_FORMAT, o_options[i].name, (*on_or_off == 1) ? on : off); + } +} + +set_minus_o_option (on_or_off, option_name) + int on_or_off; + char *option_name; +{ + int option_char = -1; + + if (STREQ (option_name, "noclobber")) + { + if (on_or_off == FLAG_ON) + bind_variable ("noclobber", ""); + else + unbind_variable ("noclobber"); + stupidly_hack_special_variables ("noclobber"); + } + else if (STREQ (option_name, "ignoreeof")) + { + unbind_variable ("ignoreeof"); + unbind_variable ("IGNOREEOF"); + if (on_or_off == FLAG_ON) + bind_variable ("IGNOREEOF", "10"); + stupidly_hack_special_variables ("IGNOREEOF"); + } + +#if defined (READLINE) + else if ((STREQ (option_name, "emacs")) || (STREQ (option_name, "vi"))) + { + if (on_or_off == FLAG_ON) + { + rl_variable_bind ("editing-mode", option_name); + + if (interactive) + with_input_from_stdin (); + no_line_editing = 0; + } + else + { + int isemacs = (rl_editing_mode == 1); + if ((isemacs && STREQ (option_name, "emacs")) || + (!isemacs && STREQ (option_name, "vi"))) + { + if (interactive) + with_input_from_stream (stdin, "stdin"); + no_line_editing = 1; + } + else + builtin_error ("not in %s editing mode", option_name); + } + } +#endif /* READLINE */ + else if (STREQ (option_name, "interactive-comments")) + interactive_comments = (on_or_off == FLAG_ON); + else if (STREQ (option_name, "posix")) + { + posixly_correct = (on_or_off == FLAG_ON); + unbind_variable ("POSIXLY_CORRECT"); + unbind_variable ("POSIX_PEDANTIC"); + if (on_or_off == FLAG_ON) + { + bind_variable ("POSIXLY_CORRECT", ""); + stupidly_hack_special_variables ("POSIXLY_CORRECT"); + } + } + else + { + register int i; + for (i = 0; o_options[i].name; i++) + { + if (STREQ (option_name, o_options[i].name)) + { + option_char = o_options[i].letter; + break; + } + } + if (option_char == -1) + { + builtin_error ("%s: unknown option name", option_name); + return (EXECUTION_FAILURE); + } + if (change_flag (option_char, on_or_off) == FLAG_ERROR) + { + bad_option (option_name); + return (EXECUTION_FAILURE); + } + } + return (EXECUTION_SUCCESS); +} + +/* Set some flags from the word values in the input list. If LIST is empty, + then print out the values of the variables instead. If LIST contains + non-flags, then set $1 - $9 to the successive words of LIST. */ +set_builtin (list) + WORD_LIST *list; +{ + int on_or_off, flag_name, force_assignment = 0; + + if (!list) + { + SHELL_VAR **vars; + + vars = all_shell_variables (); + if (vars) + { + print_var_list (vars); + free (vars); + } + + vars = all_shell_functions (); + if (vars) + { + print_var_list (vars); + free (vars); + } + + return (EXECUTION_SUCCESS); + } + + /* Check validity of flag arguments. */ + if (*list->word->word == '-' || *list->word->word == '+') + { + register char *arg; + WORD_LIST *save_list = list; + + while (list && (arg = list->word->word)) + { + char c; + + if (arg[0] != '-' && arg[0] != '+') + break; + + /* `-' or `--' signifies end of flag arguments. */ + if (arg[0] == '-' && + (!arg[1] || (arg[1] == '-' && !arg[2]))) + break; + + while (c = *++arg) + { + if (find_flag (c) == FLAG_UNKNOWN && c != 'o') + { + char s[2]; + s[0] = c; s[1] = '\0'; + bad_option (s); + if (c == '?') + builtin_usage (); + return (c == '?' ? EXECUTION_SUCCESS : EXECUTION_FAILURE); + } + } + list = list->next; + } + list = save_list; + } + + /* Do the set command. While the list consists of words starting with + '-' or '+' treat them as flags, otherwise, start assigning them to + $1 ... $n. */ + while (list) + { + char *string = list->word->word; + + /* If the argument is `--' or `-' then signal the end of the list + and remember the remaining arguments. */ + if (string[0] == '-' && (!string[1] || (string[1] == '-' && !string[2]))) + { + list = list->next; + + /* `set --' unsets the positional parameters. */ + if (string[1] == '-') + force_assignment = 1; + + /* Until told differently, the old shell behaviour of + `set - [arg ...]' being equivalent to `set +xv [arg ...]' + stands. Posix.2 says the behaviour is marked as obsolescent. */ + else + { + change_flag ('x', '+'); + change_flag ('v', '+'); + } + + break; + } + + if ((on_or_off = *string) && + (on_or_off == '-' || on_or_off == '+')) + { + int i = 1; + while (flag_name = string[i++]) + { + if (flag_name == '?') + { + builtin_usage (); + return (EXECUTION_SUCCESS); + } + else if (flag_name == 'o') /* -+o option-name */ + { + char *option_name; + WORD_LIST *opt; + + opt = list->next; + + if (!opt) + { + list_minus_o_opts (); + continue; + } + + option_name = opt->word->word; + + if (!option_name || !*option_name || (*option_name == '-')) + { + list_minus_o_opts (); + continue; + } + list = list->next; /* Skip over option name. */ + + if (set_minus_o_option (on_or_off, option_name) != EXECUTION_SUCCESS) + return (EXECUTION_FAILURE); + } + else + { + if (change_flag (flag_name, on_or_off) == FLAG_ERROR) + { + char opt[3]; + opt[0] = on_or_off; + opt[1] = flag_name; + opt[2] = '\0'; + bad_option (opt); + builtin_usage (); + return (EXECUTION_FAILURE); + } + } + } + } + else + { + break; + } + list = list->next; + } + + /* Assigning $1 ... $n */ + if (list || force_assignment) + remember_args (list, 1); + return (EXECUTION_SUCCESS); +} + +$BUILTIN unset +$FUNCTION unset_builtin +$SHORT_DOC unset [-f] [-v] [name ...] +For each NAME, remove the corresponding variable or function. Given +the `-v', unset will only act on variables. Given the `-f' flag, +unset will only act on functions. With neither flag, unset first +tries to unset a variable, and if that fails, then tries to unset a +function. Some variables (such as PATH and IFS) cannot be unset; also +see readonly. +$END + +#define NEXT_VARIABLE() any_failed++; list = list->next; continue; + +unset_builtin (list) + WORD_LIST *list; +{ + int unset_function, unset_variable, unset_array, opt, any_failed; + char *name; + + unset_function = unset_variable = unset_array = any_failed = 0; + + reset_internal_getopt (); + while ((opt = internal_getopt (list, "fv")) != -1) + { + switch (opt) + { + case 'f': + unset_function = 1; + break; + case 'v': + unset_variable = 1; + break; + default: + builtin_usage (); + return (EXECUTION_FAILURE); + } + } + + list = loptend; + + if (unset_function && unset_variable) + { + builtin_error ("cannot simultaneously unset a function and a variable"); + return (EXECUTION_FAILURE); + } + + while (list) + { + SHELL_VAR *var; + int tem; +#if defined (ARRAY_VARS) + char *t; +#endif + + name = list->word->word; + +#if defined (ARRAY_VARS) + if (!unset_function && valid_array_reference (name)) + { + t = strchr (name, '['); + *t++ = '\0'; + unset_array++; + } +#endif + + var = unset_function ? find_function (name) : find_variable (name); + + if (var && !unset_function && non_unsettable_p (var)) + { + builtin_error ("%s: cannot unset", name); + NEXT_VARIABLE (); + } + + /* Posix.2 says that unsetting readonly variables is an error. */ + if (var && readonly_p (var)) + { + builtin_error ("%s: cannot unset: readonly %s", + name, unset_function ? "function" : "variable"); + NEXT_VARIABLE (); + } + + /* Unless the -f option is supplied, the name refers to a variable. */ +#if defined (ARRAY_VARS) + if (var && unset_array) + { + if (array_p (var) == 0) + { + builtin_error ("%s: not an array variable", name); + NEXT_VARIABLE (); + } + else + tem = unbind_array_element (var, t); + } + else +#endif /* ARRAY_VARS */ + tem = makunbound (name, unset_function ? shell_functions : shell_variables); + + /* This is what Posix.2 draft 11+ says. ``If neither -f nor -v + is specified, the name refers to a variable; if a variable by + that name does not exist, a function by that name, if any, + shall be unset.'' */ + if ((tem == -1) && !unset_function && !unset_variable) + tem = makunbound (name, shell_functions); + + if (tem == -1) + any_failed++; + else if (!unset_function) + stupidly_hack_special_variables (name); + + list = list->next; + } + + if (any_failed) + return (EXECUTION_FAILURE); + else + return (EXECUTION_SUCCESS); +} diff --git a/CWRU/save/unwind_prot.h.save b/CWRU/save/unwind_prot.h.save new file mode 100644 index 00000000..998fd72b --- /dev/null +++ b/CWRU/save/unwind_prot.h.save @@ -0,0 +1,50 @@ +/* unwind_prot.h - Macros and functions for hacking unwind protection. */ + +/* Copyright (C) 1993 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + 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 2, or (at your option) any later + version. + + Bash is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + 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. */ + +#if !defined (_UNWIND_PROT_H) +#define _UNWIND_PROT_H + +/* Run a function without interrupts. */ +extern void begin_unwind_frame (); +extern void discard_unwind_frame (); +extern void run_unwind_frame (); +extern void add_unwind_protect (); +extern void remove_unwind_protect (); +extern void run_unwind_protects (); +extern void unwind_protect_var (); + +/* Define for people who like their code to look a certain way. */ +#define end_unwind_frame() + +/* How to protect an integer. */ +#define unwind_protect_int(X) unwind_protect_var (&(X), (char *)(X), sizeof (int)) + +/* How to protect a pointer to a string. */ +#define unwind_protect_string(X) \ + unwind_protect_var ((int *)&(X), (X), sizeof (char *)) + +/* How to protect any old pointer. */ +#define unwind_protect_pointer(X) unwind_protect_string (X) + +/* How to protect the contents of a jmp_buf. */ +#define unwind_protect_jmp_buf(X) \ + unwind_protect_var ((int *)(X), (char *)(X), sizeof (procenv_t)) + +#endif /* _UNWIND_PROT_H */ diff --git a/MANIFEST b/MANIFEST index eae9e1cb..d81c68d6 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1051,6 +1051,9 @@ tests/nquote4.tests f tests/nquote4.right f tests/nquote5.tests f tests/nquote5.right f +tests/parser.tests f +tests/parser.right f +tests/parser1.sub f tests/posix2.tests f tests/posix2.right f tests/posixexp.tests f @@ -1157,6 +1160,7 @@ tests/run-nquote2 f tests/run-nquote3 f tests/run-nquote4 f tests/run-nquote5 f +tests/run-parser f tests/run-posix2 f tests/run-posixexp f tests/run-posixexp2 f diff --git a/builtins/evalstring.c b/builtins/evalstring.c index ce5b4d63..85ad985f 100644 --- a/builtins/evalstring.c +++ b/builtins/evalstring.c @@ -226,6 +226,10 @@ parse_and_execute (string, from_file, flags) code = should_jump_to_top_level = 0; last_result = EXECUTION_SUCCESS; + /* We need to reset enough of the token state so we can start fresh. */ + if (current_token == yacc_EOF) + current_token = '\n'; /* reset_parser() ? */ + with_input_from_string (string, from_file); while (*(bash_input.location.string)) { diff --git a/cross-build/cygwin32.cache.old b/cross-build/cygwin32.cache.old new file mode 100644 index 00000000..640390fb --- /dev/null +++ b/cross-build/cygwin32.cache.old @@ -0,0 +1,42 @@ +# This file is a shell script that caches the results of configure +# tests for CYGWIN32 so they don't need to be done when cross-compiling. + +# AC_FUNC_GETPGRP should also define GETPGRP_VOID +ac_cv_func_getpgrp_void=${ac_cv_func_getpgrp_void='yes'} +# AC_FUNC_SETVBUF_REVERSED should not define anything else +ac_cv_func_setvbuf_reversed=${ac_cv_func_setvbuf_reversed='no'} +# on CYGWIN32, system calls do not restart +ac_cv_sys_restartable_syscalls=${ac_cv_sys_restartable_syscalls='no'} +bash_cv_sys_restartable_syscalls=${bash_cv_sys_restartable_syscalls='no'} + +# these may be necessary, but they are currently commented out +#ac_cv_c_bigendian=${ac_cv_c_bigendian='no'} +ac_cv_sizeof_char_p=${ac_cv_sizeof_char_p='4'} +ac_cv_sizeof_int=${ac_cv_sizeof_int='4'} +ac_cv_sizeof_long=${ac_cv_sizeof_long='4'} +ac_cv_sizeof_double=${ac_cv_sizeof_double='8'} + +bash_cv_dup2_broken=${bash_cv_dup2_broken='no'} +bash_cv_pgrp_pipe=${bash_cv_pgrp_pipe='no'} +bash_cv_type_rlimit=${bash_cv_type_rlimit='long'} +bash_cv_decl_under_sys_siglist=${bash_cv_decl_under_sys_siglist='no'} +bash_cv_under_sys_siglist=${bash_cv_under_sys_siglist='no'} +bash_cv_sys_siglist=${bash_cv_sys_siglist='no'} +bash_cv_opendir_not_robust=${bash_cv_opendir_not_robust='no'} +bash_cv_getenv_redef=${bash_cv_getenv_redef='yes'} +bash_cv_printf_declared=${bash_cv_printf_declared='yes'} +bash_cv_ulimit_maxfds=${bash_cv_ulimit_maxfds='no'} +bash_cv_getcwd_calls_popen=${bash_cv_getcwd_calls_popen='no'} +bash_cv_must_reinstall_sighandlers=${bash_cv_must_reinstall_sighandlers='no'} +bash_cv_job_control_missing=${bash_cv_job_control_missing='present'} +bash_cv_sys_named_pipes=${bash_cv_sys_named_pipes='missing'} +bash_cv_func_sigsetjmp=${bash_cv_func_sigsetjmp='missing'} +bash_cv_mail_dir=${bash_cv_mail_dir='unknown'} +bash_cv_func_strcoll_broken=${bash_cv_func_strcoll_broken='no'} + +bash_cv_type_int32_t=${bash_cv_type_int32_t='int'} +bash_cv_type_u_int32_t=${bash_cv_type_u_int32_t='int'} + +ac_cv_type_bits64_t=${ac_cv_type_bits64_t='no'} + +# end of cross-build/cygwin32.cache diff --git a/doc/FAQ.orig b/doc/FAQ.orig new file mode 100644 index 00000000..1cff3c8e --- /dev/null +++ b/doc/FAQ.orig @@ -0,0 +1,1745 @@ +This is the Bash FAQ, version 3.24, for Bash version 2.05b. + +This document contains a set of frequently-asked questions concerning +Bash, the GNU Bourne-Again Shell. Bash is a freely-available command +interpreter with advanced features for both interactive use and shell +programming. + +Another good source of basic information about shells is the collection +of FAQ articles periodically posted to comp.unix.shell. + +Questions and comments concerning this document should be sent to +chet@po.cwru.edu. + +This document is available for anonymous FTP with the URL + +ftp://ftp.cwru.edu/pub/bash/FAQ + +The Bash home page is http://cnswww.cns.cwru.edu/~chet/bash/bashtop.html + +---------- +Contents: + +Section A: The Basics + +A1) What is it? +A2) What's the latest version? +A3) Where can I get it? +A4) On what machines will bash run? +A5) Will bash run on operating systems other than Unix? +A6) How can I build bash with gcc? +A7) How can I make bash my login shell? +A8) I just changed my login shell to bash, and now I can't FTP into my + machine. Why not? +A9) What's the `POSIX 1003.2 standard'? +A10) What is the bash `posix mode'? + +Section B: The latest version + +B1) What's new in version 2.05b? +B2) Are there any user-visible incompatibilities between bash-2.05b and + bash-1.14.7? + +Section C: Differences from other Unix shells + +C1) How does bash differ from sh, the Bourne shell? +C2) How does bash differ from the Korn shell, version ksh88? +C3) Which new features in ksh-93 are not in bash, and which are? + +Section D: Why does bash do some things differently than other Unix shells? + +D1) Why does bash run a different version of `command' than + `which command' says it will? +D2) Why doesn't bash treat brace expansions exactly like csh? +D3) Why doesn't bash have csh variable modifiers? +D4) How can I make my csh aliases work when I convert to bash? +D5) How can I pipe standard output and standard error from one command to + another, like csh does with `|&'? +D6) Now that I've converted from ksh to bash, are there equivalents to + ksh features like autoloaded functions and the `whence' command? + +Section E: Why does bash do certain things the way it does? + +E1) Why is the bash builtin `test' slightly different from /bin/test? +E2) Why does bash sometimes say `Broken pipe'? +E3) When I have terminal escape sequences in my prompt, why does bash + wrap lines at the wrong column? +E4) If I pipe the output of a command into `read variable', why doesn't + the output show up in $variable when the read command finishes? +E5) I have a bunch of shell scripts that use backslash-escaped characters + in arguments to `echo'. Bash doesn't interpret these characters. Why + not, and how can I make it understand them? +E6) Why doesn't a while or for loop get suspended when I type ^Z? +E7) What about empty for loops in Makefiles? +E8) Why does the arithmetic evaluation code complain about `08'? +E9) Why does the pattern matching expression [A-Z]* match files beginning + with every letter except `z'? +E10) Why does `cd //' leave $PWD as `//'? +E11) If I resize my xterm while another program is running, why doesn't bash + notice the change? + +Section F: Things to watch out for on certain Unix versions + +F1) Why can't I use command line editing in my `cmdtool'? +F2) I built bash on Solaris 2. Why do globbing expansions and filename + completion chop off the first few characters of each filename? +F3) Why does bash dump core after I interrupt username completion or + `~user' tilde expansion on a machine running NIS? +F4) I'm running SVR4.2. Why is the line erased every time I type `@'? +F5) Why does bash report syntax errors when my C News scripts use a + redirection before a subshell command? +F6) Why can't I use vi-mode editing on Red Hat Linux 6.1? +F7) Why do bash-2.05a and bash-2.05b fail to compile `printf.def' on + HP/UX 11.x? + +Section G: How can I get bash to do certain common things? + +G1) How can I get bash to read and display eight-bit characters? +G2) How do I write a function `x' to replace builtin command `x', but + still invoke the command from within the function? +G3) How can I find the value of a shell variable whose name is the value + of another shell variable? +G4) How can I make the bash `time' reserved word print timing output that + looks like the output from my system's /usr/bin/time? +G5) How do I get the current directory into my prompt? +G6) How can I rename "*.foo" to "*.bar"? +G7) How can I translate a filename from uppercase to lowercase? +G8) How can I write a filename expansion (globbing) pattern that will match + all files in the current directory except "." and ".."? + +Section H: Where do I go from here? + +H1) How do I report bugs in bash, and where should I look for fixes and + advice? +H2) What kind of bash documentation is there? +H3) What's coming in future versions? +H4) What's on the bash `wish list'? +H5) When will the next release appear? + +---------- +Section A: The Basics + +A1) What is it? + +Bash is a Unix command interpreter (shell). It is an implementation of +the Posix 1003.2 shell standard, and resembles the Korn and System V +shells. + +Bash contains a number of enhancements over those shells, both +for interactive use and shell programming. Features geared +toward interactive use include command line editing, command +history, job control, aliases, and prompt expansion. Programming +features include additional variable expansions, shell +arithmetic, and a number of variables and options to control +shell behavior. + +Bash was originally written by Brian Fox of the Free Software +Foundation. The current developer and maintainer is Chet Ramey +of Case Western Reserve University. + +A2) What's the latest version? + +The latest version is 2.05b, first made available on Wednesday, 17 +July, 2002. + +A3) Where can I get it? + +Bash is the GNU project's shell, and so is available from the +master GNU archive site, ftp.gnu.org, and its mirrors. The +latest version is also available for FTP from ftp.cwru.edu. +The following URLs tell how to get version 2.05b: + +ftp://ftp.gnu.org/pub/gnu/bash/bash-2.05b.tar.gz +ftp://ftp.cwru.edu/pub/bash/bash-2.05b.tar.gz + +Formatted versions of the documentation are available with the URLs: + +ftp://ftp.gnu.org/pub/gnu/bash/bash-doc-2.05b.tar.gz +ftp://ftp.cwru.edu/pub/bash/bash-doc-2.05b.tar.gz + +A4) On what machines will bash run? + +Bash has been ported to nearly every version of UNIX. All you +should have to do to build it on a machine for which a port +exists is to type `configure' and then `make'. The build process +will attempt to discover the version of UNIX you have and tailor +itself accordingly, using a script created by GNU autoconf. + +More information appears in the file `INSTALL' in the distribution. + +The Bash web page (http://cnswww.cns.cwru.edu/~chet/bash/bashtop.html) +explains how to obtain binary versions of bash for most of the major +commercial Unix systems. + +A5) Will bash run on operating systems other than Unix? + +Configuration specifics for Unix-like systems such as QNX and +LynxOS are included in the distribution. Bash-2.05 and later +versions should compile and run on Minix 2.0 (patches were +contributed), but I don't believe anyone has built bash-2.x on +earlier Minix versions yet. + +Bash has been ported to versions of Windows implementing the Win32 +programming interface. This includes Windows 95 and Windows NT. +The port was done by Cygnus Solutions as part of their CYGWIN +project. For more information about the project, look at the URLs + +http://www.cygwin.com/ +http://sourceware.cygnus.com/cygwin + +Cygnus originally ported bash-1.14.7, and that port was part of their +early GNU-Win32 (the original name) releases. Cygnus has also done a +port of bash-2.05 to the CYGWIN environment, and it is available as +part of their current release. + +Bash-2.05b should require no local Cygnus changes to build and run under +CYGWIN. + +The Cygnus port works only on Intel machines. There is a port of bash +(I don't know which version) to the alpha/NT environment available from + +ftp://ftp.gnustep.org//pub/win32/bash-alpha-nt-1.01.tar.gz + +DJ Delorie has a port of bash-2.x which runs under MS-DOS, as part +of the DJGPP project. For more information on the project, see + +http://www.delorie.com/djgpp/ + +I have been told that the original DJGPP port was done by Daisuke Aoyama. + +Mark Elbrecht has sent me notice that bash-2.04 +is available for DJGPP V2. The files are available as: + +ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204b.zip binary +ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204d.zip documentation +ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204s.zip source + +Mark has begun to work with bash-2.05, but I don't know the status. + +Ports of bash-1.12 and bash-2.0 are available for OS/2 from + +ftp://hobbes.nmsu.edu/pub/os2/util/shell/bash_112.zip +ftp://hobbes.nmsu.edu/pub/os2/util/shell/bash-2.0(253).zip + +I haven't looked at either, but the second appears to be a binary-only +distribution. Beware. + +I have received word that Bash (I'm not sure which version, but I +believe that it's at least bash-2.02.1) is the standard shell on +BeOS. + +A6) How can I build bash with gcc? + +Bash configures to use gcc by default if it is available. Read the +file INSTALL in the distribution for more information. + +A7) How can I make bash my login shell? + +Some machines let you use `chsh' to change your login shell. Other +systems use `passwd -s' or `passwd -e'. If one of these works for +you, that's all you need. Note that many systems require the full +pathname to a shell to appear in /etc/shells before you can make it +your login shell. For this, you may need the assistance of your +friendly local system administrator. + +If you cannot do this, you can still use bash as your login shell, but +you need to perform some tricks. The basic idea is to add a command +to your login shell's startup file to replace your login shell with +bash. + +For example, if your login shell is csh or tcsh, and you have installed +bash in /usr/gnu/bin/bash, add the following line to ~/.login: + + if ( -f /usr/gnu/bin/bash ) exec /usr/gnu/bin/bash --login + +(the `--login' tells bash that it is a login shell). + +It's not a good idea to put this command into ~/.cshrc, because every +csh you run without the `-f' option, even ones started to run csh scripts, +reads that file. If you must put the command in ~/.cshrc, use something +like + + if ( $?prompt ) exec /usr/gnu/bin/bash --login + +to ensure that bash is exec'd only when the csh is interactive. + +If your login shell is sh or ksh, you have to do two things. + +First, create an empty file in your home directory named `.bash_profile'. +The existence of this file will prevent the exec'd bash from trying to +read ~/.profile, and re-execing itself over and over again. ~/.bash_profile +is the first file bash tries to read initialization commands from when +it is invoked as a login shell. + +Next, add a line similar to the above to ~/.profile: + + [ -f /usr/gnu/bin/bash ] && [ -x /usr/gnu/bin/bash ] && \ + exec /usr/gnu/bin/bash --login + +This will cause login shells to replace themselves with bash running as +a login shell. Once you have this working, you can copy your initialization +code from ~/.profile to ~/.bash_profile. + +I have received word that the recipe supplied above is insufficient for +machines running CDE. CDE has a maze of twisty little startup files, all +slightly different. + +If you cannot change your login shell in the password file to bash, you +will have to (apparently) live with CDE using the shell in the password +file to run its startup scripts. If you have changed your shell to bash, +there is code in the CDE startup files (on Solaris, at least) that attempts +to do the right thing. It is, however, often broken, and may require that +you use the $BASH_ENV trick described below. + +`dtterm' claims to use $SHELL as the default program to start, so if you +can change $SHELL in the CDE startup files, you should be able to use bash +in your terminal windows. + +Setting DTSOURCEPROFILE in ~/.dtprofile will cause the `Xsession' program +to read your login shell's startup files. You may be able to use bash for +the rest of the CDE programs by setting SHELL to bash in ~/.dtprofile as +well, but I have not tried this. + +You can use the above `exec' recipe to start bash when not logging in with +CDE by testing the value of the DT variable: + + if [ -n "$DT" ]; then + [ -f /usr/gnu/bin/bash ] && exec /usr/gnu/bin/bash --login + fi + +If CDE starts its shells non-interactively during login, the login shell +startup files (~/.profile, ~/.bash_profile) will not be sourced at login. +To get around this problem, append a line similar to the following to your +~/.dtprofile: + + BASH_ENV=${HOME}/.bash_profile ; export BASH_ENV + +and add the following line to the beginning of ~/.bash_profile: + + unset BASH_ENV + +A8) I just changed my login shell to bash, and now I can't FTP into my + machine. Why not? + +You must add the full pathname to bash to the file /etc/shells. As +noted in the answer to the previous question, many systems require +this before you can make bash your login shell. + +Most versions of ftpd use this file to prohibit `special' users +such as `uucp' and `news' from using FTP. + +A9) What's the `POSIX 1003.2 standard'? + +POSIX is a name originally coined by Richard Stallman for a +family of open system standards based on UNIX. There are a +number of aspects of UNIX under consideration for +standardization, from the basic system services at the system +call and C library level to applications and tools to system +administration and management. Each area of standardization is +assigned to a working group in the 1003 series. + +The POSIX Shell and Utilities standard has been developed by IEEE +Working Group 1003.2 (POSIX.2). It concentrates on the command +interpreter interface and utility programs commonly executed from +the command line or by other programs. An initial version of the +standard has been approved and published by the IEEE, and work is +currently underway to update it. + +Bash is concerned with the aspects of the shell's behavior +defined by POSIX.2. The shell command language has of course +been standardized, including the basic flow control and program +execution constructs, I/O redirection and pipelining, argument +handling, variable expansion, and quoting. + +The `special' builtins, which must be implemented as part of the +shell to provide the desired functionality, are specified as +being part of the shell; examples of these are `eval' and +`export'. Other utilities appear in the sections of POSIX.2 not +devoted to the shell which are commonly (and in some cases must +be) implemented as builtin commands, such as `read' and `test'. +POSIX.2 also specifies aspects of the shell's interactive +behavior as part of the UPE, including job control and command +line editing. Only vi-style line editing commands have been +standardized; emacs editing commands were left out due to +objections. + +The Open Group has made an older version of its Single Unix +Specification (version 2), which is very similar to POSIX.2, +available on the web at + +http://www.opengroup.org/onlinepubs/007908799/ + +The Single Unix Specification, version 3, is available on the web at + +http://www.opengroup.org/onlinepubs/007904975/ + +A10) What is the bash `posix mode'? + +Although bash is an implementation of the POSIX.2 shell +specification, there are areas where the bash default behavior +differs from that spec. The bash `posix mode' changes the bash +behavior in these areas so that it obeys the spec more closely. + +Posix mode is entered by starting bash with the --posix or +'-o posix' option or executing `set -o posix' after bash is running. + +The specific aspects of bash which change when posix mode is +active are listed in the file POSIX in the bash distribution. +They are also listed in a section in the Bash Reference Manual +(from which that file is generated). + +Section B: The latest version + +B1) What's new in version 2.05b? + +The raison d'etre for bash-2.05b is to make a second intermediate +release containing the first of the new features to be available +in bash-3.0 and get feedback on those features before proceeding. +The major new feature is multibyte character support in both Bash +and Readline. + +Bash-2.05b contains the following new features (see the manual page for +complete descriptions and the CHANGES and NEWS files in the bash-2.05b +distribution): + +o support for multibyte characters has been added to both bash and readline + +o the DEBUG trap is now run *before* simple commands, ((...)) commands, + [[...]] conditional commands, and for ((...)) loops + +o the shell now performs arithmetic in the largest integer size the machine + supports (intmax_t) + +o there is a new \D{...} prompt expansion; passes the `...' to strftime(3) + and inserts the result into the expanded prompt + +o there is a new `here-string' redirection operator: <<< word + +o when displaying variables, function attributes and definitions are shown + separately, allowing them to be re-used as input (attempting to re-use + the old output would result in syntax errors). + +o `read' has a new `-u fd' option to read from a specified file descriptor + +o the bash debugger in examples/bashdb has been modified to work with the + new DEBUG trap semantics, the command set has been made more gdb-like, + and the changes to $LINENO make debugging functions work better + +o the expansion of $LINENO inside a shell function is only relative to the + function start if the shell is interactive -- if the shell is running a + script, $LINENO expands to the line number in the script. This is as + POSIX-2001 requires + + +A short feature history dating from Bash-2.0: + +Bash-2.05a introduced the following new features: + +o The `printf' builtin has undergone major work + +o There is a new read-only `shopt' option: login_shell, which is set by + login shells and unset otherwise + +o New `\A' prompt string escape sequence; expanding to time in 24-hour + HH:MM format + +o New `-A group/-g' option to complete and compgen; goes group name + completion + +o New [+-]O invocation option to set and unset `shopt' options at startup + +o ksh-like `ERR' trap + +o `for' loops now allow empty word lists after the `in' reserved word + +o new `hard' and `soft' arguments for the `ulimit' builtin + +o Readline can be configured to place the user at the same point on the line + when retrieving commands from the history list + +o Readline can be configured to skip `hidden' files (filenames with a leading + `.' on Unix) when performing completion + +Bash-2.05 introduced the following new features: + +o This version has once again reverted to using locales and strcoll(3) when + processing pattern matching bracket expressions, as POSIX requires. +o Added a new `--init-file' invocation argument as a synonym for `--rcfile', + per the new GNU coding standards. +o The /dev/tcp and /dev/udp redirections now accept service names as well as + port numbers. +o `complete' and `compgen' now take a `-o value' option, which controls some + of the aspects of that compspec. Valid values are: + + default - perform bash default completion if programmable + completion produces no matches + dirnames - perform directory name completion if programmable + completion produces no matches + filenames - tell readline that the compspec produces filenames, + so it can do things like append slashes to + directory names and suppress trailing spaces +o A new loadable builtin, realpath, which canonicalizes and expands symlinks + in pathname arguments. +o When `set' is called without options, it prints function defintions in a + way that allows them to be reused as input. This affects `declare' and + `declare -p' as well. This only happens when the shell is not in POSIX + mode, since POSIX.2 forbids this behavior. + +Bash-2.04 introduced the following new features: + +o Programmable word completion with the new `complete' and `compgen' builtins; + examples are provided in examples/complete/complete-examples +o `history' has a new `-d' option to delete a history entry +o `bind' has a new `-x' option to bind key sequences to shell commands +o The prompt expansion code has new `\j' and `\l' escape sequences +o The `no_empty_cmd_completion' shell option, if enabled, inhibits + command completion when TAB is typed on an empty line +o `help' has a new `-s' option to print a usage synopsis +o New arithmetic operators: var++, var--, ++var, --var, expr1,expr2 (comma) +o New ksh93-style arithmetic for command: + for ((expr1 ; expr2; expr3 )); do list; done +o `read' has new options: `-t', `-n', `-d', `-s' +o The redirection code handles several filenames specially: /dev/fd/N, + /dev/stdin, /dev/stdout, /dev/stderr +o The redirection code now recognizes /dev/tcp/HOST/PORT and + /dev/udp/HOST/PORT and tries to open a TCP or UDP socket, respectively, + to the specified port on the specified host +o The ${!prefix*} expansion has been implemented +o A new FUNCNAME variable, which expands to the name of a currently-executing + function +o The GROUPS variable is no longer readonly +o A new shopt `xpg_echo' variable, to control the behavior of echo with + respect to backslash-escape sequences at runtime +o The NON_INTERACTIVE_LOGIN_SHELLS #define has returned + +The version of Readline released with Bash-2.04, Readline-4.1, had several +new features as well: + +o Parentheses matching is always compiled into readline, and controllable + with the new `blink-matching-paren' variable +o The history-search-forward and history-search-backward functions now leave + point at the end of the line when the search string is empty, like + reverse-search-history, and forward-search-history +o A new function for applications: rl_on_new_line_with_prompt() +o New variables for applications: rl_already_prompted, and rl_gnu_readline_p + + +Bash-2.03 had very few new features, in keeping with the convention +that odd-numbered releases provide mainly bug fixes. A number of new +features were added to Readline, mostly at the request of the Cygnus +folks. + +A new shopt option, `restricted_shell', so that startup files can test + whether or not the shell was started in restricted mode +Filename generation is now performed on the words between ( and ) in + compound array assignments (this is really a bug fix) +OLDPWD is now auto-exported, as POSIX.2 requires +ENV and BASH_ENV are read-only variables in a restricted shell +Bash may now be linked against an already-installed Readline library, + as long as the Readline library is version 4 or newer +All shells begun with the `--login' option will source the login shell + startup files, even if the shell is not interactive + +There were lots of changes to the version of the Readline library released +along with Bash-2.03. For a complete list of the changes, read the file +CHANGES in the Bash-2.03 distribution. + +Bash-2.02 contained the following new features: + +a new version of malloc (based on the old GNU malloc code in previous + bash versions) that is more page-oriented, more conservative + with memory usage, does not `orphan' large blocks when they + are freed, is usable on 64-bit machines, and has allocation + checking turned on unconditionally +POSIX.2-style globbing character classes ([:alpha:], [:alnum:], etc.) +POSIX.2-style globbing equivalence classes +POSIX.2-style globbing collating symbols +the ksh [[...]] extended conditional command +the ksh egrep-style extended pattern matching operators +a new `printf' builtin +the ksh-like $(, &>, >|, <<<, [n]<&word-, [n]>&word- + prompt string special char translation and variable expansion + auto-export of variables in initial environment + command search finds functions before builtins + bash return builtin will exit a file sourced with `.' + builtins: cd -/-L/-P, exec -l/-c/-a, echo -e/-E, hash -d/-l/-p/-t. + export -n/-f/-p/name=value, pwd -L/-P, + read -e/-p/-a/-t/-n/-d/-s/-u, + readonly -a/-f/name=value, trap -l, set +o, + set -b/-m/-o option/-h/-p/-B/-C/-H/-P, + unset -f/-v, ulimit -m/-p/-u, + type -a/-p/-t/-f/-P, suspend -f, kill -n, + test -o optname/s1 == s2/s1 < s2/s1 > s2/-nt/-ot/-ef/-O/-G/-S + bash reads ~/.bashrc for interactive shells, $ENV for non-interactive + bash restricted shell mode is more extensive + bash allows functions and variables with the same name + brace expansion + tilde expansion + arithmetic expansion with $((...)) and `let' builtin + the `[[...]]' extended conditional command + process substitution + aliases and alias/unalias builtins + local variables in functions and `local' builtin + readline and command-line editing with programmable completion + command history and history/fc builtins + csh-like history expansion + other new bash builtins: bind, command, compgen, complete, builtin, + declare/typeset, dirs, enable, fc, help, + history, logout, popd, pushd, disown, shopt, + printf + exported functions + filename generation when using output redirection (command >a*) + POSIX.2-style globbing character classes + POSIX.2-style globbing equivalence classes + POSIX.2-style globbing collating symbols + egrep-like extended pattern matching operators + case-insensitive pattern matching and globbing + variable assignments preceding commands affect only that command, + even for builtins and functions + posix mode + redirection to /dev/fd/N, /dev/stdin, /dev/stdout, /dev/stderr, + /dev/tcp/host/port, /dev/udp/host/port + +Things sh has that bash does not: + uses variable SHACCT to do shell accounting + includes `stop' builtin (bash can use alias stop='kill -s STOP') + `newgrp' builtin + turns on job control if called as `jsh' + $TIMEOUT (like bash $TMOUT) + `^' is a synonym for `|' + new SVR4.2 sh builtins: mldmode, priv + +Implementation differences: + redirection to/from compound commands causes sh to create a subshell + bash does not allow unbalanced quotes; sh silently inserts them at EOF + bash does not mess with signal 11 + sh sets (euid, egid) to (uid, gid) if -p not supplied and uid < 100 + bash splits only the results of expansions on IFS, using POSIX.2 + field splitting rules; sh splits all words on IFS + sh does not allow MAILCHECK to be unset (?) + sh does not allow traps on SIGALRM or SIGCHLD + bash allows multiple option arguments when invoked (e.g. -x -v); + sh allows only a single option argument (`sh -x -v' attempts + to open a file named `-v', and, on SunOS 4.1.4, dumps core. + On Solaris 2.4 and earlier versions, sh goes into an infinite + loop.) + sh exits a script if any builtin fails; bash exits only if one of + the POSIX.2 `special' builtins fails + +C2) How does bash differ from the Korn shell, version ksh88? + +Things bash has or uses that ksh88 does not: + long invocation options + [-+]O invocation option + -l invocation option + `!' reserved word + arithmetic for command: for ((expr1 ; expr2; expr3 )); do list; done + arithmetic in largest machine-supported size (intmax_t) + posix mode and posix conformance + command hashing + tilde expansion for assignment statements that look like $PATH + process substitution with named pipes if /dev/fd is not available + the ${!param} indirect parameter expansion operator + the ${!param*} prefix expansion operator + the ${param:offset[:length]} parameter substring operator + the ${param/pat[/string]} parameter pattern substitution operator + variables: BASH, BASH_VERSION, BASH_VERSINFO, UID, EUID, SHLVL, + TIMEFORMAT, HISTCMD, HOSTTYPE, OSTYPE, MACHTYPE, + HISTFILESIZE, HISTIGNORE, HISTCONTROL, PROMPT_COMMAND, + IGNOREEOF, FIGNORE, INPUTRC, HOSTFILE, DIRSTACK, + PIPESTATUS, HOSTNAME, OPTERR, SHELLOPTS, GLOBIGNORE, + GROUPS, FUNCNAME, histchars, auto_resume + prompt expansion with backslash escapes and command substitution + redirection: &> (stdout and stderr), <<<, [n]<&word-, [n]>&word- + more extensive and extensible editing and programmable completion + builtins: bind, builtin, command, declare, dirs, echo -e/-E, enable, + exec -l/-c/-a, fc -s, export -n/-f/-p, hash, help, history, + jobs -x/-r/-s, kill -s/-n/-l, local, logout, popd, pushd, + read -e/-p/-a/-t/-n/-d/-s, readonly -a/-n/-f/-p, + set -o braceexpand/-o histexpand/-o interactive-comments/ + -o notify/-o physical/-o posix/-o hashall/-o onecmd/ + -h/-B/-C/-b/-H/-P, set +o, suspend, trap -l, type, + typeset -a/-F/-p, ulimit -u, umask -S, alias -p, shopt, + disown, printf, complete, compgen + `!' csh-style history expansion + POSIX.2-style globbing character classes + POSIX.2-style globbing equivalence classes + POSIX.2-style globbing collating symbols + egrep-like extended pattern matching operators + case-insensitive pattern matching and globbing + `**' arithmetic operator to do exponentiation + redirection to /dev/fd/N, /dev/stdin, /dev/stdout, /dev/stderr + arrays of unlimited size + TMOUT is default timeout for `read' and `select' + +Things ksh88 has or uses that bash does not: + tracked aliases (alias -t) + variables: ERRNO, FPATH, EDITOR, VISUAL + co-processes (|&, >&p, <&p) + weirdly-scoped functions + typeset +f to list all function names without definitions + text of command history kept in a file, not memory + builtins: alias -x, cd old new, fc -e -, newgrp, print, + read -p/-s/var?prompt, set -A/-o gmacs/ + -o bgnice/-o markdirs/-o nolog/-o trackall/-o viraw/-s, + typeset -H/-L/-R/-Z/-A/-ft/-fu/-fx/-l/-u/-t, whence + using environment to pass attributes of exported variables + arithmetic evaluation done on arguments to some builtins + reads .profile from $PWD when invoked as login shell + +Implementation differences: + ksh runs last command of a pipeline in parent shell context + bash has brace expansion by default (ksh88 compile-time option) + bash has fixed startup file for all interactive shells; ksh reads $ENV + bash has exported functions + bash command search finds functions before builtins + bash waits for all commands in pipeline to exit before returning status + emacs-mode editing has some slightly different key bindings + +C3) Which new features in ksh-93 are not in bash, and which are? + +New things in ksh-93 not in bash-2.05b: + associative arrays + floating point arithmetic and variables + math library functions + ${!name[sub]} name of subscript for associative array + `.' is allowed in variable names to create a hierarchical namespace + more extensive compound assignment syntax + discipline functions + `sleep' and `getconf' builtins (bash has loadable versions) + typeset -n and `nameref' variables + KEYBD trap + variables: .sh.edchar, .sh.edmode, .sh.edcol, .sh.edtext, .sh.version, + .sh.name, .sh.subscript, .sh.value, .sh.match, HISTEDIT + backreferences in pattern matching (\N) + `&' operator in pattern lists for matching + print -f (bash uses printf) + `fc' has been renamed to `hist' + `.' can execute shell functions + exit statuses between 0 and 255 + set -o pipefail + `+=' variable assignment operator + FPATH and PATH mixing + getopts -a + -I invocation option + DEBUG trap now executed before each simple command, instead of after + printf %H, %P, %T, %Z modifiers, output base for %d + lexical scoping for local variables in `ksh' functions + no scoping for local variables in `POSIX' functions + +New things in ksh-93 present in bash-2.05b: + [n]<&word- and [n]>&word- redirections (combination dup and close) + for (( expr1; expr2; expr3 )) ; do list; done - arithmetic for command + ?:, ++, --, `expr1 , expr2' arithmetic operators + expansions: ${!param}, ${param:offset[:len]}, ${param/pat[/str]}, + ${!param*} + compound array assignment + the `!' reserved word + loadable builtins -- but ksh uses `builtin' while bash uses `enable' + `command', `builtin', `disown' builtins + new $'...' and $"..." quoting + FIGNORE (but bash uses GLOBIGNORE), HISTCMD + set -o notify/-C + changes to kill builtin + read -A (bash uses read -a) + read -t/-d + trap -p + exec -c/-a + `.' restores the positional parameters when it completes + POSIX.2 `test' + umask -S + unalias -a + command and arithmetic substitution performed on PS1, PS4, and ENV + command name completion + ENV processed only for interactive shells + +Section D: Why does bash do some things differently than other Unix shells? + +D1) Why does bash run a different version of `command' than + `which command' says it will? + +On many systems, `which' is actually a csh script that assumes +you're running csh. In tcsh, `which' and its cousin `where' +are builtins. On other Unix systems, `which' is a perl script +that uses the PATH environment variable. + +The csh script version reads the csh startup files from your +home directory and uses those to determine which `command' will +be invoked. Since bash doesn't use any of those startup files, +there's a good chance that your bash environment differs from +your csh environment. The bash `type' builtin does everything +`which' does, and will report correct results for the running +shell. If you're really wedded to the name `which', try adding +the following function definition to your .bashrc: + + which() + { + builtin type "$@" + } + +If you're moving from tcsh and would like to bring `where' along +as well, use this function: + + where() + { + builtin type -a "$@" + } + +D2) Why doesn't bash treat brace expansions exactly like csh? + +The only difference between bash and csh brace expansion is that +bash requires a brace expression to contain at least one unquoted +comma if it is to be expanded. Any brace-surrounded word not +containing an unquoted comma is left unchanged by the brace +expansion code. This affords the greatest degree of sh +compatibility. + +Bash, ksh, zsh, and pd-ksh all implement brace expansion this way. + +D3) Why doesn't bash have csh variable modifiers? + +Posix has specified a more powerful, albeit somewhat more cryptic, +mechanism cribbed from ksh, and bash implements it. + +${parameter%word} + Remove smallest suffix pattern. The WORD is expanded to produce + a pattern. It then expands to the value of PARAMETER, with the + smallest portion of the suffix matched by the pattern deleted. + + x=file.c + echo ${x%.c}.o + -->file.o + +${parameter%%word} + + Remove largest suffix pattern. The WORD is expanded to produce + a pattern. It then expands to the value of PARAMETER, with the + largest portion of the suffix matched by the pattern deleted. + + x=posix/src/std + echo ${x%%/*} + -->posix + +${parameter#word} + Remove smallest prefix pattern. The WORD is expanded to produce + a pattern. It then expands to the value of PARAMETER, with the + smallest portion of the prefix matched by the pattern deleted. + + x=$HOME/src/cmd + echo ${x#$HOME} + -->/src/cmd + +${parameter##word} + Remove largest prefix pattern. The WORD is expanded to produce + a pattern. It then expands to the value of PARAMETER, with the + largest portion of the prefix matched by the pattern deleted. + + x=/one/two/three + echo ${x##*/} + -->three + + +Given + a=/a/b/c/d + b=b.xxx + + csh bash result + --- ---- ------ + $a:h ${a%/*} /a/b/c + $a:t ${a##*/} d + $b:r ${b%.*} b + $b:e ${b##*.} xxx + + +D4) How can I make my csh aliases work when I convert to bash? + +Bash uses a different syntax to support aliases than csh does. +The details can be found in the documentation. We have provided +a shell script which does most of the work of conversion for you; +this script can be found in ./examples/misc/aliasconv.sh. Here is +how you use it: + +Start csh in the normal way for you. (e.g., `csh') + +Pipe the output of `alias' through `aliasconv.sh', saving the +results into `bash_aliases': + + alias | bash aliasconv.sh >bash_aliases + +Edit `bash_aliases', carefully reading through any created +functions. You will need to change the names of some csh specific +variables to the bash equivalents. The script converts $cwd to +$PWD, $term to $TERM, $home to $HOME, $user to $USER, and $prompt +to $PS1. You may also have to add quotes to avoid unwanted +expansion. + +For example, the csh alias: + + alias cd 'cd \!*; echo $cwd' + +is converted to the bash function: + + cd () { command cd "$@"; echo $PWD ; } + +The only thing that needs to be done is to quote $PWD: + + cd () { command cd "$@"; echo "$PWD" ; } + +Merge the edited file into your ~/.bashrc. + +There is an additional, more ambitious, script in +examples/misc/cshtobash that attempts to convert your entire csh +environment to its bash equivalent. This script can be run as +simply `cshtobash' to convert your normal interactive +environment, or as `cshtobash ~/.login' to convert your login +environment. + +D5) How can I pipe standard output and standard error from one command to + another, like csh does with `|&'? + +Use + command 2>&1 | command2 + +The key is to remember that piping is performed before redirection, so +file descriptor 1 points to the pipe when it is duplicated onto file +descriptor 2. + +D6) Now that I've converted from ksh to bash, are there equivalents to + ksh features like autoloaded functions and the `whence' command? + +There are features in ksh-88 and ksh-93 that do not have direct bash +equivalents. Most, however, can be emulated with very little trouble. + +ksh-88 feature Bash equivalent +-------------- --------------- +compiled-in aliases set up aliases in .bashrc; some ksh aliases are + bash builtins (hash, history, type) +coprocesses named pipe pairs (one for read, one for write) +typeset +f declare -F +cd, print, whence function substitutes in examples/functions/kshenv +autoloaded functions examples/functions/autoload is the same as typeset -fu +read var?prompt read -p prompt var + +ksh-93 feature Bash equivalent +-------------- --------------- +sleep, getconf Bash has loadable versions in examples/loadables +${.sh.version} $BASH_VERSION +print -f printf +hist alias hist=fc +$HISTEDIT $FCEDIT + +Section E: How can I get bash to do certain things, and why does bash do + things the way it does? + +E1) Why is the bash builtin `test' slightly different from /bin/test? + +The specific example used here is [ ! x -o x ], which is false. + +Bash's builtin `test' implements the Posix.2 spec, which can be +summarized as follows (the wording is due to David Korn): + +Here is the set of rules for processing test arguments. + + 0 Args: False + 1 Arg: True iff argument is not null. + 2 Args: If first arg is !, True iff second argument is null. + If first argument is unary, then true if unary test is true + Otherwise error. + 3 Args: If second argument is a binary operator, do binary test of $1 $3 + If first argument is !, negate two argument test of $2 $3 + If first argument is `(' and third argument is `)', do the + one-argument test of the second argument. + Otherwise error. + 4 Args: If first argument is !, negate three argument test of $2 $3 $4. + Otherwise unspecified + 5 or more Args: unspecified. (Historical shells would use their + current algorithm). + +The operators -a and -o are considered binary operators for the purpose +of the 3 Arg case. + +As you can see, the test becomes (not (x or x)), which is false. + +E2) Why does bash sometimes say `Broken pipe'? + +If a sequence of commands appears in a pipeline, and one of the +reading commands finishes before the writer has finished, the +writer receives a SIGPIPE signal. Many other shells special-case +SIGPIPE as an exit status in the pipeline and do not report it. +For example, in: + + ps -aux | head + +`head' can finish before `ps' writes all of its output, and ps +will try to write on a pipe without a reader. In that case, bash +will print `Broken pipe' to stderr when ps is killed by a +SIGPIPE. + +You can build a version of bash that will not report SIGPIPE errors +by uncommenting the definition of DONT_REPORT_SIGPIPE in the file +config-top.h. + +E3) When I have terminal escape sequences in my prompt, why does bash + wrap lines at the wrong column? + +Readline, the line editing library that bash uses, does not know +that the terminal escape sequences do not take up space on the +screen. The redisplay code assumes, unless told otherwise, that +each character in the prompt is a `printable' character that +takes up one character position on the screen. + +You can use the bash prompt expansion facility (see the PROMPTING +section in the manual page) to tell readline that sequences of +characters in the prompt strings take up no screen space. + +Use the \[ escape to begin a sequence of non-printing characters, +and the \] escape to signal the end of such a sequence. + +E4) If I pipe the output of a command into `read variable', why doesn't + the output show up in $variable when the read command finishes? + +This has to do with the parent-child relationship between Unix +processes. It affects all commands run in pipelines, not just +simple calls to `read'. For example, piping a command's output +into a `while' loop that repeatedly calls `read' will result in +the same behavior. + +Each element of a pipeline runs in a separate process, a child of +the shell running the pipeline. A subprocess cannot affect its +parent's environment. When the `read' command sets the variable +to the input, that variable is set only in the subshell, not the +parent shell. When the subshell exits, the value of the variable +is lost. + +Many pipelines that end with `read variable' can be converted +into command substitutions, which will capture the output of +a specified command. The output can then be assigned to a +variable: + + grep ^gnu /usr/lib/news/active | wc -l | read ngroup + +can be converted into + + ngroup=$(grep ^gnu /usr/lib/news/active | wc -l) + +This does not, unfortunately, work to split the text among +multiple variables, as read does when given multiple variable +arguments. If you need to do this, you can either use the +command substitution above to read the output into a variable +and chop up the variable using the bash pattern removal +expansion operators or use some variant of the following +approach. + +Say /usr/local/bin/ipaddr is the following shell script: + +#! /bin/sh +host `hostname` | awk '/address/ {print $NF}' + +Instead of using + + /usr/local/bin/ipaddr | read A B C D + +to break the local machine's IP address into separate octets, use + + OIFS="$IFS" + IFS=. + set -- $(/usr/local/bin/ipaddr) + IFS="$OIFS" + A="$1" B="$2" C="$3" D="$4" + +Beware, however, that this will change the shell's positional +parameters. If you need them, you should save them before doing +this. + +This is the general approach -- in most cases you will not need to +set $IFS to a different value. + +Some other user-supplied alternatives include: + +read A B C D << HERE + $(IFS=.; echo $(/usr/local/bin/ipaddr)) +HERE + +and, where process substitution is available, + +read A B C D < <(IFS=.; echo $(/usr/local/bin/ipaddr)) + +E5) I have a bunch of shell scripts that use backslash-escaped characters + in arguments to `echo'. Bash doesn't interpret these characters. Why + not, and how can I make it understand them? + +This is the behavior of echo on most Unix System V machines. + +The bash builtin `echo' is modeled after the 9th Edition +Research Unix version of `echo'. It does not interpret +backslash-escaped characters in its argument strings by default; +it requires the use of the -e option to enable the +interpretation. The System V echo provides no way to disable the +special characters; the bash echo has a -E option to disable +them. + +There is a configuration option that will make bash behave like +the System V echo and interpret things like `\t' by default. Run +configure with the --enable-xpg-echo-default option to turn this +on. Be aware that this will cause some of the tests run when you +type `make tests' to fail. + +There is a shell option, `xpg_echo', settable with `shopt', that will +change the behavior of echo at runtime. Enabling this option turns +on expansion of backslash-escape sequences. + +E6) Why doesn't a while or for loop get suspended when I type ^Z? + +This is a consequence of how job control works on Unix. The only +thing that can be suspended is the process group. This is a single +command or pipeline of commands that the shell forks and executes. + +When you run a while or for loop, the only thing that the shell forks +and executes are any commands in the while loop test and commands in +the loop bodies. These, therefore, are the only things that can be +suspended when you type ^Z. + +If you want to be able to stop the entire loop, you need to put it +within parentheses, which will force the loop into a subshell that +may be stopped (and subsequently restarted) as a single unit. + +E7) What about empty for loops in Makefiles? + +It's fairly common to see constructs like this in automatically-generated +Makefiles: + +SUBDIRS = @SUBDIRS@ + + ... + +subdirs-clean: + for d in ${SUBDIRS}; do \ + ( cd $$d && ${MAKE} ${MFLAGS} clean ) \ + done + +When SUBDIRS is empty, this results in a command like this being passed to +bash: + + for d in ; do + ( cd $d && ${MAKE} ${MFLAGS} clean ) + done + +In versions of bash before bash-2.05a, this was a syntax error. If the +reserved word `in' was present, a word must follow it before the semicolon +or newline. The language in the manual page referring to the list of words +being empty referred to the list after it is expanded. These versions of +bash required that there be at least one word following the `in' when the +construct was parsed. + +The idiomatic Makefile solution is something like: + +SUBDIRS = @SUBDIRS@ + +subdirs-clean: + subdirs=$SUBDIRS ; for d in $$subdirs; do \ + ( cd $$d && ${MAKE} ${MFLAGS} clean ) \ + done + +The latest drafts of the updated POSIX standard have changed this: the +word list is no longer required. Bash versions 2.05a and later accept +the new syntax. + +E8) Why does the arithmetic evaluation code complain about `08'? + +The bash arithmetic evaluation code (used for `let', $(()), (()), and in +other places), interprets a leading `0' in numeric constants as denoting +an octal number, and a leading `0x' as denoting hexadecimal. This is +in accordance with the POSIX.2 spec, section 2.9.2.1, which states that +arithmetic constants should be handled as signed long integers as defined +by the ANSI/ISO C standard. + +The POSIX.2 interpretation committee has confirmed this: + +http://www.pasc.org/interps/unofficial/db/p1003.2/pasc-1003.2-173.html + +E9) Why does the pattern matching expression [A-Z]* match files beginning + with every letter except `z'? + +Bash-2.03, Bash-2.05 and later versions honor the current locale setting +when processing ranges within pattern matching bracket expressions ([A-Z]). +This is what POSIX.2 and SUSv3/XPG6 specify. + +The behavior of the matcher in bash-2.05 and later versions depends on the +current LC_COLLATE setting. Setting this variable to `C' or `POSIX' will +result in the traditional behavior ([A-Z] matches all uppercase ASCII +characters). Many other locales, including the en_US locale (the default +on many US versions of Linux) collate the upper and lower case letters like +this: + + AaBb...Zz + +which means that [A-Z] matches every letter except `z'. Others collate like + + aAbBcC...zZ + +which means that [A-Z] matches every letter except `a'. + +The portable way to specify upper case letters is [:upper:] instead of +A-Z; lower case may be specified as [:lower:] instead of a-z. + +Look at the manual pages for setlocale(3), strcoll(3), and, if it is +present, locale(1). If you have locale(1), you can use it to find +your current locale information even if you do not have any of the +LC_ variables set. + +My advice is to put + + export LC_COLLATE=C + +into /etc/profile and inspect any shell scripts run from cron for +constructs like [A-Z]. This will prevent things like + + rm [A-Z]* + +from removing every file in the current directory except those beginning +with `z' and still allow individual users to change the collation order. +Users may put the above command into their own profiles as well, of course. + +E10) Why does `cd //' leave $PWD as `//'? + +POSIX.2, in its description of `cd', says that *three* or more leading +slashes may be replaced with a single slash when canonicalizing the +current working directory. + +This is, I presume, for historical compatibility. Certain versions of +Unix, and early network file systems, used paths of the form +//hostname/path to access `path' on server `hostname'. + +E11) If I resize my xterm while another program is running, why doesn't bash + notice the change? + +This is another issue that deals with job control. + +The kernel maintains a notion of a current terminal process group. Members +of this process group (processes whose process group ID is equal to the +current terminal process group ID) receive terminal-generated signals like +SIGWINCH. (For more details, see the JOB CONTROL section of the bash +man page.) + +If a terminal is resized, the kernel sends SIGWINCH to each member of +the terminal's current process group (the `foreground' process group). + +When bash is running with job control enabled, each pipeline (which may be +a single command) is run in its own process group, different from bash's +process group. This foreground process group receives the SIGWINCH; bash +does not. Bash has no way of knowing that the terminal has been resized. + +There is a `checkwinsize' option, settable with the `shopt' builtin, that +will cause bash to check the window size and adjust its idea of the +terminal's dimensions each time a process stops or exits and returns control +of the terminal to bash. Enable it with `shopt -s checkwinsize'. + +Section F: Things to watch out for on certain Unix versions + +F1) Why can't I use command line editing in my `cmdtool'? + +The problem is `cmdtool' and bash fighting over the input. When +scrolling is enabled in a cmdtool window, cmdtool puts the tty in +`raw mode' to permit command-line editing using the mouse for +applications that cannot do it themselves. As a result, bash and +cmdtool each try to read keyboard input immediately, with neither +getting enough of it to be useful. + +This mode also causes cmdtool to not implement many of the +terminal functions and control sequences appearing in the +`sun-cmd' termcap entry. For a more complete explanation, see +that file examples/suncmd.termcap in the bash distribution. + +`xterm' is a better choice, and gets along with bash much more +smoothly. + +If you must use cmdtool, you can use the termcap description in +examples/suncmd.termcap. Set the TERMCAP variable to the terminal +description contained in that file, i.e. + +TERMCAP='Mu|sun-cmd:am:bs:km:pt:li#34:co#80:cl=^L:ce=\E[K:cd=\E[J:rs=\E[s:' + +Then export TERMCAP and start a new cmdtool window from that shell. +The bash command-line editing should behave better in the new +cmdtool. If this works, you can put the assignment to TERMCAP +in your bashrc file. + +F2) I built bash on Solaris 2. Why do globbing expansions and filename + completion chop off the first few characters of each filename? + +This is the consequence of building bash on SunOS 5 and linking +with the libraries in /usr/ucblib, but using the definitions +and structures from files in /usr/include. + +The actual conflict is between the dirent structure in +/usr/include/dirent.h and the struct returned by the version of +`readdir' in libucb.a (a 4.3-BSD style `struct direct'). + +Make sure you've got /usr/ccs/bin ahead of /usr/ucb in your $PATH +when configuring and building bash. This will ensure that you +use /usr/ccs/bin/cc or acc instead of /usr/ucb/cc and that you +link with libc before libucb. + +If you have installed the Sun C compiler, you may also need to +put /usr/ccs/bin and /opt/SUNWspro/bin into your $PATH before +/usr/ucb. + +F3) Why does bash dump core after I interrupt username completion or + `~user' tilde expansion on a machine running NIS? + +This is a famous and long-standing bug in the SunOS YP (sorry, NIS) +client library, which is part of libc. + +The YP library code keeps static state -- a pointer into the data +returned from the server. When YP initializes itself (setpwent), +it looks at this pointer and calls free on it if it's non-null. +So far, so good. + +If one of the YP functions is interrupted during getpwent (the +exact function is interpretwithsave()), and returns NULL, the +pointer is freed without being reset to NULL, and the function +returns. The next time getpwent is called, it sees that this +pointer is non-null, calls free, and the bash free() blows up +because it's being asked to free freed memory. + +The traditional Unix mallocs allow memory to be freed multiple +times; that's probably why this has never been fixed. You can +run configure with the `--without-gnu-malloc' option to use +the C library malloc and avoid the problem. + +F4) I'm running SVR4.2. Why is the line erased every time I type `@'? + +The `@' character is the default `line kill' character in most +versions of System V, including SVR4.2. You can change this +character to whatever you want using `stty'. For example, to +change the line kill character to control-u, type + + stty kill ^U + +where the `^' and `U' can be two separate characters. + +F5) Why does bash report syntax errors when my C News scripts use a + redirection before a subshell command? + +The actual command in question is something like + + < file ( command ) + +According to the grammar given in the POSIX.2 standard, this construct +is, in fact, a syntax error. Redirections may only precede `simple +commands'. A subshell construct such as the above is one of the shell's +`compound commands'. A redirection may only follow a compound command. + +This affects the mechanical transformation of commands that use `cat' +to pipe a file into a command (a favorite Useless-Use-Of-Cat topic on +comp.unix.shell). While most commands of the form + + cat file | command + +can be converted to `< file command', shell control structures such as +loops and subshells require `command < file'. + +The file CWRU/sh-redir-hack in the bash-2.05a distribution is an +(unofficial) patch to parse.y that will modify the grammar to +support this construct. It will not apply with `patch'; you must +modify parse.y by hand. Note that if you apply this, you must +recompile with -DREDIRECTION_HACK. This introduces a large +number of reduce/reduce conflicts into the shell grammar. + +F6) Why can't I use vi-mode editing on Red Hat Linux 6.1? + +The short answer is that Red Hat screwed up. + +The long answer is that they shipped an /etc/inputrc that only works +for emacs mode editing, and then screwed all the vi users by setting +INPUTRC to /etc/inputrc in /etc/profile. + +The short fix is to do one of the following: remove or rename +/etc/inputrc, set INPUTRC=~/.inputrc in ~/.bashrc (or .bash_profile, +but make sure you export it if you do), remove the assignment to +INPUTRC from /etc/profile, add + + set keymap emacs + +to the beginning of /etc/inputrc, or bracket the key bindings in +/etc/inputrc with these lines + + $if mode=emacs + [...] + $endif + +F7) Why do bash-2.05a and bash-2.05b fail to compile `printf.def' on + HP/UX 11.x? + +HP/UX's support for long double is imperfect at best. + +GCC will support it without problems, but the HP C library functions +like strtold(3) and printf(3) don't actually work with long doubles. +HP implemented a `long_double' type as a 4-element array of 32-bit +ints, and that is what the library functions use. The ANSI C +`long double' type is a 128-bit floating point scalar. + +The easiest fix, until HP fixes things up, is to edit the generated +config.h and #undef the HAVE_LONG_DOUBLE line. After doing that, +the compilation should complete successfully. + +Section G: How can I get bash to do certain common things? + +G1) How can I get bash to read and display eight-bit characters? + +This is a process requiring several steps. + +First, you must ensure that the `physical' data path is a full eight +bits. For xterms, for example, the `vt100' resources `eightBitInput' +and `eightBitOutput' should be set to `true'. + +Once you have set up an eight-bit path, you must tell the kernel and +tty driver to leave the eighth bit of characters alone when processing +keyboard input. Use `stty' to do this: + + stty cs8 -istrip -parenb + +For old BSD-style systems, you can use + + stty pass8 + +You may also need + + stty even odd + +Finally, you need to tell readline that you will be inputting and +displaying eight-bit characters. You use readline variables to do +this. These variables can be set in your .inputrc or using the bash +`bind' builtin. Here's an example using `bind': + + bash$ bind 'set convert-meta off' + bash$ bind 'set meta-flag on' + bash$ bind 'set output-meta on' + +The `set' commands between the single quotes may also be placed +in ~/.inputrc. + +G2) How do I write a function `x' to replace builtin command `x', but + still invoke the command from within the function? + +This is why the `command' and `builtin' builtins exist. The +`command' builtin executes the command supplied as its first +argument, skipping over any function defined with that name. The +`builtin' builtin executes the builtin command given as its first +argument directly. + +For example, to write a function to replace `cd' that writes the +hostname and current directory to an xterm title bar, use +something like the following: + + cd() + { + builtin cd "$@" && xtitle "$HOST: $PWD" + } + +This could also be written using `command' instead of `builtin'; +the version above is marginally more efficient. + +G3) How can I find the value of a shell variable whose name is the value + of another shell variable? + +Versions of Bash newer than Bash-2.0 support this directly. You can use + + ${!var} + +For example, the following sequence of commands will echo `z': + + var1=var2 + var2=z + echo ${!var1} + +For sh compatibility, use the `eval' builtin. The important +thing to remember is that `eval' expands the arguments you give +it again, so you need to quote the parts of the arguments that +you want `eval' to act on. + +For example, this expression prints the value of the last positional +parameter: + + eval echo \"\$\{$#\}\" + +The expansion of the quoted portions of this expression will be +deferred until `eval' runs, while the `$#' will be expanded +before `eval' is executed. In versions of bash later than bash-2.0, + + echo ${!#} + +does the same thing. + +This is not the same thing as ksh93 `nameref' variables, though the syntax +is similar. I may add namerefs in a future bash version. + +G4) How can I make the bash `time' reserved word print timing output that + looks like the output from my system's /usr/bin/time? + +The bash command timing code looks for a variable `TIMEFORMAT' and +uses its value as a format string to decide how to display the +timing statistics. + +The value of TIMEFORMAT is a string with `%' escapes expanded in a +fashion similar in spirit to printf(3). The manual page explains +the meanings of the escape sequences in the format string. + +If TIMEFORMAT is not set, bash acts as if the following assignment had +been performed: + + TIMEFORMAT=$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS' + +The POSIX.2 default time format (used by `time -p command') is + + TIMEFORMAT=$'real %2R\nuser %2U\nsys %2S' + +The BSD /usr/bin/time format can be emulated with: + + TIMEFORMAT=$'\t%1R real\t%1U user\t%1S sys' + +The System V /usr/bin/time format can be emulated with: + + TIMEFORMAT=$'\nreal\t%1R\nuser\t%1U\nsys\t%1S' + +The ksh format can be emulated with: + + TIMEFORMAT=$'\nreal\t%2lR\nuser\t%2lU\nsys\t%2lS' + +G5) How do I get the current directory into my prompt? + +Bash provides a number of backslash-escape sequences which are expanded +when the prompt string (PS1 or PS2) is displayed. The full list is in +the manual page. + +The \w expansion gives the full pathname of the current directory, with +a tilde (`~') substituted for the current value of $HOME. The \W +expansion gives the basename of the current directory. To put the full +pathname of the current directory into the path without any tilde +subsitution, use $PWD. Here are some examples: + + PS1='\w$ ' # current directory with tilde + PS1='\W$ ' # basename of current directory + PS1='$PWD$ ' # full pathname of current directory + +The single quotes are important in the final example to prevent $PWD from +being expanded when the assignment to PS1 is performed. + +G6) How can I rename "*.foo" to "*.bar"? + +Use the pattern removal functionality described in D3. The following `for' +loop will do the trick: + + for f in *.foo; do + mv $f ${f%foo}bar + done + +G7) How can I translate a filename from uppercase to lowercase? + +The script examples/functions/lowercase, originally written by John DuBois, +will do the trick. The converse is left as an exercise. + +G8) How can I write a filename expansion (globbing) pattern that will match + all files in the current directory except "." and ".."? + +You must have set the `extglob' shell option using `shopt -s extglob' to use +this: + + echo .!(.|) * + +A solution that works without extended globbing is given in the Unix Shell +FAQ, posted periodically to comp.unix.shell. + +Section H: Where do I go from here? + +H1) How do I report bugs in bash, and where should I look for fixes and + advice? + +Use the `bashbug' script to report bugs. It is built and +installed at the same time as bash. It provides a standard +template for reporting a problem and automatically includes +information about your configuration and build environment. + +`bashbug' sends its reports to bug-bash@gnu.org, which +is a large mailing list gatewayed to the usenet newsgroup gnu.bash.bug. + +Bug fixes, answers to questions, and announcements of new releases +are all posted to gnu.bash.bug. Discussions concerning bash features +and problems also take place there. + +To reach the bash maintainers directly, send mail to +bash-maintainers@gnu.org. + +H2) What kind of bash documentation is there? + +First, look in the doc directory in the bash distribution. It should +contain at least the following files: + +bash.1 an extensive, thorough Unix-style manual page +builtins.1 a manual page covering just bash builtin commands +bashref.texi a reference manual in GNU tex`info format +bashref.info an info version of the reference manual +FAQ this file +article.ms text of an article written for The Linux Journal +readline.3 a man page describing readline + +Postscript, HTML, and ASCII files created from the above source are +available in the documentation distribution. + +There is additional documentation available for anonymous FTP from host +ftp.cwru.edu in the `pub/bash' directory. + +Cameron Newham and Bill Rosenblatt have written a book on bash, published +by O'Reilly and Associates. The book is based on Bill Rosenblatt's Korn +Shell book. The title is ``Learning the Bash Shell'', and the ISBN number +is 1-56592-147-X. Look for it in fine bookstores near you. This book +covers bash-1.14, but has an appendix describing some of the new features +in bash-2.0. + +A second edition of this book is available, published in January, 1998. +The ISBN number is 1-56592-347-2. Look for it in the same fine bookstores +or on the web. + +The GNU Bash Reference Manual has been published as a printed book by +Network Theory Ltd (Paperback, ISBN: 0-9541617-7-7, Feb 2003). It covers +bash-2.0 and is available from most online bookstores (see +http://www.network-theory.co.uk/bash/manual/ for details). The publisher +will donate $1 to the Free Software Foundation for each copy sold. + +H3) What's coming in future versions? + +These are features I hope to include in a future version of bash. + +a better bash debugger (a minimally-tested version is included with bash-2.05b) +associative arrays +co-processes, but with a new-style syntax that looks like function declaration + +H4) What's on the bash `wish list' for future versions? + +These are features that may or may not appear in a future version of bash. + +breaking some of the shell functionality into embeddable libraries +a module system like zsh's, using dynamic loading like builtins +better internationalization using GNU `gettext' +date-stamped command history +a bash programmer's guide with a chapter on creating loadable builtins +a better loadable interface to perl with access to the shell builtins and + variables (contributions gratefully accepted) +ksh93-like `nameref' variables +ksh93-like `+=' variable assignment operator +ksh93-like `xx.yy' variables (including some of the .sh.* variables) and + associated disipline functions +Some of the new ksh93 pattern matching operators, like backreferencing + +H5) When will the next release appear? + +The next version will appear sometime in 2002. Never make predictions. + + +This document is Copyright 1995-2003 by Chester Ramey. + +Permission is hereby granted, without written agreement and +without license or royalty fees, to use, copy, and distribute +this document for any purpose, provided that the above copyright +notice appears in all copies of this document and that the +contents of this document remain unaltered. diff --git a/doc/aosa-bash.pdf.old b/doc/aosa-bash.pdf.old new file mode 100644 index 0000000000000000000000000000000000000000..006a767769451694f5f25a9dfdb18282067d982b GIT binary patch literal 153472 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

t#LjeI_ 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

I(G<`;WSlMQteZ|h!? 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 0 && sourcenest >= sourcenest_max) + { + internal_error (_("%s: maximum source nesting level exceeded (%d)"), this_command_name, sourcenest); + sourcenest = 0; + jump_to_top_level (DISCARD); + } + unwind_protect_int (sourcenest); + /* The test for subshell == 0 above doesn't make a difference */ + sourcenest++; /* execute_subshell_builtin_or_function sets this to 0 */ + } + /* `return' does a longjmp() back to a saved environment in execute_function. If a variable assignment list preceded the command, and the shell is @@ -4698,6 +4714,8 @@ execute_subshell_builtin_or_function (words, redirects, builtin, var, login_shell = interactive = 0; if (builtin == eval_builtin) evalnest = 0; + else if (builtin == source_builtin) + sourcenest = 0; if (async) subshell_environment |= SUBSHELL_ASYNC; @@ -5222,7 +5240,7 @@ initialize_subshell () parse_and_execute_level = 0; /* nothing left to restore it */ /* We're no longer inside a shell function. */ - variable_context = return_catch_flag = funcnest = evalnest = 0; + variable_context = return_catch_flag = funcnest = evalnest = sourcenest = 0; executing_list = 0; /* XXX */ diff --git a/lib/readline/doc/Makefile.old b/lib/readline/doc/Makefile.old new file mode 100644 index 00000000..58d4dd76 --- /dev/null +++ b/lib/readline/doc/Makefile.old @@ -0,0 +1,76 @@ +# This makefile for Readline library documentation is in -*- text -*- mode. +# Emacs likes it that way. +RM = rm -f + +MAKEINFO = makeinfo +TEXI2DVI = texi2dvi +TEXI2HTML = texi2html +QUIETPS = #set this to -q to shut up dvips +DVIPS = dvips -D 300 $(QUIETPS) -o $@ # tricky + +INSTALL_DATA = cp +infodir = /usr/local/info + +RLSRC = rlman.texinfo rluser.texinfo rltech.texinfo +HISTSRC = hist.texinfo hsuser.texinfo hstech.texinfo + +DVIOBJ = readline.dvi history.dvi +INFOOBJ = readline.info history.info +PSOBJ = readline.ps history.ps +HTMLOBJ = readline.html history.html + +all: info dvi html ps +nodvi: info html + +readline.dvi: $(RLSRC) + $(TEXI2DVI) rlman.texinfo + mv rlman.dvi readline.dvi + +readline.info: $(RLSRC) + $(MAKEINFO) --no-split -o $@ rlman.texinfo + +history.dvi: ${HISTSRC} + $(TEXI2DVI) hist.texinfo + mv hist.dvi history.dvi + +history.info: ${HISTSRC} + $(MAKEINFO) --no-split -o $@ hist.texinfo + +readline.ps: readline.dvi + $(RM) $@ + $(DVIPS) readline.dvi + +history.ps: history.dvi + $(RM) $@ + $(DVIPS) history.dvi + +readline.html: ${RLSRC} + $(TEXI2HTML) rlman.texinfo + sed -e 's:rlman.html:readline.html:' -e 's:rlman_toc.html:readline_toc.html:' rlman.html > readline.html + sed -e 's:rlman.html:readline.html:' -e 's:rlman_toc.html:readline_toc.html:' rlman_toc.html > readline_toc.html + $(RM) rlman.html rlman_toc.html + +history.html: ${HISTSRC} + $(TEXI2HTML) hist.texinfo + sed -e 's:hist.html:history.html:' -e 's:hist_toc.html:history_toc.html:' hist.html > history.html + sed -e 's:hist.html:history.html:' -e 's:hist_toc.html:history_toc.html:' hist_toc.html > history_toc.html + $(RM) hist.html hist_toc.html + +info: $(INFOOBJ) +dvi: $(DVIOBJ) +ps: $(PSOBJ) +html: $(HTMLOBJ) + +clean: + $(RM) *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps *.pgs \ + *.fns *.kys *.tps *.vrs *.o core + +distclean: clean +mostlyclean: clean + +maintainer-clean: clean + $(RM) *.dvi *.info *.info-* *.ps *.html + +install: info + ${INSTALL_DATA} readline.info $(infodir)/readline.info + ${INSTALL_DATA} history.info $(infodir)/history.info diff --git a/lib/readline/history.c b/lib/readline/history.c index 1181e7cc..ece68fee 100644 --- a/lib/readline/history.c +++ b/lib/readline/history.c @@ -48,6 +48,9 @@ #include "xmalloc.h" +/* How big to make the_history when we first allocate it. */ +#define DEFAULT_HISTORY_INITIAL_SIZE 502 + /* The number of slots to increase the_history by. */ #define DEFAULT_HISTORY_GROW_SIZE 50 @@ -289,7 +292,10 @@ add_history (string) { if (history_size == 0) { - history_size = DEFAULT_HISTORY_GROW_SIZE; + if (history_stifled && history_max_entries > 0) + history_size = history_max_entries + 2; + else + history_size = DEFAULT_HISTORY_INITIAL_SIZE; the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *)); history_length = 1; } diff --git a/pcomplete.c b/pcomplete.c index d4b31a66..53866b31 100644 --- a/pcomplete.c +++ b/pcomplete.c @@ -300,7 +300,11 @@ filter_stringlist (sl, filterpat, text) npat = shouldexp_filterpat (filterpat) ? preproc_filterpat (filterpat, text) : filterpat; +#if defined (EXTENDED_GLOB) + not = (npat[0] == '!' && (extended_glob == 0 || npat[1] != '(')); /*)*/ +#else not = (npat[0] == '!'); +#endif t = not ? npat + 1 : npat; ret = strlist_create (sl->list_size); diff --git a/subst.h b/subst.h index 6a4110e3..d8103b79 100644 --- a/subst.h +++ b/subst.h @@ -47,6 +47,7 @@ #define ASS_MKASSOC 0x0004 #define ASS_MKGLOBAL 0x0008 /* force global assignment */ #define ASS_NAMEREF 0x0010 /* assigning to nameref variable */ +#define ASS_FROMREF 0x0020 /* assigning from value of nameref variable */ /* Flags for the string extraction functions. */ #define SX_NOALLOC 0x0001 /* just skip; don't return substring */ diff --git a/subst.h~ b/subst.h~ new file mode 100644 index 00000000..6a4110e3 --- /dev/null +++ b/subst.h~ @@ -0,0 +1,320 @@ +/* subst.h -- Names of externally visible functions in subst.c. */ + +/* Copyright (C) 1993-2010 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + 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 3 of the License, or + (at your option) any later version. + + Bash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bash. If not, see . +*/ + +#if !defined (_SUBST_H_) +#define _SUBST_H_ + +#include "stdc.h" + +/* Constants which specify how to handle backslashes and quoting in + expand_word_internal (). Q_DOUBLE_QUOTES means to use the function + slashify_in_quotes () to decide whether the backslash should be + retained. Q_HERE_DOCUMENT means slashify_in_here_document () to + decide whether to retain the backslash. Q_KEEP_BACKSLASH means + to unconditionally retain the backslash. Q_PATQUOTE means that we're + expanding a pattern ${var%#[#%]pattern} in an expansion surrounded + by double quotes. Q_DOLBRACE means we are expanding a ${...} word, so + backslashes should also escape { and } and be removed. */ +#define Q_DOUBLE_QUOTES 0x01 +#define Q_HERE_DOCUMENT 0x02 +#define Q_KEEP_BACKSLASH 0x04 +#define Q_PATQUOTE 0x08 +#define Q_QUOTED 0x10 +#define Q_ADDEDQUOTES 0x20 +#define Q_QUOTEDNULL 0x40 +#define Q_DOLBRACE 0x80 + +/* Flag values controlling how assignment statements are treated. */ +#define ASS_APPEND 0x0001 +#define ASS_MKLOCAL 0x0002 +#define ASS_MKASSOC 0x0004 +#define ASS_MKGLOBAL 0x0008 /* force global assignment */ +#define ASS_NAMEREF 0x0010 /* assigning to nameref variable */ + +/* Flags for the string extraction functions. */ +#define SX_NOALLOC 0x0001 /* just skip; don't return substring */ +#define SX_VARNAME 0x0002 /* variable name; for string_extract () */ +#define SX_REQMATCH 0x0004 /* closing/matching delimiter required */ +#define SX_COMMAND 0x0008 /* extracting a shell script/command */ +#define SX_NOCTLESC 0x0010 /* don't honor CTLESC quoting */ +#define SX_NOESCCTLNUL 0x0020 /* don't let CTLESC quote CTLNUL */ +#define SX_NOLONGJMP 0x0040 /* don't longjmp on fatal error */ +#define SX_ARITHSUB 0x0080 /* extracting $(( ... )) (currently unused) */ +#define SX_POSIXEXP 0x0100 /* extracting new Posix pattern removal expansions in extract_dollar_brace_string */ +#define SX_WORD 0x0200 /* extracting word in ${param op word} */ + +/* Remove backslashes which are quoting backquotes from STRING. Modifies + STRING, and returns a pointer to it. */ +extern char * de_backslash __P((char *)); + +/* Replace instances of \! in a string with !. */ +extern void unquote_bang __P((char *)); + +/* Extract the $( construct in STRING, and return a new string. + Start extracting at (SINDEX) as if we had just seen "$(". + Make (SINDEX) get the position just after the matching ")". + XFLAGS is additional flags to pass to other extraction functions, */ +extern char *extract_command_subst __P((char *, int *, int)); + +/* Extract the $[ construct in STRING, and return a new string. + Start extracting at (SINDEX) as if we had just seen "$[". + Make (SINDEX) get the position just after the matching "]". */ +extern char *extract_arithmetic_subst __P((char *, int *)); + +#if defined (PROCESS_SUBSTITUTION) +/* Extract the <( or >( construct in STRING, and return a new string. + Start extracting at (SINDEX) as if we had just seen "<(". + Make (SINDEX) get the position just after the matching ")". */ +extern char *extract_process_subst __P((char *, char *, int *, int)); +#endif /* PROCESS_SUBSTITUTION */ + +/* Extract the name of the variable to bind to from the assignment string. */ +extern char *assignment_name __P((char *)); + +/* Return a single string of all the words present in LIST, separating + each word with SEP. */ +extern char *string_list_internal __P((WORD_LIST *, char *)); + +/* Return a single string of all the words present in LIST, separating + each word with a space. */ +extern char *string_list __P((WORD_LIST *)); + +/* Turn $* into a single string, obeying POSIX rules. */ +extern char *string_list_dollar_star __P((WORD_LIST *)); + +/* Expand $@ into a single string, obeying POSIX rules. */ +extern char *string_list_dollar_at __P((WORD_LIST *, int)); + +/* Turn the positional paramters into a string, understanding quoting and + the various subtleties of using the first character of $IFS as the + separator. Calls string_list_dollar_at, string_list_dollar_star, and + string_list as appropriate. */ +extern char *string_list_pos_params __P((int, WORD_LIST *, int)); + +/* Perform quoted null character removal on each element of LIST. + This modifies LIST. */ +extern void word_list_remove_quoted_nulls __P((WORD_LIST *)); + +/* This performs word splitting and quoted null character removal on + STRING. */ +extern WORD_LIST *list_string __P((char *, char *, int)); + +extern char *ifs_firstchar __P((int *)); +extern char *get_word_from_string __P((char **, char *, char **)); +extern char *strip_trailing_ifs_whitespace __P((char *, char *, int)); + +/* Given STRING, an assignment string, get the value of the right side + of the `=', and bind it to the left side. If EXPAND is true, then + perform tilde expansion, parameter expansion, command substitution, + and arithmetic expansion on the right-hand side. Do not perform word + splitting on the result of expansion. */ +extern int do_assignment __P((char *)); +extern int do_assignment_no_expand __P((char *)); +extern int do_word_assignment __P((WORD_DESC *, int)); + +/* Append SOURCE to TARGET at INDEX. SIZE is the current amount + of space allocated to TARGET. SOURCE can be NULL, in which + case nothing happens. Gets rid of SOURCE by free ()ing it. + Returns TARGET in case the location has changed. */ +extern char *sub_append_string __P((char *, char *, int *, int *)); + +/* Append the textual representation of NUMBER to TARGET. + INDEX and SIZE are as in SUB_APPEND_STRING. */ +extern char *sub_append_number __P((intmax_t, char *, int *, int *)); + +/* Return the word list that corresponds to `$*'. */ +extern WORD_LIST *list_rest_of_args __P((void)); + +/* Make a single large string out of the dollar digit variables, + and the rest_of_args. If DOLLAR_STAR is 1, then obey the special + case of "$*" with respect to IFS. */ +extern char *string_rest_of_args __P((int)); + +extern int number_of_args __P((void)); + +/* Expand STRING by performing parameter expansion, command substitution, + and arithmetic expansion. Dequote the resulting WORD_LIST before + returning it, but do not perform word splitting. The call to + remove_quoted_nulls () is made here because word splitting normally + takes care of quote removal. */ +extern WORD_LIST *expand_string_unsplit __P((char *, int)); + +/* Expand the rhs of an assignment statement. */ +extern WORD_LIST *expand_string_assignment __P((char *, int)); + +/* Expand a prompt string. */ +extern WORD_LIST *expand_prompt_string __P((char *, int, int)); + +/* Expand STRING just as if you were expanding a word. This also returns + a list of words. Note that filename globbing is *NOT* done for word + or string expansion, just when the shell is expanding a command. This + does parameter expansion, command substitution, arithmetic expansion, + and word splitting. Dequote the resultant WORD_LIST before returning. */ +extern WORD_LIST *expand_string __P((char *, int)); + +/* Convenience functions that expand strings to strings, taking care of + converting the WORD_LIST * returned by the expand_string* functions + to a string and deallocating the WORD_LIST *. */ +extern char *expand_string_to_string __P((char *, int)); +extern char *expand_string_unsplit_to_string __P((char *, int)); +extern char *expand_assignment_string_to_string __P((char *, int)); + +/* Expand an arithmetic expression string */ +extern char *expand_arith_string __P((char *, int)); + +/* De-quote quoted characters in STRING. */ +extern char *dequote_string __P((char *)); + +/* De-quote CTLESC-escaped CTLESC or CTLNUL characters in STRING. */ +extern char *dequote_escapes __P((char *)); + +/* De-quote quoted characters in each word in LIST. */ +extern WORD_LIST *dequote_list __P((WORD_LIST *)); + +/* Expand WORD, performing word splitting on the result. This does + parameter expansion, command substitution, arithmetic expansion, + word splitting, and quote removal. */ +extern WORD_LIST *expand_word __P((WORD_DESC *, int)); + +/* Expand WORD, but do not perform word splitting on the result. This + does parameter expansion, command substitution, arithmetic expansion, + and quote removal. */ +extern WORD_LIST *expand_word_unsplit __P((WORD_DESC *, int)); +extern WORD_LIST *expand_word_leave_quoted __P((WORD_DESC *, int)); + +/* Return the value of a positional parameter. This handles values > 10. */ +extern char *get_dollar_var_value __P((intmax_t)); + +/* Quote a string to protect it from word splitting. */ +extern char *quote_string __P((char *)); + +/* Quote escape characters (characters special to interals of expansion) + in a string. */ +extern char *quote_escapes __P((char *)); + +/* And remove such quoted special characters. */ +extern char *remove_quoted_escapes __P((char *)); + +/* Remove CTLNUL characters from STRING unless they are quoted with CTLESC. */ +extern char *remove_quoted_nulls __P((char *)); + +/* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the + backslash quoting rules for within double quotes. */ +extern char *string_quote_removal __P((char *, int)); + +/* Perform quote removal on word WORD. This allocates and returns a new + WORD_DESC *. */ +extern WORD_DESC *word_quote_removal __P((WORD_DESC *, int)); + +/* Perform quote removal on all words in LIST. If QUOTED is non-zero, + the members of the list are treated as if they are surrounded by + double quotes. Return a new list, or NULL if LIST is NULL. */ +extern WORD_LIST *word_list_quote_removal __P((WORD_LIST *, int)); + +/* Called when IFS is changed to maintain some private variables. */ +extern void setifs __P((SHELL_VAR *)); + +/* Return the value of $IFS, or " \t\n" if IFS is unset. */ +extern char *getifs __P((void)); + +/* This splits a single word into a WORD LIST on $IFS, but only if the word + is not quoted. list_string () performs quote removal for us, even if we + don't do any splitting. */ +extern WORD_LIST *word_split __P((WORD_DESC *, char *)); + +/* Take the list of words in LIST and do the various substitutions. Return + a new list of words which is the expanded list, and without things like + variable assignments. */ +extern WORD_LIST *expand_words __P((WORD_LIST *)); + +/* Same as expand_words (), but doesn't hack variable or environment + variables. */ +extern WORD_LIST *expand_words_no_vars __P((WORD_LIST *)); + +/* Perform the `normal shell expansions' on a WORD_LIST. These are + brace expansion, tilde expansion, parameter and variable substitution, + command substitution, arithmetic expansion, and word splitting. */ +extern WORD_LIST *expand_words_shellexp __P((WORD_LIST *)); + +extern WORD_DESC *command_substitute __P((char *, int)); +extern char *pat_subst __P((char *, char *, char *, int)); + +extern int fifos_pending __P((void)); +extern int num_fifos __P((void)); +extern void unlink_fifo_list __P((void)); +extern void unlink_fifo __P((int)); + +extern char *copy_fifo_list __P((int *)); +extern void unlink_new_fifos __P((char *, int)); +extern void close_new_fifos __P((char *, int)); + +extern void clear_fifo_list __P((void)); + +extern WORD_LIST *list_string_with_quotes __P((char *)); + +#if defined (ARRAY_VARS) +extern char *extract_array_assignment_list __P((char *, int *)); +#endif + +#if defined (COND_COMMAND) +extern char *remove_backslashes __P((char *)); +extern char *cond_expand_word __P((WORD_DESC *, int)); +#endif + +/* Flags for skip_to_delim */ +#define SD_NOJMP 0x01 /* don't longjmp on fatal error. */ +#define SD_INVERT 0x02 /* look for chars NOT in passed set */ +#define SD_NOQUOTEDELIM 0x04 /* don't let single or double quotes act as delimiters */ +#define SD_NOSKIPCMD 0x08 /* don't skip over $(, <(, or >( command/process substitution; parse them as commands */ +#define SD_EXTGLOB 0x10 /* skip over extended globbing patterns if appropriate */ +#define SD_IGNOREQUOTE 0x20 /* single and double quotes are not special */ +#define SD_GLOB 0x40 /* skip over glob patterns like bracket expressions */ +#define SD_NOPROCSUB 0x80 /* don't parse process substitutions as commands */ + +extern int skip_to_delim __P((char *, int, char *, int)); + +#if defined (READLINE) +extern int char_is_quoted __P((char *, int)); +extern int unclosed_pair __P((char *, int, char *)); +extern WORD_LIST *split_at_delims __P((char *, int, char *, int, int, int *, int *)); +#endif + +/* Variables used to keep track of the characters in IFS. */ +extern SHELL_VAR *ifs_var; +extern char *ifs_value; +extern unsigned char ifs_cmap[]; + +#if defined (HANDLE_MULTIBYTE) +extern unsigned char ifs_firstc[]; +extern size_t ifs_firstc_len; +#else +extern unsigned char ifs_firstc; +#endif + +/* Evaluates to 1 if C is a character in $IFS. */ +#define isifs(c) (ifs_cmap[(unsigned char)(c)] != 0) + +/* How to determine the quoted state of the character C. */ +#define QUOTED_CHAR(c) ((c) == CTLESC) + +/* Is the first character of STRING a quoted NULL character? */ +#define QUOTED_NULL(string) ((string)[0] == CTLNUL && (string)[1] == '\0') + +#endif /* !_SUBST_H_ */ diff --git a/tests/misc/regress/log.orig b/tests/misc/regress/log.orig new file mode 100644 index 00000000..c1f1e199 --- /dev/null +++ b/tests/misc/regress/log.orig @@ -0,0 +1,50 @@ +:; ./shx + +sh: +<&$fd ok +nlbq Mon Aug 3 02:45:00 EDT 1992 +bang geoff +quote 712824302 +setbq defmsgid=<1992Aug3.024502.6176@host> +bgwait sleep done... wait 6187 + + +bash: +<&$fd ok +nlbq Mon Aug 3 02:45:09 EDT 1992 +bang geoff +quote 712824311 +setbq defmsgid=<1992Aug3.024512.6212@host> +bgwait sleep done... wait 6223 + + +ash: +<&$fd shx1: 4: Syntax error: Bad fd number +nlbq Mon Aug 3 02:45:19 EDT 1992 +bang geoff +quote getdate: `"now"' not a valid date + +setbq defmsgid=<1992Aug3.` echo 024521 +bgwait sleep done... wait 6241 + + +ksh: +<&$fd ok +nlbq ./shx: 6248 Memory fault - core dumped +bang geoff +quote getdate: `"now"' not a valid date + +setbq defmsgid=<1992Aug3.024530.6257@host> +bgwait no such job: 6265 +wait 6265 +sleep done... + +zsh: +<&$fd ok +nlbq Mon Aug 3 02:45:36 EDT 1992 +bang shx3: event not found: /s/ [4] +quote 712824337 +setbq defmsgid=<..6290@host> +bgwait shx7: unmatched " [9] +sleep done... +:; diff --git a/tests/misc/regress/shx.orig b/tests/misc/regress/shx.orig new file mode 100644 index 00000000..4b3bf2b8 --- /dev/null +++ b/tests/misc/regress/shx.orig @@ -0,0 +1,10 @@ +#! /bin/sh +for cmd in sh bash ash ksh zsh +do + echo + echo $cmd: + for demo in shx? + do + $cmd $demo + done +done diff --git a/tests/parser.right b/tests/parser.right new file mode 100644 index 00000000..43d5a8ed --- /dev/null +++ b/tests/parser.right @@ -0,0 +1 @@ +AAA diff --git a/tests/parser.tests b/tests/parser.tests new file mode 100644 index 00000000..12ff88c2 --- /dev/null +++ b/tests/parser.tests @@ -0,0 +1,4 @@ +# catch-all for parsing problems that don't fit anywhere else + +# this has to be in a separate file to get desired EOF behavior +${THIS_SH} ./parser1.sub diff --git a/tests/parser1.sub b/tests/parser1.sub new file mode 100644 index 00000000..50319316 --- /dev/null +++ b/tests/parser1.sub @@ -0,0 +1 @@ +eval "array=(foo bar)" ; echo AAA\ diff --git a/tests/run-parser b/tests/run-parser new file mode 100644 index 00000000..7834c911 --- /dev/null +++ b/tests/run-parser @@ -0,0 +1,2 @@ +${THIS_SH} ./parser.tests > /tmp/xx 2>&1 +diff /tmp/xx parser.right && rm -f /tmp/xx diff --git a/variables.c b/variables.c index 03ff67dc..44859528 100644 --- a/variables.c +++ b/variables.c @@ -2687,6 +2687,7 @@ bind_variable (name, value, flags) SHELL_VAR *v, *nv; VAR_CONTEXT *vc, *nvc; int level; + char *newname; if (shell_variables == 0) create_variable_tables (); @@ -2719,6 +2720,11 @@ bind_variable (name, value, flags) normal. */ if (nameref_cell (nv) == 0) return (bind_variable_internal (nv->name, value, nvc->table, 0, flags)); +#if defined (ARRAY_VARS) + else if (valid_array_reference (nameref_cell (nv))) + return (assign_array_element (nameref_cell (nv), value, flags)); + else +#endif return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags)); } else diff --git a/variables.c~ b/variables.c~ new file mode 100644 index 00000000..44859528 --- /dev/null +++ b/variables.c~ @@ -0,0 +1,5399 @@ +/* variables.c -- Functions for hacking shell variables. */ + +/* Copyright (C) 1987-2013 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + 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 3 of the License, or + (at your option) any later version. + + Bash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bash. If not, see . +*/ + +#include "config.h" + +#include "bashtypes.h" +#include "posixstat.h" +#include "posixtime.h" + +#if defined (__QNX__) +# if defined (__QNXNTO__) +# include +# else +# include +# endif /* !__QNXNTO__ */ +#endif /* __QNX__ */ + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include +#include "chartypes.h" +#if defined (HAVE_PWD_H) +# include +#endif +#include "bashansi.h" +#include "bashintl.h" + +#define NEED_XTRACE_SET_DECL + +#include "shell.h" +#include "flags.h" +#include "execute_cmd.h" +#include "findcmd.h" +#include "mailcheck.h" +#include "input.h" +#include "hashcmd.h" +#include "pathexp.h" +#include "alias.h" +#include "jobs.h" + +#include "version.h" + +#include "builtins/getopt.h" +#include "builtins/common.h" +#include "builtins/builtext.h" + +#if defined (READLINE) +# include "bashline.h" +# include +#else +# include +#endif + +#if defined (HISTORY) +# include "bashhist.h" +# include +#endif /* HISTORY */ + +#if defined (PROGRAMMABLE_COMPLETION) +# include "pcomplete.h" +#endif + +#define TEMPENV_HASH_BUCKETS 4 /* must be power of two */ + +#define ifsname(s) ((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0') + +/* flags for find_variable_internal */ + +#define FV_FORCETEMPENV 0x01 +#define FV_SKIPINVISIBLE 0x02 + +extern char **environ; + +/* Variables used here and defined in other files. */ +extern int posixly_correct; +extern int line_number, line_number_base; +extern int subshell_environment, indirection_level, subshell_level; +extern int build_version, patch_level; +extern int expanding_redir; +extern int last_command_exit_value; +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; +extern int assigning_in_environment; +extern int executing_builtin; +extern int funcnest_max; + +#if defined (READLINE) +extern int no_line_editing; +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; + +/* The current list of shell variables, including function scopes */ +VAR_CONTEXT *shell_variables = (VAR_CONTEXT *)NULL; + +/* The list of shell functions that the user has created, or that came from + 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; + +/* The set of shell assignments which are made only in the environment + 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]; +WORD_LIST *rest_of_args = (WORD_LIST *)NULL; + +/* The value of $$. */ +pid_t dollar_dollar_pid; + +/* Non-zero means that we have to remake EXPORT_ENV. */ +int array_needs_making = 1; + +/* The number of times BASH has been executed. This is set + by initialize_variables (). */ +int shell_level = 0; + +/* An array which is passed to commands as their environment. It is + manufactured from the union of the initial environment and the + shell variables that are marked for export. */ +char **export_env = (char **)NULL; +static int export_env_index; +static int export_env_size; + +#if defined (READLINE) +static int winsize_assignment; /* currently assigning to LINES or COLUMNS */ +#endif + +static HASH_TABLE *last_table_searched; /* hash_lookup sets this */ + +/* Some forward declarations. */ +static void create_variable_tables __P((void)); + +static void set_machine_vars __P((void)); +static void set_home_var __P((void)); +static void set_shell_var __P((void)); +static char *get_bash_name __P((void)); +static void initialize_shell_level __P((void)); +static void uidset __P((void)); +#if defined (ARRAY_VARS) +static void make_vers_array __P((void)); +#endif + +static SHELL_VAR *null_assign __P((SHELL_VAR *, char *, arrayind_t, char *)); +#if defined (ARRAY_VARS) +static SHELL_VAR *null_array_assign __P((SHELL_VAR *, char *, arrayind_t, char *)); +#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)); +static SHELL_VAR *init_dynamic_assoc_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, char *)); +static SHELL_VAR *get_seconds __P((SHELL_VAR *)); +static SHELL_VAR *init_seconds_var __P((void)); + +static int brand __P((void)); +static void sbrand __P((unsigned long)); /* set bash random number generator. */ +static void seedrand __P((void)); /* seed generator randomly */ +static SHELL_VAR *assign_random __P((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_random __P((SHELL_VAR *)); + +static SHELL_VAR *assign_lineno __P((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_lineno __P((SHELL_VAR *)); + +static SHELL_VAR *assign_subshell __P((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_subshell __P((SHELL_VAR *)); + +static SHELL_VAR *get_bashpid __P((SHELL_VAR *)); + +#if defined (HISTORY) +static SHELL_VAR *get_histcmd __P((SHELL_VAR *)); +#endif + +#if defined (READLINE) +static SHELL_VAR *get_comp_wordbreaks __P((SHELL_VAR *)); +static SHELL_VAR *assign_comp_wordbreaks __P((SHELL_VAR *, char *, arrayind_t, char *)); +#endif + +#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) +static SHELL_VAR *assign_dirstack __P((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_dirstack __P((SHELL_VAR *)); +#endif + +#if defined (ARRAY_VARS) +static SHELL_VAR *get_groupset __P((SHELL_VAR *)); + +static SHELL_VAR *build_hashcmd __P((SHELL_VAR *)); +static SHELL_VAR *get_hashcmd __P((SHELL_VAR *)); +static SHELL_VAR *assign_hashcmd __P((SHELL_VAR *, char *, arrayind_t, char *)); +# if defined (ALIAS) +static SHELL_VAR *build_aliasvar __P((SHELL_VAR *)); +static SHELL_VAR *get_aliasvar __P((SHELL_VAR *)); +static SHELL_VAR *assign_aliasvar __P((SHELL_VAR *, char *, arrayind_t, char *)); +# endif +#endif + +static SHELL_VAR *get_funcname __P((SHELL_VAR *)); +static SHELL_VAR *init_funcname_var __P((void)); + +static void initialize_dynamic_variables __P((void)); + +static SHELL_VAR *hash_lookup __P((const char *, HASH_TABLE *)); +static SHELL_VAR *new_shell_variable __P((const char *)); +static SHELL_VAR *make_new_variable __P((const char *, HASH_TABLE *)); +static SHELL_VAR *bind_variable_internal __P((const char *, char *, HASH_TABLE *, int, int)); + +static void dispose_variable_value __P((SHELL_VAR *)); +static void free_variable_hash_data __P((PTR_T)); + +static VARLIST *vlist_alloc __P((int)); +static VARLIST *vlist_realloc __P((VARLIST *, int)); +static void vlist_add __P((VARLIST *, SHELL_VAR *, int)); + +static void flatten __P((HASH_TABLE *, sh_var_map_func_t *, VARLIST *, int)); + +static int qsort_var_comp __P((SHELL_VAR **, SHELL_VAR **)); + +static SHELL_VAR **vapply __P((sh_var_map_func_t *)); +static SHELL_VAR **fapply __P((sh_var_map_func_t *)); + +static int visible_var __P((SHELL_VAR *)); +static int visible_and_exported __P((SHELL_VAR *)); +static int export_environment_candidate __P((SHELL_VAR *)); +static int local_and_exported __P((SHELL_VAR *)); +static int variable_in_context __P((SHELL_VAR *)); +#if defined (ARRAY_VARS) +static int visible_array_vars __P((SHELL_VAR *)); +#endif + +static SHELL_VAR *find_nameref_at_context __P((SHELL_VAR *, VAR_CONTEXT *)); +static SHELL_VAR *find_variable_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **)); +static SHELL_VAR *find_variable_last_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **)); + +static SHELL_VAR *bind_tempenv_variable __P((const char *, char *)); +static void push_temp_var __P((PTR_T)); +static void propagate_temp_var __P((PTR_T)); +static void dispose_temporary_env __P((sh_free_func_t *)); + +static inline char *mk_env_string __P((const char *, const char *)); +static char **make_env_array_from_var_list __P((SHELL_VAR **)); +static char **make_var_export_array __P((VAR_CONTEXT *)); +static char **make_func_export_array __P((void)); +static void add_temp_array_to_env __P((char **, int, int)); + +static int n_shell_variables __P((void)); +static int set_context __P((SHELL_VAR *)); + +static void push_func_var __P((PTR_T)); +static void push_exported_var __P((PTR_T)); + +static inline int find_special_var __P((const char *)); + +static void +create_variable_tables () +{ + if (shell_variables == 0) + { + shell_variables = global_variables = new_var_context ((char *)NULL, 0); + shell_variables->scope = 0; + shell_variables->table = hash_create (0); + } + + if (shell_functions == 0) + shell_functions = hash_create (0); + +#if defined (DEBUGGER) + if (shell_function_defs == 0) + shell_function_defs = hash_create (0); +#endif +} + +/* 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, privmode) + char **env; + int privmode; +{ + char *name, *string, *temp_string; + int c, char_index, string_index, string_length, ro; + SHELL_VAR *temp_var; + + create_variable_tables (); + + for (string_index = 0; string = env[string_index++]; ) + { + char_index = 0; + name = string; + while ((c = *string++) && c != '=') + ; + if (string[-1] == '=') + char_index = string - name - 1; + + /* If there are weird things in the environment, like `=xxx' or a + string without an `=', just skip them. */ + if (char_index == 0) + continue; + + /* ASSERT(name[char_index] == '=') */ + name[char_index] = '\0'; + /* Now, name = env variable name, string = env variable value, and + char_index == strlen (name) */ + + temp_var = (SHELL_VAR *)NULL; + + /* If exported function, define it now. Don't import functions from + the environment in privileged mode. */ + if (privmode == 0 && read_but_dont_execute == 0 && STREQN ("() {", string, 4)) + { + string_length = strlen (string); + temp_string = (char *)xmalloc (3 + string_length + char_index); + + strcpy (temp_string, name); + temp_string[char_index] = ' '; + strcpy (temp_string + char_index + 1, string); + + if (posixly_correct == 0 || legal_identifier (name)) + parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST); + + /* Ancient backwards compatibility. Old versions of bash exported + functions like name()=() {...} */ + if (name[char_index - 1] == ')' && name[char_index - 2] == '(') + name[char_index - 2] = '\0'; + + if (temp_var = find_function (name)) + { + VSETATTR (temp_var, (att_exported|att_imported)); + array_needs_making = 1; + } + else + { + if (temp_var = bind_variable (name, string, 0)) + { + VSETATTR (temp_var, (att_exported | att_imported | att_invisible)); + array_needs_making = 1; + } + last_command_exit_value = 1; + report_error (_("error importing function definition for `%s'"), name); + } + + /* ( */ + if (name[char_index - 1] == ')' && name[char_index - 2] == '\0') + name[char_index - 2] = '('; /* ) */ + } +#if defined (ARRAY_VARS) +# if ARRAY_EXPORT + /* Array variables may not yet be exported. */ + else if (*string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')') + { + string_length = 1; + temp_string = extract_array_assignment_list (string, &string_length); + temp_var = assign_array_from_string (name, temp_string); + FREE (temp_string); + VSETATTR (temp_var, (att_exported | att_imported)); + array_needs_making = 1; + } +# endif /* ARRAY_EXPORT */ +#endif +#if 0 + else if (legal_identifier (name)) +#else + else +#endif + { + ro = 0; + if (posixly_correct && STREQ (name, "SHELLOPTS")) + { + temp_var = find_variable ("SHELLOPTS"); + ro = temp_var && readonly_p (temp_var); + if (temp_var) + VUNSETATTR (temp_var, att_readonly); + } + temp_var = bind_variable (name, string, 0); + if (temp_var) + { + if (legal_identifier (name)) + VSETATTR (temp_var, (att_exported | att_imported)); + else + VSETATTR (temp_var, (att_exported | att_imported | att_invisible)); + if (ro) + VSETATTR (temp_var, att_readonly); + 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); + } + } + + set_pwd (); + + /* Set up initial value of $_ */ + temp_var = set_if_not ("_", dollar_vars[0]); + + /* Remember this pid. */ + dollar_dollar_pid = getpid (); + + /* Now make our own defaults in case the vars that we think are + important are missing. */ + temp_var = set_if_not ("PATH", DEFAULT_PATH_VALUE); +#if 0 + set_auto_export (temp_var); /* XXX */ +#endif + + temp_var = set_if_not ("TERM", "dumb"); +#if 0 + set_auto_export (temp_var); /* XXX */ +#endif + +#if defined (__QNX__) + /* set node id -- don't import it from the environment */ + { + char node_name[22]; +# if defined (__QNXNTO__) + netmgr_ndtostr(ND2S_LOCAL_STR, ND_LOCAL_NODE, node_name, sizeof(node_name)); +# else + qnx_nidtostr (getnid (), node_name, sizeof (node_name)); +# endif + temp_var = bind_variable ("NODE", node_name, 0); + set_auto_export (temp_var); + } +#endif + + /* set up the prompts. */ + if (interactive_shell) + { +#if defined (PROMPT_STRING_DECODE) + set_if_not ("PS1", primary_prompt); +#else + if (current_user.uid == -1) + get_current_user_info (); + set_if_not ("PS1", current_user.euid == 0 ? "# " : primary_prompt); +#endif + set_if_not ("PS2", secondary_prompt); + } + set_if_not ("PS4", "+ "); + + /* Don't allow IFS to be imported from the environment. */ + temp_var = bind_variable ("IFS", " \t\n", 0); + setifs (temp_var); + + /* Magic machine types. Pretty convenient. */ + set_machine_vars (); + + /* Default MAILCHECK for interactive shells. Defer the creation of a + default MAILPATH until the startup files are read, because MAIL + names a mail file if MAILPATH is not set, and we should provide a + default only if neither is set. */ + if (interactive_shell) + { + temp_var = set_if_not ("MAILCHECK", posixly_correct ? "600" : "60"); + VSETATTR (temp_var, att_integer); + } + + /* Do some things with shell level. */ + initialize_shell_level (); + + set_ppid (); + + /* Initialize the `getopts' stuff. */ + temp_var = bind_variable ("OPTIND", "1", 0); + VSETATTR (temp_var, att_integer); + getopts_reset (0); + bind_variable ("OPTERR", "1", 0); + sh_opterr = 1; + + if (login_shell == 1 && posixly_correct == 0) + set_home_var (); + + /* Get the full pathname to THIS shell, and set the BASH variable + to it. */ + name = get_bash_name (); + temp_var = bind_variable ("BASH", name, 0); + free (name); + + /* Make the exported environment variable SHELL be the user's login + shell. Note that the `tset' command looks at this variable + to determine what style of commands to output; if it ends in "csh", + then C-shell commands are output, else Bourne shell commands. */ + set_shell_var (); + + /* Make a variable called BASH_VERSION which contains the version info. */ + bind_variable ("BASH_VERSION", shell_version_string (), 0); +#if defined (ARRAY_VARS) + make_vers_array (); +#endif + + if (command_execution_string) + bind_variable ("BASH_EXECUTION_STRING", command_execution_string, 0); + + /* Find out if we're supposed to be in Posix.2 mode via an + environment variable. */ + temp_var = find_variable ("POSIXLY_CORRECT"); + if (!temp_var) + temp_var = find_variable ("POSIX_PEDANTIC"); + if (temp_var && imported_p (temp_var)) + sv_strict_posix (temp_var->name); + +#if defined (HISTORY) + /* Set history variables to defaults, and then do whatever we would + do if the variable had just been set. Do this only in the case + that we are remembering commands on the history list. */ + if (remember_on_history) + { + name = bash_tilde_expand (posixly_correct ? "~/.sh_history" : "~/.bash_history", 0); + + set_if_not ("HISTFILE", name); + free (name); + } +#endif /* HISTORY */ + + /* Seed the random number generator. */ + seedrand (); + + /* Handle some "special" variables that we may have inherited from a + parent shell. */ + if (interactive_shell) + { + temp_var = find_variable ("IGNOREEOF"); + if (!temp_var) + temp_var = find_variable ("ignoreeof"); + if (temp_var && imported_p (temp_var)) + sv_ignoreeof (temp_var->name); + } + +#if defined (HISTORY) + if (interactive_shell && remember_on_history) + { + sv_history_control ("HISTCONTROL"); + sv_histignore ("HISTIGNORE"); + sv_histtimefmt ("HISTTIMEFORMAT"); + } +#endif /* HISTORY */ + +#if defined (READLINE) && defined (STRICT_POSIX) + /* POSIXLY_CORRECT will only be 1 here if the shell was compiled + -DSTRICT_POSIX */ + if (interactive_shell && posixly_correct && no_line_editing == 0) + rl_prefer_env_winsize = 1; +#endif /* READLINE && STRICT_POSIX */ + + /* + * 24 October 2001 + * + * I'm tired of the arguing and bug reports. Bash now leaves SSH_CLIENT + * and SSH2_CLIENT alone. I'm going to rely on the shell_level check in + * isnetconn() to avoid running the startup files more often than wanted. + * That will, of course, only work if the user's login shell is bash, so + * I've made that behavior conditional on SSH_SOURCE_BASHRC being defined + * in config-top.h. + */ +#if 0 + temp_var = find_variable ("SSH_CLIENT"); + if (temp_var && imported_p (temp_var)) + { + VUNSETATTR (temp_var, att_exported); + array_needs_making = 1; + } + temp_var = find_variable ("SSH2_CLIENT"); + if (temp_var && imported_p (temp_var)) + { + VUNSETATTR (temp_var, att_exported); + array_needs_making = 1; + } +#endif + + /* Get the user's real and effective user ids. */ + uidset (); + + temp_var = find_variable ("BASH_XTRACEFD"); + if (temp_var && imported_p (temp_var)) + sv_xtracefd (temp_var->name); + + /* Initialize the dynamic variables, and seed their values. */ + initialize_dynamic_variables (); +} + +/* **************************************************************** */ +/* */ +/* Setting values for special shell variables */ +/* */ +/* **************************************************************** */ + +static void +set_machine_vars () +{ + SHELL_VAR *temp_var; + + temp_var = set_if_not ("HOSTTYPE", HOSTTYPE); + temp_var = set_if_not ("OSTYPE", OSTYPE); + temp_var = set_if_not ("MACHTYPE", MACHTYPE); + + temp_var = set_if_not ("HOSTNAME", current_host_name); +} + +/* Set $HOME to the information in the password file if we didn't get + it from the environment. */ + +/* This function is not static so the tilde and readline libraries can + use it. */ +char * +sh_get_home_dir () +{ + if (current_user.home_dir == 0) + get_current_user_info (); + return current_user.home_dir; +} + +static void +set_home_var () +{ + SHELL_VAR *temp_var; + + temp_var = find_variable ("HOME"); + if (temp_var == 0) + temp_var = bind_variable ("HOME", sh_get_home_dir (), 0); +#if 0 + VSETATTR (temp_var, att_exported); +#endif +} + +/* Set $SHELL to the user's login shell if it is not already set. Call + get_current_user_info if we haven't already fetched the shell. */ +static void +set_shell_var () +{ + SHELL_VAR *temp_var; + + temp_var = find_variable ("SHELL"); + if (temp_var == 0) + { + if (current_user.shell == 0) + get_current_user_info (); + temp_var = bind_variable ("SHELL", current_user.shell, 0); + } +#if 0 + VSETATTR (temp_var, att_exported); +#endif +} + +static char * +get_bash_name () +{ + char *name; + + if ((login_shell == 1) && RELPATH(shell_name)) + { + if (current_user.shell == 0) + get_current_user_info (); + name = savestring (current_user.shell); + } + else if (ABSPATH(shell_name)) + name = savestring (shell_name); + else if (shell_name[0] == '.' && shell_name[1] == '/') + { + /* Fast path for common case. */ + char *cdir; + int len; + + cdir = get_string_value ("PWD"); + if (cdir) + { + len = strlen (cdir); + name = (char *)xmalloc (len + strlen (shell_name) + 1); + strcpy (name, cdir); + strcpy (name + len, shell_name + 1); + } + else + name = savestring (shell_name); + } + else + { + char *tname; + int s; + + tname = find_user_command (shell_name); + + if (tname == 0) + { + /* Try the current directory. If there is not an executable + there, just punt and use the login shell. */ + s = file_status (shell_name); + if (s & FS_EXECABLE) + { + tname = make_absolute (shell_name, get_string_value ("PWD")); + if (*shell_name == '.') + { + name = sh_canonpath (tname, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + if (name == 0) + name = tname; + else + free (tname); + } + else + name = tname; + } + else + { + if (current_user.shell == 0) + get_current_user_info (); + name = savestring (current_user.shell); + } + } + else + { + name = full_pathname (tname); + free (tname); + } + } + + return (name); +} + +void +adjust_shell_level (change) + int change; +{ + char new_level[5], *old_SHLVL; + intmax_t old_level; + SHELL_VAR *temp_var; + + old_SHLVL = get_string_value ("SHLVL"); + if (old_SHLVL == 0 || *old_SHLVL == '\0' || legal_number (old_SHLVL, &old_level) == 0) + old_level = 0; + + shell_level = old_level + change; + if (shell_level < 0) + shell_level = 0; + else if (shell_level > 1000) + { + internal_warning (_("shell level (%d) too high, resetting to 1"), shell_level); + shell_level = 1; + } + + /* We don't need the full generality of itos here. */ + if (shell_level < 10) + { + new_level[0] = shell_level + '0'; + new_level[1] = '\0'; + } + else if (shell_level < 100) + { + new_level[0] = (shell_level / 10) + '0'; + new_level[1] = (shell_level % 10) + '0'; + new_level[2] = '\0'; + } + else if (shell_level < 1000) + { + new_level[0] = (shell_level / 100) + '0'; + old_level = shell_level % 100; + new_level[1] = (old_level / 10) + '0'; + new_level[2] = (old_level % 10) + '0'; + new_level[3] = '\0'; + } + + temp_var = bind_variable ("SHLVL", new_level, 0); + set_auto_export (temp_var); +} + +static void +initialize_shell_level () +{ + adjust_shell_level (1); +} + +/* If we got PWD from the environment, update our idea of the current + working directory. In any case, make sure that PWD exists before + checking it. It is possible for getcwd () to fail on shell startup, + and in that case, PWD would be undefined. If this is an interactive + login shell, see if $HOME is the current working directory, and if + that's not the same string as $PWD, set PWD=$HOME. */ + +void +set_pwd () +{ + SHELL_VAR *temp_var, *home_var; + char *temp_string, *home_string; + + home_var = find_variable ("HOME"); + home_string = home_var ? value_cell (home_var) : (char *)NULL; + + temp_var = find_variable ("PWD"); + if (temp_var && imported_p (temp_var) && + (temp_string = value_cell (temp_var)) && + same_file (temp_string, ".", (struct stat *)NULL, (struct stat *)NULL)) + set_working_directory (temp_string); + else if (home_string && interactive_shell && login_shell && + same_file (home_string, ".", (struct stat *)NULL, (struct stat *)NULL)) + { + set_working_directory (home_string); + temp_var = bind_variable ("PWD", home_string, 0); + set_auto_export (temp_var); + } + else + { + temp_string = get_working_directory ("shell-init"); + if (temp_string) + { + temp_var = bind_variable ("PWD", temp_string, 0); + set_auto_export (temp_var); + free (temp_string); + } + } + + /* According to the Single Unix Specification, v2, $OLDPWD is an + `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, 0); + VSETATTR (temp_var, (att_exported | att_invisible)); +} + +/* Make a variable $PPID, which holds the pid of the shell's parent. */ +void +set_ppid () +{ + char namebuf[INT_STRLEN_BOUND(pid_t) + 1], *name; + SHELL_VAR *temp_var; + + name = inttostr (getppid (), namebuf, sizeof(namebuf)); + temp_var = find_variable ("PPID"); + if (temp_var) + VUNSETATTR (temp_var, (att_readonly | att_exported)); + temp_var = bind_variable ("PPID", name, 0); + VSETATTR (temp_var, (att_readonly | att_integer)); +} + +static void +uidset () +{ + char buff[INT_STRLEN_BOUND(uid_t) + 1], *b; + register SHELL_VAR *v; + + b = inttostr (current_user.uid, buff, sizeof (buff)); + v = find_variable ("UID"); + if (v == 0) + { + v = bind_variable ("UID", b, 0); + 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 == 0) + { + v = bind_variable ("EUID", b, 0); + VSETATTR (v, (att_readonly | att_integer)); + } +} + +#if defined (ARRAY_VARS) +static void +make_vers_array () +{ + SHELL_VAR *vv; + ARRAY *av; + char *s, d[32], b[INT_STRLEN_BOUND(int) + 1]; + + unbind_variable ("BASH_VERSINFO"); + + vv = make_new_array_variable ("BASH_VERSINFO"); + av = array_cell (vv); + strcpy (d, dist_version); + s = strchr (d, '.'); + if (s) + *s++ = '\0'; + array_insert (av, 0, d); + array_insert (av, 1, s); + s = inttostr (patch_level, b, sizeof (b)); + array_insert (av, 2, s); + s = inttostr (build_version, b, sizeof (b)); + array_insert (av, 3, s); + array_insert (av, 4, release_status); + array_insert (av, 5, MACHTYPE); + + VSETATTR (vv, att_readonly); +} +#endif /* ARRAY_VARS */ + +/* Set the environment variables $LINES and $COLUMNS in response to + a window size change. */ +void +sh_set_lines_and_columns (lines, cols) + int lines, cols; +{ + char val[INT_STRLEN_BOUND(int) + 1], *v; + +#if defined (READLINE) + /* If we are currently assigning to LINES or COLUMNS, don't do anything. */ + if (winsize_assignment) + return; +#endif + + v = inttostr (lines, val, sizeof (val)); + bind_variable ("LINES", v, 0); + + v = inttostr (cols, val, sizeof (val)); + bind_variable ("COLUMNS", v, 0); +} + +/* **************************************************************** */ +/* */ +/* Printing variables and values */ +/* */ +/* **************************************************************** */ + +/* Print LIST (a list of shell variables) to stdout in such a way that + they can be read back in. */ +void +print_var_list (list) + register SHELL_VAR **list; +{ + register int i; + register SHELL_VAR *var; + + for (i = 0; list && (var = list[i]); i++) + if (invisible_p (var) == 0) + print_assignment (var); +} + +/* Print LIST (a list of shell functions) to stdout in such a way that + they can be read back in. */ +void +print_func_list (list) + register SHELL_VAR **list; +{ + register int i; + register SHELL_VAR *var; + + for (i = 0; list && (var = list[i]); i++) + { + printf ("%s ", var->name); + print_var_function (var); + printf ("\n"); + } +} + +/* Print the value of a single SHELL_VAR. No newline is + output, but the variable is printed in such a way that + it can be read back in. */ +void +print_assignment (var) + SHELL_VAR *var; +{ + if (var_isset (var) == 0) + return; + + if (function_p (var)) + { + printf ("%s", var->name); + print_var_function (var); + printf ("\n"); + } +#if defined (ARRAY_VARS) + else if (array_p (var)) + print_array_assignment (var, 0); + else if (assoc_p (var)) + print_assoc_assignment (var, 0); +#endif /* ARRAY_VARS */ + else + { + printf ("%s=", var->name); + print_var_value (var, 1); + printf ("\n"); + } +} + +/* Print the value cell of VAR, a shell variable. Do not print + the name, nor leading/trailing newline. If QUOTE is non-zero, + and the value contains shell metacharacters, quote the value + in such a way that it can be read back in. */ +void +print_var_value (var, quote) + SHELL_VAR *var; + int quote; +{ + char *t; + + if (var_isset (var) == 0) + return; + + if (quote && posixly_correct == 0 && ansic_shouldquote (value_cell (var))) + { + t = ansic_quote (value_cell (var), 0, (int *)0); + printf ("%s", t); + free (t); + } + else if (quote && sh_contains_shell_metas (value_cell (var))) + { + t = sh_single_quote (value_cell (var)); + printf ("%s", t); + free (t); + } + else + printf ("%s", value_cell (var)); +} + +/* Print the function cell of VAR, a shell variable. Do not + print the name, nor leading/trailing newline. */ +void +print_var_function (var) + SHELL_VAR *var; +{ + char *x; + + if (function_p (var) && var_isset (var)) + { + x = named_function_string ((char *)NULL, function_cell(var), FUNC_MULTILINE|FUNC_EXTERNAL); + printf ("%s", x); + } +} + +/* **************************************************************** */ +/* */ +/* Dynamic Variables */ +/* */ +/* **************************************************************** */ + +/* DYNAMIC VARIABLES + + These are variables whose values are generated anew each time they are + referenced. These are implemented using a pair of function pointers + in the struct variable: assign_func, which is called from bind_variable + and, if arrays are compiled into the shell, some of the functions in + arrayfunc.c, and dynamic_value, which is called from find_variable. + + assign_func is called from bind_variable_internal, if + bind_variable_internal discovers that the variable being assigned to + has such a function. The function is called as + SHELL_VAR *temp = (*(entry->assign_func)) (entry, value, ind) + and the (SHELL_VAR *)temp is returned as the value of bind_variable. It + is usually ENTRY (self). IND is an index for an array variable, and + unused otherwise. + + dynamic_value is called from find_variable_internal to return a `new' + value for the specified dynamic varible. If this function is NULL, + the variable is treated as a `normal' shell variable. If it is not, + however, then this function is called like this: + tempvar = (*(var->dynamic_value)) (var); + + Sometimes `tempvar' will replace the value of `var'. Other times, the + shell will simply use the string value. Pretty object-oriented, huh? + + Be warned, though: if you `unset' a special variable, it loses its + special meaning, even if you subsequently set it. + + The special assignment code would probably have been better put in + subst.c: do_assignment_internal, in the same style as + stupidly_hack_special_variables, but I wanted the changes as + localized as possible. */ + +#define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \ + do \ + { \ + v = bind_variable (var, (val), 0); \ + 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) + +#define INIT_DYNAMIC_ASSOC_VAR(var, gfunc, afunc) \ + do \ + { \ + v = make_new_assoc_variable (var); \ + v->dynamic_value = gfunc; \ + v->assign_func = afunc; \ + } \ + while (0) + +static SHELL_VAR * +null_assign (self, value, unused, key) + SHELL_VAR *self; + char *value; + arrayind_t unused; + char *key; +{ + return (self); +} + +#if defined (ARRAY_VARS) +static SHELL_VAR * +null_array_assign (self, value, ind, key) + SHELL_VAR *self; + char *value; + arrayind_t ind; + char *key; +{ + return (self); +} +#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. Initialize 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; +} + +static SHELL_VAR * +init_dynamic_assoc_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_ASSOC_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. */ +static intmax_t seconds_value_assigned; + +static SHELL_VAR * +assign_seconds (self, value, unused, key) + SHELL_VAR *self; + char *value; + arrayind_t unused; + char *key; +{ + if (legal_number (value, &seconds_value_assigned) == 0) + seconds_value_assigned = 0; + shell_start_time = NOW; + return (self); +} + +static SHELL_VAR * +get_seconds (var) + SHELL_VAR *var; +{ + time_t time_since_start; + char *p; + + time_since_start = NOW - shell_start_time; + p = itos(seconds_value_assigned + time_since_start); + + FREE (value_cell (var)); + + VSETATTR (var, att_integer); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +init_seconds_var () +{ + SHELL_VAR *v; + + v = find_variable ("SECONDS"); + if (v) + { + if (legal_number (value_cell(v), &seconds_value_assigned) == 0) + seconds_value_assigned = 0; + } + INIT_DYNAMIC_VAR ("SECONDS", (v ? value_cell (v) : (char *)NULL), get_seconds, assign_seconds); + return v; +} + +/* The random number seed. You can change this by setting RANDOM. */ +static unsigned long rseed = 1; +static int last_random_value; +static int seeded_subshell = 0; + +/* A linear congruential random number generator based on the example + one in the ANSI C standard. This one isn't very good, but a more + complicated one is overkill. */ + +/* Returns a pseudo-random number between 0 and 32767. */ +static int +brand () +{ + /* From "Random number generators: good ones are hard to find", + Park and Miller, Communications of the ACM, vol. 31, no. 10, + October 1988, p. 1195. filtered through FreeBSD */ + long h, l; + + /* Can't seed with 0. */ + if (rseed == 0) + rseed = 123459876; + h = rseed / 127773; + l = rseed % 127773; + rseed = 16807 * l - 2836 * h; +#if 0 + if (rseed < 0) + rseed += 0x7fffffff; +#endif + return ((unsigned int)(rseed & 32767)); /* was % 32768 */ +} + +/* Set the random number generator seed to SEED. */ +static void +sbrand (seed) + unsigned long seed; +{ + rseed = seed; + last_random_value = 0; +} + +static void +seedrand () +{ + struct timeval tv; + + gettimeofday (&tv, NULL); + sbrand (tv.tv_sec ^ tv.tv_usec ^ getpid ()); +} + +static SHELL_VAR * +assign_random (self, value, unused, key) + SHELL_VAR *self; + char *value; + arrayind_t unused; + char *key; +{ + sbrand (strtoul (value, (char **)NULL, 10)); + if (subshell_environment) + seeded_subshell = getpid (); + return (self); +} + +int +get_random_number () +{ + int rv, pid; + + /* Reset for command and process substitution. */ + pid = getpid (); + if (subshell_environment && seeded_subshell != pid) + { + seedrand (); + seeded_subshell = pid; + } + + do + rv = brand (); + while (rv == last_random_value); + return rv; +} + +static SHELL_VAR * +get_random (var) + SHELL_VAR *var; +{ + int rv; + char *p; + + rv = get_random_number (); + last_random_value = rv; + p = itos (rv); + + FREE (value_cell (var)); + + VSETATTR (var, att_integer); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +assign_lineno (var, value, unused, key) + SHELL_VAR *var; + char *value; + arrayind_t unused; + char *key; +{ + intmax_t new_value; + + if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0) + new_value = 0; + line_number = line_number_base = new_value; + return var; +} + +/* Function which returns the current line number. */ +static SHELL_VAR * +get_lineno (var) + SHELL_VAR *var; +{ + char *p; + int ln; + + ln = executing_line_number (); + p = itos (ln); + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +assign_subshell (var, value, unused, key) + SHELL_VAR *var; + char *value; + arrayind_t unused; + char *key; +{ + 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_bashpid (var) + SHELL_VAR *var; +{ + int pid; + char *p; + + pid = getpid (); + p = itos (pid); + + FREE (value_cell (var)); + VSETATTR (var, att_integer|att_readonly); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +get_bash_command (var) + SHELL_VAR *var; +{ + char *p; + + if (the_printed_command_except_trap) + p = savestring (the_printed_command_except_trap); + else + { + p = (char *)xmalloc (1); + p[0] = '\0'; + } + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + +#if defined (HISTORY) +static SHELL_VAR * +get_histcmd (var) + SHELL_VAR *var; +{ + char *p; + + p = itos (history_number ()); + FREE (value_cell (var)); + var_setvalue (var, p); + return (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; +{ + /* 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); + + FREE (value_cell (var)); + var_setvalue (var, savestring (rl_completer_word_break_characters)); + + return (var); +} + +/* When this function returns, rl_completer_word_break_characters points to + malloced memory. */ +static SHELL_VAR * +assign_comp_wordbreaks (self, value, unused, key) + SHELL_VAR *self; + char *value; + arrayind_t unused; + char *key; +{ + 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 * +assign_dirstack (self, value, ind, key) + SHELL_VAR *self; + char *value; + arrayind_t ind; + char *key; +{ + set_dirstack_element (ind, 1, value); + return self; +} + +static SHELL_VAR * +get_dirstack (self) + SHELL_VAR *self; +{ + ARRAY *a; + WORD_LIST *l; + + l = get_directory_stack (0); + a = array_from_word_list (l); + array_dispose (array_cell (self)); + dispose_words (l); + var_setarray (self, a); + return self; +} +#endif /* PUSHD AND POPD && ARRAY_VARS */ + +#if defined (ARRAY_VARS) +/* We don't want to initialize the group set with a call to getgroups() + unless we're asked to, but we only want to do it once. */ +static SHELL_VAR * +get_groupset (self) + SHELL_VAR *self; +{ + register int i; + int ng; + ARRAY *a; + static char **group_set = (char **)NULL; + + if (group_set == 0) + { + group_set = get_group_list (&ng); + a = array_cell (self); + for (i = 0; i < ng; i++) + array_insert (a, i, group_set[i]); + } + return (self); +} + +static SHELL_VAR * +build_hashcmd (self) + SHELL_VAR *self; +{ + HASH_TABLE *h; + int i; + char *k, *v; + BUCKET_CONTENTS *item; + + h = assoc_cell (self); + if (h) + assoc_dispose (h); + + if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0) + { + var_setvalue (self, (char *)NULL); + return self; + } + + h = assoc_create (hashed_filenames->nbuckets); + for (i = 0; i < hashed_filenames->nbuckets; i++) + { + for (item = hash_items (i, hashed_filenames); item; item = item->next) + { + k = savestring (item->key); + v = pathdata(item)->path; + assoc_insert (h, k, v); + } + } + + var_setvalue (self, (char *)h); + return self; +} + +static SHELL_VAR * +get_hashcmd (self) + SHELL_VAR *self; +{ + build_hashcmd (self); + return (self); +} + +static SHELL_VAR * +assign_hashcmd (self, value, ind, key) + SHELL_VAR *self; + char *value; + arrayind_t ind; + char *key; +{ + phash_insert (key, value, 0, 0); + return (build_hashcmd (self)); +} + +#if defined (ALIAS) +static SHELL_VAR * +build_aliasvar (self) + SHELL_VAR *self; +{ + HASH_TABLE *h; + int i; + char *k, *v; + BUCKET_CONTENTS *item; + + h = assoc_cell (self); + if (h) + assoc_dispose (h); + + if (aliases == 0 || HASH_ENTRIES (aliases) == 0) + { + var_setvalue (self, (char *)NULL); + return self; + } + + h = assoc_create (aliases->nbuckets); + for (i = 0; i < aliases->nbuckets; i++) + { + for (item = hash_items (i, aliases); item; item = item->next) + { + k = savestring (item->key); + v = ((alias_t *)(item->data))->value; + assoc_insert (h, k, v); + } + } + + var_setvalue (self, (char *)h); + return self; +} + +static SHELL_VAR * +get_aliasvar (self) + SHELL_VAR *self; +{ + build_aliasvar (self); + return (self); +} + +static SHELL_VAR * +assign_aliasvar (self, value, ind, key) + SHELL_VAR *self; + char *value; + arrayind_t ind; + char *key; +{ + add_alias (key, value); + return (build_aliasvar (self)); +} +#endif /* ALIAS */ + +#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) + { + FREE (value_cell (self)); + t = savestring (this_shell_function->name); + var_setvalue (self, t); + } +#endif + 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); +} + +static SHELL_VAR * +init_funcname_var () +{ + SHELL_VAR *v; + + 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; +} + +static void +initialize_dynamic_variables () +{ + SHELL_VAR *v; + + 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); + VSETATTR (v, att_integer); + INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno); + VSETATTR (v, att_integer); + + INIT_DYNAMIC_VAR ("BASHPID", (char *)NULL, get_bashpid, null_assign); + VSETATTR (v, att_integer|att_readonly); + +#if defined (HISTORY) + INIT_DYNAMIC_VAR ("HISTCMD", (char *)NULL, get_histcmd, (sh_var_assign_func_t *)NULL); + VSETATTR (v, att_integer); +#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_dynamic_array_var ("DIRSTACK", get_dirstack, assign_dirstack, 0); +#endif /* PUSHD_AND_POPD && ARRAY_VARS */ + +#if defined (ARRAY_VARS) + 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_noassign|att_nounset); + v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, att_noassign|att_nounset); +# endif /* DEBUGGER */ + v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, att_noassign|att_nounset); + v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, att_noassign|att_nounset); + + v = init_dynamic_assoc_var ("BASH_CMDS", get_hashcmd, assign_hashcmd, att_nofree); +# if defined (ALIAS) + v = init_dynamic_assoc_var ("BASH_ALIASES", get_aliasvar, assign_aliasvar, att_nofree); +# endif +#endif + + v = init_funcname_var (); +} + +/* **************************************************************** */ +/* */ +/* Retrieving variables and values */ +/* */ +/* **************************************************************** */ + +/* How to get a pointer to the shell variable or function named NAME. + HASHED_VARS is a pointer to the hash table containing the list + of interest (either variables or functions). */ + +static SHELL_VAR * +hash_lookup (name, hashed_vars) + const char *name; + HASH_TABLE *hashed_vars; +{ + BUCKET_CONTENTS *bucket; + + bucket = hash_search (name, hashed_vars, 0); + /* If we find the name in HASHED_VARS, set LAST_TABLE_SEARCHED to that + table. */ + if (bucket) + last_table_searched = hashed_vars; + return (bucket ? (SHELL_VAR *)bucket->data : (SHELL_VAR *)NULL); +} + +SHELL_VAR * +var_lookup (name, vcontext) + const char *name; + VAR_CONTEXT *vcontext; +{ + VAR_CONTEXT *vc; + SHELL_VAR *v; + + v = (SHELL_VAR *)NULL; + for (vc = vcontext; vc; vc = vc->down) + if (v = hash_lookup (name, vc->table)) + break; + + return v; +} + +/* Look up the variable entry named NAME. If SEARCH_TEMPENV is non-zero, + then also search the temporarily built list of exported variables. + The lookup order is: + temporary_env + shell_variables list +*/ + +SHELL_VAR * +find_variable_internal (name, flags) + const char *name; + int flags; +{ + SHELL_VAR *var; + int search_tempenv, force_tempenv; + VAR_CONTEXT *vc; + + var = (SHELL_VAR *)NULL; + + force_tempenv = (flags & FV_FORCETEMPENV); + + /* If explicitly requested, first look in the temporary environment for + the variable. This allows constructs such as "foo=x eval 'echo $foo'" + 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". */ + search_tempenv = force_tempenv || (expanding_redir == 0 && subshell_environment); + + if (search_tempenv && temporary_env) + var = hash_lookup (name, temporary_env); + + if (var == 0) + { + if ((flags & FV_SKIPINVISIBLE) == 0) + var = var_lookup (name, shell_variables); + else + { + /* essentially var_lookup expanded inline so we can check for + att_invisible */ + for (vc = shell_variables; vc; vc = vc->down) + { + var = hash_lookup (name, vc->table); + if (var && invisible_p (var)) + var = 0; + if (var) + break; + } + } + } + + if (var == 0) + return ((SHELL_VAR *)NULL); + + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); +} + +/* Look up and resolve the chain of nameref variables starting at V all the + way to NULL or non-nameref. */ +SHELL_VAR * +find_variable_nameref (v) + SHELL_VAR *v; +{ + int level, flags; + char *newname; + SHELL_VAR *orig, *oldv; + + level = 0; + orig = v; + while (v && nameref_p (v)) + { + level++; + if (level > NAMEREF_MAX) + return ((SHELL_VAR *)0); /* error message here? */ + newname = nameref_cell (v); + if (newname == 0 || *newname == '\0') + return ((SHELL_VAR *)0); + oldv = v; + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (newname, flags); + if (v == orig || v == oldv) + { + internal_warning (_("%s: circular name reference"), orig->name); + return ((SHELL_VAR *)0); + } + } + return v; +} + +/* Resolve the chain of nameref variables for NAME. XXX - could change later */ +SHELL_VAR * +find_variable_last_nameref (name) + const char *name; +{ + SHELL_VAR *v, *nv; + char *newname; + int level, flags; + + nv = v = find_variable_noref (name); + level = 0; + while (v && nameref_p (v)) + { + level++; + if (level > NAMEREF_MAX) + return ((SHELL_VAR *)0); /* error message here? */ + newname = nameref_cell (v); + if (newname == 0 || *newname == '\0') + return ((SHELL_VAR *)0); + nv = v; + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (newname, flags); + } + return nv; +} + +/* Resolve the chain of nameref variables for NAME. XXX - could change later */ +SHELL_VAR * +find_global_variable_last_nameref (name) + const char *name; +{ + SHELL_VAR *v, *nv; + char *newname; + int level; + + nv = v = find_global_variable_noref (name); + level = 0; + while (v && nameref_p (v)) + { + level++; + if (level > NAMEREF_MAX) + return ((SHELL_VAR *)0); /* error message here? */ + newname = nameref_cell (v); + if (newname == 0 || *newname == '\0') + return ((SHELL_VAR *)0); + nv = v; + v = find_global_variable_noref (newname); + } + return nv; +} + +static SHELL_VAR * +find_nameref_at_context (v, vc) + SHELL_VAR *v; + VAR_CONTEXT *vc; +{ + SHELL_VAR *nv, *nv2; + VAR_CONTEXT *nvc; + char *newname; + int level; + + nv = v; + level = 1; + while (nv && nameref_p (nv)) + { + level++; + if (level > NAMEREF_MAX) + return ((SHELL_VAR *)NULL); + newname = nameref_cell (nv); + if (newname == 0 || *newname == '\0') + return ((SHELL_VAR *)NULL); + nv2 = hash_lookup (newname, vc->table); + if (nv2 == 0) + break; + nv = nv2; + } + return nv; +} + +/* Do nameref resolution from the VC, which is the local context for some + function or builtin, `up' the chain to the global variables context. If + NVCP is not NULL, return the variable context where we finally ended the + nameref resolution (so the bind_variable_internal can use the correct + variable context and hash table). */ +static SHELL_VAR * +find_variable_nameref_context (v, vc, nvcp) + SHELL_VAR *v; + VAR_CONTEXT *vc; + VAR_CONTEXT **nvcp; +{ + SHELL_VAR *nv, *nv2; + VAR_CONTEXT *nvc; + + /* Look starting at the current context all the way `up' */ + for (nv = v, nvc = vc; nvc; nvc = nvc->down) + { + nv2 = find_nameref_at_context (nv, nvc); + if (nv2 == 0) + continue; + nv = nv2; + if (*nvcp) + *nvcp = nvc; + if (nameref_p (nv) == 0) + break; + } + return (nameref_p (nv) ? (SHELL_VAR *)NULL : nv); +} + +/* Do nameref resolution from the VC, which is the local context for some + function or builtin, `up' the chain to the global variables context. If + NVCP is not NULL, return the variable context where we finally ended the + nameref resolution (so the bind_variable_internal can use the correct + variable context and hash table). */ +static SHELL_VAR * +find_variable_last_nameref_context (v, vc, nvcp) + SHELL_VAR *v; + VAR_CONTEXT *vc; + VAR_CONTEXT **nvcp; +{ + SHELL_VAR *nv, *nv2; + VAR_CONTEXT *nvc; + + /* Look starting at the current context all the way `up' */ + for (nv = v, nvc = vc; nvc; nvc = nvc->down) + { + nv2 = find_nameref_at_context (nv, nvc); + if (nv2 == 0) + continue; + nv = nv2; + if (*nvcp) + *nvcp = nvc; + } + return (nameref_p (nv) ? nv : (SHELL_VAR *)NULL); +} + +/* Find a variable, forcing a search of the temporary environment first */ +SHELL_VAR * +find_variable_tempenv (name) + const char *name; +{ + SHELL_VAR *var; + + var = find_variable_internal (name, FV_FORCETEMPENV); + if (var && nameref_p (var)) + var = find_variable_nameref (var); + return (var); +} + +/* Find a variable, not forcing a search of the temporary environment first */ +SHELL_VAR * +find_variable_notempenv (name) + const char *name; +{ + SHELL_VAR *var; + + var = find_variable_internal (name, 0); + if (var && nameref_p (var)) + var = find_variable_nameref (var); + return (var); +} + +SHELL_VAR * +find_global_variable (name) + const char *name; +{ + SHELL_VAR *var; + + var = var_lookup (name, global_variables); + if (var && nameref_p (var)) + var = find_variable_nameref (var); + + if (var == 0) + return ((SHELL_VAR *)NULL); + + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); +} + +SHELL_VAR * +find_global_variable_noref (name) + const char *name; +{ + SHELL_VAR *var; + + var = var_lookup (name, global_variables); + + if (var == 0) + return ((SHELL_VAR *)NULL); + + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); +} + +SHELL_VAR * +find_shell_variable (name) + const char *name; +{ + SHELL_VAR *var; + + var = var_lookup (name, shell_variables); + if (var && nameref_p (var)) + var = find_variable_nameref (var); + + if (var == 0) + return ((SHELL_VAR *)NULL); + + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); +} + +/* Look up the variable entry named NAME. Returns the entry or NULL. */ +SHELL_VAR * +find_variable (name) + const char *name; +{ + SHELL_VAR *v; + int flags; + + last_table_searched = 0; + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (name, flags); + if (v && nameref_p (v)) + v = find_variable_nameref (v); + return v; +} + +/* Find the first instance of NAME in the variable context chain; return first + one found without att_invisible set; return 0 if no non-invisible instances + found. */ +SHELL_VAR * +find_variable_no_invisible (name) + const char *name; +{ + SHELL_VAR *v; + int flags; + + last_table_searched = 0; + flags = FV_SKIPINVISIBLE; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (name, flags); + if (v && nameref_p (v)) + v = find_variable_nameref (v); + return v; +} + +/* Find the first instance of NAME in the variable context chain; return first + one found even if att_invisible set. */ +SHELL_VAR * +find_variable_for_assignment (name) + const char *name; +{ + SHELL_VAR *v; + int flags; + + last_table_searched = 0; + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (name, flags); + if (v && nameref_p (v)) + v = find_variable_nameref (v); + return v; +} + +SHELL_VAR * +find_variable_noref (name) + const char *name; +{ + SHELL_VAR *v; + int flags; + + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (name, flags); + return v; +} + +/* Look up the function entry whose name matches STRING. + Returns the entry or NULL. */ +SHELL_VAR * +find_function (name) + const char *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; +{ +#if defined (DEBUGGER) + return ((FUNCTION_DEF *)hash_lookup (name, shell_function_defs)); +#else + return ((FUNCTION_DEF *)0); +#endif +} + +/* 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 * +get_variable_value (var) + SHELL_VAR *var; +{ + if (var == 0) + return ((char *)NULL); +#if defined (ARRAY_VARS) + else if (array_p (var)) + return (array_reference (array_cell (var), 0)); + else if (assoc_p (var)) + return (assoc_reference (assoc_cell (var), "0")); +#endif + else + return (value_cell (var)); +} + +/* Return the string value of a variable. Return NULL if the variable + doesn't exist. Don't cons a new string. This is a potential memory + leak if the variable is found in the temporary environment. Since + functions and variables have separate name spaces, returns NULL if + var_name is a shell function only. */ +char * +get_string_value (var_name) + const char *var_name; +{ + SHELL_VAR *var; + + var = find_variable (var_name); + return ((var) ? get_variable_value (var) : (char *)NULL); +} + +/* This is present for use by the tilde and readline libraries. */ +char * +sh_get_env_value (v) + const char *v; +{ + return get_string_value (v); +} + +/* **************************************************************** */ +/* */ +/* Creating and setting variables */ +/* */ +/* **************************************************************** */ + +/* Set NAME to VALUE if NAME has no value. */ +SHELL_VAR * +set_if_not (name, value) + char *name, *value; +{ + SHELL_VAR *v; + + if (shell_variables == 0) + create_variable_tables (); + + v = find_variable (name); + if (v == 0) + v = bind_variable_internal (name, value, global_variables->table, HASH_NOSRCH, 0); + return (v); +} + +/* Create a local variable referenced by NAME. */ +SHELL_VAR * +make_local_variable (name) + const char *name; +{ + SHELL_VAR *new_var, *old_var; + VAR_CONTEXT *vc; + int was_tmpvar; + char *tmp_value; + + /* local foo; local foo; is a no-op. */ + old_var = find_variable (name); + if (old_var && local_p (old_var) && old_var->context == variable_context) + return (old_var); + + was_tmpvar = old_var && tempvar_p (old_var); + /* If we're making a local variable in a shell function, the temporary env + has already been merged into the function's variable context stack. We + can assume that a temporary var in the same context appears in the same + VAR_CONTEXT and can safely be returned without creating a new variable + (which results in duplicate names in the same VAR_CONTEXT->table */ + /* We can't just test tmpvar_p because variables in the temporary env given + to a shell function appear in the function's local variable VAR_CONTEXT + but retain their tempvar attribute. We want temporary variables that are + found in temporary_env, hence the test for last_table_searched, which is + set in hash_lookup and only (so far) checked here. */ + if (was_tmpvar && old_var->context == variable_context && last_table_searched != temporary_env) + { + VUNSETATTR (old_var, att_invisible); /* XXX */ + return (old_var); + } + if (was_tmpvar) + tmp_value = value_cell (old_var); + + for (vc = shell_variables; vc; vc = vc->down) + if (vc_isfuncenv (vc) && vc->scope == variable_context) + break; + + if (vc == 0) + { + internal_error (_("make_local_variable: no function context at current scope")); + return ((SHELL_VAR *)NULL); + } + else if (vc->table == 0) + vc->table = hash_create (TEMPENV_HASH_BUCKETS); + + /* 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). Variables with the `noassign' + attribute may not be made local. The test against old_var's context + level is to disallow local copies of readonly global variables (since I + believe that this could be a security hole). Readonly copies of calling + function local variables are OK. */ + if (old_var && (noassign_p (old_var) || + (readonly_p (old_var) && old_var->context == 0))) + { + if (readonly_p (old_var)) + sh_readonly (name); + else if (noassign_p (old_var)) + builtin_error (_("%s: variable may not be assigned value"), name); +#if 0 + /* Let noassign variables through with a warning */ + if (readonly_p (old_var)) +#endif + return ((SHELL_VAR *)NULL); + } + + if (old_var == 0) + new_var = make_new_variable (name, vc->table); + else + { + new_var = make_new_variable (name, vc->table); + + /* If we found this variable in one of the temporary environments, + inherit its value. Watch to see if this causes problems with + things like `x=4 local x'. XXX - see above for temporary env + variables with the same context level as variable_context */ + /* XXX - we should only do this if the variable is not an array. */ + if (was_tmpvar) + var_setvalue (new_var, savestring (tmp_value)); + + new_var->attributes = exported_p (old_var) ? att_exported : 0; + } + + vc->flags |= VC_HASLOCAL; + + new_var->context = variable_context; + VSETATTR (new_var, att_local); + + if (ifsname (name)) + setifs (new_var); + + if (was_tmpvar == 0 && no_invisible_vars == 0) + VSETATTR (new_var, att_invisible); /* XXX */ + return (new_var); +} + +/* Create a new shell variable with name NAME. */ +static SHELL_VAR * +new_shell_variable (name) + const char *name; +{ + SHELL_VAR *entry; + + entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); + + entry->name = savestring (name); + var_setvalue (entry, (char *)NULL); + CLEAR_EXPORTSTR (entry); + + entry->dynamic_value = (sh_var_value_func_t *)NULL; + entry->assign_func = (sh_var_assign_func_t *)NULL; + + entry->attributes = 0; + + /* Always assume variables are to be made at toplevel! + make_local_variable has the responsibility of changing the + variable context. */ + entry->context = 0; + + return (entry); +} + +/* Create a new shell variable with name NAME and add it to the hash table + TABLE. */ +static SHELL_VAR * +make_new_variable (name, table) + const char *name; + HASH_TABLE *table; +{ + SHELL_VAR *entry; + BUCKET_CONTENTS *elt; + + entry = new_shell_variable (name); + + /* Make sure we have a shell_variables hash table to add to. */ + if (shell_variables == 0) + create_variable_tables (); + + elt = hash_insert (savestring (name), table, HASH_NOSRCH); + elt->data = (PTR_T)entry; + + return entry; +} + +#if defined (ARRAY_VARS) +SHELL_VAR * +make_new_array_variable (name) + char *name; +{ + SHELL_VAR *entry; + ARRAY *array; + + entry = make_new_variable (name, global_variables->table); + array = array_create (); + + var_setarray (entry, array); + VSETATTR (entry, att_array); + return entry; +} + +SHELL_VAR * +make_local_array_variable (name, assoc_ok) + char *name; + int assoc_ok; +{ + SHELL_VAR *var; + ARRAY *array; + + var = make_local_variable (name); + if (var == 0 || array_p (var) || (assoc_ok && assoc_p (var))) + return var; + + array = array_create (); + + dispose_variable_value (var); + var_setarray (var, array); + VSETATTR (var, att_array); + return var; +} + +SHELL_VAR * +make_new_assoc_variable (name) + char *name; +{ + SHELL_VAR *entry; + HASH_TABLE *hash; + + entry = make_new_variable (name, global_variables->table); + hash = assoc_create (0); + + var_setassoc (entry, hash); + VSETATTR (entry, att_assoc); + return entry; +} + +SHELL_VAR * +make_local_assoc_variable (name) + char *name; +{ + SHELL_VAR *var; + HASH_TABLE *hash; + + var = make_local_variable (name); + if (var == 0 || assoc_p (var)) + return var; + + dispose_variable_value (var); + hash = assoc_create (0); + + var_setassoc (var, hash); + VSETATTR (var, att_assoc); + return var; +} +#endif + +char * +make_variable_value (var, value, flags) + SHELL_VAR *var; + char *value; + int flags; +{ + char *retval, *oval; + intmax_t lval, rval; + int expok, olen, op; + + /* If this variable has had its type set to integer (via `declare -i'), + then do expression evaluation on it and store the result. The + functions in expr.c (evalexp()) and bind_int_variable() are responsible + for turning off the integer flag if they don't want further + evaluation done. */ + if (integer_p (var)) + { + if (flags & ASS_APPEND) + { + oval = value_cell (var); + lval = evalexp (oval, &expok); /* ksh93 seems to do this */ + if (expok == 0) + { + top_level_cleanup (); + jump_to_top_level (DISCARD); + } + } + rval = evalexp (value, &expok); + if (expok == 0) + { + top_level_cleanup (); + jump_to_top_level (DISCARD); + } + /* This can be fooled if the variable's value changes while evaluating + `rval'. We can change it if we move the evaluation of lval to here. */ + if (flags & ASS_APPEND) + rval += lval; + retval = itos (rval); + } +#if defined (CASEMOD_ATTRS) + else if (capcase_p (var) || uppercase_p (var) || lowercase_p (var)) + { + if (flags & ASS_APPEND) + { + oval = get_variable_value (var); + if (oval == 0) /* paranoia */ + oval = ""; + olen = STRLEN (oval); + retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1); + strcpy (retval, oval); + if (value) + strcpy (retval+olen, value); + } + else if (*value) + retval = savestring (value); + else + { + retval = (char *)xmalloc (1); + retval[0] = '\0'; + } + op = capcase_p (var) ? CASE_CAPITALIZE + : (uppercase_p (var) ? CASE_UPPER : CASE_LOWER); + oval = sh_modcase (retval, (char *)0, op); + free (retval); + retval = oval; + } +#endif /* CASEMOD_ATTRS */ + else if (value) + { + if (flags & ASS_APPEND) + { + oval = get_variable_value (var); + if (oval == 0) /* paranoia */ + oval = ""; + olen = STRLEN (oval); + retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1); + strcpy (retval, oval); + if (value) + strcpy (retval+olen, value); + } + else if (*value) + retval = savestring (value); + else + { + retval = (char *)xmalloc (1); + retval[0] = '\0'; + } + } + else + retval = (char *)NULL; + + return retval; +} + +/* Bind a variable NAME to VALUE in the HASH_TABLE TABLE, which may be the + temporary environment (but usually is not). */ +static SHELL_VAR * +bind_variable_internal (name, value, table, hflags, aflags) + const char *name; + char *value; + HASH_TABLE *table; + int hflags, aflags; +{ + char *newval; + SHELL_VAR *entry; + + entry = (hflags & HASH_NOSRCH) ? (SHELL_VAR *)NULL : hash_lookup (name, table); + /* Follow the nameref chain here if this is the global variables table */ + if (entry && nameref_p (entry) && (invisible_p (entry) == 0) && table == global_variables->table) + { + entry = find_global_variable (entry->name); + /* Let's see if we have a nameref referencing a variable that hasn't yet + been created. */ + if (entry == 0) + entry = find_variable_last_nameref (name); /* XXX */ + if (entry == 0) /* just in case */ + return (entry); + } + + /* The first clause handles `declare -n ref; ref=x;' */ + if (entry && invisible_p (entry) && nameref_p (entry)) + goto assign_value; + else if (entry && nameref_p (entry)) + { + newval = nameref_cell (entry); +#if defined (ARRAY_VARS) + /* declare -n foo=x[2] */ + if (valid_array_reference (newval)) + /* XXX - should it be aflags? */ + entry = assign_array_element (newval, make_variable_value (entry, value, 0), aflags); + else +#endif + { + entry = make_new_variable (newval, table); + var_setvalue (entry, make_variable_value (entry, value, 0)); + } + } + else if (entry == 0) + { + entry = make_new_variable (name, table); + var_setvalue (entry, make_variable_value (entry, value, 0)); /* XXX */ + } + else if (entry->assign_func) /* array vars have assign functions now */ + { + INVALIDATE_EXPORTSTR (entry); + newval = (aflags & ASS_APPEND) ? make_variable_value (entry, value, aflags) : value; + if (assoc_p (entry)) + entry = (*(entry->assign_func)) (entry, newval, -1, savestring ("0")); + else if (array_p (entry)) + entry = (*(entry->assign_func)) (entry, newval, 0, 0); + else + entry = (*(entry->assign_func)) (entry, newval, -1, 0); + if (newval != value) + free (newval); + return (entry); + } + else + { +assign_value: + if (readonly_p (entry) || noassign_p (entry)) + { + if (readonly_p (entry)) + err_readonly (name); + return (entry); + } + + /* Variables which are bound are visible. */ + VUNSETATTR (entry, att_invisible); + +#if defined (ARRAY_VARS) + if (assoc_p (entry) || array_p (entry)) + newval = make_array_variable_value (entry, 0, "0", value, aflags); + else +#endif + + newval = make_variable_value (entry, value, aflags); /* XXX */ + + /* 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 + `read x' or something of that nature, silently convert it to + x[0]=b or `read x[0]'. */ + if (assoc_p (entry)) + { + assoc_insert (assoc_cell (entry), savestring ("0"), newval); + free (newval); + } + else if (array_p (entry)) + { + array_insert (array_cell (entry), 0, newval); + free (newval); + } + else +#endif + { + FREE (value_cell (entry)); + var_setvalue (entry, newval); + } + } + + if (mark_modified_vars) + VSETATTR (entry, att_exported); + + if (exported_p (entry)) + array_needs_making = 1; + + return (entry); +} + +/* Bind a variable NAME to VALUE. This conses up the name + and value strings. If we have a temporary environment, we bind there + first, then we bind into shell_variables. */ + +SHELL_VAR * +bind_variable (name, value, flags) + const char *name; + char *value; + int flags; +{ + SHELL_VAR *v, *nv; + VAR_CONTEXT *vc, *nvc; + int level; + char *newname; + + if (shell_variables == 0) + create_variable_tables (); + + /* If we have a temporary environment, look there first for the variable, + and, if found, modify the value there before modifying it in the + shell_variables table. This allows sourced scripts to modify values + given to them in a temporary environment while modifying the variable + value that the caller sees. */ + if (temporary_env) + bind_tempenv_variable (name, value); + + /* XXX -- handle local variables here. */ + for (vc = shell_variables; vc; vc = vc->down) + { + if (vc_isfuncenv (vc) || vc_isbltnenv (vc)) + { + v = hash_lookup (name, vc->table); + nvc = vc; + if (v && nameref_p (v)) + { + nv = find_variable_nameref_context (v, vc, &nvc); + if (nv == 0) + { + nv = find_variable_last_nameref_context (v, vc, &nvc); + if (nv && nameref_p (nv)) + { + /* If this nameref variable doesn't have a value yet, + set the value. Otherwise, assign using the value as + normal. */ + if (nameref_cell (nv) == 0) + return (bind_variable_internal (nv->name, value, nvc->table, 0, flags)); +#if defined (ARRAY_VARS) + else if (valid_array_reference (nameref_cell (nv))) + return (assign_array_element (nameref_cell (nv), value, flags)); + else +#endif + return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags)); + } + else + v = nv; + } + else + v = nv; + } + if (v) + return (bind_variable_internal (v->name, value, nvc->table, 0, flags)); + } + } + /* bind_variable_internal will handle nameref resolution in this case */ + return (bind_variable_internal (name, value, global_variables->table, 0, flags)); +} + +SHELL_VAR * +bind_global_variable (name, value, flags) + const char *name; + char *value; + int flags; +{ + SHELL_VAR *v, *nv; + VAR_CONTEXT *vc, *nvc; + int level; + + if (shell_variables == 0) + create_variable_tables (); + + /* bind_variable_internal will handle nameref resolution in this case */ + return (bind_variable_internal (name, value, global_variables->table, 0, flags)); +} + +/* 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, aflags) + SHELL_VAR *var; + char *value; + int aflags; +{ + char *t; + int invis; + + invis = invisible_p (var); + VUNSETATTR (var, att_invisible); + + if (var->assign_func) + { + /* If we're appending, we need the old value, so use + make_variable_value */ + t = (aflags & ASS_APPEND) ? make_variable_value (var, value, aflags) : value; + (*(var->assign_func)) (var, t, -1, 0); + if (t != value && t) + free (t); + } + else + { + t = make_variable_value (var, value, aflags); +#if defined (ARRAY_VARS) + if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || (legal_identifier (t) == 0 && valid_array_reference (t) == 0))) +#else + if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || legal_identifier (t) == 0)) +#endif + { + free (t); + if (invis) + VSETATTR (var, att_invisible); /* XXX */ + return ((SHELL_VAR *)NULL); + } + FREE (value_cell (var)); + var_setvalue (var, 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, isarr, implicitarray; + + isint = isarr = implicitarray = 0; +#if defined (ARRAY_VARS) + if (valid_array_reference (lhs)) + { + isarr = 1; + v = array_variable_part (lhs, (char **)0, (int *)0); + } + else +#endif + v = find_variable (lhs); + + if (v) + { + isint = integer_p (v); + VUNSETATTR (v, att_integer); +#if defined (ARRAY_VARS) + if (array_p (v) && isarr == 0) + implicitarray = 1; +#endif + } + +#if defined (ARRAY_VARS) + if (isarr) + v = assign_array_element (lhs, rhs, 0); + else if (implicitarray) + v = bind_array_variable (lhs, 0, rhs, 0); + else +#endif + v = bind_variable (lhs, rhs, 0); + + if (v && isint) + VSETATTR (v, att_integer); + + VUNSETATTR (v, att_invisible); + + return (v); +} + +SHELL_VAR * +bind_var_to_int (var, val) + char *var; + intmax_t val; +{ + char ibuf[INT_STRLEN_BOUND (intmax_t) + 1], *p; + + p = fmtulong (val, 10, ibuf, sizeof (ibuf), 0); + return (bind_int_variable (var, p)); +} + +/* Do a function binding to a variable. You pass the name and + the command to bind to. This conses the name and command. */ +SHELL_VAR * +bind_function (name, value) + const char *name; + COMMAND *value; +{ + SHELL_VAR *entry; + + entry = find_function (name); + if (entry == 0) + { + BUCKET_CONTENTS *elt; + + elt = hash_insert (savestring (name), shell_functions, HASH_NOSRCH); + entry = new_shell_variable (name); + elt->data = (PTR_T)entry; + } + else + INVALIDATE_EXPORTSTR (entry); + + if (var_isset (entry)) + dispose_command (function_cell (entry)); + + if (value) + var_setfunc (entry, copy_command (value)); + else + var_setfunc (entry, 0); + + VSETATTR (entry, att_function); + + if (mark_modified_vars) + VSETATTR (entry, att_exported); + + 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); +} + +#if defined (DEBUGGER) +/* 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; + } +} +#endif /* DEBUGGER */ + +/* 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 + temporary environments. The expansion code in subst.c calls this. */ +int +assign_in_env (word, flags) + WORD_DESC *word; + int flags; +{ + int offset, aflags; + char *name, *temp, *value; + SHELL_VAR *var; + const char *string; + + string = word->word; + + aflags = 0; + offset = assignment (string, 0); + name = savestring (string); + value = (char *)NULL; + + if (name[offset] == '=') + { + name[offset] = 0; + + /* don't ignore the `+' when assigning temporary environment */ + if (name[offset - 1] == '+') + { + name[offset - 1] = '\0'; + aflags |= ASS_APPEND; + } + + var = find_variable (name); + if (var && (readonly_p (var) || noassign_p (var))) + { + if (readonly_p (var)) + err_readonly (name); + free (name); + return (0); + } + + temp = name + offset + 1; + value = expand_assignment_string_to_string (temp, 0); + + if (var && (aflags & ASS_APPEND)) + { + temp = make_variable_value (var, value, aflags); + FREE (value); + value = temp; + } + } + + if (temporary_env == 0) + temporary_env = hash_create (TEMPENV_HASH_BUCKETS); + + var = hash_lookup (name, temporary_env); + if (var == 0) + var = make_new_variable (name, temporary_env); + else + FREE (value_cell (var)); + + if (value == 0) + { + value = (char *)xmalloc (1); /* like do_assignment_internal */ + value[0] = '\0'; + } + + var_setvalue (var, value); + var->attributes |= (att_exported|att_tempvar); + var->context = variable_context; /* XXX */ + + INVALIDATE_EXPORTSTR (var); + var->exportstr = mk_env_string (name, value); + + array_needs_making = 1; + + if (flags) + stupidly_hack_special_variables (name); + + if (echo_command_at_execute) + /* 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; +} + +/* **************************************************************** */ +/* */ +/* Copying variables */ +/* */ +/* **************************************************************** */ + +#ifdef INCLUDE_UNUSED +/* Copy VAR to a new data structure and return that structure. */ +SHELL_VAR * +copy_variable (var) + SHELL_VAR *var; +{ + SHELL_VAR *copy = (SHELL_VAR *)NULL; + + if (var) + { + copy = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); + + copy->attributes = var->attributes; + copy->name = savestring (var->name); + + if (function_p (var)) + var_setfunc (copy, copy_command (function_cell (var))); +#if defined (ARRAY_VARS) + else if (array_p (var)) + var_setarray (copy, array_copy (array_cell (var))); + else if (assoc_p (var)) + var_setassoc (copy, assoc_copy (assoc_cell (var))); +#endif + else if (nameref_cell (var)) /* XXX - nameref */ + var_setref (copy, savestring (nameref_cell (var))); + else if (value_cell (var)) /* XXX - nameref */ + var_setvalue (copy, savestring (value_cell (var))); + else + var_setvalue (copy, (char *)NULL); + + copy->dynamic_value = var->dynamic_value; + copy->assign_func = var->assign_func; + + copy->exportstr = COPY_EXPORTSTR (var); + + copy->context = var->context; + } + return (copy); +} +#endif + +/* **************************************************************** */ +/* */ +/* Deleting and unsetting variables */ +/* */ +/* **************************************************************** */ + +/* Dispose of the information attached to VAR. */ +static void +dispose_variable_value (var) + SHELL_VAR *var; +{ + if (function_p (var)) + dispose_command (function_cell (var)); +#if defined (ARRAY_VARS) + else if (array_p (var)) + array_dispose (array_cell (var)); + else if (assoc_p (var)) + assoc_dispose (assoc_cell (var)); +#endif + else if (nameref_p (var)) + FREE (nameref_cell (var)); + else + FREE (value_cell (var)); +} + +void +dispose_variable (var) + SHELL_VAR *var; +{ + if (var == 0) + return; + + if (nofree_p (var) == 0) + dispose_variable_value (var); + + FREE_EXPORTSTR (var); + + free (var->name); + + if (exported_p (var)) + array_needs_making = 1; + + free (var); +} + +/* Unset the shell variable referenced by NAME. Unsetting a nameref variable + unsets the variable it resolves to but leaves the nameref alone. */ +int +unbind_variable (name) + const char *name; +{ + SHELL_VAR *v, *nv; + int r; + + v = var_lookup (name, shell_variables); + nv = (v && nameref_p (v)) ? find_variable_nameref (v) : (SHELL_VAR *)NULL; + + r = nv ? makunbound (nv->name, shell_variables) : makunbound (name, shell_variables); + return r; +} + +/* Unbind NAME, where NAME is assumed to be a nameref variable */ +int +unbind_nameref (name) + const char *name; +{ + SHELL_VAR *v; + + v = var_lookup (name, shell_variables); + if (v && nameref_p (v)) + return makunbound (name, shell_variables); + return 0; +} + +/* Unset the shell function named NAME. */ +int +unbind_func (name) + const char *name; +{ + BUCKET_CONTENTS *elt; + SHELL_VAR *func; + + elt = hash_remove (name, shell_functions, 0); + + if (elt == 0) + return -1; + +#if defined (PROGRAMMABLE_COMPLETION) + set_itemlist_dirty (&it_functions); +#endif + + func = (SHELL_VAR *)elt->data; + if (func) + { + if (exported_p (func)) + array_needs_making++; + dispose_variable (func); + } + + free (elt->key); + free (elt); + + return 0; +} + +#if defined (DEBUGGER) +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; +} +#endif /* DEBUGGER */ + +int +delete_var (name, vc) + const char *name; + VAR_CONTEXT *vc; +{ + BUCKET_CONTENTS *elt; + SHELL_VAR *old_var; + VAR_CONTEXT *v; + + for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down) + if (elt = hash_remove (name, v->table, 0)) + break; + + if (elt == 0) + return (-1); + + old_var = (SHELL_VAR *)elt->data; + free (elt->key); + free (elt); + + dispose_variable (old_var); + 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). + Returns non-zero if the variable couldn't be found. */ +int +makunbound (name, vc) + const char *name; + VAR_CONTEXT *vc; +{ + BUCKET_CONTENTS *elt, *new_elt; + SHELL_VAR *old_var; + VAR_CONTEXT *v; + char *t; + + for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down) + if (elt = hash_remove (name, v->table, 0)) + break; + + if (elt == 0) + return (-1); + + old_var = (SHELL_VAR *)elt->data; + + if (old_var && exported_p (old_var)) + array_needs_making++; + + /* If we're unsetting a local variable and we're still executing inside + the function, just mark the variable as invisible. The function + eventually called by pop_var_context() will clean it up later. This + must be done so that if the variable is subsequently assigned a new + value inside the function, the `local' attribute is still present. + We also need to add it back into the correct hash table. */ + if (old_var && local_p (old_var) && variable_context == old_var->context) + { + if (nofree_p (old_var)) + var_setvalue (old_var, (char *)NULL); +#if defined (ARRAY_VARS) + else if (array_p (old_var)) + array_dispose (array_cell (old_var)); + else if (assoc_p (old_var)) + assoc_dispose (assoc_cell (old_var)); +#endif + else if (nameref_p (old_var)) + FREE (nameref_cell (old_var)); + else + FREE (value_cell (old_var)); + /* 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); + var_setvalue (old_var, (char *)NULL); + INVALIDATE_EXPORTSTR (old_var); + + new_elt = hash_insert (savestring (old_var->name), v->table, 0); + new_elt->data = (PTR_T)old_var; + stupidly_hack_special_variables (old_var->name); + + free (elt->key); + free (elt); + return (0); + } + + /* Have to save a copy of name here, because it might refer to + old_var->name. If so, stupidly_hack_special_variables will + reference freed memory. */ + t = savestring (name); + + free (elt->key); + free (elt); + + dispose_variable (old_var); + stupidly_hack_special_variables (t); + free (t); + + return (0); +} + +/* Get rid of all of the variables in the current context. */ +void +kill_all_local_variables () +{ + VAR_CONTEXT *vc; + + for (vc = shell_variables; vc; vc = vc->down) + if (vc_isfuncenv (vc) && vc->scope == variable_context) + break; + if (vc == 0) + return; /* XXX */ + + if (vc->table && vc_haslocals (vc)) + { + delete_all_variables (vc->table); + hash_dispose (vc->table); + } + vc->table = (HASH_TABLE *)NULL; +} + +static void +free_variable_hash_data (data) + PTR_T data; +{ + SHELL_VAR *var; + + var = (SHELL_VAR *)data; + dispose_variable (var); +} + +/* Delete the entire contents of the hash table. */ +void +delete_all_variables (hashed_vars) + HASH_TABLE *hashed_vars; +{ + hash_flush (hashed_vars, free_variable_hash_data); +} + +/* **************************************************************** */ +/* */ +/* Setting variable attributes */ +/* */ +/* **************************************************************** */ + +#define FIND_OR_MAKE_VARIABLE(name, entry) \ + do \ + { \ + entry = find_variable (name); \ + if (!entry) \ + { \ + entry = bind_variable (name, "", 0); \ + if (!no_invisible_vars && entry) entry->attributes |= att_invisible; \ + } \ + } \ + while (0) + +/* Make the variable associated with NAME be readonly. + If NAME does not exist yet, create it. */ +void +set_var_read_only (name) + char *name; +{ + SHELL_VAR *entry; + + FIND_OR_MAKE_VARIABLE (name, entry); + VSETATTR (entry, 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 +set_func_read_only (name) + const char *name; +{ + SHELL_VAR *entry; + + entry = find_function (name); + if (entry) + VSETATTR (entry, att_readonly); +} + +/* Make the variable associated with NAME be auto-exported. + If NAME does not exist yet, create it. */ +void +set_var_auto_export (name) + char *name; +{ + SHELL_VAR *entry; + + FIND_OR_MAKE_VARIABLE (name, entry); + set_auto_export (entry); +} + +/* Make the function associated with NAME be auto-exported. */ +void +set_func_auto_export (name) + const char *name; +{ + SHELL_VAR *entry; + + entry = find_function (name); + if (entry) + set_auto_export (entry); +} +#endif + +/* **************************************************************** */ +/* */ +/* Creating lists of variables */ +/* */ +/* **************************************************************** */ + +static VARLIST * +vlist_alloc (nentries) + int nentries; +{ + VARLIST *vlist; + + vlist = (VARLIST *)xmalloc (sizeof (VARLIST)); + vlist->list = (SHELL_VAR **)xmalloc ((nentries + 1) * sizeof (SHELL_VAR *)); + vlist->list_size = nentries; + vlist->list_len = 0; + vlist->list[0] = (SHELL_VAR *)NULL; + + return vlist; +} + +static VARLIST * +vlist_realloc (vlist, n) + VARLIST *vlist; + int n; +{ + if (vlist == 0) + return (vlist = vlist_alloc (n)); + if (n > vlist->list_size) + { + vlist->list_size = n; + vlist->list = (SHELL_VAR **)xrealloc (vlist->list, (vlist->list_size + 1) * sizeof (SHELL_VAR *)); + } + return vlist; +} + +static void +vlist_add (vlist, var, flags) + VARLIST *vlist; + SHELL_VAR *var; + int flags; +{ + register int i; + + for (i = 0; i < vlist->list_len; i++) + if (STREQ (var->name, vlist->list[i]->name)) + break; + if (i < vlist->list_len) + return; + + if (i >= vlist->list_size) + vlist = vlist_realloc (vlist, vlist->list_size + 16); + + vlist->list[vlist->list_len++] = var; + vlist->list[vlist->list_len] = (SHELL_VAR *)NULL; +} + +/* Map FUNCTION over the variables in VAR_HASH_TABLE. Return an array of the + variables for which FUNCTION returns a non-zero value. A NULL value + for FUNCTION means to use all variables. */ +SHELL_VAR ** +map_over (function, vc) + sh_var_map_func_t *function; + VAR_CONTEXT *vc; +{ + VAR_CONTEXT *v; + VARLIST *vlist; + SHELL_VAR **ret; + int nentries; + + for (nentries = 0, v = vc; v; v = v->down) + nentries += HASH_ENTRIES (v->table); + + if (nentries == 0) + return (SHELL_VAR **)NULL; + + vlist = vlist_alloc (nentries); + + for (v = vc; v; v = v->down) + flatten (v->table, function, vlist, 0); + + ret = vlist->list; + free (vlist); + return ret; +} + +SHELL_VAR ** +map_over_funcs (function) + sh_var_map_func_t *function; +{ + VARLIST *vlist; + SHELL_VAR **ret; + + if (shell_functions == 0 || HASH_ENTRIES (shell_functions) == 0) + return ((SHELL_VAR **)NULL); + + vlist = vlist_alloc (HASH_ENTRIES (shell_functions)); + + flatten (shell_functions, function, vlist, 0); + + ret = vlist->list; + free (vlist); + return ret; +} + +/* Flatten VAR_HASH_TABLE, applying FUNC to each member and adding those + elements for which FUNC succeeds to VLIST->list. FLAGS is reserved + for future use. Only unique names are added to VLIST. If FUNC is + NULL, each variable in VAR_HASH_TABLE is added to VLIST. If VLIST is + NULL, FUNC is applied to each SHELL_VAR in VAR_HASH_TABLE. If VLIST + and FUNC are both NULL, nothing happens. */ +static void +flatten (var_hash_table, func, vlist, flags) + HASH_TABLE *var_hash_table; + sh_var_map_func_t *func; + VARLIST *vlist; + int flags; +{ + register int i; + register BUCKET_CONTENTS *tlist; + int r; + SHELL_VAR *var; + + if (var_hash_table == 0 || (HASH_ENTRIES (var_hash_table) == 0) || (vlist == 0 && func == 0)) + return; + + for (i = 0; i < var_hash_table->nbuckets; i++) + { + for (tlist = hash_items (i, var_hash_table); tlist; tlist = tlist->next) + { + var = (SHELL_VAR *)tlist->data; + + r = func ? (*func) (var) : 1; + if (r && vlist) + vlist_add (vlist, var, flags); + } + } +} + +void +sort_variables (array) + SHELL_VAR **array; +{ + qsort (array, strvec_len ((char **)array), sizeof (SHELL_VAR *), (QSFUNC *)qsort_var_comp); +} + +static int +qsort_var_comp (var1, var2) + SHELL_VAR **var1, **var2; +{ + int result; + + if ((result = (*var1)->name[0] - (*var2)->name[0]) == 0) + result = strcmp ((*var1)->name, (*var2)->name); + + return (result); +} + +/* Apply FUNC to each variable in SHELL_VARIABLES, adding each one for + which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */ +static SHELL_VAR ** +vapply (func) + sh_var_map_func_t *func; +{ + SHELL_VAR **list; + + list = map_over (func, shell_variables); + if (list /* && posixly_correct */) + sort_variables (list); + return (list); +} + +/* Apply FUNC to each variable in SHELL_FUNCTIONS, adding each one for + which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */ +static SHELL_VAR ** +fapply (func) + sh_var_map_func_t *func; +{ + SHELL_VAR **list; + + list = map_over_funcs (func); + if (list /* && posixly_correct */) + sort_variables (list); + return (list); +} + +/* Create a NULL terminated array of all the shell variables. */ +SHELL_VAR ** +all_shell_variables () +{ + return (vapply ((sh_var_map_func_t *)NULL)); +} + +/* Create a NULL terminated array of all the shell functions. */ +SHELL_VAR ** +all_shell_functions () +{ + return (fapply ((sh_var_map_func_t *)NULL)); +} + +static int +visible_var (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0); +} + +SHELL_VAR ** +all_visible_functions () +{ + return (fapply (visible_var)); +} + +SHELL_VAR ** +all_visible_variables () +{ + return (vapply (visible_var)); +} + +/* Return non-zero if the variable VAR is visible and exported. Array + variables cannot be exported. */ +static int +visible_and_exported (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0 && exported_p (var)); +} + +/* Candidate variables for the export environment are either valid variables + with the export attribute or invalid variables inherited from the initial + environment and simply passed through. */ +static int +export_environment_candidate (var) + SHELL_VAR *var; +{ + return (exported_p (var) && (invisible_p (var) == 0 || imported_p (var))); +} + +/* Return non-zero if VAR is a local variable in the current context and + is exported. */ +static int +local_and_exported (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context && exported_p (var)); +} + +SHELL_VAR ** +all_exported_variables () +{ + return (vapply (visible_and_exported)); +} + +SHELL_VAR ** +local_exported_variables () +{ + return (vapply (local_and_exported)); +} + +static int +variable_in_context (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context); +} + +SHELL_VAR ** +all_local_variables () +{ + VARLIST *vlist; + SHELL_VAR **ret; + VAR_CONTEXT *vc; + + vc = shell_variables; + for (vc = shell_variables; vc; vc = vc->down) + if (vc_isfuncenv (vc) && vc->scope == variable_context) + break; + + if (vc == 0) + { + 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) + return (SHELL_VAR **)NULL; + + vlist = vlist_alloc (HASH_ENTRIES (vc->table)); + + flatten (vc->table, variable_in_context, vlist, 0); + + ret = vlist->list; + free (vlist); + if (ret) + sort_variables (ret); + return ret; +} + +#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 () +{ + return (vapply (visible_array_vars)); +} +#endif /* ARRAY_VARS */ + +char ** +all_variables_matching_prefix (prefix) + const 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 = strvec_create (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; +} + +/* **************************************************************** */ +/* */ +/* Managing temporary variable scopes */ +/* */ +/* **************************************************************** */ + +/* Make variable NAME have VALUE in the temporary environment. */ +static SHELL_VAR * +bind_tempenv_variable (name, value) + const char *name; + char *value; +{ + SHELL_VAR *var; + + var = temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL; + + if (var) + { + FREE (value_cell (var)); + var_setvalue (var, savestring (value)); + INVALIDATE_EXPORTSTR (var); + } + + return (var); +} + +/* Find a variable in the temporary environment that is named NAME. + Return the SHELL_VAR *, or NULL if not found. */ +SHELL_VAR * +find_tempenv_variable (name) + const char *name; +{ + return (temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL); +} + +char **tempvar_list; +int tvlist_ind; + +/* Push the variable described by (SHELL_VAR *)DATA down to the next + variable context from the temporary environment. */ +static void +push_temp_var (data) + PTR_T data; +{ + SHELL_VAR *var, *v; + HASH_TABLE *binding_table; + + var = (SHELL_VAR *)data; + + binding_table = shell_variables->table; + if (binding_table == 0) + { + if (shell_variables == global_variables) + /* shouldn't happen */ + binding_table = shell_variables->table = global_variables->table = hash_create (0); + else + binding_table = shell_variables->table = hash_create (TEMPENV_HASH_BUCKETS); + } + + v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, 0); + + /* XXX - should we set the context here? It shouldn't matter because of how + assign_in_env works, but might want to check. */ + if (binding_table == global_variables->table) /* XXX */ + var->attributes &= ~(att_tempvar|att_propagate); + else + { + var->attributes |= att_propagate; + if (binding_table == shell_variables->table) + shell_variables->flags |= VC_HASTMPVAR; + } + v->attributes |= var->attributes; + + if (find_special_var (var->name) >= 0) + tempvar_list[tvlist_ind++] = savestring (var->name); + + dispose_variable (var); +} + +static void +propagate_temp_var (data) + PTR_T data; +{ + SHELL_VAR *var; + + var = (SHELL_VAR *)data; + if (tempvar_p (var) && (var->attributes & att_propagate)) + push_temp_var (data); + else + { + if (find_special_var (var->name) >= 0) + tempvar_list[tvlist_ind++] = savestring (var->name); + dispose_variable (var); + } +} + +/* Free the storage used in the hash table for temporary + environment variables. PUSHF is a function to be called + to free each hash table entry. It takes care of pushing variables + to previous scopes if appropriate. PUSHF stores names of variables + that require special handling (e.g., IFS) on tempvar_list, so this + function can call stupidly_hack_special_variables on all the + variables in the list when the temporary hash table is destroyed. */ +static void +dispose_temporary_env (pushf) + sh_free_func_t *pushf; +{ + int i; + + tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1); + tempvar_list[tvlist_ind = 0] = 0; + + hash_flush (temporary_env, pushf); + hash_dispose (temporary_env); + temporary_env = (HASH_TABLE *)NULL; + + tempvar_list[tvlist_ind] = 0; + + array_needs_making = 1; + +#if 0 + sv_ifs ("IFS"); /* XXX here for now -- check setifs in assign_in_env */ +#endif + for (i = 0; i < tvlist_ind; i++) + stupidly_hack_special_variables (tempvar_list[i]); + + strvec_dispose (tempvar_list); + tempvar_list = 0; + tvlist_ind = 0; +} + +void +dispose_used_env_vars () +{ + if (temporary_env) + { + dispose_temporary_env (propagate_temp_var); + maybe_make_export_env (); + } +} + +/* Take all of the shell variables in the temporary environment HASH_TABLE + and make shell variables from them at the current variable context. */ +void +merge_temporary_env () +{ + if (temporary_env) + dispose_temporary_env (push_temp_var); +} + +/* **************************************************************** */ +/* */ +/* Creating and manipulating the environment */ +/* */ +/* **************************************************************** */ + +static inline char * +mk_env_string (name, value) + const char *name, *value; +{ + int name_len, value_len; + char *p; + + name_len = strlen (name); + value_len = STRLEN (value); + p = (char *)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); +} + +#ifdef DEBUG +/* Debugging */ +static int +valid_exportstr (v) + SHELL_VAR *v; +{ + char *s; + + s = v->exportstr; + if (s == 0) + { + internal_error (_("%s has null exportstr"), v->name); + return (0); + } + if (legal_variable_starter ((unsigned char)*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 ((unsigned 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); +} +#endif + +static char ** +make_env_array_from_var_list (vars) + SHELL_VAR **vars; +{ + register int i, list_index; + register SHELL_VAR *var; + char **list, *value; + + list = strvec_create ((1 + strvec_len ((char **)vars))); + +#define USE_EXPORTSTR (value == var->exportstr) + + for (i = 0, list_index = 0; var = vars[i]; i++) + { +#if defined (__CYGWIN__) + /* We don't use the exportstr stuff on Cygwin at all. */ + INVALIDATE_EXPORTSTR (var); +#endif + if (var->exportstr) + value = var->exportstr; + else if (function_p (var)) + value = named_function_string ((char *)NULL, function_cell (var), 0); +#if defined (ARRAY_VARS) + else if (array_p (var)) +# if ARRAY_EXPORT + value = array_to_assignment_string (array_cell (var)); +# else + continue; /* XXX array vars cannot yet be exported */ +# endif /* ARRAY_EXPORT */ + else if (assoc_p (var)) +# if 0 + value = assoc_to_assignment_string (assoc_cell (var)); +# else + continue; /* XXX associative array vars cannot yet be exported */ +# endif +#endif + else + value = value_cell (var); + + if (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) + SAVE_EXPORTSTR (var, list[list_index]); + + list_index++; +#undef USE_EXPORTSTR + +#if 0 /* not yet */ +#if defined (ARRAY_VARS) + if (array_p (var) || assoc_p (var)) + free (value); +#endif +#endif + } + } + + list[list_index] = (char *)NULL; + return (list); +} + +/* Make an array of assignment statements from the hash table + HASHED_VARS which contains SHELL_VARs. Only visible, exported + variables are eligible. */ +static char ** +make_var_export_array (vcxt) + VAR_CONTEXT *vcxt; +{ + char **list; + SHELL_VAR **vars; + +#if 0 + vars = map_over (visible_and_exported, vcxt); +#else + vars = map_over (export_environment_candidate, vcxt); +#endif + + if (vars == 0) + return (char **)NULL; + + list = make_env_array_from_var_list (vars); + + free (vars); + return (list); +} + +static char ** +make_func_export_array () +{ + char **list; + SHELL_VAR **vars; + + vars = map_over_funcs (visible_and_exported); + if (vars == 0) + return (char **)NULL; + + list = make_env_array_from_var_list (vars); + + free (vars); + return (list); +} + +/* Add ENVSTR to the end of the exported environment, EXPORT_ENV. */ +#define add_to_export_env(envstr,do_alloc) \ +do \ + { \ + if (export_env_index >= (export_env_size - 1)) \ + { \ + export_env_size += 16; \ + export_env = strvec_resize (export_env, export_env_size); \ + environ = export_env; \ + } \ + export_env[export_env_index++] = (do_alloc) ? savestring (envstr) : envstr; \ + export_env[export_env_index] = (char *)NULL; \ + } while (0) + +/* Add ASSIGN to EXPORT_ENV, or supercede a previous assignment in the + array with the same left-hand side. Return the new EXPORT_ENV. */ +char ** +add_or_supercede_exported_var (assign, do_alloc) + char *assign; + int do_alloc; +{ + register int i; + int equal_offset; + + equal_offset = assignment (assign, 0); + if (equal_offset == 0) + return (export_env); + + /* If this is a function, then only supersede the function definition. + We do this by including the `=() {' in the comparison, like + initialize_shell_variables does. */ + if (assign[equal_offset + 1] == '(' && + strncmp (assign + equal_offset + 2, ") {", 3) == 0) /* } */ + equal_offset += 4; + + for (i = 0; i < export_env_index; i++) + { + if (STREQN (assign, export_env[i], equal_offset + 1)) + { + free (export_env[i]); + export_env[i] = do_alloc ? savestring (assign) : assign; + return (export_env); + } + } + add_to_export_env (assign, do_alloc); + return (export_env); +} + +static void +add_temp_array_to_env (temp_array, do_alloc, do_supercede) + char **temp_array; + int do_alloc, do_supercede; +{ + register int i; + + if (temp_array == 0) + return; + + for (i = 0; temp_array[i]; i++) + { + if (do_supercede) + export_env = add_or_supercede_exported_var (temp_array[i], do_alloc); + else + add_to_export_env (temp_array[i], do_alloc); + } + + free (temp_array); +} + +/* Make the environment array for the command about to be executed, if the + array needs making. Otherwise, do nothing. If a shell action could + change the array that commands receive for their environment, then the + code should `array_needs_making++'. + + The order to add to the array is: + temporary_env + list of var contexts whose head is shell_variables + shell_functions + + This is the shell variable lookup order. We add only new variable + names at each step, which allows local variables and variables in + the temporary environments to shadow variables in the global (or + any previous) scope. +*/ + +static int +n_shell_variables () +{ + VAR_CONTEXT *vc; + int n; + + for (n = 0, vc = shell_variables; vc; vc = vc->down) + n += HASH_ENTRIES (vc->table); + return n; +} + +int +chkexport (name) + char *name; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v && exported_p (v)) + { + array_needs_making = 1; + maybe_make_export_env (); + return 1; + } + return 0; +} + +void +maybe_make_export_env () +{ + register char **temp_array; + int new_size; + VAR_CONTEXT *tcxt; + + if (array_needs_making) + { + if (export_env) + strvec_flush (export_env); + + /* Make a guess based on how many shell variables and functions we + have. Since there will always be array variables, and array + variables are not (yet) exported, this will always be big enough + for the exported variables and functions. */ + new_size = n_shell_variables () + HASH_ENTRIES (shell_functions) + 1 + + HASH_ENTRIES (temporary_env); + if (new_size > export_env_size) + { + export_env_size = new_size; + export_env = strvec_resize (export_env, export_env_size); + environ = export_env; + } + export_env[export_env_index = 0] = (char *)NULL; + + /* Make a dummy variable context from the temporary_env, stick it on + the front of shell_variables, call make_var_export_array on the + whole thing to flatten it, and convert the list of SHELL_VAR *s + to the form needed by the environment. */ + if (temporary_env) + { + tcxt = new_var_context ((char *)NULL, 0); + tcxt->table = temporary_env; + tcxt->down = shell_variables; + } + else + tcxt = shell_variables; + + temp_array = make_var_export_array (tcxt); + if (temp_array) + add_temp_array_to_env (temp_array, 0, 0); + + if (tcxt != shell_variables) + free (tcxt); + +#if defined (RESTRICTED_SHELL) + /* Restricted shells may not export shell functions. */ + temp_array = restricted ? (char **)0 : make_func_export_array (); +#else + temp_array = make_func_export_array (); +#endif + if (temp_array) + add_temp_array_to_env (temp_array, 0, 0); + + array_needs_making = 0; + } +} + +/* This is an efficiency hack. PWD and OLDPWD are auto-exported, so + we will need to remake the exported environment every time we + change directories. `_' is always put into the environment for + every external command, so without special treatment it will always + cause the environment to be remade. + + If there is no other reason to make the exported environment, we can + just update the variables in place and mark the exported environment + as no longer needing a remake. */ +void +update_export_env_inplace (env_prefix, preflen, value) + char *env_prefix; + int preflen; + char *value; +{ + char *evar; + + evar = (char *)xmalloc (STRLEN (value) + preflen + 1); + strcpy (evar, env_prefix); + if (value) + strcpy (evar + preflen, value); + export_env = add_or_supercede_exported_var (evar, 0); +} + +/* We always put _ in the environment as the name of this command. */ +void +put_command_name_into_env (command_name) + char *command_name; +{ + update_export_env_inplace ("_=", 2, command_name); +} + +/* **************************************************************** */ +/* */ +/* Managing variable contexts */ +/* */ +/* **************************************************************** */ + +/* Allocate and return a new variable context with NAME and FLAGS. + NAME can be NULL. */ + +VAR_CONTEXT * +new_var_context (name, flags) + char *name; + int flags; +{ + VAR_CONTEXT *vc; + + vc = (VAR_CONTEXT *)xmalloc (sizeof (VAR_CONTEXT)); + vc->name = name ? savestring (name) : (char *)NULL; + vc->scope = variable_context; + vc->flags = flags; + + vc->up = vc->down = (VAR_CONTEXT *)NULL; + vc->table = (HASH_TABLE *)NULL; + + return vc; +} + +/* Free a variable context and its data, including the hash table. Dispose + all of the variables. */ +void +dispose_var_context (vc) + VAR_CONTEXT *vc; +{ + FREE (vc->name); + + if (vc->table) + { + delete_all_variables (vc->table); + hash_dispose (vc->table); + } + + free (vc); +} + +/* Set VAR's scope level to the current variable context. */ +static int +set_context (var) + SHELL_VAR *var; +{ + return (var->context = variable_context); +} + +/* Make a new variable context with NAME and FLAGS and a HASH_TABLE of + temporary variables, and push it onto shell_variables. This is + for shell functions. */ +VAR_CONTEXT * +push_var_context (name, flags, tempvars) + char *name; + int flags; + HASH_TABLE *tempvars; +{ + VAR_CONTEXT *vc; + + vc = new_var_context (name, flags); + vc->table = tempvars; + if (tempvars) + { + /* Have to do this because the temp environment was created before + variable_context was incremented. */ + flatten (tempvars, set_context, (VARLIST *)NULL, 0); + vc->flags |= VC_HASTMPVAR; + } + vc->down = shell_variables; + shell_variables->up = vc; + + return (shell_variables = vc); +} + +static void +push_func_var (data) + PTR_T data; +{ + SHELL_VAR *var, *v; + + var = (SHELL_VAR *)data; + + if (tempvar_p (var) && (posixly_correct || (var->attributes & att_propagate))) + { + /* Make sure we have a hash table to store the variable in while it is + being propagated down to the global variables table. Create one if + we have to */ + if ((vc_isfuncenv (shell_variables) || vc_istempenv (shell_variables)) && shell_variables->table == 0) + shell_variables->table = hash_create (0); + /* XXX - should we set v->context here? */ + v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0); + if (shell_variables == global_variables) + var->attributes &= ~(att_tempvar|att_propagate); + else + shell_variables->flags |= VC_HASTMPVAR; + v->attributes |= var->attributes; + } + else + stupidly_hack_special_variables (var->name); /* XXX */ + + dispose_variable (var); +} + +/* Pop the top context off of VCXT and dispose of it, returning the rest of + the stack. */ +void +pop_var_context () +{ + VAR_CONTEXT *ret, *vcxt; + + vcxt = shell_variables; + if (vc_isfuncenv (vcxt) == 0) + { + internal_error (_("pop_var_context: head of shell_variables not a function context")); + return; + } + + if (ret = vcxt->down) + { + ret->up = (VAR_CONTEXT *)NULL; + shell_variables = ret; + if (vcxt->table) + hash_flush (vcxt->table, push_func_var); + dispose_var_context (vcxt); + } + else + internal_error (_("pop_var_context: no global_variables context")); +} + +/* Delete the HASH_TABLEs for all variable contexts beginning at VCXT, and + all of the VAR_CONTEXTs except GLOBAL_VARIABLES. */ +void +delete_all_contexts (vcxt) + VAR_CONTEXT *vcxt; +{ + VAR_CONTEXT *v, *t; + + for (v = vcxt; v != global_variables; v = t) + { + t = v->down; + dispose_var_context (v); + } + + delete_all_variables (global_variables->table); + shell_variables = global_variables; +} + +/* **************************************************************** */ +/* */ +/* Pushing and Popping temporary variable scopes */ +/* */ +/* **************************************************************** */ + +VAR_CONTEXT * +push_scope (flags, tmpvars) + int flags; + HASH_TABLE *tmpvars; +{ + return (push_var_context ((char *)NULL, flags, tmpvars)); +} + +static void +push_exported_var (data) + PTR_T data; +{ + SHELL_VAR *var, *v; + + var = (SHELL_VAR *)data; + + /* If a temp var had its export attribute set, or it's marked to be + propagated, bind it in the previous scope before disposing it. */ + /* XXX - This isn't exactly right, because all tempenv variables have the + export attribute set. */ +#if 0 + if (exported_p (var) || (var->attributes & att_propagate)) +#else + if (tempvar_p (var) && exported_p (var) && (var->attributes & att_propagate)) +#endif + { + var->attributes &= ~att_tempvar; /* XXX */ + v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0); + if (shell_variables == global_variables) + var->attributes &= ~att_propagate; + v->attributes |= var->attributes; + } + else + stupidly_hack_special_variables (var->name); /* XXX */ + + dispose_variable (var); +} + +void +pop_scope (is_special) + int is_special; +{ + VAR_CONTEXT *vcxt, *ret; + + vcxt = shell_variables; + if (vc_istempscope (vcxt) == 0) + { + internal_error (_("pop_scope: head of shell_variables not a temporary environment scope")); + return; + } + + ret = vcxt->down; + if (ret) + ret->up = (VAR_CONTEXT *)NULL; + + shell_variables = ret; + + /* Now we can take care of merging variables in VCXT into set of scopes + whose head is RET (shell_variables). */ + FREE (vcxt->name); + if (vcxt->table) + { + if (is_special) + hash_flush (vcxt->table, push_func_var); + else + hash_flush (vcxt->table, push_exported_var); + hash_dispose (vcxt->table); + } + free (vcxt); + + sv_ifs ("IFS"); /* XXX here for now */ +} + +/* **************************************************************** */ +/* */ +/* Pushing and Popping function contexts */ +/* */ +/* **************************************************************** */ + +static WORD_LIST **dollar_arg_stack = (WORD_LIST **)NULL; +static int dollar_arg_stack_slots; +static int dollar_arg_stack_index; + +/* XXX - we might want to consider pushing and popping the `getopts' state + when we modify the positional parameters. */ +void +push_context (name, is_subshell, tempvars) + char *name; /* function name */ + int is_subshell; + HASH_TABLE *tempvars; +{ + if (is_subshell == 0) + push_dollar_vars (); + variable_context++; + push_var_context (name, VC_FUNCENV, tempvars); +} + +/* Only called when subshell == 0, so we don't need to check, and can + unconditionally pop the dollar vars off the stack. */ +void +pop_context () +{ + pop_dollar_vars (); + variable_context--; + pop_var_context (); + + sv_ifs ("IFS"); /* XXX here for now */ +} + +/* Save the existing positional parameters on a stack. */ +void +push_dollar_vars () +{ + if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots) + { + dollar_arg_stack = (WORD_LIST **) + xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10) + * sizeof (WORD_LIST *)); + } + dollar_arg_stack[dollar_arg_stack_index++] = list_rest_of_args (); + dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL; +} + +/* Restore the positional parameters from our stack. */ +void +pop_dollar_vars () +{ + if (!dollar_arg_stack || dollar_arg_stack_index == 0) + return; + + remember_args (dollar_arg_stack[--dollar_arg_stack_index], 1); + dispose_words (dollar_arg_stack[dollar_arg_stack_index]); + dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL; + set_dollar_vars_unchanged (); +} + +void +dispose_saved_dollar_vars () +{ + if (!dollar_arg_stack || dollar_arg_stack_index == 0) + return; + + dispose_words (dollar_arg_stack[dollar_arg_stack_index]); + 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 * + * * + *************************************************/ + +/* Extern declarations for variables this code has to manage. */ +extern int eof_encountered, eof_encountered_limit, ignoreeof; + +#if defined (READLINE) +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 + +/* This table will be sorted with qsort() the first time it's accessed. */ +struct name_and_function { + char *name; + sh_sv_func_t *function; +}; + +static struct name_and_function special_vars[] = { + { "BASH_COMPAT", sv_shcompat }, + { "BASH_XTRACEFD", sv_xtracefd }, + +#if defined (JOB_CONTROL) + { "CHILD_MAX", sv_childmax }, +#endif + +#if defined (READLINE) +# if defined (STRICT_POSIX) + { "COLUMNS", sv_winsize }, +# endif + { "COMP_WORDBREAKS", sv_comp_wordbreaks }, +#endif + + { "FUNCNEST", sv_funcnest }, + + { "GLOBIGNORE", sv_globignore }, + +#if defined (HISTORY) + { "HISTCONTROL", sv_history_control }, + { "HISTFILESIZE", sv_histsize }, + { "HISTIGNORE", sv_histignore }, + { "HISTSIZE", sv_histsize }, + { "HISTTIMEFORMAT", sv_histtimefmt }, +#endif + +#if defined (__CYGWIN__) + { "HOME", sv_home }, +#endif + +#if defined (READLINE) + { "HOSTFILE", sv_hostfile }, +#endif + + { "IFS", sv_ifs }, + { "IGNOREEOF", sv_ignoreeof }, + + { "LANG", sv_locale }, + { "LC_ALL", sv_locale }, + { "LC_COLLATE", sv_locale }, + { "LC_CTYPE", sv_locale }, + { "LC_MESSAGES", sv_locale }, + { "LC_NUMERIC", sv_locale }, + { "LC_TIME", sv_locale }, + +#if defined (READLINE) && defined (STRICT_POSIX) + { "LINES", sv_winsize }, +#endif + + { "MAIL", sv_mail }, + { "MAILCHECK", sv_mail }, + { "MAILPATH", sv_mail }, + + { "OPTERR", sv_opterr }, + { "OPTIND", sv_optind }, + + { "PATH", sv_path }, + { "POSIXLY_CORRECT", sv_strict_posix }, + +#if defined (READLINE) + { "TERM", sv_terminal }, + { "TERMCAP", sv_terminal }, + { "TERMINFO", sv_terminal }, +#endif /* READLINE */ + + { "TEXTDOMAIN", sv_locale }, + { "TEXTDOMAINDIR", sv_locale }, + +#if defined (HAVE_TZSET) + { "TZ", sv_tz }, +#endif + +#if defined (HISTORY) && defined (BANG_HISTORY) + { "histchars", sv_histchars }, +#endif /* HISTORY && BANG_HISTORY */ + + { "ignoreeof", sv_ignoreeof }, + + { (char *)0, (sh_sv_func_t *)0 } +}; + +#define N_SPECIAL_VARS (sizeof (special_vars) / sizeof (special_vars[0]) - 1) + +static int +sv_compare (sv1, sv2) + struct name_and_function *sv1, *sv2; +{ + int r; + + if ((r = sv1->name[0] - sv2->name[0]) == 0) + r = strcmp (sv1->name, sv2->name); + return r; +} + +static inline int +find_special_var (name) + const char *name; +{ + register int i, r; + + for (i = 0; special_vars[i].name; i++) + { + r = special_vars[i].name[0] - name[0]; + if (r == 0) + r = strcmp (special_vars[i].name, name); + if (r == 0) + return i; + else if (r > 0) + /* Can't match any of rest of elements in sorted list. Take this out + if it causes problems in certain environments. */ + break; + } + return -1; +} + +/* 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; +{ + static int sv_sorted = 0; + int i; + + if (sv_sorted == 0) /* shouldn't need, but it's fairly cheap. */ + { + qsort (special_vars, N_SPECIAL_VARS, sizeof (special_vars[0]), + (QSFUNC *)sv_compare); + sv_sorted = 1; + } + + i = find_special_var (name); + if (i != -1) + (*(special_vars[i].function)) (name); +} + +/* Special variables that need hooks to be run when they are unset as part + of shell reinitialization should have their sv_ functions run here. */ +void +reinit_special_variables () +{ +#if defined (READLINE) + sv_comp_wordbreaks ("COMP_WORDBREAKS"); +#endif + sv_globignore ("GLOBIGNORE"); + sv_opterr ("OPTERR"); +} + +void +sv_ifs (name) + char *name; +{ + SHELL_VAR *v; + + v = find_variable ("IFS"); + setifs (v); +} + +/* What to do just after the PATH variable has changed. */ +void +sv_path (name) + char *name; +{ + /* hash -r */ + phash_flush (); +} + +/* 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 (); + } +} + +void +sv_funcnest (name) + char *name; +{ + SHELL_VAR *v; + intmax_t num; + + v = find_variable (name); + if (v == 0) + funcnest_max = 0; + else if (legal_number (value_cell (v), &num) == 0) + funcnest_max = 0; + else + funcnest_max = num; +} + +/* What to do when GLOBIGNORE changes. */ +void +sv_globignore (name) + char *name; +{ + if (privileged_mode == 0) + setup_glob_ignore (name); +} + +#if defined (READLINE) +void +sv_comp_wordbreaks (name) + char *name; +{ + SHELL_VAR *sv; + + sv = find_variable (name); + if (sv == 0) + reset_completer_word_break_chars (); +} + +/* 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; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v == 0) + clear_hostname_list (); + else + hostname_list_initialized = 0; +} + +#if defined (STRICT_POSIX) +/* In strict posix mode, we allow assignments to LINES and COLUMNS (and values + found in the initial environment) to override the terminal size reported by + the kernel. */ +void +sv_winsize (name) + char *name; +{ + SHELL_VAR *v; + intmax_t xd; + int d; + + if (posixly_correct == 0 || interactive_shell == 0 || no_line_editing) + return; + + v = find_variable (name); + if (v == 0 || var_isnull (v)) + rl_reset_screen_size (); + else + { + if (legal_number (value_cell (v), &xd) == 0) + return; + winsize_assignment = 1; + d = xd; /* truncate */ + if (name[0] == 'L') /* LINES */ + rl_set_screen_size (d, -1); + else /* COLUMNS */ + rl_set_screen_size (-1, d); + winsize_assignment = 0; + } +} +#endif /* STRICT_POSIX */ +#endif /* READLINE */ + +/* Update the value of HOME in the export environment so tilde expansion will + work on cygwin. */ +#if defined (__CYGWIN__) +sv_home (name) + char *name; +{ + array_needs_making = 1; + maybe_make_export_env (); +} +#endif + +#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; + intmax_t num; + int hmax; + + temp = get_string_value (name); + + if (temp && *temp) + { + if (legal_number (temp, &num)) + { + hmax = num; + if (hmax < 0 && name[4] == 'S') + unstifle_history (); /* unstifle history if HISTSIZE < 0 */ + else if (name[4] == 'S') + { + stifle_history (hmax); + hmax = where_history (); + if (history_lines_this_session > hmax) + history_lines_this_session = hmax; + } + else if (hmax >= 0) /* truncate HISTFILE if HISTFILESIZE >= 0 */ + { + history_truncate_file (get_string_value ("HISTFILE"), hmax); + if (hmax <= history_lines_in_file) + history_lines_in_file = hmax; + } + } + } + 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; + char *val; + int tptr; + + history_control = 0; + temp = get_string_value (name); + + if (temp == 0 || *temp == 0) + return; + + tptr = 0; + while (val = extract_colon_unit (temp, &tptr)) + { + 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); + } +} + +#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 */ + +void +sv_histtimefmt (name) + char *name; +{ + SHELL_VAR *v; + + if (v = find_variable (name)) + { + if (history_comment_char == 0) + history_comment_char = '#'; + } + history_write_timestamps = (v != 0); +} +#endif /* HISTORY */ + +#if defined (HAVE_TZSET) +void +sv_tz (name) + char *name; +{ + if (chkexport (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; + int r; + + v = get_string_value (name); + if (name[0] == 'L' && name[1] == 'A') /* LANG */ + r = set_lang (name, v); + else + r = set_locale_var (name, v); /* LC_*, TEXTDOMAIN* */ + +#if 1 + if (r == 0 && posixly_correct) + last_command_exit_value = 1; +#endif +} + +#if defined (ARRAY_VARS) +void +set_pipestatus_array (ps, nproc) + int *ps; + int nproc; +{ + SHELL_VAR *v; + ARRAY *a; + ARRAY_ELEMENT *ae; + register int i; + char *t, tbuf[INT_STRLEN_BOUND(int) + 1]; + + 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 == 0 || array_num_elements (a) == 0) + { + for (i = 0; i < nproc; i++) /* was ps[i] != -1, not i < nproc */ + { + t = inttostr (ps[i], tbuf, sizeof (tbuf)); + array_insert (a, i, t); + } + return; + } + + /* Fast case */ + if (array_num_elements (a) == nproc && nproc == 1) + { + ae = element_forw (a->head); + free (element_value (ae)); + ae->value = itos (ps[0]); + } + else if (array_num_elements (a) <= nproc) + { + /* modify in array_num_elements members in place, then add */ + ae = a->head; + for (i = 0; i < array_num_elements (a); i++) + { + ae = element_forw (ae); + free (element_value (ae)); + ae->value = itos (ps[i]); + } + /* add any more */ + for ( ; i < nproc; i++) + { + t = inttostr (ps[i], tbuf, sizeof (tbuf)); + array_insert (a, i, t); + } + } + else + { + /* deleting elements. it's faster to rebuild the array. */ + array_flush (a); + for (i = 0; ps[i] != -1; i++) + { + t = inttostr (ps[i], tbuf, sizeof (tbuf)); + array_insert (a, i, t); + } + } +} + +ARRAY * +save_pipestatus_array () +{ + SHELL_VAR *v; + ARRAY *a, *a2; + + v = find_variable ("PIPESTATUS"); + if (v == 0 || array_p (v) == 0 || array_cell (v) == 0) + return ((ARRAY *)NULL); + + a = array_cell (v); + a2 = array_copy (array_cell (v)); + + return a2; +} + +void +restore_pipestatus_array (a) + ARRAY *a; +{ + SHELL_VAR *v; + ARRAY *a2; + + v = find_variable ("PIPESTATUS"); + /* XXX - should we still assign even if existing value is NULL? */ + if (v == 0 || array_p (v) == 0 || array_cell (v) == 0) + return; + + a2 = array_cell (v); + var_setarray (v, a); + + array_dispose (a2); +} +#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, 1); +#endif +} + +void +sv_xtracefd (name) + char *name; +{ + SHELL_VAR *v; + char *t, *e; + int fd; + FILE *fp; + + v = find_variable (name); + if (v == 0) + { + xtrace_reset (); + return; + } + + t = value_cell (v); + if (t == 0 || *t == 0) + xtrace_reset (); + else + { + fd = (int)strtol (t, &e, 10); + if (e != t && *e == '\0' && sh_validfd (fd)) + { + fp = fdopen (fd, "w"); + if (fp == 0) + internal_error (_("%s: %s: cannot open as FILE"), name, value_cell (v)); + else + xtrace_set (fd, fp); + } + else + internal_error (_("%s: %s: invalid value for trace file descriptor"), name, value_cell (v)); + } +} + +#define MIN_COMPAT_LEVEL 31 + +void +sv_shcompat (name) + char *name; +{ + SHELL_VAR *v; + char *val; + int tens, ones, compatval; + + v = find_variable (name); + if (v == 0) + { + shell_compatibility_level = DEFAULT_COMPAT_LEVEL; + set_compatibility_opts (); + return; + } + val = value_cell (v); + if (val == 0 || *val == '\0') + { + shell_compatibility_level = DEFAULT_COMPAT_LEVEL; + set_compatibility_opts (); + return; + } + /* Handle decimal-like compatibility version specifications: 4.2 */ + if (isdigit (val[0]) && val[1] == '.' && isdigit (val[2]) && val[3] == 0) + { + tens = val[0] - '0'; + ones = val[2] - '0'; + compatval = tens*10 + ones; + } + /* Handle integer-like compatibility version specifications: 42 */ + else if (isdigit (val[0]) && isdigit (val[1]) && val[2] == 0) + { + tens = val[0] - '0'; + ones = val[1] - '0'; + compatval = tens*10 + ones; + } + else + { +compat_error: + internal_error (_("%s: %s: compatibility value out of range"), name, val); + shell_compatibility_level = DEFAULT_COMPAT_LEVEL; + set_compatibility_opts (); + return; + } + + if (compatval < MIN_COMPAT_LEVEL || compatval > DEFAULT_COMPAT_LEVEL) + goto compat_error; + + shell_compatibility_level = compatval; + set_compatibility_opts (); +} + +#if defined (JOB_CONTROL) +void +sv_childmax (name) + char *name; +{ + char *tt; + int s; + + tt = get_string_value (name); + s = (tt && *tt) ? atoi (tt) : 0; + set_maxchild (s); +} +#endif