fix issue with internally quoting multibyte characters; the let builtin now suppresses additional array subscript expansion; small change to how readline export-completions displays filenames; new loadable builtin to do floating-point arithmetic

This commit is contained in:
Chet Ramey
2025-01-17 11:41:49 -05:00
parent 2ea356081d
commit 42c49d621d
22 changed files with 1718 additions and 111 deletions
+1 -1
View File
@@ -1885,7 +1885,7 @@ n. The `test -N' operator uses nanosecond timestamp granularity if it's
available.
o. Bash posix mode now treats assignment statements preceding shell function
definitions the same as in its default mode, since POSIX has changed and
calls the same as in its default mode, since POSIX has changed and
no longer requires those assignments to persist after the function returns
(POSIX interp 654).
+38
View File
@@ -10796,3 +10796,41 @@ tests/printf7.sub,tests/cond-regexp2.sub
tests/run-all, tests/run-minimal
- BASHOPTS: unset or unexport as appropriate, same as SHELLOPTS
From a report by Martin D Kealey <martin@kurahaupo.gen.nz>
1/9
---
subst.c
- string_extract_verbatim: take into account the fact that CTLESC can
quote multibyte characters; use ADVANCE_CHAR instead of increment
Fixes bug reported by jktseug@gmail.com
1/10
----
expr.c
- expr_bind_variable,expr_streval: suppress additional expansion if
called by the `let' builtin, whether or not array_expand_once is set
- expr_skipsubscript: suppress expansion while parsing subscripts
whether array_expand_once is set or not
Still have to change tests if this goes final
These are all conditional on shell_compatibility_level > 51
From a bug-bash post by Greg Wooledge <greg@wooledge.org>
1/14
----
lib/readline/complete.c
- _rl_export_completions: use print_filename instead of fprintf to
display the possible completions so slashes and file types can
be included
From a patch from Matthew Tromp <matthewktromp@gmail.com>
1/15
----
examples/loadables/fltexpr.c
- fltexpr: new loadable builtin to do floating-point arithmetic
expression evaluation and optionally print the result
1/16
----
builtins/printf.def
- getarg(), advancearg(): cosmetic changes to make it easier to
implement %N$ format specifiers in the future
+1
View File
@@ -784,6 +784,7 @@ examples/loadables/getconf.h f
examples/loadables/getconf.c f
examples/loadables/fdflags.c f
examples/loadables/finfo.c f
examples/loadables/fltexpr.c f
examples/loadables/cat.c f
examples/loadables/csv.c f
examples/loadables/dsv.c f
+86 -48
View File
@@ -242,6 +242,12 @@ static char *vbuf, *vname;
static size_t vbsize;
static size_t vblen;
/* printf format numbered argument support */
static char **narg_argv;
static int narg_argc;
static int narg_maxind;
static int narg_curind;
static intmax_t tw;
static char *conv_buf;
@@ -1329,16 +1335,32 @@ mklong (char *str, char *modifiers, size_t mlen)
return (conv_buf);
}
static inline char *
getarg (void)
{
return (garglist ? garglist->word->word : 0);
}
static inline void
advancearg (void)
{
garglist = garglist->next;
}
static int
getchr (void)
{
int ret;
char *arg;
if (garglist == 0)
arg = getarg ();
if (arg == 0)
return ('\0');
ret = (int)garglist->word->word[0];
garglist = garglist->next;
ret = (int)arg[0];
advancearg ();
return ret;
}
@@ -1347,11 +1369,11 @@ getstr (void)
{
char *ret;
if (garglist == 0)
ret = getarg ();
if (ret == 0)
return ("");
ret = garglist->word->word;
garglist = garglist->next;
advancearg ();
return ret;
}
@@ -1379,23 +1401,25 @@ static int
getint (int overflow_retval)
{
intmax_t ret;
char *ep;
char *ep, *arg;
int overflow;
if (garglist == 0)
arg = getarg ();
if (arg == 0)
return (0);
if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
if (arg[0] == '\'' || arg[0] == '"')
return asciicode ();
errno = 0;
ret = strtoimax (garglist->word->word, &ep, 0);
ret = strtoimax (arg, &ep, 0);
if (overflow = (errno == ERANGE) || (ret < INT_MIN || ret > INT_MAX))
errno = ERANGE; /* force errno */
chk_converror (garglist->word->word, ep);
chk_converror (arg, ep);
garglist = garglist->next;
advancearg ();
return (overflow ? overflow_retval : (int)ret);
}
@@ -1403,20 +1427,22 @@ static intmax_t
getintmax (void)
{
intmax_t ret;
char *ep;
char *ep, *arg;
if (garglist == 0)
arg = getarg ();
if (arg == 0)
return (0);
if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
if (arg[0] == '\'' || arg[0] == '"')
return asciicode ();
errno = 0;
ret = strtoimax (garglist->word->word, &ep, 0);
ret = strtoimax (arg, &ep, 0);
chk_converror (garglist->word->word, ep);
chk_converror (arg, ep);
garglist = garglist->next;
advancearg ();
return (ret);
}
@@ -1424,20 +1450,22 @@ static uintmax_t
getuintmax (void)
{
uintmax_t ret;
char *ep;
char *ep, *arg;
if (garglist == 0)
arg = getarg ();
if (arg == 0)
return (0);
if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
if (arg[0] == '\'' || arg[0] == '"')
return asciicode ();
errno = 0;
ret = strtoumax (garglist->word->word, &ep, 0);
ret = strtoumax (arg, &ep, 0);
chk_converror (garglist->word->word, ep);
chk_converror (arg, ep);
garglist = garglist->next;
advancearg ();
return (ret);
}
@@ -1445,20 +1473,22 @@ static double
getdouble (void)
{
double ret;
char *ep;
char *ep, *arg;
if (garglist == 0)
arg = getarg ();
if (arg == 0)
return (0);
if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
if (arg[0] == '\'' || arg[0] == '"')
return asciicode ();
errno = 0;
ret = strtod (garglist->word->word, &ep);
ret = strtod (arg, &ep);
chk_converror (garglist->word->word, ep);
chk_converror (arg, ep);
garglist = garglist->next;
advancearg ();
return (ret);
}
@@ -1466,20 +1496,22 @@ static floatmax_t
getfloatmax (void)
{
floatmax_t ret;
char *ep;
char *ep, *arg;
if (garglist == 0)
arg = getarg ();
if (arg == 0)
return (0);
if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
if (arg[0] == '\'' || arg[0] == '"')
return asciicode ();
errno = 0;
ret = strtofltmax (garglist->word->word, &ep);
ret = strtofltmax (arg, &ep);
chk_converror (garglist->word->word, ep);
chk_converror (arg, ep);
garglist = garglist->next;
advancearg ();
return (ret);
}
@@ -1488,23 +1520,25 @@ static intmax_t
asciicode (void)
{
register intmax_t ch;
char *arg;
#if defined (HANDLE_MULTIBYTE)
wchar_t wc;
size_t slen, mblength;
#endif
DECLARE_MBSTATE;
arg = getarg ();
#if defined (HANDLE_MULTIBYTE)
slen = strlen (garglist->word->word+1);
slen = strlen (arg+1);
wc = 0;
mblength = mbrtowc (&wc, garglist->word->word+1, slen, &state);
mblength = mbrtowc (&wc, arg+1, slen, &state);
if (MB_INVALIDCH (mblength) == 0)
ch = wc; /* XXX */
else
#endif
ch = (unsigned char)garglist->word->word[1];
ch = (unsigned char)arg[1];
garglist = garglist->next;
advancearg ();
return (ch);
}
@@ -1515,16 +1549,18 @@ getwidestr (size_t *lenp)
wchar_t *ws;
const char *mbs;
size_t slen, mblength;
char *arg;
DECLARE_MBSTATE;
if (garglist == 0)
arg = getarg ();
if (arg == 0)
{
if (lenp)
*lenp = 0;
return NULL;
}
mbs = garglist->word->word;
mbs = arg;
slen = strlen (mbs);
ws = (wchar_t *)xmalloc ((slen + 1) * sizeof (wchar_t));
mblength = mbsrtowcs (ws, &mbs, slen + 1, &state);
@@ -1535,13 +1571,13 @@ getwidestr (size_t *lenp)
{
int i;
for (i = 0; i < slen; i++)
ws[i] = (wchar_t)garglist->word->word[i];
ws[i] = (wchar_t)arg[i];
ws[slen] = L'\0';
if (lenp)
*lenp = slen;
}
garglist = garglist->next;
advancearg ();
return (ws);
}
@@ -1550,17 +1586,19 @@ getwidechar (void)
{
wchar_t wc;
size_t slen, mblength;
char *arg;
DECLARE_MBSTATE;
if (garglist == 0)
arg = getarg ();
if (arg == 0)
return L'\0';
wc = 0;
mblength = mbrtowc (&wc, garglist->word->word, locale_mb_cur_max, &state);
mblength = mbrtowc (&wc, arg, locale_mb_cur_max, &state);
if (MB_INVALIDCH (mblength))
wc = (wchar_t)garglist->word->word[0];
wc = (wchar_t)arg[0];
garglist = garglist->next;
advancearg ();
return (wc);
}
+6 -1
View File
@@ -1673,6 +1673,8 @@ If this variable is in the environment when
.B bash
starts up, the shell enables each option in the list before
reading any startup files.
If this variable is exported, child shells will enable each option
in the list.
This variable is read-only.
.TP
.B BASHPID
@@ -13259,7 +13261,10 @@ builtin command.
.IP \(bu
Importing function definitions from the shell environment at startup.
.IP \(bu
Parsing the value of
Parsing the values of
.SM
.B BASHOPTS
and
.SM
.B SHELLOPTS
from the shell environment at startup.
+2
View File
@@ -6715,6 +6715,8 @@ as @samp{on} by @samp{shopt}.
If this variable is in the environment when Bash
starts up, the shell enables each option in the list before
reading any startup files.
If this variable is exported, child shells will enable each option
in the list.
This variable is readonly.
@item BASHPID
+5 -1
View File
@@ -104,7 +104,7 @@ ALLPROG = print truefalse sleep finfo logname basename dirname fdflags \
tty pathchk tee head mkdir rmdir mkfifo mktemp printenv id whoami \
uname sync push ln unlink realpath strftime mypid setpgid seq rm \
accept csv dsv cut stat getconf kv strptime
OTHERPROG = necho hello cat pushd asort
OTHERPROG = necho hello cat pushd asort fltexpr
SUBDIRS = perl
@@ -250,6 +250,10 @@ stat: stat.o
asort: asort.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ asort.o $(SHOBJ_LIBS)
fltexpr: fltexpr.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ fltexpr.o $(SHOBJ_LIBS) -lm
# pushd is a special case. We use the same source that the builtin version
# uses, with special compilation options.
#
File diff suppressed because it is too large Load Diff
+57 -43
View File
@@ -88,6 +88,9 @@
#include "subst.h"
#include "typemax.h" /* INTMAX_MAX, INTMAX_MIN */
#include "builtins/common.h" /* this_shell_builtin */
#include "builtins/builtext.h" /* let_builtin */
/* Because of the $((...)) construct, expressions may include newlines.
Here is a macro which accepts newlines, tabs and spaces as whitespace. */
#define cr_whitespace(c) (whitespace(c) || ((c) == '\n'))
@@ -194,6 +197,10 @@ static intmax_t expr_streval (char *, int, struct lvalue *);
static intmax_t strlong (char *);
static void evalerror (const char *);
#if defined (ARRAYS)
static int expr_skipsubscript (char *, char *);
#endif
static void pushexp (void);
static void popexp (void);
static void expr_unwind (void);
@@ -330,7 +337,9 @@ expr_bind_variable (const char *lhs, const char *rhs)
return; /* XXX */
#if defined (ARRAY_VARS)
aflags = (array_expand_once && already_expanded) ? ASS_NOEXPAND : 0;
aflags = (array_expand_once && already_expanded) ? ASS_NOEXPAND : 0; /* XXX */
if (this_shell_builtin == let_builtin && shell_compatibility_level > 51)
aflags |= ASS_NOEXPAND; /* we didn't quote subscripts */
aflags |= ASS_ALLOWALLSUB; /* allow assoc[@]=value */
#else
aflags = 0;
@@ -347,18 +356,21 @@ expr_bind_variable (const char *lhs, const char *rhs)
static int
expr_skipsubscript (char *vp, char *cp)
{
int flags, isassoc;
int flags, isassoc, noexp;
SHELL_VAR *entry;
isassoc = 0;
isassoc = noexp = 0;
entry = 0;
if (array_expand_once & already_expanded)
/* We're not doing any evaluation here, we should suppress expansion when
skipping over the subscript */
noexp = already_expanded && (shell_compatibility_level > 51 || array_expand_once);
if (noexp)
{
*cp = '\0';
isassoc = valid_identifier (vp) && (entry = find_variable (vp)) && assoc_p (entry);
*cp = '['; /* ] */
}
flags = (isassoc && array_expand_once && already_expanded) ? VA_NOEXPAND : 0;
flags = (isassoc && noexp) ? VA_NOEXPAND : 0;
return (skipsubscript (cp, 0, flags));
}
@@ -881,9 +893,7 @@ expmuldiv (void)
val1 = exppower ();
while ((curtok == MUL) ||
(curtok == DIV) ||
(curtok == MOD))
while ((curtok == MUL) || (curtok == DIV) || (curtok == MOD))
{
int op = curtok;
char *stp, *sltp;
@@ -1057,47 +1067,49 @@ exp0 (void)
/* Skip over closing paren. */
readtok ();
}
else if ((curtok == NUM) || (curtok == STR))
else if (curtok == NUM)
{
val = tokval;
if (curtok == STR)
readtok ();
}
else if (curtok == STR)
{
val = tokval;
SAVETOK (&ec);
tokstr = (char *)NULL; /* keep it from being freed */
noeval = 1;
readtok ();
stok = curtok;
/* post-increment or post-decrement */
if (stok == POSTINC || stok == POSTDEC)
{
SAVETOK (&ec);
tokstr = (char *)NULL; /* keep it from being freed */
noeval = 1;
readtok ();
stok = curtok;
/* restore certain portions of EC */
tokstr = ec.tokstr;
noeval = ec.noeval;
curlval = ec.lval;
lasttok = STR; /* ec.curtok */
/* post-increment or post-decrement */
if (stok == POSTINC || stok == POSTDEC)
{
/* restore certain portions of EC */
tokstr = ec.tokstr;
noeval = ec.noeval;
curlval = ec.lval;
lasttok = STR; /* ec.curtok */
v2 = val + ((stok == POSTINC) ? 1 : -1);
vincdec = itos (v2);
if (noeval == 0)
{
v2 = val + ((stok == POSTINC) ? 1 : -1);
vincdec = itos (v2);
if (noeval == 0)
{
#if defined (ARRAY_VARS)
if (curlval.ind != -1)
expr_bind_array_element (curlval.tokstr, curlval.ind, vincdec);
else
if (curlval.ind != -1)
expr_bind_array_element (curlval.tokstr, curlval.ind, vincdec);
else
#endif
expr_bind_variable (tokstr, vincdec);
}
free (vincdec);
curtok = NUM; /* make sure x++=7 is flagged as an error */
}
else
{
/* XXX - watch out for pointer aliasing issues here */
if (stok == STR) /* free new tokstr before old one is restored */
FREE (tokstr);
RESTORETOK (&ec);
}
expr_bind_variable (tokstr, vincdec);
}
free (vincdec);
curtok = NUM; /* make sure x++=7 is flagged as an error */
}
else
{
/* XXX - watch out for pointer aliasing issues here */
if (stok == STR) /* free new tokstr before old one is restored */
FREE (tokstr);
RESTORETOK (&ec);
}
readtok ();
@@ -1155,6 +1167,8 @@ expr_streval (char *tok, int e, struct lvalue *lvalue)
#if defined (ARRAY_VARS)
tflag = (array_expand_once && already_expanded) ? AV_NOEXPAND : 0; /* for a start */
if (this_shell_builtin == let_builtin && shell_compatibility_level > 51)
tflag |= AV_NOEXPAND; /* we didn't quote subscripts */
#endif
/* [[[[[ */
+4 -1
View File
@@ -3066,7 +3066,10 @@ _rl_export_completions (char **matches, char *text, int start, int end)
fprintf (rl_outstream, "%s\n", text);
fprintf (rl_outstream, "%d:%d\n", start, end); /* : because it's not a radix character */
for (i = 0; i < len; i++)
fprintf (rl_outstream, "%s\n", matches[i]);
{
print_filename (matches[i], matches[i], 0);
fprintf (rl_outstream, "\n");
}
fflush (rl_outstream);
}
+2 -2
View File
@@ -79,8 +79,8 @@
.SH NAME
history \- GNU History Library
.SH COPYRIGHT
.if t The GNU History Library is Copyright \(co 1989-2024 by the Free Software Foundation, Inc.
.if n The GNU History Library is Copyright (C) 1989-2024 by the Free Software Foundation, Inc.
.if t The GNU History Library is Copyright \(co 1989-2025 by the Free Software Foundation, Inc.
.if n The GNU History Library is Copyright (C) 1989-2025 by the Free Software Foundation, Inc.
.SH DESCRIPTION
Many programs read input from the user a line at a time.
The GNU
+2 -2
View File
@@ -1,4 +1,4 @@
\input texinfo @c -*-texinfo-*-
c\input texinfo @c -*-texinfo-*-
@c %**start of header (This is for running Texinfo on a region.)
@setfilename history.info
@settitle GNU History Library
@@ -12,7 +12,7 @@ This document describes the GNU History library
a programming tool that provides a consistent user interface for
recalling lines of previously typed input.
Copyright @copyright{} 1988--2024 Free Software Foundation, Inc.
Copyright @copyright{} 1988--2025 Free Software Foundation, Inc.
@quotation
Permission is granted to copy, distribute and/or modify this document
+1 -1
View File
@@ -1,7 +1,7 @@
@ignore
This file documents the user interface to the GNU History library.
Copyright (C) 1988-2024 Free Software Foundation, Inc.
Copyright (C) 1988-2025 Free Software Foundation, Inc.
Authored by Brian Fox and Chet Ramey.
Permission is granted to make and distribute verbatim copies of this manual
+1 -1
View File
@@ -1,7 +1,7 @@
@ignore
This file documents the user interface to the GNU History library.
Copyright (C) 1988--2024 Free Software Foundation, Inc.
Copyright (C) 1988--2025 Free Software Foundation, Inc.
Authored by Brian Fox and Chet Ramey.
Permission is granted to make and distribute verbatim copies of this manual
+2 -2
View File
@@ -60,8 +60,8 @@ readline \- get a line from a user with editing
\fBreadline\fP (\fIconst char *prompt\fP);
.fi
.SH COPYRIGHT
.if n Readline is Copyright (C) 1989\-2024 Free Software Foundation, Inc.
.if t Readline is Copyright \(co 1989\-2024 Free Software Foundation, Inc.
.if n Readline is Copyright (C) 1989\-2025 Free Software Foundation, Inc.
.if t Readline is Copyright \(co 1989\-2025 Free Software Foundation, Inc.
.SH DESCRIPTION
.LP
.B readline
+1 -1
View File
@@ -13,7 +13,7 @@ This manual describes the GNU Readline Library
consistency of user interface across discrete programs which provide
a command line interface.
Copyright @copyright{} 1988--2024 Free Software Foundation, Inc.
Copyright @copyright{} 1988--2025 Free Software Foundation, Inc.
@quotation
Permission is granted to copy, distribute and/or modify this document
+1 -1
View File
@@ -7,7 +7,7 @@ This document describes the GNU Readline Library, a utility for aiding
in the consistency of user interface across discrete programs that need
to provide a command line interface.
Copyright (C) 1988--2024 Free Software Foundation, Inc.
Copyright (C) 1988--2025 Free Software Foundation, Inc.
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
+1 -1
View File
@@ -11,7 +11,7 @@ use these features. There is a document entitled "readline.texinfo"
which contains both end-user and programmer documentation for the
GNU Readline Library.
Copyright (C) 1988--2024 Free Software Foundation, Inc.
Copyright (C) 1988--2025 Free Software Foundation, Inc.
Authored by Brian Fox and Chet Ramey.
+1 -1
View File
@@ -12,7 +12,7 @@ This manual describes the end user interface of the GNU Readline Library
consistency of user interface across discrete programs which provide
a command line interface.
Copyright @copyright{} 1988--2024 Free Software Foundation, Inc.
Copyright @copyright{} 1988--2025 Free Software Foundation, Inc.
@quotation
Permission is granted to copy, distribute and/or modify this document
+1 -1
View File
@@ -1,5 +1,5 @@
@ignore
Copyright (C) 1988-2024 Free Software Foundation, Inc.
Copyright (C) 1988-2025 Free Software Foundation, Inc.
@end ignore
@set EDITION 8.3
+1 -1
View File
@@ -1,6 +1,6 @@
/* shell.c -- GNU's idea of the POSIX shell specification. */
/* Copyright (C) 1987-2024 Free Software Foundation, Inc.
/* Copyright (C) 1987-2025 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+4 -2
View File
@@ -4,7 +4,7 @@
/* ``Have a little faith, there's magic in the night. You ain't a
beauty, but, hey, you're alright.'' */
/* Copyright (C) 1987-2024 Free Software Foundation, Inc.
/* Copyright (C) 1987-2025 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -1184,7 +1184,9 @@ string_extract_verbatim (const char *string, size_t slen, size_t *sindex, char *
#endif
if ((flags & SX_NOCTLESC) == 0 && c == CTLESC)
{
i += 2;
i++;
CHECK_STRING_OVERRUN (i, i, slen, c);
ADVANCE_CHAR (string, slen, i); /* CTLESC can quote mbchars */
CHECK_STRING_OVERRUN (i, i, slen, c);
continue;
}