support haiku package naming in selection_canon
[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 */
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             selection->elements[i] |= strchr(pool_id2str(pool, relevr), '-') != 0 ? SOLVER_SETEVR : SOLVER_SETEV;
221         }
222     }
223   selection_prune(pool, selection);
224 }
225
226 static void
227 selection_addsrc(Pool *pool, Queue *selection, int flags)
228 {
229   Queue q;
230   Id p, name;
231   int i, havesrc;
232
233   if ((flags & SELECTION_INSTALLED_ONLY) != 0)
234     return;     /* sources can't be installed */
235   queue_init(&q);
236   for (i = 0; i < selection->count; i += 2)
237     {
238       if (selection->elements[i] != SOLVER_SOLVABLE_NAME)
239         continue;
240       name = selection->elements[i + 1];
241       havesrc = 0;
242       queue_empty(&q);
243       FOR_POOL_SOLVABLES(p)
244         {
245           Solvable *s = pool->solvables + p;
246           if (s->name != name)
247             continue;
248           if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
249             {
250               if (pool_disabled_solvable(pool, s))
251                 continue;
252               havesrc = 1;
253             }
254           else if (s->repo != pool->installed && !pool_installable(pool, s))
255             continue;
256           queue_push(&q, p);
257         }
258       if (!havesrc || !q.count)
259         continue;
260       if (q.count == 1)
261         {
262           selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
263           selection->elements[i + 1] = q.elements[0];
264         }
265       else
266         {
267           selection->elements[i] = SOLVER_SOLVABLE_ONE_OF;
268           selection->elements[i + 1] = pool_queuetowhatprovides(pool, &q);
269         }
270     }
271   queue_free(&q);
272 }
273
274 static int
275 selection_depglob(Pool *pool, Queue *selection, const char *name, int flags)
276 {
277   Id id, p, pp;
278   int i, match = 0;
279   int doglob = 0;
280   int globflags = 0;
281
282   if ((flags & SELECTION_SOURCE_ONLY) != 0)
283     {
284       flags &= ~SELECTION_PROVIDES;     /* sources don't provide anything */
285       flags &= ~SELECTION_WITH_SOURCE;
286     }
287
288   if (!(flags & (SELECTION_NAME|SELECTION_PROVIDES)))
289     return 0;
290
291   if ((flags & SELECTION_INSTALLED_ONLY) != 0 && !pool->installed)
292     return 0;
293
294   if (!(flags & SELECTION_NOCASE))
295     {
296       id = pool_str2id(pool, name, 0);
297       if (id)
298         {
299           if ((flags & (SELECTION_SOURCE_ONLY | SELECTION_WITH_SOURCE)) != 0 && (flags & SELECTION_NAME) != 0)
300             {
301               /* src rpms don't have provides, so we must check every solvable */
302               FOR_PROVIDES(p, pp, id)   /* try fast path first */
303                 {
304                   Solvable *s = pool->solvables + p;
305                   if (s->name == id)
306                     {
307                       if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
308                         continue;
309                       if ((flags & SELECTION_SOURCE_ONLY) != 0)
310                         id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
311                       queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
312                       if ((flags & SELECTION_WITH_SOURCE) != 0)
313                         selection_addsrc(pool, selection, flags);
314                       return SELECTION_NAME;
315                     }
316                 }
317               FOR_POOL_SOLVABLES(p)     /* slow path */
318                 {
319                   Solvable *s = pool->solvables + p;
320                   if (s->name == id && (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC))
321                     {
322                       if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
323                         continue;       /* just in case... src rpms can't be installed */
324                       if (pool_disabled_solvable(pool, s))
325                         continue;
326                       if ((flags & SELECTION_SOURCE_ONLY) != 0)
327                         id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
328                       queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
329                       if ((flags & SELECTION_WITH_SOURCE) != 0)
330                         selection_addsrc(pool, selection, flags);
331                       return SELECTION_NAME;
332                     }
333                 }
334             }
335           FOR_PROVIDES(p, pp, id)
336             {
337               Solvable *s = pool->solvables + p;
338               if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
339                 continue;
340               match = 1;
341               if (s->name == id && (flags & SELECTION_NAME) != 0)
342                 {
343                   if ((flags & SELECTION_SOURCE_ONLY) != 0)
344                     id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
345                   queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
346                   if ((flags & SELECTION_WITH_SOURCE) != 0)
347                     selection_addsrc(pool, selection, flags);
348                   return SELECTION_NAME;
349                 }
350             }
351           if (match && (flags & SELECTION_PROVIDES) != 0)
352             {
353               queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
354               return SELECTION_PROVIDES;
355             }
356         }
357     }
358
359   if ((flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0)
360     doglob = 1;
361
362   if (!doglob && !(flags & SELECTION_NOCASE))
363     return 0;
364
365   if (doglob && (flags & SELECTION_NOCASE) != 0)
366     globflags = FNM_CASEFOLD;
367
368 #if 0   /* doesn't work with selection_filter_rel yet */
369   if (doglob && !strcmp(name, "*") && (flags & SELECTION_FLAT) != 0)
370     {
371       /* can't do this for SELECTION_PROVIDES, as src rpms don't provide anything */
372       if ((flags & SELECTION_NAME) != 0)
373         {
374           queue_push2(selection, SOLVER_SOLVABLE_ALL, 0);
375           return SELECTION_NAME;
376         }
377     }
378 #endif
379
380   if ((flags & SELECTION_NAME) != 0)
381     {
382       /* looks like a name glob. hard work. */
383       FOR_POOL_SOLVABLES(p)
384         {
385           Solvable *s = pool->solvables + p;
386           if (s->repo != pool->installed && !pool_installable(pool, s))
387             {
388               if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
389                 continue;
390               if (pool_disabled_solvable(pool, s))
391                 continue;
392             }
393           if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
394             continue;
395           id = s->name;
396           if ((doglob ? fnmatch(name, pool_id2str(pool, id), globflags) : strcasecmp(name, pool_id2str(pool, id))) == 0)
397             {
398               if ((flags & SELECTION_SOURCE_ONLY) != 0)
399                 id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
400               /* queue_pushunique2 */
401               for (i = 0; i < selection->count; i += 2)
402                 if (selection->elements[i] == SOLVER_SOLVABLE_NAME && selection->elements[i + 1] == id)
403                   break;
404               if (i == selection->count)
405                 queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
406               match = 1;
407             }
408         }
409       if (match)
410         {
411           if ((flags & SELECTION_WITH_SOURCE) != 0)
412             selection_addsrc(pool, selection, flags);
413           return SELECTION_NAME;
414         }
415     }
416   if ((flags & SELECTION_PROVIDES))
417     {
418       /* looks like a dep glob. really hard work. */
419       for (id = 1; id < pool->ss.nstrings; id++)
420         {
421           if (!pool->whatprovides[id])
422             continue;
423           if ((doglob ? fnmatch(name, pool_id2str(pool, id), globflags) : strcasecmp(name, pool_id2str(pool, id))) == 0)
424             {
425               if ((flags & SELECTION_INSTALLED_ONLY) != 0)
426                 {
427                   FOR_PROVIDES(p, pp, id)
428                     if (pool->solvables[p].repo == pool->installed)
429                       break;
430                   if (!p)
431                     continue;
432                 }
433               queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
434               match = 1;
435             }
436         }
437       if (match)
438         return SELECTION_PROVIDES;
439     }
440   return 0;
441 }
442
443 static int
444 selection_depglob_arch(Pool *pool, Queue *selection, const char *name, int flags)
445 {
446   int ret;
447   const char *r;
448   Id archid;
449
450   if ((ret = selection_depglob(pool, selection, name, flags)) != 0)
451     return ret;
452   if (!(flags & SELECTION_DOTARCH))
453     return 0;
454   /* check if there is an .arch suffix */
455   if ((r = strrchr(name, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
456     {
457       char *rname = solv_strdup(name);
458       rname[r - name] = 0;
459       if (archid == ARCH_SRC || archid == ARCH_NOSRC)
460         flags |= SELECTION_SOURCE_ONLY;
461       if ((ret = selection_depglob(pool, selection, rname, flags)) != 0)
462         {
463           selection_filter_rel(pool, selection, REL_ARCH, archid);
464           solv_free(rname);
465           return ret | SELECTION_DOTARCH;
466         }
467       solv_free(rname);
468     }
469   return 0;
470 }
471
472 static int
473 selection_filelist(Pool *pool, Queue *selection, const char *name, int flags)
474 {
475   Dataiterator di;
476   Queue q;
477   int type;
478
479   type = !(flags & SELECTION_GLOB) || strpbrk(name, "[*?") == 0 ? SEARCH_STRING : SEARCH_GLOB;
480   if ((flags & SELECTION_NOCASE) != 0)
481     type |= SEARCH_NOCASE;
482   queue_init(&q);
483   dataiterator_init(&di, pool, flags & SELECTION_INSTALLED_ONLY ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES|SEARCH_COMPLETE_FILELIST);
484   while (dataiterator_step(&di))
485     {
486       Solvable *s = pool->solvables + di.solvid;
487       if (!s->repo)
488         continue;
489       if (s->repo != pool->installed && !pool_installable(pool, s))
490         {
491           if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
492             continue;
493           if (pool_disabled_solvable(pool, s))
494             continue;
495         }
496       if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
497         continue;
498       queue_push(&q, di.solvid);
499       dataiterator_skip_solvable(&di);
500     }
501   dataiterator_free(&di);
502   if (!q.count)
503     return 0;
504   if (q.count > 1) 
505     queue_push2(selection, SOLVER_SOLVABLE_ONE_OF, pool_queuetowhatprovides(pool, &q));
506   else
507     queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, q.elements[0]);
508   queue_free(&q);
509   return SELECTION_FILELIST;
510 }
511
512 static int
513 selection_rel(Pool *pool, Queue *selection, const char *name, int flags)
514 {
515   int ret, rflags = 0;
516   char *r, *rname;
517   
518   /* relation case, support:
519    * depglob rel
520    * depglob.arch rel
521    */
522   rname = solv_strdup(name);
523   if ((r = strpbrk(rname, "<=>")) != 0)
524     {
525       int nend = r - rname;
526       if (nend && *r == '=' && r[-1] == '!')
527         {
528           nend--;
529           r++;
530           rflags = REL_LT|REL_GT;
531         }
532       for (; *r; r++)
533         {
534           if (*r == '<')
535             rflags |= REL_LT;
536           else if (*r == '=')
537             rflags |= REL_EQ;
538           else if (*r == '>')
539             rflags |= REL_GT;
540           else
541             break;
542         }
543       while (*r && *r == ' ' && *r == '\t')
544         r++;
545       while (nend && (rname[nend - 1] == ' ' || rname[nend -1 ] == '\t'))
546         nend--;
547       if (!*rname || !*r)
548         {
549           solv_free(rname);
550           return 0;
551         }
552       rname[nend] = 0;
553     }
554   if ((ret = selection_depglob_arch(pool, selection, rname, flags)) != 0)
555     {
556       if (rflags)
557         selection_filter_rel(pool, selection, rflags, pool_str2id(pool, r, 1));
558       solv_free(rname);
559       return ret | SELECTION_REL;
560     }
561   solv_free(rname);
562   return 0;
563 }
564
565 #if defined(MULTI_SEMANTICS)
566 # define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE)
567 #elif defined(DEBIAN)
568 # define EVRCMP_DEPCMP EVRCMP_COMPARE
569 #else
570 # define EVRCMP_DEPCMP EVRCMP_MATCH_RELEASE
571 #endif
572
573 /* magic epoch promotion code, works only for SELECTION_NAME selections */
574 static void
575 selection_filter_evr(Pool *pool, Queue *selection, char *evr)
576 {
577   int i, j;
578   Queue q;
579   Id qbuf[10];
580
581   queue_init(&q);
582   queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
583   for (i = j = 0; i < selection->count; i += 2)
584     {
585       Id select = selection->elements[i] & SOLVER_SELECTMASK;
586       Id id = selection->elements[i + 1];
587       Id p, pp;
588       const char *lastepoch = 0;
589       int lastepochlen = 0;
590
591       queue_empty(&q);
592       FOR_JOB_SELECT(p, pp, select, id)
593         {
594           Solvable *s = pool->solvables + p;
595           const char *sevr = pool_id2str(pool, s->evr);
596           const char *sp;
597           for (sp = sevr; *sp >= '0' && *sp <= '9'; sp++)
598             ;
599           if (*sp != ':')
600             sp = sevr;
601           /* compare vr part */
602           if (strcmp(evr, sp != sevr ? sp + 1 : sevr) != 0)
603             {
604               int r = pool_evrcmp_str(pool, sp != sevr ? sp + 1 : sevr, evr, EVRCMP_DEPCMP);
605               if (r == -1 || r == 1)
606                 continue;       /* solvable does not match vr */
607             }
608           queue_push(&q, p);
609           if (sp > sevr)
610             {
611               while (sevr < sp && *sevr == '0') /* normalize epoch */
612                 sevr++;
613             }
614           if (!lastepoch)
615             {
616               lastepoch = sevr;
617               lastepochlen = sp - sevr;
618             }
619           else if (lastepochlen != sp - sevr || strncmp(lastepoch, sevr, lastepochlen) != 0)
620             lastepochlen = -1;  /* multiple different epochs */
621         }
622       if (!lastepoch || lastepochlen == 0)
623         id = pool_str2id(pool, evr, 1);         /* no match at all or zero epoch */
624       else if (lastepochlen >= 0)
625         {
626           /* found exactly one epoch, simply prepend */
627           char *evrx = solv_malloc(strlen(evr) + lastepochlen + 2);
628           strncpy(evrx, lastepoch, lastepochlen + 1);
629           strcpy(evrx + lastepochlen + 1, evr);
630           id = pool_str2id(pool, evrx, 1);
631           solv_free(evrx);
632         }
633       else
634         {
635           /* multiple epochs in multiple solvables, convert to list of solvables */
636           selection->elements[j] = (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF;
637           selection->elements[j + 1] = pool_queuetowhatprovides(pool, &q);
638           j += 2;
639           continue;
640         }
641       queue_empty(&q);
642       queue_push2(&q, selection->elements[i], selection->elements[i + 1]);
643       selection_filter_rel(pool, &q, REL_EQ, id);
644       if (!q.count)
645         continue;               /* oops, no match */
646       selection->elements[j] = q.elements[0];
647       selection->elements[j + 1] = q.elements[1];
648       j += 2;
649     }
650   queue_truncate(selection, j);
651   queue_free(&q);
652 }
653
654 /* match the "canonical" name of the package */
655 static int
656 selection_canon(Pool *pool, Queue *selection, const char *name, int flags)
657 {
658   char *rname, *r, *r2;
659   Id archid = 0;
660   int ret;
661
662   /*
663    * nameglob-version
664    * nameglob-version.arch
665    * nameglob-version-release
666    * nameglob-version-release.arch
667    */
668   flags |= SELECTION_NAME;
669   flags &= ~SELECTION_PROVIDES;
670
671   if (pool->disttype == DISTTYPE_DEB)
672     {
673       if ((r = strchr(name, '_')) == 0)
674         return 0;
675       rname = solv_strdup(name);        /* so we can modify it */
676       r = rname + (r - name);
677       *r++ = 0;
678       if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
679         {
680           solv_free(rname);
681           return 0;
682         }
683       /* is there a vaild arch? */
684       if ((r2 = strchr(r, '_')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
685         {
686           *r2 = 0;      /* split off */
687           selection_filter_rel(pool, selection, REL_ARCH, archid);
688         }
689       selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1));
690       solv_free(rname);
691       return ret | SELECTION_CANON;
692     }
693
694   if (pool->disttype == DISTTYPE_HAIKU)
695     {
696       if ((r = strchr(name, '-')) == 0)
697         return 0;
698       rname = solv_strdup(name);        /* so we can modify it */
699       r = rname + (r - name);
700       *r++ = 0;
701       if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
702         {
703           solv_free(rname);
704           return 0;
705         }
706       /* is there a vaild arch? */
707       if ((r2 = strchr(r, '-')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
708         {
709           *r2 = 0;      /* split off */
710           selection_filter_rel(pool, selection, REL_ARCH, archid);
711         }
712       selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1));
713       solv_free(rname);
714       return ret | SELECTION_CANON;
715     }
716
717   if ((r = strrchr(name, '-')) == 0)
718     return 0;
719   rname = solv_strdup(name);    /* so we can modify it */
720   r = rname + (r - name);
721   *r = 0; 
722
723   /* split off potential arch part from version */
724   if ((r2 = strrchr(r + 1, '.')) != 0 && r2[1] && (archid = str2archid(pool, r2 + 1)) != 0)
725     *r2 = 0;    /* found valid arch, split it off */
726   if (archid == ARCH_SRC || archid == ARCH_NOSRC)
727     flags |= SELECTION_SOURCE_ONLY;
728
729   /* try with just the version */
730   if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
731     {
732       /* no luck, try with version-release */
733       if ((r2 = strrchr(rname, '-')) == 0)
734         {
735           solv_free(rname);
736           return 0;
737         }
738       *r = '-'; 
739       *r2 = 0; 
740       r = r2;
741       if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
742         {
743           solv_free(rname);
744           return 0;
745         }
746     }
747   if (archid)
748     selection_filter_rel(pool, selection, REL_ARCH, archid);
749   selection_filter_evr(pool, selection, r + 1); /* magic epoch promotion */
750   solv_free(rname);
751   return ret | SELECTION_CANON;
752 }
753
754 int
755 selection_make(Pool *pool, Queue *selection, const char *name, int flags)
756 {
757   int ret = 0;
758   const char *r;
759
760   queue_empty(selection);
761   if (*name == '/' && (flags & SELECTION_FILELIST))
762     ret = selection_filelist(pool, selection, name, flags);
763   if (!ret && (flags & SELECTION_REL) != 0 && (r = strpbrk(name, "<=>")) != 0)
764     ret = selection_rel(pool, selection, name, flags);
765   if (!ret)
766     ret = selection_depglob_arch(pool, selection, name, flags);
767   if (!ret && (flags & SELECTION_CANON) != 0)
768     ret = selection_canon(pool, selection, name, flags);
769   if (ret && !selection->count)
770     ret = 0;    /* no match -> always return zero */
771   if (ret && (flags & SELECTION_FLAT) != 0)
772     selection_flatten(pool, selection);
773   return ret;
774 }
775
776 void
777 selection_filter(Pool *pool, Queue *sel1, Queue *sel2)
778 {
779   int i, j, miss;
780   Id p, pp;
781   Queue q1;
782   Map m2;
783   Id setflags = 0;
784
785   if (!sel1->count || !sel2->count)
786     {
787       queue_empty(sel1);
788       return;
789     }
790   if (sel1->count == 2 && (sel1->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
791     {
792       /* XXX: not 100% correct, but very useful */
793       queue_free(sel1);
794       queue_init_clone(sel1, sel2);
795       return;
796     }
797   queue_init(&q1);
798   map_init(&m2, pool->nsolvables);
799   for (i = 0; i < sel2->count; i += 2)
800     {
801       Id select = sel2->elements[i] & SOLVER_SELECTMASK;
802       if (select == SOLVER_SOLVABLE_ALL)
803         return;
804       if (select == SOLVER_SOLVABLE_REPO)
805         {
806           Solvable *s;
807           Repo *repo = pool_id2repo(pool, sel2->elements[i + 1]);
808           if (repo)
809             FOR_REPO_SOLVABLES(repo, p, s)
810               map_set(&m2, p);
811         }
812       else
813         {
814           FOR_JOB_SELECT(p, pp, select, sel2->elements[i + 1])
815             map_set(&m2, p);
816         }
817     }
818   if (sel2->count == 2)         /* XXX: AND all setmasks instead? */
819     setflags = sel2->elements[0] & SOLVER_SETMASK & ~SOLVER_NOAUTOSET;
820   for (i = j = 0; i < sel1->count; i += 2)
821     {
822       Id select = sel1->elements[i] & SOLVER_SELECTMASK;
823       queue_empty(&q1);
824       miss = 0;
825       if (select == SOLVER_SOLVABLE_ALL)
826         {
827           FOR_POOL_SOLVABLES(p)
828             {
829               if (map_tst(&m2, p))
830                 queue_push(&q1, p);
831               else
832                 miss = 1;
833             }
834         }
835       else if (select == SOLVER_SOLVABLE_REPO)
836         {
837           Solvable *s;
838           Repo *repo = pool_id2repo(pool, sel1->elements[i + 1]);
839           if (repo)
840             FOR_REPO_SOLVABLES(repo, p, s)
841               {
842                 if (map_tst(&m2, p))
843                   queue_push(&q1, p);
844                 else
845                   miss = 1;
846               }
847         }
848       else
849         {
850           FOR_JOB_SELECT(p, pp, select, sel1->elements[i + 1])
851             {
852               if (map_tst(&m2, p))
853                 queue_pushunique(&q1, p);
854               else
855                 miss = 1;
856             }
857         }
858       if (!q1.count)
859         continue;
860       if (!miss)
861         {
862           sel1->elements[j] = sel1->elements[i] | setflags;
863           sel1->elements[j + 1] = sel1->elements[i + 1];
864         }
865       else if (q1.count > 1) 
866         {
867           sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF | setflags;
868           sel1->elements[j + 1] = pool_queuetowhatprovides(pool, &q1);
869         }
870       else
871         {
872           sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE | SOLVER_NOAUTOSET | setflags;
873           sel1->elements[j + 1] = q1.elements[0];
874         }
875       j += 2;
876     }
877   queue_truncate(sel1, j);
878 }
879
880 void
881 selection_add(Pool *pool, Queue *sel1, Queue *sel2)
882 {
883   int i;
884   for (i = 0; i < sel2->count; i++)
885     queue_push(sel1, sel2->elements[i]);
886 }
887