From: Chet Ramey Date: Wed, 17 Dec 2025 14:59:56 +0000 (-0500) Subject: allow locale's decimal point as radix character when parsing fixed-point decimal... X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=2cdb2f9b314525a118eff5237839ccc272c2e32b;p=thirdparty%2Fbash.git allow locale's decimal point as radix character when parsing fixed-point decimal into seconds and fractional seconds; handle case of shell script file descriptor being made non-blocking; fix smalkl memory leak in programmable completion of shell option names; fix for patsub_replacement behavior when BASH_COMPAT = 42 and the replacement string is quoted; fix for readine when changing show-mode-in-prompt variable --- diff --git a/.gitignore b/.gitignore index f334b795..f357e17f 100644 --- a/.gitignore +++ b/.gitignore @@ -164,12 +164,14 @@ examples/loadables/accept 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 diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index ab59fcd1..509288ad 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -12327,3 +12327,49 @@ builtins/printf.def 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 + + 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 + + 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 diff --git a/MANIFEST b/MANIFEST index f9af056b..1e00729f 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1391,6 +1391,7 @@ tests/new-exp13.sub f 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 diff --git a/builtins/shopt.def b/builtins/shopt.def index 6ecc087f..ed057e63 100644 --- a/builtins/shopt.def +++ b/builtins/shopt.def @@ -777,7 +777,7 @@ get_shopt_options (void) 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; } diff --git a/error.h b/error.h index 6254fee1..29db88f7 100644 --- a/error.h +++ b/error.h @@ -1,6 +1,6 @@ /* 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. @@ -30,7 +30,7 @@ extern char *get_name_for_error (void); 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))); diff --git a/input.c b/input.c index 180b7e12..5de6b7ca 100644 --- a/input.c +++ b/input.c @@ -510,33 +510,53 @@ b_fill_buffer (BUFFERED_STREAM *bp) 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; diff --git a/lib/readline/bind.c b/lib/readline/bind.c index 6df53045..c663b63c 100644 --- a/lib/readline/bind.c +++ b/lib/readline/bind.c @@ -1906,7 +1906,7 @@ static const struct { { "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 }, diff --git a/lib/sh/uconvert.c b/lib/sh/uconvert.c index 39790f6b..a9a00bb6 100644 --- a/lib/sh/uconvert.c +++ b/lib/sh/uconvert.c @@ -1,7 +1,7 @@ /* 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. @@ -29,13 +29,21 @@ #include #endif +#include +#include + #include #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 { \ @@ -76,7 +84,7 @@ uconvert(const char *s, long *ip, long *up, char **ep) for ( ; p && *p; p++) { - if (*p == DECIMAL) /* decimal point */ + if (ISRADIX (*p)) /* radix character */ break; if (DIGIT(*p) == 0) RETURN(0); @@ -86,7 +94,7 @@ uconvert(const char *s, long *ip, long *up, char **ep) 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. */ diff --git a/subst.c b/subst.c index bdbafac8..eabea2aa 100644 --- a/subst.c +++ b/subst.c @@ -353,6 +353,7 @@ static int shouldexp_replacement (const char *); 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); @@ -3917,7 +3918,7 @@ expand_assignment_string_to_string (char *string, int quoted) 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; @@ -3951,12 +3952,24 @@ quote_string_for_repl (const char *string, int flags) { /* 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) { @@ -4006,6 +4019,28 @@ expand_string_for_patsub (char *string, int quoted) 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) { @@ -9501,11 +9536,8 @@ parameter_brace_patsub (char *varname, char *value, array_eltstate_t *estatep, 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 `&' diff --git a/tests/new-exp.right b/tests/new-exp.right index ac720ac3..6e059618 100644 --- a/tests/new-exp.right +++ b/tests/new-exp.right @@ -823,4 +823,29 @@ two &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 . +# +# 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//