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