]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/deb/debversion.cc
properly implement pkgRecord::Parser for *.deb files
[apt.git] / apt-pkg / deb / debversion.cc
index 17281425be816aedc9b180b37c93570bf0500730..a5eacb7f50f2a9f0ae1876906b598d743f1d33c3 100644 (file)
@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: debversion.cc,v 1.3 2001/05/07 05:14:53 jgg Exp $
+// $Id: debversion.cc,v 1.8 2003/09/10 23:39:49 mdz Exp $
 /* ######################################################################
 
    Debian Version - Versioning system for Debian
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
-#define APT_COMPATIBILITY 986
-#ifdef __GNUG__
-#pragma implementation "apt-pkg/debversion.h"
-#endif
+#include <config.h>
 
 #include <apt-pkg/debversion.h>
 #include <apt-pkg/pkgcache.h>
 
+#include <string.h>
+#include <string>
 #include <stdlib.h>
 #include <ctype.h>
                                                                        /*}}}*/
@@ -32,35 +31,34 @@ debVersioningSystem::debVersioningSystem()
    Label = "Standard .deb";
 }
                                                                        /*}}}*/
-// StrToLong - Convert the string between two iterators to a long      /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-static unsigned long StrToLong(const char *begin,const char *end)
-{
-   char S[40];
-   char *I = S;
-   for (; begin != end && I < S + 40;)
-      *I++ = *begin++;
-   *I = 0;
-   return strtoul(S,0,10);
-}
-                                                                       /*}}}*/
+
 // debVS::CmpFragment - Compare versions                               /*{{{*/
 // ---------------------------------------------------------------------
-/* This compares a fragment of the version. Dpkg has a really short 
-   version of this, but it is uh.. interesting to grok. */
-int debVersioningSystem::CmpFragment(const char *A,const char *AEnd, 
+/* This compares a fragment of the version. This is a slightly adapted 
+   version of what dpkg uses. */
+#define order(x) ((x) == '~' ? -1    \
+               : isdigit((x)) ? 0   \
+               : !(x) ? 0           \
+               : isalpha((x)) ? (x) \
+               : (x) + 256)
+int debVersioningSystem::CmpFragment(const char *A,const char *AEnd,
                                     const char *B,const char *BEnd)
 {
    if (A >= AEnd && B >= BEnd)
       return 0;
    if (A >= AEnd)
+   {
+      if (*B == '~') return 1;
       return -1;
+   }
    if (B >= BEnd)
+   {
+      if (*A == '~') return -1;
       return 1;
-   
+   }
+
    /* Iterate over the whole string
-      What this does is to spilt the whole string into groups of 
+      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:
@@ -70,58 +68,36 @@ int debVersioningSystem::CmpFragment(const char *A,const char *AEnd,
    const char *rhs = B;
    while (lhs != AEnd && rhs != BEnd)
    {
-      // Starting points
-      const char *Slhs = lhs;
-      const char *Srhs = rhs;
-      
-      // Compute ending points were we have passed over the portion
-      bool Digit = (isdigit(*lhs) > 0?true:false);
-      for (;lhs != AEnd && (isdigit(*lhs) > 0?true:false) == Digit; lhs++);
-      for (;rhs != BEnd && (isdigit(*rhs) > 0?true:false) == Digit; rhs++);
-      
-      if (Digit == true)
+      int first_diff = 0;
+
+      while (lhs != AEnd && rhs != BEnd &&
+            (!isdigit(*lhs) || !isdigit(*rhs)))
       {
-        // If the lhs has a digit and the rhs does not then <
-        if (rhs - Srhs == 0)
-           return -1;
-        
-        // Generate integers from the strings.
-        unsigned long Ilhs = StrToLong(Slhs,lhs);
-        unsigned long Irhs = StrToLong(Srhs,rhs);
-        if (Ilhs != Irhs)
-        {
-           if (Ilhs > Irhs)
-              return 1;
-           return -1;
-        }
+        int vc = order(*lhs);
+        int rc = order(*rhs);
+        if (vc != rc)
+           return vc - rc;
+        lhs++; rhs++;
       }
-      else
-      {
-        // They are equal length so do a straight text compare
-        for (;Slhs != lhs && Srhs != rhs; Slhs++, Srhs++)
-        {
-           if (*Slhs != *Srhs)
-           {
-              /* We need to compare non alpha chars as higher than alpha
-                 chars (a < !) */
-              int lc = *Slhs;
-              int rc = *Srhs;
-              if (isalpha(lc) == 0) lc += 256;
-              if (isalpha(rc) == 0) rc += 256;
-              if (lc > rc)
-                 return 1;
-              return -1;
-           }
-        }
 
-        // If the lhs is shorter than the right it is 'less'
-        if (lhs - Slhs < rhs - Srhs)
-           return -1;
+      while (*lhs == '0')
+        lhs++;
+      while (*rhs == '0')
+        rhs++;
+      while (isdigit(*lhs) && isdigit(*rhs))
+      {
+        if (!first_diff)
+           first_diff = *lhs - *rhs;
+        lhs++;
+        rhs++;
+      }
 
-        // If the lhs is longer than the right it is 'more'
-        if (lhs - Slhs > rhs - Srhs)
-           return 1;            
-      }      
+      if (isdigit(*lhs))
+        return 1;
+      if (isdigit(*rhs))
+        return -1;
+      if (first_diff)
+        return first_diff;
    }
 
    // The strings must be equal
@@ -130,13 +106,19 @@ int debVersioningSystem::CmpFragment(const char *A,const char *AEnd,
 
    // lhs is shorter
    if (lhs == AEnd)
+   {
+      if (*rhs == '~') return 1;
       return -1;
+   }
 
    // rhs is shorter
    if (rhs == BEnd)
+   {
+      if (*lhs == '~') return -1;
       return 1;
-       
-   // Shouldnt happen
+   }
+
+   // Shouldn't happen
    return 1;
 }
                                                                        /*}}}*/
@@ -147,16 +129,35 @@ int debVersioningSystem::CmpFragment(const char *A,const char *AEnd,
 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 = A;
-   const char *rhs = B;
-   for (;lhs != AEnd && *lhs != ':'; lhs++);
-   for (;rhs != BEnd && *rhs != ':'; rhs++);
-   if (lhs == AEnd)
+   // 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 == BEnd)
+   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)
@@ -168,15 +169,12 @@ int debVersioningSystem::DoCmpVersion(const char *A,const char *AEnd,
    if (rhs != B)
       rhs++;
    
-   // Find the last - 
-   const char *dlhs = AEnd-1;
-   const char *drhs = BEnd-1;
-   for (;dlhs > lhs && *dlhs != '-'; dlhs--);
-   for (;drhs > rhs && *drhs != '-'; drhs--);
-
-   if (dlhs == lhs)
+   // 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 == rhs)
+   if (drhs == NULL)
       drhs = BEnd;
    
    // Compare the main version
@@ -189,8 +187,22 @@ int debVersioningSystem::DoCmpVersion(const char *A,const char *AEnd,
       dlhs++;
    if (drhs != rhs)
       drhs++;
-   
-   return CmpFragment(dlhs,AEnd,drhs,BEnd);
+
+   // 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                         /*{{{*/
@@ -205,10 +217,15 @@ bool debVersioningSystem::CheckDep(const char *PkgVer,
       return true;
    if (PkgVer == 0 || PkgVer[0] == 0)
       return false;
-   
-   // Perform the actual comparision.
-   int Res = CmpVersion(PkgVer,DepVer);
-   switch (Op & 0x0F)
+   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)
@@ -247,7 +264,7 @@ bool debVersioningSystem::CheckDep(const char *PkgVer,
 // debVS::UpstreamVersion - Return the upstream version string         /*{{{*/
 // ---------------------------------------------------------------------
 /* This strips all the debian specific information from the version number */
-string debVersioningSystem::UpstreamVersion(const char *Ver)
+std::string debVersioningSystem::UpstreamVersion(const char *Ver)
 {
    // Strip off the bit before the first colon
    const char *I = Ver;
@@ -262,6 +279,6 @@ string debVersioningSystem::UpstreamVersion(const char *Ver)
       if (*I == '-')
         Last = I - Ver;
    
-   return string(Ver,Last);
+   return std::string(Ver,Last);
 }
                                                                        /*}}}*/