fixes for bracket expressions in pathname expansion; changes for select/pselect; jobs builtin now removes terminated jobs from the jobs table after notifying

This commit is contained in:
Chet Ramey
2022-11-18 11:01:00 -05:00
parent 96115811d8
commit 407d9afca0
12 changed files with 153 additions and 32 deletions
+59
View File
@@ -4407,3 +4407,62 @@ parse.y
- [grammar]: changed check to decrement WORD_TOP to >= 0 since we
start at -1 and we want to decrement back to -1 when all loops are
closed
builtins/jobs.def
- jobs_builtin: call notify_and_cleanup after displaying the status of
jobs to implement POSIX requirement that `jobs' remove terminated
jobs from the jobs list
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/jobs.html#tag_20_62
11/15
-----
lib/sh/input_avail.c
- include signal.h unconditionally, we need it for HAVE_SELECT and
HAVE_PSELECT
- nchars_avail: make sure we declare and use readfds and exceptfds if
we have pselect or select available
lib/readline/input.c
- rl_gather_tyi,rl_getc: need to declare and use readfds and exceptfds
if HAVE_PSELECT or HAVE_SELECT is set. Report from
Henry Bent <henry.r.bent@gmail.com>, fixes from
Koichi Murase <myoga.murase@gmail.com>
11/16
-----
lib/sh/ufuncs.c
- quit.h: include unconditionally for declaration of sigemptyset even
if HAVE_SELECT is not defined
lib/sh/timers.c
- USEC_PER_SEC: make sure it's defined even if HAVE_SELECT is not
lib/glob/sm_loop.c
- BRACKMATCH: if an equivalence class does not match, and the next
character following the class is a `]', treat that as the end of
the bracket expression.
Report and fix from Koichi Murase <myoga.murase@gmail.com>
- GMATCH: if the current character in the string is a `/' and the
current element in the pattern is a bracket expresion, and the FLAGS
include FNM_PATHNAME, return FNM_NOMATCH immediately. A bracket
expression can never match a slash.
Report and fix from Koichi Murase <myoga.murase@gmail.com>
- BRACKMATCH: if we encounter a <slash> in a bracket expression, either
individually or as part of an equivalence class, nullify the bracket
expression and force the `[' to be matched as an ordinary
character
11/17
-----
lib/glob/sm_loop.c
- BRACKMATCH: if a slash character appears as the first character
after a non-matching character class or equivalence class, treat
the bracket as an ordinary character that must be matched literally
- BRACKMATCH: if a slash character appears as the second character
of a range expression, treat the bracket as an ordinary character
- BRACKMATCH: if a slash character appears in the portion of a
bracket expression that already matched, treat the bracket as an
ordinary character
Updates from Koichi Murase <myoga.murase@gmail.com>
- BRACKMATCH: if a range expression is incomplete (no end char),
treat the bracket as an ordinary character
+6
View File
@@ -1877,7 +1877,13 @@ bash_default_completion (text, start, end, qc, compflags)
rl_completion_suppress_append = 1;
rl_filename_completion_desired = 0;
}
#if 0
/* TAG:bash-5.3 jidanni@jidanni.org 11/11/2022 */
else if (matches[0] && matches[1] && STREQ (matches[0], matches[1]) &&
matches[2] && STREQ (matches[1], matches[2]) && CMD_IS_DIR (matches[0]))
#else
else if (matches[0] && matches[1] && STREQ (matches[0], matches[1]) && CMD_IS_DIR (matches[0]))
#endif
/* There are multiple instances of the same match (duplicate
completions haven't yet been removed). In this case, all of
the matches will be the same, and the duplicate removal code
+7
View File
@@ -136,6 +136,9 @@ jobs_builtin (list)
{
case JSTATE_ANY:
list_all_jobs (form);
/* POSIX says to remove terminated jobs from the list after the jobs
builtin reports their status. */
notify_and_cleanup (); /* the notify part will be a no-op */
break;
case JSTATE_RUNNING:
list_running_jobs (form);
@@ -163,6 +166,10 @@ jobs_builtin (list)
UNBLOCK_CHILD (oset);
list = list->next;
}
/* POSIX says to remove terminated jobs from the list after the jobs
builtin reports their status. */
notify_and_cleanup ();
return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
}
+46 -9
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 1991-2021 Free Software Foundation, Inc.
/* Copyright (C) 1991-2022 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -343,6 +343,11 @@ fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe);
(n == string || ((flags & FNM_PATHNAME) && n[-1] == L('/'))))
return (FNM_NOMATCH);
/* If we are matching pathnames, we can't match a slash with a
bracket expression. */
if (sc == L('/') && (flags & FNM_PATHNAME))
return (FNM_NOMATCH);
/* `?' cannot match `.' or `..' if it is the first character of the
string or if it is the first character following a slash and
we are matching a pathname. */
@@ -403,6 +408,8 @@ PARSE_COLLSYM (p, vp)
return (p + pc + 2);
}
#define SLASH_PATHNAME(c) (c == L('/') && (flags & FNM_PATHNAME))
/* Use prototype definition here because of type promotion. */
static CHAR *
#if defined (PROTOTYPES)
@@ -451,6 +458,12 @@ BRACKMATCH (p, test, flags)
{
pc = FOLD (p[1]);
p += 4;
/* Finding a slash in a bracket expression means you have to
match the bracket as an ordinary character (see below). */
if (pc == L('/') && (flags & FNM_PATHNAME))
return ((test == L('[')) ? savep : (CHAR *)0); /*]*/
if (COLLEQUIV (test, pc))
{
/*[*/ /* Move past the closing `]', since the first thing we do at
@@ -463,6 +476,10 @@ BRACKMATCH (p, test, flags)
c = *p++;
if (c == L('\0'))
return ((test == L('[')) ? savep : (CHAR *)0); /*]*/
else if (c == L('/') && (flags & FNM_PATHNAME))
return ((test == L('[')) ? savep : (CHAR *)0); /*]*/
else if (c == L(']'))
break;
c = FOLD (c);
continue;
}
@@ -475,11 +492,11 @@ BRACKMATCH (p, test, flags)
pc = 0; /* make sure invalid char classes don't match. */
/* Find end of character class name */
for (close = p + 1; *close != '\0'; close++)
for (close = p + 1; *close != '\0' && SLASH_PATHNAME(*close) == 0; close++)
if (*close == L(':') && *(close+1) == L(']'))
break;
if (*close != L('\0'))
if (*close != L('\0') && SLASH_PATHNAME(*close) == 0)
{
ccname = (CHAR *)malloc ((close - p) * sizeof (CHAR));
if (ccname == 0)
@@ -526,6 +543,8 @@ BRACKMATCH (p, test, flags)
c = *p++;
if (c == L('\0'))
return ((test == L('[')) ? savep : (CHAR *)0);
else if (c == L('/') && (flags & FNM_PATHNAME))
return ((test == L('[')) ? savep : (CHAR *)0); /*]*/
else if (c == L(']'))
break;
c = FOLD (c);
@@ -565,15 +584,23 @@ BRACKMATCH (p, test, flags)
if (c == L('\0'))
return ((test == L('[')) ? savep : (CHAR *)0);
/* POSIX.2 2.13.3 says: `If a <slash> character is found following an
unescaped <left-square-bracket> character before a corresponding
<right-square-bracket> is found, the open bracket shall be treated
as an ordinary character.' If we find a slash in a bracket
expression and the flags indicate we're supposed to be treating the
string like a pathname, we have to treat the `[' as just a character
to be matched. */
if (c == L('/') && (flags & FNM_PATHNAME))
return ((test == L('[')) ? savep : (CHAR *)0);
c = *p++;
c = FOLD (c);
if (c == L('\0'))
return ((test == L('[')) ? savep : (CHAR *)0);
if ((flags & FNM_PATHNAME) && c == L('/'))
/* [/] can never match when matching a pathname. */
return (CHAR *)0;
else if (c == L('/') && (flags & FNM_PATHNAME))
return ((test == L('[')) ? savep : (CHAR *)0);
/* This introduces a range, unless the `-' is the last
character of the class. Find the end of the range
@@ -584,7 +611,9 @@ BRACKMATCH (p, test, flags)
if (!(flags & FNM_NOESCAPE) && cend == L('\\'))
cend = *p++;
if (cend == L('\0'))
return (CHAR *)0;
return ((test == L('[')) ? savep : (CHAR *)0);
else if (cend == L('/') && (flags & FNM_PATHNAME))
return ((test == L('[')) ? savep : (CHAR *)0);
if (cend == L('[') && *p == L('.'))
{
p = PARSE_COLLSYM (p, &pc);
@@ -636,6 +665,8 @@ matched:
/* A `[' without a matching `]' is just another character to match. */
if (c == L('\0'))
return ((test == L('[')) ? savep : (CHAR *)0);
else if (c == L('/') && (flags & FNM_PATHNAME))
return ((test == L('[')) ? savep : (CHAR *)0);
oc = c;
c = *p++;
@@ -643,7 +674,10 @@ matched:
{
brcnt++;
brchrp = p++; /* skip over the char after the left bracket */
if ((c = *p) == L('\0'))
c = *p;
if (c == L('\0'))
return ((test == L('[')) ? savep : (CHAR *)0);
else if (c == L('/') && (flags & FNM_PATHNAME))
return ((test == L('[')) ? savep : (CHAR *)0);
/* If *brchrp == ':' we should check that the rest of the characters
form a valid character class name. We don't do that yet, but we
@@ -666,6 +700,9 @@ matched:
{
if (*p == '\0')
return (CHAR *)0;
/* We don't allow backslash to quote slash if we're matching pathnames */
else if (*p == L('/') && (flags & FNM_PATHNAME))
return ((test == L('[')) ? savep : (CHAR *)0);
/* XXX 1003.2d11 is unclear if this is right. */
++p;
}
+2 -4
View File
@@ -616,10 +616,8 @@ rl_expand_prompt (char *prompt)
prompt_visible_length = prompt_physical_chars = 0;
if (local_prompt_invis_chars == 0)
{
local_prompt_invis_chars = (int *)xmalloc (sizeof (int));
local_prompt_invis_chars[0] = 0;
}
local_prompt_invis_chars = (int *)xmalloc (sizeof (int));
local_prompt_invis_chars[0] = 0;
if (prompt == 0 || *prompt == 0)
return (0);
+3 -3
View File
@@ -1,6 +1,6 @@
/* input.c -- character input functions for readline. */
/* Copyright (C) 1994-2021 Free Software Foundation, Inc.
/* Copyright (C) 1994-2022 Free Software Foundation, Inc.
This file is part of the GNU Readline Library (Readline), a library
for reading lines of text with interactive input and history editing.
@@ -250,7 +250,7 @@ rl_gather_tyi (void)
register int tem, result;
int chars_avail, k;
char input;
#if defined(HAVE_SELECT)
#if defined (HAVE_PSELECT) || defined (HAVE_SELECT)
fd_set readfds, exceptfds;
struct timeval timeout;
#endif
@@ -807,7 +807,7 @@ rl_getc (FILE *stream)
int result;
unsigned char c;
int fd;
#if defined (HAVE_PSELECT)
#if defined (HAVE_PSELECT) || defined (HAVE_SELECT)
sigset_t empty_set;
fd_set readfds;
#endif
+1 -1
View File
@@ -729,7 +729,7 @@ rl_tty_set_echoing (int u)
_rl_echoing_p = u;
return o;
}
/* **************************************************************** */
/* */
/* Bogus Flow Control */
+4 -8
View File
@@ -1,7 +1,7 @@
/* input_avail.c -- check whether or not data is available for reading on a
specified file descriptor. */
/* Copyright (C) 2008,2009-2019 Free Software Foundation, Inc.
/* Copyright (C) 2008,2009-2019,2022 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -33,9 +33,7 @@
# include <sys/file.h>
#endif /* HAVE_SYS_FILE_H */
#if defined (HAVE_PSELECT)
# include <signal.h>
#endif
#include <signal.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
@@ -107,10 +105,8 @@ nchars_avail (fd, nchars)
int nchars;
{
int result, chars_avail;
#if defined(HAVE_SELECT)
fd_set readfds, exceptfds;
#endif
#if defined (HAVE_PSELECT) || defined (HAVE_SELECT)
fd_set readfds, exceptfds;
sigset_t set, oset;
#endif
@@ -121,7 +117,7 @@ nchars_avail (fd, nchars)
chars_avail = 0;
#if defined (HAVE_SELECT)
#if defined (HAVE_PSELECT) || defined (HAVE_SELECT)
FD_ZERO (&readfds);
FD_ZERO (&exceptfds);
FD_SET (fd, &readfds);
+5 -1
View File
@@ -1,6 +1,6 @@
/* timers - functions to manage shell timers */
/* Copyright (C) 2021 Free Software Foundation, Inc.
/* Copyright (C) 2021,2022 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -47,6 +47,10 @@ extern int errno;
#define FREE(s) do { if (s) free (s); } while (0)
#endif
#ifndef USEC_PER_SEC
# define USEC_PER_SEC 1000000
#endif
extern unsigned int falarm (unsigned int, unsigned int);
static void shtimer_zero (sh_timer *);
+3 -2
View File
@@ -1,6 +1,6 @@
/* ufuncs - sleep and alarm functions that understand fractional values */
/* Copyright (C) 2008,2009-2020 Free Software Foundation, Inc.
/* Copyright (C) 2008,2009-2020,2022 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -33,9 +33,10 @@
extern int errno;
#endif /* !errno */
#include "quit.h"
#if defined (HAVE_SELECT)
# include "posixselect.h"
# include "quit.h"
# include "trap.h"
# include "stat-time.h"
#endif
+5 -1
View File
@@ -397,7 +397,7 @@ binary_test (op, arg1, arg2, flags)
else if ((op[0] == '>' || op[0] == '<') && op[1] == '\0')
{
#if defined (HAVE_STRCOLL)
if (shell_compatibility_level > 40 && flags & TEST_LOCALE)
if (shell_compatibility_level > 40 && (flags & TEST_LOCALE))
return ((op[0] == '>') ? (strcoll (arg1, arg2) > 0) : (strcoll (arg1, arg2) < 0));
else
#endif
@@ -450,7 +450,11 @@ binary_operator ()
((w[0] == '>' || w[0] == '<') && w[1] == '\0') || /* <, > */
(w[0] == '!' && w[1] == '=' && w[2] == '\0')) /* != */
{
#if 0 /* TAG: bash-5.3 POSIX interp 375 11/9/2022 */
value = binary_test (w, argv[pos], argv[pos + 2], (posixly_correct ? TEST_LOCALE : 0));
#else
value = binary_test (w, argv[pos], argv[pos + 2], 0);
#endif
pos += 3;
return (value);
}
+12 -3
View File
@@ -308,6 +308,7 @@ run_pending_traps ()
sh_parser_state_t pstate;
volatile int save_return_catch_flag, function_code;
procenv_t save_return_catch;
char *trap_command, *old_trap;
#if defined (ARRAY_VARS)
ARRAY *ps;
#endif
@@ -425,6 +426,10 @@ run_pending_traps ()
}
else
{
/* XXX - why not set SIG_INPROGRESS, clear SIG_CHANGED here? */
old_trap = trap_list[sig];
trap_command = savestring (old_trap);
save_parser_state (&pstate);
save_subst_varlist = subst_assign_varlist;
subst_assign_varlist = 0;
@@ -447,7 +452,8 @@ run_pending_traps ()
}
if (function_code == 0)
x = parse_and_execute (savestring (trap_list[sig]), "trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE);
/* XXX is x always last_command_exit_value? */
x = parse_and_execute (trap_command, "trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE);
else
{
parse_and_execute_cleanup (sig + 1); /* XXX - could use -1 */
@@ -1068,7 +1074,7 @@ _run_trap_internal (sig, tag)
old_modes = old_running = old_context = -1;
trap_exit_value = function_code = 0;
trap_exit_value = 0;
trap_saved_exit_value = last_command_exit_value;
/* Run the trap only if SIG is trapped and not ignored, and we are not
currently executing in the trap handler. */
@@ -1112,7 +1118,11 @@ _run_trap_internal (sig, tag)
save_pipeline (1); /* XXX only provides one save level */
#endif
/* XXX - set pending_traps[sig] = 0 here? */
evalnest++;
/* If we're in a function, make sure return longjmps come here, too. */
function_code = 0;
save_return_catch_flag = return_catch_flag;
if (return_catch_flag)
{
@@ -1123,7 +1133,6 @@ _run_trap_internal (sig, tag)
flags = SEVAL_NONINT|SEVAL_NOHIST;
if (sig != DEBUG_TRAP && sig != RETURN_TRAP && sig != ERROR_TRAP)
flags |= SEVAL_RESETLINE;
evalnest++;
if (function_code == 0)
{
parse_and_execute (trap_command, tag, flags);