Imported Upstream version 0.6.23
[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) | SOLVER_SETREPO;
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 inline const char *
339 skipkind(const char *n)
340 {
341   const char *s;
342   for (s = n; *s >= 'a' && *s <= 'z'; s++)
343     ;
344   if (*s == ':' && s != n)
345      return s + 1;
346   return n;
347 }
348
349 static inline void
350 queue_pushunique2(Queue *q, Id id1, Id id2)
351 {
352   int i;
353   for (i = 0; i < q->count; i += 2)
354     if (q->elements[i] == id1 && q->elements[i + 1] == id2)
355       return;
356   queue_push2(q, id1, id2);
357 }
358
359 static int
360 selection_depglob_id(Pool *pool, Queue *selection, Id id, int flags)
361 {
362   Id p, pp;
363   int match = 0;
364
365   FOR_PROVIDES(p, pp, id)
366     {
367       Solvable *s = pool->solvables + p;
368       if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
369         continue;
370       match = 1;
371       if (s->name == id && (flags & SELECTION_NAME) != 0)
372         {
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   if ((flags & (SELECTION_SOURCE_ONLY | SELECTION_WITH_SOURCE)) != 0 && (flags & SELECTION_NAME) != 0)
382     {
383       /* src rpms don't have provides, so we must check every solvable */
384       FOR_POOL_SOLVABLES(p)     /* slow path */
385         {
386           Solvable *s = pool->solvables + p;
387           if (s->name == id && (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC))
388             {
389               if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
390                 continue;       /* just in case... src rpms can't be installed */
391               if (pool_disabled_solvable(pool, s))
392                 continue;
393               if ((flags & SELECTION_SOURCE_ONLY) != 0)
394                 id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
395               queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
396               if ((flags & SELECTION_WITH_SOURCE) != 0)
397                 selection_addsrc(pool, selection, flags);
398               return SELECTION_NAME;
399             }
400         }
401     }
402   if (match && (flags & SELECTION_PROVIDES) != 0)
403     {
404       queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
405       return SELECTION_PROVIDES;
406     }
407   return 0;
408 }
409
410 static int
411 selection_depglob(Pool *pool, Queue *selection, const char *name, int flags)
412 {
413   Id id, p, pp;
414   int match = 0;
415   int doglob = 0;
416   int nocase = 0;
417   int globflags = 0;
418
419   if ((flags & SELECTION_SOURCE_ONLY) != 0)
420     {
421       flags &= ~SELECTION_PROVIDES;     /* sources don't provide anything */
422       flags &= ~SELECTION_WITH_SOURCE;
423     }
424
425   if (!(flags & (SELECTION_NAME|SELECTION_PROVIDES)))
426     return 0;
427
428   if ((flags & SELECTION_INSTALLED_ONLY) != 0 && !pool->installed)
429     return 0;
430
431   nocase = flags & SELECTION_NOCASE;
432   if (!nocase && !(flags & SELECTION_SKIP_KIND))
433     {
434       id = pool_str2id(pool, name, 0);
435       if (id)
436         {
437           /* the id is know, do the fast id matching using the whatprovides lookup */
438           int ret = selection_depglob_id(pool, selection, id, flags);
439           if (ret)
440             return ret;
441         }
442     }
443
444   if ((flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0)
445     doglob = 1;
446
447   if (!nocase && !(flags & SELECTION_SKIP_KIND) && !doglob)
448     return 0;   /* all done above in depglob_id */
449
450   if (doglob && nocase)
451     globflags = FNM_CASEFOLD;
452
453   if ((flags & SELECTION_NAME) != 0)
454     {
455       /* looks like a name glob. hard work. */
456       FOR_POOL_SOLVABLES(p)
457         {
458           Solvable *s = pool->solvables + p;
459           const char *n;
460           if (s->repo != pool->installed && !pool_installable(pool, s))
461             {
462               if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
463                 continue;
464               if (pool_disabled_solvable(pool, s))
465                 continue;
466             }
467           if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
468             continue;
469           id = s->name;
470           n = pool_id2str(pool, id);
471           if (flags & SELECTION_SKIP_KIND)
472             n = skipkind(n);
473           if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
474             {
475               if ((flags & SELECTION_SOURCE_ONLY) != 0)
476                 id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
477               queue_pushunique2(selection, SOLVER_SOLVABLE_NAME, id);
478               match = 1;
479             }
480         }
481       if (match)
482         {
483           if ((flags & SELECTION_WITH_SOURCE) != 0)
484             selection_addsrc(pool, selection, flags);
485           return SELECTION_NAME;
486         }
487     }
488
489   if ((flags & SELECTION_PROVIDES))
490     {
491       /* looks like a dep glob. really hard work. */
492       for (id = 1; id < pool->ss.nstrings; id++)
493         {
494           const char *n;
495           if (!pool->whatprovides[id] || pool->whatprovides[id] == 1)
496             continue;
497           n = pool_id2str(pool, id);
498           if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
499             {
500               if ((flags & SELECTION_INSTALLED_ONLY) != 0)
501                 {
502                   FOR_PROVIDES(p, pp, id)
503                     if (pool->solvables[p].repo == pool->installed)
504                       break;
505                   if (!p)
506                     continue;
507                 }
508               queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
509               match = 1;
510             }
511         }
512       if (match)
513         return SELECTION_PROVIDES;
514     }
515   return 0;
516 }
517
518 static int
519 selection_depglob_arch(Pool *pool, Queue *selection, const char *name, int flags)
520 {
521   int ret;
522   const char *r;
523   Id archid;
524
525   if ((ret = selection_depglob(pool, selection, name, flags)) != 0)
526     return ret;
527   if (!(flags & SELECTION_DOTARCH))
528     return 0;
529   /* check if there is an .arch suffix */
530   if ((r = strrchr(name, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
531     {
532       char *rname = solv_strdup(name);
533       rname[r - name] = 0;
534       if (archid == ARCH_SRC || archid == ARCH_NOSRC)
535         flags |= SELECTION_SOURCE_ONLY;
536       if ((ret = selection_depglob(pool, selection, rname, flags)) != 0)
537         {
538           selection_filter_rel(pool, selection, REL_ARCH, archid);
539           solv_free(rname);
540           return ret | SELECTION_DOTARCH;
541         }
542       solv_free(rname);
543     }
544   return 0;
545 }
546
547 static int
548 selection_filelist(Pool *pool, Queue *selection, const char *name, int flags)
549 {
550   Dataiterator di;
551   Queue q;
552   int type;
553
554   /* all files in the file list start with a '/' */
555   if (*name != '/')
556     {
557       if (!(flags & SELECTION_GLOB))
558         return 0;
559       if (*name != '*' && *name != '[' && *name != '?')
560         return 0;
561     }
562   type = !(flags & SELECTION_GLOB) || strpbrk(name, "[*?") == 0 ? SEARCH_STRING : SEARCH_GLOB;
563   if ((flags & SELECTION_NOCASE) != 0)
564     type |= SEARCH_NOCASE;
565   queue_init(&q);
566   dataiterator_init(&di, pool, flags & SELECTION_INSTALLED_ONLY ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES|SEARCH_COMPLETE_FILELIST);
567   while (dataiterator_step(&di))
568     {
569       Solvable *s = pool->solvables + di.solvid;
570       if (!s->repo)
571         continue;
572       if (s->repo != pool->installed && !pool_installable(pool, s))
573         {
574           if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
575             continue;
576           if (pool_disabled_solvable(pool, s))
577             continue;
578         }
579       if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
580         continue;
581       queue_push(&q, di.solvid);
582       dataiterator_skip_solvable(&di);
583     }
584   dataiterator_free(&di);
585   if (!q.count)
586     return 0;
587   if (q.count > 1)
588     queue_push2(selection, SOLVER_SOLVABLE_ONE_OF, pool_queuetowhatprovides(pool, &q));
589   else
590     queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, q.elements[0]);
591   queue_free(&q);
592   return SELECTION_FILELIST;
593 }
594
595 static char *
596 splitrel(char *rname, char *r, int *rflagsp)
597 {
598   int nend = r - rname;
599   int rflags = 0;
600   if (nend && *r == '=' && r[-1] == '!')
601     {
602       nend--;
603       r++;
604       rflags = REL_LT|REL_GT;
605     }
606   for (; *r; r++)
607     {
608       if (*r == '<')
609         rflags |= REL_LT;
610       else if (*r == '=')
611         rflags |= REL_EQ;
612       else if (*r == '>')
613         rflags |= REL_GT;
614       else
615         break;
616     }
617   while (*r && (*r == ' ' || *r == '\t'))
618     r++;
619   while (nend && (rname[nend - 1] == ' ' || rname[nend - 1] == '\t'))
620     nend--;
621   if (!*rname || !*r)
622     return 0;
623   *rflagsp = rflags;
624   rname[nend] = 0;
625   return r;
626 }
627
628 static int
629 selection_rel(Pool *pool, Queue *selection, const char *name, int flags)
630 {
631   int ret, rflags = 0;
632   char *r, *rname;
633
634   /* relation case, support:
635    * depglob rel
636    * depglob.arch rel
637    */
638   rname = solv_strdup(name);
639   if ((r = strpbrk(rname, "<=>")) != 0)
640     {
641       if ((r = splitrel(rname, r, &rflags)) == 0)
642         {
643           solv_free(rname);
644           return 0;
645         }
646     }
647   if ((ret = selection_depglob_arch(pool, selection, rname, flags)) != 0)
648     {
649       if (rflags)
650         selection_filter_rel(pool, selection, rflags, pool_str2id(pool, r, 1));
651       solv_free(rname);
652       return ret | SELECTION_REL;
653     }
654   solv_free(rname);
655   return 0;
656 }
657
658 #if defined(MULTI_SEMANTICS)
659 # define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE)
660 #elif defined(DEBIAN)
661 # define EVRCMP_DEPCMP EVRCMP_COMPARE
662 #else
663 # define EVRCMP_DEPCMP EVRCMP_MATCH_RELEASE
664 #endif
665
666 /* magic epoch promotion code, works only for SELECTION_NAME selections */
667 static void
668 selection_filter_evr(Pool *pool, Queue *selection, char *evr)
669 {
670   int i, j;
671   Queue q;
672   Id qbuf[10];
673
674   queue_init(&q);
675   queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
676   for (i = j = 0; i < selection->count; i += 2)
677     {
678       Id select = selection->elements[i] & SOLVER_SELECTMASK;
679       Id id = selection->elements[i + 1];
680       Id p, pp;
681       const char *lastepoch = 0;
682       int lastepochlen = 0;
683
684       queue_empty(&q);
685       FOR_JOB_SELECT(p, pp, select, id)
686         {
687           Solvable *s = pool->solvables + p;
688           const char *sevr = pool_id2str(pool, s->evr);
689           const char *sp;
690           for (sp = sevr; *sp >= '0' && *sp <= '9'; sp++)
691             ;
692           if (*sp != ':')
693             sp = sevr;
694           /* compare vr part */
695           if (strcmp(evr, sp != sevr ? sp + 1 : sevr) != 0)
696             {
697               int r = pool_evrcmp_str(pool, sp != sevr ? sp + 1 : sevr, evr, EVRCMP_DEPCMP);
698               if (r == -1 || r == 1)
699                 continue;       /* solvable does not match vr */
700             }
701           queue_push(&q, p);
702           if (sp > sevr)
703             {
704               while (sevr < sp && *sevr == '0') /* normalize epoch */
705                 sevr++;
706             }
707           if (!lastepoch)
708             {
709               lastepoch = sevr;
710               lastepochlen = sp - sevr;
711             }
712           else if (lastepochlen != sp - sevr || strncmp(lastepoch, sevr, lastepochlen) != 0)
713             lastepochlen = -1;  /* multiple different epochs */
714         }
715       if (!lastepoch || lastepochlen == 0)
716         id = pool_str2id(pool, evr, 1);         /* no match at all or zero epoch */
717       else if (lastepochlen >= 0)
718         {
719           /* found exactly one epoch, simply prepend */
720           char *evrx = solv_malloc(strlen(evr) + lastepochlen + 2);
721           strncpy(evrx, lastepoch, lastepochlen + 1);
722           strcpy(evrx + lastepochlen + 1, evr);
723           id = pool_str2id(pool, evrx, 1);
724           solv_free(evrx);
725         }
726       else
727         {
728           /* multiple epochs in multiple solvables, convert to list of solvables */
729           selection->elements[j] = (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF;
730           selection->elements[j + 1] = pool_queuetowhatprovides(pool, &q);
731           j += 2;
732           continue;
733         }
734       queue_empty(&q);
735       queue_push2(&q, selection->elements[i], selection->elements[i + 1]);
736       selection_filter_rel(pool, &q, REL_EQ, id);
737       if (!q.count)
738         continue;               /* oops, no match */
739       selection->elements[j] = q.elements[0];
740       selection->elements[j + 1] = q.elements[1];
741       j += 2;
742     }
743   queue_truncate(selection, j);
744   queue_free(&q);
745 }
746
747 /* match the "canonical" name of the package */
748 static int
749 selection_canon(Pool *pool, Queue *selection, const char *name, int flags)
750 {
751   char *rname, *r, *r2;
752   Id archid = 0;
753   int ret;
754
755   /*
756    * nameglob-version
757    * nameglob-version.arch
758    * nameglob-version-release
759    * nameglob-version-release.arch
760    */
761   flags |= SELECTION_NAME;
762   flags &= ~SELECTION_PROVIDES;
763
764   if (pool->disttype == DISTTYPE_DEB)
765     {
766       if ((r = strchr(name, '_')) == 0)
767         return 0;
768       rname = solv_strdup(name);        /* so we can modify it */
769       r = rname + (r - name);
770       *r++ = 0;
771       if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
772         {
773           solv_free(rname);
774           return 0;
775         }
776       /* is there a vaild arch? */
777       if ((r2 = strrchr(r, '_')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
778         {
779           *r2 = 0;      /* split off */
780           selection_filter_rel(pool, selection, REL_ARCH, archid);
781         }
782       selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1));
783       solv_free(rname);
784       return ret | SELECTION_CANON;
785     }
786
787   if (pool->disttype == DISTTYPE_HAIKU)
788     {
789       if ((r = strchr(name, '-')) == 0)
790         return 0;
791       rname = solv_strdup(name);        /* so we can modify it */
792       r = rname + (r - name);
793       *r++ = 0;
794       if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
795         {
796           solv_free(rname);
797           return 0;
798         }
799       /* is there a vaild arch? */
800       if ((r2 = strrchr(r, '-')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
801         {
802           *r2 = 0;      /* split off */
803           selection_filter_rel(pool, selection, REL_ARCH, archid);
804         }
805       selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1));
806       solv_free(rname);
807       return ret | SELECTION_CANON;
808     }
809
810   if ((r = strrchr(name, '-')) == 0)
811     return 0;
812   rname = solv_strdup(name);    /* so we can modify it */
813   r = rname + (r - name);
814   *r = 0;
815
816   /* split off potential arch part from version */
817   if ((r2 = strrchr(r + 1, '.')) != 0 && r2[1] && (archid = str2archid(pool, r2 + 1)) != 0)
818     *r2 = 0;    /* found valid arch, split it off */
819   if (archid == ARCH_SRC || archid == ARCH_NOSRC)
820     flags |= SELECTION_SOURCE_ONLY;
821
822   /* try with just the version */
823   if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
824     {
825       /* no luck, try with version-release */
826       if ((r2 = strrchr(rname, '-')) == 0)
827         {
828           solv_free(rname);
829           return 0;
830         }
831       *r = '-';
832       *r2 = 0;
833       r = r2;
834       if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
835         {
836           solv_free(rname);
837           return 0;
838         }
839     }
840   if (archid)
841     selection_filter_rel(pool, selection, REL_ARCH, archid);
842   selection_filter_evr(pool, selection, r + 1); /* magic epoch promotion */
843   solv_free(rname);
844   return ret | SELECTION_CANON;
845 }
846
847 int
848 selection_make(Pool *pool, Queue *selection, const char *name, int flags)
849 {
850   int ret = 0;
851
852   queue_empty(selection);
853   if ((flags & SELECTION_FILELIST) != 0)
854     ret = selection_filelist(pool, selection, name, flags);
855   if (!ret && (flags & SELECTION_REL) != 0 && strpbrk(name, "<=>") != 0)
856     ret = selection_rel(pool, selection, name, flags);
857   if (!ret)
858     ret = selection_depglob_arch(pool, selection, name, flags);
859   if (!ret && (flags & SELECTION_CANON) != 0)
860     ret = selection_canon(pool, selection, name, flags);
861   if (selection->count && (flags & SELECTION_INSTALLED_ONLY) != 0)
862     selection_filter_installed(pool, selection);
863   if (ret && !selection->count)
864     ret = 0;    /* no match -> always return zero */
865   if (ret && (flags & SELECTION_FLAT) != 0)
866     selection_flatten(pool, selection);
867   return ret;
868 }
869
870 static inline int
871 matchdep_str(const char *pattern, const char *string, int flags)
872 {
873   if (flags & SELECTION_GLOB)
874     {
875       int globflags = (flags & SELECTION_NOCASE) != 0 ? FNM_CASEFOLD : 0;
876       return fnmatch(pattern, string, globflags) == 0 ? 1 : 0;
877     }
878   if (flags & SELECTION_NOCASE)
879     return strcasecmp(pattern, string) == 0 ? 1 : 0;
880   return strcmp(pattern, string) == 0 ? 1 : 0;
881 }
882
883 static int
884 matchdep(Pool *pool, Id id, char *rname, int rflags, char *revr, int flags)
885 {
886   if (ISRELDEP(id))
887     {
888       Reldep *rd = GETRELDEP(pool, id);
889       if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_WITH || rd->flags == REL_COND)
890         {
891           if (matchdep(pool, rd->name, rname, rflags, revr, flags))
892             return 1;
893           if (rd->flags == REL_COND && ISRELDEP(rd->evr))
894             {
895               rd = GETRELDEP(pool, rd->evr);
896               if (rd->flags != REL_ELSE)
897                 return 0;
898             }
899           if (rd->flags != REL_COND && matchdep(pool, rd->evr, rname, rflags, revr, flags))
900             return 1;
901           return 0;
902         }
903       if (rd->flags == REL_ARCH)
904         return matchdep(pool, rd->name, rname, rflags, revr, flags);
905       if (!matchdep(pool, rd->name, rname, rflags, revr, flags))
906         return 0;
907       if (rflags)
908         {
909           /* XXX: need pool_match_flags_evr here */
910           if (!pool_match_dep(pool, pool_rel2id(pool, rd->name, pool_str2id(pool, revr, 1), rflags, 1), id))
911             return 0;
912         }
913       return 1;
914     }
915   return matchdep_str(rname, pool_id2str(pool, id), flags);
916 }
917
918 /*
919  *  select against the dependencies in keyname
920  *  like SELECTION_REL and SELECTION_PROVIDES, but with the
921  *  deps in keyname instead of provides.
922  */
923 int
924 selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int flags, int keyname, int marker)
925 {
926   char *rname, *r = 0;
927   int rflags = 0;
928   Id p;
929   Queue q;
930
931   queue_empty(selection);
932   rname = solv_strdup(name);
933   if (!(flags & SELECTION_MATCH_DEPSTR))
934     {
935       if ((r = strpbrk(rname, "<=>")) != 0)
936         {
937           if ((r = splitrel(rname, r, &rflags)) == 0)
938             {
939               solv_free(rname);
940               return 0;
941             }
942         }
943     }
944   if ((flags & SELECTION_GLOB) != 0 && !strpbrk(rname, "[*?") != 0)
945     flags &= ~SELECTION_GLOB;
946
947   queue_init(&q);
948   FOR_POOL_SOLVABLES(p)
949     {
950       Solvable *s =  pool->solvables + p;
951       int i;
952
953       if (s->repo != pool->installed && !pool_installable(pool, s))
954         {
955           if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
956             continue;
957           if (pool_disabled_solvable(pool, s))
958             continue;
959         }
960       if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
961         continue;
962       if ((s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) && !(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
963         continue;
964       queue_empty(&q);
965       repo_lookup_deparray(s->repo, p, keyname, &q, marker);
966       for (i = 0; i < q.count; i++)
967         {
968           Id id = q.elements[i];
969           if ((flags & SELECTION_MATCH_DEPSTR) != 0)
970             {
971               if (matchdep_str(rname, pool_dep2str(pool, id), flags))
972                 break;
973               continue;
974             }
975           if (matchdep(pool, id, rname, rflags, r, flags))
976             break;
977         }
978       if (i < q.count)
979         queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, p);
980     }
981   queue_free(&q);
982   solv_free(rname);
983   if (!selection->count)
984     return 0;
985   if ((flags & SELECTION_FLAT) != 0)
986     selection_flatten(pool, selection);
987   return SELECTION_PROVIDES;
988 }
989
990 int
991 selection_make_matchdepid(Pool *pool, Queue *selection, Id dep, int flags, int keyname, int marker)
992 {
993   Id p;
994   Queue q;
995
996   queue_empty(selection);
997   if (!dep)
998     return 0;
999   queue_init(&q);
1000   FOR_POOL_SOLVABLES(p)
1001     {
1002       Solvable *s =  pool->solvables + p;
1003       int i;
1004
1005       if (s->repo != pool->installed && !pool_installable(pool, s))
1006         {
1007           if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
1008             continue;
1009           if (pool_disabled_solvable(pool, s))
1010             continue;
1011         }
1012       if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
1013         continue;
1014       if ((s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) && !(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
1015         continue;
1016       queue_empty(&q);
1017       repo_lookup_deparray(s->repo, p, keyname, &q, marker);
1018       for (i = 0; i < q.count; i++)
1019         {
1020           if ((flags & SELECTION_MATCH_DEPSTR) != 0)    /* mis-use */
1021             {
1022               if (q.elements[i] == dep)
1023                 break;
1024               continue;
1025             }
1026           if (pool_match_dep(pool, q.elements[i], dep))
1027             break;
1028         }
1029       if (i < q.count)
1030         queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, p);
1031     }
1032   queue_free(&q);
1033   if (!selection->count)
1034     return 0;
1035   if ((flags & SELECTION_FLAT) != 0)
1036     selection_flatten(pool, selection);
1037   return SELECTION_PROVIDES;
1038 }
1039
1040 static inline int
1041 pool_is_kind(Pool *pool, Id name, Id kind)
1042 {
1043   const char *n;
1044   if (!kind)
1045     return 1;
1046   n = pool_id2str(pool, name);
1047   if (kind != 1)
1048     {
1049       const char *kn = pool_id2str(pool, kind);
1050       int knl = strlen(kn);
1051       return !strncmp(n, kn, knl) && n[knl] == ':' ? 1 : 0;
1052     }
1053   else
1054     {
1055       if (*n == ':')
1056         return 1;
1057       while(*n >= 'a' && *n <= 'z')
1058         n++;
1059       return *n == ':' ? 0 : 1;
1060     }
1061 }
1062
1063 void
1064 selection_filter(Pool *pool, Queue *sel1, Queue *sel2)
1065 {
1066   int i, j, miss;
1067   Id p, pp, q1filled = 0;
1068   Queue q1;
1069   Map m2;
1070   Id setflags = 0;
1071
1072   if (!sel1->count || !sel2->count)
1073     {
1074       queue_empty(sel1);
1075       return;
1076     }
1077   if (sel1->count == 2 && (sel1->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
1078     {
1079       /* XXX: not 100% correct, but very useful */
1080       p = sel1->elements[0] & ~(SOLVER_SELECTMASK | SOLVER_SETMASK);    /* job & jobflags */
1081       queue_free(sel1);
1082       queue_init_clone(sel1, sel2);
1083       for (i = 0; i < sel1->count; i += 2)
1084         sel1->elements[i] = (sel1->elements[i] & (SOLVER_SELECTMASK | SOLVER_SETMASK)) | p ;
1085       return;
1086     }
1087   queue_init(&q1);
1088   map_init(&m2, pool->nsolvables);
1089   for (i = 0; i < sel2->count; i += 2)
1090     {
1091       Id select = sel2->elements[i] & SOLVER_SELECTMASK;
1092       if (select == SOLVER_SOLVABLE_ALL)
1093         {
1094           queue_free(&q1);
1095           map_free(&m2);
1096           return;
1097         }
1098       if (select == SOLVER_SOLVABLE_REPO)
1099         {
1100           Solvable *s;
1101           Repo *repo = pool_id2repo(pool, sel2->elements[i + 1]);
1102           if (repo)
1103             FOR_REPO_SOLVABLES(repo, p, s)
1104               map_set(&m2, p);
1105         }
1106       else
1107         {
1108           if ((select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES) && ISRELDEP(sel2->elements[i + 1]))
1109             {
1110               Reldep *rd = GETRELDEP(pool, sel2->elements[i + 1]);
1111               if (rd->flags == REL_ARCH && rd->name == 0)
1112                 {
1113                   /* special arch filter */
1114                   if (!q1filled++)
1115                     selection_solvables(pool, sel1, &q1);
1116                   for (j = 0; j < q1.count; j++)
1117                     {
1118                       Id p = q1.elements[j];
1119                       Solvable *s = pool->solvables + p;
1120                       if (s->arch == rd->evr || (rd->evr == ARCH_SRC && s->arch == ARCH_NOSRC))
1121                         map_set(&m2, p);
1122                     }
1123                   continue;
1124                 }
1125               else if (rd->flags == REL_KIND && rd->name == 0)
1126                 {
1127                   /* special kind filter */
1128                   if (!q1filled++)
1129                     selection_solvables(pool, sel1, &q1);
1130                   for (j = 0; j < q1.count; j++)
1131                     {
1132                       Id p = q1.elements[j];
1133                       Solvable *s = pool->solvables + p;
1134                       if (pool_is_kind(pool, s->name, rd->evr))
1135                         map_set(&m2, p);
1136                     }
1137                   continue;
1138                 }
1139             }
1140           FOR_JOB_SELECT(p, pp, select, sel2->elements[i + 1])
1141             map_set(&m2, p);
1142         }
1143     }
1144   if (sel2->count == 2)         /* XXX: AND all setmasks instead? */
1145     setflags = sel2->elements[0] & SOLVER_SETMASK & ~SOLVER_NOAUTOSET;
1146   for (i = j = 0; i < sel1->count; i += 2)
1147     {
1148       Id select = sel1->elements[i] & SOLVER_SELECTMASK;
1149       queue_empty(&q1);
1150       miss = 0;
1151       if (select == SOLVER_SOLVABLE_ALL)
1152         {
1153           FOR_POOL_SOLVABLES(p)
1154             {
1155               if (map_tst(&m2, p))
1156                 queue_push(&q1, p);
1157               else
1158                 miss = 1;
1159             }
1160         }
1161       else if (select == SOLVER_SOLVABLE_REPO)
1162         {
1163           Solvable *s;
1164           Repo *repo = pool_id2repo(pool, sel1->elements[i + 1]);
1165           if (repo)
1166             FOR_REPO_SOLVABLES(repo, p, s)
1167               {
1168                 if (map_tst(&m2, p))
1169                   queue_push(&q1, p);
1170                 else
1171                   miss = 1;
1172               }
1173         }
1174       else
1175         {
1176           FOR_JOB_SELECT(p, pp, select, sel1->elements[i + 1])
1177             {
1178               if (map_tst(&m2, p))
1179                 queue_pushunique(&q1, p);
1180               else
1181                 miss = 1;
1182             }
1183         }
1184       if (!q1.count)
1185         continue;
1186       if (!miss)
1187         {
1188           sel1->elements[j] = sel1->elements[i] | setflags;
1189           sel1->elements[j + 1] = sel1->elements[i + 1];
1190         }
1191       else if (q1.count > 1)
1192         {
1193           sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF | setflags;
1194           sel1->elements[j + 1] = pool_queuetowhatprovides(pool, &q1);
1195         }
1196       else
1197         {
1198           sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE | SOLVER_NOAUTOSET | setflags;
1199           sel1->elements[j + 1] = q1.elements[0];
1200         }
1201       j += 2;
1202     }
1203   queue_truncate(sel1, j);
1204   queue_free(&q1);
1205   map_free(&m2);
1206 }
1207
1208 void
1209 selection_add(Pool *pool, Queue *sel1, Queue *sel2)
1210 {
1211   int i;
1212   for (i = 0; i < sel2->count; i++)
1213     queue_push(sel1, sel2->elements[i]);
1214 }
1215
1216 const char *
1217 pool_selection2str(Pool *pool, Queue *selection, Id flagmask)
1218 {
1219   char *s;
1220   const char *s2;
1221   int i;
1222   s = pool_tmpjoin(pool, 0, 0, 0);
1223   for (i = 0; i < selection->count; i += 2)
1224     {
1225       Id how = selection->elements[i];
1226       if (*s)
1227         s = pool_tmpappend(pool, s, " + ", 0);
1228       s2 = solver_select2str(pool, how & SOLVER_SELECTMASK, selection->elements[i + 1]);
1229       s = pool_tmpappend(pool, s, s2, 0);
1230       pool_freetmpspace(pool, s2);
1231       how &= flagmask & SOLVER_SETMASK;
1232       if (how)
1233         {
1234           int o = strlen(s);
1235           s = pool_tmpappend(pool, s, " ", 0);
1236           if (how & SOLVER_SETEV)
1237             s = pool_tmpappend(pool, s, ",setev", 0);
1238           if (how & SOLVER_SETEVR)
1239             s = pool_tmpappend(pool, s, ",setevr", 0);
1240           if (how & SOLVER_SETARCH)
1241             s = pool_tmpappend(pool, s, ",setarch", 0);
1242           if (how & SOLVER_SETVENDOR)
1243             s = pool_tmpappend(pool, s, ",setvendor", 0);
1244           if (how & SOLVER_SETREPO)
1245             s = pool_tmpappend(pool, s, ",setrepo", 0);
1246           if (how & SOLVER_NOAUTOSET)
1247             s = pool_tmpappend(pool, s, ",noautoset", 0);
1248           if (s[o + 1] != ',')
1249             s = pool_tmpappend(pool, s, ",?", 0);
1250           s[o + 1] = '[';
1251           s = pool_tmpappend(pool, s, "]", 0);
1252         }
1253     }
1254   return s;
1255 }
1256