debversion.cc 6.6 KB

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