5f01e2b501f8feb4befa22e4dfb945649ba05f04
[platform/upstream/libsolv.git] / src / selection.c
1 /*
2  * Copyright (c) 2012, 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 #ifdef ENABLE_CONDA
25 #include "conda.h"
26 #endif
27
28 #ifdef _WIN32
29 #include "strfncs.h"
30 #endif
31
32 static int
33 str2archid(Pool *pool, const char *arch)
34 {
35   Id id;
36   if (!*arch)
37     return 0;
38   id = pool_str2id(pool, arch, 0);
39   if (!id || id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH)
40     return id;
41   if (pool->id2arch && pool_arch2score(pool, id) == 0)
42     return 0;
43   return id;
44 }
45
46 /* remove empty jobs from the selection */
47 static void
48 selection_prune(Pool *pool, Queue *selection)
49 {
50   int i, j;
51   Id p, pp;
52   for (i = j = 0; i < selection->count; i += 2)
53     {
54       Id select = selection->elements[i] & SOLVER_SELECTMASK;
55       p = 0;
56       if (select == SOLVER_SOLVABLE_ALL)
57         p = 1;
58       else if (select == SOLVER_SOLVABLE_REPO)
59         {
60           Solvable *s;
61           Repo *repo = pool_id2repo(pool, selection->elements[i + 1]);
62           if (repo)
63             {
64               FOR_REPO_SOLVABLES(repo, p, s)
65                 break;
66             }
67         }
68       else
69         {
70           FOR_JOB_SELECT(p, pp, select, selection->elements[i + 1])
71             break;
72         }
73       if (!p)
74         continue;
75       selection->elements[j] = selection->elements[i];
76       selection->elements[j + 1] = selection->elements[i + 1];
77       j += 2;
78     }
79   queue_truncate(selection, j);
80 }
81
82
83 static int
84 selection_solvables_sortcmp(const void *ap, const void *bp, void *dp)
85 {
86   return *(const Id *)ap - *(const Id *)bp;
87 }
88
89 void
90 selection_solvables(Pool *pool, Queue *selection, Queue *pkgs)
91 {
92   int i, j;
93   Id p, pp, lastid;
94   queue_empty(pkgs);
95   for (i = 0; i < selection->count; i += 2)
96     {
97       Id select = selection->elements[i] & SOLVER_SELECTMASK;
98       Id id = selection->elements[i + 1];
99       if (select == SOLVER_SOLVABLE_ALL)
100         {
101           FOR_POOL_SOLVABLES(p)
102             queue_push(pkgs, p);
103         }
104       if (select == SOLVER_SOLVABLE_REPO)
105         {
106           Solvable *s;
107           Repo *repo = pool_id2repo(pool, id);
108           if (repo)
109             {
110               FOR_REPO_SOLVABLES(repo, p, s)
111                 queue_push(pkgs, p);
112             }
113         }
114       else if (select == SOLVER_SOLVABLE)
115         queue_push(pkgs, id);
116       else
117         {
118           FOR_JOB_SELECT(p, pp, select, id)
119             queue_push(pkgs, p);
120         }
121     }
122   if (pkgs->count < 2)
123     return;
124   /* sort and unify */
125   solv_sort(pkgs->elements, pkgs->count, sizeof(Id), selection_solvables_sortcmp, NULL);
126   lastid = pkgs->elements[0];
127   for (i = j = 1; i < pkgs->count; i++)
128     if (pkgs->elements[i] != lastid)
129       pkgs->elements[j++] = lastid = pkgs->elements[i];
130   queue_truncate(pkgs, j);
131 }
132
133 static void
134 selection_flatten(Pool *pool, Queue *selection)
135 {
136   Queue q;
137   int i;
138   if (selection->count <= 2)
139     return;
140   for (i = 0; i < selection->count; i += 2)
141     if ((selection->elements[i] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
142       {
143         selection->elements[0] = selection->elements[i];
144         selection->elements[1] = selection->elements[i + 1];
145         queue_truncate(selection, 2);
146         return;
147       }
148   queue_init(&q);
149   selection_solvables(pool, selection, &q);
150   if (!q.count)
151     {
152       queue_empty(selection);
153       return;
154     }
155   queue_truncate(selection, 2);
156   if (q.count > 1)
157     {
158       selection->elements[0] = SOLVER_SOLVABLE_ONE_OF;
159       selection->elements[1] = pool_queuetowhatprovides(pool, &q);
160     }
161   else
162     {
163       selection->elements[0] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
164       selection->elements[1] = q.elements[0];
165     }
166 }
167
168 /* only supports simple rels plus REL_ARCH */
169 static int
170 match_nevr_rel(Pool *pool, Solvable *s, Id rflags, Id revr)
171 {
172   if (rflags == REL_ARCH)
173     {
174       if (s->arch != revr) 
175         {
176           if (revr != ARCH_SRC || s->arch != ARCH_NOSRC)
177             return 0;
178         }
179       return 1;
180     }
181   if (rflags > 7)
182     return 0;
183   return pool_intersect_evrs(pool, REL_EQ, s->evr, rflags, revr);
184 }
185
186 /* only supports simple rels plus REL_ARCH */
187 static void
188 selection_filter_rel_noprune(Pool *pool, Queue *selection, Id relflags, Id relevr)
189 {
190   int i;
191
192   if (!selection->count)
193     return;
194
195   for (i = 0; i < selection->count; i += 2)
196     {
197       Id select = selection->elements[i] & SOLVER_SELECTMASK;
198       Id id = selection->elements[i + 1];
199       if (select == SOLVER_SOLVABLE || select == SOLVER_SOLVABLE_ONE_OF)
200         {
201           /* done by selection_addextra, currently implies SELECTION_NAME */
202           Queue q;
203           Id p, pp;
204           int miss = 0;
205
206           queue_init(&q);
207           FOR_JOB_SELECT(p, pp, select, id)
208             {
209               Solvable *s = pool->solvables + p;
210               if (match_nevr_rel(pool, s, relflags, relevr))
211                 queue_push(&q, p);
212               else
213                 miss = 1;
214             }
215           if (miss)
216             {
217               if (q.count == 1)
218                 {
219                   selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
220                   selection->elements[i + 1] = q.elements[0];
221                 }
222               else
223                 {
224                   selection->elements[i] = SOLVER_SOLVABLE_ONE_OF;
225                   selection->elements[i + 1] = pool_queuetowhatprovides(pool, &q);
226                 }
227             }
228           queue_free(&q);
229         }
230       else if (select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES)
231         {
232           /* don't stack src reldeps */
233           if (relflags == REL_ARCH && (relevr == ARCH_SRC || relevr == ARCH_NOSRC) && ISRELDEP(id))
234             {
235               Reldep *rd = GETRELDEP(pool, id);
236               if (rd->flags == REL_ARCH && rd->evr == ARCH_SRC)
237                 id = rd->name;
238             }
239           selection->elements[i + 1] = pool_rel2id(pool, id, relevr, relflags, 1);
240         }
241       else
242         continue;       /* actually cannot happen */
243
244       /* now add the setflags we gained */
245       if (relflags == REL_ARCH)
246         selection->elements[i] |= SOLVER_SETARCH;
247       if (relflags == REL_EQ && select != SOLVER_SOLVABLE_PROVIDES)
248         {
249           if (pool->disttype == DISTTYPE_DEB)
250             selection->elements[i] |= SOLVER_SETEVR;    /* debian can't match version only like rpm */
251           else
252             {
253               const char *rel =  strrchr(pool_id2str(pool, relevr), '-');
254               selection->elements[i] |= rel ? SOLVER_SETEVR : SOLVER_SETEV;
255             }
256         }
257     }
258 }
259
260 /* only supports simple rels plus REL_ARCH */
261 /* prunes empty jobs */
262 static void
263 selection_filter_rel(Pool *pool, Queue *selection, Id relflags, Id relevr)
264 {
265   selection_filter_rel_noprune(pool, selection, relflags, relevr);
266   selection_prune(pool, selection);
267 }
268
269 /* limit a selection to to repository */
270 /* prunes empty jobs */
271 static void
272 selection_filter_repo(Pool *pool, Queue *selection, Repo *repo, int setflags)
273 {
274   Queue q;
275   int i, j;
276
277   if (!selection->count)
278     return;
279   if (!repo)
280     {
281       queue_empty(selection);
282       return;
283     }
284   queue_init(&q);
285   for (i = j = 0; i < selection->count; i += 2)
286     {
287       Id select = selection->elements[i] & SOLVER_SELECTMASK;
288       Id id = selection->elements[i + 1];
289       if (select == SOLVER_SOLVABLE_ALL)
290         {
291           select = SOLVER_SOLVABLE_REPO;
292           id = repo->repoid;
293         }
294       else if (select == SOLVER_SOLVABLE_REPO)
295         {
296           if (id != repo->repoid)
297             continue;
298         }
299       else if (select == SOLVER_SOLVABLE)
300         {
301           if (pool->solvables[id].repo != repo)
302             continue;
303         }
304       else
305         {
306           int bad = 0;
307           Id p, pp;
308           queue_empty(&q);
309           FOR_JOB_SELECT(p, pp, select, id)
310             {
311               if (pool->solvables[p].repo != repo)
312                 bad = 1;
313               else
314                 queue_push(&q, p);
315             }
316           if (!q.count)
317             continue;
318           if (bad)
319             {
320               if (q.count == 1)
321                 {
322                   select = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
323                   id = q.elements[0];
324                 }
325               else
326                 {
327                   select = SOLVER_SOLVABLE_ONE_OF;
328                   id = pool_queuetowhatprovides(pool, &q);
329                 }
330             }
331         }
332       if (select == SOLVER_SOLVABLE_REPO)
333         {
334           Id p;
335           Solvable *s;
336           FOR_REPO_SOLVABLES(repo, p, s)
337             break;
338           if (!p)
339             continue;   /* repo is empty */
340         }
341       selection->elements[j++] = select | (selection->elements[i] & ~SOLVER_SELECTMASK) | setflags;
342       selection->elements[j++] = id;
343     }
344   queue_truncate(selection, j);
345   queue_free(&q);
346 }
347
348
349 static int
350 matchprovides(Pool *pool, Solvable *s, Id dep)
351 {
352   Id id, *idp;
353   idp = s->repo->idarraydata + s->provides;
354   while ((id = *idp++) != 0)
355     if (pool_match_dep(pool, id, dep))
356       return 1;
357   return 0;
358 }
359
360 /* change a SOLVER_SOLVABLE_NAME/PROVIDES selection to something that also includes
361  * extra packages.
362  * extra packages are: src, badarch, disabled
363  */
364 static void
365 selection_addextra(Pool *pool, Queue *selection, int flags)
366 {
367   Queue q;
368   Id p, pp, dep;
369   int i, isextra, haveextra, doprovides;
370
371   if ((flags & SELECTION_INSTALLED_ONLY) != 0)
372     flags &= ~SELECTION_WITH_SOURCE;
373
374   if (!(flags & (SELECTION_WITH_SOURCE | SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH)))
375     return;     /* nothing to add */
376
377   queue_init(&q);
378   for (i = 0; i < selection->count; i += 2)
379     {
380       if (selection->elements[i] == SOLVER_SOLVABLE_NAME)
381         doprovides = 0;
382       else if (selection->elements[i] == SOLVER_SOLVABLE_PROVIDES)
383         doprovides = 1;
384       else
385         continue;
386       dep = selection->elements[i + 1];
387       haveextra = 0;
388       queue_empty(&q);
389       if (doprovides)
390         {
391           /* first put all non-extra packages on the queue */
392           FOR_PROVIDES(p, pp, dep)
393             {
394               if ((flags & SELECTION_INSTALLED_ONLY) != 0 && pool->solvables[p].repo != pool->installed)
395                 continue;
396               queue_push(&q, p);
397             }
398         }
399       FOR_POOL_SOLVABLES(p)
400         {
401           Solvable *s = pool->solvables + p;
402           if (!doprovides && !pool_match_nevr(pool, s, dep))
403             continue;
404           if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
405             continue;
406           isextra = 0;
407           if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
408             {
409               if (!(flags & SELECTION_WITH_SOURCE) && !(flags & SELECTION_SOURCE_ONLY))
410                 continue;
411               if (!(flags & SELECTION_SOURCE_ONLY))
412                 isextra = 1;
413               if (pool_disabled_solvable(pool, s))
414                 {
415                   if (!(flags & SELECTION_WITH_DISABLED))
416                     continue;
417                   isextra = 1;
418                 }
419             }
420           else
421             {
422               if ((flags & SELECTION_SOURCE_ONLY) != 0)
423                 continue;
424               if (s->repo != pool->installed)
425                 {
426                   if (pool_disabled_solvable(pool, s))
427                     {
428                       if (!(flags & SELECTION_WITH_DISABLED))
429                         continue;
430                       isextra = 1;
431                     }
432                   if (pool_badarch_solvable(pool, s))
433                     {
434                       if (!(flags & SELECTION_WITH_BADARCH))
435                         continue;
436                       isextra = 1;
437                     }
438                 }
439             }
440           if (doprovides)
441             {
442               if (!isextra)
443                 continue;       /* already done above in FOR_PROVIDES */
444               if (!s->provides || !matchprovides(pool, s, dep))
445                 continue;
446             }
447           haveextra |= isextra;
448           queue_push(&q, p);
449         }
450       if (!haveextra || !q.count)
451         continue;
452       if (q.count == 1)
453         {
454           selection->elements[i] = (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
455           selection->elements[i + 1] = q.elements[0];
456         }
457       else
458         {
459           if (doprovides)
460             solv_sort(q.elements, q.count, sizeof(Id), selection_solvables_sortcmp, NULL);
461           selection->elements[i] = (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF;
462           selection->elements[i + 1] = pool_queuetowhatprovides(pool, &q);
463         }
464     }
465   queue_free(&q);
466 }
467
468 static inline const char *
469 skipkind(const char *n)
470 {
471   const char *s;
472   for (s = n; *s >= 'a' && *s <= 'z'; s++)
473     ;
474   if (*s == ':' && s != n)
475      return s + 1;
476   return n;
477 }
478
479 static inline void
480 queue_pushunique2(Queue *q, Id id1, Id id2)
481 {
482   int i;
483   for (i = 0; i < q->count; i += 2)
484     if (q->elements[i] == id1 && q->elements[i + 1] == id2)
485       return;
486   queue_push2(q, id1, id2);
487 }
488
489
490 /*****  provides matching  *****/
491
492 static int
493 selection_addextra_provides(Pool *pool, Queue *selection, const char *name, int flags)
494 {
495   Id p, id, *idp;
496   int match = 0;
497   int doglob, nocase, globflags;
498
499   if ((flags & SELECTION_INSTALLED_ONLY) != 0)
500     return 0;   /* neither disabled nor badarch nor src */
501
502   nocase = flags & SELECTION_NOCASE;
503   doglob = (flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0;
504   globflags = doglob && nocase ? FNM_CASEFOLD : 0;
505
506   FOR_POOL_SOLVABLES(p)
507     {
508       const char *n;
509       Solvable *s = pool->solvables + p;
510       if (!s->provides)
511         continue;
512       if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) /* no provides */
513         continue;
514       if (s->repo == pool->installed)
515         continue;
516       if (pool_disabled_solvable(pool, s))
517         {
518           if (!(flags & SELECTION_WITH_DISABLED))
519             continue;
520           if (!(flags & SELECTION_WITH_BADARCH) && pool_badarch_solvable(pool, s))
521             continue;
522         }
523       else if (pool_badarch_solvable(pool, s))
524         {
525           if (!(flags & SELECTION_WITH_BADARCH))
526             continue;
527         }
528       else
529         continue;
530       /* here is an extra solvable we need to consider */
531       idp = s->repo->idarraydata + s->provides;
532       while ((id = *idp++) != 0)
533         {
534           while (ISRELDEP(id))
535             {
536               Reldep *rd = GETRELDEP(pool, id);
537               id = rd->name;
538             }
539           if (pool->whatprovides[id] > 1)
540             continue;   /* we already did that one in the normal code path */
541           n = pool_id2str(pool, id);
542           if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
543             {
544               queue_pushunique2(selection, SOLVER_SOLVABLE_PROVIDES, id);
545               match = 1;
546             }
547         }
548     }
549   return match;
550 }
551
552 /* this is the fast path of selection_provides: the id for the name
553  * is known and thus we can use the whatprovides data to quickly
554  * check the existance of a package with that provides */
555 static int
556 selection_provides_id(Pool *pool, Queue *selection, Id id, int flags)
557 {
558   Id p, pp;
559
560   FOR_PROVIDES(p, pp, id)
561     {
562       Solvable *s = pool->solvables + p;
563       if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
564         continue;
565       queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
566       return SELECTION_PROVIDES;
567     }
568
569   if ((flags & (SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) != 0)
570     {
571       /* misuse selection_addextra to test if there is an extra package
572        * that provides the id */
573       queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
574       selection_addextra(pool, selection, flags);
575       if (selection->elements[0] == SOLVER_SOLVABLE_PROVIDES)
576         queue_empty(selection);         /* no extra package found */
577       else
578         {
579           selection->elements[0] = SOLVER_SOLVABLE_PROVIDES;
580           selection->elements[1] = id;
581         }
582       return selection->count ? SELECTION_PROVIDES : 0;
583     }
584
585   return 0;
586 }
587
588 /* match the provides of a package */
589 /* note that we only return raw SOLVER_SOLVABLE_PROVIDES jobs
590  * so that the selection can be modified later. */
591 static int
592 selection_provides(Pool *pool, Queue *selection, const char *name, int flags)
593 {
594   Id id, p, pp;
595   int match;
596   int doglob;
597   int nocase;
598   int globflags;
599   const char *n;
600
601   if ((flags & SELECTION_SOURCE_ONLY) != 0)
602     return 0;   /* sources do not have provides */
603
604   nocase = flags & SELECTION_NOCASE;
605   if (!nocase)
606     {
607       /* try the fast path first */
608       id = pool_str2id(pool, name, 0);
609       if (id)
610         {
611           /* the id is known, do the fast id matching */
612           int ret = selection_provides_id(pool, selection, id, flags);
613           if (ret)
614             return ret;
615         }
616     }
617
618   doglob = (flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0;
619   if (!nocase && !doglob)
620     {
621       /* all done above in selection_provides_id */
622       return 0;
623     }
624
625   /* looks like a glob or nocase match. really hard work. */
626   match = 0;
627   globflags = doglob && nocase ? FNM_CASEFOLD : 0;
628   for (id = 1; id < pool->ss.nstrings; id++)
629     {
630       /* do we habe packages providing this id? */
631       if ((!pool->whatprovides[id] && pool->addedfileprovides == 2) || pool->whatprovides[id] == 1)
632         continue;
633       n = pool_id2str(pool, id);
634       if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
635         {
636           if ((flags & SELECTION_INSTALLED_ONLY) != 0)
637             {
638               FOR_PROVIDES(p, pp, id)
639                 if (pool->solvables[p].repo == pool->installed)
640                   break;
641               if (!p)
642                 continue;
643             }
644           else if (!pool->whatprovides[id])
645             {
646               FOR_PROVIDES(p, pp, id)
647                 break;
648               if (!p)
649                 continue;
650             }
651           queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
652           match = 1;
653         }
654     }
655
656   if (flags & (SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED))
657     match |= selection_addextra_provides(pool, selection, name, flags);
658
659   return match ? SELECTION_PROVIDES : 0;
660 }
661
662 /*****  name matching  *****/
663
664 /* this is the fast path of selection_name: the id for the name
665  * is known and thus we can quickly check the existance of a
666  * package with that name */
667 static int
668 selection_name_id(Pool *pool, Queue *selection, Id id, int flags)
669 {
670   Id p, pp, matchid;
671
672   matchid = id;
673   if ((flags & SELECTION_SOURCE_ONLY) != 0)
674     {
675       /* sources cannot be installed */
676       if ((flags & SELECTION_INSTALLED_ONLY) != 0)
677         return 0;
678       /* add ARCH_SRC to match only sources */
679       matchid = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
680       flags &= ~SELECTION_WITH_SOURCE;
681     }
682
683   FOR_PROVIDES(p, pp, matchid)
684     {
685       Solvable *s = pool->solvables + p;
686       if (s->name != id)
687         continue;
688       if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
689         continue;
690       /* one match is all we need */
691       queue_push2(selection, SOLVER_SOLVABLE_NAME, matchid);
692       /* add the requested extra packages */
693       if ((flags & (SELECTION_WITH_SOURCE | SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) != 0)
694         selection_addextra(pool, selection, flags);
695       return SELECTION_NAME;
696     }
697
698   if ((flags & (SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) != 0)
699     {
700       queue_push2(selection, SOLVER_SOLVABLE_NAME, matchid);
701       selection_addextra(pool, selection, flags);
702       if (selection->elements[0] == SOLVER_SOLVABLE_NAME)
703         queue_empty(selection);
704       return selection->count ? SELECTION_NAME : 0;
705     }
706
707   if ((flags & SELECTION_WITH_SOURCE) != 0 && (flags & SELECTION_INSTALLED_ONLY) == 0)
708     {
709       /* WITH_SOURCE case, but we had no match. try SOURCE_ONLY instead */
710       matchid = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
711       FOR_PROVIDES(p, pp, matchid)
712         {
713           Solvable *s = pool->solvables + p;
714           if (s->name != id)
715             continue;
716           queue_push2(selection, SOLVER_SOLVABLE_NAME, matchid);
717           return SELECTION_NAME;
718         }
719     }
720   return 0;
721 }
722
723 /* does not check SELECTION_INSTALLED_ONLY, as it is normally done
724  * by other means */
725 static inline int
726 solvable_matches_selection_flags(Pool *pool, Solvable *s, int flags)
727 {
728   if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
729     {
730       if (!(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
731         return 0;
732       /* source package are never installed and never have a bad arch */
733       if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
734         return 0;
735     }
736   else
737     {
738       if ((flags & SELECTION_SOURCE_ONLY) != 0)
739         return 0;
740       if (s->repo != pool->installed)
741         {
742           if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
743             return 0;
744           if (!(flags & SELECTION_WITH_BADARCH) && pool_badarch_solvable(pool, s))
745             return 0;
746         }
747     }
748   return 1;
749 }
750
751 /* match the name of a package */
752 /* note that for SELECTION_INSTALLED_ONLY the result is not trimmed */
753 static int
754 selection_name(Pool *pool, Queue *selection, const char *name, int flags)
755 {
756   Id id, p;
757   int match;
758   int doglob, nocase;
759   int globflags;
760   const char *n;
761
762   if ((flags & SELECTION_SOURCE_ONLY) != 0)
763     flags &= ~SELECTION_WITH_SOURCE;
764
765   nocase = flags & SELECTION_NOCASE;
766   if (!nocase && !(flags & SELECTION_SKIP_KIND))
767     {
768       /* try the fast path first */
769       id = pool_str2id(pool, name, 0);
770       if (id)
771         {
772           int ret = selection_name_id(pool, selection, id, flags);
773           if (ret)
774             return ret;
775         }
776     }
777
778   doglob = (flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0;
779   if (!nocase && !(flags & SELECTION_SKIP_KIND) && !doglob)
780     return 0;   /* all done above in selection_name_id */
781
782   /* do a name match over all packages. hard work. */
783   match = 0;
784   globflags = doglob && nocase ? FNM_CASEFOLD : 0;
785   FOR_POOL_SOLVABLES(p)
786     {
787       Solvable *s = pool->solvables + p;
788       if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
789         continue;
790       if (!solvable_matches_selection_flags(pool, s, flags))
791         continue;
792       id = s->name;
793       n = pool_id2str(pool, id);
794       if (flags & SELECTION_SKIP_KIND)
795         n = skipkind(n);
796       if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
797         {
798           if ((flags & SELECTION_SOURCE_ONLY) != 0)
799             {
800               if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
801                 continue;
802               id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
803             }
804           queue_pushunique2(selection, SOLVER_SOLVABLE_NAME, id);
805           match = 1;
806         }
807     }
808   if (match)
809     {
810       /* if there was a match widen the selector to include all extra packages */
811       if ((flags & (SELECTION_WITH_SOURCE | SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) != 0)
812         selection_addextra(pool, selection, flags);
813       return SELECTION_NAME;
814     }
815   return 0;
816 }
817
818
819 /*****  SELECTION_DOTARCH and SELECTION_REL handling *****/
820
821 /* like selection_name, but check for a .arch suffix if the match did
822    not work and SELECTION_DOTARCH is used */
823 static int
824 selection_name_arch(Pool *pool, Queue *selection, const char *name, int flags, int doprovides, int noprune)
825 {
826   int ret;
827   const char *r;
828   Id archid;
829
830   if (doprovides)
831     ret = selection_provides(pool, selection, name, flags);
832   else
833     ret = selection_name(pool, selection, name, flags);
834   if (ret)
835     return ret;
836   if (!(flags & SELECTION_DOTARCH))
837     return 0;
838   /* check if there is an .arch suffix */
839   if ((r = strrchr(name, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
840     {
841       char *rname = solv_strdup(name);
842       rname[r - name] = 0;
843       if (archid == ARCH_SRC || archid == ARCH_NOSRC)
844         flags |= SELECTION_SOURCE_ONLY;
845       if (doprovides)
846         ret = selection_provides(pool, selection, rname, flags);
847       else
848         ret = selection_name(pool, selection, rname, flags);
849       if (ret)
850         {
851           selection_filter_rel_noprune(pool, selection, REL_ARCH, archid);
852           if (!noprune)
853             selection_prune(pool, selection);
854         }
855       solv_free(rname);
856       return ret && selection->count ? ret | SELECTION_DOTARCH : 0;
857     }
858   return 0;
859 }
860
861 static char *
862 splitrel(char *rname, char *r, int *rflagsp)
863 {
864   int nend = r - rname;
865   int rflags = 0;
866   if (nend && *r == '=' && r[-1] == '!')
867     {
868       nend--;
869       r++;
870       rflags = REL_LT|REL_GT;
871     }
872   for (; *r; r++)
873     {
874       if (*r == '<')
875         rflags |= REL_LT;
876       else if (*r == '=')
877         rflags |= REL_EQ;
878       else if (*r == '>')
879         rflags |= REL_GT;
880       else
881         break;
882     }
883   while (*r && (*r == ' ' || *r == '\t'))
884     r++;
885   while (nend && (rname[nend - 1] == ' ' || rname[nend - 1] == '\t'))
886     nend--;
887   if (nend <= 0 || !*r || !rflags)
888     return 0;
889   *rflagsp = rflags;
890   rname[nend] = 0;
891   return r;
892 }
893
894 /* match name/provides, support DOTARCH and REL modifiers
895  */
896 static int
897 selection_name_arch_rel(Pool *pool, Queue *selection, const char *name, int flags, int doprovides)
898 {
899   int ret, rflags = 0, noprune;
900   char *r = 0, *rname = 0;
901
902   /* try to split off an relation part */
903   if ((flags & SELECTION_REL) != 0)
904     {
905       if ((r = strpbrk(name, "<=>")) != 0)
906         {
907           rname = solv_strdup(name);
908           r = rname + (r - name);
909           if ((r = splitrel(rname, r, &rflags)) == 0)
910             rname = solv_free(rname);
911         }
912     }
913
914   /* check if we need to call selection_addextra */
915   noprune = doprovides && (flags & (SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH));
916
917   if (!r)
918     {
919       /* could not split off relation */
920       ret = selection_name_arch(pool, selection, name, flags, doprovides, noprune);
921       if (ret && noprune)
922         {
923           selection_addextra(pool, selection, flags);
924           selection_prune(pool, selection);
925         }
926       return ret && selection->count ? ret : 0;
927     }
928
929   /* we could split of a relation. prune name and then filter rel */
930   ret = selection_name_arch(pool, selection, rname, flags, doprovides, noprune);
931   if (ret)
932     {
933       selection_filter_rel_noprune(pool, selection, rflags, pool_str2id(pool, r, 1));
934       if (noprune)
935         selection_addextra(pool, selection, flags);
936       selection_prune(pool, selection);
937     }
938   solv_free(rname);
939   return ret && selection->count ? ret | SELECTION_REL : 0;
940 }
941
942 /*****  filelist matching  *****/
943
944 static int
945 selection_filelist_sortcmp(const void *ap, const void *bp, void *dp)
946 {
947   Pool *pool = dp;
948   const Id *a = ap, *b = bp;
949   if (a[0] != b[0])
950     return strcmp(pool_id2str(pool, a[0]), pool_id2str(pool, b[0]));
951   return a[1] - b[1];
952 }
953
954 static int
955 selection_filelist(Pool *pool, Queue *selection, const char *name, int flags)
956 {
957   Dataiterator di;
958   Queue q;
959   Id id;
960   int type;
961   int i, j, lastid;
962
963   /* all files in the file list start with a '/' */
964   if (*name != '/')
965     {
966       if (!(flags & SELECTION_GLOB))
967         return 0;
968       if (*name != '*' && *name != '[' && *name != '?')
969         return 0;
970     }
971   type = !(flags & SELECTION_GLOB) || strpbrk(name, "[*?") == 0 ? SEARCH_STRING : SEARCH_GLOB;
972   if ((flags & SELECTION_NOCASE) != 0)
973     type |= SEARCH_NOCASE;
974   queue_init(&q);
975   dataiterator_init(&di, pool, flags & SELECTION_INSTALLED_ONLY ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES);
976   while (dataiterator_step(&di))
977     {
978       Solvable *s = pool->solvables + di.solvid;
979       if (!s->repo)
980         continue;
981       if (!solvable_matches_selection_flags(pool, s, flags))
982         continue;
983       if ((flags & SELECTION_FLAT) != 0)
984         {
985           /* don't bother with the complex stuff */
986           queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, di.solvid);
987           dataiterator_skip_solvable(&di);
988           continue;
989         }
990       id = pool_str2id(pool, di.kv.str, 1);
991       queue_push2(&q, id, di.solvid);
992     }
993   dataiterator_free(&di);
994   if ((flags & SELECTION_FLAT) != 0)
995     {
996       queue_free(&q);
997       return selection->count ? SELECTION_FILELIST : 0;
998     }
999   if (!q.count)
1000     {
1001       queue_free(&q);
1002       return 0;
1003     }
1004   solv_sort(q.elements, q.count / 2, 2 * sizeof(Id), selection_filelist_sortcmp, pool);
1005   lastid = 0;
1006   queue_push2(&q, 0, 0);
1007   for (i = j = 0; i < q.count; i += 2)
1008     {
1009       if (q.elements[i] != lastid)
1010         {
1011           if (j == 1)
1012             queue_pushunique2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, q.elements[0]);
1013           else if (j > 1)
1014             {
1015               int k;
1016               Id *idp;
1017               /* check if we already have it */
1018               for (k = 0; k < selection->count; k += 2)
1019                 {
1020                   if (selection->elements[k] != SOLVER_SOLVABLE_ONE_OF)
1021                     continue;
1022                   idp = pool->whatprovidesdata + selection->elements[k + 1];
1023                   if (!memcmp(idp, q.elements, j * sizeof(Id)) && !idp[j])
1024                     break;
1025                 }
1026               if (k == selection->count)
1027                 queue_push2(selection, SOLVER_SOLVABLE_ONE_OF, pool_ids2whatprovides(pool, q.elements, j));
1028             }
1029           lastid = q.elements[i];
1030           j = 0;
1031         }
1032       if (!j || q.elements[j - 1] != q.elements[i])
1033         q.elements[j++] = q.elements[i + 1];
1034     }
1035   queue_free(&q);
1036   return SELECTION_FILELIST;
1037 }
1038
1039
1040 /*****  canon name matching  *****/
1041
1042 #if defined(MULTI_SEMANTICS)
1043 # define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE)
1044 #elif defined(DEBIAN)
1045 # define EVRCMP_DEPCMP EVRCMP_COMPARE
1046 #else
1047 # define EVRCMP_DEPCMP EVRCMP_MATCH_RELEASE
1048 #endif
1049
1050 /* magic epoch promotion code, works only for SELECTION_NAME selections */
1051 static void
1052 selection_filter_evr(Pool *pool, Queue *selection, const char *evr)
1053 {
1054   int i, j;
1055   Queue q;
1056   Id qbuf[10];
1057   const char *sp;
1058
1059   /* do we already have an epoch? */
1060   for (sp = evr; *sp >= '0' && *sp <= '9'; sp++)
1061     ;
1062   if (*sp == ':' && sp != evr)
1063     {
1064       /* yes, just add the rel filter */
1065       selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, evr, 1));
1066       return;
1067     }
1068
1069   queue_init(&q);
1070   queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
1071   for (i = j = 0; i < selection->count; i += 2)
1072     {
1073       Id select = selection->elements[i] & SOLVER_SELECTMASK;
1074       Id id = selection->elements[i + 1];
1075       Id p, pp;
1076       const char *lastepoch = 0;
1077       int lastepochlen = 0;
1078
1079       queue_empty(&q);
1080       FOR_JOB_SELECT(p, pp, select, id)
1081         {
1082           Solvable *s = pool->solvables + p;
1083           const char *sevr = pool_id2str(pool, s->evr);
1084           for (sp = sevr; *sp >= '0' && *sp <= '9'; sp++)
1085             ;
1086           if (*sp != ':')
1087             sp = sevr;
1088           /* compare vr part */
1089           if (strcmp(evr, sp != sevr ? sp + 1 : sevr) != 0)
1090             {
1091               int r = pool_evrcmp_str(pool, sp != sevr ? sp + 1 : sevr, evr, EVRCMP_DEPCMP);
1092               if (r == -1 || r == 1)
1093                 continue;       /* solvable does not match vr */
1094             }
1095           queue_push(&q, p);
1096           if (sp > sevr)
1097             {
1098               while (sevr < sp && *sevr == '0') /* normalize epoch */
1099                 sevr++;
1100             }
1101           if (!lastepoch)
1102             {
1103               lastepoch = sevr;
1104               lastepochlen = sp - sevr;
1105             }
1106           else if (lastepochlen != sp - sevr || strncmp(lastepoch, sevr, lastepochlen) != 0)
1107             lastepochlen = -1;  /* multiple different epochs */
1108         }
1109       if (!lastepoch || lastepochlen == 0)
1110         id = pool_str2id(pool, evr, 1);         /* no match at all or zero epoch */
1111       else if (lastepochlen >= 0)
1112         {
1113           /* found exactly one epoch, simply prepend */
1114           char *evrx = solv_malloc(strlen(evr) + lastepochlen + 2);
1115           strncpy(evrx, lastepoch, lastepochlen + 1);
1116           strcpy(evrx + lastepochlen + 1, evr);
1117           id = pool_str2id(pool, evrx, 1);
1118           solv_free(evrx);
1119         }
1120       else
1121         {
1122           /* multiple epochs in multiple solvables, convert to list of solvables */
1123           selection->elements[j] = (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF;
1124           selection->elements[j + 1] = pool_queuetowhatprovides(pool, &q);
1125           j += 2;
1126           continue;
1127         }
1128       queue_empty(&q);
1129       queue_push2(&q, selection->elements[i], selection->elements[i + 1]);
1130       selection_filter_rel(pool, &q, REL_EQ, id);
1131       if (!q.count)
1132         continue;               /* oops, no match */
1133       selection->elements[j] = q.elements[0];
1134       selection->elements[j + 1] = q.elements[1];
1135       j += 2;
1136     }
1137   queue_truncate(selection, j);
1138   queue_free(&q);
1139 }
1140
1141 /* match the "canonical" name of the package */
1142 static int
1143 selection_canon(Pool *pool, Queue *selection, const char *name, int flags)
1144 {
1145   char *rname, *r, *r2;
1146   Id archid = 0;
1147   int ret;
1148
1149   /*
1150    * nameglob-version
1151    * nameglob-version.arch
1152    * nameglob-version-release
1153    * nameglob-version-release.arch
1154    */
1155   flags |= SELECTION_NAME;
1156   flags &= ~SELECTION_PROVIDES;
1157
1158 #ifdef ENABLE_CONDA
1159   if (pool->disttype == DISTTYPE_CONDA)
1160     {
1161       Id *wp, id = pool_conda_matchspec(pool, name);
1162       if (!id)
1163         return 0;
1164       wp = pool_whatprovides_ptr(pool, id);         /* check if there is a match */
1165       if (!wp || !*wp)
1166         return 0;
1167       queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
1168       return SELECTION_CANON;
1169     }
1170 #endif
1171   if (pool->disttype == DISTTYPE_DEB)
1172     {
1173       if ((r = strchr(name, '_')) == 0)
1174         return 0;
1175       rname = solv_strdup(name);        /* so we can modify it */
1176       r = rname + (r - name);
1177       *r++ = 0;
1178       if ((ret = selection_name(pool, selection, rname, flags)) == 0)
1179         {
1180           solv_free(rname);
1181           return 0;
1182         }
1183       /* is there a vaild arch? */
1184       if ((r2 = strrchr(r, '_')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
1185         {
1186           *r2 = 0;      /* split off */
1187           selection_filter_rel(pool, selection, REL_ARCH, archid);
1188         }
1189       selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1));
1190       solv_free(rname);
1191       return selection->count ? ret | SELECTION_CANON : 0;
1192     }
1193
1194   if (pool->disttype == DISTTYPE_HAIKU)
1195     {
1196       if ((r = strchr(name, '-')) == 0)
1197         return 0;
1198       rname = solv_strdup(name);        /* so we can modify it */
1199       r = rname + (r - name);
1200       *r++ = 0;
1201       if ((ret = selection_name(pool, selection, rname, flags)) == 0)
1202         {
1203           solv_free(rname);
1204           return 0;
1205         }
1206       /* is there a vaild arch? */
1207       if ((r2 = strrchr(r, '-')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
1208         {
1209           *r2 = 0;      /* split off */
1210           selection_filter_rel(pool, selection, REL_ARCH, archid);
1211         }
1212       selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1));
1213       solv_free(rname);
1214       return selection->count ? ret | SELECTION_CANON : 0;
1215     }
1216
1217   if ((r = strrchr(name, '-')) == 0)
1218     return 0;
1219   rname = solv_strdup(name);    /* so we can modify it */
1220   r = rname + (r - name);
1221   *r = 0;
1222
1223   /* split off potential arch part from version */
1224   if ((r2 = strrchr(r + 1, '.')) != 0 && r2[1] && (archid = str2archid(pool, r2 + 1)) != 0)
1225     *r2 = 0;    /* found valid arch, split it off */
1226   if (archid == ARCH_SRC || archid == ARCH_NOSRC)
1227     flags |= SELECTION_SOURCE_ONLY;
1228
1229   /* try with just the version */
1230   if ((ret = selection_name(pool, selection, rname, flags)) == 0)
1231     {
1232       /* no luck, try with version-release */
1233       if ((r2 = strrchr(rname, '-')) == 0)
1234         {
1235           solv_free(rname);
1236           return 0;
1237         }
1238       *r = '-';
1239       *r2 = 0;
1240       r = r2;
1241       if ((ret = selection_name(pool, selection, rname, flags)) == 0)
1242         {
1243           solv_free(rname);
1244           return 0;
1245         }
1246     }
1247   if (archid)
1248     selection_filter_rel(pool, selection, REL_ARCH, archid);
1249   selection_filter_evr(pool, selection, r + 1); /* magic epoch promotion */
1250   solv_free(rname);
1251   return selection->count ? ret | SELECTION_CANON : 0;
1252 }
1253
1254 /* return the needed withbits to match the provided selection */
1255 static int
1256 selection_extrabits(Pool *pool, Queue *selection, int flags)
1257 {
1258   int i, needflags, isextra;
1259   int allflags;
1260   Id p;
1261   Solvable *s;
1262   Queue qlimit;
1263
1264   allflags = flags & (SELECTION_WITH_SOURCE | SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH);
1265   if (!selection->count)
1266     return allflags;
1267   if (selection->count == 2 && selection->elements[0] == SOLVER_SOLVABLE_ALL)
1268     return allflags;    /* don't bother */
1269   queue_init(&qlimit);
1270   selection_solvables(pool, selection, &qlimit);
1271   needflags = 0;
1272   for (i = 0; i < qlimit.count; i++)
1273     {
1274       p = qlimit.elements[i];
1275       s = pool->solvables + p;
1276       if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
1277         continue;
1278       isextra = 0;
1279       if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
1280         {
1281           if (!(flags & SELECTION_WITH_SOURCE))
1282             continue;
1283           isextra |= SELECTION_WITH_SOURCE;
1284           if (pool_disabled_solvable(pool, s))
1285             {
1286               if (!(flags & SELECTION_WITH_DISABLED))
1287                 continue;
1288               isextra |= SELECTION_WITH_DISABLED;
1289             }
1290         }
1291       else
1292         {
1293           if ((flags & SELECTION_SOURCE_ONLY) != 0)
1294             continue;
1295           if (s->repo != pool->installed)
1296             {
1297               if (pool_disabled_solvable(pool, s))
1298                 {
1299                   if (!(flags & SELECTION_WITH_DISABLED))
1300                     continue;
1301                   isextra |= SELECTION_WITH_DISABLED;
1302                 }
1303               if (pool_badarch_solvable(pool, s))
1304                 {
1305                   if (!(flags & SELECTION_WITH_BADARCH))
1306                     continue;
1307                   isextra |= SELECTION_WITH_BADARCH;
1308                 }
1309             }
1310         }
1311       if (isextra)
1312         {
1313           needflags |= isextra;
1314           if (needflags == allflags)
1315             break;
1316         }
1317     }
1318   queue_free(&qlimit);
1319   return needflags;
1320 }
1321
1322 static int
1323 selection_combine(Pool *pool, Queue *sel1, Queue *sel2, int flags, int ret)
1324 {
1325   if ((flags & SELECTION_MODEBITS) == SELECTION_ADD)
1326     selection_add(pool, sel1, sel2);
1327   else if ((flags & SELECTION_MODEBITS) == SELECTION_SUBTRACT)
1328     selection_subtract(pool, sel1, sel2);
1329   else if ((flags & SELECTION_MODEBITS) == SELECTION_FILTER)
1330     {
1331       if (ret || !(flags & SELECTION_FILTER_KEEP_IFEMPTY))
1332         {
1333           if ((flags & SELECTION_FILTER_SWAPPED) != 0)
1334             {
1335               selection_filter(pool, sel2, sel1);
1336               queue_free(sel1);
1337               queue_init_clone(sel1, sel2);
1338             }
1339           else
1340             selection_filter(pool, sel1, sel2);
1341         }
1342     }
1343   else  /* SELECTION_REPLACE */
1344     {
1345       queue_free(sel1);
1346       queue_init_clone(sel1, sel2);
1347     }
1348   queue_free(sel2);
1349   return ret;
1350 }
1351
1352 int
1353 selection_make(Pool *pool, Queue *selection, const char *name, int flags)
1354 {
1355   int ret = 0;
1356   if ((flags & SELECTION_MODEBITS) != SELECTION_REPLACE)
1357     {
1358       Queue q;
1359
1360       if ((flags & SELECTION_MODEBITS) == SELECTION_SUBTRACT || (flags & SELECTION_MODEBITS) == SELECTION_FILTER)
1361         {
1362           if (!selection->count)
1363             return 0;
1364           if ((flags & (SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH | SELECTION_WITH_SOURCE)) != 0)
1365             {
1366               /* try to drop expensive extra bits */
1367               flags = (flags & ~(SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH | SELECTION_WITH_SOURCE)) | selection_extrabits(pool, selection, flags);
1368             }
1369         }
1370       queue_init(&q);
1371       ret = selection_make(pool, &q, name, flags & ~SELECTION_MODEBITS);
1372       return selection_combine(pool, selection, &q, flags, ret);
1373     }
1374   queue_empty(selection);
1375   if ((flags & SELECTION_INSTALLED_ONLY) != 0 && !pool->installed)
1376     return 0;
1377
1378   /* here come our four selection modes */
1379   if ((flags & SELECTION_FILELIST) != 0)
1380     ret = selection_filelist(pool, selection, name, flags);
1381   if (!ret && (flags & SELECTION_NAME) != 0)
1382     ret = selection_name_arch_rel(pool, selection, name, flags, 0);
1383   if (!ret && (flags & SELECTION_PROVIDES) != 0)
1384     ret = selection_name_arch_rel(pool, selection, name, flags, 1);
1385   if (!ret && (flags & SELECTION_CANON) != 0)
1386     ret = selection_canon(pool, selection, name, flags);
1387
1388   /* now do result filtering */
1389   if (ret && (flags & SELECTION_INSTALLED_ONLY) != 0)
1390     selection_filter_repo(pool, selection, pool->installed, SOLVER_SETREPO);
1391
1392   /* flatten if requested */
1393   if (ret && (flags & SELECTION_FLAT) != 0)
1394     selection_flatten(pool, selection);
1395   return selection->count ? ret : 0;
1396 }
1397
1398 static int
1399 matchdep_str(const char *pattern, const char *string, int flags)
1400 {
1401   if (!pattern || !string)
1402     return 0;
1403   if (flags & SELECTION_GLOB)
1404     {
1405       int globflags = (flags & SELECTION_NOCASE) != 0 ? FNM_CASEFOLD : 0;
1406       return fnmatch(pattern, string, globflags) == 0 ? 1 : 0;
1407     }
1408   if (flags & SELECTION_NOCASE)
1409     return strcasecmp(pattern, string) == 0 ? 1 : 0;
1410   return strcmp(pattern, string) == 0 ? 1 : 0;
1411 }
1412
1413 /* like pool_match_dep but uses matchdep_str to match the name for glob and nocase matching */
1414 static int
1415 matchdep(Pool *pool, Id id, char *rname, int rflags, Id revr, int flags)
1416 {
1417   if (ISRELDEP(id))
1418     {
1419       Reldep *rd = GETRELDEP(pool, id);
1420       if (rd->flags > 7)
1421         {
1422           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)
1423             {
1424               if (matchdep(pool, rd->name, rname, rflags, revr, flags))
1425                 return 1;
1426               if ((rd->flags == REL_COND || rd->flags == REL_UNLESS) && ISRELDEP(rd->evr))
1427                 {
1428                   rd = GETRELDEP(pool, rd->evr);
1429                   if (rd->flags != REL_ELSE)
1430                     return 0;
1431                 }
1432               if (rd->flags != REL_COND && rd->flags != REL_UNLESS && rd->flags != REL_WITHOUT && matchdep(pool, rd->evr, rname, rflags, revr, flags))
1433                 return 1;
1434               return 0;
1435             }
1436           if (rd->flags == REL_ARCH)
1437             return matchdep(pool, rd->name, rname, rflags, revr, flags);
1438         }
1439       if (!matchdep(pool, rd->name, rname, rflags, revr, flags))
1440         return 0;
1441       if (rflags && !pool_intersect_evrs(pool, rd->flags, rd->evr, rflags, revr))
1442         return 0;
1443       return 1;
1444     }
1445   return matchdep_str(rname, pool_id2str(pool, id), flags);
1446 }
1447
1448 struct limiter {
1449   int start;    /* either 2 or repofilter->start */
1450   int end;      /* either nsolvables or repofilter->end */
1451   Repo *repofilter;
1452   Id *mapper;
1453   Queue qlimit;
1454 };
1455
1456
1457 static int
1458 selection_make_matchsolvable_common(Pool *pool, Queue *selection, Queue *solvidq, Id solvid, int flags, int keyname, int marker, struct limiter *limiter)
1459 {
1460   Map m, missc;
1461   int reloff;
1462   int li, i, j;
1463   Id p;
1464   Queue q;
1465
1466   if ((flags & SELECTION_MODEBITS) != SELECTION_REPLACE)
1467     {
1468       int ret;
1469       Queue q;
1470       queue_init(&q);
1471       ret = selection_make_matchsolvable_common(pool, &q, solvidq, solvid, flags & ~SELECTION_MODEBITS, keyname, marker, limiter);
1472       return selection_combine(pool, selection, &q, flags, ret);
1473     }
1474
1475   queue_empty(selection);
1476   if (!limiter->end)
1477     return 0;
1478   if (!solvidq && !solvid)
1479     return 0;
1480   if (solvidq && solvid)
1481     return 0;
1482
1483   if (solvidq)
1484     {
1485       map_init(&m, pool->nsolvables);
1486       for (i = 0; i < solvidq->count; i++)
1487         MAPSET(&m, solvidq->elements[i]);
1488     }
1489   queue_init(&q);
1490   reloff = pool->ss.nstrings;
1491   map_init(&missc, reloff + pool->nrels);
1492   for (li = limiter->start; li < limiter->end; li++)
1493     {
1494       Solvable *s;
1495       p = limiter->mapper ? limiter->mapper[li] : li;
1496       if (solvidq && MAPTST(&m, p))
1497         continue;
1498       if (!solvidq && p == solvid)
1499         continue;
1500       s = pool->solvables + p;
1501       if (!s->repo || (limiter->repofilter && s->repo != limiter->repofilter))
1502         continue;
1503       if (!solvable_matches_selection_flags(pool, s, flags))
1504         continue;
1505       if (solvable_matchessolvable_int(s, keyname, marker, solvid, solvidq ? &m : 0, &q, &missc, reloff, 0))
1506         queue_push(selection, p);
1507     }
1508   queue_free(&q);
1509   map_free(&missc);
1510   if (solvidq)
1511     map_free(&m);
1512
1513   /* convert package list to selection */
1514   if (!selection->count)
1515     return 0;
1516   j = selection->count;
1517   queue_insertn(selection, 0, selection->count, 0);
1518   for (i = 0; i < selection->count; i += 2)
1519     {
1520       selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
1521       selection->elements[i + 1] = selection->elements[j++];
1522     }
1523   if ((flags & SELECTION_FLAT) != 0)
1524     selection_flatten(pool, selection);
1525   return SELECTION_PROVIDES;
1526 }
1527
1528 static int
1529 selection_make_matchdeps_common(Pool *pool, Queue *selection, const char *name, Id dep, int flags, int keyname, int marker, struct limiter *limiter)
1530 {
1531   int li, i, j;
1532   int ret = 0;
1533   char *rname = 0, *r = 0;
1534   int rflags = 0;
1535   Id revr = 0;
1536   Id p;
1537   Queue q;
1538
1539   if ((flags & SELECTION_MODEBITS) != SELECTION_REPLACE)
1540     {
1541       Queue q;
1542       queue_init(&q);
1543       ret = selection_make_matchdeps_common(pool, &q, name, dep, flags & ~SELECTION_MODEBITS, keyname, marker, limiter);
1544       return selection_combine(pool, selection, &q, flags, ret);
1545     }
1546
1547   queue_empty(selection);
1548   if (!limiter->end)
1549     return 0;
1550   if (!name && !dep)
1551     return 0;
1552   if (name && dep)
1553     return 0;
1554
1555   if ((flags & SELECTION_MATCH_DEPSTR) != 0)
1556     flags &= ~SELECTION_REL;
1557
1558   if (name)
1559     {
1560       rname = solv_strdup(name);
1561       if ((flags & SELECTION_REL) != 0)
1562         {
1563           if ((r = strpbrk(rname, "<=>")) != 0)
1564             {
1565               if ((r = splitrel(rname, r, &rflags)) == 0)
1566                 {
1567                   solv_free(rname);
1568                   return 0;
1569                 }
1570             }
1571           revr = pool_str2id(pool, r, 1);
1572           ret |= SELECTION_REL;
1573         }
1574       if ((flags & SELECTION_GLOB) != 0 && strpbrk(rname, "[*?") == 0)
1575         flags &= ~SELECTION_GLOB;
1576
1577       if ((flags & SELECTION_GLOB) == 0 && (flags & SELECTION_NOCASE) == 0 && (flags & SELECTION_MATCH_DEPSTR) == 0)
1578         {
1579           /* we can use the faster selection_make_matchdepid */
1580           dep = pool_str2id(pool, rname, 1);
1581           if (rflags)
1582             dep = pool_rel2id(pool, dep, revr, rflags, 1);
1583           rname = solv_free(rname);
1584           name = 0;
1585         }
1586     }
1587   if (dep)
1588     {
1589       if (keyname == SOLVABLE_NAME && (flags & SELECTION_MATCH_DEPSTR) != 0)
1590         {
1591           Reldep *rd;
1592           if (!ISRELDEP(dep))
1593             return 0;
1594           rd = GETRELDEP(pool, dep);
1595           if (!rd->name || rd->flags != REL_EQ)
1596             return 0;
1597           dep = rd->name;
1598           rflags = rd->flags;
1599           revr = rd->evr;
1600         }
1601     }
1602
1603   queue_init(&q);
1604   for (li = limiter->start; li < limiter->end; li++)
1605     {
1606       Solvable *s;
1607       p = limiter->mapper ? limiter->mapper[li] : li;
1608       s = pool->solvables + p;
1609       if (!s->repo || (limiter->repofilter && s->repo != limiter->repofilter))
1610         continue;
1611       if (!solvable_matches_selection_flags(pool, s, flags))
1612         continue;
1613       if (keyname == SOLVABLE_NAME)                     /* nevr match hack */
1614         {
1615           if (dep)
1616             {
1617               if ((flags & SELECTION_MATCH_DEPSTR) != 0)
1618                 {
1619                   if (s->name != dep || s->evr != revr)
1620                     continue;
1621                 }
1622               else
1623                 {
1624                   if (!pool_match_nevr(pool, s, dep))
1625                     continue;
1626                 }
1627             }
1628           else
1629             {
1630               if ((flags & SELECTION_MATCH_DEPSTR) != 0)        /* mis-use */
1631                 {
1632                   char *tmp = pool_tmpjoin(pool, pool_id2str(pool, s->name), " = ", pool_id2str(pool, s->evr));
1633                   if (!matchdep_str(rname, tmp, flags))
1634                     continue;
1635                 }
1636               else
1637                 {
1638                   if (!matchdep(pool, s->name, rname, rflags, revr, flags))
1639                     continue;
1640                   if (rflags && !pool_intersect_evrs(pool, rflags, revr, REL_EQ, s->evr))
1641                     continue;
1642                 }
1643             }
1644           queue_push(selection, p);
1645           continue;
1646         }
1647       if (q.count)
1648         queue_empty(&q);
1649       repo_lookup_deparray(s->repo, p, keyname, &q, marker);
1650       if (!q.count)
1651         continue;
1652       if (dep)
1653         {
1654           if ((flags & SELECTION_MATCH_DEPSTR) != 0)    /* mis-use */
1655             {
1656               for (i = 0; i < q.count; i++)
1657                 if (q.elements[i] == dep)
1658                   break;
1659             }
1660           else
1661             {
1662               for (i = 0; i < q.count; i++)
1663                 if (pool_match_dep(pool, q.elements[i], dep))
1664                   break;
1665             }
1666         }
1667       else
1668         {
1669           if ((flags & SELECTION_MATCH_DEPSTR) != 0)
1670             {
1671               for (i = 0; i < q.count; i++)
1672                 if (matchdep_str(rname, pool_dep2str(pool, q.elements[i]), flags))
1673                   break;
1674             }
1675           else
1676             {
1677               for (i = 0; i < q.count; i++)
1678                 if (matchdep(pool, q.elements[i], rname, rflags, revr, flags))
1679                   break;
1680             }
1681         }
1682       if (i < q.count)
1683         queue_push(selection, p);
1684     }
1685   queue_free(&q);
1686   solv_free(rname);
1687
1688   /* convert package list to selection */
1689   if (!selection->count)
1690     return 0;
1691   j = selection->count;
1692   queue_insertn(selection, 0, selection->count, 0);
1693   for (i = 0; i < selection->count; i += 2)
1694     {
1695       selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
1696       selection->elements[i + 1] = selection->elements[j++];
1697     }
1698
1699   if ((flags & SELECTION_FLAT) != 0)
1700     selection_flatten(pool, selection);
1701   return ret | (keyname == SOLVABLE_NAME ? SELECTION_NAME : SELECTION_PROVIDES);
1702 }
1703
1704 static void
1705 setup_limiter(Pool *pool, Queue *selection, int flags, struct limiter *limiter)
1706 {
1707   limiter->start = 2;
1708   limiter->end = pool->nsolvables;
1709   limiter->mapper = 0;
1710   limiter->repofilter = 0;
1711   if ((flags & SELECTION_INSTALLED_ONLY) != 0)
1712     {
1713       Repo *repo = pool->installed;
1714       limiter->repofilter = repo;
1715       limiter->start = repo ? repo->start : 0;
1716       limiter->end = repo ? repo->end : 0;
1717     }
1718   if ((flags & SELECTION_MODEBITS) != SELECTION_SUBTRACT && (flags & SELECTION_MODEBITS) != SELECTION_FILTER)
1719     return;
1720   /* the result will be limited to the first selection */
1721   if (!selection->count)
1722     limiter->start = limiter->end = 0;
1723   if (!limiter->end)
1724     return;
1725   /* check for special cases where we do not need to call selection_solvables() */
1726   if (selection->count == 2 && (selection->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
1727     return;
1728   if (selection->count == 2 && (selection->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_REPO)
1729     {
1730       Repo *repo = pool_id2repo(pool, selection->elements[1]);
1731       if (limiter->repofilter && repo != limiter->repofilter)
1732         repo = 0;
1733       limiter->repofilter = repo;
1734       limiter->start = repo ? repo->start : 0;
1735       limiter->end = repo ? repo->end : 0;
1736       return;
1737     }
1738   /* convert selection into a package list and use it in the limiter */
1739   queue_init(&limiter->qlimit);
1740   selection_solvables(pool, selection, &limiter->qlimit);
1741   limiter->start = 0;
1742   limiter->end = limiter->qlimit.count;
1743   if (!limiter->qlimit.count)
1744     queue_free(&limiter->qlimit);
1745   else
1746     limiter->mapper = limiter->qlimit.elements;
1747 }
1748
1749 static void
1750 free_limiter(struct limiter *limiter)
1751 {
1752   if (limiter->mapper)
1753     queue_free(&limiter->qlimit);
1754 }
1755
1756 /*
1757  *  select against the dependencies in keyname
1758  *  like SELECTION_PROVIDES, but with the deps in keyname instead of provides.
1759  *  supported match modifiers:
1760  *    SELECTION_REL
1761  *    SELECTION_GLOB
1762  *    SELECTION_NOCASE
1763  */
1764 int
1765 selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int flags, int keyname, int marker)
1766 {
1767   struct limiter limiter;
1768   int ret;
1769   setup_limiter(pool, selection, flags, &limiter);
1770   ret = selection_make_matchdeps_common(pool, selection, name, 0, flags, keyname, marker, &limiter);
1771   free_limiter(&limiter);
1772   return ret;
1773 }
1774
1775 /*
1776  *  select against the dependency id in keyname
1777  */
1778 int
1779 selection_make_matchdepid(Pool *pool, Queue *selection, Id dep, int flags, int keyname, int marker)
1780 {
1781   struct limiter limiter;
1782   int ret;
1783   setup_limiter(pool, selection, flags, &limiter);
1784   ret = selection_make_matchdeps_common(pool, selection, 0, dep, flags, keyname, marker, &limiter);
1785   free_limiter(&limiter);
1786   return ret;
1787 }
1788
1789 int
1790 selection_make_matchsolvable(Pool *pool, Queue *selection, Id solvid, int flags, int keyname, int marker)
1791 {
1792   struct limiter limiter;
1793   int ret;
1794   setup_limiter(pool, selection, flags, &limiter);
1795   ret = selection_make_matchsolvable_common(pool, selection, 0, solvid, flags, keyname, marker, &limiter);
1796   free_limiter(&limiter);
1797   return ret;
1798 }
1799
1800 int
1801 selection_make_matchsolvablelist(Pool *pool, Queue *selection, Queue *solvidq, int flags, int keyname, int marker)
1802 {
1803   struct limiter limiter;
1804   int ret;
1805   setup_limiter(pool, selection, flags, &limiter);
1806   ret = selection_make_matchsolvable_common(pool, selection, solvidq, 0, flags, keyname, marker, &limiter);
1807   free_limiter(&limiter);
1808   return ret;
1809 }
1810
1811 static inline int
1812 pool_is_kind(Pool *pool, Id name, Id kind)
1813 {
1814   const char *n;
1815   if (!kind)
1816     return 1;
1817   n = pool_id2str(pool, name);
1818   if (kind != 1)
1819     {
1820       const char *kn = pool_id2str(pool, kind);
1821       int knl = strlen(kn);
1822       return !strncmp(n, kn, knl) && n[knl] == ':' ? 1 : 0;
1823     }
1824   else
1825     {
1826       if (*n == ':')
1827         return 1;
1828       while(*n >= 'a' && *n <= 'z')
1829         n++;
1830       return *n == ':' ? 0 : 1;
1831     }
1832 }
1833
1834 static void
1835 selection_filter_map(Pool *pool, Queue *sel, Map *m, int setflags)
1836 {
1837   int i, j, miss;
1838   Queue q;
1839   Id p, pp;
1840
1841   queue_init(&q);
1842   for (i = j = 0; i < sel->count; i += 2)
1843     {
1844       Id select = sel->elements[i] & SOLVER_SELECTMASK;
1845       Id id = sel->elements[i + 1];
1846       if (q.count)
1847         queue_empty(&q);
1848       miss = 0;
1849       if (select == SOLVER_SOLVABLE_ALL)
1850         {
1851           FOR_POOL_SOLVABLES(p)
1852             {
1853               if (map_tst(m, p))
1854                 queue_push(&q, p);
1855               else
1856                 miss = 1;
1857             }
1858         }
1859       else if (select == SOLVER_SOLVABLE_REPO)
1860         {
1861           Solvable *s;
1862           Repo *repo = pool_id2repo(pool, id);
1863           if (repo)
1864             {
1865               FOR_REPO_SOLVABLES(repo, p, s)
1866                 {
1867                   if (map_tst(m, p))
1868                     queue_push(&q, p);
1869                   else
1870                     miss = 1;
1871                 }
1872             }
1873         }
1874       else if (select == SOLVER_SOLVABLE)
1875         {
1876           if (!map_tst(m, id))
1877             continue;
1878           sel->elements[j] = sel->elements[i] | setflags;
1879           sel->elements[j + 1] = id;
1880           j += 2;
1881           continue;
1882         }
1883       else
1884         {
1885           FOR_JOB_SELECT(p, pp, select, id)
1886             {
1887               if (map_tst(m, p))
1888                 queue_pushunique(&q, p);
1889               else
1890                 miss = 1;
1891             }
1892         }
1893       if (!q.count)
1894         continue;
1895       if (!miss)
1896         {
1897           sel->elements[j] = sel->elements[i] | setflags;
1898           sel->elements[j + 1] = id;
1899         }
1900       else if (q.count > 1)
1901         {
1902           sel->elements[j] = (sel->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF | setflags;
1903           sel->elements[j + 1] = pool_queuetowhatprovides(pool, &q);
1904         }
1905       else
1906         {
1907           sel->elements[j] = (sel->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE | SOLVER_NOAUTOSET | setflags;
1908           sel->elements[j + 1] = q.elements[0];
1909         }
1910       j += 2;
1911     }
1912   queue_truncate(sel, j);
1913   queue_free(&q);
1914 }
1915
1916 static void
1917 selection_filter_int(Pool *pool, Queue *sel1, Queue *sel2, int invert)
1918 {
1919   int i, j;
1920   Id p, pp, q1filled = 0;
1921   Queue q1;
1922   Map m2;
1923   Id setflags = 0;
1924
1925   /* handle special cases */
1926   if (!sel1->count || !sel2->count)
1927     {
1928       if (invert && !sel2->count)
1929         return;
1930       queue_empty(sel1);
1931       return;
1932     }
1933   if (sel1->count == 2 && (sel1->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL && !invert)
1934     {
1935       /* XXX: not 100% correct, but very useful */
1936       setflags = sel1->elements[0] & ~(SOLVER_SELECTMASK | SOLVER_SETMASK);     /* job & jobflags */
1937       queue_free(sel1);
1938       queue_init_clone(sel1, sel2);
1939       for (i = 0; i < sel1->count; i += 2)
1940         sel1->elements[i] = (sel1->elements[i] & (SOLVER_SELECTMASK | SOLVER_SETMASK)) | setflags;
1941       return;
1942     }
1943   if (sel1->count == 2 && (sel1->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_REPO && !invert)
1944     {
1945       Repo *repo = pool_id2repo(pool, sel1->elements[1]);
1946       setflags = sel1->elements[0] & ~(SOLVER_SELECTMASK | SOLVER_NOAUTOSET);   /* job, jobflags, setflags */
1947       queue_free(sel1);
1948       queue_init_clone(sel1, sel2);
1949       for (i = 0; i < sel1->count; i += 2)
1950         sel1->elements[i] &= SOLVER_SELECTMASK | SOLVER_SETMASK;        /* remove job and jobflags */
1951       selection_filter_repo(pool, sel1, repo, setflags);
1952       return;
1953     }
1954   if (sel2->count == 2 && (sel2->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
1955     {
1956       if (invert)
1957         queue_empty(sel1);
1958       return;
1959     }
1960   if (sel2->count == 2 && (sel2->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_REPO && !invert)
1961     {
1962       Repo *repo = pool_id2repo(pool, sel2->elements[1]);
1963       setflags = sel2->elements[0] & (SOLVER_SETMASK & ~SOLVER_NOAUTOSET);
1964       selection_filter_repo(pool, sel1, repo, setflags);
1965       return;
1966     }
1967
1968   /* convert sel2 into a map */
1969   queue_init(&q1);
1970   map_init(&m2, pool->nsolvables);
1971   for (i = 0; i < sel2->count; i += 2)
1972     {
1973       Id select = sel2->elements[i] & SOLVER_SELECTMASK;
1974       if (select == SOLVER_SOLVABLE_ALL)
1975         {
1976           queue_free(&q1);
1977           map_free(&m2);
1978           if (invert)
1979             queue_empty(sel1);
1980           return;
1981         }
1982       if (select == SOLVER_SOLVABLE_REPO)
1983         {
1984           Solvable *s;
1985           Repo *repo = pool_id2repo(pool, sel2->elements[i + 1]);
1986           if (repo)
1987             {
1988               FOR_REPO_SOLVABLES(repo, p, s)
1989                 map_set(&m2, p);
1990             }
1991         }
1992       else
1993         {
1994           if ((select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES) && ISRELDEP(sel2->elements[i + 1]))
1995             {
1996               Reldep *rd = GETRELDEP(pool, sel2->elements[i + 1]);
1997               if (rd->flags == REL_ARCH && rd->name == 0)
1998                 {
1999                   /* special arch filter */
2000                   if (!q1filled++)
2001                     selection_solvables(pool, sel1, &q1);
2002                   for (j = 0; j < q1.count; j++)
2003                     {
2004                       Id p = q1.elements[j];
2005                       Solvable *s = pool->solvables + p;
2006                       if (s->arch == rd->evr || (rd->evr == ARCH_SRC && s->arch == ARCH_NOSRC))
2007                         map_set(&m2, p);
2008                     }
2009                   continue;
2010                 }
2011               else if (rd->flags == REL_KIND && rd->name == 0)
2012                 {
2013                   /* special kind filter */
2014                   if (!q1filled++)
2015                     selection_solvables(pool, sel1, &q1);
2016                   for (j = 0; j < q1.count; j++)
2017                     {
2018                       Id p = q1.elements[j];
2019                       Solvable *s = pool->solvables + p;
2020                       if (pool_is_kind(pool, s->name, rd->evr))
2021                         map_set(&m2, p);
2022                     }
2023                   continue;
2024                 }
2025             }
2026           FOR_JOB_SELECT(p, pp, select, sel2->elements[i + 1])
2027             map_set(&m2, p);
2028         }
2029     }
2030   queue_free(&q1);
2031
2032   /* now filter sel1 with the map */
2033   if (invert)
2034     map_invertall(&m2);
2035   if (sel2->count == 2)
2036     setflags = sel2->elements[0] & (SOLVER_SETMASK & ~SOLVER_NOAUTOSET);
2037   selection_filter_map(pool, sel1, &m2, setflags);
2038   map_free(&m2);
2039 }
2040
2041 void
2042 selection_filter(Pool *pool, Queue *sel1, Queue *sel2)
2043 {
2044   selection_filter_int(pool, sel1, sel2, 0);
2045 }
2046
2047 void
2048 selection_add(Pool *pool, Queue *sel1, Queue *sel2)
2049 {
2050   if (sel2->count)
2051     queue_insertn(sel1, sel1->count, sel2->count, sel2->elements);
2052 }
2053
2054 void
2055 selection_subtract(Pool *pool, Queue *sel1, Queue *sel2)
2056 {
2057   selection_filter_int(pool, sel1, sel2, 1);
2058 }
2059
2060 const char *
2061 pool_selection2str(Pool *pool, Queue *selection, Id flagmask)
2062 {
2063   char *s;
2064   const char *s2;
2065   int i;
2066   s = pool_tmpjoin(pool, 0, 0, 0);
2067   for (i = 0; i < selection->count; i += 2)
2068     {
2069       Id how = selection->elements[i];
2070       if (*s)
2071         s = pool_tmpappend(pool, s, " + ", 0);
2072       s2 = solver_select2str(pool, how & SOLVER_SELECTMASK, selection->elements[i + 1]);
2073       s = pool_tmpappend(pool, s, s2, 0);
2074       pool_freetmpspace(pool, s2);
2075       how &= flagmask & SOLVER_SETMASK;
2076       if (how)
2077         {
2078           int o = strlen(s);
2079           s = pool_tmpappend(pool, s, " ", 0);
2080           if (how & SOLVER_SETEV)
2081             s = pool_tmpappend(pool, s, ",setev", 0);
2082           if (how & SOLVER_SETEVR)
2083             s = pool_tmpappend(pool, s, ",setevr", 0);
2084           if (how & SOLVER_SETARCH)
2085             s = pool_tmpappend(pool, s, ",setarch", 0);
2086           if (how & SOLVER_SETVENDOR)
2087             s = pool_tmpappend(pool, s, ",setvendor", 0);
2088           if (how & SOLVER_SETREPO)
2089             s = pool_tmpappend(pool, s, ",setrepo", 0);
2090           if (how & SOLVER_NOAUTOSET)
2091             s = pool_tmpappend(pool, s, ",noautoset", 0);
2092           if (s[o + 1] != ',')
2093             s = pool_tmpappend(pool, s, ",?", 0);
2094           s[o + 1] = '[';
2095           s = pool_tmpappend(pool, s, "]", 0);
2096         }
2097     }
2098   return s;
2099 }
2100