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