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