examples/loadables/asort
examples/loadables/basename
examples/loadables/cat
+examples/loadables/chmod
examples/loadables/csv
examples/loadables/cut
examples/loadables/dirname
examples/loadables/dsv
examples/loadables/fdflags
examples/loadables/finfo
+examples/loadables/fltexpr
examples/loadables/getconf
examples/loadables/head
examples/loadables/hello
discussed in thread starting with
https://lists.gnu.org/archive/html/bug-bash/2025-02/msg00151.html
+ 12/5
+ ----
+lib/sh/uconvert.c
+ - uconvert: allow locale's decimal point character to serve as radix
+ character when parsing fixed-point number into seconds and
+ microseconds
+
+ 12/8
+ ----
+input.c
+ - b_fill_buffer: handle unlikely case of file descriptor being made
+ non-blocking by retrying read on EAGAIN/EWOULDBLOCK
+ Report and patch from Keno Fischer <keno@juliahub.com>
+
+ 12/10
+ -----
+builtins/shopt.def
+ - get_shopt_options: don't allocate memory for each member of the
+ option name array, since programmable completion doesn't free the
+ list members
+ From https://savannah.gnu.org/patch/?10551
+
+ 12/12
+ -----
+subst.c
+ - expand_string_for_patsub42: new function, uses code from bash-4.2 to
+ expand the pattern replacement string if patsub_replacement is not
+ set; calls expand_string_for_patsub with the same value for QUOTING
+ to quote patsub_replacement strings appropriately if it is set.
+ This means that double-quoting the pattern substitution has the
+ effect of quoting any `&' in the replacement string, which is iffy
+ but closer to what bash-4.2 did
+ - parameter_brace_patsub: call expand_string_for_patsub42 if the
+ shell compatibility level is <= 42
+ - quote_string_for_repl: if the shell compatibility level is <= 42
+ and the replacement string is quoted, quote backslashes that quote
+ `&' or `\' so strcreplace() preserves them
+ Fixes most patsub_replacement compatibility issues with bash-4.2
+ most recently raised by <a.elata@icloud.com>
+
+ 12/16
+ -----
+lib/readline/bind.c
+ - show-mode-in-prompt: add V_SPECIAL flag so hack_special_boolean_var()
+ gets called and _rl_reset_prompt will be called when it's changed
+ Report and fix from Martin D Kealey <martin@kurahaupo.gen.nz>
tests/new-exp14.sub f
tests/new-exp15.sub f
tests/new-exp16.sub f
+tests/new-exp17.sub f
tests/new-exp.right f
tests/nquote.tests f
tests/nquote.right f
n = sizeof (shopt_vars) / sizeof (shopt_vars[0]);
ret = strvec_create (n + 1);
for (i = 0; shopt_vars[i].name; i++)
- ret[i] = savestring (shopt_vars[i].name);
+ ret[i] = shopt_vars[i].name;
ret[i] = (char *)NULL;
return ret;
}
/* error.h -- External declarations of functions appearing in error.c. */
-/* Copyright (C) 1993-2022 Free Software Foundation, Inc.
+/* Copyright (C) 1993-2025 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
extern void file_error (const char *);
/* Report a programmer's error, and abort. Pass REASON, and ARG1 ... ARG5. */
-extern void programming_error (const char *, ...) __attribute__((__format__ (printf, 1, 2))) __attribute__((__noreturn__));;
+extern void programming_error (const char *, ...) __attribute__((__format__ (printf, 1, 2))) __attribute__((__noreturn__));
/* General error reporting. Pass FORMAT and ARG1 ... ARG5. */
extern void report_error (const char *, ...) __attribute__((__format__ (printf, 1, 2)));
if (bp->b_flag & B_ERROR) /* try making read errors `sticky' */
return EOF;
- /* In an environment where text and binary files are treated differently,
- compensate for lseek() on text files returning an offset different from
- the count of characters read() returns. Text-mode streams have to be
- treated as unbuffered. */
- if ((bp->b_flag & (B_TEXT | B_UNBUFF)) == B_TEXT)
+ while (1) /* loop to handle non-blocking fds */
{
- o = lseek (bp->b_fd, 0, SEEK_CUR);
- nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
- if (nr > 0 && nr < lseek (bp->b_fd, 0, SEEK_CUR) - o)
+ /* In an environment where text and binary files are treated differently,
+ compensate for lseek() on text files returning an offset different from
+ the count of characters read() returns. Text-mode streams have to be
+ treated as unbuffered. */
+ if ((bp->b_flag & (B_TEXT | B_UNBUFF)) == B_TEXT)
{
- lseek (bp->b_fd, o, SEEK_SET);
- bp->b_flag |= B_UNBUFF;
- bp->b_size = 1;
+ o = lseek (bp->b_fd, 0, SEEK_CUR);
nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
+ if (nr > 0 && nr < lseek (bp->b_fd, 0, SEEK_CUR) - o)
+ {
+ lseek (bp->b_fd, o, SEEK_SET);
+ bp->b_flag |= B_UNBUFF;
+ bp->b_size = 1;
+ nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
+ }
}
- }
- else
- nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
- if (nr <= 0)
- {
+ else
+ nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
+
+ if (nr > 0)
+ break;
+
bp->b_used = bp->b_inputp = 0;
bp->b_buffer[0] = 0;
+
if (nr == 0)
- bp->b_flag |= B_EOF;
+ {
+ bp->b_flag |= B_EOF;
+ return (EOF);
+ }
+ else if (errno == X_EAGAIN || errno == X_EWOULDBLOCK)
+ {
+ if (sh_unset_nodelay_mode (bp->b_fd) < 0)
+ {
+ sys_error (_("cannot reset nodelay mode for fd %d"), bp->b_fd);
+ bp->b_flag |= B_ERROR;
+ return (EOF);
+ }
+ continue;
+ }
else
- bp->b_flag |= B_ERROR;
- return (EOF);
+ {
+ bp->b_flag |= B_ERROR;
+ return (EOF);
+ }
}
bp->b_used = nr;
{ "search-ignore-case", &_rl_search_case_fold, 0 },
{ "show-all-if-ambiguous", &_rl_complete_show_all, 0 },
{ "show-all-if-unmodified", &_rl_complete_show_unmodified, 0 },
- { "show-mode-in-prompt", &_rl_show_mode_in_prompt, 0 },
+ { "show-mode-in-prompt", &_rl_show_mode_in_prompt, V_SPECIAL },
{ "skip-completed-text", &_rl_skip_completed_text, 0 },
#if defined (VISIBLE_STATS)
{ "visible-stats", &rl_visible_stats, 0 },
/* uconvert - convert string representations of decimal numbers into whole
number/fractional value pairs. */
-/* Copyright (C) 2008,2009,2020,2022 Free Software Foundation, Inc.
+/* Copyright (C) 2008,2009,2020-2025 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
#include <unistd.h>
#endif
+#include <bashintl.h>
+#include <stdc.h>
+
#include <stdio.h>
#include "chartypes.h"
#include "shell.h"
#include "builtins.h"
-#define DECIMAL '.' /* XXX - should use locale */
+#ifndef locale_decpoint
+extern int locale_decpoint (void);
+#endif
+
+#define DECIMAL '.'
+#define ISRADIX(c) ((c) == DECIMAL || (c) == locale_decpoint())
#define RETURN(x) \
do { \
for ( ; p && *p; p++)
{
- if (*p == DECIMAL) /* decimal point */
+ if (ISRADIX (*p)) /* radix character */
break;
if (DIGIT(*p) == 0)
RETURN(0);
if (p == 0 || *p == 0) /* callers ensure p can never be 0; this is to shut up clang */
RETURN(1);
- if (*p == DECIMAL)
+ if (ISRADIX (*p))
p++;
/* Look for up to six digits past a decimal point. */
static char *pos_params_pat_subst (char *, char *, char *, int);
static char *expand_string_for_patsub (char *, int);
+static char *expand_string_for_patsub42 (char *, int); /* BASH_COMPAT=42 version */
static char *parameter_brace_patsub (char *, char *, array_eltstate_t *, char *, int, int, int);
static char *pos_params_casemod (char *, char *, int, int);
or a backslash into a backslash. The output of this function must eventually
be processed by strcreplace(). */
static char *
-quote_string_for_repl (const char *string, int flags)
+quote_string_for_repl (const char *string, int quoted)
{
size_t slen;
char *result, *t;
{
/* This function's result has to be processed by strcreplace() */
if (*s == CTLESC && (s[1] == '&' || s[1] == '\\'))
- {
- *t++ = '\\';
- s++;
- *t++ = *s++;
- continue;
- }
+ {
+ *t++ = '\\';
+ s++;
+ *t++ = *s++;
+ continue;
+ }
+ /* Bash-4.2 and earlier don't perform quote removal on double-quoted
+ pattern substitutions. */
+ if (shell_compatibility_level <= 42 &&
+ (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) &&
+ *s == '\\' && (s[1] == '&' || s[1] == '\\'))
+ {
+ *t++ = '\\'; *t++ = '\\';
+ *t++ = '\\';
+ s++;
+ *t++ = *s++;
+ continue;
+ }
/* Dequote it */
if (*s == CTLESC)
{
return (ret);
}
+static char *
+expand_string_for_patsub42 (char *string, int quoted)
+{
+ char *ret, *t;
+
+ if (string == 0 || *string == '\0')
+ return (char *)NULL;
+
+ /* This is the bash-4.2 code from parameter_brace_patsub(). */
+ if (patsub_replacement == 0)
+ {
+ if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)
+ ret = expand_string_if_necessary (string, quoted, expand_string_unsplit);
+ else
+ ret = expand_string_to_string_internal (string, quoted, expand_string_unsplit);
+ }
+ else
+ ret = expand_string_for_patsub (string, quoted);
+
+ return (ret);
+}
+
char *
expand_arith_string (char *string, int quoted)
{
rep = expand_string_if_necessary (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT), expand_string_unsplit);
else if (shell_compatibility_level > 42 && patsub_replacement)
rep = expand_string_for_patsub (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT));
- /* This is the bash-4.2 code. */
- else if ((mflags & MATCH_QUOTED) == 0)
- rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit);
else
- rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit);
+ rep = expand_string_for_patsub42 (rep, quoted);
/* Check whether or not to replace `&' in the replacement string after
expanding it, since we want to treat backslashes quoting the `&'
&two
otwone
&twone
+ new-exp17.sub
+unquoted word expansion with quoted pattern and replacement
+4.2: 4.2, a < b
+5.3: 4.2, a < b
+5.3: 5.2, a < b
+double-quoted word expansion with quoted pattern and replacement
+4.2: 4.2, a '<' b
+5.3: 4.2, a '<' b
+5.3: 5.2, a < b
+unquoted word expansion with unquoted pattern and replacement
+4.2: 4.2, a < b
+5.3: 4.2, a <lt; b
+5.3: 5.2, a <lt; b
+double-quoted word expansion with unquoted pattern and replacement
+4.2: 4.2, a < b
+5.3: 4.2, a < b
+5.3: 5.2, a <lt; b
+unquoted word expansion with backslash-quoted &
+4.2: 4.2, a < b
+5.3: 4.2, a < b
+5.3: 5.2, a < b
+double-quoted word expansion with backslash-quoted &
+4.2: 4.2, a \< b
+5.3: 4.2, a \< b
+5.3: 5.2, a < b
./new-exp.tests: line 1: ABXD: parameter unset
# pattern substitution with `&' (quoted and unquoted) in the replacement string
test_runsub ./new-exp16.sub
+test_runsub ./new-exp17.sub # test bash-4.2 compat
expect $0: 'ABXD: parameter unset'
${THIS_SH} -c 'recho ${ABXD:?"parameter unset"}' $0
--- /dev/null
+# 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/>.
+#
+# address issues with patsub_replacement, quoting `&', and BASH_COMPAT <= 42
+
+# unquoted pattern substitutions with unquoted pattern and replacement strings
+# will still perform matching and replacement even if BASH_COMPAT == 42
+
+s="a < b"
+
+echo unquoted word expansion with quoted pattern and replacement
+echo '4.2: 4.2, a < b'
+for ver in 4.2 5.2; do
+ BASH_COMPAT=$ver # ignored for bash version less than 5.0
+ t=${s//'<'/'<'}
+ echo "${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}: $BASH_COMPAT, $t"
+done
+
+echo double-quoted word expansion with quoted pattern and replacement
+echo "4.2: 4.2, a '<' b"
+for ver in 4.2 5.2; do
+ BASH_COMPAT=$ver # ignored for bash version less than 5.0
+ t="${s//'<'/'<'}"
+ echo "${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}: $BASH_COMPAT, $t"
+done
+
+echo unquoted word expansion with unquoted pattern and replacement
+echo '4.2: 4.2, a < b'
+for ver in 4.2 5.2; do
+ BASH_COMPAT=$ver # ignored for bash version less than 5.0
+ t=${s//</<}
+ echo "${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}: $BASH_COMPAT, $t"
+done
+
+# XXX - this is iffy but difficult to distinguish internally
+echo double-quoted word expansion with unquoted pattern and replacement
+echo '4.2: 4.2, a < b'
+for ver in 4.2 5.2; do
+ BASH_COMPAT=$ver # ignored for bash version less than 5.0
+ t="${s//</<}"
+ echo "${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}: $BASH_COMPAT, $t"
+done
+
+echo unquoted word expansion with backslash-quoted '&'
+echo '4.2: 4.2, a < b'
+for ver in 4.2 5.2; do
+ BASH_COMPAT=$ver # ignored for bash version less than 5.0
+ t=${s//</\<}
+ echo "${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}: $BASH_COMPAT, $t"
+done
+
+echo double-quoted word expansion with backslash-quoted '&'
+echo '4.2: 4.2, a \< b'
+for ver in 4.2 5.2; do
+ BASH_COMPAT=$ver # ignored for bash version less than 5.0
+ t="${s//</\<}"
+ echo "${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}: $BASH_COMPAT, $t"
+done