When substituting interpreter variables, allow '$' to be part of

the variable expresstion only within '[]' or '()'. That lets
forms like "$a$b" to be treated as two substitutions, not one.
This commit is contained in:
Giles Atkinson 2023-10-18 13:21:24 +01:00
parent 3ba314d4bc
commit 89851872ed
1 changed files with 15 additions and 4 deletions

View File

@ -789,7 +789,7 @@ cp_getvar(char *name, enum cp_types type, void *retval, size_t rsize)
* isset is TRUE if the variable is being set, FALSE if unset. Also
* required is a routine cp_enqvar(name) which returns a struct
* variable *, which allows the host program to provide values for
* non-cshpar variables. See line 855 */
* non-cshpar variables. */
/* Non-alphanumeric characters that may appear in variable names. < is very
* special...
@ -806,10 +806,11 @@ cp_getvar(char *name, enum cp_types type, void *retval, size_t rsize)
* Return value
* Address of the first character after the variable name.
*/
char *span_var_expr(char *t)
char *span_var_expr(char *s)
{
int parenthesis = 0;
int brackets = 0;
char *t = s;
int parenthesis = 0;
int brackets = 0;
while (*t && (isalnum_c(*t) || strchr(VALIDCHARS, *t)))
switch (*t++)
@ -832,6 +833,14 @@ char *span_var_expr(char *t)
if (--parenthesis <= 0)
return t;
break;
case '$':
if (brackets <= 0 && parenthesis <= 0) {
if (t == s + 1) // Special case: "$$".
return t;
else
return t-1;
}
break;
default:
break;
}
@ -1000,6 +1009,8 @@ wordlist *vareval(/* NOT const */ char *string)
if (eq(v->va_name, string))
break;
if (!v && isdigit_c(*string)) {
/* Treat $i for some integer i as argv[i] - positional parameters. */
for (v = variables; v; v = v->va_next) {
if (eq(v->va_name, "argv")) {
break;