diff --git a/docs/manual/macros.md b/docs/manual/macros.md index daf11279b..11f598c7b 100644 --- a/docs/manual/macros.md +++ b/docs/manual/macros.md @@ -98,6 +98,7 @@ to perform useful operations. The current list is %{lua:...} expand using the [embedded Lua interpreter](lua.md) %{expand:...} like eval, expand ... to and (re-)expand %{expr:...} evaluate an expression + %{shescape:...} single quote with escapes for use in shell %{shrink:...} trim leading and trailing whitespace, reduce intermediate whitespace to a single space %{quote:...} quote a parametric macro argument, needed to pass diff --git a/rpmio/macro.c b/rpmio/macro.c index eeeffa2b1..3263e0a91 100644 --- a/rpmio/macro.c +++ b/rpmio/macro.c @@ -1145,6 +1145,29 @@ static size_t doVerbose(MacroBuf mb, rpmMacroEntry me, ARGV_t argv) return 0; } +static size_t doShescape(MacroBuf mb, rpmMacroEntry me, ARGV_t argv) +{ + char *result, *dst; + const char *src = argv[1]; + + result = dst = xmalloc(strlen(src) * 4 + 3); + *dst++ = '\''; + for (; *src != '\0'; src++) { + if (*src == '\'') { + *dst++ = '\''; + *dst++ = '\\'; + *dst++ = '\''; + *dst++ = '\''; + } else { + *dst++ = *src; + } + } + *dst++ = '\''; + *dst = '\0'; + mbAppendStr(mb, result); + return 0; +} + static size_t doFoo(MacroBuf mb, rpmMacroEntry me, ARGV_t argv) { @@ -1279,6 +1302,7 @@ static struct builtins_s { { "suffix", doFoo, 1, ME_FUNC }, { "trace", doTrace, 0, ME_FUNC }, { "u2p", doFoo, 1, ME_FUNC }, + { "shescape", doShescape, 1, ME_FUNC }, { "uncompress", doUncompress, 1, ME_FUNC }, { "undefine", doUndefine, 1, ME_FUNC }, { "url2path", doFoo, 1, ME_FUNC }, diff --git a/tests/rpmmacro.at b/tests/rpmmacro.at index fb6b21f4b..f79f7deec 100644 --- a/tests/rpmmacro.at +++ b/tests/rpmmacro.at @@ -863,6 +863,18 @@ runroot rpm \ ]) AT_CLEANUP +AT_SETUP([%shescape macro]) +AT_KEYWORDS([macros]) +AT_CHECK([ +runroot rpm \ + --eval "%{shescape:foo's}" +], +[0], +['foo'\''s' +], +[]) +AT_CLEANUP + AT_SETUP([macro with a line starting by "{"]) AT_KEYWORDS([macros]) AT_CHECK([