From 423abc3e31b16f3f9136de9c44f3d3ac5881228d Mon Sep 17 00:00:00 2001 From: Panu Matilainen Date: Thu, 22 Oct 2020 13:05:31 +0300 Subject: [PATCH 1/3] Separate macro table from the context No functional changes, but needed for next steps. --- rpmio/macro.c | 106 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 38 deletions(-) diff --git a/rpmio/macro.c b/rpmio/macro.c index 1edcb39e6d..a470e352ee 100644 --- a/rpmio/macro.c +++ b/rpmio/macro.c @@ -52,10 +52,14 @@ struct rpmMacroEntry_s { char arena[]; /*!< String arena. */ }; +typedef struct macroTable_s { + rpmMacroEntry *tab; /*!< Macro entry table (array of pointers). */ + int n; /*!< No. of macros. */ +} *macroTable; + /*! The structure used to store the set of macros in a context. */ struct rpmMacroContext_s { - rpmMacroEntry *tab; /*!< Macro entry table (array of pointers). */ - int n; /*!< No. of macros. */ + struct macroTable_s tab; /*!< Macro table */ int depth; /*!< Depth tracking when recursing from Lua */ int level; /*!< Scope level tracking when recursing from Lua */ pthread_mutex_t lock; @@ -127,6 +131,7 @@ typedef const char *(*parseFunc)(MacroBuf mb, const char * se); static int expandMacro(MacroBuf mb, const char *src, size_t slen); static void pushMacro(rpmMacroContext mc, const char * n, const char * o, const char * b, int level, int flags); +static void macroTablePop(macroTable mt, const char * n); static void popMacro(rpmMacroContext mc, const char * n); static int loadMacroFile(rpmMacroContext mc, const char * fn); static void doBody(MacroBuf mb, int chkexist, int negate, @@ -173,23 +178,23 @@ static rpmMacroContext rpmmctxRelease(rpmMacroContext mc) /** * Find entry in macro table. - * @param mc macro context + * @param mt macro table * @param name macro name * @param namelen no. of bytes * @param pos found/insert position * @return address of slot in macro table with name (or NULL) */ static rpmMacroEntry * -findEntry(rpmMacroContext mc, const char *name, size_t namelen, size_t *pos) +macroTableFind(const struct macroTable_s *mt, const char *name, size_t namelen, size_t *pos) { /* bsearch */ int cmp = 1; size_t l = 0; - size_t u = mc->n; + size_t u = mt->n; size_t i = 0; while (l < u) { i = (l + u) / 2; - rpmMacroEntry me = mc->tab[i]; + rpmMacroEntry me = mt->tab[i]; if (namelen == 0) cmp = strcmp(me->name, name); else { @@ -209,7 +214,23 @@ findEntry(rpmMacroContext mc, const char *name, size_t namelen, size_t *pos) if (pos) *pos = (cmp < 0) ? i + 1 : i; if (cmp == 0) - return &mc->tab[i]; + return &mt->tab[i]; + return NULL; +} + +static rpmMacroEntry * +findEntry(rpmMacroContext mc, const char *name, size_t namelen, size_t *pos) +{ + return macroTableFind(&mc->tab, name, namelen, pos); +} + +static macroTable macroTableFree(macroTable mt) +{ + while (mt->n > 0) { + /* remove from the end to avoid memmove */ + rpmMacroEntry me = mt->tab[mt->n - 1]; + macroTablePop(mt, me->name); + } return NULL; } @@ -832,10 +853,11 @@ static void freeArgs(MacroBuf mb) { rpmMacroContext mc = mb->mc; + macroTable mt = &mc->tab; /* Delete dynamic macro definitions */ - for (int i = 0; i < mc->n; i++) { - rpmMacroEntry me = mc->tab[i]; + for (int i = 0; i < mt->n; i++) { + rpmMacroEntry me = mt->tab[i]; assert(me); if (me->level < mb->level) continue; @@ -850,7 +872,7 @@ freeArgs(MacroBuf mb) /* compensate if the slot is to go away */ if (me->prev == NULL) i--; - popMacro(mc, me->name); + macroTablePop(mt, me->name); } mb->level--; mb->args = argvFree(mb->args); @@ -1605,7 +1627,7 @@ static int doExpandMacros(rpmMacroContext mc, const char *src, int flags, return rc; } -static void pushMacro(rpmMacroContext mc, +static void macroTablePush(macroTable mt, const char * n, const char * o, const char * b, int level, int flags) { /* new entry */ @@ -1618,7 +1640,7 @@ static void pushMacro(rpmMacroContext mc, size_t mesize = sizeof(*me) + blen + 1 + (olen ? olen + 1 : 0); size_t pos; - rpmMacroEntry *mep = findEntry(mc, n, 0, &pos); + rpmMacroEntry *mep = macroTableFind(mt, n, 0, &pos); if (mep) { /* entry with shared name */ me = xmalloc(mesize); @@ -1635,14 +1657,14 @@ static void pushMacro(rpmMacroContext mc, else { /* extend macro table */ const int delta = 256; - if (mc->n % delta == 0) - mc->tab = xrealloc(mc->tab, sizeof(me) * (mc->n + delta)); + if (mt->n % delta == 0) + mt->tab = xrealloc(mt->tab, sizeof(me) * (mt->n + delta)); /* shift pos+ entries to the right */ - memmove(mc->tab + pos + 1, mc->tab + pos, sizeof(me) * (mc->n - pos)); - mc->n++; + memmove(mt->tab + pos + 1, mt->tab + pos, sizeof(me) * (mt->n - pos)); + mt->n++; /* make slot */ - mc->tab[pos] = NULL; - mep = &mc->tab[pos]; + mt->tab[pos] = NULL; + mep = &mt->tab[pos]; /* entry with new name */ size_t nlen = strlen(n); me = xmalloc(mesize + nlen + 1); @@ -1672,30 +1694,41 @@ static void pushMacro(rpmMacroContext mc, *mep = me; } -static void popMacro(rpmMacroContext mc, const char * n) +static void pushMacro(rpmMacroContext mc, + const char * n, const char * o, const char * b, int level, int flags) +{ + macroTablePush(&mc->tab, n, o, b, level, flags); +} + +static void macroTablePop(macroTable mt, const char * n) { size_t pos; - rpmMacroEntry *mep = findEntry(mc, n, 0, &pos); + rpmMacroEntry *mep = macroTableFind(mt, n, 0, &pos); if (mep == NULL) return; /* parting entry */ rpmMacroEntry me = *mep; assert(me); /* detach/pop definition */ - mc->tab[pos] = me->prev; + mt->tab[pos] = me->prev; /* shrink macro table */ if (me->prev == NULL) { - mc->n--; - /* move pos+ elements to the left */ - memmove(mc->tab + pos, mc->tab + pos + 1, sizeof(me) * (mc->n - pos)); + mt->n--; /* deallocate */ - if (mc->n == 0) - mc->tab = _free(mc->tab); + if (mt->n == 0) + mt->tab = _free(mt->tab); + /* move pos+ elements to the left */ + memmove(mt->tab + pos, mt->tab + pos + 1, sizeof(me) * (mt->n - pos)); } /* comes in a single chunk */ free(me); } +static void popMacro(rpmMacroContext mc, const char * n) +{ + macroTablePop(&mc->tab, n); +} + static int defineMacro(rpmMacroContext mc, const char * macro, int level) { MacroBuf mb = xcalloc(1, sizeof(*mb)); @@ -1753,12 +1786,12 @@ static int loadMacroFile(rpmMacroContext mc, const char * fn) return rc; } -static void copyMacros(rpmMacroContext src, rpmMacroContext dst, int level) +static void copyMacros(macroTable src, macroTable dst, int level) { for (int i = 0; i < src->n; i++) { rpmMacroEntry me = src->tab[i]; assert(me); - pushMacro(dst, me->name, me->opts, me->body, level, me->flags); + macroTablePush(dst, me->name, me->opts, me->body, level, me->flags); } } @@ -1786,11 +1819,12 @@ void rpmDumpMacroTable(rpmMacroContext mc, FILE * fp) { mc = rpmmctxAcquire(mc); + macroTable mt = &mc->tab; if (fp == NULL) fp = stderr; fprintf(fp, "========================\n"); - for (int i = 0; i < mc->n; i++) { - rpmMacroEntry me = mc->tab[i]; + for (int i = 0; i < mt->n; i++) { + rpmMacroEntry me = mt->tab[i]; assert(me); fprintf(fp, "%3d%c %s", me->level, ((me->flags & ME_USED) ? '=' : ':'), me->name); @@ -1801,7 +1835,7 @@ rpmDumpMacroTable(rpmMacroContext mc, FILE * fp) fprintf(fp, "\n"); } fprintf(fp, _("======================== active %d empty %d\n"), - mc->n, 0); + mt->n, 0); rpmmctxRelease(mc); } @@ -1872,7 +1906,7 @@ rpmLoadMacros(rpmMacroContext mc, int level) gmc = rpmmctxAcquire(NULL); mc = rpmmctxAcquire(mc); - copyMacros(mc, gmc, level); + copyMacros(&mc->tab, &gmc->tab, level); rpmmctxRelease(mc); rpmmctxRelease(gmc); @@ -1924,7 +1958,7 @@ rpmInitMacros(rpmMacroContext mc, const char * macrofiles) /* Reload cmdline macros */ climc = rpmmctxAcquire(rpmCLIMacroContext); - copyMacros(climc, mc, RMIL_CMDLINE); + copyMacros(&climc->tab, &mc->tab, RMIL_CMDLINE); rpmmctxRelease(climc); rpmmctxRelease(mc); @@ -1934,11 +1968,7 @@ void rpmFreeMacros(rpmMacroContext mc) { mc = rpmmctxAcquire(mc); - while (mc->n > 0) { - /* remove from the end to avoid memmove */ - rpmMacroEntry me = mc->tab[mc->n - 1]; - popMacro(mc, me->name); - } + macroTableFree(&mc->tab); rpmmctxRelease(mc); } From cddb7ddba0094b278862aaf8a7febf8efd8bca2f Mon Sep 17 00:00:00 2001 From: Panu Matilainen Date: Thu, 22 Oct 2020 14:49:01 +0300 Subject: [PATCH 2/3] Implement a real stack for parametric macro locals Mixing up local stack and global data never was such a hot idea, as locals could get trapped between globals and not freed at appropriate times etc. This clears up the semantics wrt that, fixing long-standing expected failures in the test-suite: locals always shadow globals, and undefines occur from localmost towards global. We no longer need to huff and puff through the entire macro table on exit from parametric macro, but we do pay a prize on lookup as there are now multiple macro tables we need to look at. --- build/rpmfc.c | 2 +- rpmio/macro.c | 89 ++++++++++++++++++++++++++--------------------- rpmio/rpmmacro.h | 1 + tests/rpmmacro.at | 20 ++++++++--- 4 files changed, 66 insertions(+), 46 deletions(-) diff --git a/build/rpmfc.c b/build/rpmfc.c index 6fb67fdddc..8757046c44 100644 --- a/build/rpmfc.c +++ b/build/rpmfc.c @@ -538,7 +538,7 @@ static ARGV_t runCall(const char *cmd, rpmlog(RPMLOG_DEBUG, "Calling %s() on %s\n", cmd, fn); /* Hack to pass in the path as what looks like a macro argument */ - rpmPushMacroFlags(NULL, "1", NULL, fn, 1, RPMMACRO_LITERAL); + rpmPushMacroFlags(NULL, "1", NULL, fn, RMIL_GLOBAL, RPMMACRO_LITERAL); char *exp = rpmExpand(cmd, NULL); rpmPopMacro(NULL, "1"); if (*exp) diff --git a/rpmio/macro.c b/rpmio/macro.c index a470e352ee..537f8b318f 100644 --- a/rpmio/macro.c +++ b/rpmio/macro.c @@ -19,6 +19,15 @@ #define MACROBUFSIZ (BUFSIZ * 2) +#define _MAX_MACRO_DEPTH 64 +static int max_macro_depth = _MAX_MACRO_DEPTH; + +#define _PRINT_MACRO_TRACE 0 +static int print_macro_trace = _PRINT_MACRO_TRACE; + +#define _PRINT_EXPAND_TRACE 0 +static int print_expand_trace = _PRINT_EXPAND_TRACE; + #include #include #include @@ -60,6 +69,7 @@ typedef struct macroTable_s { /*! The structure used to store the set of macros in a context. */ struct rpmMacroContext_s { struct macroTable_s tab; /*!< Macro table */ + struct macroTable_s local[_MAX_MACRO_DEPTH]; /*!< Local macro tables */ int depth; /*!< Depth tracking when recursing from Lua */ int level; /*!< Scope level tracking when recursing from Lua */ pthread_mutex_t lock; @@ -104,7 +114,6 @@ typedef struct MacroBuf_s { size_t tpos; /*!< Current position in expansion buffer */ size_t nb; /*!< No. bytes remaining in expansion buffer. */ int depth; /*!< Current expansion depth. */ - int level; /*!< Current scoping level */ int error; /*!< Errors encountered during expansion? */ int macro_trace; /*!< Pre-print macro to expand? */ int expand_trace; /*!< Post-print macro expansion? */ @@ -114,15 +123,6 @@ typedef struct MacroBuf_s { rpmMacroContext mc; } * MacroBuf; -#define _MAX_MACRO_DEPTH 64 -static int max_macro_depth = _MAX_MACRO_DEPTH; - -#define _PRINT_MACRO_TRACE 0 -static int print_macro_trace = _PRINT_MACRO_TRACE; - -#define _PRINT_EXPAND_TRACE 0 -static int print_expand_trace = _PRINT_EXPAND_TRACE; - typedef void (*macroFunc)(MacroBuf mb, int chkexist, int negate, const char * f, size_t fn, const char * g, size_t gn); typedef const char *(*parseFunc)(MacroBuf mb, const char * se); @@ -221,7 +221,25 @@ macroTableFind(const struct macroTable_s *mt, const char *name, size_t namelen, static rpmMacroEntry * findEntry(rpmMacroContext mc, const char *name, size_t namelen, size_t *pos) { - return macroTableFind(&mc->tab, name, namelen, pos); + rpmMacroEntry * mep = NULL; + + if (namelen == 0) + namelen = strlen(name); + + /* User-defined scoped macros are accessible from levels above */ + for (int i = mc->level; mep == NULL && i >= 0; i--) { + mep = macroTableFind(&mc->local[i], name, namelen, pos); + + /* Only look for automatic macros on the current level */ + if (namelen < 3) + break; + } + + /* Finally, look at globals */ + if (mep == NULL) + mep = macroTableFind(&mc->tab, name, namelen, pos); + + return mep; } static macroTable macroTableFree(macroTable mt) @@ -828,7 +846,7 @@ doUndefine(MacroBuf mb, const char * se) static const char * doDef(MacroBuf mb, const char * se) { - return doDefine(mb, se, mb->level, 0); + return doDefine(mb, se, RMIL_LOCAL, 0); } static const char * doGlobal(MacroBuf mb, const char * se) @@ -853,14 +871,11 @@ static void freeArgs(MacroBuf mb) { rpmMacroContext mc = mb->mc; - macroTable mt = &mc->tab; + macroTable mt = &mc->local[mc->level]; /* Delete dynamic macro definitions */ for (int i = 0; i < mt->n; i++) { rpmMacroEntry me = mt->tab[i]; - assert(me); - if (me->level < mb->level) - continue; /* Warn on defined but unused non-automatic, scoped macros */ if (!(me->flags & (ME_AUTO|ME_USED))) { mbErr(mb, 0, _("Macro %%%s defined but not used within scope\n"), @@ -868,13 +883,9 @@ freeArgs(MacroBuf mb) /* Only whine once */ me->flags |= ME_USED; } - - /* compensate if the slot is to go away */ - if (me->prev == NULL) - i--; - macroTablePop(mt, me->name); } - mb->level--; + macroTableFree(mt); + mc->level--; mb->args = argvFree(mb->args); mb->me = NULL; } @@ -923,13 +934,13 @@ static int mbopt(int c, const char *oarg, int oint, void *data) } else { rasprintf(&body, "-%c", c); } - pushMacro(mb->mc, name, NULL, body, mb->level, ME_AUTO | ME_LITERAL); + pushMacro(mb->mc, name, NULL, body, RMIL_LOCAL, ME_AUTO | ME_LITERAL); free(name); free(body); if (oarg) { rasprintf(&name, "-%c*", c); - pushMacro(mb->mc, name, NULL, oarg, mb->level, ME_AUTO | ME_LITERAL); + pushMacro(mb->mc, name, NULL, oarg, RMIL_LOCAL, ME_AUTO | ME_LITERAL); free(name); } return 0; @@ -948,6 +959,7 @@ static const char * grabArgs(MacroBuf mb, const rpmMacroEntry me, const char * se, const char * lastc) { + rpmMacroContext mc = mb->mc; const char *cont = NULL; char *args = NULL; ARGV_t argv = NULL; @@ -974,10 +986,10 @@ grabArgs(MacroBuf mb, const rpmMacroEntry me, const char * se, } /* Bump call depth on entry before first macro define */ - mb->level++; + mc->level++; /* Setup macro name as %0 */ - pushMacro(mb->mc, "0", NULL, me->name, mb->level, ME_AUTO | ME_LITERAL); + pushMacro(mb->mc, "0", NULL, me->name, RMIL_LOCAL, ME_AUTO | ME_LITERAL); /* * The macro %* analoguous to the shell's $* means "Pass all non-macro @@ -988,7 +1000,7 @@ grabArgs(MacroBuf mb, const rpmMacroEntry me, const char * se, * This is the (potential) justification for %{**} ... */ args = argvJoin(argv + 1, " "); - pushMacro(mb->mc, "**", NULL, args, mb->level, ME_AUTO | ME_LITERAL); + pushMacro(mb->mc, "**", NULL, args, RMIL_LOCAL, ME_AUTO | ME_LITERAL); free(args); argc = argvCount(argv); @@ -1003,7 +1015,7 @@ grabArgs(MacroBuf mb, const rpmMacroEntry me, const char * se, /* Add argument count (remaining non-option items) as macro. */ { char *ac = NULL; rasprintf(&ac, "%d", (argc - ind)); - pushMacro(mb->mc, "#", NULL, ac, mb->level, ME_AUTO | ME_LITERAL); + pushMacro(mb->mc, "#", NULL, ac, RMIL_LOCAL, ME_AUTO | ME_LITERAL); free(ac); } @@ -1012,14 +1024,14 @@ grabArgs(MacroBuf mb, const rpmMacroEntry me, const char * se, for (c = ind; c < argc; c++) { char *name = NULL; rasprintf(&name, "%d", (c - ind + 1)); - pushMacro(mb->mc, name, NULL, argv[c], mb->level, ME_AUTO | ME_LITERAL); + pushMacro(mb->mc, name, NULL, argv[c], RMIL_LOCAL, ME_AUTO | ME_LITERAL); free(name); } } /* Add concatenated unexpanded arguments as yet another macro. */ args = argvJoin(argv + ind, " "); - pushMacro(mb->mc, "*", NULL, args ? args : "", mb->level, ME_AUTO | ME_LITERAL); + pushMacro(mb->mc, "*", NULL, args ? args : "", RMIL_LOCAL, ME_AUTO | ME_LITERAL); free(args); exit: @@ -1089,7 +1101,6 @@ static void doLua(MacroBuf mb, int chkexist, int negate, const char * f, size_t scriptbuf[gn] = '\0'; rpmluaPushPrintBuffer(lua); mc->depth = mb->depth; - mc->level = mb->level; if (rpmluaRunScript(lua, scriptbuf, name, opts, args) == -1) mb->error = 1; mc->depth = odepth; @@ -1526,13 +1537,8 @@ expandMacro(MacroBuf mb, const char *src, size_t slen) me = (mep ? *mep : NULL); if (me) { - if ((me->flags & ME_AUTO) && mb->level > me->level) { - /* Ignore out-of-scope automatic macros */ - me = NULL; - } else { - /* If we looked up a macro, consider it used */ - me->flags |= ME_USED; - } + /* If we looked up a macro, consider it used */ + me->flags |= ME_USED; } /* XXX Special processing for flags and existance test */ @@ -1611,7 +1617,6 @@ static int doExpandMacros(rpmMacroContext mc, const char *src, int flags, mb->buf = NULL; mb->depth = mc->depth; - mb->level = mc->level; mb->macro_trace = print_macro_trace; mb->expand_trace = print_expand_trace; mb->mc = mc; @@ -1697,7 +1702,11 @@ static void macroTablePush(macroTable mt, static void pushMacro(rpmMacroContext mc, const char * n, const char * o, const char * b, int level, int flags) { - macroTablePush(&mc->tab, n, o, b, level, flags); + if (flags & ME_AUTO || level > 0) { + macroTablePush(&mc->local[mc->level], n, o, b, mc->level, flags); + } else { + macroTablePush(&mc->tab, n, o, b, level, flags); + } } static void macroTablePop(macroTable mt, const char * n) diff --git a/rpmio/rpmmacro.h b/rpmio/rpmmacro.h index 005ff88ca6..a48a6ce18c 100644 --- a/rpmio/rpmmacro.h +++ b/rpmio/rpmmacro.h @@ -44,6 +44,7 @@ extern const char * macrofiles; #define RMIL_SPEC -3 #define RMIL_OLDSPEC -1 #define RMIL_GLOBAL 0 +#define RMIL_LOCAL 1 /* Deprecated compatibility wrappers */ #define addMacro(_mc, _n, _o, _b, _l) rpmPushMacro(_mc, _n, _o, _b, _l) diff --git a/tests/rpmmacro.at b/tests/rpmmacro.at index d972a1197d..b55e7d03e3 100644 --- a/tests/rpmmacro.at +++ b/tests/rpmmacro.at @@ -683,7 +683,7 @@ runroot rpm \ ], [0], [1 -%xxx +1 . . ]) AT_CLEANUP @@ -707,7 +707,6 @@ AT_CLEANUP AT_SETUP([%define + %undefine in nested levels 3]) AT_KEYWORDS([macros define]) AT_CHECK([ -AT_XFAIL_IF([test $RPM_XFAIL -ne 0]) # %define macro twice in a nested scope runroot rpm \ --define '%foo() %{expand:%define xxx 1} %{echo:%xxx} %{expand: %define xxx 2} %{echo:%xxx}' \ @@ -725,8 +724,6 @@ AT_CLEANUP AT_SETUP([%define + %undefine in nested levels 4]) AT_KEYWORDS([macros define global]) AT_CHECK([ -AT_XFAIL_IF([test $RPM_XFAIL -ne 0]) -# %define in a nested level covered by %global runroot rpm \ --define '%foo() %{expand:%define xxx 1} %{echo:%xxx} %{expand: %global xxx 2} %{echo:%xxx}' \ --eval .'%foo'. \ @@ -736,7 +733,7 @@ runroot rpm \ ], [0], [1 -2 +1 . . 2 .. @@ -744,6 +741,19 @@ runroot rpm \ ]) AT_CLEANUP +AT_SETUP([%define + %undefine in nested levels 5]) +AT_KEYWORDS([macros define]) +AT_CHECK([ +runroot rpm \ + --define "foo() %bar" \ + --define "foo2() %{expand:%define bar hello}%{foo}" \ + --eval "%foo2" +], +[0], +[hello +]) +AT_CLEANUP + AT_SETUP([%define in conditional macro]) AT_KEYWORDS([macros]) AT_CHECK([ From c2eb4dda7d410b658d926c1b1bdaa66eb58825cd Mon Sep 17 00:00:00 2001 From: Panu Matilainen Date: Fri, 23 Oct 2020 15:19:53 +0300 Subject: [PATCH 3/3] Handle unused macro warnings at deletion Avoids having to walk over the macro tables just looking for things to nag about when we'll come across it in the next step anyhow. Permit mbErr() to be called with NULL mb if it's not an error, such as here. --- rpmio/macro.c | 20 +++++++------------- tests/rpmmacro.at | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/rpmio/macro.c b/rpmio/macro.c index 537f8b318f..f52dc885a9 100644 --- a/rpmio/macro.c +++ b/rpmio/macro.c @@ -362,7 +362,7 @@ static void mbErr(MacroBuf mb, int error, const char *fmt, ...) free(pfx); } - if (error) + if (error && mb) mb->error = error; free(emsg); @@ -871,20 +871,9 @@ static void freeArgs(MacroBuf mb) { rpmMacroContext mc = mb->mc; - macroTable mt = &mc->local[mc->level]; /* Delete dynamic macro definitions */ - for (int i = 0; i < mt->n; i++) { - rpmMacroEntry me = mt->tab[i]; - /* Warn on defined but unused non-automatic, scoped macros */ - if (!(me->flags & (ME_AUTO|ME_USED))) { - mbErr(mb, 0, _("Macro %%%s defined but not used within scope\n"), - me->name); - /* Only whine once */ - me->flags |= ME_USED; - } - } - macroTableFree(mt); + macroTableFree(&mc->local[mc->level]); mc->level--; mb->args = argvFree(mb->args); mb->me = NULL; @@ -1718,6 +1707,11 @@ static void macroTablePop(macroTable mt, const char * n) /* parting entry */ rpmMacroEntry me = *mep; assert(me); + /* Warn on defined but unused non-automatic, scoped macros */ + if (me->level > 0 && !(me->flags & (ME_AUTO|ME_USED))) { + mbErr(NULL, 0, _("Macro %%%s defined but not used within scope\n"), + me->name); + } /* detach/pop definition */ mt->tab[pos] = me->prev; /* shrink macro table */ diff --git a/tests/rpmmacro.at b/tests/rpmmacro.at index b55e7d03e3..3b44b0b9c7 100644 --- a/tests/rpmmacro.at +++ b/tests/rpmmacro.at @@ -754,6 +754,20 @@ runroot rpm \ ]) AT_CLEANUP +AT_SETUP([%define + %undefine in nested levels 6]) +AT_KEYWORDS([macros define]) +AT_CHECK([ +runroot rpm \ + --define "foo() %{expand:%define bar hello}111" \ + --eval "%foo" +], +[0], +[111 +], +[warning: Macro %bar defined but not used within scope +]) +AT_CLEANUP + AT_SETUP([%define in conditional macro]) AT_KEYWORDS([macros]) AT_CHECK([