]> git.ipfire.org Git - thirdparty/libsolv.git/commitdiff
Move dependency matching from pool.c to pooldep.c
authorMichael Schroeder <mls@suse.de>
Tue, 29 Jul 2025 13:34:09 +0000 (15:34 +0200)
committerMichael Schroeder <mls@suse.de>
Tue, 29 Jul 2025 13:34:09 +0000 (15:34 +0200)
src/CMakeLists.txt
src/pool.c
src/pooldep.c [new file with mode: 0644]

index f11d555a436578c5d5d2d6e2cf03ad25349be00c..812abe6e16b482fe904a9bb19502ddccb5917930 100644 (file)
@@ -14,7 +14,7 @@ ENDIF (HAVE___QSORT_R)
 ADD_DEFINITIONS (-DLIBSOLV_INTERNAL=1)
 
 SET (libsolv_SRCS
-    bitmap.c poolarch.c poolvendor.c poolid.c
+    bitmap.c poolarch.c poolvendor.c poolid.c pooldep.c
     poolwhatprovides.c pool.c strpool.c dirpool.c
     solver.c solverdebug.c repo_solv.c repo_write.c evr.c
     queue.c repo.c repodata.c repopage.c util.c policy.c solvable.c
index 4c4c46253c0d86fdc36f863699241f6b43812fe1..a82b15006cf8e6c80b96e43f46d0da17888f0163 100644 (file)
@@ -27,9 +27,6 @@
 #include "util.h"
 #include "bitmap.h"
 #include "evr.h"
-#ifdef ENABLE_CONDA
-#include "conda.h"
-#endif
 
 #define SOLVABLE_BLOCK 255
 
@@ -295,7 +292,6 @@ pool_free_solvable_block(Pool *pool, Id start, int count, int reuseids)
   memset(pool->solvables + start, 0, sizeof(Solvable) * count);
 }
 
-
 void
 pool_set_installed(Pool *pool, Repo *installed)
 {
@@ -305,336 +301,6 @@ pool_set_installed(Pool *pool, Repo *installed)
   pool_freewhatprovides(pool);
 }
 
-
-/*************************************************************************/
-
-#if defined(HAIKU) || defined(MULTI_SEMANTICS)
-/* forward declaration */
-static int pool_intersect_evrs_rel_compat(Pool *pool, Reldep *range, int flags, int evr);
-#endif
-
-#if defined(MULTI_SEMANTICS)
-# define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE)
-#elif defined(DEBIAN)
-# define EVRCMP_DEPCMP EVRCMP_COMPARE
-#else
-# define EVRCMP_DEPCMP EVRCMP_MATCH_RELEASE
-#endif
-
-/* match (flags, evr) against provider (pflags, pevr) */
-/* note that this code is also in poolwhatprovides */
-int
-pool_intersect_evrs(Pool *pool, int pflags, Id pevr, int flags, int evr)
-{
-  if (!pflags || !flags || pflags >= 8 || flags >= 8)
-    return 0;
-  if (flags == 7 || pflags == 7)
-    return 1;          /* rel provides every version */
-  if ((pflags & flags & (REL_LT | REL_GT)) != 0)
-    return 1;          /* both rels show in the same direction */
-  if (pevr == evr)
-    return (flags & pflags & REL_EQ) ? 1 : 0;
-#if defined(HAIKU) || defined(MULTI_SEMANTICS)
-  if (ISRELDEP(pevr))
-    {
-      Reldep *rd = GETRELDEP(pool, pevr);
-      if (rd->flags == REL_COMPAT)
-       return pool_intersect_evrs_rel_compat(pool, rd, flags, evr);
-    }
-#endif
-  switch (pool_evrcmp(pool, pevr, evr, EVRCMP_DEPCMP))
-    {
-    case -2:
-      return (pflags & REL_EQ) ? 1 : 0;
-    case -1:
-      return (flags & REL_LT) || (pflags & REL_GT) ? 1 : 0;
-    case 0:
-      return (flags & pflags & REL_EQ) ? 1 : 0;
-    case 1:
-      return (flags & REL_GT) || (pflags & REL_LT) ? 1 : 0;
-    case 2:
-      return (flags & REL_EQ) ? 1 : 0;
-    default:
-      break;
-    }
-  return 0;
-}
-
-#if defined(HAIKU) || defined(MULTI_SEMANTICS)
-static int
-pool_intersect_evrs_rel_compat(Pool *pool, Reldep *range, int flags, int evr)
-{
-  /* range->name is the actual version, range->evr the backwards compatibility
-     version. If flags are '>=' or '>', we match the compatibility version
-     as well, otherwise only the actual version. */
-  if (!(flags & REL_GT) || (flags & REL_LT))
-    return pool_intersect_evrs(pool, REL_EQ, range->name, flags, evr);
-  return pool_intersect_evrs(pool, REL_LT | REL_EQ, range->name, flags, evr) &&
-         pool_intersect_evrs(pool, REL_GT | REL_EQ, range->evr, REL_EQ, evr);
-}
-#endif
-
-/* check if a package's nevr matches a dependency */
-/* semi-private, called from public pool_match_nevr */
-int
-pool_match_nevr_rel(Pool *pool, Solvable *s, Id d)
-{
-  Reldep *rd = GETRELDEP(pool, d);
-  Id name = rd->name;
-  Id evr = rd->evr;
-  int flags = rd->flags;
-
-  if (flags > 7)
-    {
-      switch (flags)
-       {
-       case REL_ARCH:
-         if (s->arch != evr)
-           {
-             if (evr != ARCH_SRC || s->arch != ARCH_NOSRC)
-               return 0;
-           }
-         return pool_match_nevr(pool, s, name);
-       case REL_OR:
-         if (pool_match_nevr(pool, s, name))
-           return 1;
-         return pool_match_nevr(pool, s, evr);
-       case REL_AND:
-       case REL_WITH:
-         if (!pool_match_nevr(pool, s, name))
-           return 0;
-         return pool_match_nevr(pool, s, evr);
-       case REL_WITHOUT:
-         if (!pool_match_nevr(pool, s, name))
-           return 0;
-         return !pool_match_nevr(pool, s, evr);
-       case REL_MULTIARCH:
-         if (evr != ARCH_ANY)
-           return 0;
-         /* XXX : need to check for Multi-Arch: allowed! */
-         return pool_match_nevr(pool, s, name);
-       default:
-         return 0;
-       }
-    }
-  if (!pool_match_nevr(pool, s, name))
-    return 0;
-  if (evr == s->evr)
-    return (flags & REL_EQ) ? 1 : 0;
-  if (!flags)
-    return 0;
-  if (flags == 7)
-    return 1;
-  switch (pool_evrcmp(pool, s->evr, evr, EVRCMP_DEPCMP))
-    {
-    case -2:
-      return 1;
-    case -1:
-      return (flags & REL_LT) ? 1 : 0;
-    case 0:
-      return (flags & REL_EQ) ? 1 : 0;
-    case 1:
-      return (flags & REL_GT) ? 1 : 0;
-    case 2:
-      return (flags & REL_EQ) ? 1 : 0;
-    default:
-      break;
-    }
-  return 0;
-}
-
-static int
-is_interval_dep(Pool *pool, Id d1, Id d2)
-{
-  Reldep *rd1, *rd2;
-  if (!ISRELDEP(d1) || !ISRELDEP(d2))
-    return 0;
-  rd1 = GETRELDEP(pool, d1);
-  rd2 = GETRELDEP(pool, d2);
-  if (rd1->name != rd2->name || rd1->flags >= 8 || rd2->flags >= 8)
-    return 0;
-  if (((rd1->flags ^ rd2->flags) & (REL_LT|REL_GT)) != (REL_LT|REL_GT))
-    return 0;
-  return 1;
-}
-
-
-/* match two dependencies (d1 = provider) */
-
-int
-pool_match_dep(Pool *pool, Id d1, Id d2)
-{
-  Reldep *rd1, *rd2;
-
-  if (d1 == d2)
-    return 1;
-
-  if (ISRELDEP(d1))
-    {
-      /* we use potentially matches for complex deps */
-      rd1 = GETRELDEP(pool, d1);
-      if (rd1->flags == REL_AND || rd1->flags == REL_OR || rd1->flags == REL_WITH || rd1->flags == REL_WITHOUT || rd1->flags == REL_COND || rd1->flags == REL_UNLESS)
-       {
-         if (rd1->flags == REL_WITH && is_interval_dep(pool, rd1->name, rd1->evr))
-           return pool_match_dep(pool, rd1->name, d2) && pool_match_dep(pool, rd1->evr, d2);
-         if (pool_match_dep(pool, rd1->name, d2))
-           return 1;
-         if ((rd1->flags == REL_COND || rd1->flags == REL_UNLESS) && ISRELDEP(rd1->evr))
-           {
-             rd1 = GETRELDEP(pool, rd1->evr);
-             if (rd1->flags != REL_ELSE)
-               return 0;
-           }
-         if (rd1->flags != REL_COND && rd1->flags != REL_UNLESS && rd1->flags != REL_WITHOUT && pool_match_dep(pool, rd1->evr, d2))
-           return 1;
-         return 0;
-       }
-    }
-  if (ISRELDEP(d2))
-    {
-      /* we use potentially matches for complex deps */
-      rd2 = GETRELDEP(pool, d2);
-      if (rd2->flags == REL_AND || rd2->flags == REL_OR || rd2->flags == REL_WITH || rd2->flags == REL_WITHOUT || rd2->flags == REL_COND || rd2->flags == REL_UNLESS)
-       {
-         if (rd2->flags == REL_WITH && is_interval_dep(pool, rd2->name, rd2->evr))
-           return pool_match_dep(pool, d1, rd2->name) && pool_match_dep(pool, d1, rd2->evr);
-         if (pool_match_dep(pool, d1, rd2->name))
-           return 1;
-         if ((rd2->flags == REL_COND || rd2->flags == REL_UNLESS) && ISRELDEP(rd2->evr))
-           {
-             rd2 = GETRELDEP(pool, rd2->evr);
-             if (rd2->flags != REL_ELSE)
-               return 0;
-           }
-         if (rd2->flags != REL_COND && rd2->flags != REL_UNLESS && rd2->flags != REL_WITHOUT && pool_match_dep(pool, d1, rd2->evr))
-           return 1;
-         return 0;
-       }
-    }
-  if (!ISRELDEP(d1))
-    {
-      if (!ISRELDEP(d2))
-       return 0;       /* cannot match as d1 != d2 */
-      rd2 = GETRELDEP(pool, d2);
-      return pool_match_dep(pool, d1, rd2->name);
-    }
-  rd1 = GETRELDEP(pool, d1);
-  if (!ISRELDEP(d2))
-    {
-      return pool_match_dep(pool, rd1->name, d2);
-    }
-  rd2 = GETRELDEP(pool, d2);
-  /* first match name */
-  if (!pool_match_dep(pool, rd1->name, rd2->name))
-    return 0;
-  /* name matches, check flags and evr */
-  return pool_intersect_evrs(pool, rd1->flags, rd1->evr, rd2->flags, rd2->evr);
-}
-
-
-/* intersect dependencies in keyname with dep, return list of matching packages */
-void
-pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker)
-{
-  Id p;
-  Queue qq;
-  int i;
-
-  queue_empty(q);
-  if (keyname == SOLVABLE_NAME)
-    {
-      Id pp;
-      FOR_PROVIDES(p, pp, dep)
-        if (pool_match_nevr(pool, pool->solvables + p, dep))
-         queue_push(q, p);
-      return;
-    }
-  queue_init(&qq);
-  FOR_POOL_SOLVABLES(p)
-    {
-      Solvable *s = pool->solvables + p;
-      if (s->repo->disabled)
-       continue;
-      if (s->repo != pool->installed && !pool_installable(pool, s))
-       continue;
-      if (qq.count)
-       queue_empty(&qq);
-      solvable_lookup_deparray(s, keyname, &qq, marker);
-      for (i = 0; i < qq.count; i++)
-       if (pool_match_dep(pool, qq.elements[i], dep))
-         {
-           queue_push(q, p);
-           break;
-         }
-    }
-  queue_free(&qq);
-}
-
-/* check if keyname contains dep, return list of matching packages */
-void
-pool_whatcontainsdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker)
-{
-  Id p;
-  Queue qq;
-  int i;
-
-  queue_empty(q);
-  if (!dep)
-    return;
-  queue_init(&qq);
-  FOR_POOL_SOLVABLES(p)
-    {
-      Solvable *s = pool->solvables + p;
-      if (s->repo->disabled)
-        continue;
-      if (s->repo != pool->installed && !pool_installable(pool, s))
-        continue;
-      if (qq.count)
-        queue_empty(&qq);
-      solvable_lookup_deparray(s, keyname, &qq, marker);
-      for (i = 0; i < qq.count; i++)
-        if (qq.elements[i] == dep)
-          {
-            queue_push(q, p);
-            break;
-          }
-    }
-  queue_free(&qq);
-}
-
-/* intersect dependencies in keyname with all provides of solvable solvid,
- * return list of matching packages */
-/* this currently only works for installable packages */
-void
-pool_whatmatchessolvable(Pool *pool, Id keyname, Id solvid, Queue *q, int marker)
-{
-  Id p;
-  Queue qq;
-  Map missc;           /* cache for misses */
-  int reloff;
-
-  queue_empty(q);
-  queue_init(&qq);
-  reloff = pool->ss.nstrings;
-  map_init(&missc, reloff + pool->nrels);
-  FOR_POOL_SOLVABLES(p)
-    {
-      Solvable *s = pool->solvables + p;
-      if (p == solvid)
-       continue;       /* filter out self-matches */
-      if (s->repo->disabled)
-       continue;
-      if (s->repo != pool->installed && !pool_installable(pool, s))
-       continue;
-      if (solvable_matchessolvable_int(s, keyname, marker, solvid, 0, &qq, &missc, reloff, 0))
-        queue_push(q, p);
-    }
-  map_free(&missc);
-  queue_free(&qq);
-}
-
-/*************************************************************************/
-
 void
 pool_debug(Pool *pool, int type, const char *format, ...)
 {
diff --git a/src/pooldep.c b/src/pooldep.c
new file mode 100644 (file)
index 0000000..d397c28
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2025, SUSE LLC
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * pooldep.c
+ *
+ * dependency matching and searching
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#include "evr.h"
+
+
+#if defined(MULTI_SEMANTICS)
+# define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE)
+#elif defined(DEBIAN)
+# define EVRCMP_DEPCMP EVRCMP_COMPARE
+#else
+# define EVRCMP_DEPCMP EVRCMP_MATCH_RELEASE
+#endif
+
+
+#if defined(HAIKU) || defined(MULTI_SEMANTICS)
+static int
+pool_intersect_evrs_rel_compat(Pool *pool, Reldep *range, int flags, int evr)
+{
+  /* range->name is the actual version, range->evr the backwards compatibility
+     version. If flags are '>=' or '>', we match the compatibility version
+     as well, otherwise only the actual version. */
+  if (!(flags & REL_GT) || (flags & REL_LT))
+    return pool_intersect_evrs(pool, REL_EQ, range->name, flags, evr);
+  return pool_intersect_evrs(pool, REL_LT | REL_EQ, range->name, flags, evr) &&
+         pool_intersect_evrs(pool, REL_GT | REL_EQ, range->evr, REL_EQ, evr);
+}
+#endif
+
+/* match (flags, evr) against provider (pflags, pevr) */
+/* note that this code is also in poolwhatprovides */
+int
+pool_intersect_evrs(Pool *pool, int pflags, Id pevr, int flags, int evr)
+{
+  if (!pflags || !flags || pflags >= 8 || flags >= 8)
+    return 0;
+  if (flags == 7 || pflags == 7)
+    return 1;          /* rel provides every version */
+  if ((pflags & flags & (REL_LT | REL_GT)) != 0)
+    return 1;          /* both rels show in the same direction */
+  if (pevr == evr)
+    return (flags & pflags & REL_EQ) ? 1 : 0;
+#if defined(HAIKU) || defined(MULTI_SEMANTICS)
+  if (ISRELDEP(pevr))
+    {
+      Reldep *rd = GETRELDEP(pool, pevr);
+      if (rd->flags == REL_COMPAT)
+       return pool_intersect_evrs_rel_compat(pool, rd, flags, evr);
+    }
+#endif
+  switch (pool_evrcmp(pool, pevr, evr, EVRCMP_DEPCMP))
+    {
+    case -2:
+      return (pflags & REL_EQ) ? 1 : 0;
+    case -1:
+      return (flags & REL_LT) || (pflags & REL_GT) ? 1 : 0;
+    case 0:
+      return (flags & pflags & REL_EQ) ? 1 : 0;
+    case 1:
+      return (flags & REL_GT) || (pflags & REL_LT) ? 1 : 0;
+    case 2:
+      return (flags & REL_EQ) ? 1 : 0;
+    default:
+      break;
+    }
+  return 0;
+}
+
+/* check if a package's nevr matches a dependency */
+/* semi-private, called from public pool_match_nevr */
+int
+pool_match_nevr_rel(Pool *pool, Solvable *s, Id d)
+{
+  Reldep *rd = GETRELDEP(pool, d);
+  Id name = rd->name;
+  Id evr = rd->evr;
+  int flags = rd->flags;
+
+  if (flags > 7)
+    {
+      switch (flags)
+       {
+       case REL_ARCH:
+         if (s->arch != evr)
+           {
+             if (evr != ARCH_SRC || s->arch != ARCH_NOSRC)
+               return 0;
+           }
+         return pool_match_nevr(pool, s, name);
+       case REL_OR:
+         if (pool_match_nevr(pool, s, name))
+           return 1;
+         return pool_match_nevr(pool, s, evr);
+       case REL_AND:
+       case REL_WITH:
+         if (!pool_match_nevr(pool, s, name))
+           return 0;
+         return pool_match_nevr(pool, s, evr);
+       case REL_WITHOUT:
+         if (!pool_match_nevr(pool, s, name))
+           return 0;
+         return !pool_match_nevr(pool, s, evr);
+       case REL_MULTIARCH:
+         if (evr != ARCH_ANY)
+           return 0;
+         /* XXX : need to check for Multi-Arch: allowed! */
+         return pool_match_nevr(pool, s, name);
+       default:
+         return 0;
+       }
+    }
+  if (!pool_match_nevr(pool, s, name))
+    return 0;
+  if (evr == s->evr)
+    return (flags & REL_EQ) ? 1 : 0;
+  if (!flags)
+    return 0;
+  if (flags == 7)
+    return 1;
+  switch (pool_evrcmp(pool, s->evr, evr, EVRCMP_DEPCMP))
+    {
+    case -2:
+      return 1;
+    case -1:
+      return (flags & REL_LT) ? 1 : 0;
+    case 0:
+      return (flags & REL_EQ) ? 1 : 0;
+    case 1:
+      return (flags & REL_GT) ? 1 : 0;
+    case 2:
+      return (flags & REL_EQ) ? 1 : 0;
+    default:
+      break;
+    }
+  return 0;
+}
+
+static int
+is_interval_dep(Pool *pool, Id d1, Id d2)
+{
+  Reldep *rd1, *rd2;
+  if (!ISRELDEP(d1) || !ISRELDEP(d2))
+    return 0;
+  rd1 = GETRELDEP(pool, d1);
+  rd2 = GETRELDEP(pool, d2);
+  if (rd1->name != rd2->name || rd1->flags >= 8 || rd2->flags >= 8)
+    return 0;
+  if (((rd1->flags ^ rd2->flags) & (REL_LT|REL_GT)) != (REL_LT|REL_GT))
+    return 0;
+  return 1;
+}
+
+
+/* match two dependencies (d1 = provider) */
+
+int
+pool_match_dep(Pool *pool, Id d1, Id d2)
+{
+  Reldep *rd1, *rd2;
+
+  if (d1 == d2)
+    return 1;
+
+  if (ISRELDEP(d1))
+    {
+      /* we use potentially matches for complex deps */
+      rd1 = GETRELDEP(pool, d1);
+      if (rd1->flags == REL_AND || rd1->flags == REL_OR || rd1->flags == REL_WITH || rd1->flags == REL_WITHOUT || rd1->flags == REL_COND || rd1->flags == REL_UNLESS)
+       {
+         if (rd1->flags == REL_WITH && is_interval_dep(pool, rd1->name, rd1->evr))
+           return pool_match_dep(pool, rd1->name, d2) && pool_match_dep(pool, rd1->evr, d2);
+         if (pool_match_dep(pool, rd1->name, d2))
+           return 1;
+         if ((rd1->flags == REL_COND || rd1->flags == REL_UNLESS) && ISRELDEP(rd1->evr))
+           {
+             rd1 = GETRELDEP(pool, rd1->evr);
+             if (rd1->flags != REL_ELSE)
+               return 0;
+           }
+         if (rd1->flags != REL_COND && rd1->flags != REL_UNLESS && rd1->flags != REL_WITHOUT && pool_match_dep(pool, rd1->evr, d2))
+           return 1;
+         return 0;
+       }
+    }
+  if (ISRELDEP(d2))
+    {
+      /* we use potentially matches for complex deps */
+      rd2 = GETRELDEP(pool, d2);
+      if (rd2->flags == REL_AND || rd2->flags == REL_OR || rd2->flags == REL_WITH || rd2->flags == REL_WITHOUT || rd2->flags == REL_COND || rd2->flags == REL_UNLESS)
+       {
+         if (rd2->flags == REL_WITH && is_interval_dep(pool, rd2->name, rd2->evr))
+           return pool_match_dep(pool, d1, rd2->name) && pool_match_dep(pool, d1, rd2->evr);
+         if (pool_match_dep(pool, d1, rd2->name))
+           return 1;
+         if ((rd2->flags == REL_COND || rd2->flags == REL_UNLESS) && ISRELDEP(rd2->evr))
+           {
+             rd2 = GETRELDEP(pool, rd2->evr);
+             if (rd2->flags != REL_ELSE)
+               return 0;
+           }
+         if (rd2->flags != REL_COND && rd2->flags != REL_UNLESS && rd2->flags != REL_WITHOUT && pool_match_dep(pool, d1, rd2->evr))
+           return 1;
+         return 0;
+       }
+    }
+  if (!ISRELDEP(d1))
+    {
+      if (!ISRELDEP(d2))
+       return 0;       /* cannot match as d1 != d2 */
+      rd2 = GETRELDEP(pool, d2);
+      return pool_match_dep(pool, d1, rd2->name);
+    }
+  rd1 = GETRELDEP(pool, d1);
+  if (!ISRELDEP(d2))
+    {
+      return pool_match_dep(pool, rd1->name, d2);
+    }
+  rd2 = GETRELDEP(pool, d2);
+  /* first match name */
+  if (!pool_match_dep(pool, rd1->name, rd2->name))
+    return 0;
+  /* name matches, check flags and evr */
+  return pool_intersect_evrs(pool, rd1->flags, rd1->evr, rd2->flags, rd2->evr);
+}
+
+
+/* intersect dependencies in keyname with dep, return list of matching packages */
+void
+pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker)
+{
+  Id p;
+  Queue qq;
+  int i;
+
+  queue_empty(q);
+  if (keyname == SOLVABLE_NAME)
+    {
+      Id pp;
+      FOR_PROVIDES(p, pp, dep)
+        if (pool_match_nevr(pool, pool->solvables + p, dep))
+         queue_push(q, p);
+      return;
+    }
+  queue_init(&qq);
+  FOR_POOL_SOLVABLES(p)
+    {
+      Solvable *s = pool->solvables + p;
+      if (s->repo->disabled)
+       continue;
+      if (s->repo != pool->installed && !pool_installable(pool, s))
+       continue;
+      if (qq.count)
+       queue_empty(&qq);
+      solvable_lookup_deparray(s, keyname, &qq, marker);
+      for (i = 0; i < qq.count; i++)
+       if (pool_match_dep(pool, qq.elements[i], dep))
+         {
+           queue_push(q, p);
+           break;
+         }
+    }
+  queue_free(&qq);
+}
+
+/* check if keyname contains dep, return list of matching packages */
+void
+pool_whatcontainsdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker)
+{
+  Id p;
+  Queue qq;
+  int i;
+
+  queue_empty(q);
+  if (!dep)
+    return;
+  queue_init(&qq);
+  FOR_POOL_SOLVABLES(p)
+    {
+      Solvable *s = pool->solvables + p;
+      if (s->repo->disabled)
+        continue;
+      if (s->repo != pool->installed && !pool_installable(pool, s))
+        continue;
+      if (qq.count)
+        queue_empty(&qq);
+      solvable_lookup_deparray(s, keyname, &qq, marker);
+      for (i = 0; i < qq.count; i++)
+        if (qq.elements[i] == dep)
+          {
+            queue_push(q, p);
+            break;
+          }
+    }
+  queue_free(&qq);
+}
+
+/* intersect dependencies in keyname with all provides of solvable solvid,
+ * return list of matching packages */
+/* this currently only works for installable packages */
+void
+pool_whatmatchessolvable(Pool *pool, Id keyname, Id solvid, Queue *q, int marker)
+{
+  Id p;
+  Queue qq;
+  Map missc;           /* cache for misses */
+  int reloff;
+
+  queue_empty(q);
+  queue_init(&qq);
+  reloff = pool->ss.nstrings;
+  map_init(&missc, reloff + pool->nrels);
+  FOR_POOL_SOLVABLES(p)
+    {
+      Solvable *s = pool->solvables + p;
+      if (p == solvid)
+       continue;       /* filter out self-matches */
+      if (s->repo->disabled)
+       continue;
+      if (s->repo != pool->installed && !pool_installable(pool, s))
+       continue;
+      if (solvable_matchessolvable_int(s, keyname, marker, solvid, 0, &qq, &missc, reloff, 0))
+        queue_push(q, p);
+    }
+  map_free(&missc);
+  queue_free(&qq);
+}
+
+/* EOF */