improve magic epoch promotion code to work better when multiple epochs match
[platform/upstream/libsolv.git] / src / selection.c
1 /*
2  * Copyright (c) 2007, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /*
9  * selection.c
10  *
11  */
12
13 #define _GNU_SOURCE
14 #include <string.h>
15 #include <fnmatch.h>
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20
21 #include "selection.h"
22 #include "solver.h"
23 #include "evr.h"
24
25
26 static int
27 str2archid(Pool *pool, const char *arch)
28 {
29   Id id;
30   if (!*arch)
31     return 0;
32   id = pool_str2id(pool, arch, 0);
33   if (!id || id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH)
34     return id;
35   if (pool->id2arch && (id > pool->lastarch || !pool->id2arch[id]))
36     return 0;
37   return id;
38 }
39
40 static void
41 selection_prune(Pool *pool, Queue *selection)
42 {
43   int i, j;
44   Id p, pp;
45   for (i = j = 0; i < selection->count; i += 2)
46     {
47       Id select = selection->elements[i] & SOLVER_SELECTMASK;
48       p = 0;
49       if (select == SOLVER_SOLVABLE_ALL)
50         p = 1;
51       else if (select == SOLVER_SOLVABLE_REPO)
52         {
53           Solvable *s;
54           Repo *repo = pool_id2repo(pool, selection->elements[i + 1]);
55           if (repo)
56             FOR_REPO_SOLVABLES(repo, p, s)
57               break;
58         }
59       else
60         {
61           FOR_JOB_SELECT(p, pp, select, selection->elements[i + 1])
62             break;
63         }
64       if (!p)
65         continue;
66       selection->elements[j] = selection->elements[i];
67       selection->elements[j + 1] = selection->elements[i + 1];
68       j += 2;
69     }
70   queue_truncate(selection, j);
71 }
72
73
74 static int
75 selection_solvables_sortcmp(const void *ap, const void *bp, void *dp)
76 {
77   return *(const Id *)ap - *(const Id *)bp;
78 }
79
80 void
81 selection_solvables(Pool *pool, Queue *selection, Queue *pkgs)
82 {
83   int i, j;
84   Id p, pp, lastid;
85   queue_empty(pkgs);
86   for (i = 0; i < selection->count; i += 2)
87     {
88       Id select = selection->elements[i] & SOLVER_SELECTMASK;
89       if (select == SOLVER_SOLVABLE_ALL)
90         {
91           FOR_POOL_SOLVABLES(p)
92             queue_push(pkgs, p);
93         }
94       if (select == SOLVER_SOLVABLE_REPO)
95         {
96           Solvable *s;
97           Repo *repo = pool_id2repo(pool, selection->elements[i + 1]);
98           if (repo)
99             FOR_REPO_SOLVABLES(repo, p, s)
100               queue_push(pkgs, p);
101         }
102       else
103         {
104           FOR_JOB_SELECT(p, pp, select, selection->elements[i + 1])
105             queue_push(pkgs, p);
106         }
107     }
108   if (pkgs->count < 2)
109     return;
110   /* sort and unify */
111   solv_sort(pkgs->elements, pkgs->count, sizeof(Id), selection_solvables_sortcmp, NULL);
112   lastid = pkgs->elements[0];
113   for (i = j = 1; i < pkgs->count; i++)
114     if (pkgs->elements[i] != lastid)
115       pkgs->elements[j++] = lastid = pkgs->elements[i];
116   queue_truncate(pkgs, j);
117 }
118
119 static void
120 selection_flatten(Pool *pool, Queue *selection)
121 {
122   Queue q;
123   int i;
124   if (selection->count <= 1)
125     return;
126   for (i = 0; i < selection->count; i += 2)
127     if ((selection->elements[i] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
128       {
129         selection->elements[0] = selection->elements[i];
130         selection->elements[1] = selection->elements[i + 1];
131         queue_truncate(selection, 2);
132         return;
133       }
134   queue_init(&q);
135   selection_solvables(pool, selection, &q);
136   if (!q.count)
137     {
138       queue_empty(selection);
139       return;
140     }
141   queue_truncate(selection, 2);
142   if (q.count > 1)
143     {
144       selection->elements[0] = SOLVER_SOLVABLE_ONE_OF;
145       selection->elements[1] = pool_queuetowhatprovides(pool, &q);
146     }
147   else
148     {
149       selection->elements[0] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
150       selection->elements[1] = q.elements[0];
151     }
152 }
153
154 static void
155 selection_limit_rel(Pool *pool, Queue *selection, Id relflags, Id relevr)
156 {
157   int i;
158   for (i = 0; i < selection->count; i += 2)
159     {
160       Id select = selection->elements[i] & SOLVER_SELECTMASK;
161       Id id = selection->elements[i + 1];
162       if (select == SOLVER_SOLVABLE || select == SOLVER_SOLVABLE_ONE_OF)
163         {
164           /* done by selection_addsrc */
165           Queue q;
166           Id p, pp;
167           Id rel = 0, relname = 0;
168           int miss = 0;
169
170           queue_init(&q);
171           FOR_JOB_SELECT(p, pp, select, id)
172             {
173               Solvable *s = pool->solvables + p;
174               if (!rel || s->name != relname)
175                 {
176                   relname = s->name;
177                   rel = pool_rel2id(pool, relname, relevr, relflags, 1);
178                 }
179               if (pool_match_nevr(pool, s, rel))
180                 queue_push(&q, p);
181               else
182                 miss = 1;
183             }
184           if (miss)
185             {
186               if (q.count == 1)
187                 {
188                   selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
189                   selection->elements[i + 1] = q.elements[0];
190                 }
191               else
192                 {
193                   selection->elements[i] = SOLVER_SOLVABLE_ONE_OF;
194                   selection->elements[i + 1] = pool_queuetowhatprovides(pool, &q);
195                 }
196             }
197           queue_free(&q);
198           continue;
199         }
200       if (select != SOLVER_SOLVABLE_NAME && select != SOLVER_SOLVABLE_PROVIDES)
201         continue;       /* actually internal error */
202       if (relflags == REL_ARCH && (relevr == ARCH_SRC || relevr == ARCH_NOSRC) && ISRELDEP(id))
203         {
204           Reldep *rd = GETRELDEP(pool, id);
205           if (rd->flags == REL_ARCH && rd->evr == ARCH_SRC)
206             id = rd->name;
207         }
208       selection->elements[i + 1] = pool_rel2id(pool, id, relevr, relflags, 1);
209       if (relflags == REL_ARCH)
210         selection->elements[i] |= SOLVER_SETARCH;
211       if (relflags == REL_EQ && select == SOLVER_SOLVABLE_NAME && selection->elements[i])
212         {
213           if (pool->disttype == DISTTYPE_DEB)
214             selection->elements[i] |= SOLVER_SETEVR;    /* debian can't match version only like rpm */
215           else
216             selection->elements[i] |= strchr(pool_id2str(pool, relevr), '-') != 0 ? SOLVER_SETEVR : SOLVER_SETEV;
217         }
218     }
219   selection_prune(pool, selection);
220 }
221
222 static void
223 selection_addsrc(Pool *pool, Queue *selection, int flags)
224 {
225   Queue q;
226   Id p, name;
227   int i, havesrc;
228
229   if ((flags & SELECTION_INSTALLED_ONLY) != 0)
230     return;     /* sources can't be installed */
231   queue_init(&q);
232   for (i = 0; i < selection->count; i += 2)
233     {
234       if (selection->elements[i] != SOLVER_SOLVABLE_NAME)
235         continue;
236       name = selection->elements[i + 1];
237       havesrc = 0;
238       queue_empty(&q);
239       FOR_POOL_SOLVABLES(p)
240         {
241           Solvable *s = pool->solvables + p;
242           if (s->name != name)
243             continue;
244           if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
245             havesrc = 1;
246           else if (!pool_installable(pool, s))
247             continue;
248           queue_push(&q, p);
249         }
250       if (!havesrc || !q.count)
251         continue;
252       if (q.count == 1)
253         {
254           selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
255           selection->elements[i + 1] = q.elements[0];
256         }
257       else
258         {
259           selection->elements[i] = SOLVER_SOLVABLE_ONE_OF;
260           selection->elements[i + 1] = pool_queuetowhatprovides(pool, &q);
261         }
262     }
263   queue_free(&q);
264 }
265
266 static int
267 selection_depglob(Pool *pool, Queue *selection, const char *name, int flags)
268 {
269   Id id, p, pp;
270   int i, match = 0;
271   int doglob = 0;
272   int globflags = 0;
273
274   if ((flags & SELECTION_SOURCE_ONLY) != 0)
275     {
276       flags &= ~SELECTION_PROVIDES;     /* sources don't provide anything */
277       flags &= ~SELECTION_WITH_SOURCE;
278     }
279
280   if (!(flags & (SELECTION_NAME|SELECTION_PROVIDES)))
281     return 0;
282
283   if ((flags & SELECTION_INSTALLED_ONLY) != 0 && !pool->installed)
284     return 0;
285
286   if (!(flags & SELECTION_NOCASE))
287     {
288       id = pool_str2id(pool, name, 0);
289       if (id)
290         {
291           if ((flags & (SELECTION_SOURCE_ONLY | SELECTION_WITH_SOURCE)) != 0 && (flags & SELECTION_NAME) != 0)
292             {
293               /* src rpms don't have provides, so we must check every solvable */
294               FOR_PROVIDES(p, pp, id)   /* try fast path first */
295                 {
296                   Solvable *s = pool->solvables + p;
297                   if (s->name == id)
298                     {
299                       if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
300                         continue;
301                       if ((flags & SELECTION_SOURCE_ONLY) != 0)
302                         id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
303                       queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
304                       if ((flags & SELECTION_WITH_SOURCE) != 0)
305                         selection_addsrc(pool, selection, flags);
306                       return SELECTION_NAME;
307                     }
308                 }
309               FOR_POOL_SOLVABLES(p)     /* slow path */
310                 {
311                   Solvable *s = pool->solvables + p;
312                   if (s->name == id && (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC))
313                     {
314                       if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
315                         continue;       /* just in case... src rpms can't be installed */
316                       if ((flags & SELECTION_SOURCE_ONLY) != 0)
317                         id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
318                       queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
319                       if ((flags & SELECTION_WITH_SOURCE) != 0)
320                         selection_addsrc(pool, selection, flags);
321                       return SELECTION_NAME;
322                     }
323                 }
324             }
325           FOR_PROVIDES(p, pp, id)
326             {
327               Solvable *s = pool->solvables + p;
328               if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
329                 continue;
330               match = 1;
331               if (s->name == id && (flags & SELECTION_NAME) != 0)
332                 {
333                   if ((flags & SELECTION_SOURCE_ONLY) != 0)
334                     id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
335                   queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
336                   if ((flags & SELECTION_WITH_SOURCE) != 0)
337                     selection_addsrc(pool, selection, flags);
338                   return SELECTION_NAME;
339                 }
340             }
341           if (match && (flags & SELECTION_PROVIDES) != 0)
342             {
343               queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
344               return SELECTION_PROVIDES;
345             }
346         }
347     }
348
349   if ((flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0)
350     doglob = 1;
351
352   if (!doglob && !(flags & SELECTION_NOCASE))
353     return 0;
354
355   if (doglob && (flags & SELECTION_NOCASE) != 0)
356     globflags = FNM_CASEFOLD;
357
358 #if 0   /* doesn't work with selection_limit_rel yet */
359   if (doglob && !strcmp(name, "*") && (flags & SELECTION_FLAT) != 0)
360     {
361       /* can't do this for SELECTION_PROVIDES, as src rpms don't provide anything */
362       if ((flags & SELECTION_NAME) != 0)
363         {
364           queue_push2(selection, SOLVER_SOLVABLE_ALL, 0);
365           return SELECTION_NAME;
366         }
367     }
368 #endif
369
370   if ((flags & SELECTION_NAME) != 0)
371     {
372       /* looks like a name glob. hard work. */
373       FOR_POOL_SOLVABLES(p)
374         {
375           Solvable *s = pool->solvables + p;
376           if (!pool_installable(pool, s))
377             if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
378               continue;
379           if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
380             continue;
381           id = s->name;
382           if ((doglob ? fnmatch(name, pool_id2str(pool, id), globflags) : strcasecmp(name, pool_id2str(pool, id))) == 0)
383             {
384               if ((flags & SELECTION_SOURCE_ONLY) != 0)
385                 id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
386               /* queue_pushunique2 */
387               for (i = 0; i < selection->count; i += 2)
388                 if (selection->elements[i] == SOLVER_SOLVABLE_NAME && selection->elements[i + 1] == id)
389                   break;
390               if (i == selection->count)
391                 queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
392               match = 1;
393             }
394         }
395       if (match)
396         {
397           if ((flags & SELECTION_WITH_SOURCE) != 0)
398             selection_addsrc(pool, selection, flags);
399           return SELECTION_NAME;
400         }
401     }
402   if ((flags & SELECTION_PROVIDES))
403     {
404       /* looks like a dep glob. really hard work. */
405       for (id = 1; id < pool->ss.nstrings; id++)
406         {
407           if (!pool->whatprovides[id])
408             continue;
409           if ((doglob ? fnmatch(name, pool_id2str(pool, id), globflags) : strcasecmp(name, pool_id2str(pool, id))) == 0)
410             {
411               if ((flags & SELECTION_INSTALLED_ONLY) != 0)
412                 {
413                   FOR_PROVIDES(p, pp, id)
414                     if (pool->solvables[p].repo == pool->installed)
415                       break;
416                   if (!p)
417                     continue;
418                 }
419               queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
420               match = 1;
421             }
422         }
423       if (match)
424         return SELECTION_PROVIDES;
425     }
426   return 0;
427 }
428
429 static int
430 selection_depglob_arch(Pool *pool, Queue *selection, const char *name, int flags)
431 {
432   int ret;
433   const char *r;
434   Id archid;
435
436   if ((ret = selection_depglob(pool, selection, name, flags)) != 0)
437     return ret;
438   /* check if theres an .arch suffix */
439   if ((r = strrchr(name, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
440     {
441       char *rname = solv_strdup(name);
442       rname[r - name] = 0;
443       if (archid == ARCH_SRC || archid == ARCH_NOSRC)
444         flags |= SELECTION_SOURCE_ONLY;
445       if ((ret = selection_depglob(pool, selection, rname, flags)) != 0)
446         {
447           selection_limit_rel(pool, selection, REL_ARCH, archid);
448           solv_free(rname);
449           return ret;
450         }
451       solv_free(rname);
452     }
453   return 0;
454 }
455
456 static int
457 selection_filelist(Pool *pool, Queue *selection, const char *name, int flags)
458 {
459   Dataiterator di;
460   Queue q;
461   int type;
462
463   type = !(flags & SELECTION_GLOB) || strpbrk(name, "[*?") == 0 ? SEARCH_STRING : SEARCH_GLOB;
464   if ((flags & SELECTION_NOCASE) != 0)
465     type |= SEARCH_NOCASE;
466   queue_init(&q);
467   dataiterator_init(&di, pool, flags & SELECTION_INSTALLED_ONLY ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES|SEARCH_COMPLETE_FILELIST);
468   while (dataiterator_step(&di))
469     {
470       Solvable *s = pool->solvables + di.solvid;
471       if (!s->repo)
472         continue;
473       if (!pool_installable(pool, s))
474         if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
475           continue;
476       if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
477         continue;
478       queue_push(&q, di.solvid);
479       dataiterator_skip_solvable(&di);
480     }
481   dataiterator_free(&di);
482   if (!q.count)
483     return 0;
484   if (q.count > 1) 
485     queue_push2(selection, SOLVER_SOLVABLE_ONE_OF, pool_queuetowhatprovides(pool, &q));
486   else
487     queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, q.elements[0]);
488   queue_free(&q);
489   return SELECTION_FILELIST;
490 }
491
492 static int
493 selection_rel(Pool *pool, Queue *selection, const char *name, int flags)
494 {
495   int ret, rflags = 0;
496   char *r, *rname;
497   
498   /* relation case, support:
499    * depglob rel
500    * depglob.arch rel
501    */
502   rname = solv_strdup(name);
503   if ((r = strpbrk(rname, "<=>")) != 0)
504     {
505       int nend = r - rname;
506       for (; *r; r++)
507         {
508           if (*r == '<')
509             rflags |= REL_LT;
510           else if (*r == '=')
511             rflags |= REL_EQ;
512           else if (*r == '>')
513             rflags |= REL_GT;
514           else
515             break;
516         }
517       while (*r && *r == ' ' && *r == '\t')
518         r++;
519       while (nend && (rname[nend - 1] == ' ' || rname[nend -1 ] == '\t'))
520         nend--;
521       if (!*rname || !*r)
522         {
523           solv_free(rname);
524           return 0;
525         }
526       rname[nend] = 0;
527     }
528   if ((ret = selection_depglob_arch(pool, selection, rname, flags)) != 0)
529     {
530       if (rflags)
531         selection_limit_rel(pool, selection, rflags, pool_str2id(pool, r, 1));
532       solv_free(rname);
533       return ret;
534     }
535   solv_free(rname);
536   return 0;
537 }
538
539 #if defined(MULTI_SEMANTICS)
540 # define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE)
541 #elif defined(DEBIAN)
542 # define EVRCMP_DEPCMP EVRCMP_COMPARE
543 #else
544 # define EVRCMP_DEPCMP EVRCMP_MATCH_RELEASE
545 #endif
546
547 /* magic epoch promotion code, works only for SELECTION_NAME selections */
548 static void
549 selection_limit_evr(Pool *pool, Queue *selection, char *evr)
550 {
551   int i, j;
552   Queue q;
553   Id qbuf[10];
554
555   queue_init(&q);
556   queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
557   for (i = j = 0; i < selection->count; i += 2)
558     {
559       Id select = selection->elements[i] & SOLVER_SELECTMASK;
560       Id id = selection->elements[i + 1];
561       Id p, pp;
562       const char *lastepoch = 0;
563       int lastepochlen = 0;
564
565       queue_empty(&q);
566       FOR_JOB_SELECT(p, pp, select, id)
567         {
568           Solvable *s = pool->solvables + p;
569           const char *sevr = pool_id2str(pool, s->evr);
570           const char *sp;
571           for (sp = sevr; *sp >= '0' && *sp <= '9'; sp++)
572             ;
573           if (*sp != ':')
574             sp = sevr;
575           /* compare vr part */
576           if (strcmp(evr, sp != sevr ? sp + 1 : sevr) != 0)
577             {
578               int r = pool_evrcmp_str(pool, sp != sevr ? sp + 1 : sevr, evr, EVRCMP_DEPCMP);
579               if (r == -1 || r == 1)
580                 continue;       /* solvable does not match vr */
581             }
582           queue_push(&q, p);
583           if (sp > sevr)
584             {
585               while (sevr < sp && *sevr == '0') /* normalize */
586                 sevr++;
587             }
588           if (!lastepoch)
589             {
590               lastepoch = sevr;
591               lastepochlen = sp - sevr;
592             }
593           else if (lastepochlen != sp - sevr || strncmp(lastepoch, sevr, lastepochlen) != 0)
594             lastepochlen = -1;  /* multiple different epochs */
595         }
596       if (!lastepoch || lastepochlen == 0)
597         id = pool_str2id(pool, evr, 1);         /* no match at all or zero epoch */
598       else if (lastepochlen >= 0)
599         {
600           /* found exactly one epoch, simlpy prepend */
601           char *evrx = solv_malloc(strlen(evr) + lastepochlen + 2);
602           strncpy(evrx, lastepoch, lastepochlen + 1);
603           strcpy(evrx + lastepochlen + 1, evr);
604           id = pool_str2id(pool, evrx, 1);
605           solv_free(evrx);
606         }
607       else
608         {
609           /* multiple epochs in multiple solvables, convert to listy of solvables */
610           selection->elements[j] = (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF;
611           selection->elements[j + 1] = pool_queuetowhatprovides(pool, &q);
612           j += 2;
613           continue;
614         }
615       queue_empty(&q);
616       queue_push2(&q, selection->elements[i], selection->elements[i + 1]);
617       selection_limit_rel(pool, &q, REL_EQ, id);
618       if (!q.count)
619         {
620           queue_free(&q);
621           continue;             /* oops, no match */
622         }
623       selection->elements[j] = q.elements[0];
624       selection->elements[j + 1] = q.elements[1];
625       j += 2;
626     }
627   queue_truncate(selection, j);
628   queue_free(&q);
629 }
630
631 static int
632 selection_nevra(Pool *pool, Queue *selection, const char *name, int flags)
633 {
634   char *rname, *r, *r2;
635   Id archid = 0;
636   int ret;
637
638   /*
639    * nameglob-version
640    * nameglob-version.arch
641    * nameglob-version-release
642    * nameglob-version-release.arch
643    */
644   flags |= SELECTION_NAME;
645   flags &= ~SELECTION_PROVIDES;
646
647   if (pool->disttype == DISTTYPE_DEB)
648     {
649       if ((r = strchr(name, '_')) == 0)
650         return 0;
651       rname = solv_strdup(name);        /* so we can modify it */
652       r = rname + (r - name);
653       *r++ = 0;
654       if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
655         {
656           solv_free(rname);
657           return 0;
658         }
659       /* is there a vaild arch? */
660       if ((r2 = strchr(r, '_')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
661         {
662           *r2 = 0;      /* split off */
663           selection_limit_rel(pool, selection, REL_ARCH, archid);
664         }
665       selection_limit_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1));
666       solv_free(rname);
667       return ret;
668     }
669
670   if ((r = strrchr(name, '-')) == 0)
671     return 0;
672   rname = solv_strdup(name);    /* so we can modify it */
673   r = rname + (r - name);
674   *r = 0; 
675
676   /* split off potential arch part from version */
677   if ((r2 = strrchr(r + 1, '.')) != 0 && r2[1] && (archid = str2archid(pool, r2 + 1)) != 0)
678     *r2 = 0;    /* found valid arch, split it off */
679   if (archid == ARCH_SRC || archid == ARCH_NOSRC)
680     flags |= SELECTION_SOURCE_ONLY;
681
682   /* try with just the version */
683   if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
684     {
685       /* no luck, try with version-release */
686       if ((r2 = strrchr(rname, '-')) == 0)
687         {
688           solv_free(rname);
689           return 0;
690         }
691       *r = '-'; 
692       *r2 = 0; 
693       r = r2;
694       if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
695         {
696           solv_free(rname);
697           return 0;
698         }
699     }
700   if (archid)
701     selection_limit_rel(pool, selection, REL_ARCH, archid);
702   selection_limit_evr(pool, selection, r + 1);  /* magic epoch promotion */
703   solv_free(rname);
704   return ret;
705 }
706
707 int
708 selection_make(Pool *pool, Queue *selection, const char *name, int flags)
709 {
710   int ret = 0;
711   const char *r;
712
713   queue_empty(selection);
714   if (*name == '/' && (flags & SELECTION_FILELIST))
715     ret = selection_filelist(pool, selection, name, flags);
716   if (!ret && (r = strpbrk(name, "<=>")) != 0)
717     ret = selection_rel(pool, selection, name, flags);
718   if (!ret)
719     ret = selection_depglob_arch(pool, selection, name, flags);
720   if (!ret && (flags & SELECTION_NAME) != 0)
721     ret = selection_nevra(pool, selection, name, flags);
722   if (ret && (flags & SELECTION_FLAT) != 0)
723     selection_flatten(pool, selection);
724   return ret;
725 }
726
727 void
728 selection_limit(Pool *pool, Queue *sel1, Queue *sel2)
729 {
730   int i, j, miss;
731   Id p, pp;
732   Queue q1;
733   Map m2;
734   Id setflags = 0;
735
736   if (!sel1->count || !sel2->count)
737     {
738       queue_empty(sel1);
739       return;
740     }
741   if (sel1->count == 2 && (sel1->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
742     {
743       /* XXX: not 100% correct, but very useful */
744       queue_free(sel1);
745       queue_init_clone(sel1, sel2);
746       return;
747     }
748   queue_init(&q1);
749   map_init(&m2, pool->nsolvables);
750   for (i = 0; i < sel2->count; i += 2)
751     {
752       Id select = sel2->elements[i] & SOLVER_SELECTMASK;
753       if (select == SOLVER_SOLVABLE_ALL)
754         return;
755       if (select == SOLVER_SOLVABLE_REPO)
756         {
757           Solvable *s;
758           Repo *repo = pool_id2repo(pool, sel2->elements[i + 1]);
759           if (repo)
760             FOR_REPO_SOLVABLES(repo, p, s)
761               map_set(&m2, p);
762         }
763       else
764         {
765           FOR_JOB_SELECT(p, pp, select, sel2->elements[i + 1])
766             map_set(&m2, p);
767         }
768     }
769   if (sel2->count == 2)         /* XXX: AND all setmasks instead? */
770     setflags = sel2->elements[0] & SOLVER_SETMASK & ~SOLVER_NOAUTOSET;
771   for (i = j = 0; i < sel1->count; i += 2)
772     {
773       Id select = sel1->elements[i] & SOLVER_SELECTMASK;
774       queue_empty(&q1);
775       miss = 0;
776       if (select == SOLVER_SOLVABLE_ALL)
777         {
778           FOR_POOL_SOLVABLES(p)
779             {
780               if (map_tst(&m2, p))
781                 queue_push(&q1, p);
782               else
783                 miss = 1;
784             }
785         }
786       else if (select == SOLVER_SOLVABLE_REPO)
787         {
788           Solvable *s;
789           Repo *repo = pool_id2repo(pool, sel1->elements[i + 1]);
790           if (repo)
791             FOR_REPO_SOLVABLES(repo, p, s)
792               {
793                 if (map_tst(&m2, p))
794                   queue_push(&q1, p);
795                 else
796                   miss = 1;
797               }
798         }
799       else
800         {
801           FOR_JOB_SELECT(p, pp, select, sel1->elements[i + 1])
802             {
803               if (map_tst(&m2, p))
804                 queue_pushunique(&q1, p);
805               else
806                 miss = 1;
807             }
808         }
809       if (!q1.count)
810         continue;
811       if (!miss)
812         {
813           sel1->elements[j] = sel1->elements[i] | setflags;
814           sel1->elements[j + 1] = sel1->elements[i + 1];
815         }
816       else if (q1.count > 1) 
817         {
818           sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF | setflags;
819           sel1->elements[j + 1] = pool_queuetowhatprovides(pool, &q1);
820         }
821       else
822         {
823           sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE | SOLVER_NOAUTOSET | setflags;
824           sel1->elements[j + 1] = q1.elements[0];
825         }
826       j += 2;
827     }
828   queue_truncate(sel1, j);
829 }
830
831 void
832 selection_add(Pool *pool, Queue *sel1, Queue *sel2)
833 {
834   int i;
835   for (i = 0; i < sel2->count; i++)
836     queue_push(sel1, sel2->elements[i]);
837 }
838