- [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
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
{
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);
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);
}
-/* 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.
(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. */
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)
{
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
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;
}
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)
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);
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
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);
/* 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++;
{
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
{
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;
}
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);
/* 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.
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
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
_rl_echoing_p = u;
return o;
}
-\f
+
/* **************************************************************** */
/* */
/* Bogus Flow Control */
/* 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.
# 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>
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
chars_avail = 0;
-#if defined (HAVE_SELECT)
+#if defined (HAVE_PSELECT) || defined (HAVE_SELECT)
FD_ZERO (&readfds);
FD_ZERO (&exceptfds);
FD_SET (fd, &readfds);
/* 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.
#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 *);
/* 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.
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
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
((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);
}
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
}
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;
}
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 */
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. */
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)
{
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);