version.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /*
  2. * libdpkg - Debian packaging suite library routines
  3. * version.c - version handling functions
  4. *
  5. * Copyright © 1995 Ian Jackson <ian@chiark.greenend.org.uk>
  6. *
  7. * This is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  19. */
  20. #include <config.h>
  21. #include <compat.h>
  22. #include <dpkg/dpkg.h> /* cis* */
  23. #include <dpkg/ehandle.h>
  24. #include <dpkg/string.h>
  25. #include <dpkg/version.h>
  26. /**
  27. * Turn the passed version into an empty version.
  28. *
  29. * This can be used to ensure the version is properly initialized.
  30. *
  31. * @param version The version to clear.
  32. */
  33. void
  34. dpkg_version_blank(struct dpkg_version *version)
  35. {
  36. version->epoch = 0;
  37. version->version = NULL;
  38. version->revision = NULL;
  39. }
  40. /**
  41. * Test if a version is not empty.
  42. *
  43. * @param version The version to test.
  44. *
  45. * @retval true If the version is informative (i.e. not an empty version).
  46. * @retval false If the version is empty.
  47. */
  48. bool
  49. dpkg_version_is_informative(const struct dpkg_version *version)
  50. {
  51. return (version->epoch ||
  52. str_is_set(version->version) ||
  53. str_is_set(version->revision));
  54. }
  55. /**
  56. * Give a weight to the character to order in the version comparison.
  57. *
  58. * @param c An ASCII character.
  59. */
  60. static int
  61. order(int c)
  62. {
  63. if (cisdigit(c))
  64. return 0;
  65. else if (cisalpha(c))
  66. return c;
  67. else if (c == '~')
  68. return -1;
  69. else if (c)
  70. return c + 256;
  71. else
  72. return 0;
  73. }
  74. static int
  75. verrevcmp(const char *a, const char *b)
  76. {
  77. if (a == NULL)
  78. a = "";
  79. if (b == NULL)
  80. b = "";
  81. while (*a || *b) {
  82. int first_diff = 0;
  83. while ((*a && !cisdigit(*a)) || (*b && !cisdigit(*b))) {
  84. int ac = order(*a);
  85. int bc = order(*b);
  86. if (ac != bc)
  87. return ac - bc;
  88. a++;
  89. b++;
  90. }
  91. while (*a == '0')
  92. a++;
  93. while (*b == '0')
  94. b++;
  95. while (cisdigit(*a) && cisdigit(*b)) {
  96. if (!first_diff)
  97. first_diff = *a - *b;
  98. a++;
  99. b++;
  100. }
  101. if (cisdigit(*a))
  102. return 1;
  103. if (cisdigit(*b))
  104. return -1;
  105. if (first_diff)
  106. return first_diff;
  107. }
  108. return 0;
  109. }
  110. /**
  111. * Compares two Debian versions.
  112. *
  113. * This function follows the convention of the comparator functions used by
  114. * qsort().
  115. *
  116. * @see deb-version(5)
  117. *
  118. * @param a The first version.
  119. * @param b The second version.
  120. *
  121. * @retval 0 If a and b are equal.
  122. * @retval <0 If a is smaller than b.
  123. * @retval >0 If a is greater than b.
  124. */
  125. int
  126. dpkg_version_compare(const struct dpkg_version *a,
  127. const struct dpkg_version *b)
  128. {
  129. int rc;
  130. if (a->epoch > b->epoch)
  131. return 1;
  132. if (a->epoch < b->epoch)
  133. return -1;
  134. rc = verrevcmp(a->version, b->version);
  135. if (rc)
  136. return rc;
  137. return verrevcmp(a->revision, b->revision);
  138. }
  139. /**
  140. * Check if two versions have a certain relation.
  141. *
  142. * @param a The first version.
  143. * @param rel The relation.
  144. * @param b The second version.
  145. *
  146. * @retval true If the expression “a rel b” is true.
  147. * @retval true If rel is #dpkg_relation_none.
  148. * @retval false Otherwise.
  149. *
  150. * @warning If rel is not a valid relation, this function will terminate
  151. * the program.
  152. */
  153. bool
  154. dpkg_version_relate(const struct dpkg_version *a,
  155. enum dpkg_relation rel,
  156. const struct dpkg_version *b)
  157. {
  158. int rc;
  159. if (rel == dpkg_relation_none)
  160. return true;
  161. rc = dpkg_version_compare(a, b);
  162. switch (rel) {
  163. case dpkg_relation_eq:
  164. return rc == 0;
  165. case dpkg_relation_lt:
  166. return rc < 0;
  167. case dpkg_relation_le:
  168. return rc <= 0;
  169. case dpkg_relation_gt:
  170. return rc > 0;
  171. case dpkg_relation_ge:
  172. return rc >= 0;
  173. default:
  174. internerr("unknown dpkg_relation %d", rel);
  175. }
  176. return false;
  177. }