Version.pm 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. # Copyright Colin Watson <cjwatson@debian.org>
  2. # Copyright Ian Jackson <iwj@debian.org>
  3. # Copyright 2007 by Don Armstrong <don@donarmstrong.com>.
  4. # This program is free software; you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation; either version 2 of the License, or
  7. # (at your option) any later version.
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. # You should have received a copy of the GNU General Public License along
  13. # with this program; if not, write to the Free Software Foundation, Inc.,
  14. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. package Dpkg::Version;
  16. use strict;
  17. use warnings;
  18. use Exporter;
  19. our @ISA = qw(Exporter);
  20. our @EXPORT_OK = qw(vercmp);
  21. =head1 NAME
  22. Dpkg::Version - pure-Perl dpkg-style version comparison
  23. =head1 DESCRIPTION
  24. The Dpkg::Version module provides pure-Perl routines to compare
  25. dpkg-style version numbers, as used in Debian packages. If you have the
  26. libapt-pkg Perl bindings available (Debian package libapt-pkg-perl), they
  27. may offer better performance.
  28. =head1 METHODS
  29. =over 8
  30. =cut
  31. sub parseversion ($)
  32. {
  33. my $ver = shift;
  34. my %verhash;
  35. if ($ver =~ /:/)
  36. {
  37. $ver =~ /^(\d+):(.+)/ or die "bad version number '$ver'";
  38. $verhash{epoch} = $1;
  39. $ver = $2;
  40. }
  41. else
  42. {
  43. $verhash{epoch} = 0;
  44. }
  45. if ($ver =~ /(.+)-(.+)$/)
  46. {
  47. $verhash{version} = $1;
  48. $verhash{revision} = $2;
  49. }
  50. else
  51. {
  52. $verhash{version} = $ver;
  53. $verhash{revision} = 0;
  54. }
  55. return %verhash;
  56. }
  57. # verrevcmp
  58. # This function is almost exactly equivalent
  59. # to dpkg's verrevcmp function, including the
  60. # order subroutine which it uses.
  61. sub verrevcmp($$)
  62. {
  63. sub order{
  64. my ($x) = @_;
  65. ##define order(x) ((x) == '~' ? -1 \
  66. # : cisdigit((x)) ? 0 \
  67. # : !(x) ? 0 \
  68. # : cisalpha((x)) ? (x) \
  69. # : (x) + 256)
  70. # This comparison is out of dpkg's order to avoid
  71. # comparing things to undef and triggering warnings.
  72. if (not defined $x) {
  73. return 0;
  74. }
  75. elsif ($x eq '~') {
  76. return -1;
  77. }
  78. elsif ($x =~ /^\d$/) {
  79. return 0;
  80. }
  81. elsif ($x =~ /^[A-Z]$/i) {
  82. return ord($x);
  83. }
  84. else {
  85. return ord($x) + 256;
  86. }
  87. }
  88. sub next_elem(\@){
  89. my $a = shift;
  90. return @{$a} ? shift @{$a} : undef;
  91. }
  92. my ($val, $ref) = @_;
  93. $val = "" if not defined $val;
  94. $ref = "" if not defined $ref;
  95. my @val = split //,$val;
  96. my @ref = split //,$ref;
  97. my $vc = next_elem @val;
  98. my $rc = next_elem @ref;
  99. while (defined $vc or defined $rc) {
  100. my $first_diff = 0;
  101. while ((defined $vc and $vc !~ /^\d$/) or
  102. (defined $rc and $rc !~ /^\d$/)) {
  103. my $vo = order($vc); my $ro = order($rc);
  104. # Unlike dpkg's verrevcmp, we only return 1 or -1 here.
  105. return (($vo - $ro > 0) ? 1 : -1) if $vo != $ro;
  106. $vc = next_elem @val; $rc = next_elem @ref;
  107. }
  108. while (defined $vc and $vc eq '0') {
  109. $vc = next_elem @val;
  110. }
  111. while (defined $rc and $rc eq '0') {
  112. $rc = next_elem @ref;
  113. }
  114. while (defined $vc and $vc =~ /^\d$/ and
  115. defined $rc and $rc =~ /^\d$/) {
  116. $first_diff = ord($vc) - ord($rc) if !$first_diff;
  117. $vc = next_elem @val; $rc = next_elem @ref;
  118. }
  119. return 1 if defined $vc and $vc =~ /^\d$/;
  120. return -1 if defined $rc and $rc =~ /^\d$/;
  121. return $first_diff if $first_diff;
  122. }
  123. return 0;
  124. }
  125. =item vercmp
  126. Compare the two arguments as dpkg-style version numbers. Returns -1 if the
  127. first argument represents a lower version number than the second, 1 if the
  128. first argument represents a higher version number than the second, and 0 if
  129. the two arguments represent equal version numbers.
  130. =cut
  131. sub vercmp ($$)
  132. {
  133. my %version = parseversion $_[0];
  134. my %refversion = parseversion $_[1];
  135. return 1 if $version{epoch} > $refversion{epoch};
  136. return -1 if $version{epoch} < $refversion{epoch};
  137. my $r = verrevcmp($version{version}, $refversion{version});
  138. return $r if $r;
  139. return verrevcmp($version{revision}, $refversion{revision});
  140. }
  141. =back
  142. =head1 AUTHOR
  143. Don Armstrong <don@donarmstrong.com> and Colin Watson
  144. E<lt>cjwatson@debian.orgE<gt>, based on the implementation in
  145. C<dpkg/lib/vercmp.c> by Ian Jackson and others.
  146. =cut
  147. 1;