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