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