summaryrefslogtreecommitdiffstats
path: root/apt-pkg/deb/debversion.cc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--apt-pkg/deb/debversion.cc279
1 files changed, 279 insertions, 0 deletions
diff --git a/apt-pkg/deb/debversion.cc b/apt-pkg/deb/debversion.cc
new file mode 100644
index 0000000..ec7c953
--- /dev/null
+++ b/apt-pkg/deb/debversion.cc
@@ -0,0 +1,279 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+/* ######################################################################
+
+ Debian Version - Versioning system for Debian
+
+ This implements the standard Debian versioning system.
+
+ ##################################################################### */
+ /*}}}*/
+// Include Files /*{{{*/
+#include <config.h>
+
+#include <apt-pkg/debversion.h>
+#include <apt-pkg/pkgcache.h>
+
+#include <cctype>
+#include <cstdlib>
+#include <cstring>
+ /*}}}*/
+
+debVersioningSystem debVS;
+
+// debVS::debVersioningSystem - Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+debVersioningSystem::debVersioningSystem()
+{
+ Label = "Standard .deb";
+}
+ /*}}}*/
+
+// debVS::CmpFragment - Compare versions /*{{{*/
+// ---------------------------------------------------------------------
+/* This compares a fragment of the version. This is a slightly adapted
+ version of what dpkg uses in dpkg/lib/dpkg/version.c.
+ In particular, the a | b = NULL check is removed as we check this in the
+ caller, we use an explicit end for a | b strings and we check ~ explicit. */
+static int order(char c)
+{
+ if (isdigit(c))
+ return 0;
+ else if (isalpha_ascii(c))
+ return c;
+ else if (c == '~')
+ return -1;
+ else if (c)
+ return c + 256;
+ else
+ return 0;
+}
+int debVersioningSystem::CmpFragment(const char *A,const char *AEnd,
+ const char *B,const char *BEnd)
+{
+ /* Iterate over the whole string
+ What this does is to split the whole string into groups of
+ numeric and non numeric portions. For instance:
+ a67bhgs89
+ Has 4 portions 'a', '67', 'bhgs', '89'. A more normal:
+ 2.7.2-linux-1
+ Has '2', '.', '7', '.' ,'-linux-','1' */
+ const char *lhs = A;
+ const char *rhs = B;
+ while (lhs != AEnd && rhs != BEnd)
+ {
+ int first_diff = 0;
+
+ while (lhs != AEnd && rhs != BEnd &&
+ (!isdigit(*lhs) || !isdigit(*rhs)))
+ {
+ int vc = order(*lhs);
+ int rc = order(*rhs);
+ if (vc != rc)
+ return vc - rc;
+ ++lhs; ++rhs;
+ }
+
+ while (*lhs == '0')
+ ++lhs;
+ while (*rhs == '0')
+ ++rhs;
+ while (isdigit(*lhs) && isdigit(*rhs))
+ {
+ if (!first_diff)
+ first_diff = *lhs - *rhs;
+ ++lhs;
+ ++rhs;
+ }
+
+ if (isdigit(*lhs))
+ return 1;
+ if (isdigit(*rhs))
+ return -1;
+ if (first_diff)
+ return first_diff;
+ }
+
+ // The strings must be equal
+ if (lhs == AEnd && rhs == BEnd)
+ return 0;
+
+ // lhs is shorter
+ if (lhs == AEnd)
+ {
+ if (*rhs == '~') return 1;
+ return -1;
+ }
+
+ // rhs is shorter
+ if (rhs == BEnd)
+ {
+ if (*lhs == '~') return -1;
+ return 1;
+ }
+
+ // Shouldn't happen
+ return 1;
+}
+ /*}}}*/
+// debVS::CmpVersion - Comparison for versions /*{{{*/
+// ---------------------------------------------------------------------
+/* This fragments the version into E:V-R triples and compares each
+ portion separately. */
+int debVersioningSystem::DoCmpVersion(const char *A,const char *AEnd,
+ const char *B,const char *BEnd)
+{
+ // Strip off the epoch and compare it
+ const char *lhs = (const char*) memchr(A, ':', AEnd - A);
+ const char *rhs = (const char*) memchr(B, ':', BEnd - B);
+ if (lhs == NULL)
+ lhs = A;
+ if (rhs == NULL)
+ rhs = B;
+
+ // Special case: a zero epoch is the same as no epoch,
+ // so remove it.
+ if (lhs != A)
+ {
+ for (; *A == '0'; ++A);
+ if (A == lhs)
+ {
+ ++A;
+ ++lhs;
+ }
+ }
+ if (rhs != B)
+ {
+ for (; *B == '0'; ++B);
+ if (B == rhs)
+ {
+ ++B;
+ ++rhs;
+ }
+ }
+
+ // Compare the epoch
+ int Res = CmpFragment(A,lhs,B,rhs);
+ if (Res != 0)
+ return Res;
+
+ // Skip the :
+ if (lhs != A)
+ lhs++;
+ if (rhs != B)
+ rhs++;
+
+ // Find the last -
+ const char *dlhs = (const char*) memrchr(lhs, '-', AEnd - lhs);
+ const char *drhs = (const char*) memrchr(rhs, '-', BEnd - rhs);
+ if (dlhs == NULL)
+ dlhs = AEnd;
+ if (drhs == NULL)
+ drhs = BEnd;
+
+ // Compare the main version
+ Res = CmpFragment(lhs,dlhs,rhs,drhs);
+ if (Res != 0)
+ return Res;
+
+ // Skip the -
+ if (dlhs != lhs)
+ dlhs++;
+ if (drhs != rhs)
+ drhs++;
+
+ // no debian revision need to be treated like -0
+ if (*(dlhs-1) == '-' && *(drhs-1) == '-')
+ return CmpFragment(dlhs,AEnd,drhs,BEnd);
+ else if (*(dlhs-1) == '-')
+ {
+ const char* null = "0";
+ return CmpFragment(dlhs,AEnd,null, null+1);
+ }
+ else if (*(drhs-1) == '-')
+ {
+ const char* null = "0";
+ return CmpFragment(null, null+1, drhs, BEnd);
+ }
+ else
+ return 0;
+}
+ /*}}}*/
+// debVS::CheckDep - Check a single dependency /*{{{*/
+// ---------------------------------------------------------------------
+/* This simply performs the version comparison and switch based on
+ operator. If DepVer is 0 then we are comparing against a provides
+ with no version. */
+bool debVersioningSystem::CheckDep(const char *PkgVer,
+ int Op,const char *DepVer)
+{
+ if (DepVer == 0 || DepVer[0] == 0)
+ return true;
+ if (PkgVer == 0 || PkgVer[0] == 0)
+ return false;
+ Op &= 0x0F;
+
+ // fast track for (equal) strings [by location] which are by definition equal versions
+ if (PkgVer == DepVer)
+ return Op == pkgCache::Dep::Equals || Op == pkgCache::Dep::LessEq || Op == pkgCache::Dep::GreaterEq;
+
+ // Perform the actual comparison.
+ int const Res = CmpVersion(PkgVer, DepVer);
+ switch (Op)
+ {
+ case pkgCache::Dep::LessEq:
+ if (Res <= 0)
+ return true;
+ break;
+
+ case pkgCache::Dep::GreaterEq:
+ if (Res >= 0)
+ return true;
+ break;
+
+ case pkgCache::Dep::Less:
+ if (Res < 0)
+ return true;
+ break;
+
+ case pkgCache::Dep::Greater:
+ if (Res > 0)
+ return true;
+ break;
+
+ case pkgCache::Dep::Equals:
+ if (Res == 0)
+ return true;
+ break;
+
+ case pkgCache::Dep::NotEquals:
+ if (Res != 0)
+ return true;
+ break;
+ }
+
+ return false;
+}
+ /*}}}*/
+// debVS::UpstreamVersion - Return the upstream version string /*{{{*/
+// ---------------------------------------------------------------------
+/* This strips all the debian specific information from the version number */
+std::string debVersioningSystem::UpstreamVersion(const char *Ver)
+{
+ // Strip off the bit before the first colon
+ const char *I = Ver;
+ for (; *I != 0 && *I != ':'; I++);
+ if (*I == ':')
+ Ver = I + 1;
+
+ // Chop off the trailing -
+ I = Ver;
+ unsigned Last = strlen(Ver);
+ for (; *I != 0; I++)
+ if (*I == '-')
+ Last = I - Ver;
+
+ return std::string(Ver,Last);
+}
+ /*}}}*/