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