diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 459cfb87..b33d763b 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -10714,3 +10714,87 @@ lib/readline/complete.c or equal to the length of the string to be printed (print_len), make sure to set the prefix length to 0 so the entire string is printed. From a report from Grisha Levit + + 4/25 + ---- +subst.c + - command_substitute: update the conditions under which we give the + terminal to pipeline_pgrp with give_terminal_to to the same ones + where wait_for uses to decide whether to give the terminal back to + shell_pgrp. This code exists to undo the work wait_for does; it + has to give the terminal back to pipeline_pgrp only under those + conditions when wait_for gives it back to the shell pgrp. Fix for + bug reported by Paulo Bardes + + 4/26 + ---- +bashline.c + - bash_filename_stat_hook: temporarily disable the `nounset' shell + option around calls to expand_prompt_string so we don't get error + messages during completion. Fixes issue reported by Eric Pruitt + + + 4/27 + ---- +doc/{bash.1,bashref.texi} + - extdebug: clarify that having this option enabled at shell startup + acts identically to --debugger. From a report from Grisha Levit + + +jobs.[ch] + - wait_for_single_pid: now takes additional `int flags' argument + +{jobs,execute_cmd}.c,builtins/wait.def + - wait_for_single_pid: changed callers to add extra argument + +jobs.c + - wait_for_single_pid: if (flags & 1) == 0, don't print the error message + if PID isn't found; changed execute_pipeline call when lastpipe is + set + + 4/28 + ---- +general.c + - bash_tilde_expand: try not setting interrupt_immediately or + terminate_immediately; see what happens with networked password + databases + + 4/29 + ---- +subst.c + - parameter_brace_expand, parameter_brace_expand_rhs: now take an + additional `pflags' argument from its caller so we can pass + state + - parameter_brace_expand_rhs: if expand_string_for_rhs returns a + quoted null, but l_hasdollat is set to 1, meaning we saw a quoted + "$@" of some form, we need to turn off special handling of "$@" + so something like "${@-${@-$@}}" expands to an empty string like + Posix says it should. Fixes bug reported by Grisha Levit + + + 5/1 + --- +variables.c + - bind_variable_internal: if we have a nameref variable with a valid + array reference that is invalid for assignment (e.g., a[*]), and + assign_array_element returns NULL, short-circuit and return NULL. + Fixes bug reported by Grisha Levit + +general.[ch] + - valid_nameref_value: new function, return 1 if passed argument is + a valid variable name argument for a nameref variable: a valid + identifier, a valid array reference, or a valid positional + parameter. Second argument indicates whether the value is to be + used for an assignment; in this case, return an error if the name + consists of all digits + +builtins/declare.def + - declare_internal: disallow values for nameref variables that don't + pass the tests in valid_nameref_value. Part of fix for bug + reported by Grisha Levit + +variables.c + - bind_variable_internal: if trying to assign a value to a nameref + variable, throw an error if valid_nameref_value fails (with a second + argument of 1). More fixes for bug reported by Grisha Levit + diff --git a/MANIFEST b/MANIFEST index c7fc63f1..4b266d21 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1061,6 +1061,7 @@ tests/jobs.right f tests/lastpipe.right f tests/lastpipe.tests f tests/lastpipe1.sub f +tests/lastpipe2.sub f tests/mapfile.data f tests/mapfile.right f tests/mapfile.tests f diff --git a/bashline.c b/bashline.c index 3d1927ef..3f1027fc 100644 --- a/bashline.c +++ b/bashline.c @@ -54,6 +54,7 @@ #include "pathexp.h" #include "shmbutil.h" #include "trap.h" +#include "flags.h" #if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR) # include /* mbschr */ @@ -1648,6 +1649,11 @@ bash_default_completion (text, start, end, qc, compflags) else { matches = rl_completion_matches (text, variable_completion_function); + /* If a single match, see if it expands to a directory name and append + a slash if it does. This requires us to expand the variable name, + so we don't want to display errors if the variable is unset. This + can happen with dynamic variables whose value has never been + requested. */ if (matches && matches[0] && matches[1] == 0) { t = savestring (matches[0]); @@ -3124,6 +3130,7 @@ bash_filename_stat_hook (dirname) { char *local_dirname, *new_dirname, *t; int should_expand_dirname, return_value; + int global_nounset; WORD_LIST *wl; struct stat sb; @@ -3140,7 +3147,12 @@ bash_filename_stat_hook (dirname) if (should_expand_dirname) { new_dirname = savestring (local_dirname); + /* no error messages, and expand_prompt_string doesn't longjmp so we don't + have to worry about restoring this setting. */ + global_nounset = unbound_vars_is_error; + unbound_vars_is_error = 0; wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB); /* does the right thing */ + unbound_vars_is_error = global_nounset; if (wl) { free (new_dirname); diff --git a/builtins/declare.def b/builtins/declare.def index a1e9b4e5..d8339b1f 100644 --- a/builtins/declare.def +++ b/builtins/declare.def @@ -341,8 +341,8 @@ declare_internal (list, local_var) assign_error++; NEXT_VARIABLE (); } -#if 0 - if (value && *value && legal_identifier (value) == 0) +#if 1 + if (value && *value && valid_nameref_value (value, 0) == 0) { builtin_error (_("%s: invalid variable name for name reference"), value); assign_error++; @@ -402,6 +402,12 @@ declare_internal (list, local_var) var = make_local_array_variable (name, making_array_special); else #endif + if (offset == 0 && (flags_on & att_nameref)) + { + refvar = mkglobal ? find_global_variable_last_nameref (name) : find_variable_last_nameref (name); + var = 0; + } + else var = make_local_variable (name); /* sets att_invisible for new vars */ if (var == 0) { @@ -570,8 +576,8 @@ declare_internal (list, local_var) } else if (flags_on & att_nameref) { -#if 0 - if (nameref_p (var) == 0 && var_isset (var) && var_isnull (var) == 0 && legal_identifier (value_cell (var)) == 0) +#if 1 + if (nameref_p (var) == 0 && var_isset (var) && var_isnull (var) == 0 && valid_nameref_value (value_cell (var), 0) == 0) { builtin_error (_("%s: invalid variable name for name reference"), value_cell (var)); any_failed++; diff --git a/builtins/wait.def b/builtins/wait.def index 1cf9f879..974f959b 100644 --- a/builtins/wait.def +++ b/builtins/wait.def @@ -179,7 +179,7 @@ wait_builtin (list) if (legal_number (w, &pid_value) && pid_value == (pid_t)pid_value) { pid = (pid_t)pid_value; - status = wait_for_single_pid (pid); + status = wait_for_single_pid (pid, 1); } else { diff --git a/doc/bash.1 b/doc/bash.1 index 829a4a55..2b76cf6c 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -5,12 +5,12 @@ .\" Case Western Reserve University .\" chet.ramey@case.edu .\" -.\" Last Change: Mon Feb 8 10:15:48 EST 2016 +.\" Last Change: Wed Apr 27 09:19:58 EDT 2016 .\" .\" bash_builtins, strip all but Built-Ins section .if \n(zZ=1 .ig zZ .if \n(zY=1 .ig zY -.TH BASH 1 "2016 February 8" "GNU Bash 4.4" +.TH BASH 1 "2016 April 27" "GNU Bash 4.4" .\" .\" There's some problem with having a `@' .\" in a tagged paragraph with the BSD man macros. @@ -9627,7 +9627,9 @@ If set, aliases are expanded as described above under This option is enabled by default for interactive shells. .TP 8 .B extdebug -If set, behavior intended for use by debuggers is enabled: +If set at shell invocation, arrange to execute the debugger profile +before the shell starts, identical to the \fB\-\-debugger\fP option. +If set after invocation, behavior intended for use by debuggers is enabled: .RS .TP .B 1. diff --git a/doc/bashref.texi b/doc/bashref.texi index d95c2e37..9e6fa501 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -1513,7 +1513,7 @@ When applied to a string-valued variable, @var{value} is expanded and appended to the variable's value. A variable can be assigned the @var{nameref} attribute using the -@option{-n} option to the \fBdeclare\fP or \fBlocal\fP builtin commands +@option{-n} option to the @code{declare} or @code{local} builtin commands (@pxref{Bash Builtins}) to create a @var{nameref}, or a reference to another variable. This allows variables to be manipulated indirectly. @@ -5143,7 +5143,9 @@ If set, aliases are expanded as described below under Aliases, This option is enabled by default for interactive shells. @item extdebug -If set, behavior intended for use by debuggers is enabled: +If set at shell invocation, arrange to execute the debugger profile +before the shell starts, identical to the @option{--debugger} option. +If set after invocation, behavior intended for use by debuggers is enabled: @enumerate @item diff --git a/doc/version.texi b/doc/version.texi index 84b4326c..2b3ce66d 100644 --- a/doc/version.texi +++ b/doc/version.texi @@ -2,10 +2,10 @@ Copyright (C) 1988-2016 Free Software Foundation, Inc. @end ignore -@set LASTCHANGE Sun Feb 28 15:32:09 EST 2016 +@set LASTCHANGE Wed Apr 27 09:19:38 EDT 2016 @set EDITION 4.4 @set VERSION 4.4 -@set UPDATED 28 February 2016 -@set UPDATED-MONTH February 2016 +@set UPDATED 27 April 2016 +@set UPDATED-MONTH April 2016 diff --git a/execute_cmd.c b/execute_cmd.c index 82d9ee00..05f3d036 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -2486,7 +2486,7 @@ execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close) lstdin = wait_for (lastpid); } else - lstdin = wait_for_single_pid (lastpid); /* checks bgpids list */ + lstdin = wait_for_single_pid (lastpid, 0); /* checks bgpids list */ #else lstdin = wait_for (lastpid); #endif diff --git a/general.c b/general.c index ff23f8c7..7a96090b 100644 --- a/general.c +++ b/general.c @@ -1,6 +1,6 @@ /* general.c -- Stuff that is used by all files. */ -/* Copyright (C) 1987-2015 Free Software Foundation, Inc. +/* Copyright (C) 1987-2016 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -227,6 +227,24 @@ legal_identifier (name) return (1); } +int +valid_nameref_value (name, for_assignment) + char *name; + int for_assignment; +{ + intmax_t r; + +#if defined (ARRAY_VARS) + if (legal_identifier (name) || valid_array_reference (name, 0)) +#else + if (legal_identifier (name)) +#endif + return 1; + if (for_assignment == 0 && legal_number (name, &r)) + return 1; + return 0; +} + /* Make sure that WORD is a valid shell identifier, i.e. does not contain a dollar sign, nor is quoted in any way. Nor does it consist of all digits. If CHECK_WORD is non-zero, @@ -1039,6 +1057,7 @@ bash_tilde_expand (s, assign_p) int old_immed, old_term, r; char *ret; +#if 0 old_immed = interrupt_immediately; old_term = terminate_immediately; /* We want to be able to interrupt tilde expansion. Ordinarily, we can just @@ -1048,6 +1067,7 @@ bash_tilde_expand (s, assign_p) if (any_signals_trapped () < 0) interrupt_immediately = 1; terminate_immediately = 1; +#endif tilde_additional_prefixes = assign_p == 0 ? (char **)0 : (assign_p == 2 ? bash_tilde_prefixes2 : bash_tilde_prefixes); @@ -1057,8 +1077,10 @@ bash_tilde_expand (s, assign_p) r = (*s == '~') ? unquoted_tilde_word (s) : 1; ret = r ? tilde_expand (s) : savestring (s); +#if 0 interrupt_immediately = old_immed; terminate_immediately = old_term; +#endif QUIT; diff --git a/general.h b/general.h index 430aeceb..2d37beca 100644 --- a/general.h +++ b/general.h @@ -1,6 +1,6 @@ /* general.h -- defines that everybody likes to use. */ -/* Copyright (C) 1993-2009 Free Software Foundation, Inc. +/* Copyright (C) 1993-2016 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -289,6 +289,7 @@ extern int legal_identifier __P((char *)); extern int importable_function_name __P((char *, size_t)); extern int exportable_function_name __P((char *)); extern int check_identifier __P((WORD_DESC *, int)); +extern int valid_nameref_value __P((char *, int)); extern int legal_alias_name __P((char *, int)); extern int assignment __P((const char *, int)); diff --git a/jobs.c b/jobs.c index b6c2506f..b3716ef1 100644 --- a/jobs.c +++ b/jobs.c @@ -2313,10 +2313,13 @@ find_last_pid (job, block) This low-level function prints an error message if PID is not a child of this shell. It returns -1 if it fails, or whatever wait_for returns otherwise. If the child is not found in the - jobs table, it returns 127. */ + jobs table, it returns 127. If FLAGS doesn't include 1, we + suppress the error message if PID isn't found. */ + int -wait_for_single_pid (pid) +wait_for_single_pid (pid, flags) pid_t pid; + int flags; { register PROCESS *child; sigset_t set, oset; @@ -2335,7 +2338,8 @@ wait_for_single_pid (pid) if (child == 0) { - internal_error (_("wait: pid %ld is not a child of this shell"), (long)pid); + if (flags & 1) + internal_error (_("wait: pid %ld is not a child of this shell"), (long)pid); return (127); } @@ -2395,7 +2399,7 @@ wait_for_background_pids () UNBLOCK_CHILD (oset); QUIT; errno = 0; /* XXX */ - r = wait_for_single_pid (pid); + r = wait_for_single_pid (pid, 1); if (r == -1) { /* If we're mistaken about job state, compensate. */ @@ -2789,7 +2793,11 @@ itrace("wait_for: blocking wait for %d returns %d child = %p", (int)pid, r, chil if (job == NO_JOB) itrace("wait_for: job == NO_JOB, giving the terminal to shell_pgrp (%ld)", (long)shell_pgrp); #endif - /* Don't modify terminal pgrp if we are running in background or a subshell */ + /* Don't modify terminal pgrp if we are running in background or a + subshell. Make sure subst.c:command_substitute uses the same + conditions to determine whether or not it should undo this and + give the terminal to pipeline_pgrp. */ + if (running_in_background == 0 && (subshell_environment&(SUBSHELL_ASYNC|SUBSHELL_PIPE)) == 0) give_terminal_to (shell_pgrp, 0); } diff --git a/jobs.h b/jobs.h index 88c4b78a..4ba3513c 100644 --- a/jobs.h +++ b/jobs.h @@ -230,7 +230,7 @@ extern int set_tty_state __P((void)); extern int job_exit_status __P((int)); extern int job_exit_signal __P((int)); -extern int wait_for_single_pid __P((pid_t)); +extern int wait_for_single_pid __P((pid_t, int)); extern void wait_for_background_pids __P((void)); extern int wait_for __P((pid_t)); extern int wait_for_job __P((int)); diff --git a/lib/readline/doc/rltech.texi b/lib/readline/doc/rltech.texi index 9b21e279..0902852a 100644 --- a/lib/readline/doc/rltech.texi +++ b/lib/readline/doc/rltech.texi @@ -1435,12 +1435,16 @@ It understands the EOF character or "exit" to exit the program. @example /* Standard include files. stdio.h is required. */ #include +#include #include +#include /* Used for select(2) */ #include #include +#include + #include /* Standard readline include files. */ @@ -1448,10 +1452,20 @@ It understands the EOF character or "exit" to exit the program. #include static void cb_linehandler (char *); +static void sighandler (int); int running; +int sigwinch_received; const char *prompt = "rltest$ "; +/* Handle SIGWINCH and window size changes when readline is not active and + reading a character. */ +static void +sighandler (int sig) +@{ + sigwinch_received = 1; +@} + /* Callback function called for each line when accept-line executed, EOF seen, or EOF character read. This sets a flag and returns; it could also call exit(3). */ @@ -1486,6 +1500,13 @@ main (int c, char **v) fd_set fds; int r; + /* Set the default locale values according to environment variables. */ + setlocale (LC_ALL, ""); + + /* Handle window size changes when readline is not active and reading + characters. */ + signal (SIGWINCH, sighandler); + /* Install the line handler. */ rl_callback_handler_install (prompt, cb_linehandler); @@ -1500,12 +1521,19 @@ main (int c, char **v) FD_SET (fileno (rl_instream), &fds); r = select (FD_SETSIZE, &fds, NULL, NULL, NULL); - if (r < 0) + if (r < 0 && errno != EINTR) @{ perror ("rltest: select"); rl_callback_handler_remove (); break; @} + if (sigwinch_received) + @{ + rl_resize_terminal (); + sigwinch_received = 0; + }@ + if (r < 0) + continue; if (FD_ISSET (fileno (rl_instream), &fds)) rl_callback_read_char (); diff --git a/lib/tilde/tilde.c b/lib/tilde/tilde.c index 3788eba6..95bc4215 100644 --- a/lib/tilde/tilde.c +++ b/lib/tilde/tilde.c @@ -236,7 +236,11 @@ tilde_expand (string) string += end; expansion = tilde_expand_word (tilde_word); - xfree (tilde_word); + + if (expansion == 0) + expansion = tilde_word; + else + xfree (tilde_word); len = strlen (expansion); #ifdef __CYGWIN__ diff --git a/subst.c b/subst.c index 4d90b46a..5af7bb58 100644 --- a/subst.c +++ b/subst.c @@ -4,7 +4,7 @@ /* ``Have a little faith, there's magic in the night. You ain't a beauty, but, hey, you're alright.'' */ -/* Copyright (C) 1987-2015 Free Software Foundation, Inc. +/* Copyright (C) 1987-2016 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -170,9 +170,9 @@ int no_longjmp_on_fatal_error = 0; /* Extern functions and variables from different files. */ extern int last_command_exit_value, last_command_exit_signal; -extern int subshell_environment, line_number; +extern int subshell_environment, running_in_background; extern int subshell_level, parse_and_execute_level, sourcelevel; -extern int eof_encountered; +extern int eof_encountered, line_number; extern int return_catch_flag, return_catch_value; extern pid_t dollar_dollar_pid; extern int posixly_correct; @@ -310,7 +310,7 @@ static int chk_arithsub __P((const char *, int)); static WORD_DESC *parameter_brace_expand_word __P((char *, int, int, int, arrayind_t *)); static char *parameter_brace_find_indir __P((char *, int, int, int)); static WORD_DESC *parameter_brace_expand_indir __P((char *, int, int, int *, int *)); -static WORD_DESC *parameter_brace_expand_rhs __P((char *, char *, int, int, int *, int *)); +static WORD_DESC *parameter_brace_expand_rhs __P((char *, char *, int, int, int, int *, int *)); static void parameter_brace_expand_error __P((char *, char *)); static int valid_length_expression __P((char *)); @@ -3728,9 +3728,9 @@ expand_string_leave_quoted (string, quoted) /* This does not perform word splitting or dequote the WORD_LIST it returns. */ static WORD_LIST * -expand_string_for_rhs (string, quoted, dollar_at_p, has_dollar_at) +expand_string_for_rhs (string, quoted, dollar_at_p, expanded_p) char *string; - int quoted, *dollar_at_p, *has_dollar_at; + int quoted, *dollar_at_p, *expanded_p; { WORD_DESC td; WORD_LIST *tresult; @@ -3741,7 +3741,7 @@ expand_string_for_rhs (string, quoted, dollar_at_p, has_dollar_at) expand_no_split_dollar_star = 1; td.flags = W_NOSPLIT2; /* no splitting, remove "" and '' */ td.word = string; - tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, has_dollar_at); + tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p); expand_no_split_dollar_star = 0; return (tresult); @@ -6174,8 +6174,13 @@ command_substitute (string, quoted) pipeline_pgrp is non-zero only while we are constructing a pipeline, so what we are concerned about is whether or not that pipeline was started in the background. A pipeline started in - the background should never get the tty back here. */ - if (interactive && pipeline_pgrp != (pid_t)0 && (subshell_environment & SUBSHELL_ASYNC) == 0) + the background should never get the tty back here. We duplicate + the conditions that wait_for tests to make sure we only give + the terminal back to pipeline_pgrp under the conditions that wait_for + gave it to shell_pgrp. If wait_for doesn't mess with the terminal + pgrp, we should not either. */ + if (interactive && pipeline_pgrp != (pid_t)0 && running_in_background == 0 && + (subshell_environment & (SUBSHELL_ASYNC|SUBSHELL_PIPE)) == 0) give_terminal_to (pipeline_pgrp, 0); #endif /* JOB_CONTROL */ @@ -6579,45 +6584,49 @@ parameter_brace_expand_indir (name, var_is_special, quoted, quoted_dollar_atp, c "-", "+", or "=". QUOTED is true if the entire brace expression occurs between double quotes. */ static WORD_DESC * -parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat) +parameter_brace_expand_rhs (name, value, c, quoted, pflags, qdollaratp, hasdollarat) char *name, *value; - int c, quoted, *qdollaratp, *hasdollarat; + int c, quoted, pflags, *qdollaratp, *hasdollarat; { WORD_DESC *w; WORD_LIST *l; char *t, *t1, *temp, *vname; - int hasdol; + int l_hasdollat, sindex; +/*itrace("parameter_brace_expand_rhs: %s:%s pflags = %d", name, value, pflags);*/ /* If the entire expression is between double quotes, we want to treat the value as a double-quoted string, with the exception that we strip embedded unescaped double quotes (for sh backwards compatibility). */ if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value) { - hasdol = 0; - temp = string_extract_double_quoted (value, &hasdol, 1); + sindex = 0; + temp = string_extract_double_quoted (value, &sindex, 1); } else temp = value; w = alloc_word_desc (); - hasdol = 0; + l_hasdollat = 0; /* XXX was 0 not quoted */ - l = *temp ? expand_string_for_rhs (temp, quoted, &hasdol, (int *)NULL) + l = *temp ? expand_string_for_rhs (temp, quoted, &l_hasdollat, (int *)NULL) : (WORD_LIST *)0; if (hasdollarat) - *hasdollarat = hasdol || (l && l->next); + *hasdollarat = l_hasdollat || (l && l->next); if (temp != value) free (temp); if (l) { /* If l->next is not null, we know that TEMP contained "$@", since that is the only expansion that creates more than one word. */ - if (qdollaratp && ((hasdol && quoted) || l->next)) - *qdollaratp = 1; + if (qdollaratp && ((l_hasdollat && quoted) || l->next)) + { +/*itrace("parameter_brace_expand_rhs: %s:%s: l != NULL, set *qdollaratp", name, value);*/ + *qdollaratp = 1; + } /* The expansion of TEMP returned something. We need to treat things - slightly differently if HASDOL is non-zero. If we have "$@", the - individual words have already been quoted. We need to turn them + slightly differently if L_HASDOLLAT is non-zero. If we have "$@", + the individual words have already been quoted. We need to turn them into a string with the words separated by the first character of $IFS without any additional quoting, so string_list_dollar_at won't do the right thing. If IFS is null, we want "$@" to split into @@ -6630,7 +6639,7 @@ parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat) w->flags |= W_SPLITSPACE; } else - temp = (hasdol || l->next) ? string_list_dollar_star (l) : string_list (l); + temp = (l_hasdollat || l->next) ? string_list_dollar_star (l) : string_list (l); /* If we have a quoted null result (QUOTED_NULL(temp)) and the word is a quoted null (l->next == 0 && QUOTED_NULL(l->word->word)), the @@ -6641,24 +6650,32 @@ parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat) if (l->next == 0 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp) && QUOTED_NULL (l->word->word) && (l->word->flags & W_HASQUOTEDNULL)) { w->flags |= W_HASQUOTEDNULL; +/*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null, turning off qdollaratp", name, value);*/ + /* If we return a quoted null with L_HASDOLLARAT, we either have a + construct like "${@-$@}" or "${@-${@-$@}}" with no positional + parameters or a quoted expansion of "$@" with $1 == ''. In either + case, we don't want to enable special handling of $@. */ + if (qdollaratp && l_hasdollat) + *qdollaratp = 0; } dispose_words (l); } - else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && hasdol) + else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && l_hasdollat) { /* Posix interp 221 changed the rules on this. The idea is that something like "$xxx$@" should expand the same as "${foo-$xxx$@}" when foo and xxx are unset. The problem is that it's not in any way backwards compatible and few other shells do it. We're eventually going to try and split the difference (heh) a little bit here. */ - /* hasdol == 1 means we saw a quoted dollar at. */ + /* l_hasdollat == 1 means we saw a quoted dollar at. */ /* The brace expansion occurred between double quotes and there was a $@ in TEMP. It does not matter if the $@ is quoted, as long as it does not expand to anything. In this case, we want to return - a quoted empty string. */ + a quoted empty string. Posix interp 888 */ temp = make_quoted_char ('\0'); w->flags |= W_HASQUOTEDNULL; +/*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null", name, value);*/ } else temp = (char *)NULL; @@ -7795,7 +7812,7 @@ chk_arithsub (s, len) static WORD_DESC * parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, contains_dollar_at) char *string; - int *indexp, quoted, *quoted_dollar_atp, *contains_dollar_at, pflags; + int *indexp, quoted, pflags, *quoted_dollar_atp, *contains_dollar_at; { int check_nullness, var_is_set, var_is_null, var_is_special; int want_substring, want_indir, want_patsub, want_casemod; @@ -8299,6 +8316,7 @@ bad_substitution: quoted |= Q_DOLBRACE; ret = parameter_brace_expand_rhs (name, value, c, quoted, + pflags, quoted_dollar_atp, contains_dollar_at); /* XXX - fix up later, esp. noting presence of @@ -8346,7 +8364,7 @@ bad_substitution: removed. */ if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) quoted |= Q_DOLBRACE; - ret = parameter_brace_expand_rhs (name, value, c, quoted, + ret = parameter_brace_expand_rhs (name, value, c, quoted, pflags, quoted_dollar_atp, contains_dollar_at); /* XXX - fix up later, esp. noting presence of @@ -8388,6 +8406,7 @@ param_expand (string, sindex, quoted, expanded_something, WORD_DESC *tdesc, *ret; int tflag; +/*itrace("param_expand: `%s' pflags = %d", string+*sindex, pflags);*/ zindex = *sindex; c = string[++zindex]; 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/histexp.right b/tests/histexp.right index c929e585..5b3dbdf8 100644 --- a/tests/histexp.right +++ b/tests/histexp.right @@ -129,7 +129,8 @@ ok 2 ok 3 echo shopt a shopt a -echo a b c d 2 > /dev/null +echo a b c d 2> /dev/null +a b c d ! ! ! diff --git a/tests/histexp.tests b/tests/histexp.tests index ca701870..e440b988 100644 --- a/tests/histexp.tests +++ b/tests/histexp.tests @@ -123,6 +123,8 @@ echo ${!var2} # history_comment_char echo ok 3 # !1200 +# bash versions through bash-4.3 fail this; they make the digit preceding the +# > into a separate word, changing the meaning of the redirection shopt a b c d 2>/dev/null echo !shopt-1 diff --git a/tests/lastpipe.right b/tests/lastpipe.right index 23fe0891..0168df85 100644 --- a/tests/lastpipe.right +++ b/tests/lastpipe.right @@ -8,3 +8,12 @@ last = c 1 -- 0 0 1 1 -- 0 1 0 lastpipe1.sub returns 14 +A1 +A2 +B1 +B2 +HI +A1 +A2 +B1 +B2 diff --git a/tests/lastpipe.tests b/tests/lastpipe.tests index 13fa214f..16dc8419 100644 --- a/tests/lastpipe.tests +++ b/tests/lastpipe.tests @@ -56,3 +56,6 @@ set +o pipefail ${THIS_SH} ./lastpipe1.sub echo lastpipe1.sub returns $? + +${THIS_SH} ./lastpipe2.sub + diff --git a/tests/lastpipe2.sub b/tests/lastpipe2.sub new file mode 100644 index 00000000..7cb6dc14 --- /dev/null +++ b/tests/lastpipe2.sub @@ -0,0 +1,20 @@ +shopt -s lastpipe +echo -e 'A\nB' | while read letter; do + echo -e '1\n2' | while read digit; do + echo $letter$digit + done +done + +myPipefunc() +{ + cat | tee $TMPDIR/outfile +} +echo HI | myPipefunc + +echo -e 'A\nB' | while read letter; do + echo -e '1\n2' | while read digit; do + echo $letter$digit | myPipefunc + done +done + +rm -f $TMPDIR/outfile diff --git a/tests/outfile b/tests/outfile new file mode 100644 index 00000000..6d8ba7cb --- /dev/null +++ b/tests/outfile @@ -0,0 +1 @@ +B2 diff --git a/variables.c b/variables.c index 69ed1703..839f5635 100644 --- a/variables.c +++ b/variables.c @@ -2629,15 +2629,26 @@ bind_variable_internal (name, value, table, hflags, aflags) /* The first clause handles `declare -n ref; ref=x;' */ if (entry && invisible_p (entry) && nameref_p (entry)) - goto assign_value; + { + if (valid_nameref_value (value, 1) == 0) + { + sh_invalidid (value); + return ((SHELL_VAR *)NULL); + } + 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, 0)) - /* XXX - should it be aflags? */ - entry = assign_array_element (newval, make_variable_value (entry, value, 0), aflags); + { + /* XXX - should it be aflags? */ + entry = assign_array_element (newval, make_variable_value (entry, value, 0), aflags); + if (entry == 0) + return entry; + } else #endif {