diff --git a/Changes b/Changes index a1915e5..a435409 100644 --- a/Changes +++ b/Changes @@ -1,5 +1,12 @@ Revision history for Perl extension NetAddr::IP +4.044 Wed May 18 14:47:34 PDT 2011 + added missing support for ->compactref(\@list) which is described + in the documentation but not implemented. + + Thanks to Rusty Bourland codebard@gmail.com for spotting this + and providing both a patch and test code + 4.043 Wed Apr 6 11:31:19 PDT 2011 Update documentation on the use of "adding constants to an IP address". diff --git a/IP.pm b/IP.pm index 760b0ee..8839464 100644 --- a/IP.pm +++ b/IP.pm @@ -4,7 +4,7 @@ use strict; #use diagnostics; -use NetAddr::IP::Lite 1.27 qw(Zero Zeros Ones V4mask V4net); +use NetAddr::IP::Lite 1.28 qw(Zero Zeros Ones V4mask V4net); use NetAddr::IP::Util 1.36 qw( sub128 inet_aton @@ -34,7 +34,7 @@ @ISA = qw(Exporter NetAddr::IP::Lite); -$VERSION = do { sprintf " %d.%03d", (q$Revision: 4.43 $ =~ /\d+/g) }; +$VERSION = do { sprintf " %d.%03d", (q$Revision: 4.44 $ =~ /\d+/g) }; =pod @@ -390,7 +390,9 @@ } sub compact { - return @{compactref(\@_)}; + return (ref $_[0] eq 'ARRAY') + ? compactref($_[0]) # Compact(\@list) + : @{compactref(\@_)}; # Compact(@list) or ->compact(@list) } *Compact = \&compact; @@ -1084,7 +1086,9 @@ =item C<$me-Ecompactref(\@list)> -As usual, a faster version of =item C<-Ecompact()> that returns a +=item C<$compacted_object_list = Compact(\@list)> + +As usual, a faster version of C<-Ecompact()> that returns a reference to a list. Note that this method takes a reference to a list instead. @@ -1097,39 +1101,57 @@ # or return []; # return [] unless @r; - return [] unless (my @unr = @{$_[0]}); + my @r; + { + my $unr = []; + my $args = $_[0]; - foreach(0..$#unr) { - $unr[$_]->{addr} = $unr[$_]->network->{addr}; + if (ref $_[0] eq __PACKAGE__ and ref $_[1] eq 'ARRAY') { + # ->compactref(\@list) + # + $unr = [$_[0], @{$_[1]}]; # keeping structures intact + } + else { + # Compact(@list) or ->compact(@list) or Compact(\@list) + # + $unr = $args; + } + + return [] unless @$unr; + + foreach(@$unr) { + $_->{addr} = $_->network->{addr}; + } + + @r = sort @$unr; } - my @r = sort @unr; my $changed; do { - $changed = 0; - for(my $i=0; $i <= $#r -1;$i++) { - if ($r[$i]->contains($r[$i +1])) { - splice(@r,$i +1,1); - ++$changed; - --$i; - } - elsif ((notcontiguous($r[$i]->{mask}))[1] == (notcontiguous($r[$i +1]->{mask}))[1]) { # masks the same - if (hasbits($r[$i]->network->{addr} ^ $r[$i +1]->network->{addr})) { # if not the same netblock - my $upnet = $r[$i]->copy; - $upnet->{mask} = shiftleft($upnet->{mask},1); - if ($upnet->contains($r[$i +1])) { # adjacent nets in next net up - $r[$i] = $upnet; - splice(@r,$i +1,1); - ++$changed; - --$i; - } - } else { # identical nets - splice(@r,$i +1,1); - ++$changed; - --$i; - } - } - } + $changed = 0; + for(my $i=0; $i <= $#r -1;$i++) { + if ($r[$i]->contains($r[$i +1])) { + splice(@r,$i +1,1); + ++$changed; + --$i; + } + elsif ((notcontiguous($r[$i]->{mask}))[1] == (notcontiguous($r[$i +1]->{mask}))[1]) { # masks the same + if (hasbits($r[$i]->{addr} ^ $r[$i +1]->{addr})) { # if not the same netblock + my $upnet = $r[$i]->copy; + $upnet->{mask} = shiftleft($upnet->{mask},1); + if ($upnet->contains($r[$i +1])) { # adjacent nets in next net up + $r[$i] = $upnet; + splice(@r,$i +1,1); + ++$changed; + --$i; + } + } else { # identical nets + splice(@r,$i +1,1); + ++$changed; + --$i; + } + } + } } while $changed; return \@r; } diff --git a/Lite/README b/Lite/README index 2b7df59..575fc19 100644 --- a/Lite/README +++ b/Lite/README @@ -148,7 +148,7 @@ hosts above the current objects start address. For instance, this code: - print NetAddr::IP::Lite->new('127.0.0.1') + 5; + print NetAddr::IP::Lite->new('127.0.0.1/8') + 5; will output 127.0.0.6/8. The address will wrap around at the broadcast back to the network address. This code: diff --git a/META.yml b/META.yml index 7f77f5b..4af6471 100644 --- a/META.yml +++ b/META.yml @@ -1,6 +1,6 @@ --- #YAML:1.0 name: NetAddr-IP -version: 4.043 +version: 4.044 abstract: Manages IPv4 and IPv6 addresses and subnets license: ~ author: diff --git a/t/v4-compact.t b/t/v4-compact.t index 0e630c2..feca1de 100644 --- a/t/v4-compact.t +++ b/t/v4-compact.t @@ -18,44 +18,93 @@ exit 0; } -print "1..2\n"; +print "1..9\n"; -my @ips; +my @ips1; for my $ip ('10.0.0.0', '11.0.0.0', '12.0.0.0') { - push @ips, NetAddr::IP->new($ip, 24)->split(32); + push @ips1, NetAddr::IP->new($ip, 24)->split(32); } for my $ip ('20.0.0.0', '30.0.0.0', '40.0.0.0') { - push @ips, NetAddr::IP->new($ip, 16)->split(28); + push @ips1, NetAddr::IP->new($ip, 16)->split(28); } -my @c = Compact(@ips); -my @m; +my @ips2; -for my $c (@c) { - push @m, grep { $c->addr eq $_->[0] and $c->mask eq $_->[1] } @r; +for my $num (0 .. 255) { + push @ips2, NetAddr::IP->new("192.168.$num.0", 24); } +my $ips2_compact = '192.168.0.0/16'; -if (@m == @c) { - print "ok 1\n"; -} -else { - print "not ok 1\n"; -} +# Compact(@) +# +compact_ips1_check(1, Compact(@ips1)); +compact_ips2_check(2, Compact(@ips2)); -@ips = (); +# ->compact(@) +# +compact_ips1_check(3, $ips1[0]->compact(@ips1[1..$#ips1])); +compact_ips2_check(4, $ips2[0]->compact(@ips2[1..$#ips2])); + +# Compact([]) +# +compact_ips1_check(5, @{Compact(\@ips1)}); +compact_ips2_check(6, @{Compact(\@ips2)}); + +# ->compactref([]) +# +compact_ips1_check(7, @{$ips1[0]->compactref([@ips1[1..$#ips1]])}); +compact_ips2_check(8, @{$ips2[0]->compactref([@ips2[1..$#ips2]])}); + +# duplicate IP +# +@ips1 = (); for my $ip (qw(1.1.1.1 1.1.1.1 1.1.1.1 1.1.1.1)) { - push(@ips, NetAddr::IP->new($ip)); + push(@ips1, NetAddr::IP->new($ip)); } -@c = NetAddr::IP::compact(@ips); +@c = NetAddr::IP::compact(@ips1); if (@c == 1 and $c[0]->cidr() eq '1.1.1.1/32') { - print "ok 2\n"; + print "ok 9\n"; } else { - print "not ok 2\n"; + print "not ok 9\n"; } + +###################################################################### +sub compact_ips1_check +{ + my $num = shift; + my @ips = shift; + + my @mips; + for my $ip (@ips) { + push @mips, grep { $ip->addr eq $_->[0] and $ip->mask eq $_->[1] } @r; + } + + if (@mips == @ips) { + print "ok $num\n"; + } + else { + print "not ok $num\n"; + } +} + + +###################################################################### +sub compact_ips2_check +{ + my $num = shift; + my @ips = shift; + + if (@ips == 1 and $ips[0] eq $ips2_compact) { + print "ok $num\n"; + } + else { + print "not ok $num\n"; + } +}