2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
21 #include "selection.h"
26 str2archid(Pool *pool, const char *arch)
31 id = pool_str2id(pool, arch, 0);
32 if (!id || id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH)
34 if (pool->id2arch && (id > pool->lastarch || !pool->id2arch[id]))
40 selection_prune(Pool *pool, Queue *selection)
44 for (i = j = 0; i < selection->count; i += 2)
46 Id select = selection->elements[i] & SOLVER_SELECTMASK;
48 if (select == SOLVER_SOLVABLE_ALL)
50 else if (select == SOLVER_SOLVABLE_REPO)
53 Repo *repo = pool_id2repo(pool, selection->elements[i + 1]);
55 FOR_REPO_SOLVABLES(repo, p, s)
60 FOR_JOB_SELECT(p, pp, select, selection->elements[i + 1])
65 selection->elements[j] = selection->elements[i];
66 selection->elements[j + 1] = selection->elements[i + 1];
69 queue_truncate(selection, j);
74 selection_flatten_sortcmp(const void *ap, const void *bp, void *dp)
76 return *(const Id *)ap - *(const Id *)bp;
80 selection_flatten(Pool *pool, Queue *selection)
85 if (selection->count <= 1)
88 for (i = 0; i < selection->count; i += 2)
90 Id select = selection->elements[i] & SOLVER_SELECTMASK;
91 if (select == SOLVER_SOLVABLE_ALL)
93 selection->elements[0] = selection->elements[i];
94 selection->elements[1] = selection->elements[i + 1];
95 queue_truncate(selection, 2);
98 if (select == SOLVER_SOLVABLE_REPO)
101 Repo *repo = pool_id2repo(pool, selection->elements[i + 1]);
103 FOR_REPO_SOLVABLES(repo, p, s)
108 FOR_JOB_SELECT(p, pp, select, selection->elements[i + 1])
114 queue_empty(selection);
120 solv_sort(q.elements, q.count, sizeof(Id), selection_flatten_sortcmp, NULL);
121 lastid = q.elements[0];
122 for (i = j = 1; i < q.count; i++)
123 if (q.elements[i] != lastid)
124 q.elements[j++] = lastid = q.elements[i];
125 queue_truncate(&q, j);
127 queue_truncate(selection, 2);
130 selection->elements[0] = SOLVER_SOLVABLE_ONE_OF;
131 selection->elements[1] = pool_queuetowhatprovides(pool, &q);
135 selection->elements[0] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
136 selection->elements[1] = q.elements[0];
141 selection_limit_rel(Pool *pool, Queue *selection, Id flags, Id evr)
144 for (i = j = 0; i < selection->count; i += 2)
146 Id select = selection->elements[i] & SOLVER_SELECTMASK;
147 if (select != SOLVER_SOLVABLE_NAME && select != SOLVER_SOLVABLE_PROVIDES)
148 continue; /* actually internal error */
149 selection->elements[i + 1] = pool_rel2id(pool, selection->elements[i + 1], evr, flags, 1);
150 if (flags == REL_ARCH)
151 selection->elements[i] |= SOLVER_SETARCH;
152 if (flags == REL_EQ && select == SOLVER_SOLVABLE_NAME && selection->elements[i])
154 if (pool->disttype == DISTTYPE_DEB)
155 selection->elements[i] |= SOLVER_SETEVR; /* debian can't match version only like rpm */
157 selection->elements[i] |= strchr(pool_id2str(pool, evr), '-') != 0 ? SOLVER_SETEVR : SOLVER_SETEV;
160 selection_prune(pool, selection);
164 selection_depglob(Pool *pool, Queue *selection, const char *name, int flags)
171 if (!(flags & (SELECTION_NAME|SELECTION_PROVIDES)))
174 if ((flags & SELECTION_INSTALLED_ONLY) != 0 && !pool->installed)
177 if (!(flags & SELECTION_NOCASE))
179 id = pool_str2id(pool, name, 0);
182 FOR_PROVIDES(p, pp, id)
184 Solvable *s = pool->solvables + p;
185 if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
188 if (s->name == id && (flags & SELECTION_NAME) != 0)
190 queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
191 return SELECTION_NAME;
194 if (match && (flags & SELECTION_PROVIDES) != 0)
196 queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
197 return SELECTION_PROVIDES;
202 if ((flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0)
205 if (!doglob && !(flags & SELECTION_NOCASE))
208 if (doglob && (flags & SELECTION_NOCASE) != 0)
209 globflags = FNM_CASEFOLD;
211 #if 0 /* doesn't work with selection_limit_rel yet */
212 if (doglob && !strcmp(name, "*") && (flags & SELECTION_FLAT) != 0)
214 /* can't do this for SELECTION_PROVIDES, as src rpms don't provide anything */
215 if ((flags & SELECTION_NAME) != 0)
217 queue_push2(selection, SOLVER_SOLVABLE_ALL, 0);
218 return SELECTION_NAME;
223 if ((flags & SELECTION_NAME) != 0)
225 /* looks like a name glob. hard work. */
226 for (p = 1; p < pool->nsolvables; p++)
228 Solvable *s = pool->solvables + p;
229 if (!s->repo || !pool_installable(pool, s))
231 if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
234 if ((doglob ? fnmatch(name, pool_id2str(pool, id), globflags) : strcasecmp(name, pool_id2str(pool, id))) == 0)
236 for (i = 0; i < selection->count; i += 2)
237 if (selection->elements[i] == SOLVER_SOLVABLE_NAME && selection->elements[i + 1] == id)
239 if (i == selection->count)
240 queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
245 return SELECTION_NAME;
247 if ((flags & SELECTION_PROVIDES))
249 /* looks like a dep glob. really hard work. */
250 for (id = 1; id < pool->ss.nstrings; id++)
252 if (!pool->whatprovides[id])
254 if ((doglob ? fnmatch(name, pool_id2str(pool, id), globflags) : strcasecmp(name, pool_id2str(pool, id))) == 0)
256 if ((flags & SELECTION_INSTALLED_ONLY) != 0)
258 FOR_PROVIDES(p, pp, id)
259 if (pool->solvables[p].repo == pool->installed)
264 queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
269 return SELECTION_PROVIDES;
275 selection_depglob_arch(Pool *pool, Queue *selection, const char *name, int flags)
281 if ((ret = selection_depglob(pool, selection, name, flags)) != 0)
283 /* check if theres an .arch suffix */
284 if ((r = strrchr(name, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
286 char *rname = solv_strdup(name);
288 if ((ret = selection_depglob(pool, selection, rname, flags)) != 0)
290 selection_limit_rel(pool, selection, REL_ARCH, archid);
300 selection_filelist(Pool *pool, Queue *selection, const char *name, int flags)
306 type = !(flags & SELECTION_GLOB) || strpbrk(name, "[*?") == 0 ? SEARCH_STRING : SEARCH_GLOB;
307 if ((flags & SELECTION_NOCASE) != 0)
308 type |= SEARCH_NOCASE;
310 dataiterator_init(&di, pool, flags & SELECTION_INSTALLED_ONLY ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES|SEARCH_COMPLETE_FILELIST);
311 while (dataiterator_step(&di))
313 Solvable *s = pool->solvables + di.solvid;
314 if (!s->repo || !pool_installable(pool, s))
316 queue_push(&q, di.solvid);
317 dataiterator_skip_solvable(&di);
319 dataiterator_free(&di);
323 queue_push2(selection, SOLVER_SOLVABLE_ONE_OF, pool_queuetowhatprovides(pool, &q));
325 queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, q.elements[0]);
327 return SELECTION_FILELIST;
331 selection_rel(Pool *pool, Queue *selection, const char *name, int flags)
336 /* relation case, support:
340 rname = solv_strdup(name);
341 if ((r = strpbrk(rname, "<=>")) != 0)
343 int nend = r - rname;
355 while (*r && *r == ' ' && *r == '\t')
357 while (nend && (rname[nend - 1] == ' ' || rname[nend -1 ] == '\t'))
366 if ((ret = selection_depglob_arch(pool, selection, rname, flags)) != 0)
369 selection_limit_rel(pool, selection, rflags, pool_str2id(pool, r, 1));
378 selection_nevra(Pool *pool, Queue *selection, const char *name, int flags)
380 char *rname, *r, *r2;
386 * nameglob-version.arch
387 * nameglob-version-release
388 * nameglob-version-release.arch
390 flags |= SELECTION_NAME;
391 flags &= ~SELECTION_PROVIDES;
393 if (pool->disttype == DISTTYPE_DEB)
395 if ((r = strchr(name, '_')) == 0)
397 rname = solv_strdup(name); /* so we can modify it */
398 r = rname + (r - name);
400 if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
405 /* is there a vaild arch? */
406 if ((r2 = strchr(r, '_')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
408 *r2 = 0; /* split off */
409 selection_limit_rel(pool, selection, REL_ARCH, archid);
411 selection_limit_rel(pool, selection, flags, pool_str2id(pool, r, 1));
416 if ((r = strrchr(name, '-')) == 0)
418 rname = solv_strdup(name); /* so we can modify it */
419 r = rname + (r - name);
421 /* try with just the version */
422 if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
424 /* no luck, try with version-release */
425 if ((r2 = strrchr(rname, '-')) == 0)
433 if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
439 /* we now know the name, check if we need to split of the arch */
441 if ((r2 = strrchr(r, '.')) != 0 && r2[1] && (archid = str2archid(pool, r2 + 1)) != 0)
443 /* found valid arch, split it off */
445 selection_limit_rel(pool, selection, REL_ARCH, archid);
447 selection_limit_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1));
453 selection_make(Pool *pool, Queue *selection, const char *name, int flags)
458 queue_empty(selection);
459 if (*name == '/' && (flags & SELECTION_FILELIST))
460 ret = selection_filelist(pool, selection, name, flags);
461 if (!ret && (r = strpbrk(name, "<=>")) != 0)
462 ret = selection_rel(pool, selection, name, flags);
464 ret = selection_depglob_arch(pool, selection, name, flags);
465 if (!ret && (flags & SELECTION_NAME) != 0)
466 ret = selection_nevra(pool, selection, name, flags);
467 if (ret && (flags & SELECTION_FLAT) != 0)
468 selection_flatten(pool, selection);
473 selection_limit(Pool *pool, Queue *sel1, Queue *sel2)
481 if (!sel1->count || !sel2->count)
486 if (sel1->count == 2 && (sel1->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
488 /* XXX: not 100% correct, but very useful */
490 queue_init_clone(sel1, sel2);
494 map_init(&m2, pool->nsolvables);
495 for (i = 0; i < sel2->count; i += 2)
497 Id select = sel2->elements[i] & SOLVER_SELECTMASK;
498 if (select == SOLVER_SOLVABLE_ALL)
500 if (select == SOLVER_SOLVABLE_REPO)
503 Repo *repo = pool_id2repo(pool, sel2->elements[i + 1]);
505 FOR_REPO_SOLVABLES(repo, p, s)
510 FOR_JOB_SELECT(p, pp, select, sel2->elements[i + 1])
514 if (sel2->count == 2) /* XXX: AND all setmasks instead? */
515 setflags = sel2->elements[0] & SOLVER_SETMASK & ~SOLVER_NOAUTOSET;
516 for (i = j = 0; i < sel1->count; i += 2)
518 Id select = sel1->elements[i] & SOLVER_SELECTMASK;
521 if (select == SOLVER_SOLVABLE_ALL)
523 for (p = 2; p < pool->nsolvables; p++)
529 else if (select == SOLVER_SOLVABLE_REPO)
532 Repo *repo = pool_id2repo(pool, sel1->elements[i + 1]);
534 FOR_REPO_SOLVABLES(repo, p, s)
544 FOR_JOB_SELECT(p, pp, select, sel1->elements[i + 1])
547 queue_pushunique(&q1, p);
556 sel1->elements[j] = sel1->elements[i] | setflags;
557 sel1->elements[j + 1] = sel1->elements[i + 1];
559 else if (q1.count > 1)
561 sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF | setflags;
562 sel1->elements[j + 1] = pool_queuetowhatprovides(pool, &q1);
566 sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE | SOLVER_NOAUTOSET | setflags;
567 sel1->elements[j + 1] = q1.elements[0];
571 queue_truncate(sel1, j);
575 selection_add(Pool *pool, Queue *sel1, Queue *sel2)
578 for (i = 0; i < sel2->count; i++)
579 queue_push(sel1, sel2->elements[i]);