diff --git a/rpmio/macro.cc b/rpmio/macro.cc index 71d4354c81..e50503f727 100644 --- a/rpmio/macro.cc +++ b/rpmio/macro.cc @@ -40,6 +40,7 @@ #include "debug.h" using std::string; +using namespace rpm; enum macroFlags_e { ME_NONE = 0, @@ -131,18 +132,6 @@ static void popMacro(rpmMacroContext mc, const char * n); static int loadMacroFile(rpmMacroContext mc, const char * fn); /* =============================================================== */ -static void freeMacros(rpmMacroContext mc) -{ - mc->tab.clear(); -} - -static rpmMacroContext rpmmctxAcquire(rpmMacroContext mc) -{ - if (mc == NULL) - mc = rpmGlobalMacroContext; - return mc; -} - /** * Find entry in macro table. * @param mc macro context @@ -1882,13 +1871,7 @@ static void copyMacros(rpmMacroContext src, rpmMacroContext dst, int level) int rpmExpandMacros(rpmMacroContext mc, const char * sbuf, char ** obuf, int flags) { - string target; - int rc; - - mc = rpmmctxAcquire(mc); - wrlock lock(mc->mutex); - - rc = doExpandMacros(mc, sbuf, flags, &target); + auto [ rc, target ] = macros(mc).expand(sbuf, flags); if (rc) { return -1; @@ -1900,20 +1883,8 @@ int rpmExpandMacros(rpmMacroContext mc, const char * sbuf, char ** obuf, int fla int rpmExpandThisMacro(rpmMacroContext mc, const char *n, ARGV_const_t args, char ** obuf, int flags) { - rpmMacroEntry mep; - string target; - int rc = 1; /* assume failure */ - - mc = rpmmctxAcquire(mc); - wrlock lock(mc->mutex); + auto [ rc, target ] = macros(mc).expand_this(n, args, flags); - mep = findEntry(mc, n, 0, NULL); - if (mep) { - rpmMacroBuf mb = mbCreate(mc, flags); - rc = expandThisMacro(mb, mep, args, flags); - target = mb->buf; - delete mb; - } if (rc) { return -1; } else { @@ -1925,33 +1896,14 @@ int rpmExpandThisMacro(rpmMacroContext mc, const char *n, ARGV_const_t args, ch void rpmDumpMacroTable(rpmMacroContext mc, FILE * fp) { - mc = rpmmctxAcquire(mc); - wrlock lock(mc->mutex); - if (fp == NULL) fp = stderr; - - fprintf(fp, "========================\n"); - for (auto & entry : mc->tab) { - auto const & me = entry.second.top(); - fprintf(fp, "%3d%c %s", me.level, - ((me.flags & ME_USED) ? '=' : ':'), me.name); - if (me.opts && *me.opts) - fprintf(fp, "(%s)", me.opts); - if (me.body && *me.body) - fprintf(fp, "\t%s", me.body); - fprintf(fp, "\n"); - } - fprintf(fp, _("======================== active %zu empty %d\n"), - mc->tab.size(), 0); + macros(mc).dump(fp); } int rpmPushMacroFlags(rpmMacroContext mc, const char * n, const char * o, const char * b, int level, rpmMacroFlags flags) { - mc = rpmmctxAcquire(mc); - wrlock lock(mc->mutex); - pushMacro(mc, n, o, b, level, flags & RPMMACRO_LITERAL ? ME_LITERAL : ME_NONE); - return 0; + return macros(mc).push(n, o, b, level, flags); } int rpmPushMacro(rpmMacroContext mc, @@ -1965,52 +1917,28 @@ int rpmPushMacroAux(rpmMacroContext mc, macroFunc f, void *priv, int nargs, int level, rpmMacroFlags flags) { - mc = rpmmctxAcquire(mc); - wrlock lock(mc->mutex); - pushMacroAny(mc, n, nargs ? "" : NULL, "", f, priv, nargs, - level, flags|ME_FUNC); - return 0; + return macros(mc).push_aux(n, o, f, priv, nargs, level, flags); } int rpmPopMacro(rpmMacroContext mc, const char * n) { - mc = rpmmctxAcquire(mc); - wrlock lock(mc->mutex); - popMacro(mc, n); - return 0; + return macros(mc).pop(n); } int rpmDefineMacro(rpmMacroContext mc, const char * macro, int level) { - int rc; - mc = rpmmctxAcquire(mc); - wrlock lock(mc->mutex); - rc = defineMacro(mc, macro, level); - return rc; + return macros(mc).define(macro, level); } int rpmMacroIsDefined(rpmMacroContext mc, const char *n) { - int defined = 0; - if ((mc = rpmmctxAcquire(mc)) != NULL) { - wrlock lock(mc->mutex); - if (findEntry(mc, n, 0, NULL)) - defined = 1; - } - return defined; + return macros(mc).is_defined(n); } int rpmMacroIsParametric(rpmMacroContext mc, const char *n) { - int parametric = 0; - if ((mc = rpmmctxAcquire(mc)) != NULL) { - wrlock lock(mc->mutex); - rpmMacroEntry mep = findEntry(mc, n, 0, NULL); - if (mep && mep->opts) - parametric = 1; - } - return parametric; + return macros(mc).is_parametric(n); } void *rpmMacroEntryPriv(rpmMacroEntry me) @@ -2021,48 +1949,166 @@ void *rpmMacroEntryPriv(rpmMacroEntry me) void rpmLoadMacros(rpmMacroContext mc, int level) { - rpmMacroContext gmc; if (mc == NULL || mc == rpmGlobalMacroContext) return; - gmc = rpmmctxAcquire(NULL); - mc = rpmmctxAcquire(mc); - wrlock glock(gmc->mutex); - wrlock lock(mc->mutex); - - copyMacros(mc, gmc, level); + macros global(rpmGlobalMacroContext); + macros(mc).copy(global, level); } int rpmLoadMacroFile(rpmMacroContext mc, const char * fn) { - int rc; - - mc = rpmmctxAcquire(mc); - wrlock lock(mc->mutex); - rc = loadMacroFile(mc, fn); - - return rc; + return macros(mc).load(fn); } void rpmInitMacros(rpmMacroContext mc, const char * macrofiles) { - ARGV_t pattern, globs = NULL; - rpmMacroContext climc; - mc = rpmmctxAcquire(mc); - wrlock lock(mc->mutex); + macros(mc).init(macrofiles); +} + +void +rpmFreeMacros(rpmMacroContext mc) +{ + macros(mc).clear(); +} + +char * +rpmExpand(const char *arg, ...) +{ + if (arg == NULL) + return xstrdup(""); + std::string buf; + va_list ap; + + va_start(ap, arg); + for (const char *s = arg; s != NULL; s = va_arg(ap, const char *)) + buf += s; + va_end(ap); + + auto [ ign, res ] = macros().expand(buf); + return xstrdup(res.c_str()); +} + +int +rpmExpandNumeric(const char *arg) +{ + if (arg == NULL) + return 0; + auto [ ign, val ] = macros().expand_numeric(arg); + return val; +} + +void macros::clear() +{ + mc->tab.clear(); +} + +void macros::copy(rpm::macros & dest, int level) +{ + copyMacros(mc, dest.mc, level); +} + +int macros::define(const char *macro, int level) +{ + return defineMacro(mc, macro, level); +} + +void macros::dump(FILE *fp) +{ + fprintf(fp, "========================\n"); + for (auto & entry : mc->tab) { + auto const & me = entry.second.top(); + fprintf(fp, "%3d%c %s", me.level, + ((me.flags & ME_USED) ? '=' : ':'), me.name); + if (me.opts && *me.opts) + fprintf(fp, "(%s)", me.opts); + if (me.body && *me.body) + fprintf(fp, "\t%s", me.body); + fprintf(fp, "\n"); + } + fprintf(fp, _("======================== active %zu empty %d\n"), + mc->tab.size(), 0); +} + +std::pair +macros::expand(const std::string & src, int flags) +{ + string ret; + int rc = doExpandMacros(mc, src, flags, &ret); + return std::make_pair(rc, ret); +} + +std::pair +macros::expand(const std::initializer_list src, int flags) +{ + string buf; + for (auto const & s : src) + buf += s; + return expand(buf, flags); +} + +std::pair +macros::expand_this(const char *n, ARGV_const_t args, int flags) +{ + string target; + int rc = 1; /* assume failure */ + + rpmMacroEntry mep = findEntry(mc, n, 0, NULL); + if (mep) { + rpmMacroBuf mb = mbCreate(mc, flags); + rc = expandThisMacro(mb, mep, args, flags); + target = mb->buf; + delete mb; + } + return std::make_pair(rc, target); +} + +std::pair +macros::expand_numeric(const std::string & src, int flags) +{ + auto [ exrc, s ] = macros().expand(src, flags); + const char *val = s.c_str(); + int rc = 0; + if (!(val && *val != '%')) + rc = 0; + else if (*val == 'Y' || *val == 'y') + rc = 1; + else if (*val == 'N' || *val == 'n') + rc = 0; + else { + char *end; + rc = strtol(val, &end, 0); + if (!(end && *end == '\0')) + rc = 0; + } + return std::make_pair(exrc, rc); +} + +std::pair +macros::expand_numeric(const std::initializer_list & src, int flags) +{ + string buf; + for (auto const & s : src) + buf += s; + return expand_numeric(buf, flags); +} + +void macros::init(const char *macrofiles) +{ /* Define built-in macros */ for (const struct builtins_s *b = builtinmacros; b->name; b++) { pushMacroAny(mc, b->name, b->nargs ? "" : NULL, "", b->func, NULL, b->nargs, RMIL_BUILTIN, b->flags | ME_FUNC); } + ARGV_t pattern, globs = NULL; argvSplit(&globs, macrofiles, ":"); for (pattern = globs; pattern && *pattern; pattern++) { ARGV_t path, files = NULL; - + /* Glob expand the macro file path element, expanding ~ to $HOME. */ if (rpmGlob(*pattern, NULL, &files) != 0) { continue; @@ -2071,7 +2117,7 @@ rpmInitMacros(rpmMacroContext mc, const char * macrofiles) /* Read macros from each file. */ for (path = files; *path; path++) { size_t len = strlen(*path); - if (rpmFileHasSuffix(*path, ".rpmnew") || + if (rpmFileHasSuffix(*path, ".rpmnew") || rpmFileHasSuffix(*path, ".rpmsave") || rpmFileHasSuffix(*path, ".rpmorig") || (len > 0 && !risalnum((*path)[len - 1]))) { @@ -2084,64 +2130,49 @@ rpmInitMacros(rpmMacroContext mc, const char * macrofiles) argvFree(globs); /* Reload cmdline macros */ - climc = rpmmctxAcquire(rpmCLIMacroContext); - wrlock clilock(climc->mutex); - copyMacros(climc, mc, RMIL_CMDLINE); + macros cli(rpmCLIMacroContext); + copyMacros(cli.mc, mc, RMIL_CMDLINE); } -void -rpmFreeMacros(rpmMacroContext mc) +bool macros::is_defined(const char *n) { - mc = rpmmctxAcquire(mc); - wrlock lock(mc->mutex); - freeMacros(mc); + return (findEntry(mc, n, 0, NULL) != NULL); } -char * -rpmExpand(const char *arg, ...) +bool macros::is_parametric(const char *n) { - if (arg == NULL) - return xstrdup(""); - - std::string buf, ret; - va_list ap; - - va_start(ap, arg); - for (const char *s = arg; s != NULL; s = va_arg(ap, const char *)) - buf += s; - va_end(ap); - - rpmMacroContext mc = rpmmctxAcquire(NULL); - wrlock lock(mc->mutex); - - (void) doExpandMacros(mc, buf, 0, &ret); - - return xstrdup(ret.c_str()); + rpmMacroEntry mep = findEntry(mc, n, 0, NULL); + return (mep && mep->opts); +} +int macros::load(const char *fn) +{ + return loadMacroFile(mc, fn); } -int -rpmExpandNumeric(const char *arg) +int macros::pop(const char *n) { - char *val; - int rc; + popMacro(mc, n); + return 0; +} - if (arg == NULL) - return 0; +int macros::push(const char *n, const char *o, const char *b, + int level, int flags) +{ + pushMacro(mc, n, o, b, level, flags & RPMMACRO_LITERAL ? ME_LITERAL : ME_NONE); + return 0; +} - val = rpmExpand(arg, NULL); - if (!(val && *val != '%')) - rc = 0; - else if (*val == 'Y' || *val == 'y') - rc = 1; - else if (*val == 'N' || *val == 'n') - rc = 0; - else { - char *end; - rc = strtol(val, &end, 0); - if (!(end && *end == '\0')) - rc = 0; - } - free(val); +int macros::push_aux(const char *n, const char *o, + macroFunc f, void *priv, int nargs, + int level, int flags) +{ + pushMacroAny(mc, n, nargs ? "" : NULL, "", f, priv, nargs, + level, flags|ME_FUNC); + return 0; +} - return rc; +macros::macros(rpmMacroContext mctx) : + mc(mctx ? mctx : rpmGlobalMacroContext), lock(mc->mutex) +{ } + diff --git a/rpmio/rpmmacro_internal.hh b/rpmio/rpmmacro_internal.hh index 9fc1ee6f34..3acffeb96a 100644 --- a/rpmio/rpmmacro_internal.hh +++ b/rpmio/rpmmacro_internal.hh @@ -1,6 +1,12 @@ #ifndef _H_MACRO_INTERNAL #define _H_MACRO_INTERNAL +#include +#include +#include +#include + +#include #include #include @@ -30,4 +36,57 @@ void splitQuoted(ARGV_t *av, const char * str, const char * seps); RPM_GNUC_INTERNAL char *unsplitQuoted(ARGV_const_t av, const char *sep); +namespace rpm { + +/* + * This is basically a RAII proxy C++ native macro interface, prefer it + * over the public C API for all internal needs. + * The constructor grabs a lock on the underlying macro context and + * automatically unlocks when the handle goes out of scope. This allows + * multiple macro operations on a single lock/unlock cycle, while also + * making sure locking and unlocking are not forgotten. Use as local + * variable only and in the smallest possible scope to get the job + * done, mind what other code gets called while holding the handle. + * + * Generally the method names and arguments map to the C API in obvious ways, + * exceptions noted below. + */ +class macros { +public: + /* Clear all macro definitions in this context, like rpmFreeMacros() */ + void clear(); + /* Copy all macros from this context to another one */ + void copy(rpm::macros & dest, int level); + int define(const char *macro, int level); + void dump(FILE *fp = stderr); + /* Expand macros to a C++ string, with a return code (rc, string) */ + std::pair expand(const std::string & src, int flags = 0); + std::pair expand(const std::initializer_list src, + int flags = 0); + std::pair expand_this(const char *n, ARGV_const_t args, + int flags = 0); + /* Expand macros to numeric value, with a return code (rc, number) */ + std::pair expand_numeric(const std::string & src, int flags = 0); + std::pair expand_numeric(const std::initializer_list & src, + int flags = 0); + void init(const char *macrofiles); + bool is_defined(const char *n); + bool is_parametric(const char *n); + int load(const char *fn); + int pop(const char *n); + int push(const char *n, const char *o, const char *b, + int level, int flags = RPMMACRO_DEFAULT); + int push_aux(const char *n, const char *o, + macroFunc f, void *priv, int nargs, + int level, int flags = RPMMACRO_DEFAULT); + + macros(rpmMacroContext mctx = rpmGlobalMacroContext); + ~macros() = default; +private: + rpmMacroContext mc; + std::lock_guard lock; +}; + +}; /* namespace rpm */ + #endif /* _H_ MACRO_INTERNAL */