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