#!/usr/bin/env perl
# ipfmt --- display IP addresses in multiple common formats
# Author: Noah Friedman <friedman@splode.com>
# Created: 2004-04-12
# Public domain

# $Id: ipfmt,v 1.3 2006/05/17 02:30:47 friedman Exp $

# Commentary:

# Need to add ipv6 support.

# Code:

$^W = 1; # enable warnings

use Socket;
use strict;

sub bin
{
  my ($n, $i) = (0,0);
  map { $n |= $_ << $i++ } reverse split (//, $_[0]);
  return $n;
}

sub parse_ip
{
  local $_ = shift;
  s/[ \t]//g;

  return unpack ("N", inet_aton ($_)) if (/^\d+\.\d+\.\d+\.\d+$/);
  return hex ($_)                     if (/[a-f]|^0x/i);
  return oct ($_)                     if (/^0[0-7]+$/);
  return bin ($_)                     if (/^[01]{32}$/);
  return (1<<31 | -$_)                if (/^-/);
  return $_;
}

sub sline
{
  return sprintf ("%-15s %10s %11s %-10s %-12s %s\n",
                  "IP", "base10u", "base10s", "base16", "base8", "base2")
    unless @_;

  my $ip     = parse_ip ($_[0]);
  my $signed = 1<<31 & $ip ? -(1<<31 ^ $ip) : $ip;

  sprintf ("%-15s %10u %11d 0x%08x 0%011o %032b\n",
           inet_ntoa (pack ("N", $ip)), $ip, $signed, $ip, $ip, $ip);
}

sub mline
{
  return unless @_;

  my $ip     = parse_ip ($_[0]);
  my $signed = 1<<31 & $ip ? -(1<<31 ^ $ip) : $ip;

  my $hex = sprintf ("%08x",   $ip);  $hex =~ s/([0-9a-f]{2})/$1 /g;
  my $oct = sprintf ("0%011o", $ip);  $oct =~ s/(\d{3})/$1 /g;
  my $bin = sprintf ("%032b",  $ip);  $bin =~ s/(\d{4})/$1 /g;

  sprintf (join ("\n",
                 "[%s]",
                 ($ip == $signed
                  ? "dec = %u"
                  : "dec = %u (%d)"),
                 "hex = %s",
                 "oct = %s",
                 "bin = %s",
                 "\n"),
           inet_ntoa (pack ("N", $ip)),
           ($ip == $signed ? $ip : ($ip, $signed)),
           $hex, $oct, $bin);
}

sub main
{
  local *fn = \&mline;

  if (@_ && $_[0] eq '-1')
    {
      shift @_;
      *fn = \&sline;
      print sline;
    }

  map { print fn($_) } @_;
}

main (@ARGV);

# eof
