94df084ec5
Before this patch, strcmp(3) would be used to select the best package. This was sometimes counter-intuitive (for example, APT would choose autoconf_2.5 over autoconf_2.13). [NB: fixing this can break some packages that rely on the historic sort order; e.g. postgresql74 may be preferred to postgresql8.2.] We considered using rpmvercmp() for package name comparison, but chose to write a specially-crafted function that's mostly compatible with strcmp(3), except for numeric fragments in the names. As a matter of fact, strtoull usage is suboptimal here. It may overflow the returned long long, leading to an incorrect comparison. Fixing the code to avoid strtoull is, however, left as an exercise to the diligent maintenance programmer (and you are insane anyway if you need package names that trigger the overflow).
44 lines
1.4 KiB
Diff
44 lines
1.4 KiB
Diff
diff --git a/apt/apt-pkg/algorithms.cc b/apt/apt-pkg/algorithms.cc
|
|
index e8abff2..a5bf5ca 100644
|
|
--- a/apt/apt-pkg/algorithms.cc
|
|
+++ b/apt/apt-pkg/algorithms.cc
|
|
@@ -1402,6 +1402,27 @@ bool pkgProblemResolver::RemoveDepends()
|
|
return true;
|
|
}
|
|
/*}}}*/
|
|
+/* Like strcmp, but compares digit sections by number value.
|
|
+ * E.g.: tar-1.10 > tar-1.9 > tar-1.1a
|
|
+ * (while strcmp gives tar-1.10 < tar-1.9). */
|
|
+static int nameCompare(const char* n1, const char* n2)
|
|
+{
|
|
+ while(*n1 && *n2) {
|
|
+ if(isdigit(*n1) && isdigit(*n2)) {
|
|
+ unsigned long long i1, i2;
|
|
+ i1 = strtoull(n1, const_cast<char **>(&n1), 10);
|
|
+ i2 = strtoull(n2, const_cast<char **>(&n2), 10);
|
|
+ if(i1 != i2)
|
|
+ return (i1 > i2) ? 1 : -1;
|
|
+ } else if(*n1 != *n2) {
|
|
+ return (*n1 > *n2) ? 1 : -1;
|
|
+ } else {
|
|
+ n1++;
|
|
+ n2++;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
|
|
// PrioSortList - Sort a list of versions by priority /*{{{*/
|
|
// ---------------------------------------------------------------------
|
|
@@ -1423,7 +1444,9 @@ static int PrioComp(const void *A,const void *B)
|
|
|
|
if (L->Priority != R->Priority)
|
|
return L->Priority - R->Priority;
|
|
- return strcmp(L.ParentPkg().Name(),R.ParentPkg().Name());
|
|
+ // PrioComp("gcc2","gcc3") == 1
|
|
+ // PrioComp("gcc2", gcc10") == 1
|
|
+ return nameCompare(R.ParentPkg().Name(),L.ParentPkg().Name());
|
|
}
|
|
void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List)
|
|
{
|