From bddda3d2e1db0cd378bdf3866dd4eff8e6d78909 Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Mon, 23 May 2016 09:57:30 -0400 Subject: [PATCH] commit bash-20160520 snapshot --- CWRU/CWRU.chlog | 156 ++++++++++++++++++++++++++++++++++ MANIFEST | 2 + arrayfunc.c | 17 +++- bashline.c | 4 +- builtins/declare.def | 11 +-- builtins/getopts.def | 12 +-- builtins/read.def | 5 +- builtins/set.def | 6 +- builtins/setattr.def | 23 ++++- config-bot.h | 4 + config-top.h | 4 + config.h.in | 3 + configure | 13 ++- configure.ac | 3 +- examples/loadables/mypid.c | 7 +- execute_cmd.c | 22 ++--- general.c | 8 +- lib/sh/shmatch.c | 2 +- lib/sh/tmpfile.c | 22 ++++- pcomplete.c | 14 ++-- subst.c | 11 ++- tests/RUN-ONE-TEST | 2 +- tests/getopts.right | 5 ++ tests/getopts.tests | 2 + tests/getopts10.sub | 17 ++++ tests/nameref.right | 89 +++++++++++++++----- tests/nameref.tests | 1 + tests/nameref11.sub | 22 ++++- tests/nameref12.sub | 35 ++++++++ tests/nameref14.sub | 43 ++++++++++ variables.c | 166 +++++++++++++++++++++++++++++-------- variables.h | 7 ++ 32 files changed, 625 insertions(+), 113 deletions(-) create mode 100644 tests/getopts10.sub create mode 100644 tests/nameref14.sub diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 3163415e..375e087b 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -10941,3 +10941,159 @@ execute_cmd.c - execute_for_command: check whether or not the word in the for command is IFS; call setifs every time the variable is assigned a value. Fixes bug report from Grisha Levit + + 5/16 + ---- +general.c + - valid_nameref_value: explicitly handle name == 0 and *name == 0 right + away to save calls to legal_identifier + +builtins/declare.def + - declare_internal: if trying to set nameref attribute on a variable with + a null value, flag as invalid assignment, just as if running + `declare -n r=""'. Fixes bug report from Grisha Levit + + - declare_internal: when creating a variable with a temporary value (""), + use ASS_FORCE in the assignment flags to bypass name validity checks on + nameref variable names + +variables.c + - bind_variable_internal: don't call valid_nameref_value if we're forcing + assignment with (flags & ASS_FORCE) + +builtins/read.def + - read_builtin: handle bind_variable returning NULL when setting REPLY. + Report and fix from Grisha Levit + +builtins/setattr.def + - set_var_attribute: handle bind_variable returning NULL + +lib/sh/tmpfile.c + - sh_seedrand(): call srandom() to seed the random number generator + - sh_mktmpname, sh_mktmpfd: if we have random(), assume we have srandom() + and seed the random number generator. Still looking for better value to + see random number generator with + +variables.c + - check_unbind_variable: use internal_error instead of builtin_error + +{execute_cmd,variables}.c + - fix some places where bind_variable could return NULL and it was not + checked. Fix from Piotr Grzybowski + + 5/17 + ---- +arrayfunc.c + - convert_var_to_{array,assoc}: make sure to turn off nameref attribute, + since namerefs can't be arrays + +execute_cmd.c + - coproc_setvars: if the coproc name names a nameref, resolve the nameref + and use it as the name of the coproc. Suggested by Grisha Levit + + +subst.c + - command_substitute: don't bother calling QUIT after calling + reset_signal_handlers in the child, kill the child with SIGINT in + case we just reset the signal handler to SIG_DFL and we should just + exit instead of throwing to top level. Fixes bug reported by + Grisha Levit + + 5/18 + ---- +variables.c + - find_variable_nameref_for_create: find a nameref variable whose value + doesn't resolve to an existing variable and see whether or not that + value is appropriate for a new variable to be created + - find_variable_nameref_for_assignment: find a nameref variable whose value + doesn't resolve to an existing variable and see whether or not that + value is appropriate for a new variable to be created. Difference + between _assignment and _create is that _assignment allows the nameref + value to be a subscripted array reference + +builtins/setattr.def + - set_var_attribute: if variable lookup doesn't return anything, check + for a nameref and make sure that any reference value is something we + should be working on here, using find_variable_nameref_for_create(). + If it fails, error out and return, otherwise it's probably a reference + to a variable that hasn't been set yet, so let bind_variable take care + of that. Report from Grisha Levit + +arrayfunc.c + - bind_array_variable: if find_shell_variable returns NULL, check for a + nameref using find_variable_nameref_for_create and create a new array + variable with the value if it returns a valid nameref variable. + Makes `unset var; declare -n ref=var ; ref[0]=foo' work right. + Report from Grisha Levit + + 5/19 + ---- +variables.[ch] + - unbind_variable_noref: unset a variable NAME without following any + nameref chain. If the first instance of the variable with that name + is a nameref, just unset that nameref variable. + +builtins/getopts.def + - getopts_unbind_variable: if OPTARG is going to be unbound, use + unbind_variable_noref to unbind that name even if it is a nameref + variable. Issue raised by Grisha Levit + +execute_cmd.c + - coproc_unsetvars: use unbind_variable_noref in case someone sets the + coproc _PID variable as a nameref pointing to something read-only or + strange. Issue raised by Grisha Levit + +builtins/set.def + - set_ignoreeof: use unbind_variable_noref to unset "IGNOREEOF" and + "ignoreeof" + - set_posix_mode: use unbind_variable_noref to unset "POSIXLY_CORRECT" + +variables.c + - make_vers_array: use unbind_variable_noref to unset "BASH_VERSINFO" + +lib/sh/shmatch.c + - sh_regmatch: use unbind_variable_noref to unset "BASH_REMATCH" + +bashline.c + - bash_execute_unix_command: use check_unbind_variable to unset + READLINE_LINE and READLINE_POINT + +pcomplete.c + - unbind_compfunc_variables: use unbind_variable_noref to unset COMP_LINE, + COMP_POINT, COMP_WORDS, COMP_CWORD, COMP_TYPE, COMP_KEY + - gen_shell_function_matches: use unbind_variable_noref to unset COMPREPLY + +config-top.h + - USE_MKTEMP/USE_MKSTEMP: define by default to use libc version of mktemp + and mkstemp in lib/sh/tmpfile.c. Recommended by by Mike Frysinger + to fix a FreeBSD problem + +configure.ac,config.h.in + - mkstemp: check for mkstemp, define HAVE_MKSTEMP if available + +config-bot.h + - USE_MKSTEMP: #undef if HAVE_MKSTEMP not defined + + 5/22 + ---- +variables.c + - assign_in_env: if appending to a variable's value, make sure we call + make_variable_value with the empty string if expand_assignment_string_to_string + returns NULL, as do_assignment_internal does. Fixes bug with + `str=''; val=foo ; val+=str printenv val' reported by Grisha Levit + + - assign_in_env: if assigning to a nameref variable in the temporary + environment, and the nameref has a valid value for assignment (even + if the target variable is not set), resolve the nameref and create + a variable in the temporary environment named by the nameref's value. + If the nameref variable is invisible or isn't set to a valid value + for assignment, just create a regular temporary variable with the + nameref's name. This provides a degree of ksh93 compatibility. + Suggested by Grisha Levit + - find_variable_nameref_context,find_variable_last_nameref_context: + instead of returning NULL when detecting a loop, return a distinguished + value: &nameref_maxloop_value + - bind_variable: catch nameref_maxloop_value so we can do different + things based on whether or not we get it. Right now we don't do + anything different, but we could + diff --git a/MANIFEST b/MANIFEST index 1c3d17c4..a636d0c6 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1008,6 +1008,7 @@ tests/getopts6.sub f tests/getopts7.sub f tests/getopts8.sub f tests/getopts9.sub f +tests/getopts10.sub f tests/glob.tests f tests/glob1.sub f tests/glob.right f @@ -1083,6 +1084,7 @@ tests/nameref10.sub f tests/nameref11.sub f tests/nameref12.sub f tests/nameref13.sub f +tests/nameref14.sub f tests/nameref.right f tests/new-exp.tests f tests/new-exp1.sub f diff --git a/arrayfunc.c b/arrayfunc.c index e1de5fbc..af43191d 100644 --- a/arrayfunc.c +++ b/arrayfunc.c @@ -90,6 +90,9 @@ convert_var_to_array (var) /* Make sure it's not marked as an associative array any more */ VUNSETATTR (var, att_assoc); + /* Since namerefs can't be array variables, turn off nameref attribute */ + VUNSETATTR (var, att_nameref); + return var; } @@ -124,6 +127,9 @@ convert_var_to_assoc (var) /* Make sure it's not marked as an indexed array any more */ VUNSETATTR (var, att_array); + /* Since namerefs can't be array variables, turn off nameref attribute */ + VUNSETATTR (var, att_nameref); + return var; } @@ -210,6 +216,15 @@ bind_array_variable (name, ind, value, flags) entry = find_shell_variable (name); + if (entry == (SHELL_VAR *) 0) + { + /* Is NAME a nameref variable that points to an unset variable? */ + entry = find_variable_nameref_for_create (name, 0); + if (entry == INVALID_NAMEREF_VALUE) + return ((SHELL_VAR *)0); + if (entry && nameref_p (entry)) + entry = make_new_array_variable (nameref_cell (entry)); + } if (entry == (SHELL_VAR *) 0) entry = make_new_array_variable (name); else if ((readonly_p (entry) && (flags&ASS_FORCE) == 0) || noassign_p (entry)) @@ -984,7 +999,7 @@ array_variable_part (s, subp, lenp) t = array_variable_name (s, subp, lenp); if (t == 0) return ((SHELL_VAR *)NULL); - var = find_variable (t); + var = find_variable (t); /* XXX - handle namerefs here? */ free (t); return var; /* now return invisible variables; caller must handle */ diff --git a/bashline.c b/bashline.c index 3f1027fc..552253b5 100644 --- a/bashline.c +++ b/bashline.c @@ -4135,8 +4135,8 @@ bash_execute_unix_command (count, key) } } - unbind_variable ("READLINE_LINE"); - unbind_variable ("READLINE_POINT"); + check_unbind_variable ("READLINE_LINE"); + check_unbind_variable ("READLINE_POINT"); array_needs_making = 1; /* and restore the readline buffer and display after command execution. */ diff --git a/builtins/declare.def b/builtins/declare.def index b9c01321..1f227e52 100644 --- a/builtins/declare.def +++ b/builtins/declare.def @@ -344,7 +344,7 @@ declare_internal (list, local_var) #if 1 if (value && *value && valid_nameref_value (value, 0) == 0) { - builtin_error (_("%s: invalid variable name for name reference"), value); + builtin_error (_("`%s': invalid variable name for name reference"), value); assign_error++; NEXT_VARIABLE (); } @@ -570,7 +570,8 @@ declare_internal (list, local_var) else #endif if (offset) - var = mkglobal ? bind_global_variable (name, "", 0) : bind_variable (name, "", 0); + /* We're just setting a temporary value here, so force assignment */ + var = mkglobal ? bind_global_variable (name, (char *)NULL, ASS_FORCE) : bind_variable (name, (char *)NULL, ASS_FORCE); else { var = mkglobal ? bind_global_variable (name, (char *)NULL, 0) : bind_variable (name, (char *)NULL, 0); @@ -592,7 +593,7 @@ declare_internal (list, local_var) } else if (nameref_p (var) && (flags_on & att_nameref) == 0 && (flags_off & att_nameref) == 0 && offset && valid_nameref_value (value, 1) == 0) { - builtin_error (_("%s: invalid variable name for name reference"), value); + builtin_error (_("`%s': invalid variable name for name reference"), value); any_failed++; NEXT_VARIABLE (); } @@ -601,9 +602,9 @@ declare_internal (list, local_var) #if 1 /* Check of offset is to allow an assignment to a nameref var as part of the declare word to override existing value */ - if (nameref_p (var) == 0 && var_isset (var) && var_isnull (var) == 0 && offset == 0 && valid_nameref_value (value_cell (var), 0) == 0) + if (nameref_p (var) == 0 && var_isset (var) && offset == 0 && valid_nameref_value (value_cell (var), 0) == 0) { - builtin_error (_("%s: invalid variable name for name reference"), value_cell (var)); + builtin_error (_("`%s': invalid variable name for name reference"), value_cell (var)); any_failed++; NEXT_VARIABLE (); } diff --git a/builtins/getopts.def b/builtins/getopts.def index c7af9825..590b1103 100644 --- a/builtins/getopts.def +++ b/builtins/getopts.def @@ -106,16 +106,10 @@ getopts_unbind_variable (name) char *name; { #if 0 - SHELL_VAR *v; - - v = find_variable (name); - if (v && readonly_p (v)) - { - builtin_error (_("%s: cannot unset: readonly %s"), name, "variable"); - return -1; - } -#endif return (unbind_variable (name)); +#else + return (unbind_variable_noref (name)); +#endif } static int diff --git a/builtins/read.def b/builtins/read.def index 5e2348ce..48fda330 100644 --- a/builtins/read.def +++ b/builtins/read.def @@ -797,9 +797,10 @@ assign_vars: } else var = bind_variable ("REPLY", input_string, 0); - VUNSETATTR (var, att_invisible); - if (readonly_p (var) || noassign_p (var)) + if (var == 0 || readonly_p (var) || noassign_p (var)) retval = EXECUTION_FAILURE; + else + VUNSETATTR (var, att_invisible); xfree (input_string); return (retval); diff --git a/builtins/set.def b/builtins/set.def index 1d9394cb..8f74f0e6 100644 --- a/builtins/set.def +++ b/builtins/set.def @@ -367,11 +367,11 @@ set_ignoreeof (on_or_off, option_name) char *option_name; { ignoreeof = on_or_off == FLAG_ON; - unbind_variable ("ignoreeof"); + unbind_variable_noref ("ignoreeof"); if (ignoreeof) bind_variable ("IGNOREEOF", "10", 0); else - unbind_variable ("IGNOREEOF"); + unbind_variable_noref ("IGNOREEOF"); sv_ignoreeof ("IGNOREEOF"); return 0; } @@ -383,7 +383,7 @@ set_posix_mode (on_or_off, option_name) { posixly_correct = on_or_off == FLAG_ON; if (posixly_correct == 0) - unbind_variable ("POSIXLY_CORRECT"); + unbind_variable_noref ("POSIXLY_CORRECT"); else bind_variable ("POSIXLY_CORRECT", "y", 0); sv_strict_posix ("POSIXLY_CORRECT"); diff --git a/builtins/setattr.def b/builtins/setattr.def index 9e9309ff..8f29e11e 100644 --- a/builtins/setattr.def +++ b/builtins/setattr.def @@ -538,8 +538,8 @@ set_var_attribute (name, attribute, undo) char *name; int attribute, undo; { - SHELL_VAR *var, *tv, *v; - char *tvalue; + SHELL_VAR *var, *tv, *v, *refvar; + char *tvalue, *refname; if (undo) var = find_variable (name); @@ -554,6 +554,11 @@ set_var_attribute (name, attribute, undo) tvalue = var_isset (tv) ? savestring (value_cell (tv)) : savestring (""); var = bind_variable (tv->name, tvalue, 0); + if (var == 0) + { + free (tvalue); + return; /* XXX - no error message here */ + } var->attributes |= tv->attributes & ~att_tempvar; /* This avoids an error message when propagating a read-only var later on. */ @@ -578,10 +583,22 @@ set_var_attribute (name, attribute, undo) else { var = find_variable_notempenv (name); + if (var == 0) + { + /* We might have a nameref pointing to something that we can't + resolve to a shell variable. If we do, skip it. We do a little + checking just so we can print an error message. */ + refvar = find_variable_nameref_for_create (name, 0); + if (refvar == INVALID_NAMEREF_VALUE) + return; + /* Otherwise we probably have a nameref pointing to a variable + that hasn't been created yet. bind_variable will take care + of that. */ + } if (var == 0) { var = bind_variable (name, (char *)NULL, 0); - if (no_invisible_vars == 0) + if (var && no_invisible_vars == 0) VSETATTR (var, att_invisible); } else if (var->context != 0) diff --git a/config-bot.h b/config-bot.h index 334581a2..5563e2a8 100644 --- a/config-bot.h +++ b/config-bot.h @@ -94,6 +94,10 @@ # undef COND_REGEXP #endif +#if !HAVE_MKSTEMP +# undef USE_MKSTEMP +#endif + /* If the shell is called by this name, it will become restricted. */ #if defined (RESTRICTED_SHELL) # define RESTRICTED_SHELL_NAME "rbash" diff --git a/config-top.h b/config-top.h index d3659ec6..d89682e5 100644 --- a/config-top.h +++ b/config-top.h @@ -156,3 +156,7 @@ /* Define to the maximum level of recursion you want for the source/. builtin. 0 means the limit is not active. */ #define SOURCENEST_MAX 0 + +/* Define to use libc mktemp/mkstemp instead of replacements in lib/sh/tmpfile.c */ +#define USE_MKTEMP +#define USE_MKSTEMP diff --git a/config.h.in b/config.h.in index 894892fb..d3ab5486 100644 --- a/config.h.in +++ b/config.h.in @@ -736,6 +736,9 @@ /* Define if you have the mkfifo function. */ #undef HAVE_MKFIFO +/* Define if you have the mkstemp function. */ +#undef HAVE_MKSTEMP + /* Define if you have the pathconf function. */ #undef HAVE_PATHCONF diff --git a/configure b/configure index c9c433c7..c0d903a0 100755 --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.ac for Bash 4.4, version 4.078. +# From configure.ac for Bash 4.4, version 4.079. # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for bash 4.4-rc2. # @@ -9884,6 +9884,17 @@ _ACEOF fi done +for ac_func in mkstemp +do : + ac_fn_c_check_func "$LINENO" "mkstemp" "ac_cv_func_mkstemp" +if test "x$ac_cv_func_mkstemp" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MKSTEMP 1 +_ACEOF + +fi +done + ac_fn_c_check_func "$LINENO" "getcwd" "ac_cv_func_getcwd" if test "x$ac_cv_func_getcwd" = xyes; then : $as_echo "#define HAVE_GETCWD 1" >>confdefs.h diff --git a/configure.ac b/configure.ac index ab8f066d..156f2804 100644 --- a/configure.ac +++ b/configure.ac @@ -21,7 +21,7 @@ dnl Process this file with autoconf to produce a configure script. # You should have received a copy of the GNU General Public License # along with this program. If not, see . -AC_REVISION([for Bash 4.4, version 4.078])dnl +AC_REVISION([for Bash 4.4, version 4.079])dnl define(bashvers, 4.4) define(relstatus, rc2) @@ -783,6 +783,7 @@ AC_CHECK_FUNCS(bcopy bzero confstr faccessat fnmatch \ AC_CHECK_FUNCS(vasprintf asprintf) AC_CHECK_FUNCS(isascii isblank isgraph isprint isspace isxdigit) AC_CHECK_FUNCS(getpwent getpwnam getpwuid) +AC_CHECK_FUNCS(mkstemp) AC_REPLACE_FUNCS(getcwd memset) AC_REPLACE_FUNCS(strcasecmp strcasestr strerror strftime strnlen strpbrk strstr) AC_REPLACE_FUNCS(strtod strtol strtoul strtoll strtoull strtoimax strtoumax) diff --git a/examples/loadables/mypid.c b/examples/loadables/mypid.c index 8f2341f9..fc1b267a 100644 --- a/examples/loadables/mypid.c +++ b/examples/loadables/mypid.c @@ -23,8 +23,11 @@ #define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \ do \ { SHELL_VAR *v = bind_variable (var, (val), 0); \ - v->dynamic_value = gfunc; \ - v->assign_func = afunc; \ + if (v) \ + { \ + v->dynamic_value = gfunc; \ + v->assign_func = afunc; \ + } \ } \ while (0) diff --git a/execute_cmd.c b/execute_cmd.c index c70717ea..09f47724 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -2175,19 +2175,14 @@ coproc_setvars (cp) /* This is the same code as in find_or_make_array_variable */ if (v == 0) { - v = find_variable_last_nameref (cp->c_name, 1); - if (v && nameref_p (v) && invisible_p (v)) - { - internal_warning (_("coproc: %s: removing nameref attribute"), cp->c_name); - VUNSETATTR (v, att_nameref); - } + v = find_variable_nameref_for_create (cp->c_name, 1); + if (v == INVALID_NAMEREF_VALUE) + return; if (v && nameref_p (v)) { - if (valid_nameref_value (cp->c_name, 1) == 0) - { - sh_invalidid (cp->c_name); - return; - } + free (cp->c_name); + cp->c_name = savestring (nameref_cell (v)); + v = make_new_array_variable (cp->c_name); } } @@ -2244,7 +2239,7 @@ coproc_unsetvars (cp) namevar = xmalloc (l + 16); sprintf (namevar, "%s_PID", cp->c_name); - unbind_variable (namevar); + unbind_variable_noref (namevar); #if defined (ARRAY_VARS) check_unbind_variable (cp->c_name); @@ -3812,7 +3807,8 @@ bind_lastarg (arg) if (arg == 0) arg = ""; var = bind_variable ("_", arg, 0); - VUNSETATTR (var, att_exported); + if (var) + VUNSETATTR (var, att_exported); } /* Execute a null command. Fork a subshell if the command uses pipes or is diff --git a/general.c b/general.c index 89e359e2..2d9e6272 100644 --- a/general.c +++ b/general.c @@ -238,16 +238,16 @@ valid_nameref_value (name, for_assignment) { intmax_t r; + if (name == 0 || *name == 0) + return 0; + #if defined (ARRAY_VARS) if (legal_identifier (name) || valid_array_reference (name, 0)) #else if (legal_identifier (name)) #endif return 1; -#if 0 - if (for_assignment == 0 && legal_number (name, &r)) - return 1; -#endif + return 0; } diff --git a/lib/sh/shmatch.c b/lib/sh/shmatch.c index fcd228ef..da05211e 100644 --- a/lib/sh/shmatch.c +++ b/lib/sh/shmatch.c @@ -92,7 +92,7 @@ sh_regmatch (string, pattern, flags) /* Store the parenthesized subexpressions in the array BASH_REMATCH. Element 0 is the portion that matched the entire regexp. Element 1 is the part that matched the first subexpression, and so on. */ - unbind_variable ("BASH_REMATCH"); + unbind_variable_noref ("BASH_REMATCH"); rematch = make_new_array_variable ("BASH_REMATCH"); amatch = array_cell (rematch); diff --git a/lib/sh/tmpfile.c b/lib/sh/tmpfile.c index d42d1807..7c2fbf22 100644 --- a/lib/sh/tmpfile.c +++ b/lib/sh/tmpfile.c @@ -114,6 +114,23 @@ get_tmpdir (flags) return tdir; } +static void +sh_seedrand () +{ +#if HAVE_RANDOM + int d; + static int seeded = 0; + if (seeded == 0) + { + struct timeval tv; + + gettimeofday (&tv, NULL); + srandom (tv.tv_sec ^ tv.tv_usec ^ (getpid () << 16) ^ (unsigned int)&d); + seeded = 1; + } +#endif +} + char * sh_mktmpname (nameroot, flags) char *nameroot; @@ -122,6 +139,7 @@ sh_mktmpname (nameroot, flags) char *filename, *tdir, *lroot; struct stat sb; int r, tdlen; + static int seeded = 0; filename = (char *)xmalloc (PATH_MAX + 1); tdir = get_tmpdir (flags); @@ -137,6 +155,7 @@ sh_mktmpname (nameroot, flags) filename = NULL; } #else /* !USE_MKTEMP */ + sh_seedrand (); while (1) { filenum = (filenum << 1) ^ @@ -167,7 +186,7 @@ sh_mktmpfd (nameroot, flags, namep) { char *filename, *tdir, *lroot; int fd, tdlen; - + filename = (char *)xmalloc (PATH_MAX + 1); tdir = get_tmpdir (flags); tdlen = strlen (tdir); @@ -186,6 +205,7 @@ sh_mktmpfd (nameroot, flags, namep) *namep = filename; return fd; #else /* !USE_MKSTEMP */ + sh_seedrand (); do { filenum = (filenum << 1) ^ diff --git a/pcomplete.c b/pcomplete.c index ba5e9ff5..ac0903a9 100644 --- a/pcomplete.c +++ b/pcomplete.c @@ -1025,13 +1025,13 @@ static void unbind_compfunc_variables (exported) int exported; { - unbind_variable ("COMP_LINE"); - unbind_variable ("COMP_POINT"); - unbind_variable ("COMP_TYPE"); - unbind_variable ("COMP_KEY"); + unbind_variable_noref ("COMP_LINE"); + unbind_variable_noref ("COMP_POINT"); + unbind_variable_noref ("COMP_TYPE"); + unbind_variable_noref ("COMP_KEY"); #ifdef ARRAY_VARS - unbind_variable ("COMP_WORDS"); - unbind_variable ("COMP_CWORD"); + unbind_variable_noref ("COMP_WORDS"); + unbind_variable_noref ("COMP_CWORD"); #endif if (exported) array_needs_making = 1; @@ -1183,7 +1183,7 @@ gen_shell_function_matches (cs, cmd, text, line, ind, lwords, nw, cw, foundp) } /* XXX - should we unbind COMPREPLY here? */ - unbind_variable ("COMPREPLY"); + unbind_variable_noref ("COMPREPLY"); return (sl); #endif diff --git a/subst.c b/subst.c index ebc0ea12..7053a43a 100644 --- a/subst.c +++ b/subst.c @@ -6011,6 +6011,11 @@ command_substitute (string, quoted) trap strings. Set a flag noting that we have to free the trap strings if we run trap to change a signal disposition. */ reset_signal_handlers (); + if (ISINTERRUPT) + { + kill (getpid (), SIGINT); + CLRINTERRUPT; /* if we're ignoring SIGINT somehow */ + } QUIT; /* catch any interrupts we got post-fork */ subshell_environment |= SUBSHELL_RESETTRAP; } @@ -6040,6 +6045,9 @@ command_substitute (string, quoted) if (pid == 0) { + /* The currently executing shell is not interactive. */ + interactive = 0; + set_sigint_handler (); /* XXX */ free_pushed_string_input (); @@ -6077,9 +6085,6 @@ command_substitute (string, quoted) sh_setlinebuf (stdout); #endif /* __CYGWIN__ */ - /* The currently executing shell is not interactive. */ - interactive = 0; - /* This is a subshell environment. */ subshell_environment |= SUBSHELL_COMSUB; diff --git a/tests/RUN-ONE-TEST b/tests/RUN-ONE-TEST index d29259a9..a5ab273d 100755 --- a/tests/RUN-ONE-TEST +++ b/tests/RUN-ONE-TEST @@ -1,4 +1,4 @@ -BUILD_DIR=/usr/local/build/chet/bash/bash-current +BUILD_DIR=/usr/local/build/bash/bash-current THIS_SH=$BUILD_DIR/bash PATH=$PATH:$BUILD_DIR diff --git a/tests/getopts.right b/tests/getopts.right index 7be41b04..fff9729f 100644 --- a/tests/getopts.right +++ b/tests/getopts.right @@ -61,3 +61,8 @@ opt: b opt: c opt: z $1 = a +./getopts10.sub: line 3: OPTARG: readonly variable +OPTARG = x = ? +unset x = ? +declare -r RO="foo" +declare -r RO="foo" diff --git a/tests/getopts.tests b/tests/getopts.tests index c6d10b88..d54190cc 100644 --- a/tests/getopts.tests +++ b/tests/getopts.tests @@ -39,3 +39,5 @@ ${THIS_SH} ./getopts7.sub -a ${THIS_SH} ./getopts8.sub ${THIS_SH} ./getopts9.sub + +${THIS_SH} ./getopts10.sub diff --git a/tests/getopts10.sub b/tests/getopts10.sub new file mode 100644 index 00000000..84bacf8f --- /dev/null +++ b/tests/getopts10.sub @@ -0,0 +1,17 @@ +set -- -a bb +readonly OPTARG +getopts :x x + +echo OPTARG = $OPTARG x = $x + +getopts x x +echo ${OPTARG-unset} x = $x + +typeset -r RO=foo +typeset -n OPTARG=RO + +getopts :x x +typeset -p RO + +getopts x x +typeset -p RO diff --git a/tests/nameref.right b/tests/nameref.right index 3c6255d8..5406ae77 100644 --- a/tests/nameref.right +++ b/tests/nameref.right @@ -166,8 +166,8 @@ declare -i bar="8" 8 declare -n foo="bar" ./nameref10.sub: line 64: typeset: bar: not found -./nameref11.sub: line 1: declare: /: invalid variable name for name reference -./nameref11.sub: line 2: declare: /: invalid variable name for name reference +./nameref11.sub: line 1: declare: `/': invalid variable name for name reference +./nameref11.sub: line 2: declare: `/': invalid variable name for name reference ./nameref11.sub: line 3: `/': not a valid identifier ./nameref11.sub: line 4: declare: `/': not a valid identifier ./nameref11.sub: line 5: `/': not a valid identifier @@ -176,29 +176,48 @@ declare -n foo="bar" x ./nameref11.sub: line 7: ((: `0': not a valid identifier -./nameref11.sub: line 8: declare: 0: invalid variable name for name reference -./nameref11.sub: line 9: declare: /: invalid variable name for name reference -./nameref11.sub: line 10: declare: /: invalid variable name for name reference -./nameref11.sub: line 11: `/': not a valid identifier - +./nameref11.sub: line 8: declare: `0': invalid variable name for name reference +./nameref11.sub: line 9: declare: `/': invalid variable name for name reference +./nameref11.sub: line 10: declare: `/': invalid variable name for name reference +/ ./nameref11.sub: line 12: `/': not a valid identifier ./nameref11.sub: line 13: exec: `10': not a valid identifier ./nameref11.sub: line 13: r: cannot assign fd to variable -./nameref11.sub: line 14: warning: coproc: r: removing nameref attribute +./nameref11.sub: line 14: warning: r: removing nameref attribute 63 ./nameref11.sub: line 15: declare: RO: readonly variable ./nameref11.sub: line 15: RO: readonly variable -./nameref11.sub: line 16: declare: /: invalid variable name for name reference +./nameref11.sub: line 16: declare: `/': invalid variable name for name reference / -./nameref11.sub: line 17: declare: /: invalid variable name for name reference +./nameref11.sub: line 17: declare: `/': invalid variable name for name reference ./nameref11.sub: illegal option -- h ./nameref11.sub: line 18: getopts: `?': not a valid identifier ./nameref11.sub: line 19: warning: r: removing nameref attribute declare -a r=() ./nameref11.sub: line 20: declare: r: reference variable cannot be an array ./nameref11.sub: line 21: printf: `/': not a valid identifier -./nameref12.sub: line 6: declare: /: invalid variable name for name reference -./nameref12.sub: line 9: declare: %: invalid variable name for name reference +./nameref11.sub: line 23: `': not a valid identifier +./nameref11.sub: line 24: declare: `': not a valid identifier +./nameref11.sub: line 25: `': not a valid identifier +./nameref11.sub: line 26: printf: `': not a valid identifier +./nameref11.sub: line 27: declare: `': invalid variable name for name reference +declare -r ROVAR="42" +./nameref11.sub: line 32: ROVAR: readonly variable +./nameref11.sub: line 32: ROVAR: cannot unset: readonly variable +declare -r ROVAR="42" +./nameref11.sub +./nameref11.sub: line 34: `@': not a valid identifier +./nameref11.sub +declare -n ref="x" +./nameref11.sub: line 39: RO: readonly variable +declare -r RO_PID +./nameref11.sub: line 39: RO: cannot unset: readonly variable +declare -r RO="x" +./nameref11.sub: line 39: declare: RO_PID: not found +./nameref11.sub: line 41: ref_PID: readonly variable +declare -r RO2="a" +./nameref12.sub: line 6: declare: `/': invalid variable name for name reference +./nameref12.sub: line 9: declare: `%': invalid variable name for name reference ./nameref12.sub: line 13: `^': not a valid identifier declare -n r declare -a foo @@ -206,15 +225,23 @@ declare -a foo=([0]="7") ./nameref12.sub: line 26: declare: `42': not a valid identifier ./nameref12.sub: line 27: declare: x: not found declare -nr RO="foo" -./nameref12.sub: line 37: `/': not a valid identifier 0 0 -./nameref12.sub: line 38: `/': not a valid identifier - -./nameref12.sub: line 43: declare: `7*6': not a valid identifier -./nameref12.sub: line 43: declare: foo: not found -./nameref12.sub: line 45: `7*6': not a valid identifier +/ +./nameref12.sub: line 45: declare: `7*6': not a valid identifier +./nameref12.sub: line 45: declare: foo: not found +./nameref12.sub: line 47: `7*6': not a valid identifier declare -n ref="var" declare -n ref="var" +./nameref12.sub: line 74: readonly: `var[0]': not a valid identifier +declare -- var="foo" +declare -r var2="foo" +declare -n ref="var" +declare -a var=([0]="foo") +./nameref12.sub: line 91: `': not a valid identifier +declare -n ref +declare -- ref="global" +declare -a var=([0]="foo2") +./nameref12.sub: line 100: declare: global: not found declare -- a declare -n r="a" declare -- a @@ -227,7 +254,29 @@ declare -n r="a" 0 declare -n r declare -n r -./nameref13.sub: line 88: typeset: 12345: invalid variable name for name reference +./nameref13.sub: line 88: typeset: `12345': invalid variable name for name reference declare -n foo -./nameref13.sub: line 97: typeset: 12345: invalid variable name for name reference +./nameref13.sub: line 97: typeset: `12345': invalid variable name for name reference declare -n foo +declare -nx ref="var" +var +var +var +var +foo +foo +foo +foo +before +declare -n ref="var" +./nameref14.sub: line 23: typeset: var: not found +first +declare -n ref="var" +declare -x var="xxx" +invalid +declare -n ref="var" +declare -x var="5" +after +declare -n ref="var" +./nameref14.sub: line 32: typeset: var: not found +declare -n ref="var" diff --git a/tests/nameref.tests b/tests/nameref.tests index 548daa8c..1f8c454e 100644 --- a/tests/nameref.tests +++ b/tests/nameref.tests @@ -128,3 +128,4 @@ ${THIS_SH} ./nameref10.sub ${THIS_SH} ./nameref11.sub ${THIS_SH} ./nameref12.sub ${THIS_SH} ./nameref13.sub +${THIS_SH} ./nameref14.sub diff --git a/tests/nameref11.sub b/tests/nameref11.sub index a790ce1b..b1ac686c 100644 --- a/tests/nameref11.sub +++ b/tests/nameref11.sub @@ -18,4 +18,24 @@ declare -n r=s; declare -n s; s=/ ; unset -n r; unset -n s declare -n r; getopts x r -h ; unset r; unset -n r declare -n r; mapfile r < /dev/null ; declare -p r; unset r ; unset -n r mapfile r < /dev/null; declare -n r ; unset r ; unset -n r -declare -n r; printf -v r / +declare -n r; printf -v r / ; unset -n r + +declare -n r; r="" ; unset -n r +declare -n r="" ; unset -n r +declare -n r; : ${r=} ; unset -n r +declare -n r; printf -v r '' ; unset -n r +r=""; declare -n r ; unset -n r +export r + +# coproc tests, since coproc sets and unsets variables +declare -r ROVAR=42 +declare -p ROVAR; coproc ROVAR { :; }; wait; declare -p ROVAR + +echo ${@:0}; coproc @ { :; }; wait ; echo ${@:0} + +declare -n ref=x; coproc ref { :; }; wait ; declare -p ref +unset -n ref ; unset ref + +declare -r RO RO_PID; coproc RO { :; }; declare -p RO_PID; wait; declare -p RO RO_PID + +declare -r RO2=a; declare -n ref_PID=RO2; coproc ref { :; }; wait; declare -p RO2 diff --git a/tests/nameref12.sub b/tests/nameref12.sub index 7a5936cc..531d4e87 100644 --- a/tests/nameref12.sub +++ b/tests/nameref12.sub @@ -31,6 +31,8 @@ declare -p RO unset -n r; unset r +# the details of this may change; currently we put namerefs and values into +# the tempenv if the nameref value is an invalid variable name f() { echo $r; } declare -n r @@ -63,3 +65,36 @@ f() declare -p ref } f + +unset ref; unset -n ref +unset var + +var=foo +typeset -n ref=var[0] +readonly ref +typeset -p var + +var2=foo +typeset -n ref2=var2 +readonly ref2 +typeset -p var2 + +unset var +unset -n ref ref2 + +unset var; typeset -n ref=var +ref[0]=foo +typeset -p ref var +unset -n ref + +unset var; typeset -n ref +ref[0]=foo +typeset -p ref +unset -n ref + +ref=global +f() { declare -n ref=var; ref[0]=foo1; }; f +f() { declare -n ref=var; ref[0]=foo2; }; f +declare -p ref var + +declare -p global diff --git a/tests/nameref14.sub b/tests/nameref14.sub new file mode 100644 index 00000000..7880b007 --- /dev/null +++ b/tests/nameref14.sub @@ -0,0 +1,43 @@ +# exporting namerefs and putting namerefs in temp env post bash-4.3 + +typeset -nx ref=var; +typeset -p ref + +var=foo; str='' +printenv ref # var +ref+=$str printenv ref # var +ref+="$str" printenv ref # var +ref=$ref$str printenv ref # var + +export ref # follows nameref and exports var + +printenv var # foo +ref+=$str printenv var # foo +ref+="$str" printenv var # foo +ref=$ref$str printenv var # foo + +# none of these should change ref; should follow the nameref and export var +unset var; unset -n ref; typeset -n ref=var + +echo before +typeset -p ref var + +echo first +ref=xxx typeset -p ref var + +echo invalid +var= ref=5 typeset -p ref var + +echo after +typeset -p ref var + +# ref isn't exported, so none of the printenvs should print anything +unset var ; unset -n ref +typeset -n ref=var; +typeset -p ref + +var=foo; str='' +printenv ref +ref+=$str printenv ref +ref+="$str" printenv ref +ref=$ref$str printenv ref diff --git a/variables.c b/variables.c index 1877b175..256ddb3c 100644 --- a/variables.c +++ b/variables.c @@ -176,6 +176,9 @@ static int export_env_size; static int winsize_assignment; /* currently assigning to LINES or COLUMNS */ #endif +SHELL_VAR nameref_invalid_value; +static SHELL_VAR nameref_maxloop_value; + static HASH_TABLE *last_table_searched; /* hash_lookup sets this */ /* Some forward declarations. */ @@ -485,7 +488,8 @@ initialize_shell_variables (env, privmode) qnx_nidtostr (getnid (), node_name, sizeof (node_name)); # endif temp_var = bind_variable ("NODE", node_name, 0); - set_auto_export (temp_var); + if (temp_var) + set_auto_export (temp_var); } #endif @@ -948,7 +952,7 @@ make_vers_array () ARRAY *av; char *s, d[32], b[INT_STRLEN_BOUND(int) + 1]; - unbind_variable ("BASH_VERSINFO"); + unbind_variable_noref ("BASH_VERSINFO"); vv = make_new_array_variable ("BASH_VERSINFO"); av = array_cell (vv); @@ -1898,7 +1902,7 @@ find_variable_nameref (v) SHELL_VAR *v; { int level, flags; - char *newname; + char *newname, *t; SHELL_VAR *orig, *oldv; level = 0; @@ -1915,6 +1919,7 @@ find_variable_nameref (v) flags = 0; if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) flags |= FV_FORCETEMPENV; + /* We don't handle array subscripts here. */ v = find_variable_internal (newname, flags); if (v == orig || v == oldv) { @@ -1944,15 +1949,12 @@ find_variable_last_nameref (name, vflags) return ((SHELL_VAR *)0); /* error message here? */ newname = nameref_cell (v); if (newname == 0 || *newname == '\0') -#if 0 - return ((SHELL_VAR *)0); -#else return ((vflags && invisible_p (v)) ? v : (SHELL_VAR *)0); -#endif nv = v; flags = 0; if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) flags |= FV_FORCETEMPENV; + /* We don't accommodate array subscripts here. */ v = find_variable_internal (newname, flags); } return nv; @@ -1977,12 +1979,9 @@ find_global_variable_last_nameref (name, vflags) return ((SHELL_VAR *)0); /* error message here? */ newname = nameref_cell (v); if (newname == 0 || *newname == '\0') -#if 0 - return ((SHELL_VAR *)0); -#else return ((vflags && invisible_p (v)) ? v : (SHELL_VAR *)0); -#endif nv = v; + /* We don't accommodate array subscripts here. */ v = find_global_variable_noref (newname); } return nv; @@ -2004,7 +2003,7 @@ find_nameref_at_context (v, vc) { level++; if (level > NAMEREF_MAX) - return ((SHELL_VAR *)NULL); + return (&nameref_maxloop_value); newname = nameref_cell (nv); if (newname == 0 || *newname == '\0') return ((SHELL_VAR *)NULL); @@ -2034,6 +2033,8 @@ find_variable_nameref_context (v, vc, nvcp) for (nv = v, nvc = vc; nvc; nvc = nvc->down) { nv2 = find_nameref_at_context (nv, nvc); + if (nv2 == &nameref_maxloop_value) + return (nv2); /* XXX */ if (nv2 == 0) continue; nv = nv2; @@ -2063,6 +2064,8 @@ find_variable_last_nameref_context (v, vc, nvcp) for (nv = v, nvc = vc; nvc; nvc = nvc->down) { nv2 = find_nameref_at_context (nv, nvc); + if (nv2 == &nameref_maxloop_value) + return (nv2); /* XXX */ if (nv2 == 0) continue; nv = nv2; @@ -2072,6 +2075,58 @@ find_variable_last_nameref_context (v, vc, nvcp) return (nameref_p (nv) ? nv : (SHELL_VAR *)NULL); } +SHELL_VAR * +find_variable_nameref_for_create (name, flags) + const char *name; + int flags; +{ + SHELL_VAR *var; + + /* See if we have a nameref pointing to a variable that hasn't been + created yet. */ + var = find_variable_last_nameref (name, 1); + if ((flags&1) && var && nameref_p (var) && invisible_p (var)) + { + internal_warning (_("%s: removing nameref attribute"), name); + VUNSETATTR (var, att_nameref); + } + if (var && nameref_p (var)) + { + if (legal_identifier (nameref_cell (var)) == 0) + { + sh_invalidid (nameref_cell (var) ? nameref_cell (var) : ""); + return ((SHELL_VAR *)INVALID_NAMEREF_VALUE); + } + } + return (var); +} + +SHELL_VAR * +find_variable_nameref_for_assignment (name, flags) + const char *name; + int flags; +{ + SHELL_VAR *var; + + /* See if we have a nameref pointing to a variable that hasn't been + created yet. */ + var = find_variable_last_nameref (name, 1); + if (var && nameref_p (var) && invisible_p (var)) /* XXX - flags */ + { + internal_warning (_("%s: removing nameref attribute"), name); + VUNSETATTR (var, att_nameref); + } + if (var && nameref_p (var)) + { + if (valid_nameref_value (nameref_cell (var), 1) == 0) + { + sh_invalidid (nameref_cell (var) ? nameref_cell (var) : ""); + return ((SHELL_VAR *)INVALID_NAMEREF_VALUE); + } + } + return (var); +} + /* Find a variable, forcing a search of the temporary environment first */ SHELL_VAR * find_variable_tempenv (name) @@ -2652,7 +2707,7 @@ bind_variable_internal (name, value, table, hflags, aflags) declare -n ref' */ if (entry && invisible_p (entry) && nameref_p (entry)) { - if (value && *value && valid_nameref_value (value, 0) == 0) + if ((aflags & ASS_FORCE) == 0 && value && valid_nameref_value (value, 0) == 0) { sh_invalidid (value); return ((SHELL_VAR *)NULL); @@ -2814,9 +2869,27 @@ bind_variable (name, value, flags) #endif return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags)); } + else if (nv == &nameref_maxloop_value) + { + internal_warning (_("%s: circular name reference"), v->name); +#if 0 + return (bind_variable_value (v, value, flags|ASS_NAMEREF)); +#else + return (bind_variable_internal (v->name, value, nvc->table, 0, flags)); +#endif + } else v = nv; } + else if (nv == &nameref_maxloop_value) + { + internal_warning (_("%s: circular name reference"), v->name); +#if 0 + return (bind_variable_value (v, value, flags|ASS_NAMEREF)); +#else + return (bind_variable_internal (v->name, value, nvc->table, 0, flags)); +#endif + } else v = nv; } @@ -3054,7 +3127,7 @@ assign_in_env (word, flags) int flags; { int offset, aflags; - char *name, *temp, *value; + char *name, *temp, *value, *newname; SHELL_VAR *var; const char *string; @@ -3062,7 +3135,7 @@ assign_in_env (word, flags) aflags = 0; offset = assignment (string, 0); - name = savestring (string); + newname = name = savestring (string); value = (char *)NULL; if (name[offset] == '=') @@ -3078,7 +3151,21 @@ assign_in_env (word, flags) var = find_variable (name); if (var == 0) - var = find_variable_last_nameref (name, 1); + { + var = find_variable_last_nameref (name, 1); + /* If we're assigning a value to a nameref variable in the temp + environment, and the value of the nameref is valid for assignment, + but the variable does not already exist, assign to the nameref + target and add the target to the temporary environment. This is + what ksh93 does */ + if (var && nameref_p (var) && valid_nameref_value (nameref_cell (var), 1)) + { + newname = nameref_cell (var); + var = 0; /* don't use it for append */ + } + } + else + newname = name_cell (var); /* no-op if not nameref */ if (var && (readonly_p (var) || noassign_p (var))) { @@ -3088,19 +3175,16 @@ assign_in_env (word, flags) return (0); } temp = name + offset + 1; - if (var && nameref_p (var) && valid_nameref_value (temp, 0) == 0) - { - /* If we're assigning a value to a nameref variable in the temp - environment that's an invalid name, flag an error. */ - sh_invalidid (temp); - free (name); - return (0); - } value = expand_assignment_string_to_string (temp, 0); if (var && (aflags & ASS_APPEND)) { + if (value == 0) + { + value = (char *)xmalloc (1); /* like do_assignment_internal */ + value[0] = '\0'; + } temp = make_variable_value (var, value, aflags); FREE (value); value = temp; @@ -3110,15 +3194,15 @@ assign_in_env (word, flags) if (temporary_env == 0) temporary_env = hash_create (TEMPENV_HASH_BUCKETS); - var = hash_lookup (name, temporary_env); + var = hash_lookup (newname, temporary_env); if (var == 0) - var = make_new_variable (name, temporary_env); + var = make_new_variable (newname, temporary_env); else FREE (value_cell (var)); if (value == 0) { - value = (char *)xmalloc (1); /* like do_assignment_internal */ + value = (char *)xmalloc (1); /* see above */ value[0] = '\0'; } @@ -3127,12 +3211,12 @@ assign_in_env (word, flags) var->context = variable_context; /* XXX */ INVALIDATE_EXPORTSTR (var); - var->exportstr = mk_env_string (name, value, 0); + var->exportstr = mk_env_string (newname, value, 0); array_needs_making = 1; if (flags) - stupidly_hack_special_variables (name); + stupidly_hack_special_variables (newname); if (echo_command_at_execute) /* The Korn shell prints the `+ ' in front of assignment statements, @@ -3264,6 +3348,19 @@ unbind_nameref (name) return 0; } +/* Unbind the first instance of NAME, whether it's a nameref or not */ +int +unbind_variable_noref (name) + const char *name; +{ + SHELL_VAR *v; + + v = var_lookup (name, shell_variables); + if (v) + return makunbound (name, shell_variables); + return 0; +} + int check_unbind_variable (name) const char *name; @@ -3273,7 +3370,7 @@ check_unbind_variable (name) v = find_variable (name); if (v && readonly_p (v)) { - builtin_error (_("%s: cannot unset: readonly %s"), name, "variable"); + internal_error (_("%s: cannot unset: readonly %s"), name, "variable"); return -1; } return (unbind_variable (name)); @@ -3954,7 +4051,8 @@ push_temp_var (data) if (binding_table == shell_variables->table) shell_variables->flags |= VC_HASTMPVAR; } - v->attributes |= var->attributes; + if (v) + v->attributes |= var->attributes; if (find_special_var (var->name) >= 0) tempvar_list[tvlist_ind++] = savestring (var->name); @@ -4548,7 +4646,8 @@ push_func_var (data) var->attributes &= ~(att_tempvar|att_propagate); else shell_variables->flags |= VC_HASTMPVAR; - v->attributes |= var->attributes; + if (v) + v->attributes |= var->attributes; } else stupidly_hack_special_variables (var->name); /* XXX */ @@ -4636,7 +4735,8 @@ push_exported_var (data) 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; + if (v) + v->attributes |= var->attributes; } else stupidly_hack_special_variables (var->name); /* XXX */ diff --git a/variables.h b/variables.h index 84e49d4a..5a7e44ea 100644 --- a/variables.h +++ b/variables.h @@ -217,6 +217,10 @@ typedef struct _vlist { } while (0) #define ifsname(s) ((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0') + +/* Special value for nameref with invalid value for creation or assignment */ +extern SHELL_VAR nameref_invalid_value; +#define INVALID_NAMEREF_VALUE (void *)&nameref_invalid_value /* Stuff for hacking variables. */ typedef int sh_var_map_func_t __P((SHELL_VAR *)); @@ -249,6 +253,8 @@ extern SHELL_VAR *find_variable_noref __P((const char *)); extern SHELL_VAR *find_variable_last_nameref __P((const char *, int)); extern SHELL_VAR *find_global_variable_last_nameref __P((const char *, int)); extern SHELL_VAR *find_variable_nameref __P((SHELL_VAR *)); +extern SHELL_VAR *find_variable_nameref_for_create __P((const char *, int)); +extern SHELL_VAR *find_variable_nameref_for_assignment __P((const char *, int)); extern SHELL_VAR *find_variable_internal __P((const char *, int)); extern SHELL_VAR *find_variable_tempenv __P((const char *)); extern SHELL_VAR *find_variable_notempenv __P((const char *)); @@ -298,6 +304,7 @@ extern int assign_in_env __P((WORD_DESC *, int)); extern int unbind_variable __P((const char *)); extern int check_unbind_variable __P((const char *)); extern int unbind_nameref __P((const char *)); +extern int unbind_variable_noref __P((const char *)); extern int unbind_func __P((const char *)); extern int unbind_function_def __P((const char *)); extern int delete_var __P((const char *, VAR_CONTEXT *));