From: Chet Ramey Date: Tue, 17 Oct 2023 15:09:23 +0000 (-0400) Subject: changes for backslashes in glob patterns and single-quoted strings; brace expansion... X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1e1a0342a40b770d0d0d8045c1a7115a7bfa1ef9;p=thirdparty%2Fbash.git 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 --- diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 773912d18..a9f2dfe49 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -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 + + 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 + +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 + +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 + +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 + - 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. diff --git a/braces.c b/braces.c index a4476868c..3d096db75 100644 --- a/braces.c +++ b/braces.c @@ -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 diff --git a/builtins/read.def b/builtins/read.def index 587be2873..0fcc6f4e4 100644 --- a/builtins/read.def +++ b/builtins/read.def @@ -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); diff --git a/lib/sh/strtrans.c b/lib/sh/strtrans.c index d3b27f3bf..af75dcfa8 100644 --- a/lib/sh/strtrans.c +++ b/lib/sh/strtrans.c @@ -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*/ diff --git a/parse.y b/parse.y index 3e5b814f2..dd35ea768 100644 --- a/parse.y +++ b/parse.y @@ -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; } diff --git a/pathexp.c b/pathexp.c index a050ca2c8..f62efafb6 100644 --- a/pathexp.c +++ b/pathexp.c @@ -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') diff --git a/subst.c b/subst.c index aa73feadd..f6347a4fd 100644 --- a/subst.c +++ b/subst.c @@ -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); } diff --git a/subst.h b/subst.h index c83bf5a20..2117e7ccc 100644 --- a/subst.h +++ b/subst.h @@ -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 *);