version.cc 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: version.cc,v 1.7 1998/11/28 20:50:24 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. // cout << string(A,AEnd) << ',' << string(B,BEnd) << endl;
  55. if (A >= AEnd && B >= BEnd)
  56. return 0;
  57. if (A >= AEnd)
  58. return -1;
  59. if (B >= BEnd)
  60. return 1;
  61. /* Iterate over the whole string
  62. What this does is to spilt the whole string into groups of
  63. numeric and non numeric portions. For instance:
  64. a67bhgs89
  65. Has 4 portions 'a', '67', 'bhgs', '89'. A more normal:
  66. 2.7.2-linux-1
  67. Has '2', '.', '7', '.' ,'-linux-','1' */
  68. const char *lhs = A;
  69. const char *rhs = B;
  70. while (lhs != AEnd && rhs != BEnd)
  71. {
  72. // Starting points
  73. const char *Slhs = lhs;
  74. const char *Srhs = rhs;
  75. // Compute ending points were we have passed over the portion
  76. bool Digit = (isdigit(*lhs) > 0?true:false);
  77. for (;lhs != AEnd && (isdigit(*lhs) > 0?true:false) == Digit; lhs++);
  78. for (;rhs != BEnd && (isdigit(*rhs) > 0?true:false) == Digit; rhs++);
  79. if (Digit == true)
  80. {
  81. // If the lhs has a digit and the rhs does not then <
  82. if (rhs - Srhs == 0)
  83. return -1;
  84. // Generate integers from the strings.
  85. unsigned long Ilhs = StrToLong(Slhs,lhs);
  86. unsigned long Irhs = StrToLong(Srhs,rhs);
  87. if (Ilhs != Irhs)
  88. {
  89. if (Ilhs > Irhs)
  90. return 1;
  91. return -1;
  92. }
  93. }
  94. else
  95. {
  96. // They are equal length so do a straight text compare
  97. for (;Slhs != lhs && Srhs != rhs; Slhs++, Srhs++)
  98. {
  99. if (*Slhs != *Srhs)
  100. {
  101. /* We need to compare non alpha chars as higher than alpha
  102. chars (a < !) */
  103. int lc = *Slhs;
  104. int rc = *Srhs;
  105. if (isalpha(lc) == 0) lc += 256;
  106. if (isalpha(rc) == 0) rc += 256;
  107. if (lc > rc)
  108. return 1;
  109. return -1;
  110. }
  111. }
  112. // If the lhs is shorter than the right it is 'less'
  113. if (lhs - Slhs < rhs - Srhs)
  114. return -1;
  115. // If the lhs is longer than the right it is 'more'
  116. if (lhs - Slhs > rhs - Srhs)
  117. return 1;
  118. }
  119. }
  120. // The strings must be equal
  121. if (lhs == AEnd && rhs == BEnd)
  122. return 0;
  123. // lhs is shorter
  124. if (lhs == AEnd)
  125. return -1;
  126. // rhs is shorter
  127. if (rhs == BEnd)
  128. return 1;
  129. // Shouldnt happen
  130. return 1;
  131. }
  132. /*}}}*/
  133. // VersionCompare - Comparison for versions /*{{{*/
  134. // ---------------------------------------------------------------------
  135. /* This fragments the version into E:V-R triples and compares each
  136. portion seperately. */
  137. int pkgVersionCompare(const char *A, const char *AEnd, const char *B,
  138. const char *BEnd)
  139. {
  140. // Strip off the epoch and compare it
  141. const char *lhs = A;
  142. const char *rhs = B;
  143. for (;lhs != AEnd && *lhs != ':'; lhs++);
  144. for (;rhs != BEnd && *rhs != ':'; rhs++);
  145. if (lhs == AEnd)
  146. lhs = A;
  147. if (rhs == BEnd)
  148. rhs = B;
  149. // Compare the epoch
  150. int Res = iVersionCompare(A,lhs,B,rhs);
  151. if (Res != 0)
  152. return Res;
  153. // Skip the :
  154. if (lhs != A)
  155. lhs++;
  156. if (rhs != B)
  157. rhs++;
  158. // Find the last -
  159. const char *dlhs = AEnd-1;
  160. const char *drhs = BEnd-1;
  161. for (;dlhs > lhs && *dlhs != '-'; dlhs--);
  162. for (;drhs > rhs && *drhs != '-'; drhs--);
  163. if (dlhs == A)
  164. dlhs = AEnd;
  165. if (drhs == B)
  166. drhs = BEnd;
  167. // Compare the main version
  168. Res = iVersionCompare(lhs,dlhs,rhs,drhs);
  169. if (Res != 0)
  170. return Res;
  171. // Skip the -
  172. if (dlhs != lhs)
  173. dlhs++;
  174. if (drhs != rhs)
  175. drhs++;
  176. return iVersionCompare(dlhs,AEnd,drhs,BEnd);
  177. }
  178. /*}}}*/
  179. // CheckDep - Check a single dependency /*{{{*/
  180. // ---------------------------------------------------------------------
  181. /* This simply preforms the version comparison and switch based on
  182. operator. */
  183. bool pkgCheckDep(const char *DepVer,const char *PkgVer,int Op)
  184. {
  185. if (DepVer == 0)
  186. return true;
  187. if (PkgVer == 0)
  188. return false;
  189. // Perform the actuall comparision.
  190. int Res = pkgVersionCompare(PkgVer,DepVer);
  191. switch (Op & 0x0F)
  192. {
  193. case pkgCache::Dep::LessEq:
  194. if (Res <= 0)
  195. return true;
  196. break;
  197. case pkgCache::Dep::GreaterEq:
  198. if (Res >= 0)
  199. return true;
  200. break;
  201. case pkgCache::Dep::Less:
  202. if (Res < 0)
  203. return true;
  204. break;
  205. case pkgCache::Dep::Greater:
  206. if (Res > 0)
  207. return true;
  208. break;
  209. case pkgCache::Dep::Equals:
  210. if (Res == 0)
  211. return true;
  212. break;
  213. case pkgCache::Dep::NotEquals:
  214. if (Res != 0)
  215. return true;
  216. break;
  217. }
  218. return false;
  219. }
  220. /*}}}*/