|
Packit |
7d6a7d |
################################################################################
|
|
Packit |
7d6a7d |
#
|
|
Packit |
7d6a7d |
# ppptools.pl -- various utility functions
|
|
Packit |
7d6a7d |
#
|
|
Packit |
7d6a7d |
################################################################################
|
|
Packit |
7d6a7d |
#
|
|
Packit |
7d6a7d |
# Version 3.x, Copyright (C) 2004-2013, Marcus Holland-Moritz.
|
|
Packit |
7d6a7d |
# Version 2.x, Copyright (C) 2001, Paul Marquess.
|
|
Packit |
7d6a7d |
# Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
|
|
Packit |
7d6a7d |
#
|
|
Packit |
7d6a7d |
# This program is free software; you can redistribute it and/or
|
|
Packit |
7d6a7d |
# modify it under the same terms as Perl itself.
|
|
Packit |
7d6a7d |
#
|
|
Packit |
7d6a7d |
################################################################################
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
sub cat_file
|
|
Packit |
7d6a7d |
{
|
|
Packit |
7d6a7d |
eval { require File::Spec };
|
|
Packit |
7d6a7d |
return $@ ? join('/', @_) : File::Spec->catfile(@_);
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
sub all_files_in_dir
|
|
Packit |
7d6a7d |
{
|
|
Packit |
7d6a7d |
my $dir = shift;
|
|
Packit |
7d6a7d |
local *DIR;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
opendir DIR, $dir or die "cannot open directory $dir: $!\n";
|
|
Packit |
7d6a7d |
my @files = grep { !-d && !/^\./ } readdir DIR; # no dirs or hidden files
|
|
Packit |
7d6a7d |
closedir DIR;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
return map { cat_file($dir, $_) } sort @files;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
sub parse_todo
|
|
Packit |
7d6a7d |
{
|
|
Packit |
7d6a7d |
my $dir = shift || 'parts/todo';
|
|
Packit |
7d6a7d |
local *TODO;
|
|
Packit |
7d6a7d |
my %todo;
|
|
Packit |
7d6a7d |
my $todo;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
for $todo (all_files_in_dir($dir)) {
|
|
Packit |
7d6a7d |
open TODO, $todo or die "cannot open $todo: $!\n";
|
|
Packit |
7d6a7d |
my $perl = <TODO>;
|
|
Packit |
7d6a7d |
chomp $perl;
|
|
Packit |
7d6a7d |
while (<TODO>) {
|
|
Packit |
7d6a7d |
chomp;
|
|
Packit |
7d6a7d |
s/#.*//;
|
|
Packit |
7d6a7d |
s/^\s+//; s/\s+$//;
|
|
Packit |
7d6a7d |
/^\s*$/ and next;
|
|
Packit |
7d6a7d |
/^\w+$/ or die "invalid identifier: $_\n";
|
|
Packit |
7d6a7d |
exists $todo{$_} and die "duplicate identifier: $_ ($todo{$_} <=> $perl)\n";
|
|
Packit |
7d6a7d |
$todo{$_} = $perl;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
close TODO;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
return \%todo;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
sub expand_version
|
|
Packit |
7d6a7d |
{
|
|
Packit |
7d6a7d |
my($op, $ver) = @_;
|
|
Packit |
7d6a7d |
my($r, $v, $s) = parse_version($ver);
|
|
Packit |
7d6a7d |
$r == 5 or die "only Perl revision 5 is supported\n";
|
|
Packit |
7d6a7d |
my $bcdver = sprintf "0x%d%03d%03d", $r, $v, $s;
|
|
Packit |
7d6a7d |
return "(PERL_BCDVERSION $op $bcdver)";
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
sub parse_partspec
|
|
Packit |
7d6a7d |
{
|
|
Packit |
7d6a7d |
my $file = shift;
|
|
Packit |
7d6a7d |
my $section = 'implementation';
|
|
Packit |
7d6a7d |
my $vsec = join '|', qw( provides dontwarn implementation
|
|
Packit |
7d6a7d |
xsubs xsinit xsmisc xshead xsboot tests );
|
|
Packit |
7d6a7d |
my(%data, %options);
|
|
Packit |
7d6a7d |
local *F;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
open F, $file or die "$file: $!\n";
|
|
Packit |
7d6a7d |
while (<F>) {
|
|
Packit |
7d6a7d |
/[ \t]+$/ and warn "$file:$.: warning: trailing whitespace\n";
|
|
Packit |
7d6a7d |
if ($section eq 'implementation') {
|
|
Packit |
7d6a7d |
m!//! && !m!(?:=~|s/).*//! && !m!(?:ht|f)tp(?:s)://!
|
|
Packit |
7d6a7d |
and warn "$file:$.: warning: potential C++ comment\n";
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
/^##/ and next;
|
|
Packit |
7d6a7d |
if (/^=($vsec)(?:\s+(.*))?/) {
|
|
Packit |
7d6a7d |
$section = $1;
|
|
Packit |
7d6a7d |
if (defined $2) {
|
|
Packit |
7d6a7d |
my $opt = $2;
|
|
Packit |
7d6a7d |
$options{$section} = eval "{ $opt }";
|
|
Packit |
7d6a7d |
$@ and die "$file:$.: invalid options ($opt) in section $section: $@\n";
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
next;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
push @{$data{$section}}, $_;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
close F;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
for (keys %data) {
|
|
Packit |
7d6a7d |
my @v = @{$data{$_}};
|
|
Packit |
7d6a7d |
shift @v while @v && $v[0] =~ /^\s*$/;
|
|
Packit |
7d6a7d |
pop @v while @v && $v[-1] =~ /^\s*$/;
|
|
Packit |
7d6a7d |
$data{$_} = join '', @v;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
unless (exists $data{provides}) {
|
|
Packit |
7d6a7d |
$data{provides} = ($file =~ /(\w+)\.?$/)[0];
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
$data{provides} = [$data{provides} =~ /(\S+)/g];
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
if (exists $data{dontwarn}) {
|
|
Packit |
7d6a7d |
$data{dontwarn} = [$data{dontwarn} =~ /(\S+)/g];
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
my @prov;
|
|
Packit |
7d6a7d |
my %proto;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
if (exists $data{tests} && (!exists $data{implementation} || $data{implementation} !~ /\S/)) {
|
|
Packit |
7d6a7d |
$data{implementation} = '';
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
else {
|
|
Packit |
7d6a7d |
$data{implementation} =~ /\S/ or die "Empty implementation in $file\n";
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
my $p;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
for $p (@{$data{provides}}) {
|
|
Packit |
7d6a7d |
if ($p =~ m#^/.*/\w*$#) {
|
|
Packit |
7d6a7d |
my @tmp = eval "\$data{implementation} =~ ${p}gm";
|
|
Packit |
7d6a7d |
$@ and die "invalid regex $p in $file\n";
|
|
Packit |
7d6a7d |
@tmp or warn "no matches for regex $p in $file\n";
|
|
Packit |
7d6a7d |
push @prov, do { my %h; grep !$h{$_}++, @tmp };
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
elsif ($p eq '__UNDEFINED__') {
|
|
Packit |
7d6a7d |
my @tmp = $data{implementation} =~ /^\s*__UNDEFINED__[^\r\n\S]+(\w+)/gm;
|
|
Packit |
7d6a7d |
@tmp or warn "no __UNDEFINED__ macros in $file\n";
|
|
Packit |
7d6a7d |
push @prov, @tmp;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
else {
|
|
Packit |
7d6a7d |
push @prov, $p;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
for (@prov) {
|
|
Packit |
7d6a7d |
if ($data{implementation} !~ /\b\Q$_\E\b/) {
|
|
Packit |
7d6a7d |
warn "$file claims to provide $_, but doesn't seem to do so\n";
|
|
Packit |
7d6a7d |
next;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
# scan for prototypes
|
|
Packit |
7d6a7d |
my($proto) = $data{implementation} =~ /
|
|
Packit |
7d6a7d |
( ^ (?:[\w*]|[^\S\r\n])+
|
|
Packit |
7d6a7d |
[\r\n]*?
|
|
Packit |
7d6a7d |
^ \b$_\b \s*
|
|
Packit |
7d6a7d |
\( [^{]* \)
|
|
Packit |
7d6a7d |
)
|
|
Packit |
7d6a7d |
\s* \{
|
|
Packit |
7d6a7d |
/xm or next;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
$proto =~ s/^\s+//;
|
|
Packit |
7d6a7d |
$proto =~ s/\s+$//;
|
|
Packit |
7d6a7d |
$proto =~ s/\s+/ /g;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
exists $proto{$_} and warn "$file: duplicate prototype for $_\n";
|
|
Packit |
7d6a7d |
$proto{$_} = $proto;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
for $section (qw( implementation xsubs xsinit xsmisc xshead xsboot )) {
|
|
Packit |
7d6a7d |
if (exists $data{$section}) {
|
|
Packit |
7d6a7d |
$data{$section} =~ s/\{\s*version\s*(<|>|==|!=|>=|<=)\s*([\d._]+)\s*\}/expand_version($1, $2)/gei;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
$data{provides} = \@prov;
|
|
Packit |
7d6a7d |
$data{prototypes} = \%proto;
|
|
Packit |
7d6a7d |
$data{OPTIONS} = \%options;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
my %prov = map { ($_ => 1) } @prov;
|
|
Packit |
7d6a7d |
my %dontwarn = exists $data{dontwarn} ? map { ($_ => 1) } @{$data{dontwarn}} : ();
|
|
Packit |
7d6a7d |
my @maybeprov = do { my %h;
|
|
Packit |
7d6a7d |
grep {
|
|
Packit |
7d6a7d |
my($nop) = /^Perl_(.*)/;
|
|
Packit |
7d6a7d |
not exists $prov{$_} ||
|
|
Packit |
7d6a7d |
exists $dontwarn{$_} ||
|
|
Packit |
7d6a7d |
/^D_PPP_/ ||
|
|
Packit |
7d6a7d |
(defined $nop && exists $prov{$nop} ) ||
|
|
Packit |
7d6a7d |
(defined $nop && exists $dontwarn{$nop}) ||
|
|
Packit |
7d6a7d |
$h{$_}++;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
$data{implementation} =~ /^\s*#\s*define\s+(\w+)/gm };
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
if (@maybeprov) {
|
|
Packit |
7d6a7d |
warn "$file seems to provide these macros, but doesn't list them:\n "
|
|
Packit |
7d6a7d |
. join("\n ", @maybeprov) . "\n";
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
return \%data;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
sub compare_prototypes
|
|
Packit |
7d6a7d |
{
|
|
Packit |
7d6a7d |
my($p1, $p2) = @_;
|
|
Packit |
7d6a7d |
for ($p1, $p2) {
|
|
Packit |
7d6a7d |
s/^\s+//;
|
|
Packit |
7d6a7d |
s/\s+$//;
|
|
Packit |
7d6a7d |
s/\s+/ /g;
|
|
Packit |
7d6a7d |
s/(\w)\s(\W)/$1$2/g;
|
|
Packit |
7d6a7d |
s/(\W)\s(\w)/$1$2/g;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
return $p1 cmp $p2;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
sub ppcond
|
|
Packit |
7d6a7d |
{
|
|
Packit |
7d6a7d |
my $s = shift;
|
|
Packit |
7d6a7d |
my @c;
|
|
Packit |
7d6a7d |
my $p;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
for $p (@$s) {
|
|
Packit |
7d6a7d |
push @c, map "!($_)", @{$p->{pre}};
|
|
Packit |
7d6a7d |
defined $p->{cur} and push @c, "($p->{cur})";
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
join " && ", @c;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
sub trim_arg
|
|
Packit |
7d6a7d |
{
|
|
Packit |
7d6a7d |
my $in = shift;
|
|
Packit |
7d6a7d |
my $remove = join '|', qw( NN NULLOK VOL );
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
$in eq '...' and return ($in);
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
local $_ = $in;
|
|
Packit |
7d6a7d |
my $id;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
s/[*()]/ /g;
|
|
Packit |
7d6a7d |
s/\[[^\]]*\]/ /g;
|
|
Packit |
7d6a7d |
s/\b(?:auto|const|extern|inline|register|static|volatile|restrict)\b//g;
|
|
Packit |
7d6a7d |
s/\b(?:$remove)\b//;
|
|
Packit |
7d6a7d |
s/^\s*//; s/\s*$//;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
if( /^\b(?:struct|union|enum)\s+\w+(?:\s+(\w+))?$/ ) {
|
|
Packit |
7d6a7d |
defined $1 and $id = $1;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
else {
|
|
Packit |
7d6a7d |
if( s/\b(?:char|double|float|int|long|short|signed|unsigned|void)\b//g ) {
|
|
Packit |
7d6a7d |
/^\s*(\w+)\s*$/ and $id = $1;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
else {
|
|
Packit |
7d6a7d |
/^\s*\w+\s+(\w+)\s*$/ and $id = $1;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
$_ = $in;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
defined $id and s/\b$id\b//;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
# these don't matter at all
|
|
Packit |
7d6a7d |
s/\b(?:auto|extern|inline|register|static|volatile|restrict)\b//g;
|
|
Packit |
7d6a7d |
s/\b(?:$remove)\b//;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
s/(?=<\*)\s+(?=\*)//g;
|
|
Packit |
7d6a7d |
s/\s*(\*+)\s*/ $1 /g;
|
|
Packit |
7d6a7d |
s/^\s*//; s/\s*$//;
|
|
Packit |
7d6a7d |
s/\s+/ /g;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
return ($_, $id);
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
sub parse_embed
|
|
Packit |
7d6a7d |
{
|
|
Packit |
7d6a7d |
my @files = @_;
|
|
Packit |
7d6a7d |
my @func;
|
|
Packit |
7d6a7d |
my @pps;
|
|
Packit |
7d6a7d |
my $file;
|
|
Packit |
7d6a7d |
local *FILE;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
for $file (@files) {
|
|
Packit |
7d6a7d |
open FILE, $file or die "$file: $!\n";
|
|
Packit |
7d6a7d |
my($line, $l);
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
while (defined($line = <FILE>)) {
|
|
Packit |
7d6a7d |
while ($line =~ /\\$/ && defined($l = <FILE>)) {
|
|
Packit |
7d6a7d |
$line =~ s/\\\s*//;
|
|
Packit |
7d6a7d |
$line .= $l;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
next if $line =~ /^\s*:/;
|
|
Packit |
7d6a7d |
$line =~ s/^\s+|\s+$//gs;
|
|
Packit |
7d6a7d |
my($dir, $args) = ($line =~ /^\s*#\s*(\w+)(?:\s*(.*?)\s*)?$/);
|
|
Packit |
7d6a7d |
if (defined $dir and defined $args) {
|
|
Packit |
7d6a7d |
for ($dir) {
|
|
Packit |
7d6a7d |
/^ifdef$/ and do { push @pps, { pre => [], cur => "defined($args)" } ; last };
|
|
Packit |
7d6a7d |
/^ifndef$/ and do { push @pps, { pre => [], cur => "!defined($args)" } ; last };
|
|
Packit |
7d6a7d |
/^if$/ and do { push @pps, { pre => [], cur => $args } ; last };
|
|
Packit |
7d6a7d |
/^elif$/ and do { push @{$pps[-1]{pre}}, $pps[-1]{cur}; $pps[-1]{cur} = $args; last };
|
|
Packit |
7d6a7d |
/^else$/ and do { push @{$pps[-1]{pre}}, $pps[-1]{cur}; $pps[-1]{cur} = undef; last };
|
|
Packit |
7d6a7d |
/^endif$/ and do { pop @pps ; last };
|
|
Packit |
7d6a7d |
/^include$/ and last;
|
|
Packit |
7d6a7d |
/^define$/ and last;
|
|
Packit |
7d6a7d |
/^undef$/ and last;
|
|
Packit |
7d6a7d |
warn "unhandled preprocessor directive: $dir\n";
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
else {
|
|
Packit |
7d6a7d |
my @e = split /\s*\|\s*/, $line;
|
|
Packit |
7d6a7d |
if( @e >= 3 ) {
|
|
Packit |
7d6a7d |
my($flags, $ret, $name, @args) = @e;
|
|
Packit |
7d6a7d |
if ($name =~ /^[^\W\d]\w*$/) {
|
|
Packit |
7d6a7d |
for (@args) {
|
|
Packit |
7d6a7d |
$_ = [trim_arg($_)];
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
($ret) = trim_arg($ret);
|
|
Packit |
7d6a7d |
push @func, {
|
|
Packit |
7d6a7d |
name => $name,
|
|
Packit |
7d6a7d |
flags => { map { $_, 1 } $flags =~ /./g },
|
|
Packit |
7d6a7d |
ret => $ret,
|
|
Packit |
7d6a7d |
args => \@args,
|
|
Packit |
7d6a7d |
cond => ppcond(\@pps),
|
|
Packit |
7d6a7d |
};
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
elsif ($name =~ /^[^\W\d]\w*-E<gt>[^\W\d]\w*$/) {
|
|
Packit |
7d6a7d |
# silenty ignore entries of the form
|
|
Packit |
7d6a7d |
# PL_parser-E<gt>linestr
|
|
Packit |
7d6a7d |
# which documents a struct entry rather than a function
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
else {
|
|
Packit |
7d6a7d |
warn "mysterious name [$name] in $file, line $.\n";
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
close FILE;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
return @func;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
sub make_prototype
|
|
Packit |
7d6a7d |
{
|
|
Packit |
7d6a7d |
my $f = shift;
|
|
Packit |
7d6a7d |
my @args = map { "@$_" } @{$f->{args}};
|
|
Packit |
7d6a7d |
my $proto;
|
|
Packit |
7d6a7d |
my $pTHX_ = exists $f->{flags}{n} ? "" : "pTHX_ ";
|
|
Packit |
7d6a7d |
$proto = "$f->{ret} $f->{name}" . "($pTHX_" . join(', ', @args) . ')';
|
|
Packit |
7d6a7d |
return $proto;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
sub format_version
|
|
Packit |
7d6a7d |
{
|
|
Packit |
7d6a7d |
my $ver = shift;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
$ver =~ s/$/000000/;
|
|
Packit |
7d6a7d |
my($r,$v,$s) = $ver =~ /(\d+)\.(\d{3})(\d{3})/;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
$v = int $v;
|
|
Packit |
7d6a7d |
$s = int $s;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
if ($r < 5 || ($r == 5 && $v < 6)) {
|
|
Packit |
7d6a7d |
if ($s % 10) {
|
|
Packit |
7d6a7d |
die "invalid version '$ver'\n";
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
$s /= 10;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
$ver = sprintf "%d.%03d", $r, $v;
|
|
Packit |
7d6a7d |
$s > 0 and $ver .= sprintf "_%02d", $s;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
return $ver;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
return sprintf "%d.%d.%d", $r, $v, $s;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
sub parse_version
|
|
Packit |
7d6a7d |
{
|
|
Packit |
7d6a7d |
my $ver = shift;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
if ($ver =~ /^(\d+)\.(\d+)\.(\d+)$/) {
|
|
Packit |
7d6a7d |
return ($1, $2, $3);
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
elsif ($ver !~ /^\d+\.[\d_]+$/) {
|
|
Packit |
7d6a7d |
die "cannot parse version '$ver'\n";
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
$ver =~ s/_//g;
|
|
Packit |
7d6a7d |
$ver =~ s/$/000000/;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
my($r,$v,$s) = $ver =~ /(\d+)\.(\d{3})(\d{3})/;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
$v = int $v;
|
|
Packit |
7d6a7d |
$s = int $s;
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
if ($r < 5 || ($r == 5 && $v < 6)) {
|
|
Packit |
7d6a7d |
if ($s % 10) {
|
|
Packit |
7d6a7d |
die "cannot parse version '$ver'\n";
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
$s /= 10;
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
return ($r, $v, $s);
|
|
Packit |
7d6a7d |
}
|
|
Packit |
7d6a7d |
|
|
Packit |
7d6a7d |
1;
|