Parse an IP Address

From Rosetta Code
Revision as of 15:44, 28 September 2011 by Rdm (talk | contribs)
Parse an IP Address is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

The purpose of this task is to demonstrate parsing of text-format IP addresses, using IPv4 and IPv6. The task itself should be trivial, the role of this page is primarily informative.

Taking the following as inputs:

127.0.0.1 The "localhost" IPv4 address
127.0.0.1:80 The "localhost" IPv4 address, with a specified port (80)
::1 The "localhost" IPv6 address
[::1]:80 The "localhost" IPv6 address, with a specified port (80)
2605:2700:0:3::4713:93e3 Rosetta Code's primary server's public IPv6 address
[2605:2700:0:3::4713:93e3]:80 Rosetta Code's primary server's public IPv6 address, with a specified port (80)

Emit each described IP address as a hexadecimal integer representing the address, the address space, and the port number specified, if any. In languages where variant result types are clumsy, the result should be ipv4 or ipv6 address number, something which says which address space was represented, port number and something that says if the port was specified.

For example 127.0.0.1 has the address number 7F000001 (2130706433 decimal) in the ipv4 address space.  ::127.0.0.1 represents the same address in the ipv6 address space where it has the address number FFFF7F000001 (281472812449793 decimal). Meanwhile ::1 has address number 1 and serves the same purpose in the ipv6 address space that 127.0.0.1 serves in the ipv4 address space.

PicoLisp

<lang PicoLisp># Return a cons pair of address and port: (address . port) (de ipAddress (Adr)

  (use (@A @B @C @D @Port)
     (cond
        ((match '("[" @A "]" ":" @Port) Adr)
           (adrIPv6 (split @A ":") @Port) )
        ((match '("[" @A "]") Adr)
           (adrIPv6 (split @A ":")) )
        ((match '(@A ":" @B ":" @C) Adr)
           (adrIPv6 (cons @A @B (split @C ":"))) )
        ((match '(@A "." @B "." @C "." @D ":" @Port) Adr)
           (adrIPv4 (list @A @B @C @D) @Port) )
        ((match '(@A "." @B "." @C "." @D) Adr)
           (adrIPv4 (list @A @B @C @D)) )
        (T (quit "Bad IP address" (pack Adr))) ) ) )

(de adrIPv4 (Lst Port)

  (cons
     (sum >> (-24 -16 -8 0) (mapcar format Lst))
     (format Port) ) )

(de adrIPv6 (Lst Port)

  (cons
     (sum >>
        (-112 -96 -80 -64 -48 -32 -16 0)
        (mapcan
           '((X)
              (if X
                 (cons (hex X))
                 (need (- 9 (length Lst)) 0) ) )  # Handle '::'
           (cons (or (car Lst) "0") (cdr Lst)) ) )
     (format Port) ) )</lang>

Test: <lang PicoLisp>(for A

  (quote
     "127.0.0.1"
     "127.0.0.1:80"
     "::1"
     "[::1]:80"
     "2605:2700:0:3::4713:93e3"
     "[2605:2700:0:3::4713:93e3]:80" )
  (let I (ipAddress (chop A))
     (tab (-29 34 40 7)
        A
        (hex (car I))
        (format (car I))
        (cdr I) ) ) )</lang>

Output:

127.0.0.1                                              7F000001                              2130706433
127.0.0.1:80                                           7F000001                              2130706433     80
::1                                                           1                                       1
[::1]:80                                                      1                                       1     80
2605:2700:0:3::4713:93e3       260527000000000300000000471393E3  50537416338094019778974086937420469219
[2605:2700:0:3::4713:93e3]:80  260527000000000300000000471393E3  50537416338094019778974086937420469219     80