]> git.ipfire.org Git - thirdparty/libsolv.git/commitdiff
Add new solver_util.c file for helper functions
authorMichael Schroeder <mls@suse.de>
Wed, 4 Oct 2017 11:48:27 +0000 (13:48 +0200)
committerMichael Schroeder <mls@suse.de>
Wed, 4 Oct 2017 11:54:15 +0000 (13:54 +0200)
No need to clutter up the solver.c and rules.c with those
functions.

src/CMakeLists.txt
src/rules.c
src/solver.c
src/solver_private.h
src/solver_util.c [new file with mode: 0644]

index 76ea9f16d0aef2b8dff961c4084c9c0dc7508cb7..9f19efa3ac9c1c222b3d8050cd6b1e5e36024c5f 100644 (file)
@@ -19,7 +19,7 @@ SET (libsolv_SRCS
     queue.c repo.c repodata.c repopage.c util.c policy.c solvable.c
     transaction.c order.c rules.c problems.c linkedpkg.c cplxdeps.c
     chksum.c md5.c sha1.c sha2.c solvversion.c selection.c
-    fileprovides.c diskusage.c suse.c)
+    fileprovides.c diskusage.c suse.c solver_util.c)
 
 SET (libsolv_HEADERS
     bitmap.h evr.h hash.h policy.h poolarch.h poolvendor.h pool.h
index 7206ebbd85480a3d77606fde90af80f600437242..71bb4f14efdb55c4c87a199964398b5477b80b0e 100644 (file)
 static void addpkgruleinfo(Solver *solv, Id p, Id p2, Id d, int type, Id dep);
 static void solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded);
 
-/*-------------------------------------------------------------------
- * Check if dependency is possible
- *
- * mirrors solver_dep_fulfilled but uses map m instead of the decisionmap.
- * used in solver_addpkgrulesforweak and solver_createcleandepsmap.
- */
-
-static inline int
-dep_possible(Solver *solv, Id dep, Map *m)
-{
-  Pool *pool = solv->pool;
-  Id p, pp;
-
-  if (ISRELDEP(dep))
-    {
-      Reldep *rd = GETRELDEP(pool, dep);
-      if (rd->flags >= 8)
-        {
-         if (rd->flags == REL_COND || rd->flags == REL_UNLESS)
-           return 1;
-         if (rd->flags == REL_AND)
-           {
-             if (!dep_possible(solv, rd->name, m))
-               return 0;
-             return dep_possible(solv, rd->evr, m);
-           }
-         if (rd->flags == REL_OR)
-           {
-             if (dep_possible(solv, rd->name, m))
-               return 1;
-             return dep_possible(solv, rd->evr, m);
-           }
-         if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
-           return solver_splitprovides(solv, rd->evr, m);
-       }
-    }
-  FOR_PROVIDES(p, pp, dep)
-    {
-      if (MAPTST(m, p))
-       return 1;
-    }
-  return 0;
-}
-
 static inline int
 is_otherproviders_dep(Pool *pool, Id dep)
 {
@@ -1205,7 +1161,7 @@ solver_addpkgrulesforweak(Solver *solv, Map *m)
          /* find possible supplements */
          supp = s->repo->idarraydata + s->supplements;
          while ((sup = *supp++) != 0)
-           if (dep_possible(solv, sup, m))
+           if (solver_dep_possible(solv, sup, m))
              break;
        }
 
@@ -1214,7 +1170,7 @@ solver_addpkgrulesforweak(Solver *solv, Map *m)
        {
          supp = s->repo->idarraydata + s->enhances;
          while ((sup = *supp++) != 0)
-           if (dep_possible(solv, sup, m))
+           if (solver_dep_possible(solv, sup, m))
              break;
        }
       /* if nothing found, goto next solvables */
@@ -2137,120 +2093,6 @@ reenableduprule(Solver *solv, Id name)
 #define DISABLE_INFARCH        2
 #define DISABLE_DUP    3
 
-/*
- * add all installed packages that package p obsoletes to Queue q.
- * Package p is not installed. Also, we know that if
- * solv->keepexplicitobsoletes is not set, p is not in the multiversion map.
- * Entries may get added multiple times.
- */
-static void
-add_obsoletes(Solver *solv, Id p, Queue *q)
-{
-  Pool *pool = solv->pool;
-  Repo *installed = solv->installed;
-  Id p2, pp2;
-  Solvable *s = pool->solvables + p;
-  Id obs, *obsp;
-  Id lastp2 = 0;
-
-  if (!solv->keepexplicitobsoletes || !(solv->multiversion.size && MAPTST(&solv->multiversion, p)))
-    {
-      FOR_PROVIDES(p2, pp2, s->name)
-       {
-         Solvable *ps = pool->solvables + p2;
-         if (ps->repo != installed)
-           continue;
-         if (!pool->implicitobsoleteusesprovides && ps->name != s->name)
-           continue;
-         if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
-           continue;
-         queue_push(q, p2);
-         lastp2 = p2;
-       }
-    }
-  if (!s->obsoletes)
-    return;
-  obsp = s->repo->idarraydata + s->obsoletes;
-  while ((obs = *obsp++) != 0)
-    FOR_PROVIDES(p2, pp2, obs)
-      {
-       Solvable *ps = pool->solvables + p2;
-       if (ps->repo != installed)
-         continue;
-       if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
-         continue;
-       if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
-         continue;
-       if (p2 == lastp2)
-         continue;
-       queue_push(q, p2);
-       lastp2 = p2;
-      }
-}
-
-/*
- * Call add_obsoletes and intersect the result with the
- * elements in Queue q starting at qstart.
- * Assumes that it's the first call if qstart == q->count.
- * May use auxillary map m for the intersection process, all
- * elements of q starting at qstart must have their bit cleared.
- * (This is also true after the function returns.)
- */
-static void
-intersect_obsoletes(Solver *solv, Id p, Queue *q, int qstart, Map *m)
-{
-  int i, j;
-  int qcount = q->count;
-
-  add_obsoletes(solv, p, q);
-  if (qcount == qstart)
-    return;    /* first call */
-  if (qcount == q->count)
-    j = qstart;        
-  else if (qcount == qstart + 1)
-    {
-      /* easy if there's just one element */
-      j = qstart;
-      for (i = qcount; i < q->count; i++)
-       if (q->elements[i] == q->elements[qstart])
-         {
-           j++;        /* keep the element */
-           break;
-         }
-    }
-  else if (!m->size && q->count - qstart <= 8)
-    {
-      /* faster than a map most of the time */
-      int k;
-      for (i = j = qstart; i < qcount; i++)
-       {
-         Id ip = q->elements[i];
-         for (k = qcount; k < q->count; k++)
-           if (q->elements[k] == ip)
-             {
-               q->elements[j++] = ip;
-               break;
-             }
-       }
-    }
-  else
-    {
-      /* for the really pathologic cases we use the map */
-      Repo *installed = solv->installed;
-      if (!m->size)
-       map_init(m, installed->end - installed->start);
-      for (i = qcount; i < q->count; i++)
-       MAPSET(m, q->elements[i] - installed->start);
-      for (i = j = qstart; i < qcount; i++)
-       if (MAPTST(m, q->elements[i] - installed->start))
-         {
-           MAPCLR(m, q->elements[i] - installed->start);
-           q->elements[j++] = q->elements[i];
-         }
-    }
-  queue_truncate(q, j);
-}
-
 static void
 jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
 {
@@ -2366,7 +2208,7 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
       qstart = q->count;
       FOR_JOB_SELECT(p, pp, select, what)
        {
-         intersect_obsoletes(solv, p, q, qstart, &omap);
+         solver_intersect_obsoleted(solv, p, q, qstart, &omap);
          if (q->count == qstart)
            break;
        }
@@ -4243,7 +4085,7 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded)
                        }
                    }
                  else
-                   intersect_obsoletes(solv, p, &iq, iqstart, &om);
+                   solver_intersect_obsoleted(solv, p, &iq, iqstart, &om);
                  if (iq.count == iqstart)
                    break;
                }
@@ -4311,13 +4153,13 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded)
                continue;
              supp = s->repo->idarraydata + s->supplements;
              while ((sup = *supp++) != 0)
-               if (dep_possible(solv, sup, &im))
+               if (solver_dep_possible(solv, sup, &im))
                  break;
              if (!sup)
                {
                  supp = s->repo->idarraydata + s->supplements;
                  while ((sup = *supp++) != 0)
-                   if (dep_possible(solv, sup, &installedm) || (xsuppq.count && queue_contains(&xsuppq, sup)))
+                   if (solver_dep_possible(solv, sup, &installedm) || (xsuppq.count && queue_contains(&xsuppq, sup)))
                      {
                        /* no longer supplemented, also erase */
                        int iqcount = iq.count;
@@ -4473,7 +4315,7 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded)
                continue;
              supp = s->repo->idarraydata + s->supplements;
              while ((sup = *supp++) != 0)
-               if (dep_possible(solv, sup, &im))
+               if (solver_dep_possible(solv, sup, &im))
                  break;
              if (sup)
                {
@@ -4832,7 +4674,7 @@ solver_get_unneeded(Solver *solv, Queue *unneededq, int filtered)
              Id *dp;
              int k;
              for (dp = s->repo->idarraydata + s->supplements; *dp; dp++)
-               if (dep_possible(solv, *dp, &installedm))
+               if (solver_dep_possible(solv, *dp, &installedm))
                  {
                    Queue iq;
                    Id iqbuf[16];
index 4aa92901e3e01d9fddf380c0ed844c1ec457165c..25969ec8a630c9ab083fd393b358fe17bf40c4e2 100644 (file)
 #define RULES_BLOCK 63
 
 
-/********************************************************************
- *
- * dependency check helpers
- *
- */
-
-/*-------------------------------------------------------------------
- * handle split provides
- *
- * a splitprovides dep looks like
- *     namespace:splitprovides(pkg REL_WITH path)
- * and is only true if pkg is installed and contains the specified path.
- * we also make sure that pkg is selected for an update, otherwise the
- * update would always be forced onto the user.
- * Map m is the map used when called from dep_possible.
- */
-
-static int
-solver_is_updating(Solver *solv, Id p)
-{
-  /* check if the update rule is true */
-  Pool *pool = solv->pool;
-  Rule *r;
-  Id l, pp;
-  if (solv->decisionmap[p] >= 0)
-    return 0;  /* old package stayed */
-  r = solv->rules + solv->updaterules + (p - solv->installed->start);
-  FOR_RULELITERALS(l, pp, r)
-    if (l > 0 && l != p && solv->decisionmap[l] > 0)
-      return 1;
-  return 0;
-}
-
-int
-solver_splitprovides(Solver *solv, Id dep, Map *m)
-{
-  Pool *pool = solv->pool;
-  Id p, pp;
-  Reldep *rd;
-  Solvable *s;
-
-  if (!solv->dosplitprovides || !solv->installed)
-    return 0;
-  if (!ISRELDEP(dep))
-    return 0;
-  rd = GETRELDEP(pool, dep);
-  if (rd->flags != REL_WITH)
-    return 0;
-  /*
-   * things are a bit tricky here if pool->addedprovides == 1, because most split-provides are in
-   * a non-standard location. If we simply call pool_whatprovides, we'll drag in the complete
-   * file list. Instead we rely on pool_addfileprovides ignoring the addfileprovidesfiltered flag
-   * for installed packages and check the lazywhatprovidesq (ignoring the REL_WITH part, but
-   * we filter the package name further down anyway).
-   */
-  if (pool->addedfileprovides == 1 && !ISRELDEP(rd->evr) && !pool->whatprovides[rd->evr])
-    pp = pool_searchlazywhatprovidesq(pool, rd->evr);
-  else
-    pp = pool_whatprovides(pool, dep);
-  while ((p = pool->whatprovidesdata[pp++]) != 0)
-    {
-      /* here we have packages that provide the correct name and contain the path,
-       * now do extra filtering */
-      s = pool->solvables + p;
-      if (s->repo != solv->installed || s->name != rd->name)
-       continue;
-      /* check if the package is updated. if m is set, we're called from dep_possible */
-      if (m || solver_is_updating(solv, p))
-       return 1;
-    }
-  return 0;
-}
-
-int
-solver_dep_fulfilled_cplx(Solver *solv, Reldep *rd)
-{
-  Pool *pool = solv->pool;
-  if (rd->flags == REL_COND)
-    {
-      if (ISRELDEP(rd->evr))
-       {
-         Reldep *rd2 = GETRELDEP(pool, rd->evr);
-         if (rd2->flags == REL_ELSE)
-           {
-             if (solver_dep_fulfilled(solv, rd2->name))
-               return solver_dep_fulfilled(solv, rd->name);
-             return solver_dep_fulfilled(solv, rd2->evr);
-           }
-       }
-      if (solver_dep_fulfilled(solv, rd->name))
-       return 1;
-      return !solver_dep_fulfilled(solv, rd->evr);
-    }
-  if (rd->flags == REL_UNLESS)
-    {
-      if (ISRELDEP(rd->evr))
-       {
-         Reldep *rd2 = GETRELDEP(pool, rd->evr);
-         if (rd2->flags == REL_ELSE)
-           {
-             if (!solver_dep_fulfilled(solv, rd2->name))
-               return solver_dep_fulfilled(solv, rd->name);
-             return solver_dep_fulfilled(solv, rd2->evr);
-           }
-       }
-      if (!solver_dep_fulfilled(solv, rd->name))
-       return 0;
-      return !solver_dep_fulfilled(solv, rd->evr);
-    }
-  if (rd->flags == REL_AND)
-    {
-      if (!solver_dep_fulfilled(solv, rd->name))
-       return 0;
-      return solver_dep_fulfilled(solv, rd->evr);
-    }
-  if (rd->flags == REL_OR)
-    {
-      if (solver_dep_fulfilled(solv, rd->name))
-       return 1;
-      return solver_dep_fulfilled(solv, rd->evr);
-    }
-  return 0;
-}
-
-
-/* mirrors solver_dep_fulfilled, but returns 2 if a new package
- * was involved */
-static int
-solver_dep_fulfilled_alreadyinstalled(Solver *solv, Id dep)
-{
-  Pool *pool = solv->pool;
-  Id p, pp;
-  int r;
-
-  if (ISRELDEP(dep))
-    {
-      Reldep *rd = GETRELDEP(pool, dep);
-      if (rd->flags == REL_COND)
-       {
-         int r1, r2;
-         if (ISRELDEP(rd->evr))
-           {
-             Reldep *rd2 = GETRELDEP(pool, rd->evr);
-             if (rd2->flags == REL_ELSE)
-               {
-                 r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->name);
-                 if (r1)
-                   {
-                     r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
-                     return r2 && r1 == 2 ? 2 : r2;
-                   }
-                 return solver_dep_fulfilled_alreadyinstalled(solv, rd2->evr);
-               }
-           }
-         r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
-         r2 = !solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
-         if (!r1 && !r2)
-           return 0;
-          return r1 == 2 ? 2 : 1;
-       }
-      if (rd->flags == REL_UNLESS)
-       {
-         int r1, r2;
-         if (ISRELDEP(rd->evr))
-           {
-             Reldep *rd2 = GETRELDEP(pool, rd->evr);
-             if (rd2->flags == REL_ELSE)
-               {
-                 r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->name);
-                 if (r1)
-                   {
-                     r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->evr);
-                     return r2 && r1 == 2 ? 2 : r2;
-                   }
-                 return solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
-               }
-           }
-         /* A AND NOT(B) */
-         r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
-         r2 = !solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
-         if (!r1 || !r2)
-           return 0;
-          return r1 == 2 ? 2 : 1;
-       }
-      if (rd->flags == REL_AND)
-        {
-         int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
-          if (!r1)
-            return 0;
-         r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
-         if (!r2)
-           return 0;
-          return r1 == 2 || r2 == 2 ? 2 : 1;
-        }
-      if (rd->flags == REL_OR)
-       {
-         int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
-         r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
-         if (!r1 && !r2)
-           return 0;
-          return r1 == 2 || r2 == 2 ? 2 : 1;
-       }
-      if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
-        return solver_splitprovides(solv, rd->evr, 0) ? 2 : 0;
-      if (rd->flags == REL_NAMESPACE && solv->installsuppdepq)
-       {
-         Queue *q = solv->installsuppdepq;
-         int i;
-         for (i = 0; i < q->count; i++)
-           if (q->elements[i] == dep || q->elements[i] == rd->name)
-             return 2;
-       }
-    }
-  r = 0;
-  FOR_PROVIDES(p, pp, dep)
-    if (solv->decisionmap[p] > 0)
-      {
-       Solvable *s = pool->solvables + p;
-       if (s->repo && s->repo != solv->installed)
-         return 2;
-        r = 1;
-      }
-  return r;
-}
-
-static int
-solver_is_supplementing_alreadyinstalled(Solver *solv, Solvable *s)
-{
-  Id sup, *supp;
-  supp = s->repo->idarraydata + s->supplements;
-  while ((sup = *supp++) != 0)
-    if (solver_dep_fulfilled_alreadyinstalled(solv, sup) == 2)
-      return 1;
-  return 0;
-}
-
 static Id
 autouninstall(Solver *solv, Id *problem)
 {
index a2342238c340fa430c002aba10fa7a02cf21d124..50cf2932fa648ea66767accc0e97c1c80237e0e0 100644 (file)
@@ -17,7 +17,29 @@ extern void solver_run_sat(Solver *solv, int disablerules, int doweak);
 extern void solver_reset(Solver *solv);
 
 extern int solver_splitprovides(Solver *solv, Id dep, Map *m);
+extern int solver_dep_possible_slow(Solver *solv, Id dep, Map *m);
 extern int solver_dep_fulfilled_cplx(Solver *solv, Reldep *rd);
+extern int solver_is_supplementing_alreadyinstalled(Solver *solv, Solvable *s);
+extern void solver_intersect_obsoleted(Solver *solv, Id p, Queue *q, int qstart, Map *m);
+
+
+#define ISSIMPLEDEP(pool, dep) (!ISRELDEP(dep) || GETRELDEP(pool, dep)->flags < 8)
+
+static inline int
+solver_dep_possible(Solver *solv, Id dep, Map *m)
+{
+  Pool *pool = solv->pool;
+  Id p, pp;
+
+  if (!ISSIMPLEDEP(pool, dep))
+    return solver_dep_possible_slow(solv, dep, m);
+  FOR_PROVIDES(p, pp, dep)
+    {  
+      if (MAPTST(m, p))
+        return 1;
+    }
+  return 0;
+}
 
 static inline int
 solver_dep_fulfilled(Solver *solv, Id dep)
diff --git a/src/solver_util.c b/src/solver_util.c
new file mode 100644 (file)
index 0000000..d5096ac
--- /dev/null
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2017, SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * solver_util.c
+ *
+ * Dependency solver helper functions
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "solver.h"
+#include "solver_private.h"
+#include "bitmap.h"
+#include "pool.h"
+#include "poolarch.h"
+#include "util.h"
+
+
+/*-------------------------------------------------------------------
+ * check if a installed package p is being updated
+ */
+static int
+solver_is_updating(Solver *solv, Id p)
+{
+  /* check if the update rule is true */
+  Pool *pool = solv->pool;
+  Rule *r;
+  Id l, pp;
+  if (solv->decisionmap[p] >= 0)
+    return 0;  /* old package stayed */
+  r = solv->rules + solv->updaterules + (p - solv->installed->start);
+  FOR_RULELITERALS(l, pp, r)
+    if (l > 0 && l != p && solv->decisionmap[l] > 0)
+      return 1;
+  return 0;
+}
+
+/*-------------------------------------------------------------------
+ * handle split provides
+ *
+ * a splitprovides dep looks like
+ *     namespace:splitprovides(pkg REL_WITH path)
+ * and is only true if pkg is installed and contains the specified path.
+ * we also make sure that pkg is selected for an update, otherwise the
+ * update would always be forced onto the user.
+ * Map m is the map used when called from dep_possible.
+ */
+int
+solver_splitprovides(Solver *solv, Id dep, Map *m)
+{
+  Pool *pool = solv->pool;
+  Id p, pp;
+  Reldep *rd;
+  Solvable *s;
+
+  if (!solv->dosplitprovides || !solv->installed)
+    return 0;
+  if (!ISRELDEP(dep))
+    return 0;
+  rd = GETRELDEP(pool, dep);
+  if (rd->flags != REL_WITH)
+    return 0;
+  /*
+   * things are a bit tricky here if pool->addedprovides == 1, because most split-provides are in
+   * a non-standard location. If we simply call pool_whatprovides, we'll drag in the complete
+   * file list. Instead we rely on pool_addfileprovides ignoring the addfileprovidesfiltered flag
+   * for installed packages and check the lazywhatprovidesq (ignoring the REL_WITH part, but
+   * we filter the package name further down anyway).
+   */
+  if (pool->addedfileprovides == 1 && !ISRELDEP(rd->evr) && !pool->whatprovides[rd->evr])
+    pp = pool_searchlazywhatprovidesq(pool, rd->evr);
+  else
+    pp = pool_whatprovides(pool, dep);
+  while ((p = pool->whatprovidesdata[pp++]) != 0)
+    {
+      /* here we have packages that provide the correct name and contain the path,
+       * now do extra filtering */
+      s = pool->solvables + p;
+      if (s->repo != solv->installed || s->name != rd->name)
+       continue;
+      /* check if the package is updated. if m is set, we're called from dep_possible */
+      if (m || solver_is_updating(solv, p))
+       return 1;
+    }
+  return 0;
+}
+
+int
+solver_dep_possible_slow(Solver *solv, Id dep, Map *m)
+{
+  Pool *pool = solv->pool;
+  Id p, pp;
+
+  if (ISRELDEP(dep))
+    {
+      Reldep *rd = GETRELDEP(pool, dep);
+      if (rd->flags >= 8)
+         {
+          if (rd->flags == REL_COND || rd->flags == REL_UNLESS)
+            return 1;
+          if (rd->flags == REL_AND)
+            {
+              if (!solver_dep_possible_slow(solv, rd->name, m))
+                return 0;
+              return solver_dep_possible_slow(solv, rd->evr, m);
+            }
+          if (rd->flags == REL_OR)
+            {
+              if (solver_dep_possible_slow(solv, rd->name, m))
+                return 1;
+              return solver_dep_possible_slow(solv, rd->evr, m);
+            }
+          if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
+            return solver_splitprovides(solv, rd->evr, m);
+        }
+    }
+  FOR_PROVIDES(p, pp, dep)
+    {
+      if (MAPTST(m, p))
+        return 1;
+    }
+  return 0;
+}
+
+int
+solver_dep_fulfilled_cplx(Solver *solv, Reldep *rd)
+{
+  Pool *pool = solv->pool;
+  if (rd->flags == REL_COND)
+    {
+      if (ISRELDEP(rd->evr))
+       {
+         Reldep *rd2 = GETRELDEP(pool, rd->evr);
+         if (rd2->flags == REL_ELSE)
+           {
+             if (solver_dep_fulfilled(solv, rd2->name))
+               return solver_dep_fulfilled(solv, rd->name);
+             return solver_dep_fulfilled(solv, rd2->evr);
+           }
+       }
+      if (solver_dep_fulfilled(solv, rd->name))
+       return 1;
+      return !solver_dep_fulfilled(solv, rd->evr);
+    }
+  if (rd->flags == REL_UNLESS)
+    {
+      if (ISRELDEP(rd->evr))
+       {
+         Reldep *rd2 = GETRELDEP(pool, rd->evr);
+         if (rd2->flags == REL_ELSE)
+           {
+             if (!solver_dep_fulfilled(solv, rd2->name))
+               return solver_dep_fulfilled(solv, rd->name);
+             return solver_dep_fulfilled(solv, rd2->evr);
+           }
+       }
+      if (!solver_dep_fulfilled(solv, rd->name))
+       return 0;
+      return !solver_dep_fulfilled(solv, rd->evr);
+    }
+  if (rd->flags == REL_AND)
+    {
+      if (!solver_dep_fulfilled(solv, rd->name))
+       return 0;
+      return solver_dep_fulfilled(solv, rd->evr);
+    }
+  if (rd->flags == REL_OR)
+    {
+      if (solver_dep_fulfilled(solv, rd->name))
+       return 1;
+      return solver_dep_fulfilled(solv, rd->evr);
+    }
+  return 0;
+}
+
+
+/* mirrors solver_dep_fulfilled, but returns 2 if a new package
+ * was involved */
+static int
+solver_dep_fulfilled_alreadyinstalled(Solver *solv, Id dep)
+{
+  Pool *pool = solv->pool;
+  Id p, pp;
+  int r;
+
+  if (ISRELDEP(dep))
+    {
+      Reldep *rd = GETRELDEP(pool, dep);
+      if (rd->flags == REL_COND)
+       {
+         int r1, r2;
+         if (ISRELDEP(rd->evr))
+           {
+             Reldep *rd2 = GETRELDEP(pool, rd->evr);
+             if (rd2->flags == REL_ELSE)
+               {
+                 r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->name);
+                 if (r1)
+                   {
+                     r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
+                     return r2 && r1 == 2 ? 2 : r2;
+                   }
+                 return solver_dep_fulfilled_alreadyinstalled(solv, rd2->evr);
+               }
+           }
+         r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
+         r2 = !solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
+         if (!r1 && !r2)
+           return 0;
+          return r1 == 2 ? 2 : 1;
+       }
+      if (rd->flags == REL_UNLESS)
+       {
+         int r1, r2;
+         if (ISRELDEP(rd->evr))
+           {
+             Reldep *rd2 = GETRELDEP(pool, rd->evr);
+             if (rd2->flags == REL_ELSE)
+               {
+                 r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->name);
+                 if (r1)
+                   {
+                     r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->evr);
+                     return r2 && r1 == 2 ? 2 : r2;
+                   }
+                 return solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
+               }
+           }
+         /* A AND NOT(B) */
+         r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
+         r2 = !solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
+         if (!r1 || !r2)
+           return 0;
+          return r1 == 2 ? 2 : 1;
+       }
+      if (rd->flags == REL_AND)
+        {
+         int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
+          if (!r1)
+            return 0;
+         r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
+         if (!r2)
+           return 0;
+          return r1 == 2 || r2 == 2 ? 2 : 1;
+        }
+      if (rd->flags == REL_OR)
+       {
+         int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
+         r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
+         if (!r1 && !r2)
+           return 0;
+          return r1 == 2 || r2 == 2 ? 2 : 1;
+       }
+      if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
+        return solver_splitprovides(solv, rd->evr, 0) ? 2 : 0;
+      if (rd->flags == REL_NAMESPACE && solv->installsuppdepq)
+       {
+         Queue *q = solv->installsuppdepq;
+         int i;
+         for (i = 0; i < q->count; i++)
+           if (q->elements[i] == dep || q->elements[i] == rd->name)
+             return 2;
+       }
+    }
+  r = 0;
+  FOR_PROVIDES(p, pp, dep)
+    if (solv->decisionmap[p] > 0)
+      {
+       Solvable *s = pool->solvables + p;
+       if (s->repo && s->repo != solv->installed)
+         return 2;
+        r = 1;
+      }
+  return r;
+}
+
+int
+solver_is_supplementing_alreadyinstalled(Solver *solv, Solvable *s)
+{
+  Id sup, *supp;
+  supp = s->repo->idarraydata + s->supplements;
+  while ((sup = *supp++) != 0)
+    if (solver_dep_fulfilled_alreadyinstalled(solv, sup) == 2)
+      return 1;
+  return 0;
+}
+/*
+ * add all installed packages that package p obsoletes to Queue q.
+ * Package p is not installed. Also, we know that if
+ * solv->keepexplicitobsoletes is not set, p is not in the multiversion map.
+ * Entries may get added multiple times.
+ */
+static void
+solver_add_obsoleted(Solver *solv, Id p, Queue *q)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  Id p2, pp2;
+  Solvable *s = pool->solvables + p;
+  Id obs, *obsp;
+  Id lastp2 = 0;
+
+  if (!solv->keepexplicitobsoletes || !(solv->multiversion.size && MAPTST(&solv->multiversion, p)))
+    {
+      FOR_PROVIDES(p2, pp2, s->name)
+        {
+          Solvable *ps = pool->solvables + p2;
+          if (ps->repo != installed)
+            continue;
+          if (!pool->implicitobsoleteusesprovides && ps->name != s->name)
+            continue;
+          if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
+            continue;
+          queue_push(q, p2);
+          lastp2 = p2;
+        }
+    }
+  if (!s->obsoletes)
+    return;
+  obsp = s->repo->idarraydata + s->obsoletes;
+  while ((obs = *obsp++) != 0)
+    FOR_PROVIDES(p2, pp2, obs)
+      {
+        Solvable *ps = pool->solvables + p2;
+        if (ps->repo != installed)
+          continue;
+        if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
+          continue;
+        if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
+          continue;
+        if (p2 == lastp2)
+          continue;
+        queue_push(q, p2);
+        lastp2 = p2;
+      }
+}
+
+/*
+ * Call solver_add_obsoleted and intersect the result with the
+ * elements in Queue q starting at qstart.
+ * Assumes that it's the first call if qstart == q->count.
+ * May use auxillary map m for the intersection process, all
+ * elements of q starting at qstart must have their bit cleared.
+ * (This is also true after the function returns.)
+ * (See solver_add_obsoleted for limitations of the package p)
+ */
+void
+solver_intersect_obsoleted(Solver *solv, Id p, Queue *q, int qstart, Map *m)
+{
+  int i, j;
+  int qcount = q->count;
+
+  solver_add_obsoleted(solv, p, q);
+  if (qcount == qstart)
+    return;     /* first call */
+  if (qcount == q->count)
+    j = qstart;
+  else if (qcount == qstart + 1)
+    {
+      /* easy if there's just one element */
+      j = qstart;
+      for (i = qcount; i < q->count; i++)
+        if (q->elements[i] == q->elements[qstart])
+          {
+            j++;        /* keep the element */
+            break;
+          }
+    }
+  else if (!m->size && q->count - qstart <= 8)
+    {
+      /* faster than a map most of the time */
+      int k;
+      for (i = j = qstart; i < qcount; i++)
+        {
+          Id ip = q->elements[i];
+          for (k = qcount; k < q->count; k++)
+            if (q->elements[k] == ip)
+              {
+                q->elements[j++] = ip;
+                break;
+              }
+        }
+    }
+  else
+    {
+      /* for the really pathologic cases we use the map */
+      Repo *installed = solv->installed;
+      if (!m->size)
+        map_init(m, installed->end - installed->start);
+      for (i = qcount; i < q->count; i++)
+        MAPSET(m, q->elements[i] - installed->start);
+      for (i = j = qstart; i < qcount; i++)
+        if (MAPTST(m, q->elements[i] - installed->start))
+          {
+            MAPCLR(m, q->elements[i] - installed->start);
+            q->elements[j++] = q->elements[i];
+          }
+    }
+  queue_truncate(q, j);
+}
+