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 */ 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_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 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 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 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 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 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 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 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 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 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