zejames has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks,

I have just written a little function that translates a network mask in /xx notation to a network mask in xx.xx.xx.xx notation. My code follows :
# This function takes a number in paramater (eg 24) and # returns the corresponding mask in longer format # (eg 255.255.0.0) sub mask_short_to_long { my $short_mask = shift; my ($bin, $num, @mask); $bin = "1" x $short_mask . "0" x (32 - $short_mask); for my $i (0..31) { $num += substr($bin,31 - $i,1) * (2 ** $i); } for my $i (0..3) { unshift @mask, (($num >> ($i * 8)) & 0xFF); } return join('.',@mask); }
But I just feel something more elegant and shorter could be done.

Any idea to improve it?

Any one-liner? ;))

Zejames

Replies are listed 'Best First'.
Re: Shorter code ?
by jmcnamara (Monsignor) on Mar 11, 2002 at 13:55 UTC

    How about something like this:
    sub mask_short_to_long1 { my @octets = unpack "C4", pack "V", 2 ** $_[0] -1 ; @octets = map {unpack "C", pack "b8", sprintf "%08b", $_} @oct +ets; return join '.', @octets; }

    Or, this for Perl versions before 5.6.0 (i.e., without "%b"):

    sub mask_short_to_long2 { my @octets = unpack "b8b8b8b8", pack "V", 2 ** $_[0] -1 ; @octets = map {ord pack "B8", $_} @octets; return join '.', @octets; }
    Or, a more direct approach:
    sub mask_short_to_long3 { my $mask = shift; my @octets = (0,0,0,0); for (@octets) { $_ = $mask > 8 ? 255 : 256 - 2**(8-$mask); $mask = $mask > 8 ? $mask -8 : 0; } join '.', @octets; }

    It is a little bit long for a one-liner but since you asked: perl -le'print+join".",map{ord pack"B8",$_}unpack"b8"x4,pack"V",-1+2**pop' num

    --
    John.

      Whow !!! Thanks !!

      That is why I love perl...

      zejames
Re: Shorter code ?
by Kanji (Parson) on Mar 11, 2002 at 14:22 UTC
    Any idea to improve it?

    Don't reinvent the wheel. :-)

    Any one-liner? ;))

    Using Net::Netmask (alt.)...

    sub mask_short_to_long { Net::Netmask->new( "0.0.0.0/" . shift )->mask + } # or as a real one-liner! :) perl -MNet::Netmask -le 'print Net::Netmask->new( "0.0.0.0/" . shift ) +->mask' 24

        --k.


      One liner, perhaps. Less code, no way! Not when the module you're requiring is 400 lines of code. :-P

      -fuzzyping