X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fsolvable.c;h=657a8b828e8a009aa6625b80020c255c2987068c;hb=1aac48dff40ef592968a18058bad270da65ed847;hp=4e46eaf5069dd26449d1b683c4cbc5ec5c909ab8;hpb=c36ef29531924b0a2ec37cdac57211dac32837b1;p=platform%2Fupstream%2Flibsolv.git diff --git a/src/solvable.c b/src/solvable.c index 4e46eaf..657a8b8 100644 --- a/src/solvable.c +++ b/src/solvable.c @@ -20,7 +20,11 @@ #include "pool.h" #include "repo.h" #include "util.h" +#include "policy.h" +#include "poolvendor.h" #include "chksum.h" +#include "linkedpkg.h" +#include "evr.h" const char * pool_solvable2str(Pool *pool, Solvable *s) @@ -29,9 +33,9 @@ pool_solvable2str(Pool *pool, Solvable *s) int nl, el, al; char *p; n = pool_id2str(pool, s->name); - e = pool_id2str(pool, s->evr); + e = s->evr ? pool_id2str(pool, s->evr) : ""; /* XXX: may want to skip the epoch here */ - a = pool_id2str(pool, s->arch); + a = s->arch ? pool_id2str(pool, s->arch) : ""; nl = strlen(n); el = strlen(e); al = strlen(a); @@ -44,10 +48,27 @@ pool_solvable2str(Pool *pool, Solvable *s) } p = pool_alloctmpspace(pool, nl + el + al + 3); strcpy(p, n); - p[nl] = '-'; - strncpy(p + nl + 1, e, el); - p[nl + 1 + el] = '.'; - strcpy(p + nl + 1 + el + 1, a); + if (el) + { + p[nl++] = '-'; + strncpy(p + nl, e, el); + p[nl + el] = 0; + } + if (al) + { + p[nl + el] = pool->disttype == DISTTYPE_HAIKU ? '-' : '.'; + strcpy(p + nl + el + 1, a); + } + if (pool->disttype == DISTTYPE_CONDA && solvable_lookup_type(s, SOLVABLE_BUILDFLAVOR)) + { + Queue flavorq; + int i; + queue_init(&flavorq); + solvable_lookup_idarray(s, SOLVABLE_BUILDFLAVOR, &flavorq); + for (i = 0; i < flavorq.count; i++) + p = pool_tmpappend(pool, p, "-", pool_id2str(pool, flavorq.elements[i])); + queue_free(&flavorq); + } return p; } @@ -89,12 +110,41 @@ solvable_lookup_deparray(Solvable *s, Id keyname, Queue *q, Id marker) return repo_lookup_deparray(s->repo, s - s->repo->pool->solvables, keyname, q, marker); } +static const char * +solvable_lookup_str_joinarray(Solvable *s, Id keyname, const char *joinstr) +{ + Queue q; + Id qbuf[10]; + char *str = 0; + + queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf)); + if (solvable_lookup_idarray(s, keyname, &q) && q.count) + { + Pool *pool = s->repo->pool; + if (q.count == 1) + str = (char *)pool_id2str(pool, q.elements[0]); + else + { + int i; + str = pool_tmpjoin(pool, pool_id2str(pool, q.elements[0]), 0, 0); + for (i = 1; i < q.count; i++) + str = pool_tmpappend(pool, str, joinstr, pool_id2str(pool, q.elements[i])); + } + } + queue_free(&q); + return str; +} + const char * solvable_lookup_str(Solvable *s, Id keyname) { + const char *str; if (!s->repo) return 0; - return repo_lookup_str(s->repo, s - s->repo->pool->solvables, keyname); + str = repo_lookup_str(s->repo, s - s->repo->pool->solvables, keyname); + if (!str && (keyname == SOLVABLE_LICENSE || keyname == SOLVABLE_GROUP || keyname == SOLVABLE_BUILDFLAVOR)) + str = solvable_lookup_str_joinarray(s, keyname, ", "); + return str; } static const char * @@ -102,7 +152,7 @@ solvable_lookup_str_base(Solvable *s, Id keyname, Id basekeyname, int usebase) { Pool *pool; const char *str, *basestr; - Id p, pp; + Id p, pp, name; Solvable *s2; int pass; @@ -119,13 +169,14 @@ solvable_lookup_str_base(Solvable *s, Id keyname, Id basekeyname, int usebase) * translation */ if (!pool->whatprovides) return usebase ? basestr : 0; + name = s->name; /* we do this in two passes, first same vendor, then all other vendors */ for (pass = 0; pass < 2; pass++) { - FOR_PROVIDES(p, pp, s->name) + FOR_PROVIDES(p, pp, name) { s2 = pool->solvables + p; - if (s2->name != s->name) + if (s2->name != name) continue; if ((s->vendor == s2->vendor) != (pass == 0)) continue; @@ -136,6 +187,15 @@ solvable_lookup_str_base(Solvable *s, Id keyname, Id basekeyname, int usebase) if (str) return str; } +#ifdef ENABLE_LINKED_PKGS + /* autopattern/product translation magic */ + if (pass == 1 && name == s->name) + { + name = find_autopackage_name(pool, s); + if (name && name != s->name) + pass = -1; /* start over with new name */ + } +#endif } return usebase ? basestr : 0; } @@ -189,14 +249,14 @@ solvable_lookup_str_poollang(Solvable *s, Id keyname) const char * solvable_lookup_str_lang(Solvable *s, Id keyname, const char *lang, int usebase) { - if (s->repo) - { - Id id = pool_id2langid(s->repo->pool, keyname, lang, 0); - if (id) - return solvable_lookup_str_base(s, id, keyname, usebase); - if (!usebase) - return 0; - } + Id id; + if (!s->repo) + return 0; + id = pool_id2langid(s->repo->pool, keyname, lang, 0); + if (id) + return solvable_lookup_str_base(s, id, keyname, usebase); + if (!usebase) + return 0; return solvable_lookup_str(s, keyname); } @@ -208,14 +268,14 @@ solvable_lookup_num(Solvable *s, Id keyname, unsigned long long notfound) return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, notfound); } -unsigned int -solvable_lookup_sizek(Solvable *s, Id keyname, unsigned int notfound) +unsigned long long +solvable_lookup_sizek(Solvable *s, Id keyname, unsigned long long notfound) { unsigned long long size; if (!s->repo) return notfound; - size = solvable_lookup_num(s, keyname, (unsigned long long)notfound << 10); - return (unsigned int)((size + 1023) >> 10); + size = solvable_lookup_num(s, keyname, (unsigned long long)-1); + return size == (unsigned long long)-1 ? notfound : ((size + 1023) >> 10); } int @@ -229,25 +289,27 @@ solvable_lookup_void(Solvable *s, Id keyname) int solvable_lookup_bool(Solvable *s, Id keyname) { + Id type; if (!s->repo) return 0; /* historic nonsense: there are two ways of storing a bool, as num == 1 or void. test both. */ - if (repo_lookup_type(s->repo, s - s->repo->pool->solvables, keyname) == REPOKEY_TYPE_VOID) + type = repo_lookup_type(s->repo, s - s->repo->pool->solvables, keyname); + if (type == REPOKEY_TYPE_VOID) return 1; - return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, 0) == 1; + if (type == REPOKEY_TYPE_NUM || type == REPOKEY_TYPE_CONSTANT) + return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, 0) == 1; + return 0; } const unsigned char * solvable_lookup_bin_checksum(Solvable *s, Id keyname, Id *typep) { - Repo *repo = s->repo; - - if (!repo) + if (!s->repo) { *typep = 0; return 0; } - return repo_lookup_bin_checksum(repo, s - repo->pool->solvables, keyname, typep); + return repo_lookup_bin_checksum(s->repo, s - s->repo->pool->solvables, keyname, typep); } const char * @@ -257,6 +319,12 @@ solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep) return chk ? pool_bin2hex(s->repo->pool, chk, solv_chksum_len(*typep)) : 0; } +unsigned int +solvable_lookup_count(Solvable *s, Id keyname) +{ + return s->repo ? repo_lookup_count(s->repo, s - s->repo->pool->solvables, keyname) : 0; +} + static inline const char * evrid2vrstr(Pool *pool, Id evrid) { @@ -265,11 +333,11 @@ evrid2vrstr(Pool *pool, Id evrid) return evr; for (p = evr; *p >= '0' && *p <= '9'; p++) ; - return p != evr && *p == ':' ? p + 1 : evr; + return p != evr && *p == ':' && p[1] ? p + 1 : evr; } -char * -solvable_get_location(Solvable *s, unsigned int *medianrp) +const char * +solvable_lookup_location(Solvable *s, unsigned int *medianrp) { Pool *pool; int l = 0; @@ -282,7 +350,7 @@ solvable_get_location(Solvable *s, unsigned int *medianrp) return 0; pool = s->repo->pool; if (medianrp) - *medianrp = solvable_lookup_num(s, SOLVABLE_MEDIANR, 1); + *medianrp = solvable_lookup_num(s, SOLVABLE_MEDIANR, 0); if (solvable_lookup_void(s, SOLVABLE_MEDIADIR)) mediadir = pool_id2str(pool, s->arch); else @@ -316,213 +384,45 @@ solvable_get_location(Solvable *s, unsigned int *medianrp) return loc; } -/*****************************************************************************/ - -static inline Id dep2name(Pool *pool, Id dep) -{ - while (ISRELDEP(dep)) - { - Reldep *rd = rd = GETRELDEP(pool, dep); - dep = rd->name; - } - return dep; -} - -static int providedbyinstalled_multiversion(Pool *pool, Map *installed, Id n, Id con) -{ - Id p, pp; - Solvable *sn = pool->solvables + n; - - FOR_PROVIDES(p, pp, sn->name) - { - Solvable *s = pool->solvables + p; - if (s->name != sn->name || s->arch != sn->arch) - continue; - if (!MAPTST(installed, p)) - continue; - if (pool_match_nevr(pool, pool->solvables + p, con)) - continue; - return 1; /* found installed package that doesn't conflict */ - } - return 0; -} - -static inline int providedbyinstalled(Pool *pool, Map *installed, Id dep, int ispatch, Map *noobsoletesmap) +const char * +solvable_get_location(Solvable *s, unsigned int *medianrp) { - Id p, pp; - FOR_PROVIDES(p, pp, dep) - { - if (p == SYSTEMSOLVABLE) - return -1; - if (ispatch && !pool_match_nevr(pool, pool->solvables + p, dep)) - continue; - if (ispatch && noobsoletesmap && noobsoletesmap->size && MAPTST(noobsoletesmap, p) && ISRELDEP(dep)) - if (providedbyinstalled_multiversion(pool, installed, p, dep)) - continue; - if (MAPTST(installed, p)) - return 1; - } - return 0; + const char *loc = solvable_lookup_location(s, medianrp); + if (medianrp && *medianrp == 0) + *medianrp = 1; /* compat, to be removed */ + return loc; } -/* - * solvable_trivial_installable_map - anwers is a solvable is installable - * without any other installs/deinstalls. - * The packages considered to be installed are provided via the - * installedmap bitmap. A additional "conflictsmap" bitmap providing - * information about the conflicts of the installed packages can be - * used for extra speed up. Provide a NULL pointer if you do not - * have this information. - * Both maps can be created with pool_create_state_maps() or - * solver_create_state_maps(). - * - * returns: - * 1: solvable is installable without any other package changes - * 0: solvable is not installable - * -1: solvable is installable, but doesn't constrain any installed packages - */ -int -solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap, Map *noobsoletesmap) +const char * +solvable_lookup_sourcepkg(Solvable *s) { - Pool *pool = s->repo->pool; - Solvable *s2; - Id p, *dp; - Id *reqp, req; - Id *conp, con; - int r, interesting = 0; + Pool *pool; + const char *evr, *name; + Id archid; - if (conflictsmap && MAPTST(conflictsmap, s - pool->solvables)) + if (!s->repo) return 0; - if (s->requires) - { - reqp = s->repo->idarraydata + s->requires; - while ((req = *reqp++) != 0) - { - if (req == SOLVABLE_PREREQMARKER) - continue; - r = providedbyinstalled(pool, installedmap, req, 0, 0); - if (!r) - return 0; - if (r > 0) - interesting = 1; - } - } - if (s->conflicts) - { - int ispatch = 0; - - if (!strncmp("patch:", pool_id2str(pool, s->name), 6)) - ispatch = 1; - conp = s->repo->idarraydata + s->conflicts; - while ((con = *conp++) != 0) - { - if (providedbyinstalled(pool, installedmap, con, ispatch, noobsoletesmap)) - return 0; - if (!interesting && ISRELDEP(con)) - { - con = dep2name(pool, con); - if (providedbyinstalled(pool, installedmap, con, ispatch, noobsoletesmap)) - interesting = 1; - } - } - } -#if 0 - if (s->repo) - { - Id *obsp, obs; - Repo *installed = 0; - if (s->obsoletes && s->repo != installed) - { - obsp = s->repo->idarraydata + s->obsoletes; - while ((obs = *obsp++) != 0) - { - if (providedbyinstalled(pool, installedmap, obs, 0, 0)) - return 0; - } - } - if (s->repo != installed) - { - Id pp; - FOR_PROVIDES(p, pp, s->name) - { - s2 = pool->solvables + p; - if (s2->repo == installed && s2->name == s->name) - return 0; - } - } - } -#endif - if (!conflictsmap) - { - int i; - - p = s - pool->solvables; - for (i = 1; i < pool->nsolvables; i++) - { - if (!MAPTST(installedmap, i)) - continue; - s2 = pool->solvables + i; - if (!s2->conflicts) - continue; - conp = s2->repo->idarraydata + s2->conflicts; - while ((con = *conp++) != 0) - { - dp = pool_whatprovides_ptr(pool, con); - for (; *dp; dp++) - if (*dp == p) - return 0; - } - } - } - return interesting ? 1 : -1; -} - -/* - * different interface for solvable_trivial_installable_map, where - * the information about the installed packages is provided - * by a queue. - */ -int -solvable_trivial_installable_queue(Solvable *s, Queue *installed, Map *noobsoletesmap) -{ - Pool *pool = s->repo->pool; - int i; - Id p; - Map installedmap; - int r; - - map_init(&installedmap, pool->nsolvables); - for (i = 0; i < installed->count; i++) + pool = s->repo->pool; + if (solvable_lookup_void(s, SOLVABLE_SOURCENAME)) + name = pool_id2str(pool, s->name); + else + name = solvable_lookup_str(s, SOLVABLE_SOURCENAME); + if (!name) + return 0; + archid = solvable_lookup_id(s, SOLVABLE_SOURCEARCH); + if (solvable_lookup_void(s, SOLVABLE_SOURCEEVR)) + evr = evrid2vrstr(pool, s->evr); + else + evr = solvable_lookup_str(s, SOLVABLE_SOURCEEVR); + if (archid == ARCH_SRC || archid == ARCH_NOSRC) { - p = installed->elements[i]; - if (p > 0) /* makes it work with decisionq */ - MAPSET(&installedmap, p); + char *str; + str = pool_tmpjoin(pool, name, evr ? "-" : 0, evr); + str = pool_tmpappend(pool, str, ".", pool_id2str(pool, archid)); + return pool_tmpappend(pool, str, ".rpm", 0); } - r = solvable_trivial_installable_map(s, &installedmap, 0, noobsoletesmap); - map_free(&installedmap); - return r; -} - -/* - * different interface for solvable_trivial_installable_map, where - * the information about the installed packages is provided - * by a repo containing the installed solvables. - */ -int -solvable_trivial_installable_repo(Solvable *s, Repo *installed, Map *noobsoletesmap) -{ - Pool *pool = s->repo->pool; - Id p; - Solvable *s2; - Map installedmap; - int r; - - map_init(&installedmap, pool->nsolvables); - FOR_REPO_SOLVABLES(installed, p, s2) - MAPSET(&installedmap, p); - r = solvable_trivial_installable_map(s, &installedmap, 0, noobsoletesmap); - map_free(&installedmap); - return r; + else + return name; /* FIXME */ } @@ -531,9 +431,9 @@ solvable_trivial_installable_repo(Solvable *s, Repo *installed, Map *noobsoletes /* * Create maps containing the state of each solvable. Input is a "installed" queue, * it contains all solvable ids that are considered to be installed. - * - * The created maps can be used for solvable_trivial_installable_map(), - * pool_calc_duchanges(), pool_calc_installsizechange(). + * + * The created maps can be used for * pool_calc_duchanges() and + * pool_calc_installsizechange(). * */ void @@ -571,22 +471,28 @@ pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *con /* Tests if two solvables have identical content. Currently * both solvables need to come from the same pool */ + int solvable_identical(Solvable *s1, Solvable *s2) { - unsigned int bt1, bt2; + unsigned long long bt1, bt2; Id rq1, rq2; Id *reqp; - if (s1->name != s2->name) return 0; if (s1->arch != s2->arch) return 0; if (s1->evr != s2->evr) return 0; - /* map missing vendor to empty string */ + + /* check vendor, map missing vendor to empty string */ if ((s1->vendor ? s1->vendor : 1) != (s2->vendor ? s2->vendor : 1)) - return 0; + { + /* workaround for bug 881493 */ + if (s1->repo && !strncmp(pool_id2str(s1->repo->pool, s1->name), "product:", 8)) + return 1; + return 0; + } /* looking good, try some fancier stuff */ /* might also look up the package checksum here */ @@ -599,6 +505,13 @@ solvable_identical(Solvable *s1, Solvable *s2) } else { + if (s1->repo) + { + /* workaround for bugs 881493 and 885830*/ + const char *n = pool_id2str(s1->repo->pool, s1->name); + if (!strncmp(n, "product:", 8) || !strncmp(n, "application:", 12)) + return 1; + } /* look at requires in a last attempt to find recompiled packages */ rq1 = rq2 = 0; if (s1->requires) @@ -610,6 +523,19 @@ solvable_identical(Solvable *s1, Solvable *s2) if (rq1 != rq2) return 0; } + if (s1->repo && s1->repo->pool->disttype == DISTTYPE_CONDA) + { + /* check buildflavor and buildversion */ + const char *str1, *str2; + str1 = solvable_lookup_str(s1, SOLVABLE_BUILDFLAVOR); + str2 = solvable_lookup_str(s2, SOLVABLE_BUILDFLAVOR); + if (str1 != str2 && (!str1 || !str2 || strcmp(str1, str2) != 0)) + return 0; + str1 = solvable_lookup_str(s1, SOLVABLE_BUILDVERSION); + str2 = solvable_lookup_str(s2, SOLVABLE_BUILDVERSION); + if (str1 != str2 && (!str1 || !str2 || strcmp(str1, str2) != 0)) + return 0; + } return 1; } @@ -694,3 +620,246 @@ solvable_set_deparray(Solvable *s, Id keyname, Queue *q, Id marker) repo_set_deparray(s->repo, s - s->repo->pool->solvables, keyname, q, marker); } +void +solvable_unset(Solvable *s, Id keyname) +{ + repo_unset(s->repo, s - s->repo->pool->solvables, keyname); +} + +/* return true if a dependency intersects dep in the keyname array */ +int +solvable_matchesdep(Solvable *s, Id keyname, Id dep, int marker) +{ + int i; + Pool *pool = s->repo->pool; + Queue q; + + if (keyname == SOLVABLE_NAME) + return pool_match_nevr(pool, s, dep) ? 1 : 0; /* nevr match hack */ + queue_init(&q); + solvable_lookup_deparray(s, keyname, &q, marker); + for (i = 0; i < q.count; i++) + if (pool_match_dep(pool, q.elements[i], dep)) + break; + i = i == q.count ? 0 : 1; + queue_free(&q); + return i; +} + +int +solvable_matchessolvable_int(Solvable *s, Id keyname, int marker, Id solvid, Map *solvidmap, Queue *depq, Map *missc, int reloff, Queue *outdepq) +{ + Pool *pool = s->repo->pool; + int i, boff; + Id *wp; + + if (depq->count) + queue_empty(depq); + if (outdepq && outdepq->count) + queue_empty(outdepq); + solvable_lookup_deparray(s, keyname, depq, marker); + for (i = 0; i < depq->count; i++) + { + Id dep = depq->elements[i]; + boff = ISRELDEP(dep) ? reloff + GETRELID(dep) : dep; + if (MAPTST(missc, boff)) + continue; + if (ISRELDEP(dep)) + { + Reldep *rd = GETRELDEP(pool, dep); + if (!ISRELDEP(rd->name) && rd->flags < 8) + { + /* do pre-filtering on the base */ + if (MAPTST(missc, rd->name)) + continue; + wp = pool_whatprovides_ptr(pool, rd->name); + if (solvidmap) + { + for (; *wp; wp++) + if (MAPTST(solvidmap, *wp)) + break; + } + else + { + for (; *wp; wp++) + if (*wp == solvid) + break; + } + if (!*wp) + { + /* the base does not include solvid, no need to check the complete dep */ + MAPSET(missc, rd->name); + MAPSET(missc, boff); + continue; + } + } + } + wp = pool_whatprovides_ptr(pool, dep); + if (solvidmap) + { + for (; *wp; wp++) + if (MAPTST(solvidmap, *wp)) + break; + } + else + { + for (; *wp; wp++) + if (*wp == solvid) + break; + } + if (*wp) + { + if (outdepq) + { + queue_pushunique(outdepq, dep); + continue; + } + return 1; + } + MAPSET(missc, boff); + } + return outdepq && outdepq->count ? 1 : 0; +} + +int +solvable_matchessolvable(Solvable *s, Id keyname, Id solvid, Queue *depq, int marker) +{ + Pool *pool = s->repo->pool; + Map missc; /* cache for misses */ + int res, reloff; + Queue qq; + + if (depq && depq->count) + queue_empty(depq); + if (s - pool->solvables == solvid) + return 0; /* no self-matches */ + + queue_init(&qq); + reloff = pool->ss.nstrings; + map_init(&missc, reloff + pool->nrels); + res = solvable_matchessolvable_int(s, keyname, marker, solvid, 0, &qq, &missc, reloff, depq); + map_free(&missc); + queue_free(&qq); + return res; +} + +static int +solvidset2str_evrcmp(Pool *pool, Id a, Id b) +{ + Solvable *as = pool->solvables + a, *bs = pool->solvables + b; + return as->evr != bs->evr ? pool_evrcmp(pool, as->evr, bs->evr, EVRCMP_COMPARE) : 0; +} + +static int +solvidset2str_sortcmp(const void *va, const void *vb, void *vd) +{ + Pool *pool = vd; + Solvable *as = pool->solvables + *(Id *)va, *bs = pool->solvables + *(Id *)vb; + if (as->name != bs->name) + { + int r = strcmp(pool_id2str(pool, as->name), pool_id2str(pool, bs->name)); + if (r) + return r; + return as->name - bs->name; + } + if (as->evr != bs->evr) + { + int r = pool_evrcmp(pool, as->evr, bs->evr, EVRCMP_COMPARE); + if (r) + return r; + } + return *(Id *)va - *(Id *)vb; +} + +static const char * +solvidset2str_striprelease(Pool *pool, Id evr, Id otherevr) +{ + const char *evrstr = pool_id2str(pool, evr); + const char *r = strchr(evrstr, '-'); + char *evrstr2; + int cmp; + if (!r) + return evrstr; + evrstr2 = pool_tmpjoin(pool, evrstr, 0, 0); + evrstr2[r - evrstr] = 0; + cmp = pool_evrcmp_str(pool, evrstr2, pool_id2str(pool, otherevr), pool->disttype != DISTTYPE_DEB ? EVRCMP_MATCH_RELEASE : EVRCMP_COMPARE); + return cmp == 1 ? evrstr2 : evrstr; +} + +const char * +pool_solvidset2str(Pool *pool, Queue *q) +{ + Queue pq; + Queue pr; + char *s = 0; + int i, j, k, kstart; + Id name = 0; + + if (!q->count) + return ""; + if (q->count == 1) + return pool_solvid2str(pool, q->elements[0]); + queue_init_clone(&pq, q); + queue_init(&pr); + solv_sort(pq.elements, pq.count, sizeof(Id), solvidset2str_sortcmp, pool); + + for (i = 0; i < pq.count; i++) + { + Id p = pq.elements[i]; + if (s) + s = pool_tmpappend(pool, s, ", ", 0); + + if (i == 0 || pool->solvables[p].name != name) + { + Id p2, pp2; + name = pool->solvables[p].name; + queue_empty(&pr); + FOR_PROVIDES(p2, pp2, name) + if (pool->solvables[p].name == name) + queue_push(&pr, p2); + if (pr.count > 1) + solv_sort(pr.elements, pr.count, sizeof(Id), solvidset2str_sortcmp, pool); + } + + for (k = 0; k < pr.count; k++) + if (pr.elements[k] == p) + break; + if (k == pr.count) + { + /* not in provides, list as singularity */ + s = pool_tmpappend(pool, s, pool_solvid2str(pool, pq.elements[i]), 0); + continue; + } + if (k && solvidset2str_evrcmp(pool, pr.elements[k], pr.elements[k - 1]) == 0) + { + /* unclear start, list as single package */ + s = pool_tmpappend(pool, s, pool_solvid2str(pool, pq.elements[i]), 0); + continue; + } + kstart = k; + for (j = i + 1, k = k + 1; j < pq.count; j++, k++) + if (k == pr.count || pq.elements[j] != pr.elements[k]) + break; + while (j > i + 1 && k && k < pr.count && solvidset2str_evrcmp(pool, pr.elements[k], pr.elements[k - 1]) == 0) + { + j--; + k--; + } + if (k == 0 || j == i + 1) + { + s = pool_tmpappend(pool, s, pool_solvid2str(pool, pq.elements[i]), 0); + continue; + } + /* create an interval */ + s = pool_tmpappend(pool, s, pool_id2str(pool, name), 0); + if (kstart > 0) + s = pool_tmpappend(pool, s, " >= ", solvidset2str_striprelease(pool, pool->solvables[pr.elements[kstart]].evr, pool->solvables[pr.elements[kstart - 1]].evr)); + if (k < pr.count) + s = pool_tmpappend(pool, s, " < ", solvidset2str_striprelease(pool, pool->solvables[pr.elements[k]].evr, pool->solvables[pr.elements[k - 1]].evr)); + i = j - 1; + } + queue_free(&pq); + queue_free(&pr); + return s; +} +