debversion.cc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: debversion.cc,v 1.8 2003/09/10 23:39:49 mdz Exp $
  4. /* ######################################################################
  5. Debian Version - Versioning system for Debian
  6. This implements the standard Debian versioning system.
  7. ##################################################################### */
  8. /*}}}*/
  9. // Include Files /*{{{*/
  10. #include <config.h>
  11. #include <apt-pkg/debversion.h>
  12. #include <apt-pkg/pkgcache.h>
  13. #include <stdlib.h>
  14. #include <ctype.h>
  15. /*}}}*/
  16. debVersioningSystem debVS;
  17. // debVS::debVersioningSystem - Constructor /*{{{*/
  18. // ---------------------------------------------------------------------
  19. /* */
  20. debVersioningSystem::debVersioningSystem()
  21. {
  22. Label = "Standard .deb";
  23. }
  24. /*}}}*/
  25. // debVS::CmpFragment - Compare versions /*{{{*/
  26. // ---------------------------------------------------------------------
  27. /* This compares a fragment of the version. This is a slightly adapted
  28. version of what dpkg uses. */
  29. #define order(x) ((x) == '~' ? -1 \
  30. : isdigit((x)) ? 0 \
  31. : !(x) ? 0 \
  32. : isalpha((x)) ? (x) \
  33. : (x) + 256)
  34. int debVersioningSystem::CmpFragment(const char *A,const char *AEnd,
  35. const char *B,const char *BEnd)
  36. {
  37. if (A >= AEnd && B >= BEnd)
  38. return 0;
  39. if (A >= AEnd)
  40. {
  41. if (*B == '~') return 1;
  42. return -1;
  43. }
  44. if (B >= BEnd)
  45. {
  46. if (*A == '~') return -1;
  47. return 1;
  48. }
  49. /* Iterate over the whole string
  50. What this does is to split the whole string into groups of
  51. numeric and non numeric portions. For instance:
  52. a67bhgs89
  53. Has 4 portions 'a', '67', 'bhgs', '89'. A more normal:
  54. 2.7.2-linux-1
  55. Has '2', '.', '7', '.' ,'-linux-','1' */
  56. const char *lhs = A;
  57. const char *rhs = B;
  58. while (lhs != AEnd && rhs != BEnd)
  59. {
  60. int first_diff = 0;
  61. while (lhs != AEnd && rhs != BEnd &&
  62. (!isdigit(*lhs) || !isdigit(*rhs)))
  63. {
  64. int vc = order(*lhs);
  65. int rc = order(*rhs);
  66. if (vc != rc)
  67. return vc - rc;
  68. lhs++; rhs++;
  69. }
  70. while (*lhs == '0')
  71. lhs++;
  72. while (*rhs == '0')
  73. rhs++;
  74. while (isdigit(*lhs) && isdigit(*rhs))
  75. {
  76. if (!first_diff)
  77. first_diff = *lhs - *rhs;
  78. lhs++;
  79. rhs++;
  80. }
  81. if (isdigit(*lhs))
  82. return 1;
  83. if (isdigit(*rhs))
  84. return -1;
  85. if (first_diff)
  86. return first_diff;
  87. }
  88. // The strings must be equal
  89. if (lhs == AEnd && rhs == BEnd)
  90. return 0;
  91. // lhs is shorter
  92. if (lhs == AEnd)
  93. {
  94. if (*rhs == '~') return 1;
  95. return -1;
  96. }
  97. // rhs is shorter
  98. if (rhs == BEnd)
  99. {
  100. if (*lhs == '~') return -1;
  101. return 1;
  102. }
  103. // Shouldn't happen
  104. return 1;
  105. }
  106. /*}}}*/
  107. // debVS::CmpVersion - Comparison for versions /*{{{*/
  108. // ---------------------------------------------------------------------
  109. /* This fragments the version into E:V-R triples and compares each
  110. portion separately. */
  111. int debVersioningSystem::DoCmpVersion(const char *A,const char *AEnd,
  112. const char *B,const char *BEnd)
  113. {
  114. // Strip off the epoch and compare it
  115. const char *lhs = (const char*) memchr(A, ':', AEnd - A);
  116. const char *rhs = (const char*) memchr(B, ':', BEnd - B);
  117. if (lhs == NULL)
  118. lhs = A;
  119. if (rhs == NULL)
  120. rhs = B;
  121. // Special case: a zero epoch is the same as no epoch,
  122. // so remove it.
  123. if (lhs != A)
  124. {
  125. for (; *A == '0'; ++A);
  126. if (A == lhs)
  127. {
  128. ++A;
  129. ++lhs;
  130. }
  131. }
  132. if (rhs != B)
  133. {
  134. for (; *B == '0'; ++B);
  135. if (B == rhs)
  136. {
  137. ++B;
  138. ++rhs;
  139. }
  140. }
  141. // Compare the epoch
  142. int Res = CmpFragment(A,lhs,B,rhs);
  143. if (Res != 0)
  144. return Res;
  145. // Skip the :
  146. if (lhs != A)
  147. lhs++;
  148. if (rhs != B)
  149. rhs++;
  150. // Find the last -
  151. const char *dlhs = (const char*) memrchr(lhs, '-', AEnd - lhs);
  152. const char *drhs = (const char*) memrchr(rhs, '-', BEnd - rhs);
  153. if (dlhs == NULL)
  154. dlhs = AEnd;
  155. if (drhs == NULL)
  156. drhs = BEnd;
  157. // Compare the main version
  158. Res = CmpFragment(lhs,dlhs,rhs,drhs);
  159. if (Res != 0)
  160. return Res;
  161. // Skip the -
  162. if (dlhs != lhs)
  163. dlhs++;
  164. if (drhs != rhs)
  165. drhs++;
  166. // no debian revision need to be treated like -0
  167. if (*(dlhs-1) == '-' && *(drhs-1) == '-')
  168. return CmpFragment(dlhs,AEnd,drhs,BEnd);
  169. else if (*(dlhs-1) == '-')
  170. {
  171. const char* null = "0";
  172. return CmpFragment(dlhs,AEnd,null, null+1);
  173. }
  174. else if (*(drhs-1) == '-')
  175. {
  176. const char* null = "0";
  177. return CmpFragment(null, null+1, drhs, BEnd);
  178. }
  179. else
  180. return 0;
  181. }
  182. /*}}}*/
  183. // debVS::CheckDep - Check a single dependency /*{{{*/
  184. // ---------------------------------------------------------------------
  185. /* This simply preforms the version comparison and switch based on
  186. operator. If DepVer is 0 then we are comparing against a provides
  187. with no version. */
  188. bool debVersioningSystem::CheckDep(const char *PkgVer,
  189. int Op,const char *DepVer)
  190. {
  191. if (DepVer == 0 || DepVer[0] == 0)
  192. return true;
  193. if (PkgVer == 0 || PkgVer[0] == 0)
  194. return false;
  195. Op &= 0x0F;
  196. // fast track for (equal) strings [by location] which are by definition equal versions
  197. if (PkgVer == DepVer)
  198. return Op == pkgCache::Dep::Equals || Op == pkgCache::Dep::LessEq || Op == pkgCache::Dep::GreaterEq;
  199. // Perform the actual comparison.
  200. int const Res = CmpVersion(PkgVer, DepVer);
  201. switch (Op)
  202. {
  203. case pkgCache::Dep::LessEq:
  204. if (Res <= 0)
  205. return true;
  206. break;
  207. case pkgCache::Dep::GreaterEq:
  208. if (Res >= 0)
  209. return true;
  210. break;
  211. case pkgCache::Dep::Less:
  212. if (Res < 0)
  213. return true;
  214. break;
  215. case pkgCache::Dep::Greater:
  216. if (Res > 0)
  217. return true;
  218. break;
  219. case pkgCache::Dep::Equals:
  220. if (Res == 0)
  221. return true;
  222. break;
  223. case pkgCache::Dep::NotEquals:
  224. if (Res != 0)
  225. return true;
  226. break;
  227. }
  228. return false;
  229. }
  230. /*}}}*/
  231. // debVS::UpstreamVersion - Return the upstream version string /*{{{*/
  232. // ---------------------------------------------------------------------
  233. /* This strips all the debian specific information from the version number */
  234. std::string debVersioningSystem::UpstreamVersion(const char *Ver)
  235. {
  236. // Strip off the bit before the first colon
  237. const char *I = Ver;
  238. for (; *I != 0 && *I != ':'; I++);
  239. if (*I == ':')
  240. Ver = I + 1;
  241. // Chop off the trailing -
  242. I = Ver;
  243. unsigned Last = strlen(Ver);
  244. for (; *I != 0; I++)
  245. if (*I == '-')
  246. Last = I - Ver;
  247. return std::string(Ver,Last);
  248. }
  249. /*}}}*/