home *** CD-ROM | disk | FTP | other *** search
/ Clickx 115 / Clickx 115.iso / software / tools / windows / tails-i386-0.16.iso / live / filesystem.squashfs / usr / share / perl5 / Dpkg / Version.pm < prev   
Encoding:
Perl POD Document  |  2012-09-17  |  10.5 KB  |  399 lines

  1. # Copyright ┬⌐ Colin Watson <cjwatson@debian.org>
  2. # Copyright ┬⌐ Ian Jackson <iwj@debian.org>
  3. # Copyright ┬⌐ 2007 Don Armstrong <don@donarmstrong.com>.
  4. # Copyright ┬⌐ 2009 Rapha├½l Hertzog <hertzog@debian.org>
  5. #
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  
  19. package Dpkg::Version;
  20.  
  21. use strict;
  22. use warnings;
  23.  
  24. our $VERSION = "1.00";
  25.  
  26. use Dpkg::ErrorHandling;
  27. use Dpkg::Gettext;
  28.  
  29. use base qw(Exporter);
  30. our @EXPORT = qw(version_compare version_compare_relation
  31.                  version_normalize_relation version_compare_string
  32.                  version_compare_part version_split_digits version_check
  33.                  REL_LT REL_LE REL_EQ REL_GE REL_GT);
  34.  
  35. use constant {
  36.     REL_LT => '<<',
  37.     REL_LE => '<=',
  38.     REL_EQ => '=',
  39.     REL_GE => '>=',
  40.     REL_GT => '>>',
  41. };
  42.  
  43. use overload
  44.     '<=>' => \&comparison,
  45.     'cmp' => \&comparison,
  46.     '""'  => \&as_string,
  47.     'bool' => sub { return $_[0]->as_string() if $_[0]->is_valid(); },
  48.     'fallback' => 1;
  49.  
  50. =encoding utf8
  51.  
  52. =head1 NAME
  53.  
  54. Dpkg::Version - handling and comparing dpkg-style version numbers
  55.  
  56. =head1 DESCRIPTION
  57.  
  58. The Dpkg::Version module provides pure-Perl routines to compare
  59. dpkg-style version numbers (as used in Debian packages) and also
  60. an object oriented interface overriding perl operators
  61. to do the right thing when you compare Dpkg::Version object between
  62. them.
  63.  
  64. =head1 OBJECT INTERFACE
  65.  
  66. =over 4
  67.  
  68. =item my $v = Dpkg::Version->new($version, %opts)
  69.  
  70. Create a new Dpkg::Version object corresponding to the version indicated in
  71. the string (scalar) $version. By default it will accepts any string
  72. and consider it as a valid version. If you pass the option "check => 1",
  73. it will return undef if the version is invalid (see version_check for
  74. details).
  75.  
  76. You can always call $v->is_valid() later on to verify that the version is
  77. valid.
  78.  
  79. =cut
  80.  
  81. sub new {
  82.     my ($this, $ver, %opts) = @_;
  83.     my $class = ref($this) || $this;
  84.     $ver = "$ver" if ref($ver); # Try to stringify objects
  85.  
  86.     if ($opts{'check'}) {
  87.     return undef unless version_check($ver);
  88.     }
  89.  
  90.     my $self = {};
  91.     if ($ver =~ /^(\d*):(.+)$/) {
  92.     $self->{'epoch'} = $1;
  93.     $ver = $2;
  94.     } else {
  95.     $self->{'epoch'} = 0;
  96.     $self->{'no_epoch'} = 1;
  97.     }
  98.     if ($ver =~ /(.*)-(.*)$/) {
  99.     $self->{'version'} = $1;
  100.     $self->{'revision'} = $2;
  101.     } else {
  102.     $self->{'version'} = $ver;
  103.     $self->{'revision'} = 0;
  104.     $self->{'no_revision'} = 1;
  105.     }
  106.  
  107.     return bless $self, $class;
  108. }
  109.  
  110. =item boolean evaluation
  111.  
  112. When the Dpkg::Version object is used in a boolean evaluation (for example
  113. in "if ($v)" or "$v || 'default'") it returns its string representation
  114. if the version stored is valid ($v->is_valid()) and undef otherwise.
  115.  
  116. =item $v->is_valid()
  117.  
  118. Returns true if the version is valid, false otherwise.
  119.  
  120. =cut
  121.  
  122. sub is_valid {
  123.     my ($self) = @_;
  124.     return scalar version_check($self);
  125. }
  126.  
  127. =item $v->epoch(), $v->version(), $v->revision()
  128.  
  129. Returns the corresponding part of the full version string.
  130.  
  131. =cut
  132.  
  133. sub epoch {
  134.     my $self = shift;
  135.     return $self->{'epoch'};
  136. }
  137.  
  138. sub version {
  139.     my $self = shift;
  140.     return $self->{'version'};
  141. }
  142.  
  143. sub revision {
  144.     my $self = shift;
  145.     return $self->{'revision'};
  146. }
  147.  
  148. =item $v1 <=> $v2, $v1 < $v2, $v1 <= $v2, $v1 > $v2, $v1 >= $v2
  149.  
  150. Numerical comparison of various versions numbers. One of the two operands
  151. needs to be a Dpkg::Version, the other one can be anything provided that
  152. its string representation is a version number.
  153.  
  154. =cut
  155.  
  156. sub comparison {
  157.     my ($a, $b, $inverted) = @_;
  158.     if (not ref($b) or not $b->isa("Dpkg::Version")) {
  159.         $b = Dpkg::Version->new($b);
  160.     }
  161.     ($a, $b) = ($b, $a) if $inverted;
  162.     my $r = $a->epoch() <=> $b->epoch();
  163.     return $r if $r;
  164.     $r = version_compare_part($a->version(), $b->version());
  165.     return $r if $r;
  166.     return version_compare_part($a->revision(), $b->revision());
  167. }
  168.  
  169. =item "$v", $v->as_string()
  170.  
  171. Returns the string representation of the version number.
  172.  
  173. =cut
  174.  
  175. sub as_string {
  176.     my ($self) = @_;
  177.     my $str = "";
  178.     $str .= $self->{epoch} . ":" unless $self->{no_epoch};
  179.     $str .= $self->{version};
  180.     $str .= "-" . $self->{revision} unless $self->{no_revision};
  181.     return $str;
  182. }
  183.  
  184. =back
  185.  
  186. =head1 FUNCTIONS
  187.  
  188. All the functions are exported by default.
  189.  
  190. =over 4
  191.  
  192. =item version_compare($a, $b)
  193.  
  194. Returns -1 if $a is earlier than $b, 0 if they are equal and 1 if $a
  195. is later than $b.
  196.  
  197. If $a or $b are not valid version numbers, it dies with an error.
  198.  
  199. =cut
  200.  
  201. sub version_compare($$) {
  202.     my ($a, $b) = @_;
  203.     my $va = Dpkg::Version->new($a, check => 1);
  204.     defined($va) || error(_g("%s is not a valid version"), "$a");
  205.     my $vb = Dpkg::Version->new($b, check => 1);
  206.     defined($vb) || error(_g("%s is not a valid version"), "$b");
  207.     return $va <=> $vb;
  208. }
  209.  
  210. =item version_compare_relation($a, $rel, $b)
  211.  
  212. Returns the result (0 or 1) of the given comparison operation. This
  213. function is implemented on top of version_compare().
  214.  
  215. Allowed values for $rel are the exported constants REL_GT, REL_GE,
  216. REL_EQ, REL_LE, REL_LT. Use version_normalize_relation() if you
  217. have an input string containing the operator.
  218.  
  219. =cut
  220.  
  221. sub version_compare_relation($$$) {
  222.     my ($a, $op, $b) = @_;
  223.     my $res = version_compare($a, $b);
  224.  
  225.     if ($op eq REL_GT) {
  226.     return $res > 0;
  227.     } elsif ($op eq REL_GE) {
  228.     return $res >= 0;
  229.     } elsif ($op eq REL_EQ) {
  230.     return $res == 0;
  231.     } elsif ($op eq REL_LE) {
  232.     return $res <= 0;
  233.     } elsif ($op eq REL_LT) {
  234.     return $res < 0;
  235.     } else {
  236.     internerr("unsupported relation for version_compare_relation(): '$op'");
  237.     }
  238. }
  239.  
  240. =item my $rel = version_normalize_relation($rel_string)
  241.  
  242. Returns the normalized constant of the relation $rel (a value
  243. among REL_GT, REL_GE, REL_EQ, REL_LE and REL_LT). Supported
  244. relations names in input are: "gt", "ge", "eq", "le", "lt", ">>", ">=",
  245. "=", "<=", "<<". ">" and "<" are also supported but should not be used as
  246. they are obsolete aliases of ">=" and "<=".
  247.  
  248. =cut
  249.  
  250. sub version_normalize_relation($) {
  251.     my $op = shift;
  252.  
  253.     warning("relation %s is deprecated: use %s or %s",
  254.             $op, "$op$op", "$op=") if ($op eq '>' or $op eq '<');
  255.  
  256.     if ($op eq '>>' or $op eq 'gt') {
  257.     return REL_GT;
  258.     } elsif ($op eq '>=' or $op eq 'ge' or $op eq '>') {
  259.     return REL_GE;
  260.     } elsif ($op eq '=' or $op eq 'eq') {
  261.     return REL_EQ;
  262.     } elsif ($op eq '<=' or $op eq 'le' or $op eq '<') {
  263.     return REL_LE;
  264.     } elsif ($op eq '<<' or $op eq 'lt') {
  265.     return REL_LT;
  266.     } else {
  267.     internerr("bad relation '$op'");
  268.     }
  269. }
  270.  
  271. =item version_compare_string($a, $b)
  272.  
  273. String comparison function used for comparing non-numerical parts of version
  274. numbers. Returns -1 if $a is earlier than $b, 0 if they are equal and 1 if $a
  275. is later than $b.
  276.  
  277. The "~" character always sort lower than anything else. Digits sort lower
  278. than non-digits. Among remaining characters alphabetic characters (A-Za-z)
  279. sort lower than the other ones. Within each range, the ASCII decimal value
  280. of the character is used to sort between characters.
  281.  
  282. =cut
  283.  
  284. sub version_compare_string($$) {
  285.     sub order {
  286.         my ($x) = @_;
  287.     if ($x eq '~') {
  288.         return -1;
  289.     } elsif ($x =~ /^\d$/) {
  290.         return $x * 1 + 1;
  291.     } elsif ($x =~ /^[A-Za-z]$/) {
  292.         return ord($x);
  293.     } else {
  294.         return ord($x) + 256;
  295.     }
  296.     }
  297.     my @a = map(order($_), split(//, shift));
  298.     my @b = map(order($_), split(//, shift));
  299.     while (1) {
  300.         my ($a, $b) = (shift @a, shift @b);
  301.         return 0 if not defined($a) and not defined($b);
  302.         $a ||= 0; # Default order for "no character"
  303.         $b ||= 0;
  304.         return 1 if $a > $b;
  305.         return -1 if $a < $b;
  306.     }
  307. }
  308.  
  309. =item version_compare_part($a, $b)
  310.  
  311. Compare two corresponding sub-parts of a version number (either upstream
  312. version or debian revision).
  313.  
  314. Each parameter is split by version_split_digits() and resulting items
  315. are compared together.in digits and non-digits items that are compared
  316. together. As soon as a difference happens, it returns -1 if $a is earlier
  317. than $b, 0 if they are equal and 1 if $a is later than $b.
  318.  
  319. =cut
  320.  
  321. sub version_compare_part($$) {
  322.     my @a = version_split_digits(shift);
  323.     my @b = version_split_digits(shift);
  324.     while (1) {
  325.         my ($a, $b) = (shift @a, shift @b);
  326.         return 0 if not defined($a) and not defined($b);
  327.         $a ||= 0; # Default value for lack of version
  328.         $b ||= 0;
  329.         if ($a =~ /^\d+$/ and $b =~ /^\d+$/) {
  330.             # Numerical comparison
  331.             my $cmp = $a <=> $b;
  332.             return $cmp if $cmp;
  333.         } else {
  334.             # String comparison
  335.             my $cmp = version_compare_string($a, $b);
  336.             return $cmp if $cmp;
  337.         }
  338.     }
  339. }
  340.  
  341. =item my @items = version_split_digits($version)
  342.  
  343. Splits a string in items that are each entirely composed either
  344. of digits or of non-digits. For instance for "1.024~beta1+svn234" it would
  345. return ("1", ".", "024", "~beta", "1", "+svn", "234").
  346.  
  347. =cut
  348.  
  349. sub version_split_digits($) {
  350.     return split(/(?<=\d)(?=\D)|(?<=\D)(?=\d)/, $_[0]);
  351. }
  352.  
  353. =item my ($ok, $msg) = version_check($version)
  354.  
  355. =item my $ok = version_check($version)
  356.  
  357. Checks the validity of $version as a version number. Returns 1 in $ok
  358. if the version is valid, 0 otherwise. In the latter case, $msg
  359. contains a description of the problem with the $version scalar.
  360.  
  361. =cut
  362.  
  363. sub version_check($) {
  364.     my $version = shift;
  365.     $version = "$version" if ref($version);
  366.  
  367.     if (not defined($version) or not length($version)) {
  368.         my $msg = _g("version number cannot be empty");
  369.         return (0, $msg) if wantarray;
  370.         return 0;
  371.     }
  372.     if ($version =~ m/([^-+:.0-9a-zA-Z~])/o) {
  373.         my $msg = sprintf(_g("version number contains illegal character `%s'"), $1);
  374.         return (0, $msg) if wantarray;
  375.         return 0;
  376.     }
  377.     if ($version =~ /:/ and $version !~ /^\d*:/) {
  378.         $version =~ /^([^:]*):/;
  379.         my $msg = sprintf(_g("epoch part of the version number " .
  380.                              "is not a number: '%s'"), $1);
  381.         return (0, $msg) if wantarray;
  382.         return 0;
  383.     }
  384.     return (1, "") if wantarray;
  385.     return 1;
  386. }
  387.  
  388. =back
  389.  
  390. =head1 AUTHOR
  391.  
  392. Don Armstrong <don@donarmstrong.com>, Colin Watson
  393. <cjwatson@debian.org> and Rapha├½l Hertzog <hertzog@debian.org>, based on
  394. the implementation in C<dpkg/lib/vercmp.c> by Ian Jackson and others.
  395.  
  396. =cut
  397.  
  398. 1;
  399.