subst.c,subst.h
- rename quote_rhs -> quote_nosplit
+ 2/19
+ ----
+
subst.c
- quote_var_value: break the code that quotes a variable value ($x,
${x}, ${x[n]}, etc.) into a separate inline function and call it
AV_ASSIGNRHS if we are expanding unquoted ${A[*]} in a place where
word splitting does not occur with a non-null $IFS; array_value will
quote appropriately here
+ - parameter_brace_expand_word,param_expand: use quote_var_value when
+ expanding $N and ${N}
+
+doc/bash.1,doc/bashref.texi
+ - HISTIGNORE: clarify the description a little to emphasize that lines
+ matching one of the patterns are not saved in the history list
+ From https://savannah.gnu.org/support/index.php?111020
+
+ 2/20
+ ----
+builtins/evalfile.c
+ - FEVAL_RETRY: if set in FLAGS, _evalfile will retry an interrupted
+ open
+ - _evalfile: if open() returns -1, FEVAL_RETRY is set in FLAGS, and
+ errno == EINTR, retry the open after checking for interrupts or
+ terminating signals
+ - maybe_execute_file,force_execute_file: pass FEVAL_RETRY in flags
+
+bashhist.c
+ - load_history: retry read_history if it returns EINTR after checking
+ for interrupts or terminating signals
+
+lib/readline/bind.c
+ - _rl_read_init_file: retry the open once if it's interrupted due to a
+ signal. If we are at a point where readline has installed its
+ signal handlers, check for signals readline handles
+ From a patch from Grisha Levit <grishalevit@gmail.com>
if (hf && *hf && file_exists (hf))
{
- read_history (hf);
+ while (read_history (hf) == EINTR) /* 0 on success */
+ QUIT;
/* We have read all of the lines from the history file, even if we
read more lines than $HISTSIZE. Remember the total number of lines
we read so we don't count the last N lines as new over and over
#define FEVAL_CHECKBINARY 0x040
#define FEVAL_REGFILE 0x080
#define FEVAL_NOPUSHARGS 0x100
+#define FEVAL_RETRY 0x200
/* How many `levels' of sourced files we have. */
int sourcelevel = 0;
USE_VAR(pflags);
-#if defined (ARRAY_VARS)
- GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a);
- GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a);
- GET_ARRAY_FROM_VAR ("BASH_LINENO", bash_lineno_v, bash_lineno_a);
-# if defined (DEBUGGER)
- GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
- GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
-# endif
-#endif
-
- fd = open (filename, O_RDONLY);
+ errno = 0;
+ do
+ {
+ fd = open (filename, O_RDONLY);
+ i = errno;
+ if (fd < 0 && i == EINTR)
+ QUIT;
+ errno = i;
+ }
+ while (fd < 0 && errno == EINTR && (flags & FEVAL_RETRY));
if (fd < 0 || (fstat (fd, &finfo) == -1))
{
retain_fifos++; /* XXX */
#if defined (ARRAY_VARS)
+ GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a);
+ GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a);
+ GET_ARRAY_FROM_VAR ("BASH_LINENO", bash_lineno_v, bash_lineno_a);
+# if defined (DEBUGGER)
+ GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
+ GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
+# endif
+
array_push (bash_source_a, (char *)filename);
t = itos (executing_line_number ());
array_push (bash_lineno_a, t);
int result, flags;
filename = bash_tilde_expand (fname, 0);
- flags = FEVAL_ENOENTOK;
+ flags = FEVAL_ENOENTOK|FEVAL_RETRY;
if (force_noninteractive)
flags |= FEVAL_NONINT;
result = _evalfile (filename, flags);
int result, flags;
filename = bash_tilde_expand (fname, 0);
- flags = 0;
+ flags = FEVAL_RETRY;
if (force_noninteractive)
flags |= FEVAL_NONINT;
result = _evalfile (filename, flags);
.\" Case Western Reserve University
.\" chet.ramey@case.edu
.\"
-.\" Last Change: Mon Feb 5 10:51:21 EST 2024
+.\" Last Change: Mon Feb 19 16:52:45 EST 2024
.\"
.\" bash_builtins, strip all but Built-Ins section
.\" avoid a warning about an undefined register
.\" .if !rzY .nr zY 0
.if \n(zZ=1 .ig zZ
.if \n(zY=1 .ig zY
-.TH BASH 1 "2024 February 5" "GNU Bash 5.3"
+.TH BASH 1 "2024 February 19" "GNU Bash 5.3"
.\"
.\" There's some problem with having a `@'
.\" in a tagged paragraph with the BSD man macros.
.TP
.B HISTIGNORE
A colon-separated list of patterns used to decide which command lines
-should be saved on the history list. Each pattern is anchored at the
+should be saved on the history list.
+If a command line matches one of the patterns in the value of
+.SM
+.BR HISTIGNORE ,
+it is not saved on the history list.
+Each pattern is anchored at the
beginning of the line and must match the complete line
(\fBbash\fP will not implicitly append a
.Q \fB*\fP ).
@item HISTIGNORE
A colon-separated list of patterns used to decide which command
lines should be saved on the history list.
+If a command line matches one of the patterns in the value of
+@code{HISTIGNORE}, it is not saved on the history list.
Each pattern is
anchored at the beginning of the line and must match the complete
line (Bash will not implicitly append a @samp{*}).
Copyright (C) 1988-2024 Free Software Foundation, Inc.
@end ignore
-@set LASTCHANGE Fri Feb 2 09:37:55 EST 2024
+@set LASTCHANGE Mon Feb 19 16:52:26 EST 2024
@set EDITION 5.3
@set VERSION 5.3
-@set UPDATED 2 February 2024
+@set UPDATED 19 February 2024
@set UPDATED-MONTH February 2024
char *buffer;
int i, file;
- file = -1;
- if (((file = open (filename, O_RDONLY, 0666)) < 0) || (fstat (file, &finfo) < 0))
+ file = open (filename, O_RDONLY, 0666);
+ /* If the open is interrupted, retry once */
+ if (file < 0 && errno == EINTR)
{
+ RL_CHECK_SIGNALS ();
+ file = open (filename, O_RDONLY, 0666);
+ }
+
+ if ((file < 0) || (fstat (file, &finfo) < 0))
+ {
+ i = errno;
if (file >= 0)
close (file);
+ errno = i;
return ((char *)NULL);
}
/* check for overflow on very large files */
if (file_size != finfo.st_size || file_size + 1 < file_size)
{
+ i = errno;
if (file >= 0)
close (file);
#if defined (EFBIG)
errno = EFBIG;
+#else
+ errno = i;
#endif
return ((char *)NULL);
}
if (home == 0)
return (NULL);
- else
- home_len = strlen (home);
+ home_len = strlen (home);
return_val = (char *)xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */
strcpy (return_val, home);
return_val[home_len] = '/';
buffer = last_ts = (char *)NULL;
input = history_filename (filename);
- file = input ? open (input, O_RDONLY|O_BINARY, 0666) : -1;
+ if (input == 0)
+ return 0;
+ errno = 0;
+ file = open (input, O_RDONLY|O_BINARY, 0666);
if ((file < 0) || (fstat (file, &finfo) == -1))
goto error_and_exit;
buffer = (char *)NULL;
filename = history_filename (fname);
+ if (filename == 0)
+ return 0;
tempname = 0;
- file = filename ? open (filename, O_RDONLY|O_BINARY, 0666) : -1;
+ file = open (filename, O_RDONLY|O_BINARY, 0666);
rv = exists = 0;
orig_lines = lines;
if (valid_number (name, &arg_index))
{
tt = get_dollar_var_value (arg_index);
- if (tt)
- temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
- ? quote_string (tt)
- : quote_escapes (tt);
- else
- temp = (char *)NULL;
+ temp = quote_var_value (tt, quoted, pflags);
FREE (tt);
}
else if (var_is_special) /* ${@} */
err_unboundvar (uerror);
return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
}
- if (temp1)
- temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
- ? quote_string (temp1)
- : quote_escapes (temp1);
- else
- temp = (char *)NULL;
-
+ temp = quote_var_value (temp1, quoted, pflags);
break;
/* $$ -- pid of the invoking shell. */
/* Quote the value appropriately */
if (temp == 0 && unbound_vars_is_error)
- goto unbound_variable;
+ goto unbound_variable; /* can happen if array[0] is not set */
else
temp = quote_var_value (temp, quoted, pflags);
+# This program 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.
+#
+# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
set aa bb cc -- dd ; f=$'\1' IFS=$f
recho "$f$*$f"
[[ ${f}${A[*]}${f} == $f${A[*]}$f ]] && echo ok 23
[[ ${A[*]} == ${A[*]} ]] && echo ok 24
+
+# now test $N/${N}/${A[N]}
+set aa bb $'\1' cc -- dd ; f=$'\1' IFS=$f
+
+[[ $3$*$3 == $3$*$3 ]] && echo ok 25
+[[ $3$*$3 == ${3}${*}${3} ]] && echo ok 26
+[[ $3$*$3 == $3${*}${3} ]] && echo ok 27
+[[ $* == *$3* ]]&& echo ok 28
+[[ $* == *${3}* ]]&& echo ok 29
+
+# now use an array instead of $*
+A=( aa bb $'\1' cc -- dd )
+
+[[ ${A[2]}${A[*]}${A[2]} == ${A[2]}${A[*]}${A[2]} ]] && echo ok 30
+[[ ${A[2]}$*${A[2]} == ${A[2]}${*}${A[2]} ]] && echo ok 31
+[[ ${A[2]}$*${A[2]} == ${A[2]}${*}${A[2]} ]] && echo ok 32
+[[ $* == *${A[2]}* ]]&& echo ok 33
+[[ $* == *${A[2]}* ]]&& echo ok 34
+
+unset -v A
+
+set -- aa bb cc -- dd
+case $* in
+"$*") echo ok 35;;
+*) echo bad 35;;
+esac
+
+case $f in
+$f) echo ok 36;;
+*) echo bad 36;;
+esac
+
+case $f$*$f in
+$f"$*"$f) echo ok 37;;
+*) echo bad 37;;
+esac
+
+case $f$*$f in
+*$f--$f*) echo ok 38;;
+*) echo bad 38;;
+esac
ok 22
ok 23
ok 24
+ok 25
+ok 26
+ok 27
+ok 28
+ok 29
+ok 30
+ok 31
+ok 32
+ok 33
+ok 34
+ok 35
+ok 36
+ok 37
+ok 38