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