Imported Upstream version 0.6.29
[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
25
26 static int
27 str2archid(Pool *pool, const char *arch)
28 {
29   Id id;
30   if (!*arch)
31     return 0;
32   id = pool_str2id(pool, arch, 0);
33   if (!id || id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH)
34     return id;
35   if (pool->id2arch && (id > pool->lastarch || !pool->id2arch[id]))
36     return 0;
37   return id;
38 }
39
40 static void
41 selection_prune(Pool *pool, Queue *selection)
42 {
43   int i, j;
44   Id p, pp;
45   for (i = j = 0; i < selection->count; i += 2)
46     {
47       Id select = selection->elements[i] & SOLVER_SELECTMASK;
48       p = 0;
49       if (select == SOLVER_SOLVABLE_ALL)
50         p = 1;
51       else if (select == SOLVER_SOLVABLE_REPO)
52         {
53           Solvable *s;
54           Repo *repo = pool_id2repo(pool, selection->elements[i + 1]);
55           if (repo)
56             {
57               FOR_REPO_SOLVABLES(repo, p, s)
58                 break;
59             }
60         }
61       else
62         {
63           FOR_JOB_SELECT(p, pp, select, selection->elements[i + 1])
64             break;
65         }
66       if (!p)
67         continue;
68       selection->elements[j] = selection->elements[i];
69       selection->elements[j + 1] = selection->elements[i + 1];
70       j += 2;
71     }
72   queue_truncate(selection, j);
73 }
74
75
76 static int
77 selection_solvables_sortcmp(const void *ap, const void *bp, void *dp)
78 {
79   return *(const Id *)ap - *(const Id *)bp;
80 }
81
82 void
83 selection_solvables(Pool *pool, Queue *selection, Queue *pkgs)
84 {
85   int i, j;
86   Id p, pp, lastid;
87   queue_empty(pkgs);
88   for (i = 0; i < selection->count; i += 2)
89     {
90       Id select = selection->elements[i] & SOLVER_SELECTMASK;
91       if (select == SOLVER_SOLVABLE_ALL)
92         {
93           FOR_POOL_SOLVABLES(p)
94             queue_push(pkgs, p);
95         }
96       if (select == SOLVER_SOLVABLE_REPO)
97         {
98           Solvable *s;
99           Repo *repo = pool_id2repo(pool, selection->elements[i + 1]);
100           if (repo)
101             {
102               FOR_REPO_SOLVABLES(repo, p, s)
103                 queue_push(pkgs, p);
104             }
105         }
106       else
107         {
108           FOR_JOB_SELECT(p, pp, select, selection->elements[i + 1])
109             queue_push(pkgs, p);
110         }
111     }
112   if (pkgs->count < 2)
113     return;
114   /* sort and unify */
115   solv_sort(pkgs->elements, pkgs->count, sizeof(Id), selection_solvables_sortcmp, NULL);
116   lastid = pkgs->elements[0];
117   for (i = j = 1; i < pkgs->count; i++)
118     if (pkgs->elements[i] != lastid)
119       pkgs->elements[j++] = lastid = pkgs->elements[i];
120   queue_truncate(pkgs, j);
121 }
122
123 static void
124 selection_flatten(Pool *pool, Queue *selection)
125 {
126   Queue q;
127   int i;
128   if (selection->count <= 2)
129     return;
130   for (i = 0; i < selection->count; i += 2)
131     if ((selection->elements[i] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
132       {
133         selection->elements[0] = selection->elements[i];
134         selection->elements[1] = selection->elements[i + 1];
135         queue_truncate(selection, 2);
136         return;
137       }
138   queue_init(&q);
139   selection_solvables(pool, selection, &q);
140   if (!q.count)
141     {
142       queue_empty(selection);
143       return;
144     }
145   queue_truncate(selection, 2);
146   if (q.count > 1)
147     {
148       selection->elements[0] = SOLVER_SOLVABLE_ONE_OF;
149       selection->elements[1] = pool_queuetowhatprovides(pool, &q);
150     }
151   else
152     {
153       selection->elements[0] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
154       selection->elements[1] = q.elements[0];
155     }
156 }
157
158 static void
159 selection_filter_rel(Pool *pool, Queue *selection, Id relflags, Id relevr)
160 {
161   int i;
162
163   for (i = 0; i < selection->count; i += 2)
164     {
165       Id select = selection->elements[i] & SOLVER_SELECTMASK;
166       Id id = selection->elements[i + 1];
167       if (select == SOLVER_SOLVABLE || select == SOLVER_SOLVABLE_ONE_OF)
168         {
169           /* done by selection_addsrc, currently implies SELECTION_NAME */
170           Queue q;
171           Id p, pp;
172           Id rel = 0, relname = 0;
173           int miss = 0;
174
175           queue_init(&q);
176           FOR_JOB_SELECT(p, pp, select, id)
177             {
178               Solvable *s = pool->solvables + p;
179               if (!rel || s->name != relname)
180                 {
181                   relname = s->name;
182                   rel = pool_rel2id(pool, relname, relevr, relflags, 1);
183                 }
184               if (pool_match_nevr(pool, s, rel))
185                 queue_push(&q, p);
186               else
187                 miss = 1;
188             }
189           if (miss)
190             {
191               if (q.count == 1)
192                 {
193                   selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
194                   selection->elements[i + 1] = q.elements[0];
195                 }
196               else
197                 {
198                   selection->elements[i] = SOLVER_SOLVABLE_ONE_OF;
199                   selection->elements[i + 1] = pool_queuetowhatprovides(pool, &q);
200                 }
201             }
202           queue_free(&q);
203         }
204       else if (select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES)
205         {
206           /* don't stack src reldeps */
207           if (relflags == REL_ARCH && (relevr == ARCH_SRC || relevr == ARCH_NOSRC) && ISRELDEP(id))
208             {
209               Reldep *rd = GETRELDEP(pool, id);
210               if (rd->flags == REL_ARCH && rd->evr == ARCH_SRC)
211                 id = rd->name;
212             }
213           selection->elements[i + 1] = pool_rel2id(pool, id, relevr, relflags, 1);
214         }
215       else
216         continue;       /* actually internal error */
217       if (relflags == REL_ARCH)
218         selection->elements[i] |= SOLVER_SETARCH;
219       if (relflags == REL_EQ && select != SOLVER_SOLVABLE_PROVIDES)
220         {
221           if (pool->disttype == DISTTYPE_DEB)
222             selection->elements[i] |= SOLVER_SETEVR;    /* debian can't match version only like rpm */
223           else
224             {
225               const char *rel =  strrchr(pool_id2str(pool, relevr), '-');
226               selection->elements[i] |= rel ? SOLVER_SETEVR : SOLVER_SETEV;
227             }
228         }
229     }
230   selection_prune(pool, selection);
231 }
232
233 static void
234 selection_filter_installed(Pool *pool, Queue *selection)
235 {
236   Queue q;
237   int i, j;
238
239   if (!pool->installed)
240     queue_empty(selection);
241   queue_init(&q);
242   for (i = j = 0; i < selection->count; i += 2)
243     {
244       Id select = selection->elements[i] & SOLVER_SELECTMASK;
245       Id id = selection->elements[i + 1];
246       if (select == SOLVER_SOLVABLE_ALL)
247         {
248           select = SOLVER_SOLVABLE_REPO;
249           id = pool->installed->repoid;
250         }
251       else if (select == SOLVER_SOLVABLE_REPO)
252         {
253           if (id != pool->installed->repoid)
254             select = 0;
255         }
256       else
257         {
258           int bad = 0;
259           Id p, pp;
260           queue_empty(&q);
261           FOR_JOB_SELECT(p, pp, select, id)
262             {
263               if (pool->solvables[p].repo != pool->installed)
264                 bad = 1;
265               else
266                 queue_push(&q, p);
267             }
268           if (bad || !q.count)
269             {
270               if (!q.count)
271                 select = 0;
272               else if (q.count == 1)
273                 {
274                   select = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
275                   id = q.elements[0];
276                 }
277               else
278                 {
279                   select = SOLVER_SOLVABLE_ONE_OF;
280                   id = pool_queuetowhatprovides(pool, &q);
281                 }
282             }
283         }
284       if (select)
285         {
286           selection->elements[j++] = select | (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SETREPO;
287           selection->elements[j++] = id;
288         }
289     }
290   queue_truncate(selection, j);
291   queue_free(&q);
292 }
293
294 static void
295 selection_addsrc(Pool *pool, Queue *selection, int flags)
296 {
297   Queue q;
298   Id p, name;
299   int i, havesrc;
300
301   if ((flags & SELECTION_INSTALLED_ONLY) != 0)
302     return;     /* sources can't be installed */
303   queue_init(&q);
304   for (i = 0; i < selection->count; i += 2)
305     {
306       if (selection->elements[i] != SOLVER_SOLVABLE_NAME)
307         continue;
308       name = selection->elements[i + 1];
309       havesrc = 0;
310       queue_empty(&q);
311       FOR_POOL_SOLVABLES(p)
312         {
313           Solvable *s = pool->solvables + p;
314           if (s->name != name)
315             continue;
316           if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
317             {
318               if (pool_disabled_solvable(pool, s))
319                 continue;
320               havesrc = 1;
321             }
322           else if (s->repo != pool->installed && !pool_installable(pool, s))
323             continue;
324           queue_push(&q, p);
325         }
326       if (!havesrc || !q.count)
327         continue;
328       if (q.count == 1)
329         {
330           selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
331           selection->elements[i + 1] = q.elements[0];
332         }
333       else
334         {
335           selection->elements[i] = SOLVER_SOLVABLE_ONE_OF;
336           selection->elements[i + 1] = pool_queuetowhatprovides(pool, &q);
337         }
338     }
339   queue_free(&q);
340 }
341
342 static inline const char *
343 skipkind(const char *n)
344 {
345   const char *s;
346   for (s = n; *s >= 'a' && *s <= 'z'; s++)
347     ;
348   if (*s == ':' && s != n)
349      return s + 1;
350   return n;
351 }
352
353 static inline void
354 queue_pushunique2(Queue *q, Id id1, Id id2)
355 {
356   int i;
357   for (i = 0; i < q->count; i += 2)
358     if (q->elements[i] == id1 && q->elements[i + 1] == id2)
359       return;
360   queue_push2(q, id1, id2);
361 }
362
363 static int
364 selection_depglob_id(Pool *pool, Queue *selection, Id id, int flags)
365 {
366   Id p, pp;
367   int match = 0;
368
369   FOR_PROVIDES(p, pp, id)
370     {
371       Solvable *s = pool->solvables + p;
372       if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
373         continue;
374       match = 1;
375       if (s->name == id && (flags & SELECTION_NAME) != 0)
376         {
377           if ((flags & SELECTION_SOURCE_ONLY) != 0)
378             id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
379           queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
380           if ((flags & SELECTION_WITH_SOURCE) != 0)
381             selection_addsrc(pool, selection, flags);
382           return SELECTION_NAME;
383         }
384     }
385   if ((flags & (SELECTION_SOURCE_ONLY | SELECTION_WITH_SOURCE)) != 0 && (flags & SELECTION_NAME) != 0)
386     {
387       /* src rpms don't have provides, so we must check every solvable */
388       FOR_POOL_SOLVABLES(p)     /* slow path */
389         {
390           Solvable *s = pool->solvables + p;
391           if (s->name == id && (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC))
392             {
393               if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
394                 continue;       /* just in case... src rpms can't be installed */
395               if (pool_disabled_solvable(pool, s))
396                 continue;
397               if ((flags & SELECTION_SOURCE_ONLY) != 0)
398                 id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
399               queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
400               if ((flags & SELECTION_WITH_SOURCE) != 0)
401                 selection_addsrc(pool, selection, flags);
402               return SELECTION_NAME;
403             }
404         }
405     }
406   if (match && (flags & SELECTION_PROVIDES) != 0)
407     {
408       queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
409       return SELECTION_PROVIDES;
410     }
411   return 0;
412 }
413
414 static int
415 selection_depglob(Pool *pool, Queue *selection, const char *name, int flags)
416 {
417   Id id, p, pp;
418   int match = 0;
419   int doglob = 0;
420   int nocase = 0;
421   int globflags = 0;
422
423   if ((flags & SELECTION_SOURCE_ONLY) != 0)
424     {
425       flags &= ~SELECTION_PROVIDES;     /* sources don't provide anything */
426       flags &= ~SELECTION_WITH_SOURCE;
427     }
428
429   if (!(flags & (SELECTION_NAME|SELECTION_PROVIDES)))
430     return 0;
431
432   if ((flags & SELECTION_INSTALLED_ONLY) != 0 && !pool->installed)
433     return 0;
434
435   nocase = flags & SELECTION_NOCASE;
436   if (!nocase && !(flags & SELECTION_SKIP_KIND))
437     {
438       id = pool_str2id(pool, name, 0);
439       if (id)
440         {
441           /* the id is know, do the fast id matching using the whatprovides lookup */
442           int ret = selection_depglob_id(pool, selection, id, flags);
443           if (ret)
444             return ret;
445         }
446     }
447
448   if ((flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0)
449     doglob = 1;
450
451   if (!nocase && !(flags & SELECTION_SKIP_KIND) && !doglob)
452     return 0;   /* all done above in depglob_id */
453
454   if (doglob && nocase)
455     globflags = FNM_CASEFOLD;
456
457   if ((flags & SELECTION_NAME) != 0)
458     {
459       /* looks like a name glob. hard work. */
460       FOR_POOL_SOLVABLES(p)
461         {
462           Solvable *s = pool->solvables + p;
463           const char *n;
464           if (s->repo != pool->installed && !pool_installable(pool, s))
465             {
466               if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
467                 continue;
468               if (pool_disabled_solvable(pool, s))
469                 continue;
470             }
471           if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
472             continue;
473           id = s->name;
474           n = pool_id2str(pool, id);
475           if (flags & SELECTION_SKIP_KIND)
476             n = skipkind(n);
477           if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
478             {
479               if ((flags & SELECTION_SOURCE_ONLY) != 0)
480                 id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
481               queue_pushunique2(selection, SOLVER_SOLVABLE_NAME, id);
482               match = 1;
483             }
484         }
485       if (match)
486         {
487           if ((flags & SELECTION_WITH_SOURCE) != 0)
488             selection_addsrc(pool, selection, flags);
489           return SELECTION_NAME;
490         }
491     }
492
493   if ((flags & SELECTION_PROVIDES))
494     {
495       /* looks like a dep glob. really hard work. */
496       for (id = 1; id < pool->ss.nstrings; id++)
497         {
498           const char *n;
499           if (!pool->whatprovides[id] || pool->whatprovides[id] == 1)
500             continue;
501           n = pool_id2str(pool, id);
502           if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
503             {
504               if ((flags & SELECTION_INSTALLED_ONLY) != 0)
505                 {
506                   FOR_PROVIDES(p, pp, id)
507                     if (pool->solvables[p].repo == pool->installed)
508                       break;
509                   if (!p)
510                     continue;
511                 }
512               queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
513               match = 1;
514             }
515         }
516       if (match)
517         return SELECTION_PROVIDES;
518     }
519   return 0;
520 }
521
522 static int
523 selection_depglob_arch(Pool *pool, Queue *selection, const char *name, int flags)
524 {
525   int ret;
526   const char *r;
527   Id archid;
528
529   if ((ret = selection_depglob(pool, selection, name, flags)) != 0)
530     return ret;
531   if (!(flags & SELECTION_DOTARCH))
532     return 0;
533   /* check if there is an .arch suffix */
534   if ((r = strrchr(name, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
535     {
536       char *rname = solv_strdup(name);
537       rname[r - name] = 0;
538       if (archid == ARCH_SRC || archid == ARCH_NOSRC)
539         flags |= SELECTION_SOURCE_ONLY;
540       if ((ret = selection_depglob(pool, selection, rname, flags)) != 0)
541         {
542           selection_filter_rel(pool, selection, REL_ARCH, archid);
543           solv_free(rname);
544           return ret | SELECTION_DOTARCH;
545         }
546       solv_free(rname);
547     }
548   return 0;
549 }
550
551 static int
552 selection_filelist(Pool *pool, Queue *selection, const char *name, int flags)
553 {
554   Dataiterator di;
555   Queue q;
556   int type;
557
558   /* all files in the file list start with a '/' */
559   if (*name != '/')
560     {
561       if (!(flags & SELECTION_GLOB))
562         return 0;
563       if (*name != '*' && *name != '[' && *name != '?')
564         return 0;
565     }
566   type = !(flags & SELECTION_GLOB) || strpbrk(name, "[*?") == 0 ? SEARCH_STRING : SEARCH_GLOB;
567   if ((flags & SELECTION_NOCASE) != 0)
568     type |= SEARCH_NOCASE;
569   queue_init(&q);
570   dataiterator_init(&di, pool, flags & SELECTION_INSTALLED_ONLY ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES|SEARCH_COMPLETE_FILELIST);
571   while (dataiterator_step(&di))
572     {
573       Solvable *s = pool->solvables + di.solvid;
574       if (!s->repo)
575         continue;
576       if (s->repo != pool->installed && !pool_installable(pool, s))
577         {
578           if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
579             continue;
580           if (pool_disabled_solvable(pool, s))
581             continue;
582         }
583       if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
584         continue;
585       queue_push(&q, di.solvid);
586       dataiterator_skip_solvable(&di);
587     }
588   dataiterator_free(&di);
589   if (!q.count)
590     return 0;
591   if (q.count > 1)
592     queue_push2(selection, SOLVER_SOLVABLE_ONE_OF, pool_queuetowhatprovides(pool, &q));
593   else
594     queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, q.elements[0]);
595   queue_free(&q);
596   return SELECTION_FILELIST;
597 }
598
599 static char *
600 splitrel(char *rname, char *r, int *rflagsp)
601 {
602   int nend = r - rname;
603   int rflags = 0;
604   if (nend && *r == '=' && r[-1] == '!')
605     {
606       nend--;
607       r++;
608       rflags = REL_LT|REL_GT;
609     }
610   for (; *r; r++)
611     {
612       if (*r == '<')
613         rflags |= REL_LT;
614       else if (*r == '=')
615         rflags |= REL_EQ;
616       else if (*r == '>')
617         rflags |= REL_GT;
618       else
619         break;
620     }
621   while (*r && (*r == ' ' || *r == '\t'))
622     r++;
623   while (nend && (rname[nend - 1] == ' ' || rname[nend - 1] == '\t'))
624     nend--;
625   if (!*rname || !*r)
626     return 0;
627   *rflagsp = rflags;
628   rname[nend] = 0;
629   return r;
630 }
631
632 static int
633 selection_rel(Pool *pool, Queue *selection, const char *name, int flags)
634 {
635   int ret, rflags = 0;
636   char *r, *rname;
637
638   /* relation case, support:
639    * depglob rel
640    * depglob.arch rel
641    */
642   rname = solv_strdup(name);
643   if ((r = strpbrk(rname, "<=>")) != 0)
644     {
645       if ((r = splitrel(rname, r, &rflags)) == 0)
646         {
647           solv_free(rname);
648           return 0;
649         }
650     }
651   if ((ret = selection_depglob_arch(pool, selection, rname, flags)) != 0)
652     {
653       if (rflags)
654         selection_filter_rel(pool, selection, rflags, pool_str2id(pool, r, 1));
655       solv_free(rname);
656       return ret | SELECTION_REL;
657     }
658   solv_free(rname);
659   return 0;
660 }
661
662 #if defined(MULTI_SEMANTICS)
663 # define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE)
664 #elif defined(DEBIAN)
665 # define EVRCMP_DEPCMP EVRCMP_COMPARE
666 #else
667 # define EVRCMP_DEPCMP EVRCMP_MATCH_RELEASE
668 #endif
669
670 /* magic epoch promotion code, works only for SELECTION_NAME selections */
671 static void
672 selection_filter_evr(Pool *pool, Queue *selection, char *evr)
673 {
674   int i, j;
675   Queue q;
676   Id qbuf[10];
677
678   queue_init(&q);
679   queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
680   for (i = j = 0; i < selection->count; i += 2)
681     {
682       Id select = selection->elements[i] & SOLVER_SELECTMASK;
683       Id id = selection->elements[i + 1];
684       Id p, pp;
685       const char *lastepoch = 0;
686       int lastepochlen = 0;
687
688       queue_empty(&q);
689       FOR_JOB_SELECT(p, pp, select, id)
690         {
691           Solvable *s = pool->solvables + p;
692           const char *sevr = pool_id2str(pool, s->evr);
693           const char *sp;
694           for (sp = sevr; *sp >= '0' && *sp <= '9'; sp++)
695             ;
696           if (*sp != ':')
697             sp = sevr;
698           /* compare vr part */
699           if (strcmp(evr, sp != sevr ? sp + 1 : sevr) != 0)
700             {
701               int r = pool_evrcmp_str(pool, sp != sevr ? sp + 1 : sevr, evr, EVRCMP_DEPCMP);
702               if (r == -1 || r == 1)
703                 continue;       /* solvable does not match vr */
704             }
705           queue_push(&q, p);
706           if (sp > sevr)
707             {
708               while (sevr < sp && *sevr == '0') /* normalize epoch */
709                 sevr++;
710             }
711           if (!lastepoch)
712             {
713               lastepoch = sevr;
714               lastepochlen = sp - sevr;
715             }
716           else if (lastepochlen != sp - sevr || strncmp(lastepoch, sevr, lastepochlen) != 0)
717             lastepochlen = -1;  /* multiple different epochs */
718         }
719       if (!lastepoch || lastepochlen == 0)
720         id = pool_str2id(pool, evr, 1);         /* no match at all or zero epoch */
721       else if (lastepochlen >= 0)
722         {
723           /* found exactly one epoch, simply prepend */
724           char *evrx = solv_malloc(strlen(evr) + lastepochlen + 2);
725           strncpy(evrx, lastepoch, lastepochlen + 1);
726           strcpy(evrx + lastepochlen + 1, evr);
727           id = pool_str2id(pool, evrx, 1);
728           solv_free(evrx);
729         }
730       else
731         {
732           /* multiple epochs in multiple solvables, convert to list of solvables */
733           selection->elements[j] = (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF;
734           selection->elements[j + 1] = pool_queuetowhatprovides(pool, &q);
735           j += 2;
736           continue;
737         }
738       queue_empty(&q);
739       queue_push2(&q, selection->elements[i], selection->elements[i + 1]);
740       selection_filter_rel(pool, &q, REL_EQ, id);
741       if (!q.count)
742         continue;               /* oops, no match */
743       selection->elements[j] = q.elements[0];
744       selection->elements[j + 1] = q.elements[1];
745       j += 2;
746     }
747   queue_truncate(selection, j);
748   queue_free(&q);
749 }
750
751 /* match the "canonical" name of the package */
752 static int
753 selection_canon(Pool *pool, Queue *selection, const char *name, int flags)
754 {
755   char *rname, *r, *r2;
756   Id archid = 0;
757   int ret;
758
759   /*
760    * nameglob-version
761    * nameglob-version.arch
762    * nameglob-version-release
763    * nameglob-version-release.arch
764    */
765   flags |= SELECTION_NAME;
766   flags &= ~SELECTION_PROVIDES;
767
768   if (pool->disttype == DISTTYPE_DEB)
769     {
770       if ((r = strchr(name, '_')) == 0)
771         return 0;
772       rname = solv_strdup(name);        /* so we can modify it */
773       r = rname + (r - name);
774       *r++ = 0;
775       if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
776         {
777           solv_free(rname);
778           return 0;
779         }
780       /* is there a vaild arch? */
781       if ((r2 = strrchr(r, '_')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
782         {
783           *r2 = 0;      /* split off */
784           selection_filter_rel(pool, selection, REL_ARCH, archid);
785         }
786       selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1));
787       solv_free(rname);
788       return ret | SELECTION_CANON;
789     }
790
791   if (pool->disttype == DISTTYPE_HAIKU)
792     {
793       if ((r = strchr(name, '-')) == 0)
794         return 0;
795       rname = solv_strdup(name);        /* so we can modify it */
796       r = rname + (r - name);
797       *r++ = 0;
798       if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
799         {
800           solv_free(rname);
801           return 0;
802         }
803       /* is there a vaild arch? */
804       if ((r2 = strrchr(r, '-')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
805         {
806           *r2 = 0;      /* split off */
807           selection_filter_rel(pool, selection, REL_ARCH, archid);
808         }
809       selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1));
810       solv_free(rname);
811       return ret | SELECTION_CANON;
812     }
813
814   if ((r = strrchr(name, '-')) == 0)
815     return 0;
816   rname = solv_strdup(name);    /* so we can modify it */
817   r = rname + (r - name);
818   *r = 0;
819
820   /* split off potential arch part from version */
821   if ((r2 = strrchr(r + 1, '.')) != 0 && r2[1] && (archid = str2archid(pool, r2 + 1)) != 0)
822     *r2 = 0;    /* found valid arch, split it off */
823   if (archid == ARCH_SRC || archid == ARCH_NOSRC)
824     flags |= SELECTION_SOURCE_ONLY;
825
826   /* try with just the version */
827   if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
828     {
829       /* no luck, try with version-release */
830       if ((r2 = strrchr(rname, '-')) == 0)
831         {
832           solv_free(rname);
833           return 0;
834         }
835       *r = '-';
836       *r2 = 0;
837       r = r2;
838       if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
839         {
840           solv_free(rname);
841           return 0;
842         }
843     }
844   if (archid)
845     selection_filter_rel(pool, selection, REL_ARCH, archid);
846   selection_filter_evr(pool, selection, r + 1); /* magic epoch promotion */
847   solv_free(rname);
848   return ret | SELECTION_CANON;
849 }
850
851 int
852 selection_make(Pool *pool, Queue *selection, const char *name, int flags)
853 {
854   int ret = 0;
855
856   queue_empty(selection);
857   if ((flags & SELECTION_FILELIST) != 0)
858     ret = selection_filelist(pool, selection, name, flags);
859   if (!ret && (flags & SELECTION_REL) != 0 && strpbrk(name, "<=>") != 0)
860     ret = selection_rel(pool, selection, name, flags);
861   if (!ret)
862     ret = selection_depglob_arch(pool, selection, name, flags);
863   if (!ret && (flags & SELECTION_CANON) != 0)
864     ret = selection_canon(pool, selection, name, flags);
865   if (selection->count && (flags & SELECTION_INSTALLED_ONLY) != 0)
866     selection_filter_installed(pool, selection);
867   if (ret && !selection->count)
868     ret = 0;    /* no match -> always return zero */
869   if (ret && (flags & SELECTION_FLAT) != 0)
870     selection_flatten(pool, selection);
871   return ret;
872 }
873
874 static inline int
875 matchdep_str(const char *pattern, const char *string, int flags)
876 {
877   if (flags & SELECTION_GLOB)
878     {
879       int globflags = (flags & SELECTION_NOCASE) != 0 ? FNM_CASEFOLD : 0;
880       return fnmatch(pattern, string, globflags) == 0 ? 1 : 0;
881     }
882   if (flags & SELECTION_NOCASE)
883     return strcasecmp(pattern, string) == 0 ? 1 : 0;
884   return strcmp(pattern, string) == 0 ? 1 : 0;
885 }
886
887 static int
888 matchdep(Pool *pool, Id id, char *rname, int rflags, char *revr, int flags)
889 {
890   if (ISRELDEP(id))
891     {
892       Reldep *rd = GETRELDEP(pool, id);
893       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)
894         {
895           if (matchdep(pool, rd->name, rname, rflags, revr, flags))
896             return 1;
897           if ((rd->flags == REL_COND || rd->flags == REL_UNLESS) && ISRELDEP(rd->evr))
898             {
899               rd = GETRELDEP(pool, rd->evr);
900               if (rd->flags != REL_ELSE)
901                 return 0;
902             }
903           if (rd->flags != REL_COND && rd->flags != REL_UNLESS && rd->flags != REL_WITHOUT && matchdep(pool, rd->evr, rname, rflags, revr, flags))
904             return 1;
905           return 0;
906         }
907       if (rd->flags == REL_ARCH)
908         return matchdep(pool, rd->name, rname, rflags, revr, flags);
909       if (!matchdep(pool, rd->name, rname, rflags, revr, flags))
910         return 0;
911       if (rflags)
912         {
913           /* XXX: need pool_match_flags_evr here */
914           if (!pool_match_dep(pool, pool_rel2id(pool, rd->name, pool_str2id(pool, revr, 1), rflags, 1), id))
915             return 0;
916         }
917       return 1;
918     }
919   return matchdep_str(rname, pool_id2str(pool, id), flags);
920 }
921
922 /*
923  *  select against the dependencies in keyname
924  *  like SELECTION_REL and SELECTION_PROVIDES, but with the
925  *  deps in keyname instead of provides.
926  */
927 int
928 selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int flags, int keyname, int marker)
929 {
930   char *rname, *r = 0;
931   int rflags = 0;
932   Id p;
933   Queue q;
934
935   queue_empty(selection);
936   rname = solv_strdup(name);
937   if (!(flags & SELECTION_MATCH_DEPSTR))
938     {
939       if ((r = strpbrk(rname, "<=>")) != 0)
940         {
941           if ((r = splitrel(rname, r, &rflags)) == 0)
942             {
943               solv_free(rname);
944               return 0;
945             }
946         }
947     }
948   if ((flags & SELECTION_GLOB) != 0 && !strpbrk(rname, "[*?") != 0)
949     flags &= ~SELECTION_GLOB;
950
951   queue_init(&q);
952   FOR_POOL_SOLVABLES(p)
953     {
954       Solvable *s =  pool->solvables + p;
955       int i;
956
957       if (s->repo != pool->installed && !pool_installable(pool, s))
958         {
959           if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
960             continue;
961           if (pool_disabled_solvable(pool, s))
962             continue;
963         }
964       if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
965         continue;
966       if ((s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) && !(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
967         continue;
968       queue_empty(&q);
969       repo_lookup_deparray(s->repo, p, keyname, &q, marker);
970       for (i = 0; i < q.count; i++)
971         {
972           Id id = q.elements[i];
973           if ((flags & SELECTION_MATCH_DEPSTR) != 0)
974             {
975               if (matchdep_str(rname, pool_dep2str(pool, id), flags))
976                 break;
977               continue;
978             }
979           if (matchdep(pool, id, rname, rflags, r, flags))
980             break;
981         }
982       if (i < q.count)
983         queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, p);
984     }
985   queue_free(&q);
986   solv_free(rname);
987   if (!selection->count)
988     return 0;
989   if ((flags & SELECTION_FLAT) != 0)
990     selection_flatten(pool, selection);
991   return SELECTION_PROVIDES;
992 }
993
994 int
995 selection_make_matchdepid(Pool *pool, Queue *selection, Id dep, int flags, int keyname, int marker)
996 {
997   Id p;
998   Queue q;
999
1000   queue_empty(selection);
1001   if (!dep)
1002     return 0;
1003   queue_init(&q);
1004   FOR_POOL_SOLVABLES(p)
1005     {
1006       Solvable *s =  pool->solvables + p;
1007       int i;
1008
1009       if (s->repo != pool->installed && !pool_installable(pool, s))
1010         {
1011           if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
1012             continue;
1013           if (pool_disabled_solvable(pool, s))
1014             continue;
1015         }
1016       if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
1017         continue;
1018       if ((s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) && !(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
1019         continue;
1020       queue_empty(&q);
1021       repo_lookup_deparray(s->repo, p, keyname, &q, marker);
1022       for (i = 0; i < q.count; i++)
1023         {
1024           if ((flags & SELECTION_MATCH_DEPSTR) != 0)    /* mis-use */
1025             {
1026               if (q.elements[i] == dep)
1027                 break;
1028               continue;
1029             }
1030           if (pool_match_dep(pool, q.elements[i], dep))
1031             break;
1032         }
1033       if (i < q.count)
1034         queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, p);
1035     }
1036   queue_free(&q);
1037   if (!selection->count)
1038     return 0;
1039   if ((flags & SELECTION_FLAT) != 0)
1040     selection_flatten(pool, selection);
1041   return SELECTION_PROVIDES;
1042 }
1043
1044 static inline int
1045 pool_is_kind(Pool *pool, Id name, Id kind)
1046 {
1047   const char *n;
1048   if (!kind)
1049     return 1;
1050   n = pool_id2str(pool, name);
1051   if (kind != 1)
1052     {
1053       const char *kn = pool_id2str(pool, kind);
1054       int knl = strlen(kn);
1055       return !strncmp(n, kn, knl) && n[knl] == ':' ? 1 : 0;
1056     }
1057   else
1058     {
1059       if (*n == ':')
1060         return 1;
1061       while(*n >= 'a' && *n <= 'z')
1062         n++;
1063       return *n == ':' ? 0 : 1;
1064     }
1065 }
1066
1067 void
1068 selection_filter(Pool *pool, Queue *sel1, Queue *sel2)
1069 {
1070   int i, j, miss;
1071   Id p, pp, q1filled = 0;
1072   Queue q1;
1073   Map m2;
1074   Id setflags = 0;
1075
1076   if (!sel1->count || !sel2->count)
1077     {
1078       queue_empty(sel1);
1079       return;
1080     }
1081   if (sel1->count == 2 && (sel1->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
1082     {
1083       /* XXX: not 100% correct, but very useful */
1084       p = sel1->elements[0] & ~(SOLVER_SELECTMASK | SOLVER_SETMASK);    /* job & jobflags */
1085       queue_free(sel1);
1086       queue_init_clone(sel1, sel2);
1087       for (i = 0; i < sel1->count; i += 2)
1088         sel1->elements[i] = (sel1->elements[i] & (SOLVER_SELECTMASK | SOLVER_SETMASK)) | p ;
1089       return;
1090     }
1091   queue_init(&q1);
1092   map_init(&m2, pool->nsolvables);
1093   for (i = 0; i < sel2->count; i += 2)
1094     {
1095       Id select = sel2->elements[i] & SOLVER_SELECTMASK;
1096       if (select == SOLVER_SOLVABLE_ALL)
1097         {
1098           queue_free(&q1);
1099           map_free(&m2);
1100           return;
1101         }
1102       if (select == SOLVER_SOLVABLE_REPO)
1103         {
1104           Solvable *s;
1105           Repo *repo = pool_id2repo(pool, sel2->elements[i + 1]);
1106           if (repo)
1107             {
1108               FOR_REPO_SOLVABLES(repo, p, s)
1109                 map_set(&m2, p);
1110             }
1111         }
1112       else
1113         {
1114           if ((select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES) && ISRELDEP(sel2->elements[i + 1]))
1115             {
1116               Reldep *rd = GETRELDEP(pool, sel2->elements[i + 1]);
1117               if (rd->flags == REL_ARCH && rd->name == 0)
1118                 {
1119                   /* special arch filter */
1120                   if (!q1filled++)
1121                     selection_solvables(pool, sel1, &q1);
1122                   for (j = 0; j < q1.count; j++)
1123                     {
1124                       Id p = q1.elements[j];
1125                       Solvable *s = pool->solvables + p;
1126                       if (s->arch == rd->evr || (rd->evr == ARCH_SRC && s->arch == ARCH_NOSRC))
1127                         map_set(&m2, p);
1128                     }
1129                   continue;
1130                 }
1131               else if (rd->flags == REL_KIND && rd->name == 0)
1132                 {
1133                   /* special kind filter */
1134                   if (!q1filled++)
1135                     selection_solvables(pool, sel1, &q1);
1136                   for (j = 0; j < q1.count; j++)
1137                     {
1138                       Id p = q1.elements[j];
1139                       Solvable *s = pool->solvables + p;
1140                       if (pool_is_kind(pool, s->name, rd->evr))
1141                         map_set(&m2, p);
1142                     }
1143                   continue;
1144                 }
1145             }
1146           FOR_JOB_SELECT(p, pp, select, sel2->elements[i + 1])
1147             map_set(&m2, p);
1148         }
1149     }
1150   if (sel2->count == 2)         /* XXX: AND all setmasks instead? */
1151     setflags = sel2->elements[0] & SOLVER_SETMASK & ~SOLVER_NOAUTOSET;
1152   for (i = j = 0; i < sel1->count; i += 2)
1153     {
1154       Id select = sel1->elements[i] & SOLVER_SELECTMASK;
1155       queue_empty(&q1);
1156       miss = 0;
1157       if (select == SOLVER_SOLVABLE_ALL)
1158         {
1159           FOR_POOL_SOLVABLES(p)
1160             {
1161               if (map_tst(&m2, p))
1162                 queue_push(&q1, p);
1163               else
1164                 miss = 1;
1165             }
1166         }
1167       else if (select == SOLVER_SOLVABLE_REPO)
1168         {
1169           Solvable *s;
1170           Repo *repo = pool_id2repo(pool, sel1->elements[i + 1]);
1171           if (repo)
1172             {
1173               FOR_REPO_SOLVABLES(repo, p, s)
1174                 {
1175                   if (map_tst(&m2, p))
1176                     queue_push(&q1, p);
1177                   else
1178                     miss = 1;
1179                 }
1180             }
1181         }
1182       else
1183         {
1184           FOR_JOB_SELECT(p, pp, select, sel1->elements[i + 1])
1185             {
1186               if (map_tst(&m2, p))
1187                 queue_pushunique(&q1, p);
1188               else
1189                 miss = 1;
1190             }
1191         }
1192       if (!q1.count)
1193         continue;
1194       if (!miss)
1195         {
1196           sel1->elements[j] = sel1->elements[i] | setflags;
1197           sel1->elements[j + 1] = sel1->elements[i + 1];
1198         }
1199       else if (q1.count > 1)
1200         {
1201           sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF | setflags;
1202           sel1->elements[j + 1] = pool_queuetowhatprovides(pool, &q1);
1203         }
1204       else
1205         {
1206           sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE | SOLVER_NOAUTOSET | setflags;
1207           sel1->elements[j + 1] = q1.elements[0];
1208         }
1209       j += 2;
1210     }
1211   queue_truncate(sel1, j);
1212   queue_free(&q1);
1213   map_free(&m2);
1214 }
1215
1216 void
1217 selection_add(Pool *pool, Queue *sel1, Queue *sel2)
1218 {
1219   int i;
1220   for (i = 0; i < sel2->count; i++)
1221     queue_push(sel1, sel2->elements[i]);
1222 }
1223
1224 const char *
1225 pool_selection2str(Pool *pool, Queue *selection, Id flagmask)
1226 {
1227   char *s;
1228   const char *s2;
1229   int i;
1230   s = pool_tmpjoin(pool, 0, 0, 0);
1231   for (i = 0; i < selection->count; i += 2)
1232     {
1233       Id how = selection->elements[i];
1234       if (*s)
1235         s = pool_tmpappend(pool, s, " + ", 0);
1236       s2 = solver_select2str(pool, how & SOLVER_SELECTMASK, selection->elements[i + 1]);
1237       s = pool_tmpappend(pool, s, s2, 0);
1238       pool_freetmpspace(pool, s2);
1239       how &= flagmask & SOLVER_SETMASK;
1240       if (how)
1241         {
1242           int o = strlen(s);
1243           s = pool_tmpappend(pool, s, " ", 0);
1244           if (how & SOLVER_SETEV)
1245             s = pool_tmpappend(pool, s, ",setev", 0);
1246           if (how & SOLVER_SETEVR)
1247             s = pool_tmpappend(pool, s, ",setevr", 0);
1248           if (how & SOLVER_SETARCH)
1249             s = pool_tmpappend(pool, s, ",setarch", 0);
1250           if (how & SOLVER_SETVENDOR)
1251             s = pool_tmpappend(pool, s, ",setvendor", 0);
1252           if (how & SOLVER_SETREPO)
1253             s = pool_tmpappend(pool, s, ",setrepo", 0);
1254           if (how & SOLVER_NOAUTOSET)
1255             s = pool_tmpappend(pool, s, ",noautoset", 0);
1256           if (s[o + 1] != ',')
1257             s = pool_tmpappend(pool, s, ",?", 0);
1258           s[o + 1] = '[';
1259           s = pool_tmpappend(pool, s, "]", 0);
1260         }
1261     }
1262   return s;
1263 }
1264