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