changes for backslashes in glob patterns and single-quoted strings; brace expansion knows '${...}' expansions; read returns status 2 if trying to assign to a readonly variable

This commit is contained in:
Chet Ramey
2023-10-17 11:09:23 -04:00
parent 7a698806d1
commit 1e1a0342a4
8 changed files with 73 additions and 37 deletions
+40 -1
View File
@@ -6861,7 +6861,6 @@ builtins/evalstring.c
subst.c
- param_expand: free TEMP1 in code paths that don't do it now
bashline.c
- bash_command_name_stat_hook: if we modify *NAME, free the old value
@@ -7825,3 +7824,43 @@ builtins/return.def
invalid numeric arg from get_exitstat, return immediately and let
the caller deal with exiting
All prompted by a report by Martin Schulte <gnu@schrader-schulte.de>
10/13
-----
pathexp.c
- unquoted_glob_pattern_p: restore some of the special treatment of
backslash followed by CTLESC removed on 10/7
Report and patch from Grisha Levit <grishalevit@gmail.com>
parse.y
- parse_matched_pair: don't add an extra CTLESC after reading \CTLESC,
like in other parts of the parser
subst.c
- dequote_string: don't drop trailing CTLESC in a string with more
than a single character
Report and patch from Grisha Levit <grishalevit@gmail.com>
lib/sh/strtrans.c
- ansicstr: handle $'\c^A' and $'\c^?' correctly when being expanded
by the parser (flags&2). The parser passes these as \c^A^A and
\c^A^?, respectively, so we should strip the quoting CTLESC.
Report from Grisha Levit <grishalevit@gmail.com>
subst.[ch]
- extract_dollar_brace_string: now global so brace expansion can use it
braces.c
- brace_gobbler: use extract_dollar_brace_string if we see ${ with
the appropriate value of QUOTING, so we don't have to teach brace
expansion more shell syntax.
Report from Emanuele Torre <torreemanuele6@gmail.com>
- brace_gobbler: call the word extraction functions with SX_NOALLOC
so we don't have to allocate memory we're just going to free
10/16
-----
builtins/read.def
- read_builtin: return EX_MISCERROR (2) if there is an error trying
to assign to one of the variables. This is what the newest POSIX
draft specifies.
+5 -8
View File
@@ -619,10 +619,9 @@ brace_gobbler (char *text, size_t tlen, int *indx, int satisfy)
/* If compiling for the shell, treat ${...} like \{...} */
if (c == '$' && text[i+1] == '{' && quoted != '\'') /* } */
{
pass_next = 1;
i++;
if (quoted == 0)
level++;
si = i + 2;
t = extract_dollar_brace_string (text, &si, 0, SX_NOALLOC);
i = si + 1;
continue;
}
#endif
@@ -657,10 +656,8 @@ brace_gobbler (char *text, size_t tlen, int *indx, int satisfy)
{
comsub:
si = i + 2;
t = extract_command_subst (text, &si, 0);
i = si;
free (t);
i++;
t = extract_command_subst (text, &si, SX_NOALLOC);
i = si + 1;
continue;
}
#endif
+3 -3
View File
@@ -500,7 +500,7 @@ read_builtin (WORD_LIST *list)
read_timeout = shtimer_alloc ();
read_timeout->flags = SHTIMER_LONGJMP;
#if defined (HAVE_SELECT)
#if defined (HAVE_SELECT) || defined (HAVE_PSELECT)
read_timeout->flags |= (edit || posixly_correct) ? SHTIMER_ALARM : SHTIMER_SELECT;
#else
read_timeout->flags |= SHTIMER_ALARM;
@@ -966,7 +966,7 @@ assign_vars:
else
var = bind_variable ("REPLY", input_string, 0);
if (var == 0 || readonly_p (var) || noassign_p (var))
retval = EXECUTION_FAILURE;
retval = EX_MISCERROR;
else
VUNSETATTR (var, att_invisible);
@@ -1027,7 +1027,7 @@ assign_vars:
if (var == 0)
{
free (orig_input_string);
return (EXECUTION_FAILURE);
return (EX_MISCERROR);
}
stupidly_hack_special_variables (varname);
+4 -2
View File
@@ -45,7 +45,7 @@
that we're translating a string for `echo -e', and therefore should not
treat a single quote as a character that may be escaped with a backslash.
If (FLAGS&2) is non-zero, we're expanding for the parser and want to
quote CTLESC and CTLNUL with CTLESC. If (flags&4) is non-zero, we want
quote CTLESC and CTLNUL with CTLESC. If (FLAGS&4) is non-zero, we want
to remove the backslash before any unrecognized escape sequence. */
char *
ansicstr (const char *string, size_t len, int flags, int *sawc, size_t *rlen)
@@ -198,7 +198,9 @@ ansicstr (const char *string, size_t len, int flags, int *sawc, size_t *rlen)
s++;
if ((flags & 2) && c == '\\' && c == *s)
s++; /* Posix requires $'\c\\' do backslash escaping */
c = TOCTRL(c);
else if ((flags & 2) && c == CTLESC && (*s == CTLESC || *s == CTLNUL))
c = *s++;
c = TOCTRL(c);
break;
}
/*FALLTHROUGH*/
+1 -3
View File
@@ -3834,9 +3834,7 @@ parse_matched_pair (int qc, int open, int close, size_t *lenp, int flags)
continue;
}
RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
if MBTEST(ch == CTLESC)
ret[retind++] = CTLESC;
RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
ret[retind++] = ch;
continue;
}
+8 -4
View File
@@ -104,11 +104,15 @@ unquoted_glob_pattern_p (char *string)
continue;
case '\\':
/* Even after an unquoted backslash, CTLESC either quotes the next
char or escapes a CTLESC or CTLNUL. Either way, the character
after it is not an unquoted globbing char. */
if (*string == CTLESC)
string++;
{
string++;
/* If the CTLESC was quoting a CTLESC, skip it so that it's not
treated as a quoting character */
if (*string == CTLESC)
string++;
}
else
/*FALLTHROUGH*/
case CTLESC:
if (*string++ == '\0')
+3 -16
View File
@@ -269,7 +269,6 @@ static inline size_t skip_single_quoted (const char *, size_t, size_t, int);
static int skip_double_quoted (const char *, size_t, size_t, int);
static char *extract_delimited_string (const char *, size_t *, char *, char *, char *, int);
static char *extract_heredoc_dolbrace_string (const char *, size_t *, int, int);
static char *extract_dollar_brace_string (const char *, size_t *, int, int);
static int skip_matched_pair (const char *, int, int, int, int);
static char *pos_params (const char *, int, int, int, int);
@@ -1805,7 +1804,7 @@ static int dbstate[PARAMEXPNEST_MAX];
gets the position of the matching `}'. QUOTED is non-zero if this
occurs inside double quotes. */
/* XXX -- this is very similar to extract_delimited_string -- XXX */
static char *
char *
extract_dollar_brace_string (const char *string, size_t *sindex, int quoted, int flags)
{
register int i, c;
@@ -4810,14 +4809,6 @@ dequote_string (const char *string)
return (result);
}
/* A string consisting of only a single CTLESC should pass through unchanged */
if (string[0] == CTLESC && string[1] == 0)
{
result[0] = CTLESC;
result[1] = '\0';
return (result);
}
/* If no character in the string can be quoted, don't bother examining
each character. Just return a copy of the string passed to us. */
if (strchr (string, CTLESC) == NULL)
@@ -4827,12 +4818,8 @@ dequote_string (const char *string)
s = (char *)string;
while (*s)
{
if (*s == CTLESC)
{
s++;
if (*s == '\0')
break;
}
if (*s == CTLESC && s[1]) /* don't drop trailing CTLESC */
s++;
COPY_CHAR_P (t, s, send);
}
+9
View File
@@ -103,6 +103,15 @@ extern char *extract_arithmetic_subst (const char *, size_t *);
extern char *extract_process_subst (const char *, char *, size_t *, int);
#endif /* PROCESS_SUBSTITUTION */
/* Extract a parameter expansion expression within ${ and } from STRING.
Obey the Posix.2 rules for finding the ending `}': count braces while
skipping over enclosed quoted strings and command substitutions.
SINDEX is the address of an int describing the current offset in STRING;
it should point to just after the first `{' found. On exit, SINDEX
gets the position of the matching `}'. QUOTED is non-zero if this
occurs inside double quotes. */
extern char *extract_dollar_brace_string (const char *, size_t *, int, int);
/* Extract the name of the variable to bind to from the assignment string. */
extern char *assignment_name (const char *);