[Rpm-maint] First experiments with complex dependencies
Michael Schroeder
mls at suse.de
Mon Aug 4 16:47:37 UTC 2014
Hi rpm-maint,
attached is a hackish version that implements complex dependencies
for rpm. It's just meant as starting point for a real implementation,
so don't be too cruel on the code. It seems to kind of work,
although I haven't done excessive testing.
Complex dependencies are encoded as simple string in the name
field, and with RPMSENSE_COMPLEX set. The patch insists on all
complex deps starting with '(' and ending with ')', so that there
can be no compatibility issue with old dependencies.
Word parsing in a complex dependency is slightly different: a ')'
with no matching '(' terminates the word. That's so that people
can write "Requires: (A OR B)" and don't need extra spaces.
I implemented the AND, OR, and IF operator, multiple AND and OR
ops may be chained (but you may not mix ops, e.g. (A AND B AND C)
is ok, but (A AND B OR C) needs extra parens).
I'm not very proud of having three different parsers for complex
deps (in rpmds.c, parseReqs.c, and rpmdb.c), this is something
that really should be unified.
Cheers,
Michael.
--
Michael Schroeder mls at suse.de
SUSE LINUX Products GmbH, GF Jeff Hawn, HRB 16746 AG Nuernberg
main(_){while(_=~getchar())putchar(~_-1/(~(_|32)/13*2-11)*13);}
-------------- next part --------------
diff --git a/build/parseReqs.c b/build/parseReqs.c
index 1427111..e63c974 100644
--- a/build/parseReqs.c
+++ b/build/parseReqs.c
@@ -32,8 +32,20 @@ const char * token;
{ NULL, 0 },
};
+static struct OpComp {
+const char * token;
+ int op;
+ int chainable;
+} const OpComparisons[] = {
+ { "AND", 1, 1 },
+ { "OR", 2, 1 },
+ { "IF", 3, 0 },
+ { NULL, 0, 0 },
+};
+
#define SKIPWHITE(_x) {while(*(_x) && (risspace(*_x) || *(_x) == ',')) (_x)++;}
#define SKIPNONWHITE(_x){while(*(_x) &&!(risspace(*_x) || *(_x) == ',')) (_x)++;}
+#define SKIPNONWHITEX(_x){int bl = 0; while(*(_x) &&!(risspace(*_x) || *(_x) == ',' || (*(_x) == ')' && bl-- <= 0))) if (*(_x)++ == '(') bl++;}
static int checkSep(const char *s, char c, char **emsg)
{
@@ -45,6 +57,209 @@ static int checkSep(const char *s, char c, char **emsg)
return 0;
}
+struct ComplexDep {
+ /* simple literal */
+ char *N;
+ char *EVR;
+ rpmsenseFlags Flags;
+ /* complex literal */
+ struct ComplexDep *lit;
+
+ int op;
+ struct ComplexDep *oparg;
+};
+
+static void freeComplexDep(struct ComplexDep *cd)
+{
+ _free(cd->N);
+ _free(cd->EVR);
+ if (cd->lit)
+ freeComplexDep(cd->lit);
+ if (cd->oparg)
+ freeComplexDep(cd->oparg);
+ free(cd);
+}
+
+static char *strjoin(char *s, char *s2)
+{
+ char *ns = xmalloc(strlen(s) + strlen(s2) + 1);
+ strcpy(ns, s);
+ strcat(ns, s2);
+ free(s);
+ return ns;
+}
+
+static char *formatComplexDep(struct ComplexDep *cd)
+{
+ int oldop = 0;
+ char *s = strdup("(");
+ while (cd) {
+ if (cd->lit) {
+ char *ns = formatComplexDep(cd->lit);
+ s = strjoin(s, ns);
+ free(ns);
+ } else {
+ s = strjoin(s, cd->N);
+ if (cd->EVR) {
+ s = strjoin(s, " ");
+ if (cd->Flags & RPMSENSE_LESS)
+ s = strjoin(s, "<");
+ if (cd->Flags & RPMSENSE_EQUAL)
+ s = strjoin(s, "=");
+ if (cd->Flags & RPMSENSE_GREATER)
+ s = strjoin(s, ">");
+ s = strjoin(s, " ");
+ s = strjoin(s, cd->EVR);
+ }
+ }
+ if (!cd->op)
+ break;
+ if (cd->op == 1)
+ s = strjoin(s, " AND ");
+ if (cd->op == 2)
+ s = strjoin(s, " OR ");
+ if (cd->op == 3)
+ s = strjoin(s, " IF ");
+ if (!oldop || (oldop != 3 && cd->op == oldop)) {
+ oldop = cd->op;
+ cd = cd->oparg;
+ } else {
+ char *ns = formatComplexDep(cd->oparg);
+ s = strjoin(s, ns);
+ free(ns);
+ cd = 0;
+ }
+ }
+ s = strjoin(s, ")");
+ return s;
+}
+
+struct ComplexDep *parseComplexDep(rpmSpec spec, const char **rp, char **emsg, int oldop)
+{
+ struct ComplexDep *cd;
+ const char *r, *re, *v, *ve;
+
+ cd = xmalloc(sizeof(*cd));
+ memset(cd, 0, sizeof(*cd));
+
+ r = *rp;
+ SKIPWHITE(r);
+ if (*r == '(') {
+ r++;
+ cd->lit = parseComplexDep(spec, &r, emsg, 0);
+ if (!cd->lit) {
+ freeComplexDep(cd);
+ return 0;
+ }
+ } else {
+ re = r;
+ SKIPNONWHITEX(re);
+ cd->N = xmalloc((re-r) + 1);
+ rstrlcpy(cd->N, r, (re-r) + 1);
+
+ /* Parse EVR */
+ v = re;
+ SKIPWHITE(v);
+ ve = v;
+ SKIPNONWHITE(ve);
+
+ re = v; /* ==> next token (if no EVR found) starts here */
+
+ /* Check for possible logical operator */
+ if (ve > v) {
+ const struct ReqComp *rc;
+ for (rc = ReqComparisons; rc->token != NULL; rc++) {
+ if ((ve-v) != strlen(rc->token) || !rstreqn(v, rc->token, (ve-v)))
+ continue;
+
+ if (r[0] == '/') {
+ rasprintf(emsg, _("Versioned file name not permitted"));
+ freeComplexDep(cd);
+ return 0;
+ }
+
+ cd->Flags |= rc->sense;
+
+ /* now parse EVR */
+ v = ve;
+ SKIPWHITE(v);
+ ve = v;
+ SKIPNONWHITEX(ve);
+ break;
+ }
+ }
+
+ if (cd->Flags & RPMSENSE_SENSEMASK) {
+ if (*v == '\0' || ve == v) {
+ rasprintf(emsg, _("Version required"));
+ freeComplexDep(cd);
+ return 0;
+ }
+ cd->EVR = xmalloc((ve-v) + 1);
+ rstrlcpy(cd->EVR, v, (ve-v) + 1);
+ if (rpmCharCheck(spec, cd->EVR, ve-v, ".-_+:%{}~")) {
+ freeComplexDep(cd);
+ return 0;
+ }
+
+ /* While ':' and '-' are valid, only one of each is valid. */
+ if (checkSep(cd->EVR, '-', emsg) || checkSep(cd->EVR, ':', emsg)) {
+ freeComplexDep(cd);
+ return 0;
+ }
+
+ re = ve; /* ==> next token after EVR string starts here */
+ }
+ r = re;
+ }
+ SKIPWHITE(r);
+ if (*r && *r != ')') {
+ const struct OpComp *oc;
+ v = r;
+ ve = v;
+ SKIPNONWHITE(ve);
+ for (oc = OpComparisons; oc->token != NULL; oc++) {
+ if ((ve-v) != strlen(oc->token) || !rstreqn(v, oc->token, (ve-v)))
+ continue;
+ break;
+ }
+ if (oc->token == NULL) {
+ rasprintf(emsg, "unknown op '%.*s'", (int)(ve - v), v);
+ freeComplexDep(cd);
+ return 0;
+ }
+ if (oldop && oc->op != oldop) {
+ rasprintf(emsg, "cannot chain different ops");
+ freeComplexDep(cd);
+ return 0;
+ }
+ if (oldop && !oc->chainable) {
+ rasprintf(emsg, "cannot chain op");
+ freeComplexDep(cd);
+ return 0;
+ }
+ cd->op = oc->op;
+ r = ve;
+ cd->oparg = parseComplexDep(spec, &r, emsg, cd->op);
+ if (!cd->oparg) {
+ freeComplexDep(cd);
+ return 0;
+ }
+ }
+ SKIPWHITE(r);
+ if (!cd->op) {
+ if (*r != ')') {
+ rasprintf(emsg, "unterminated");
+ freeComplexDep(cd);
+ return 0;
+ }
+ r++;
+ }
+ *rp = r;
+ return cd;
+}
+
+
rpmRC parseRCPOT(rpmSpec spec, Package pkg, const char *field, rpmTagVal tagN,
int index, rpmsenseFlags tagflags)
{
@@ -123,6 +338,23 @@ rpmRC parseRCPOT(rpmSpec spec, Package pkg, const char *field, rpmTagVal tagN,
Flags = (tagflags & ~RPMSENSE_SENSEMASK);
+ if (r[0] == '(') {
+ struct ComplexDep *cd;
+ char *cdf;
+ r++;
+ cd = parseComplexDep(spec, &r, &emsg, 0);
+ if (!cd) {
+ goto exit;
+ }
+ re = r;
+ cdf = formatComplexDep(cd);
+ if (addReqProv(pkg, nametag, cdf, NULL, Flags | RPMSENSE_COMPLEX, index)) {
+ rasprintf(&emsg, _("invalid dependency"));
+ goto exit;
+ }
+ _free(cdf);
+ continue;
+ }
/*
* Tokens must begin with alphanumeric, _, or /, but we don't know
* the spec's encoding so we only check what we can: plain ascii.
diff --git a/lib/depends.c b/lib/depends.c
index 7fd3986..b8a6bf1 100644
--- a/lib/depends.c
+++ b/lib/depends.c
@@ -619,6 +619,42 @@ retry:
if (!adding && isInstallPreReq(dsflags) && !isErasePreReq(dsflags))
goto exit;
+ if (dsflags & RPMSENSE_COMPLEX) {
+ rpmds ds1, ds2;
+ char *emsg = 0;
+ int op = rpmdsParseCplxDep(dep, &ds1, &ds2, &emsg);
+ if (op == RPMCPLXDEPOP_ERROR) {
+ if (emsg) {
+ rpmdsNotify(dep, emsg, 1);
+ free(emsg);
+ }
+ goto unsatisfied;
+ }
+ /* an IF on a conflict is actually just an AND */
+ if (op == RPMCPLXDEPOP_IF && rpmdsTagN(dep) == RPMTAG_CONFLICTNAME)
+ op = RPMCPLXDEPOP_AND;
+ if (op == RPMCPLXDEPOP_IF) {
+ rc = unsatisfiedDepend(ts, dcache, ds2);
+ if (rc) {
+ ds1 = rpmdsFree(ds1);
+ ds2 = rpmdsFree(ds2);
+ rc = 0;
+ rpmdsNotify(dep, "(complex)", 0);
+ goto exit;
+ }
+ }
+ rc = unsatisfiedDepend(ts, dcache, ds1);
+ if ((rc && op == RPMCPLXDEPOP_OR) || (!rc && op == RPMCPLXDEPOP_AND)) {
+ rc = unsatisfiedDepend(ts, dcache, ds2);
+ }
+ ds1 = rpmdsFree(ds1);
+ ds2 = rpmdsFree(ds2);
+ if (rc)
+ goto unsatisfied;
+ rpmdsNotify(dep, "(complex)", 0);
+ goto exit;
+ }
+
/* Pretrans dependencies can't be satisfied by added packages. */
if (!(dsflags & RPMSENSE_PRETRANS)) {
rpmte *matches = rpmalAllSatisfiesDepend(tsmem->addedPackages, dep);
@@ -670,7 +706,10 @@ unsatisfied:
} else {
/* dependency is unsatisfied */
rc = 1;
- rpmdsNotify(dep, NULL, rc);
+ if (dsflags & RPMSENSE_COMPLEX)
+ rpmdsNotify(dep, "(complex)", rc);
+ else
+ rpmdsNotify(dep, NULL, rc);
}
exit:
@@ -689,7 +728,7 @@ static void checkDS(rpmts ts, depCache dcache, rpmte te,
ds = rpmdsInit(ds);
while (rpmdsNext(ds) >= 0) {
/* Filter out dependencies that came along for the ride. */
- if (depName != NULL && !rstreq(depName, rpmdsN(ds)))
+ if (depName != NULL && !rstreq(depName, rpmdsN(ds)) && !(rpmdsFlags(ds) & RPMSENSE_COMPLEX))
continue;
/* Ignore colored dependencies not in our rainbow. */
diff --git a/lib/rpmdb.c b/lib/rpmdb.c
index b6d3247..295ec7f 100644
--- a/lib/rpmdb.c
+++ b/lib/rpmdb.c
@@ -2032,6 +2032,74 @@ int rpmdbRemove(rpmdb db, unsigned int hdrNum)
return 0;
}
+static const char *collectComplexDep(const char *p, ARGV_t *argvp)
+{
+ p++;
+ for (;;) {
+ while (risspace(*p))
+ p++;
+ if (!*p)
+ return p;
+ if (*p == '(') {
+ p = collectComplexDep(p, argvp);
+ if (*p != ')')
+ return p;
+ p++;
+ } else if (*p == ')') {
+ return p;
+ } else {
+ const char *ps = p;
+ int bl = 0;
+ while ((*p) && !(risspace(*p) || (*p == ')' && bl-- <= 0)))
+ if (*p++ == '(')
+ bl++;
+ if (p > ps) {
+ char *name = rstrdup(ps);
+ name[p - ps] = 0;
+ argvAdd(argvp, name);
+ free(name);
+ }
+ while (risspace(*p))
+ p++;
+ if (*p == '>' || *p == '<' || *p == '=') {
+ while (*p == '>' || *p == '<' || *p == '=')
+ p++;
+ while (risspace(*p))
+ p++;
+ while ((*p) && !(risspace(*p) || (*p == ')' && bl-- <= 0)))
+ if (*p++ == '(')
+ bl++;
+ }
+ while (risspace(*p))
+ p++;
+ if (*p && *p != ')') {
+ while (*p && !risspace(*p) && *p != ')')
+ p++;
+ }
+ }
+ }
+}
+
+static rpmRC updatecplxdep(dbiCursor dbc, const char *str,
+ struct dbiIndexItem_s *rec,
+ idxfunc idxupdate)
+{
+ int n, i, rc = 0;
+ ARGV_t argv = argvNew();
+ collectComplexDep(str, &argv);
+ n = argvCount(argv);
+ if (n) {
+ argvSort(argv, NULL);
+ for (i = 0; i < n; i++) {
+ if (i && !strcmp(argv[i - 1], argv[i]))
+ continue; /* ignore dups */
+ rc += idxupdate(dbc, argv[i], strlen(argv[i]), rec);
+ }
+ }
+ argvFree(argv);
+ return rc;
+}
+
static rpmRC tag2index(dbiIndex dbi, rpmTagVal rpmtag,
unsigned int hdrNum, Header h,
idxfunc idxupdate)
@@ -2098,6 +2166,13 @@ static rpmRC tag2index(dbiIndex dbi, rpmTagVal rpmtag,
continue;
rc += idxupdate(dbc, key, keylen, &rec);
+
+ if ((rpmtag == RPMTAG_REQUIRENAME || rpmtag == RPMTAG_CONFLICTNAME) && *(char *)key == '(') {
+ if (rpmtdType(&tagdata) == RPM_STRING_ARRAY_TYPE) {
+ const char *str = rpmtdGetString(&tagdata);
+ rc += updatecplxdep(dbc, str, &rec, idxupdate);
+ }
+ }
}
dbiCursorFree(dbc);
diff --git a/lib/rpmds.c b/lib/rpmds.c
index e1a6315..94967f2 100644
--- a/lib/rpmds.c
+++ b/lib/rpmds.c
@@ -1251,10 +1251,252 @@ rpmFlags rpmSanitizeDSFlags(rpmTagVal tagN, rpmFlags Flags)
case RPMTAG_SUPPLEMENTNAME:
case RPMTAG_ENHANCENAME:
case RPMTAG_REQUIRENAME:
- extra = Flags & _ALL_REQUIRES_MASK;
+ extra = Flags & (_ALL_REQUIRES_MASK | RPMSENSE_COMPLEX);
+ break;
+ case RPMTAG_CONFLICTNAME:
+ extra = Flags & RPMSENSE_COMPLEX;
break;
default:
break;
}
return (Flags & RPMSENSE_SENSEMASK) | extra;
}
+
+static const char *skipComplexDep(const char *p)
+{
+ p++;
+ for (;;) {
+ while (risspace(*p))
+ p++;
+ if (!*p)
+ return p;
+ if (*p == '(') {
+ p = skipComplexDep(p);
+ if (*p != ')')
+ return p;
+ p++;
+ } else if (*p == ')') {
+ return p;
+ } else {
+ int bl = 0;
+ while ((*p) && !(risspace(*p) || (*p == ')' && bl-- <= 0)))
+ if (*p++ == '(')
+ bl++;
+ }
+ }
+}
+
+static const char *makeSimpleDep(rpmds ods, const char *dstr, rpmds *dsp)
+{
+ const char *n, *ne, *e = 0, *ee = 0;
+ int flags = 0;
+ rpmds ds;
+ const char *p = dstr;
+ int bl;
+
+ bl = 0;
+ while ((*p) && !(risspace(*p) || (*p == ')' && bl-- <= 0)))
+ if (*p++ == '(')
+ bl++;
+ n = dstr;
+ ne = p;
+ while (risspace(*p))
+ p++;
+ for (;; p++) {
+ if (*p == '>')
+ flags |= RPMSENSE_GREATER;
+ else if (*p == '=')
+ flags |= RPMSENSE_EQUAL;
+ else if (*p == '<')
+ flags |= RPMSENSE_LESS;
+ else
+ break;
+ }
+ if (flags) {
+ while (risspace(*p))
+ p++;
+ e = p;
+ while ((*p) && !(risspace(*p) || (*p == ')' && bl-- <= 0)))
+ if (*p++ == '(')
+ bl++;
+ ee = p;
+ }
+ flags |= rpmdsFlags(ods) & ~(RPMSENSE_SENSEMASK | RPMSENSE_COMPLEX);
+ ds = singleDS(ods->pool, ods->tagN, 0, 0, flags, 0, 0);
+ if (ds) {
+ if (!e)
+ e = ee = n;
+ ds->N[0] = rpmstrPoolIdn(ds->pool, n, ne - n, 1);
+ ds->EVR[0] = rpmstrPoolIdn(ds->pool, e, ee - e, 1);
+ if (ds->pool != ods->pool)
+ rpmstrPoolFreeze(ds->pool, 0);
+ }
+ *dsp = ds;
+ return p;
+}
+
+
+rpmCplxDepOp rpmdsParseCplxDep(rpmds dep, rpmds *leftds, rpmds *rightds, char **emsg)
+{
+ rpmCplxDepOp op = 0, chainop = 0;
+ const char *chainstart;
+ const char *dstr = rpmdsN(dep);
+ const char *p = dstr;
+ rpmsenseFlags flags = rpmdsFlags(dep);
+ rpmds ds;
+ const char *pe;
+
+ *leftds = *rightds = 0;
+ if (*p++ != '(') {
+ if (emsg)
+ rasprintf(emsg, "Complex dependency does not start with '('");
+ return RPMCPLXDEPOP_ERROR;
+ }
+ while (risspace(*p))
+ p++;
+ if (*p == '(') {
+ /* sub-dependency */
+ pe = skipComplexDep(p);
+ if (*pe != ')') {
+ if (emsg)
+ rasprintf(emsg, "Unterminated complex dependency: '%s'", p);
+ return RPMCPLXDEPOP_ERROR;
+ }
+ pe++;
+ ds = singleDS(dep->pool, dep->tagN, 0, 0, flags, 0, 0);
+ if (ds) {
+ ds->N[0] = rpmstrPoolIdn(ds->pool, p, pe - p, 1);
+ ds->EVR[0] = rpmstrPoolId(ds->pool, "", 1);
+ }
+ *leftds = ds;
+ p = pe;
+ } else if (*p == ')') {
+ if (emsg)
+ rasprintf(emsg, "Empty complex dependency");
+ return RPMCPLXDEPOP_ERROR;
+ } else {
+ p = makeSimpleDep(dep, p, leftds);
+ }
+ while (risspace(*p))
+ p++;
+ if (!*p) {
+ if (emsg)
+ rasprintf(emsg, "Complex dependency does not end with ')'");
+ *leftds = rpmdsFree(*leftds);
+ return RPMCPLXDEPOP_ERROR;
+ }
+ if (*p == ')') {
+ if (p[1]) {
+ if (emsg)
+ rasprintf(emsg, "Junk at end of complex dependency");
+ *leftds = rpmdsFree(*leftds);
+ return RPMCPLXDEPOP_ERROR;
+ }
+ return RPMCPLXDEPOP_SINGLE;
+ }
+ for (;;) {
+ pe = p;
+ while (*pe && !risspace(*pe) && *pe != ')')
+ pe++;
+ op = 0;
+ if (pe - p == 3 && !strncmp(p, "AND", 3))
+ op = RPMCPLXDEPOP_AND;
+ if (pe - p == 2 && !strncmp(p, "OR", 2))
+ op = RPMCPLXDEPOP_OR;
+ if (pe - p == 2 && !strncmp(p, "IF", 2))
+ op = RPMCPLXDEPOP_IF;
+ if (!op) {
+ if (emsg)
+ rasprintf(emsg, "Unknown dependency op '%.*s'", (int)(pe - p), p);
+ *leftds = rpmdsFree(*leftds);
+ return RPMCPLXDEPOP_ERROR;
+ }
+ p = pe;
+ if (chainop) {
+ char *chainstr;
+ *rightds = rpmdsFree(*rightds);
+ if (chainop != op) {
+ *leftds = rpmdsFree(*leftds);
+ if (emsg)
+ rasprintf(emsg, "Cannot chain different ops");
+ return RPMCPLXDEPOP_ERROR;
+ }
+ if (op == RPMCPLXDEPOP_IF) {
+ *leftds = rpmdsFree(*leftds);
+ if (emsg)
+ rasprintf(emsg, "Cannot chain IF ops");
+ return RPMCPLXDEPOP_ERROR;
+ }
+ chainstr = strdup(chainstart - 1);
+ *chainstr = '(';
+ p = chainstr;
+ pe = skipComplexDep(p);
+ if (*pe)
+ pe++;
+ ds = singleDS(dep->pool, dep->tagN, 0, 0, flags, 0, 0);
+ if (ds) {
+ ds->N[0] = rpmstrPoolIdn(ds->pool, p, pe - p, 1);
+ ds->EVR[0] = rpmstrPoolId(ds->pool, "", 1);
+ }
+ *rightds = ds;
+ free(chainstr);
+ return chainop;
+ }
+ while (risspace(*p))
+ p++;
+ if (!chainop)
+ chainstart = p;
+ if (*p == '(') {
+ /* sub-dependency */
+ pe = skipComplexDep(p);
+ if (*pe != ')') {
+ if (emsg)
+ rasprintf(emsg, "Unterminated complex dependency: '%s'", p);
+ return RPMCPLXDEPOP_ERROR;
+ }
+ pe++;
+ ds = singleDS(dep->pool, dep->tagN, 0, 0, flags, 0, 0);
+ if (ds) {
+ ds->N[0] = rpmstrPoolIdn(ds->pool, p, pe - p, 1);
+ ds->EVR[0] = rpmstrPoolId(ds->pool, "", 1);
+ }
+ *rightds = ds;
+ p = pe;
+ } else if (*p == ')') {
+ if (emsg)
+ rasprintf(emsg, "Missing argument after complex op");
+ return RPMCPLXDEPOP_ERROR;
+ } else {
+ p = makeSimpleDep(dep, p, rightds);
+ }
+ while (risspace(*p))
+ p++;
+ if (!*p || *p == ')')
+ break;
+ /* chain */
+ chainop = op;
+ }
+ if (!*p) {
+ if (emsg)
+ rasprintf(emsg, "Complex dependency does not end with ')'");
+ *leftds = rpmdsFree(*leftds);
+ *rightds = rpmdsFree(*rightds);
+ return RPMCPLXDEPOP_ERROR;
+ }
+ if (*p != ')') {
+ if (emsg)
+ rasprintf(emsg, "Complex dependency does not end with ')'");
+ *leftds = rpmdsFree(*leftds);
+ *rightds = rpmdsFree(*rightds);
+ return RPMCPLXDEPOP_ERROR;
+ }
+ if (p[1]) {
+ if (emsg)
+ rasprintf(emsg, "Junk at end of complex dependency");
+ *leftds = rpmdsFree(*leftds);
+ *rightds = rpmdsFree(*rightds);
+ return RPMCPLXDEPOP_ERROR;
+ }
+ return op;
+}
+
diff --git a/lib/rpmds.h b/lib/rpmds.h
index 9b7c908..a30d08e 100644
--- a/lib/rpmds.h
+++ b/lib/rpmds.h
@@ -49,7 +49,8 @@ enum rpmsenseFlags_e {
RPMSENSE_TRIGGERPREIN = (1 << 25), /*!< %triggerprein dependency. */
RPMSENSE_KEYRING = (1 << 26),
/* bit 27 unused */
- RPMSENSE_CONFIG = (1 << 28)
+ RPMSENSE_CONFIG = (1 << 28),
+ RPMSENSE_COMPLEX = (1 << 29)
};
typedef rpmFlags rpmsenseFlags;
@@ -87,6 +88,14 @@ typedef rpmFlags rpmsenseFlags;
+typedef enum rpmCplxDepOp_e {
+ RPMCPLXDEPOP_ERROR = 0,
+ RPMCPLXDEPOP_SINGLE = 1,
+ RPMCPLXDEPOP_AND = 2,
+ RPMCPLXDEPOP_OR = 3,
+ RPMCPLXDEPOP_IF = 4
+} rpmCplxDepOp;
+
/** \ingroup rpmds
* Return only those flags allowed for given type of dependencies
* @param tagN type of dependency
@@ -454,6 +463,8 @@ rpmds rpmdsSinglePoolTix(rpmstrPool pool, rpmTagVal tagN,
*/
int rpmdsRpmlibPool(rpmstrPool pool, rpmds * dsp, const void * tblp);
+rpmCplxDepOp rpmdsParseCplxDep(rpmds dep, rpmds *leftds, rpmds *rightds, char **emsg);
+
#ifdef __cplusplus
}
#endif
More information about the Rpm-maint
mailing list