Well, I also tried adding support for bash's ${var@Q} (which I think is the
most readable way to solve quoting) but it seems I really don't understand
how ash's subevalvar() works after all :)
./busybox ash -xvc 'v="ab cd"; echo "(${v@Q})"'
+ v='ab cd'
ash: vstransform:str='Q'
ash: vstransform:startp='ab cd'
+ echo ''"'"'a'"'"'ab cd'"'"')'
'a'ab cd')
diff --git a/shell/ash.c b/shell/ash.c
index ae1b79f37..8d5d6146d 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -222,6 +222,8 @@
#define IF_BASH_PATTERN_SUBST IF_ASH_BASH_COMPAT
#define BASH_SUBSTR ENABLE_ASH_BASH_COMPAT
#define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT
+#define BASH_PARAM_TRANSFORM ENABLE_ASH_BASH_COMPAT
+#define IF_BASH_PARAM_TRANSFORM IF_ASH_BASH_COMPAT
/* BASH_TEST2: [[ EXPR ]]
* Status of [[ support:
* && and || work as they should
@@ -574,6 +576,7 @@ var_end(const char *var)
return var;
}
+static int hasmeta(const char *);
/* ============ Parser data */
@@ -868,6 +871,9 @@ out2str(const char *p)
#define VSREPLACE 0xd /* ${var/pattern/replacement} */
#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
#endif
+#if BASH_PARAM_TRANSFORM
+#define VSTRANSFORM 0xf /* ${var@operator} */
+#endif
static const char dolatstr[] ALIGN1 = {
CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
@@ -7262,6 +7268,20 @@ subevalvar(char *start, char *str, int strloc,
repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos)
);
+#if BASH_PARAM_TRANSFORM
+ if (subtype == VSTRANSFORM) {
+ bb_error_msg("vstransform:str='%s'", str);
+ if (strcmp(str, "Q") != 0)
+ goto out1;
+ bb_error_msg("vstransform:startp='%s'", startp);
+ char *quoted = single_quote(startp);
+ int len = strlen(quoted);
+ memmove(startp, quoted, len);
+ loc = startp + len;
+ goto out;
+ }
+#endif /* BASH_PARAM_TRANSFORM */
+
#if BASH_PATTERN_SUBST
workloc = expdest - (char *)stackblock();
if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
@@ -7432,7 +7452,7 @@ subevalvar(char *start, char *str, int strloc,
out:
amount = loc - expdest;
STADJUST(amount, expdest);
-#if BASH_PATTERN_SUBST
+#if BASH_PATTERN_SUBST || BASH_PARAM_TRANSFORM
out1:
#endif
/* Remove any recorded regions beyond start of variable */
@@ -7671,6 +7691,9 @@ evalvar(char *p, int flag)
#if BASH_PATTERN_SUBST
case VSREPLACE:
case VSREPLACEALL:
+#endif
+#if BASH_PARAM_TRANSFORM
+ case VSTRANSFORM:
#endif
break;
default:
@@ -12989,6 +13012,13 @@ parsesub: {
goto badsub;
subtype++; /* VSREPLACEALL */
break;
+#endif
+#if BASH_PARAM_TRANSFORM
+ case '@':
+ /* ${v@operator} */
+ subtype = VSTRANSFORM;
+ newsyn = BASESYNTAX;
+ break;
#endif
}
} else {
On Thu, 15 Feb 2024, David Laight wrote:
From: David Leonard
Sent: 15 February 2024 08:46
To: Harvey <h...@gmx.de>
Cc: busybox@busybox.net
Subject: Re: Failing shell code under busybox 1.36.1 that worked with 1.31.1
_result="$_result '${_p//'/'\"'\"'}'"
Busybox ash has a CONFIG_ASH_BASH_COMPAT config to get this ${var//...}
replacement behaviour. And, in bash, the ' in the pattern section is treated
as a quote start. To give the ' a literal meaning, use \'
eg ${_p//\'/..repl..}
...
It is probably safer to the quotes into variables.
Then the syntax analysis won't get messed up.
So something like:
sq="'"
qsq='"'"'"'"'
then
"${_p/$sg/$qsq}"
is probably ok and maybe more readable.
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT,
UK
Registration No: 1397386 (Wales)
_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox