+ if (!selection->count)
+ return 0;
+ if ((flags & (SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH | SELECTION_WITH_SOURCE)) != 0)
+ {
+ /* try to drop expensive extra bits */
+ flags = (flags & ~(SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH | SELECTION_WITH_SOURCE)) | selection_extrabits(pool, selection, flags);
+ }
+ }
+ queue_init(&q);
+ ret = selection_make(pool, &q, name, flags & ~SELECTION_MODEBITS);
+ return selection_combine(pool, selection, &q, flags, ret);
+ }
+ queue_empty(selection);
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0 && !pool->installed)
+ return 0;
+
+ /* here come our four selection modes */
+ if ((flags & SELECTION_FILELIST) != 0)
+ ret = selection_filelist(pool, selection, name, flags);
+ if (!ret && (flags & SELECTION_NAME) != 0)
+ ret = selection_name_arch_rel(pool, selection, name, flags, 0);
+ if (!ret && (flags & SELECTION_PROVIDES) != 0)
+ ret = selection_name_arch_rel(pool, selection, name, flags, 1);
+ if (!ret && (flags & SELECTION_CANON) != 0)
+ ret = selection_canon(pool, selection, name, flags);
+
+ /* now do result filtering */
+ if (ret && (flags & SELECTION_INSTALLED_ONLY) != 0)
+ selection_filter_repo(pool, selection, pool->installed, SOLVER_SETREPO);
+
+ /* flatten if requested */
+ if (ret && (flags & SELECTION_FLAT) != 0)
+ selection_flatten(pool, selection);
+ return selection->count ? ret : 0;
+}
+
+static int
+matchdep_str(const char *pattern, const char *string, int flags)
+{
+ if (!pattern || !string)
+ return 0;
+ if (flags & SELECTION_GLOB)
+ {
+ int globflags = (flags & SELECTION_NOCASE) != 0 ? FNM_CASEFOLD : 0;
+ return fnmatch(pattern, string, globflags) == 0 ? 1 : 0;
+ }
+ if (flags & SELECTION_NOCASE)
+ return strcasecmp(pattern, string) == 0 ? 1 : 0;
+ return strcmp(pattern, string) == 0 ? 1 : 0;
+}
+
+/* like pool_match_dep but uses matchdep_str to match the name for glob and nocase matching */
+static int
+matchdep(Pool *pool, Id id, char *rname, int rflags, Id revr, int flags)
+{
+ if (ISRELDEP(id))
+ {
+ Reldep *rd = GETRELDEP(pool, id);
+ if (rd->flags > 7)
+ {
+ if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_WITH || rd->flags == REL_WITHOUT || rd->flags == REL_COND || rd->flags == REL_UNLESS)
+ {
+ if (matchdep(pool, rd->name, rname, rflags, revr, flags))
+ return 1;
+ if ((rd->flags == REL_COND || rd->flags == REL_UNLESS) && ISRELDEP(rd->evr))
+ {
+ rd = GETRELDEP(pool, rd->evr);
+ if (rd->flags != REL_ELSE)
+ return 0;
+ }
+ if (rd->flags != REL_COND && rd->flags != REL_UNLESS && rd->flags != REL_WITHOUT && matchdep(pool, rd->evr, rname, rflags, revr, flags))
+ return 1;
+ return 0;
+ }
+ if (rd->flags == REL_ARCH)
+ return matchdep(pool, rd->name, rname, rflags, revr, flags);
+ }
+ if (!matchdep(pool, rd->name, rname, rflags, revr, flags))
+ return 0;
+ if (rflags && !pool_intersect_evrs(pool, rd->flags, rd->evr, rflags, revr))
+ return 0;
+ return 1;
+ }
+ return matchdep_str(rname, pool_id2str(pool, id), flags);
+}
+
+struct limiter {
+ int start; /* either 2 or repofilter->start */
+ int end; /* either nsolvables or repofilter->end */
+ Repo *repofilter;
+ Id *mapper;
+ Queue qlimit;
+};
+
+
+static int
+selection_make_matchsolvable_common(Pool *pool, Queue *selection, Queue *solvidq, Id solvid, int flags, int keyname, int marker, struct limiter *limiter)
+{
+ Map m, missc;
+ int reloff;
+ int li, i, j;
+ Id p;
+ Queue q;
+
+ if ((flags & SELECTION_MODEBITS) != SELECTION_REPLACE)
+ {
+ int ret;
+ Queue q;
+ queue_init(&q);
+ ret = selection_make_matchsolvable_common(pool, &q, solvidq, solvid, flags & ~SELECTION_MODEBITS, keyname, marker, limiter);
+ return selection_combine(pool, selection, &q, flags, ret);
+ }
+
+ queue_empty(selection);
+ if (!limiter->end)
+ return 0;
+ if (!solvidq && !solvid)
+ return 0;
+ if (solvidq && solvid)
+ return 0;
+
+ if (solvidq)
+ {
+ map_init(&m, pool->nsolvables);
+ for (i = 0; i < solvidq->count; i++)
+ MAPSET(&m, solvidq->elements[i]);
+ }
+ queue_init(&q);
+ reloff = pool->ss.nstrings;
+ map_init(&missc, reloff + pool->nrels);
+ for (li = limiter->start; li < limiter->end; li++)
+ {
+ Solvable *s;
+ p = limiter->mapper ? limiter->mapper[li] : li;
+ if (solvidq && MAPTST(&m, p))
+ continue;
+ if (!solvidq && p == solvid)
+ continue;
+ s = pool->solvables + p;
+ if (!s->repo || (limiter->repofilter && s->repo != limiter->repofilter))
+ continue;
+ if (!solvable_matches_selection_flags(pool, s, flags))
+ continue;
+ if (solvable_matchessolvable_int(s, keyname, marker, solvid, solvidq ? &m : 0, &q, &missc, reloff, 0))
+ queue_push(selection, p);
+ }
+ queue_free(&q);
+ map_free(&missc);
+ if (solvidq)
+ map_free(&m);
+
+ /* convert package list to selection */
+ if (!selection->count)
+ return 0;
+ j = selection->count;
+ queue_insertn(selection, 0, selection->count, 0);
+ for (i = 0; i < selection->count; i += 2)
+ {
+ selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
+ selection->elements[i + 1] = selection->elements[j++];
+ }
+ if ((flags & SELECTION_FLAT) != 0)
+ selection_flatten(pool, selection);
+ return SELECTION_PROVIDES;
+}
+
+static int
+selection_make_matchdeps_common(Pool *pool, Queue *selection, const char *name, Id dep, int flags, int keyname, int marker, struct limiter *limiter)
+{
+ int li, i, j;
+ int ret = 0;
+ char *rname = 0, *r = 0;
+ int rflags = 0;
+ Id revr = 0;
+ Id p;
+ Queue q;
+
+ if ((flags & SELECTION_MODEBITS) != SELECTION_REPLACE)
+ {
+ Queue q;
+ queue_init(&q);
+ ret = selection_make_matchdeps_common(pool, &q, name, dep, flags & ~SELECTION_MODEBITS, keyname, marker, limiter);
+ return selection_combine(pool, selection, &q, flags, ret);
+ }
+
+ queue_empty(selection);
+ if (!limiter->end)
+ return 0;
+ if (!name && !dep)
+ return 0;
+ if (name && dep)
+ return 0;
+
+ if ((flags & SELECTION_MATCH_DEPSTR) != 0)
+ flags &= ~SELECTION_REL;
+
+ if (name)
+ {
+ rname = solv_strdup(name);
+ if ((flags & SELECTION_REL) != 0)
+ {
+ if ((r = strpbrk(rname, "<=>")) != 0)
+ {
+ if ((r = splitrel(rname, r, &rflags)) == 0)
+ {
+ solv_free(rname);
+ return 0;
+ }
+ }
+ revr = pool_str2id(pool, r, 1);
+ ret |= SELECTION_REL;
+ }
+ if ((flags & SELECTION_GLOB) != 0 && strpbrk(rname, "[*?") == 0)
+ flags &= ~SELECTION_GLOB;
+
+ if ((flags & SELECTION_GLOB) == 0 && (flags & SELECTION_NOCASE) == 0 && (flags & SELECTION_MATCH_DEPSTR) == 0)
+ {
+ /* we can use the faster selection_make_matchdepid */
+ dep = pool_str2id(pool, rname, 1);
+ if (rflags)
+ dep = pool_rel2id(pool, dep, revr, rflags, 1);
+ rname = solv_free(rname);
+ name = 0;
+ }
+ }
+ if (dep)
+ {
+ if (keyname == SOLVABLE_NAME && (flags & SELECTION_MATCH_DEPSTR) != 0)
+ {
+ Reldep *rd;
+ if (!ISRELDEP(dep))
+ return 0;
+ rd = GETRELDEP(pool, dep);
+ if (!rd->name || rd->flags != REL_EQ)
+ return 0;
+ dep = rd->name;
+ rflags = rd->flags;
+ revr = rd->evr;
+ }
+ }
+
+ queue_init(&q);
+ for (li = limiter->start; li < limiter->end; li++)
+ {
+ Solvable *s;
+ p = limiter->mapper ? limiter->mapper[li] : li;
+ s = pool->solvables + p;
+ if (!s->repo || (limiter->repofilter && s->repo != limiter->repofilter))
+ continue;
+ if (!solvable_matches_selection_flags(pool, s, flags))
+ continue;
+ if (keyname == SOLVABLE_NAME) /* nevr match hack */
+ {
+ if (dep)
+ {
+ if ((flags & SELECTION_MATCH_DEPSTR) != 0)
+ {
+ if (s->name != dep || s->evr != revr)
+ continue;
+ }
+ else
+ {
+ if (!pool_match_nevr(pool, s, dep))
+ continue;
+ }
+ }
+ else
+ {
+ if ((flags & SELECTION_MATCH_DEPSTR) != 0) /* mis-use */
+ {
+ char *tmp = pool_tmpjoin(pool, pool_id2str(pool, s->name), " = ", pool_id2str(pool, s->evr));
+ if (!matchdep_str(rname, tmp, flags))
+ continue;
+ }
+ else
+ {
+ if (!matchdep(pool, s->name, rname, rflags, revr, flags))
+ continue;
+ if (rflags && !pool_intersect_evrs(pool, rflags, revr, REL_EQ, s->evr))
+ continue;
+ }
+ }
+ queue_push(selection, p);
+ continue;
+ }
+ if (q.count)
+ queue_empty(&q);
+ repo_lookup_deparray(s->repo, p, keyname, &q, marker);
+ if (!q.count)
+ continue;
+ if (dep)
+ {
+ if ((flags & SELECTION_MATCH_DEPSTR) != 0) /* mis-use */
+ {
+ for (i = 0; i < q.count; i++)
+ if (q.elements[i] == dep)
+ break;
+ }
+ else
+ {
+ for (i = 0; i < q.count; i++)
+ if (pool_match_dep(pool, q.elements[i], dep))
+ break;
+ }