+ for (i = 0; i < 2; i++)
+ {
+ s = pool->solvables + plist->elements[i];
+ other = plist->elements[1 - i];
+ if (s->obsoletes)
+ {
+ obsp = s->repo->idarraydata + s->obsoletes;
+ while ((obs = *obsp++) != 0)
+ {
+ FOR_PROVIDES(p, pp, obs)
+ {
+ Solvable *ps;
+ if (p != other)
+ continue;
+ ps = pool->solvables + p;
+ if (ps->name == s->name)
+ continue;
+ if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
+ continue;
+ if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
+ continue;
+ obmap |= 1 << i;
+ break;
+ }
+ if (p)
+ break;
+ }
+ }
+ }
+ if (obmap == 0 || obmap == 3)
+ return;
+ if (obmap == 2)
+ plist->elements[0] = plist->elements[1];
+ plist->count = 1;
+}
+
+/*
+ * bring those elements to the front of the queue that
+ * have a installed solvable with the same name
+ */
+static void
+move_installed_to_front(Pool *pool, Queue *plist)
+{
+ int i, j;
+ Solvable *s;
+ Id p, pp;
+
+ for (i = j = 0; i < plist->count; i++)
+ {
+ s = pool->solvables + plist->elements[i];
+ if (s->repo != pool->installed)
+ {
+ FOR_PROVIDES(p, pp, s->name)
+ {
+ Solvable *ps = pool->solvables + p;
+ if (s->name == ps->name && ps->repo == pool->installed)
+ {
+ s = ps;
+ break;
+ }
+ }
+ }
+ if (s->repo == pool->installed)
+ {
+ if (i != j)
+ {
+ p = plist->elements[i];
+ if (i - j == 1)
+ plist->elements[i] = plist->elements[j];
+ else
+ memmove(plist->elements + j + 1, plist->elements + j, (i - j) * sizeof(Id));
+ plist->elements[j] = p;
+ }
+ else if (j + 2 == plist->count)
+ break; /* no need to check last element if all prev ones are installed */
+ j++;
+ }
+ }
+}
+
+/*
+ * prune_to_best_version
+ *
+ * sort list of packages (given through plist) by name and evr
+ * return result through plist
+ */
+void
+prune_to_best_version(Pool *pool, Queue *plist)
+{
+ int i, j, r;
+ Solvable *s, *best;
+
+ if (plist->count < 2) /* no need to prune for a single entry */
+ return;
+ POOL_DEBUG(SOLV_DEBUG_POLICY, "prune_to_best_version %d\n", plist->count);
+
+ /* sort by name first, prefer installed */
+ solv_sort(plist->elements, plist->count, sizeof(Id), prune_to_best_version_sortcmp, pool);
+
+ /* now find best 'per name' */
+ best = 0;
+ for (i = j = 0; i < plist->count; i++)
+ {
+ s = pool->solvables + plist->elements[i];
+
+ POOL_DEBUG(SOLV_DEBUG_POLICY, "- %s[%s]\n",
+ pool_solvable2str(pool, s),
+ (pool->installed && s->repo == pool->installed) ? "installed" : "not installed");
+
+ if (!best) /* if no best yet, the current is best */
+ {
+ best = s;
+ continue;
+ }
+
+ /* name switch: finish group, re-init */
+ if (best->name != s->name) /* new name */
+ {
+ plist->elements[j++] = best - pool->solvables; /* move old best to front */
+ best = s; /* take current as new best */
+ continue;
+ }
+ r = best->evr != s->evr ? pool_evrcmp(pool, best->evr, s->evr, EVRCMP_COMPARE) : 0;
+#ifdef ENABLE_LINKED_PKGS
+ if (r == 0 && has_package_link(pool, s))
+ r = pool_link_evrcmp(pool, best, s);
+#endif
+ if (r < 0)
+ best = s;
+ }
+ plist->elements[j++] = best - pool->solvables; /* finish last group */
+ plist->count = j;
+
+ /* we reduced the list to one package per name, now look at
+ * package obsoletes */
+ if (plist->count > 1)
+ {
+ if (plist->count == 2)
+ prune_obsoleted_2(pool, plist);
+ else
+ prune_obsoleted(pool, plist);
+ }
+ if (plist->count > 1 && pool->installed)
+ move_installed_to_front(pool, plist);
+}
+
+
+static int
+sort_by_name_evr_sortcmp(const void *ap, const void *bp, void *dp)
+{
+ Pool *pool = dp;
+ Id a, *aa = (Id *)ap;
+ Id b, *bb = (Id *)bp;
+ Id r = aa[1] - bb[1];
+ if (r)
+ return r < 0 ? -1 : 1;
+ if (aa[2] == bb[2])
+ return 0;
+ a = aa[2] < 0 ? -aa[2] : aa[2];
+ b = bb[2] < 0 ? -bb[2] : bb[2];
+ if (pool->disttype != DISTTYPE_DEB && a != b)
+ {
+ /* treat release-less versions different */
+ const char *as = pool_id2str(pool, a);
+ const char *bs = pool_id2str(pool, b);
+ if (strchr(as, '-'))
+ {
+ if (!strchr(bs, '-'))
+ return -2;
+ }
+ else
+ {
+ if (strchr(bs, '-'))
+ return 2;
+ }
+ }
+ r = pool_evrcmp(pool, b, a, EVRCMP_COMPARE);
+ if (!r && (aa[2] < 0 || bb[2] < 0))
+ {
+ if (bb[2] >= 0)
+ return 1;
+ if (aa[2] >= 0)
+ return -1;
+ }
+ if (r)
+ return r < 0 ? -1 : 1;
+ return 0;
+}
+
+/* common end of sort_by_srcversion and sort_by_common_dep */
+static void
+sort_by_name_evr_array(Pool *pool, Queue *plist, int count, int ent)
+{
+ Id lastname;
+ int i, j, bad, havebad;
+ Id *pp, *elements = plist->elements;
+
+ if (ent < 2)
+ {
+ queue_truncate(plist, count);
+ return;
+ }
+ solv_sort(elements + count * 2, ent, sizeof(Id) * 3, sort_by_name_evr_sortcmp, pool);
+ lastname = 0;
+ bad = havebad = 0;
+ for (i = 0, pp = elements + count * 2; i < ent; i++, pp += 3)
+ {
+ if (lastname && pp[1] == lastname)
+ {
+ if (pp[0] != pp[-3] && sort_by_name_evr_sortcmp(pp - 3, pp, pool) == -1)
+ {
+#if 0
+ printf("%s - %s: bad %s %s - %s\n", pool_solvid2str(pool, elements[pp[-3]]), pool_solvid2str(pool, elements[pp[0]]), pool_dep2str(pool, lastname), pool_id2str(pool, pp[-1] < 0 ? -pp[-1] : pp[-1]), pool_id2str(pool, pp[2] < 0 ? -pp[2] : pp[2]));
+#endif
+ bad++;
+ havebad = 1;
+ }
+ }
+ else
+ {
+ bad = 0;
+ lastname = pp[1];
+ }
+ elements[count + pp[0]] += bad;
+ }
+
+#if 0
+for (i = 0; i < count; i++)
+ printf("%s badness %d\n", pool_solvid2str(pool, elements[i]), elements[count + i]);
+#endif
+
+ if (havebad)
+ {
+ /* simple stable insertion sort */
+ if (pool->installed)
+ for (i = 0; i < count; i++)
+ if (pool->solvables[elements[i]].repo == pool->installed)
+ elements[i + count] = 0;
+ for (i = 1; i < count; i++)
+ for (j = i, pp = elements + count + j; j > 0; j--, pp--)
+ if (pp[-1] > pp[0])
+ {
+ Id *pp2 = pp - count;
+ Id p = pp[-1];
+ pp[-1] = pp[0];
+ pp[0] = p;
+ p = pp2[-1];
+ pp2[-1] = pp2[0];
+ pp2[0] = p;
+ }
+ else
+ break;
+ }
+ queue_truncate(plist, count);
+}
+
+#if 0
+static void
+sort_by_srcversion(Pool *pool, Queue *plist)
+{
+ int i, count = plist->count, ent = 0;
+ queue_insertn(plist, count, count, 0);
+ for (i = 0; i < count; i++)
+ {
+ Id name, evr, p = plist->elements[i];
+ Solvable *s = pool->solvables + p;
+ if (solvable_lookup_void(s, SOLVABLE_SOURCENAME))
+ name = s->name;
+ else
+ name = solvable_lookup_id(s, SOLVABLE_SOURCENAME);
+ if (solvable_lookup_void(s, SOLVABLE_SOURCEEVR))
+ evr = s->evr;
+ else
+ evr = solvable_lookup_id(s, SOLVABLE_SOURCEEVR);
+ if (!name || !evr || ISRELDEP(evr))
+ continue;
+ queue_push(plist, i);
+ queue_push2(plist, name, evr);
+ ent++;
+ }
+ sort_by_name_evr_array(pool, plist, count, ent);
+}
+#endif
+
+static void
+sort_by_common_dep(Pool *pool, Queue *plist)
+{
+ int i, count = plist->count, ent = 0;
+ Id id, *dp;
+ queue_insertn(plist, count, count, 0);
+ for (i = 0; i < count; i++)
+ {
+ Id p = plist->elements[i];
+ Solvable *s = pool->solvables + p;
+ if (!s->provides)
+ continue;
+ for (dp = s->repo->idarraydata + s->provides; (id = *dp++) != 0; )
+ {
+ Reldep *rd;
+ if (!ISRELDEP(id))
+ continue;
+ rd = GETRELDEP(pool, id);
+ if ((rd->flags == REL_EQ || rd->flags == (REL_EQ | REL_LT) || rd->flags == REL_LT) && !ISRELDEP(rd->evr))
+ {
+ if (rd->flags == REL_EQ)
+ {
+ /* ignore hashes */
+ const char *s = pool_id2str(pool, rd->evr);
+ if (strlen(s) >= 4)
+ {
+ while ((*s >= 'a' && *s <= 'f') || (*s >= '0' && *s <= '9'))
+ s++;
+ if (!*s)
+ continue;
+ }
+ }
+ queue_push(plist, i);
+ queue_push2(plist, rd->name, rd->flags == REL_LT ? -rd->evr : rd->evr);
+ ent++;
+ }
+ }
+ }
+ sort_by_name_evr_array(pool, plist, count, ent);
+}
+
+/* check if we have an update candidate */
+static void
+dislike_old_versions(Pool *pool, Queue *plist)
+{
+ int i, count;
+
+ for (i = 0, count = plist->count; i < count; i++)
+ {
+ Id p = plist->elements[i];
+ Solvable *s = pool->solvables + p;
+ Repo *repo = s->repo;
+ Id q, qq;
+ int bad = 0;
+
+ if (!repo || repo == pool->installed)
+ continue;
+ FOR_PROVIDES(q, qq, s->name)
+ {
+ Solvable *qs = pool->solvables + q;
+ if (q == p)
+ continue;
+ if (s->name != qs->name || s->arch != qs->arch)
+ continue;
+ if (repo->priority != qs->repo->priority)
+ {
+ if (repo->priority > qs->repo->priority)
+ continue;
+ bad = 1;
+ break;
+ }
+ if (pool_evrcmp(pool, qs->evr, s->evr, EVRCMP_COMPARE) > 0)
+ {
+ bad = 1;
+ break;
+ }
+ }
+ if (!bad)
+ continue;
+ /* bring to back */
+ if (i < plist->count - 1)
+ {
+ memmove(plist->elements + i, plist->elements + i + 1, (plist->count - 1 - i) * sizeof(Id));
+ plist->elements[plist->count - 1] = p;
+ }
+ i--;
+ count--;
+ }
+}