version.cc 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: version.cc,v 1.8 1998/12/05 01:44:57 jgg Exp $
  4. /* ######################################################################
  5. Version - Version string
  6. Version comparing is done using the == and < operators. STL's
  7. function.h provides the remaining set of comparitors. A directly
  8. callable non-string class version is provided for functions manipulating
  9. the cache file (esp the sort function).
  10. A version is defined to be equal if a case sensitive compare returns
  11. that the two strings are the same. For compatibility with the QSort
  12. function this version returns -1,0,1.
  13. ##################################################################### */
  14. /*}}}*/
  15. // Include Files /*{{{*/
  16. #ifdef __GNUG__
  17. #pragma implementation "apt-pkg/version.h"
  18. #endif
  19. #include <apt-pkg/version.h>
  20. #include <apt-pkg/pkgcache.h>
  21. #include <stdlib.h>
  22. /*}}}*/
  23. // StrToLong - Convert the string between two iterators to a long /*{{{*/
  24. // ---------------------------------------------------------------------
  25. /* */
  26. static unsigned long StrToLong(const char *begin,const char *end)
  27. {
  28. char S[40];
  29. char *I = S;
  30. for (; begin != end && I < S + 40;)
  31. *I++ = *begin++;
  32. *I = 0;
  33. return strtoul(S,0,10);
  34. }
  35. /*}}}*/
  36. // VersionCompare (op) - Greater than comparison for versions /*{{{*/
  37. // ---------------------------------------------------------------------
  38. /* */
  39. int pkgVersionCompare(const char *A, const char *B)
  40. {
  41. return pkgVersionCompare(A,A + strlen(A),B,B + strlen(B));
  42. }
  43. int pkgVersionCompare(string A,string B)
  44. {
  45. return pkgVersionCompare(A.begin(),A.end(),B.begin(),B.end());
  46. }
  47. /*}}}*/
  48. // iVersionCompare - Compare versions /*{{{*/
  49. // ---------------------------------------------------------------------
  50. /* This compares a fragment of the version. */
  51. static int iVersionCompare(const char *A, const char *AEnd, const char *B,
  52. const char *BEnd)
  53. {
  54. if (A >= AEnd && B >= BEnd)
  55. return 0;
  56. if (A >= AEnd)
  57. return -1;
  58. if (B >= BEnd)
  59. return 1;
  60. /* Iterate over the whole string
  61. What this does is to spilt the whole string into groups of
  62. numeric and non numeric portions. For instance:
  63. a67bhgs89
  64. Has 4 portions 'a', '67', 'bhgs', '89'. A more normal:
  65. 2.7.2-linux-1
  66. Has '2', '.', '7', '.' ,'-linux-','1' */
  67. const char *lhs = A;
  68. const char *rhs = B;
  69. while (lhs != AEnd && rhs != BEnd)
  70. {
  71. // Starting points
  72. const char *Slhs = lhs;
  73. const char *Srhs = rhs;
  74. // Compute ending points were we have passed over the portion
  75. bool Digit = (isdigit(*lhs) > 0?true:false);
  76. for (;lhs != AEnd && (isdigit(*lhs) > 0?true:false) == Digit; lhs++);
  77. for (;rhs != BEnd && (isdigit(*rhs) > 0?true:false) == Digit; rhs++);
  78. if (Digit == true)
  79. {
  80. // If the lhs has a digit and the rhs does not then <
  81. if (rhs - Srhs == 0)
  82. return -1;
  83. // Generate integers from the strings.
  84. unsigned long Ilhs = StrToLong(Slhs,lhs);
  85. unsigned long Irhs = StrToLong(Srhs,rhs);
  86. if (Ilhs != Irhs)
  87. {
  88. if (Ilhs > Irhs)
  89. return 1;
  90. return -1;
  91. }
  92. }
  93. else
  94. {
  95. // They are equal length so do a straight text compare
  96. for (;Slhs != lhs && Srhs != rhs; Slhs++, Srhs++)
  97. {
  98. if (*Slhs != *Srhs)
  99. {
  100. /* We need to compare non alpha chars as higher than alpha
  101. chars (a < !) */
  102. int lc = *Slhs;
  103. int rc = *Srhs;
  104. if (isalpha(lc) == 0) lc += 256;
  105. if (isalpha(rc) == 0) rc += 256;
  106. if (lc > rc)
  107. return 1;
  108. return -1;
  109. }
  110. }
  111. // If the lhs is shorter than the right it is 'less'
  112. if (lhs - Slhs < rhs - Srhs)
  113. return -1;
  114. // If the lhs is longer than the right it is 'more'
  115. if (lhs - Slhs > rhs - Srhs)
  116. return 1;
  117. }
  118. }
  119. // The strings must be equal
  120. if (lhs == AEnd && rhs == BEnd)
  121. return 0;
  122. // lhs is shorter
  123. if (lhs == AEnd)
  124. return -1;
  125. // rhs is shorter
  126. if (rhs == BEnd)
  127. return 1;
  128. // Shouldnt happen
  129. return 1;
  130. }
  131. /*}}}*/
  132. // VersionCompare - Comparison for versions /*{{{*/
  133. // ---------------------------------------------------------------------
  134. /* This fragments the version into E:V-R triples and compares each
  135. portion seperately. */
  136. int pkgVersionCompare(const char *A, const char *AEnd, const char *B,
  137. const char *BEnd)
  138. {
  139. // Strip off the epoch and compare it
  140. const char *lhs = A;
  141. const char *rhs = B;
  142. for (;lhs != AEnd && *lhs != ':'; lhs++);
  143. for (;rhs != BEnd && *rhs != ':'; rhs++);
  144. if (lhs == AEnd)
  145. lhs = A;
  146. if (rhs == BEnd)
  147. rhs = B;
  148. // Compare the epoch
  149. int Res = iVersionCompare(A,lhs,B,rhs);
  150. if (Res != 0)
  151. return Res;
  152. // Skip the :
  153. if (lhs != A)
  154. lhs++;
  155. if (rhs != B)
  156. rhs++;
  157. // Find the last -
  158. const char *dlhs = AEnd-1;
  159. const char *drhs = BEnd-1;
  160. for (;dlhs > lhs && *dlhs != '-'; dlhs--);
  161. for (;drhs > rhs && *drhs != '-'; drhs--);
  162. if (dlhs == lhs)
  163. dlhs = AEnd;
  164. if (drhs == rhs)
  165. drhs = BEnd;
  166. // Compare the main version
  167. Res = iVersionCompare(lhs,dlhs,rhs,drhs);
  168. if (Res != 0)
  169. return Res;
  170. // Skip the -
  171. if (dlhs != lhs)
  172. dlhs++;
  173. if (drhs != rhs)
  174. drhs++;
  175. return iVersionCompare(dlhs,AEnd,drhs,BEnd);
  176. }
  177. /*}}}*/
  178. // CheckDep - Check a single dependency /*{{{*/
  179. // ---------------------------------------------------------------------
  180. /* This simply preforms the version comparison and switch based on
  181. operator. */
  182. bool pkgCheckDep(const char *DepVer,const char *PkgVer,int Op)
  183. {
  184. if (DepVer == 0)
  185. return true;
  186. if (PkgVer == 0)
  187. return false;
  188. // Perform the actuall comparision.
  189. int Res = pkgVersionCompare(PkgVer,DepVer);
  190. switch (Op & 0x0F)
  191. {
  192. case pkgCache::Dep::LessEq:
  193. if (Res <= 0)
  194. return true;
  195. break;
  196. case pkgCache::Dep::GreaterEq:
  197. if (Res >= 0)
  198. return true;
  199. break;
  200. case pkgCache::Dep::Less:
  201. if (Res < 0)
  202. return true;
  203. break;
  204. case pkgCache::Dep::Greater:
  205. if (Res > 0)
  206. return true;
  207. break;
  208. case pkgCache::Dep::Equals:
  209. if (Res == 0)
  210. return true;
  211. break;
  212. case pkgCache::Dep::NotEquals:
  213. if (Res != 0)
  214. return true;
  215. break;
  216. }
  217. return false;
  218. }
  219. /*}}}*/