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