#!/usr/bin/perl package PatchIndexer; use Data::Dumper; use Clone qw(clone); use warnings; use strict; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK); require Exporter; @ISA = qw(Exporter AutoLoader); @EXPORT = qw( parseIndex printIndex selectPatches ); sub parseIndex { my $fh = shift; our (@data, $patch, @ver, @pn, $desc, $comment); while(my $i = <$fh>) { #print "DATA: $i"; if(0) { # These lines exists for patching only # # } elsif($i =~ /^\s*$/) { # Ignore whitespace #print "White: $i"; getEntry(); storeEntry() if(length($patch) or length($comment)); #cleanEntry(); } elsif($i =~ /^\@patch\s+(\S+)\s+$/) { cleanEntry(); $patch = $1; chomp $patch; } elsif($i =~ /^\@ver\s+(\S+)\s+to\s+(\S+)\s+$/) { my $min = $1; my $max = $2; chomp $min; chomp $max; #print "Pushing ver $1 $2\n"; push @ver, [$1,$2]; } elsif($i =~ /^\@pn\s+(\S+)\s+$/) { my $mypn = $1; chomp $mypn; push @pn, $mypn; } elsif($i =~ /^\@\@\s+(.*)\s+$/) { # Do not chomp descriptions $desc .= $1."\n"; } elsif($i =~ /^#(.*)\s+$/) { # Do not chomp comments $comment .= $1."\n"; } else { print "Bad! $i\n"; } } storeEntry() if(length($patch) or length($comment)); #print Dumper(@data); return @data; sub getEntry { my %entry; $entry{patch} = $patch if (length($patch) > 0); $entry{ver} = \@ver if (@ver); $entry{pn} = \@pn if (@pn); chomp $desc; $entry{desc} = $desc if (length($desc) > 0); chomp $comment; $entry{comment} = $comment if (length($comment) > 0); #print Dumper(\%entry); return %entry; } sub storeEntry { my %entry = getEntry(); my $entry = clone(\%entry); #print Dumper(\%entry); push @data, $entry; cleanEntry(); } sub cleanEntry { $patch = ''; @ver = (); @pn = (); $desc = ''; $comment = ''; } } sub printIndex { $_ = shift; my @index = @{ $_ }; my $os = ''; foreach my $i (@index) { #print Dumper($i); $os .= sprintf "\@patch %s\n", $i->{patch} if $i->{patch}; foreach $_ ( @{ $i->{ver} } ) { my @v = @$_; $os .= sprintf "\@ver %s to %s\n", $v[0], $v[1]; } foreach my $pn ( @{ $i->{pn} } ) { $os .= sprintf "\@pn %s\n", $pn; } if($i->{desc}) { my $desc = $i->{desc}; $desc =~ s/^/@@ /gm; $os .= $desc."\n"; } if($i->{comment}) { my $comment = $i->{comment}; $comment =~ s/^/#/gm; $os .= $comment."\n"; } $os .= "\n"; } chomp $os; return $os; } sub selectPatches { my (@index, $pn, $pv, @newindex); $_ = shift; @index = @{ $_ }; $pn = shift; { $_ = shift; my @_pv = split /\./, $_; until($#_pv >= 3) { push @_pv, 0; }; $pv = join('.', @_pv); } #printf "PN: %s\n", $pn; #printf "PV: %s\n", $pv; INDEX: foreach my $i (@index) { my ($match_pn, $match_pv); $match_pn = $match_pv = 0; TESTPN: foreach my $testpn ( @{ $i->{pn} } ) { #printf("testing pn='%s' against '%s' ", $pn, $testpn); if("$pn" eq "$testpn") { #printf("PASS\n"); $match_pn = 1; last TESTPN; } else { #printf("FAIL\n"); } } TESTPV: foreach my $testpv ( @{ $i->{ver} } ) { my @v = @$testpv; #printf("testing pv='%s' against '%s'-'%s' ", $pv, $v[0], $v[1]); if(pvGte($pv,$v[0]) and pvLte($pv,$v[1])) { #printf("PASS\n"); $match_pv = 1; last TESTPV; } else { #printf("FAIL\n"); } } # Special case for comments if(defined($i) and defined($i->{comment}) and length($i->{comment})) { $match_pn = $match_pv = 1; } if($match_pn == 1 and $match_pv == 1) { #printf "match on %s\n", $i->{patch}; push @newindex, $i; } else { #printf "no match on %s\n", $i->{patch}; } } return @newindex; } sub pvCmp { my (@v1, @v2); @v1 = split(/\./, shift); @v2 = split(/\./, shift); for(my $i = 0; $i < 4; $i++) { if($v1[$i] > $v2[$i]) { return 1; } elsif($v1[$i] < $v2[$i]) { return -1; } } return 0; } sub pvGt { return pvCmp(shift, shift) > 0; } sub pvLt { return pvCmp(shift, shift) < 0; } sub pvGte { return pvCmp(shift, shift) >= 0; } sub pvLte { return pvCmp(shift, shift) <= 0; }