Unify builtin and user-defined parametric macro calling syntax
Accept both %{foo:arg} and %{foo arg} notation for both builtins and user-defined parametric macros, the former only ever has one argument whereas the latter can have multiple. "parse" type builtins such as %define are trickier and only work with traditional syntax for now.
This commit is contained in:
parent
8901a6be16
commit
1de248d440
|
@ -44,6 +44,7 @@ enum macroFlags_e {
|
||||||
|
|
||||||
#define ME_BUILTIN (ME_PARSE|ME_FUNC)
|
#define ME_BUILTIN (ME_PARSE|ME_FUNC)
|
||||||
#define ME_ARGFUNC (ME_FUNC|ME_HAVEARG)
|
#define ME_ARGFUNC (ME_FUNC|ME_HAVEARG)
|
||||||
|
#define ME_ARGPARSE (ME_PARSE|ME_HAVEARG)
|
||||||
|
|
||||||
/*! The structure used to store a macro. */
|
/*! The structure used to store a macro. */
|
||||||
struct rpmMacroEntry_s {
|
struct rpmMacroEntry_s {
|
||||||
|
@ -1251,9 +1252,9 @@ static struct builtins_s {
|
||||||
{ "P", doSP, ME_ARGFUNC },
|
{ "P", doSP, ME_ARGFUNC },
|
||||||
{ "S", doSP, ME_ARGFUNC },
|
{ "S", doSP, ME_ARGFUNC },
|
||||||
{ "basename", doFoo, ME_ARGFUNC },
|
{ "basename", doFoo, ME_ARGFUNC },
|
||||||
{ "define", doDef, ME_PARSE },
|
{ "define", doDef, ME_ARGPARSE },
|
||||||
{ "dirname", doFoo, ME_ARGFUNC },
|
{ "dirname", doFoo, ME_ARGFUNC },
|
||||||
{ "dnl", doDnl, ME_PARSE },
|
{ "dnl", doDnl, ME_ARGPARSE },
|
||||||
{ "dump", doDump, ME_PARSE },
|
{ "dump", doDump, ME_PARSE },
|
||||||
{ "echo", doOutput, ME_ARGFUNC },
|
{ "echo", doOutput, ME_ARGFUNC },
|
||||||
{ "error", doOutput, ME_ARGFUNC },
|
{ "error", doOutput, ME_ARGFUNC },
|
||||||
|
@ -1263,7 +1264,7 @@ static struct builtins_s {
|
||||||
{ "getconfdir", doFoo, ME_FUNC },
|
{ "getconfdir", doFoo, ME_FUNC },
|
||||||
{ "getenv", doFoo, ME_ARGFUNC },
|
{ "getenv", doFoo, ME_ARGFUNC },
|
||||||
{ "getncpus", doFoo, ME_FUNC },
|
{ "getncpus", doFoo, ME_FUNC },
|
||||||
{ "global", doGlobal, ME_PARSE },
|
{ "global", doGlobal, ME_ARGPARSE },
|
||||||
{ "load", doLoad, ME_ARGFUNC },
|
{ "load", doLoad, ME_ARGFUNC },
|
||||||
#ifdef WITH_LUA
|
#ifdef WITH_LUA
|
||||||
{ "lua", doLua, ME_ARGFUNC },
|
{ "lua", doLua, ME_ARGFUNC },
|
||||||
|
@ -1275,7 +1276,7 @@ static struct builtins_s {
|
||||||
{ "trace", doTrace, ME_FUNC },
|
{ "trace", doTrace, ME_FUNC },
|
||||||
{ "u2p", doFoo, ME_ARGFUNC },
|
{ "u2p", doFoo, ME_ARGFUNC },
|
||||||
{ "uncompress", doUncompress, ME_ARGFUNC },
|
{ "uncompress", doUncompress, ME_ARGFUNC },
|
||||||
{ "undefine", doUndefine, ME_PARSE },
|
{ "undefine", doUndefine, ME_ARGPARSE },
|
||||||
{ "url2path", doFoo, ME_ARGFUNC },
|
{ "url2path", doFoo, ME_ARGFUNC },
|
||||||
{ "verbose", doVerbose, ME_FUNC },
|
{ "verbose", doVerbose, ME_FUNC },
|
||||||
{ "warn", doOutput, ME_ARGFUNC },
|
{ "warn", doOutput, ME_ARGFUNC },
|
||||||
|
@ -1329,29 +1330,48 @@ const char *findMacroEnd(const char *str)
|
||||||
* @param mb macro expansion state
|
* @param mb macro expansion state
|
||||||
* @param me macro entry slot
|
* @param me macro entry slot
|
||||||
* @param args arguments for parametric macros
|
* @param args arguments for parametric macros
|
||||||
|
* @param parsed how many characters ME_PARSE parsed (or NULL)
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
doExpandThisMacro(MacroBuf mb, rpmMacroEntry me, ARGV_t args)
|
doExpandThisMacro(MacroBuf mb, rpmMacroEntry me, ARGV_t args, size_t *parsed)
|
||||||
{
|
{
|
||||||
rpmMacroEntry prevme = mb->me;
|
rpmMacroEntry prevme = mb->me;
|
||||||
ARGV_t prevarg = mb->args;
|
ARGV_t prevarg = mb->args;
|
||||||
|
|
||||||
|
/* Recursively expand body of macro */
|
||||||
|
if (me->flags & ME_BUILTIN) {
|
||||||
|
int nargs = argvCount(args) - 1;
|
||||||
|
int needarg = (me->flags & ME_HAVEARG) ? 1 : 0;
|
||||||
|
int havearg = (nargs > 0);
|
||||||
|
if (needarg != havearg) {
|
||||||
|
mbErr(mb, 1, "%%%s: %s\n", me->name, needarg ?
|
||||||
|
_("argument expected") : _("unexpected argument"));
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
const char *arg = havearg ? args[1] : NULL;
|
||||||
|
if (me->flags & ME_PARSE) {
|
||||||
|
parseFunc parse = me->func;
|
||||||
|
const char *s = parse(mb, me, arg);
|
||||||
|
if (parsed)
|
||||||
|
*parsed = s-arg;
|
||||||
|
} else {
|
||||||
|
macroFunc func = me->func;
|
||||||
|
func(mb, me, arg, arg ? strlen(arg) : 0);
|
||||||
|
}
|
||||||
|
} else if (me->body && *me->body) {
|
||||||
/* Setup args for "%name " macros with opts */
|
/* Setup args for "%name " macros with opts */
|
||||||
if (args != NULL)
|
if (args != NULL)
|
||||||
setupArgs(mb, me, args);
|
setupArgs(mb, me, args);
|
||||||
/* Recursively expand body of macro */
|
|
||||||
if (me->flags & ME_BUILTIN) {
|
|
||||||
/* XXX not yet */
|
|
||||||
mbErr(mb, 1, "tried to expand a builtin: %s\n", me->name);
|
|
||||||
} else if (me->body && *me->body) {
|
|
||||||
if ((me->flags & ME_LITERAL) != 0)
|
if ((me->flags & ME_LITERAL) != 0)
|
||||||
mbAppendStr(mb, me->body);
|
mbAppendStr(mb, me->body);
|
||||||
else
|
else
|
||||||
expandMacro(mb, me->body, 0);
|
expandMacro(mb, me->body, 0);
|
||||||
}
|
|
||||||
/* Free args for "%name " macros with opts */
|
/* Free args for "%name " macros with opts */
|
||||||
if (args != NULL)
|
if (args != NULL)
|
||||||
freeArgs(mb);
|
freeArgs(mb);
|
||||||
|
}
|
||||||
|
exit:
|
||||||
mb->args = prevarg;
|
mb->args = prevarg;
|
||||||
mb->me = prevme;
|
mb->me = prevme;
|
||||||
}
|
}
|
||||||
|
@ -1504,7 +1524,7 @@ expandMacro(MacroBuf mb, const char *src, size_t slen)
|
||||||
if (g && g < ge) { /* Expand X in %{...:X} */
|
if (g && g < ge) { /* Expand X in %{...:X} */
|
||||||
expandMacro(mb, g, gn);
|
expandMacro(mb, g, gn);
|
||||||
} else if (me) {
|
} else if (me) {
|
||||||
doExpandThisMacro(mb, me, NULL);
|
doExpandThisMacro(mb, me, NULL, NULL);
|
||||||
}
|
}
|
||||||
s = se;
|
s = se;
|
||||||
continue;
|
continue;
|
||||||
|
@ -1517,36 +1537,23 @@ expandMacro(MacroBuf mb, const char *src, size_t slen)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Expand builtin macros */
|
|
||||||
if (me->flags & ME_BUILTIN) {
|
|
||||||
int havearg = (me->flags & ME_HAVEARG) ? 1 : 0;
|
|
||||||
if (havearg != (g != NULL)) {
|
|
||||||
mbErr(mb, 1, "%%%s: %s\n", me->name, havearg ?
|
|
||||||
_("argument expected") : _("unexpected argument"));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (me->flags & ME_PARSE) {
|
|
||||||
parseFunc parse = me->func;
|
|
||||||
s = parse(mb, me, se);
|
|
||||||
} else {
|
|
||||||
macroFunc func = me->func;
|
|
||||||
func(mb, me, g, gn);
|
|
||||||
s = se;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Grab args for parametric macros */
|
/* Grab args for parametric macros */
|
||||||
ARGV_t args = NULL;
|
ARGV_t args = NULL;
|
||||||
|
size_t fwd = 0;
|
||||||
if (me->opts != NULL) {
|
if (me->opts != NULL) {
|
||||||
argvAdd(&args, me->name);
|
argvAdd(&args, me->name);
|
||||||
if (lastc)
|
if (g) {
|
||||||
se = grabArgs(mb, &args, fe, lastc);
|
argvAddN(&args, g, gn);
|
||||||
|
} else if (me->flags & ME_PARSE) {
|
||||||
|
argvAdd(&args, se);
|
||||||
|
} else if (lastc) {
|
||||||
|
fwd = (grabArgs(mb, &args, fe, lastc) - se);
|
||||||
}
|
}
|
||||||
doExpandThisMacro(mb, me, args);
|
}
|
||||||
|
doExpandThisMacro(mb, me, args, &fwd);
|
||||||
if (args != NULL)
|
if (args != NULL)
|
||||||
argvFree(args);
|
argvFree(args);
|
||||||
s = se;
|
s = se + (g ? 0 : fwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
mbFini(mb, &med);
|
mbFini(mb, &med);
|
||||||
|
@ -1596,7 +1603,7 @@ expandThisMacro(MacroBuf mb, rpmMacroEntry me, ARGV_const_t args, int flags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
doExpandThisMacro(mb, me, optargs);
|
doExpandThisMacro(mb, me, optargs, NULL);
|
||||||
if (optargs)
|
if (optargs)
|
||||||
argvFree(optargs);
|
argvFree(optargs);
|
||||||
|
|
||||||
|
@ -1950,7 +1957,7 @@ rpmInitMacros(rpmMacroContext mc, const char * macrofiles)
|
||||||
|
|
||||||
/* Define built-in macros */
|
/* Define built-in macros */
|
||||||
for (const struct builtins_s *b = builtinmacros; b->name; b++) {
|
for (const struct builtins_s *b = builtinmacros; b->name; b++) {
|
||||||
pushMacroAny(mc, b->name, NULL, "<builtin>", b->func,
|
pushMacroAny(mc, b->name, "", "<builtin>", b->func,
|
||||||
RMIL_BUILTIN, b->flags);
|
RMIL_BUILTIN, b->flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -302,29 +302,57 @@ AT_CHECK([
|
||||||
runroot rpm --eval "%{dirname}"
|
runroot rpm --eval "%{dirname}"
|
||||||
runroot rpm --eval "%{dirname:}"
|
runroot rpm --eval "%{dirname:}"
|
||||||
runroot rpm --eval "%{dirname:dir}"
|
runroot rpm --eval "%{dirname:dir}"
|
||||||
|
runroot rpm --eval "%{dirname dir}"
|
||||||
runroot rpm --define '%xxx /hello/%%%%/world' --eval '%{dirname:%xxx}'
|
runroot rpm --define '%xxx /hello/%%%%/world' --eval '%{dirname:%xxx}'
|
||||||
runroot rpm --eval "%{uncompress}"
|
runroot rpm --eval "%{uncompress}"
|
||||||
runroot rpm --eval "%{uncompress:}"
|
runroot rpm --eval "%{uncompress:}"
|
||||||
runroot rpm --eval "%{getncpus:}"
|
runroot rpm --eval "%{getncpus:}"
|
||||||
runroot rpm --eval "%{getncpus:5}"
|
runroot rpm --eval "%{getncpus:5}"
|
||||||
runroot rpm --eval "%{define:}"
|
runroot rpm --eval "%{define:}"
|
||||||
|
runroot rpm --eval "%{define:foo}"
|
||||||
|
runroot rpm --eval "%{define:foo bar}%{foo}"
|
||||||
runroot rpm --eval "%{dump:foo}"
|
runroot rpm --eval "%{dump:foo}"
|
||||||
],
|
],
|
||||||
[1],
|
[1],
|
||||||
[
|
[
|
||||||
dir
|
dir
|
||||||
|
dir
|
||||||
/hello/%%
|
/hello/%%
|
||||||
|
|
||||||
|
bar
|
||||||
],
|
],
|
||||||
[error: %dirname: argument expected
|
[error: %dirname: argument expected
|
||||||
error: %uncompress: argument expected
|
error: %uncompress: argument expected
|
||||||
error: %getncpus: unexpected argument
|
error: %getncpus: unexpected argument
|
||||||
error: %getncpus: unexpected argument
|
error: %getncpus: unexpected argument
|
||||||
error: %define: unexpected argument
|
error: Macro % has illegal name (%define)
|
||||||
|
error: Macro %foo has empty body
|
||||||
error: %dump: unexpected argument
|
error: %dump: unexpected argument
|
||||||
])
|
])
|
||||||
AT_CLEANUP
|
AT_CLEANUP
|
||||||
|
|
||||||
|
AT_SETUP([macro arguments])
|
||||||
|
AT_KEYWORDS([macros])
|
||||||
|
AT_CHECK([
|
||||||
|
runroot rpm \
|
||||||
|
--define 'zzz xxx' \
|
||||||
|
--eval '%{defined zzz}' \
|
||||||
|
--eval '%{defined:zzz}' \
|
||||||
|
--eval '%defined zzz' \
|
||||||
|
--eval '%{defined aaa}' \
|
||||||
|
--eval '%{defined:aaa}' \
|
||||||
|
--eval '%defined aaa'
|
||||||
|
],
|
||||||
|
[0],
|
||||||
|
[1
|
||||||
|
1
|
||||||
|
1
|
||||||
|
0
|
||||||
|
0
|
||||||
|
0
|
||||||
|
])
|
||||||
|
AT_CLEANUP
|
||||||
|
|
||||||
AT_SETUP([expr macro 1])
|
AT_SETUP([expr macro 1])
|
||||||
AT_KEYWORDS([macros])
|
AT_KEYWORDS([macros])
|
||||||
AT_CHECK([
|
AT_CHECK([
|
||||||
|
|
Loading…
Reference in New Issue