1 # This module is part of debbugs, and is released
2 # under the terms of the GPL version 2, or any later
3 # version at your option.
4 # See the file README and COPYING for more information.
6 # Copyright Colin Watson <cjwatson@debian.org>
7 # Copyright Ian Jackson <iwj@debian.org>
8 # Copyright 2007 by Don Armstrong <don@donarmstrong.com>.
11 package Debbugs::Versions::Dpkg;
17 Debbugs::Versions::Dpkg - pure-Perl dpkg-style version comparison
21 The Debbugs::Versions::Dpkg module provides pure-Perl routines to compare
22 dpkg-style version numbers, as used in Debian packages. If you have the
23 libapt-pkg Perl bindings available (Debian package libapt-pkg-perl), they
24 may offer better performance.
38 $ver =~ /^(\d+):(.+)/ or die "bad version number '$ver'";
46 if ($ver =~ /(.+)-(.+)$/)
48 $verhash{version} = $1;
49 $verhash{revision} = $2;
53 $verhash{version} = $ver;
54 $verhash{revision} = 0;
61 # This function is almost exactly equivalent
62 # to dpkg's verrevcmp function, including the
63 # order subroutine which it uses.
70 ##define order(x) ((x) == '~' ? -1 \
71 # : cisdigit((x)) ? 0 \
73 # : cisalpha((x)) ? (x) \
75 # This comparison is out of dpkg's order to avoid
76 # comparing things to undef and triggering warnings.
83 elsif ($x =~ /^\d$/) {
86 elsif ($x =~ /^[A-Z]$/i) {
96 return @{$a} ? shift @{$a} : undef;
99 $val = "" if not defined $val;
100 $ref = "" if not defined $ref;
101 my @val = split //,$val;
102 my @ref = split //,$ref;
103 my $vc = next_elem @val;
104 my $rc = next_elem @ref;
105 while (defined $vc or defined $rc) {
107 while ((defined $vc and $vc !~ /^\d$/) or
108 (defined $rc and $rc !~ /^\d$/)) {
109 my $vo = order($vc); my $ro = order($rc);
110 # Unlike dpkg's verrevcmp, we only return 1 or -1 here.
111 return (($vo - $ro > 0) ? 1 : -1) if $vo != $ro;
112 $vc = next_elem @val; $rc = next_elem @ref;
114 while (defined $vc and $vc eq '0') {
115 $vc = next_elem @val;
117 while (defined $rc and $rc eq '0') {
118 $rc = next_elem @ref;
120 while (defined $vc and $vc =~ /^\d$/ and
121 defined $rc and $rc =~ /^\d$/) {
122 $first_diff = ord($vc) - ord($rc) if !$first_diff;
123 $vc = next_elem @val; $rc = next_elem @ref;
125 return 1 if defined $vc and $vc =~ /^\d$/;
126 return -1 if defined $rc and $rc =~ /^\d$/;
127 return $first_diff if $first_diff;
134 Compare the two arguments as dpkg-style version numbers. Returns -1 if the
135 first argument represents a lower version number than the second, 1 if the
136 first argument represents a higher version number than the second, and 0 if
137 the two arguments represent equal version numbers.
143 my %version = parseversion $_[0];
144 my %refversion = parseversion $_[1];
145 return 1 if $version{epoch} > $refversion{epoch};
146 return -1 if $version{epoch} < $refversion{epoch};
147 my $r = verrevcmp($version{version}, $refversion{version});
149 return verrevcmp($version{revision}, $refversion{revision});
156 Don Armstrong <don@donarmstrong.com> and Colin Watson
157 E<lt>cjwatson@debian.orgE<gt>, based on the implementation in
158 C<dpkg/lib/vercmp.c> by Ian Jackson and others.