On Mon, Sep 08, 2014 at 04:51:12PM +0200, Michael Schroeder wrote: > Hi Panu et al, > > attached is an updated version of my rich dependencies patch. > I cleanup up the code a bit, now we have only one generic parser > instead of three specialized ones, and we use a callback function > to do the needed work.
New version attached: some bugs fixed plus the ordering code now also understands rich deps. Cheers, Michael. -- Michael Schroeder m...@suse.de SUSE LINUX Products GmbH, GF Jeff Hawn, HRB 16746 AG Nuernberg main(_){while(_=~getchar())putchar(~_-1/(~(_|32)/13*2-11)*13);}
diff --git a/build/pack.c b/build/pack.c index 74471d9..fee89b5 100644 --- a/build/pack.c +++ b/build/pack.c @@ -265,6 +265,29 @@ static int haveTildeDep(Header h) return 0; } +static int depContainsRich(Header h, rpmTagVal tagFlags) +{ + struct rpmtd_s flags; + rpm_flag_t *flag = NULL; + + if (headerGet(h, tagFlags, &flags, HEADERGET_MINMEM)) { + while ((flag = rpmtdNextUint32(&flags)) != NULL) + if (*flag & RPMSENSE_RICH) + break; + rpmtdFreeData(&flags); + } + return flag != NULL; +} + +static int haveRichDep(Header h) +{ + if (depContainsRich(h, RPMTAG_REQUIREFLAGS)) + return 1; + if (depContainsRich(h, RPMTAG_CONFLICTFLAGS)) + return 1; + return 0; +} + static rpm_loff_t estimateCpioSize(Package pkg) { rpmfi fi; @@ -438,6 +461,10 @@ static rpmRC writeRPM(Package pkg, unsigned char ** pkgidp, if (haveTildeDep(pkg->header)) (void) rpmlibNeedsFeature(pkg, "TildeInVersions", "4.10.0-1"); + /* check if the package has a rich dependency */ + if (haveRichDep(pkg->header)) + (void) rpmlibNeedsFeature(pkg, "RichDependencies", "4.12.0-1"); + /* All dependencies added finally, write them into the header */ for (int i = 0; i < PACKAGE_NUM_DEPS; i++) { /* Nuke any previously added dependencies from the header */ diff --git a/build/parseReqs.c b/build/parseReqs.c index 37ee1fc..eaf10fb 100644 --- a/build/parseReqs.c +++ b/build/parseReqs.c @@ -68,6 +68,70 @@ static rpmRC checkDep(rpmSpec spec, char *N, char *EVR, char **emsg) return RPMRC_OK; } +struct parseRCPOTRichData { + rpmSpec spec; + StringBuf sb; + int no_if; + int stacked_if; +}; + +/* Callback for the rich dependency parser. We use this to do check for invalid + * characters and to build a normailzed version of the dependency */ +static rpmRC parseRCPOTRichCB(void *cbdata, int type, + const char *n, int nl, const char *e, int el, rpmsenseFlags sense, + rpmrichOp op, char **emsg) { + struct parseRCPOTRichData *data = cbdata; + StringBuf sb = data->sb; + rpmRC rc = RPMRC_OK; + + if (type == RPMRICH_PARSE_ENTER) { + appendStringBuf(sb, "("); + } else if (type == RPMRICH_PARSE_LEAVE) { + appendStringBuf(sb, ")"); + if (op == RPMRICHOP_IF) + data->stacked_if--; + } else if (type == RPMRICH_PARSE_SIMPLE) { + char *N = xmalloc(nl + 1); + char *EVR = NULL; + rstrlcpy(N, n, nl + 1); + appendStringBuf(sb, N); + if (el) { + char rel[6], *rp = rel; + EVR = xmalloc(el + 1); + rstrlcpy(EVR, e, el + 1); + *rp++ = ' '; + if (sense & RPMSENSE_LESS) + *rp++ = '<'; + if (sense & RPMSENSE_GREATER) + *rp++ = '>'; + if (sense & RPMSENSE_EQUAL) + *rp++ = '='; + *rp++ = ' '; + *rp = 0; + appendStringBuf(sb, rel); + appendStringBuf(sb, EVR); + } + rc = checkDep(data->spec, N, EVR, emsg); + _free(N); + _free(EVR); + } else if (type == RPMRICH_PARSE_OP) { + if (op == RPMRICHOP_IF) { + if (data->no_if) { + rasprintf(emsg, "IF not allowed in conflicts dependencies"); + rc = RPMRC_FAIL; + } else if (data->stacked_if) { + rasprintf(emsg, "Stacked IF is not supported "); + rc = RPMRC_FAIL; + } + data->stacked_if++; + } + appendStringBuf(sb, " "); + appendStringBuf(sb, rpmrichOpStr(op)); + appendStringBuf(sb, " "); + } + return rc; +} + rpmRC parseRCPOT(rpmSpec spec, Package pkg, const char *field, rpmTagVal tagN, int index, rpmsenseFlags tagflags) { @@ -146,6 +210,32 @@ rpmRC parseRCPOT(rpmSpec spec, Package pkg, const char *field, rpmTagVal tagN, Flags = (tagflags & ~RPMSENSE_SENSEMASK); + if (r[0] == '(') { + struct parseRCPOTRichData data; + if (nametag != RPMTAG_REQUIRENAME && nametag != RPMTAG_CONFLICTNAME && + nametag != RPMTAG_RECOMMENDNAME && nametag != RPMTAG_SUPPLEMENTNAME && + nametag != RPMTAG_SUGGESTNAME && nametag != RPMTAG_ENHANCENAME) { + rasprintf(&emsg, _("No rich dependencies allowed for this type")); + goto exit; + } + data.spec = spec; + data.sb = newStringBuf(); + data.no_if = (nametag == RPMTAG_CONFLICTNAME); + data.stacked_if = 0; + if (rpmrichParse(&r, &emsg, parseRCPOTRichCB, &data) != RPMRC_OK) { + freeStringBuf(data.sb); + goto exit; + } + if (addReqProv(pkg, nametag, getStringBuf(data.sb), NULL, Flags | RPMSENSE_RICH, index)) { + rasprintf(&emsg, _("invalid dependency")); + freeStringBuf(data.sb); + goto exit; + } + freeStringBuf(data.sb); + re = r; + continue; + } + re = r; SKIPNONWHITE(re); N = xmalloc((re-r) + 1); diff --git a/lib/depends.c b/lib/depends.c index 2ed0d99..438c178 100644 --- a/lib/depends.c +++ b/lib/depends.c @@ -57,6 +57,13 @@ const int rpmFLAGS = RPMSENSE_EQUAL; #undef HTKEYTYPE #undef HTDATATYPE +#define HASHTYPE depexistsCache +#define HTKEYTYPE const char * +#include "lib/rpmhash.H" +#include "lib/rpmhash.C" +#undef HASHTYPE +#undef HTKEYTYPE + enum addOp_e { RPMTE_INSTALL = 0, RPMTE_UPGRADE = 1, @@ -621,6 +628,32 @@ retry: if (!adding && isInstallPreReq(dsflags) && !isErasePreReq(dsflags)) goto exit; + /* Handle rich dependencies */ + if (dsflags & RPMSENSE_RICH) { + rpmds ds1, ds2; + rpmrichOp op; + char *emsg = 0; + if (rpmdsParseRichDep(dep, &ds1, &ds2, &op, &emsg) != RPMRC_OK) { + rc = rpmdsTagN(dep) == RPMTAG_CONFLICTNAME ? 0 : 1; + if (rpmdsInstance(dep) != 0) + rc = !rc; /* ignore errors for installed packages */ + rpmdsNotify(dep, emsg ? emsg : "(parse error)", rc); + _free(emsg); + goto exit; + } + if (op == RPMRICHOP_IF) + rc = !unsatisfiedDepend(ts, dcache, ds2); + if (op != RPMRICHOP_IF || rc) + rc = unsatisfiedDepend(ts, dcache, ds1); + if ((rc && op == RPMRICHOP_OR) || (!rc && op == RPMRICHOP_AND)) { + rc = unsatisfiedDepend(ts, dcache, ds2); + } + ds1 = rpmdsFree(ds1); + ds2 = rpmdsFree(ds2); + rpmdsNotify(dep, "(rich)", rc); + goto exit; + } + /* Pretrans dependencies can't be satisfied by added packages. */ if (!(dsflags & RPMSENSE_PRETRANS)) { rpmte *matches = rpmalAllSatisfiesDepend(tsmem->addedPackages, dep); @@ -714,8 +747,18 @@ static void checkInstDeps(rpmts ts, depCache dcache, rpmte te, rpmdbFreeIterator(mi); } +static void checkNotInstDeps(rpmts ts, depCache dcache, rpmte te, + rpmTag depTag, const char *dep) +{ + char *ndep = rmalloc(strlen(dep) + 2); + ndep[0] = '!'; + strcpy(ndep + 1, dep); + checkInstDeps(ts, dcache, te, depTag, ndep); + free(ndep); +} + static void checkInstFileDeps(rpmts ts, depCache dcache, rpmte te, - rpmTag depTag, rpmfi fi, + rpmTag depTag, rpmfi fi, int is_not, filedepCache cache, fingerPrintCache *fpcp) { fingerPrintCache fpc = *fpcp; @@ -734,15 +777,23 @@ static void checkInstFileDeps(rpmts ts, depCache dcache, rpmte te, dirname = rpmfiDN(fi); fpLookup(fpc, dirname, basename, &fp); for (i = 0; i < ndirnames; i++) { + char *fpdep = 0; + const char *dep; if (!strcmp(dirnames[i], dirname)) { - checkInstDeps(ts, dcache, te, depTag, rpmfiFN(fi)); + dep = rpmfiFN(fi); } else if (fpLookupEquals(fpc, fp, dirnames[i], basename)) { - char *dep = rmalloc(strlen(dirnames[i]) + strlen(basename) + 1); - strcpy(dep, dirnames[i]); - strcat(dep, basename); - checkInstDeps(ts, dcache, te, depTag, dep); - free(dep); + fpdep = rmalloc(strlen(dirnames[i]) + strlen(basename) + 1); + strcpy(fpdep, dirnames[i]); + strcat(fpdep, basename); + dep = fpdep; + } else { + continue; } + if (!is_not) + checkInstDeps(ts, dcache, te, depTag, dep); + else + checkNotInstDeps(ts, dcache, te, depTag, dep); + _free(fpdep); } _free(fp); } @@ -773,6 +824,8 @@ int rpmtsCheck(rpmts ts) depCache dcache = NULL; filedepCache confilecache = NULL; /* file conflicts of installed packages */ filedepCache reqfilecache = NULL; /* file requires of installed packages */ + filedepCache reqnotfilecache = NULL; /* file requires of installed packages */ + depexistsCache reqnotcache = NULL; fingerPrintCache fpc = NULL; (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_CHECK), 0); @@ -812,13 +865,35 @@ int rpmtsCheck(rpmts ts) (filedepCacheFreeData)rfree); if (reqfilecache) { rpmdbIndexIterator ii = rpmdbIndexIteratorInit(rpmtsGetRdb(ts), RPMTAG_REQUIRENAME); + reqnotcache = depexistsCacheCreate(257, rstrhash, strcmp, + (filedepCacheFreeKey)rfree); + reqnotfilecache = filedepCacheCreate(257, rstrhash, strcmp, + (filedepCacheFreeKey)rfree, + (filedepCacheFreeData)rfree); if (ii) { char *key; size_t keylen; - while ((rpmdbIndexIteratorNext(ii, (const void**)&key, &keylen)) == 0) + while ((rpmdbIndexIteratorNext(ii, (const void**)&key, &keylen)) == 0) { + if (key && keylen && key[0] == '!') { + char *keystr; + /* inverted name from some rich dependency with IF */ + key++; + keylen--; + keystr = rmalloc(keylen + 1); + strncpy(keystr, key, keylen); + keystr[keylen] = 0; + depexistsCacheAddEntry(reqnotcache, keystr); + addFileDepToCache(reqnotfilecache, key, keylen); + continue; + } addFileDepToCache(reqfilecache, key, keylen); + } rpmdbIndexIteratorFree(ii); } + if (reqnotcache && !depexistsCacheNumKeys(reqnotcache)) + reqnotcache = depexistsCacheFree(reqnotcache); + if (reqnotfilecache && !filedepCacheNumKeys(reqnotfilecache)) + reqnotfilecache = filedepCacheFree(reqnotfilecache); } @@ -842,7 +917,10 @@ int rpmtsCheck(rpmts ts) /* Check provides against conflicts in installed packages. */ while (rpmdsNext(provides) >= 0) { - checkInstDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, rpmdsN(provides)); + const char *dep = rpmdsN(provides); + checkInstDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, dep); + if (reqnotcache && depexistsCacheHasEntry(reqnotcache, dep)) + checkNotInstDeps(ts, dcache, p, RPMTAG_REQUIRENAME, dep); } /* Skip obsoletion checks for source packages (ie build) */ @@ -853,11 +931,14 @@ int rpmtsCheck(rpmts ts) checkInstDeps(ts, dcache, p, RPMTAG_OBSOLETENAME, rpmteN(p)); /* Check filenames against installed conflicts */ - if (confilecache) { + if (confilecache || reqnotfilecache) { rpmfiles files = rpmteFiles(p); rpmfi fi = rpmfilesIter(files, RPMFI_ITER_FWD); while (rpmfiNext(fi) >= 0) { - checkInstFileDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, fi, confilecache, &fpc); + if (confilecache) + checkInstFileDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, fi, 0, confilecache, &fpc); + if (reqnotfilecache) + checkInstFileDeps(ts, dcache, p, RPMTAG_REQUIRENAME, fi, 1, reqnotfilecache, &fpc); } rpmfiFree(fi); rpmfilesFree(files); @@ -885,7 +966,7 @@ int rpmtsCheck(rpmts ts) rpmfi fi = rpmfilesIter(files, RPMFI_ITER_FWD);; while (rpmfiNext(fi) >= 0) { if (RPMFILE_IS_INSTALLED(rpmfiFState(fi))) { - checkInstFileDeps(ts, dcache, p, RPMTAG_REQUIRENAME, fi, reqfilecache, &fpc); + checkInstFileDeps(ts, dcache, p, RPMTAG_REQUIRENAME, fi, 0, reqfilecache, &fpc); } } rpmfiFree(fi); @@ -898,6 +979,8 @@ exit: depCacheFree(dcache); filedepCacheFree(confilecache); filedepCacheFree(reqfilecache); + filedepCacheFree(reqnotfilecache); + depexistsCacheFree(reqnotcache); fpCacheFree(fpc); (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_CHECK), 0); diff --git a/lib/order.c b/lib/order.c index f09b192..b8c81d7 100644 --- a/lib/order.c +++ b/lib/order.c @@ -152,6 +152,18 @@ static inline int addRelation(rpmts ts, if (dsflags & (RPMSENSE_RPMLIB|RPMSENSE_CONFIG|RPMSENSE_PRETRANS|RPMSENSE_POSTTRANS)) return 0; + if (dsflags & RPMSENSE_RICH) { + rpmds ds1, ds2; + rpmrichOp op; + if (rpmdsParseRichDep(requires, &ds1, &ds2, &op, NULL) == RPMRC_OK) { + addRelation(ts, al, p, ds1); + if (op == RPMRICHOP_AND || op == RPMRICHOP_OR) + addRelation(ts, al, p, ds2); + ds1 = rpmdsFree(ds1); + ds2 = rpmdsFree(ds2); + } + return 0; + } q = rpmalSatisfiesDepend(al, p, requires); /* Avoid deps outside this transaction and self dependencies */ diff --git a/lib/rpmdb.c b/lib/rpmdb.c index b6d3247..af69ed5 100644 --- a/lib/rpmdb.c +++ b/lib/rpmdb.c @@ -2032,6 +2032,50 @@ int rpmdbRemove(rpmdb db, unsigned int hdrNum) return 0; } +struct updateRichDepData { + ARGV_t argv; + int neg; +}; + +static rpmRC updateRichDepCB(void *cbdata, int type, const char *n, int nl, const char *e, int el, rpmsenseFlags sense, rpmrichOp op, char **emsg) { + struct updateRichDepData *data = cbdata; + if (type == RPMRICH_PARSE_SIMPLE && nl) { + char *name = xmalloc(data->neg + nl + 1); + *name = '!'; + strncpy(name + data->neg, n, nl); + name[data->neg + nl] = 0; + argvAdd(&data->argv, name); + _free(name); + } else if ((type == RPMRICH_PARSE_OP || RPMRICH_PARSE_LEAVE) && op == RPMRICHOP_IF) { + data->neg ^= 1; + } + return RPMRC_OK; +} + +static rpmRC updateRichDep(dbiCursor dbc, const char *str, + struct dbiIndexItem_s *rec, + idxfunc idxupdate) +{ + int n, i, rc = 0; + struct updateRichDepData data; + + data.argv = argvNew(); + data.neg = 0; + if (rpmrichParse(&str, NULL, updateRichDepCB, &data) == RPMRC_OK) { + n = argvCount(data.argv); + if (n) { + argvSort(data.argv, NULL); + for (i = 0; i < n; i++) { + if (i && !strcmp(data.argv[i - 1], data.argv[i])) + continue; /* ignore dups */ + rc += idxupdate(dbc, data.argv[i], strlen(data.argv[i]), rec); + } + } + } + argvFree(data.argv); + return rc; +} + static rpmRC tag2index(dbiIndex dbi, rpmTagVal rpmtag, unsigned int hdrNum, Header h, idxfunc idxupdate) @@ -2098,6 +2142,12 @@ static rpmRC tag2index(dbiIndex dbi, rpmTagVal rpmtag, continue; rc += idxupdate(dbc, key, keylen, &rec); + + if (rpmtag == RPMTAG_REQUIRENAME && *(char *)key == '(') { + if (rpmtdType(&tagdata) == RPM_STRING_ARRAY_TYPE) { + rc += updateRichDep(dbc, rpmtdGetString(&tagdata), &rec, idxupdate); + } + } } dbiCursorFree(dbc); diff --git a/lib/rpmds.c b/lib/rpmds.c index 49e33bc..617710c 100644 --- a/lib/rpmds.c +++ b/lib/rpmds.c @@ -1209,6 +1209,9 @@ static const struct rpmlibProvides_s rpmlibProvides[] = { { "rpmlib(LargeFiles)", "4.12.0-1", ( RPMSENSE_EQUAL), N_("support files larger than 4GB") }, + { "rpmlib(RichDependencies)", "4.12.0-1", + ( RPMSENSE_EQUAL), + N_("support for rich dependencies.") }, { NULL, NULL, 0, NULL } }; @@ -1259,10 +1262,264 @@ 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_RICH); + break; + case RPMTAG_CONFLICTNAME: + extra = Flags & RPMSENSE_RICH; break; default: break; } return (Flags & RPMSENSE_SENSEMASK) | extra; } + +struct rpmdsParseRichDepData { + rpmds dep; + rpmsenseFlags depflags; + + rpmds leftds; + rpmds rightds; + rpmrichOp op; + + int depth; + const char *rightstart; + int dochain; +}; + +static rpmRC rpmdsParseRichDepCB(void *cbdata, int type, const char *n, int nl, const char *e, int el, rpmsenseFlags sense, rpmrichOp op, char **emsg) { + struct rpmdsParseRichDepData *data = cbdata; + rpmds ds = 0; + + if (type == RPMRICH_PARSE_ENTER) + data->depth++; + else if (type == RPMRICH_PARSE_LEAVE) { + if (--data->depth == 0 && data->dochain && data->rightstart) { + /* chain op hack, construct a sub-ds from the right side of the chain */ + char *right = xmalloc(n + nl - data->rightstart + 2); + right[0] = '('; + strncpy(right + 1, data->rightstart, n + nl - data->rightstart); + right[n + nl - data->rightstart + 1] = 0; + data->rightds = rpmdsFree(data->rightds); + ds = singleDS(data->dep->pool, data->dep->tagN, 0, 0, RPMSENSE_RICH | data->depflags, 0, 0, 0); + ds->N[0] = rpmstrPoolIdn(ds->pool, n, nl, 1); + ds->EVR[0] = rpmstrPoolIdn(ds->pool, e ? e : "", el, 1); + data->rightds = ds; + } + } + if (data->depth != 1) + return RPMRC_OK; /* we're only interested in top-level parsing */ + if ((type == RPMRICH_PARSE_SIMPLE || type == RPMRICH_PARSE_LEAVE) && !data->dochain) { + if (type == RPMRICH_PARSE_LEAVE) + sense = RPMSENSE_RICH; + ds = singleDS(data->dep->pool, data->dep->tagN, 0, 0, sense | data->depflags, 0, 0, 0); + ds->N[0] = rpmstrPoolIdn(ds->pool, n, nl, 1); + ds->EVR[0] = rpmstrPoolIdn(ds->pool, e ? e : "", el, 1); + if (!data->leftds) + data->leftds = ds; + else { + data->rightds = ds; + data->rightstart = n; + } + } + if (type == RPMRICH_PARSE_OP) { + if (data->op != RPMRICHOP_SINGLE) + data->dochain = 1; /* this is a chained op */ + data->op = op; + } + return RPMRC_OK; +} + + +rpmRC rpmdsParseRichDep(rpmds dep, rpmds *leftds, rpmds *rightds, rpmrichOp *op, char **emsg) +{ + rpmRC rc; + struct rpmdsParseRichDepData data; + const char *depstr = rpmdsN(dep); + memset(&data, 0, sizeof(data)); + data.dep = dep; + data.op = RPMRICHOP_SINGLE; + data.depflags = rpmdsFlags(dep) & ~(RPMSENSE_SENSEMASK | RPMSENSE_RICH | RPMSENSE_MISSINGOK); + rc = rpmrichParse(&depstr, emsg, rpmdsParseRichDepCB, &data); + if (rc == RPMRC_OK && *depstr) { + if (emsg) + rasprintf(emsg, "Junk after rich dependency"); + rc = RPMRC_FAIL; + } + if (rc != RPMRC_OK) { + rpmdsFree(data.leftds); + rpmdsFree(data.rightds); + } else { + *leftds = data.leftds; + *rightds = data.rightds; + *op = data.op; + } + return rc; +} + + +static rpmRC parseRichDepOp(const char **dstrp, rpmrichOp *opp, char **emsg) +{ + const char *p = *dstrp, *pe = p; + + while (*pe && !risspace(*pe) && *pe != ')') + pe++; + if (pe - p == 3 && !strncmp(p, "AND", 3)) + *opp = RPMRICHOP_AND; + else if (pe - p == 2 && !strncmp(p, "OR", 2)) + *opp = RPMRICHOP_OR; + else if (pe - p == 2 && !strncmp(p, "IF", 2)) + *opp = RPMRICHOP_IF; + else { + if (emsg) + rasprintf(emsg, "Unknown rich dependency op '%.*s'", (int)(pe - p), p); + return RPMRC_FAIL; + } + *dstrp = pe; + return RPMRC_OK; +} + + +static struct ReqComp { +const char * token; + rpmsenseFlags sense; +} const ReqComparisons[] = { + { "<=", RPMSENSE_LESS | RPMSENSE_EQUAL}, + { "=<", RPMSENSE_LESS | RPMSENSE_EQUAL}, + { "<", RPMSENSE_LESS}, + + { "==", RPMSENSE_EQUAL}, + { "=", RPMSENSE_EQUAL}, + + { ">=", RPMSENSE_GREATER | RPMSENSE_EQUAL}, + { "=>", RPMSENSE_GREATER | RPMSENSE_EQUAL}, + { ">", RPMSENSE_GREATER}, + + { NULL, 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 rpmRC parseSimpleDep(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata) +{ + const char *p = *dstrp; + const char *n, *e = 0; + int nl, el = 0; + rpmsenseFlags sense = 0; + + n = p; + SKIPNONWHITEX(p); + nl = p - n; + if (nl == 0) { + if (emsg) + rasprintf(emsg, "Name required"); + return RPMRC_FAIL; + } + SKIPWHITE(p); + if (*p) { + const char *pe = p; + int i; + + SKIPNONWHITE(pe); + for (i = 0; ReqComparisons[i].token; i++) { + if (pe - p == strlen(ReqComparisons[i].token) && !strncmp(p, ReqComparisons[i].token, pe - p)) { + sense = ReqComparisons[i].sense; + break; + } + } + if (sense) { + p = pe; + SKIPWHITE(p); + e = p; + SKIPNONWHITEX(p); + el = p - e; + } + } + if (e && el == 0) { + if (emsg) + rasprintf(emsg, "Version required"); + return RPMRC_FAIL; + } + if (cb(cbdata, RPMRICH_PARSE_SIMPLE, n, nl, e, el, sense, RPMRICHOP_SINGLE, emsg) != RPMRC_OK) + return RPMRC_FAIL; + *dstrp = p; + return RPMRC_OK; +} + +rpmRC rpmrichParse(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata) +{ + const char *p = *dstrp, *pe; + rpmrichOp op = RPMRICHOP_SINGLE, chainop = 0; + + if (cb(cbdata, RPMRICH_PARSE_ENTER, p, 0, 0, 0, 0, op, emsg) != RPMRC_OK) + return RPMRC_FAIL; + if (*p++ != '(') { + if (emsg) + rasprintf(emsg, "Rich dependency does not start with '('"); + return RPMRC_FAIL; + } + for (;;) { + SKIPWHITE(p); + if (*p == ')') { + if (emsg) { + if (chainop) + rasprintf(emsg, "Missing argument to op"); + else + rasprintf(emsg, "Empty rich dependency"); + } + return RPMRC_FAIL; + } + if (*p == '(') { + if (rpmrichParse(&p, emsg, cb, cbdata) != RPMRC_OK) + return RPMRC_FAIL; + } else { + if (parseSimpleDep(&p, emsg, cb, cbdata) != RPMRC_OK) + return RPMRC_FAIL; + } + SKIPWHITE(p); + if (!*p) { + if (emsg) + rasprintf(emsg, "Unterminated rich dependency: %s", *dstrp); + return RPMRC_FAIL; + } + if (*p == ')') + break; + pe = p; + if (parseRichDepOp(&pe, &op, emsg) != RPMRC_OK) + return RPMRC_FAIL; + if (chainop && op != chainop) { + if (emsg) + rasprintf(emsg, "Cannot chain different ops"); + return RPMRC_FAIL; + } + if (chainop == RPMRICHOP_IF) { + if (emsg) + rasprintf(emsg, "Cannot chain IF ops"); + return RPMRC_FAIL; + } + chainop = op; + if (cb(cbdata, RPMRICH_PARSE_OP, p, pe - p, 0, 0, 0, op, emsg) != RPMRC_OK) + return RPMRC_FAIL; + p = pe; + } + p++; + if (cb(cbdata, RPMRICH_PARSE_LEAVE, *dstrp, p - *dstrp , 0, 0, 0, op, emsg) != RPMRC_OK) + return RPMRC_FAIL; + *dstrp = p; + return RPMRC_OK; +} + +const char *rpmrichOpStr(rpmrichOp op) +{ + if (op == RPMRICHOP_SINGLE) + return "SINGLE"; + if (op == RPMRICHOP_AND) + return "AND"; + if (op == RPMRICHOP_OR) + return "OR"; + if (op == RPMRICHOP_IF) + return "IF"; + return NULL; +} + diff --git a/lib/rpmds.h b/lib/rpmds.h index 9b7c908..bdde57a 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_RICH = (1 << 29) }; typedef rpmFlags rpmsenseFlags; @@ -454,6 +455,52 @@ rpmds rpmdsSinglePoolTix(rpmstrPool pool, rpmTagVal tagN, */ int rpmdsRpmlibPool(rpmstrPool pool, rpmds * dsp, const void * tblp); + +typedef enum rpmrichOp_e { + RPMRICHOP_SINGLE = 1, + RPMRICHOP_AND = 2, + RPMRICHOP_OR = 3, + RPMRICHOP_IF = 4 +} rpmrichOp; + +/** + * Parse a rich dependency string + * @param dep the dependency + * @param leftds returns the left dependency + * @param rightds returns the right dependency + * @param op returns the rich dep op + * @param emsg returns the error string + * @return RPMRC_OK on success + */ +rpmRC rpmdsParseRichDep(rpmds dep, rpmds *leftds, rpmds *rightds, rpmrichOp *op, char **emsg); + + +#define RPMRICH_PARSE_SIMPLE 1 /* standard N <=> EVR dep */ +#define RPMRICH_PARSE_ENTER 2 /* entering sub-dependency */ +#define RPMRICH_PARSE_LEAVE 3 /* leaving sub-dependency */ +#define RPMRICH_PARSE_OP 4 /* parsed a rich dep op */ + +typedef rpmRC (*rpmrichParseFunction) (void *cbdata, int type, + const char *n, int nl, const char *e, int el, rpmsenseFlags sense, + rpmrichOp op, char **emsg); + +/** + * Parse a rich dependency string + * @param dstrp pointer to sting, will be updated + * @param emsg returns the error string, can be NULL + * @param cb callback function + * @param cbdata callback function data + * @return RPMRC_OK on success + */ +rpmRC rpmrichParse(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata); + +/** + * Return a string representation of the rich dependency op + * @param op the dependency op + * @return constant string, do not free + */ +const char *rpmrichOpStr(rpmrichOp op); + #ifdef __cplusplus } #endif
_______________________________________________ Rpm-maint mailing list Rpm-maint@lists.rpm.org http://lists.rpm.org/mailman/listinfo/rpm-maint