September Morn Update

This commit is contained in:
Ingy döt Net 2019-09-12 10:33:56 -07:00
parent 4e2d22a71d
commit aac6731f2c
6856 changed files with 141342 additions and 21127 deletions

View file

@ -1,7 +1,7 @@
The purpose of this task is to demonstrate parsing of text-format IP addresses, using IPv4 and IPv6.
Taking the following as inputs:
{| border="1" cellspacing="0" cellpadding=2
::: {| border="5" cellspacing="0" cellpadding=2
|-
|127.0.0.1
|The "localhost" IPv4 address
@ -22,6 +22,7 @@ Taking the following as inputs:
|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. ::ffff: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.

View file

@ -0,0 +1 @@
--- {}

View file

@ -15,16 +15,16 @@ grammar IP_Addr {
| <h16> +% ':' <?{ $<h16> == 8 }>
{ @*by16 = @$<h16> }
| [ (<h16>) +% ':']? '::' (<h16>) +% ':' <?{ @$0 + @$1 <= 8 }>
{ @*by16 = @$0, '0' xx 8 - (@$0 + @$1), @$1 }
| [ (<h16>) +% ':']? '::' [ (<h16>) +% ':' ]? <?{ @$0 + @$1 ≤ 8 }>
{ @*by16 = |@$0, |('0' xx 8 - (@$0 + @$1)), |@$1 }
| '::ffff:' <IPv4>
{ @*by16 = '0' xx 5, 'ffff', by8to16 @*by8 }
{ @*by16 = |('0' xx 5), 'ffff', |(by8to16 @*by8) }
}
token d8 { (\d+) <?{ $0 < 256 }> }
token d16 { (\d+) <?{ $0 < 65536 }> }
token h16 { (<:hexdigit>+) <?{ @$0 <= 4 }> }
token h16 { (<:hexdigit>+) <?{ @$0 4 }> }
token port {
':' <d16> { $*port = +$<d16> }
@ -70,7 +70,7 @@ for @cases -> $addr {
say $addr;
if @*by16 {
say " IPv6: ", @*by16».map({:16(~$_)})».fmt("%04x").join;
say " IPv6: ", @*by16.map({:16(~$_)})».fmt("%04x").join;
say " Port: ", $*port if $*port;
}
elsif @*by8 {

View file

@ -0,0 +1,147 @@
function parse_ip(string txt)
sequence r
integer dot = find('.',txt),
colon = find(':',txt),
openbr = find('[',txt),
closebr = find(']',txt)
if colon=5 and txt[1..4] = "http" then
txt = trim(txt[6..$],"/")
return parse_ip(txt)
end if
bool ipv6 = openbr or dot=0 or (colon and colon<dot)
if ipv6 then
sequence res = repeat(0,8)
if openbr then
if openbr!=1 or closebr<openbr then return 0 end if
r = scanf(txt[closebr+1..$],":%d")
if length(r)!=1 then return 0 end if
atom port = r[1][1]
if port<0 or port>65535 then return 0 end if
res &= port
txt = txt[2..closebr-1]
end if
if dot then
colon = rfind(':',txt)
if colon>dot then return 0 end if
object r4 = parse_ip(txt[colon+1..$])
if not sequence(r4) or length(r4)!=4 then return 0 end if
res[7] = r4[1]*#100+r4[2]
res[8] = r4[3]*#100+r4[4]
txt = txt[1..colon-1+(txt[colon-1]=':')]
dot = 2
end if
sequence r8 = {}
integer ip = 0
while length(txt) do
colon = find(':',txt)
if colon=1 then
if ip then return 0 end if
ip = length(r8)+1
txt = txt[2+(length(r8)=0)..$]
else
r = scanf(txt[1..colon-1],"%x")
if length(r)!=1 then return 0 end if
atom r11 = r[1][1]
if r11<0 or r11>#FFFF then return 0 end if
r8 &= r11
if colon=0 then exit end if
txt = txt[colon+1..$]
end if
end while
if ip then
if length(r8)>=(8-dot) then return 0 end if
r8[ip..ip-1] = repeat(0,(8-dot)-length(r8))
else
if length(r8)!=8-dot then return 0 end if
end if
res[1..8-dot] = r8
return res
end if
-- ipv4:
if dot=0 or (colon and colon<dot) then return 0 end if
r = scanf(txt[1..colon-1],"%d.%d.%d.%d")
if length(r)!=1 then return 0 end if
r = r[1]
for i=1 to length(r) do
if r[i]<0 or r[i]>255 then return 0 end if
end for
if colon then
sequence r2 = scanf(txt[colon+1..$],"%d")
if length(r2)!=1 then return 0 end if
atom port = r2[1][1]
if port<0 or port>65535 then return 0 end if
r &= port
end if
return r
end function
constant tests = {{"127.0.0.1",{127,0,0,1}},
{"127.0.0.1:80",{127,0,0,1,80}},
{"::1",{0,0,0,0,0,0,0,1}},
{"[::1]:80",{0,0,0,0,0,0,0,1,80}},
{"2605:2700:0:3::4713:93e3",{#2605,#2700,0,3,0,0,#4713,#93e3}},
{"[2605:2700:0:3::4713:93e3]:80",{#2605,#2700,0,3,0,0,#4713,#93e3,80}},
{"::ffff:192.168.173.22",{0,0,0,0,0,#ffff,#c0a8,#ad16}},
{"[::ffff:192.168.173.22]:80",{0,0,0,0,0,#ffff,#c0a8,#ad16,80}},
{"1::",{1,0,0,0,0,0,0,0}},
{"[1::]:80",{1,0,0,0,0,0,0,0,80}},
{"::",{0,0,0,0,0,0,0,0}},
{"[::]:80",{0,0,0,0,0,0,0,0,80}},
{"192.168.0.1",{192,168,0,1}},
{"2001:db8:85a3:0:0:8a2e:370:7334",{#2001,#db8,#85a3,0,0,#8a2e,#370,#7334}},
{"2001:db8:85a3::8a2e:370:7334",{#2001,#db8,#85a3,0,0,#8a2e,#370,#7334}},
{"[2001:db8:85a3:8d3:1319:8a2e:370:7334]:443",{#2001,#db8,#85a3,#8d3,#1319,#8a2e,#370,#7334,443}},
{"256.0.0.0",0},
{"g::1",0},
{"::ffff:127.0.0.0.1",0},
{"a::b::1",0},
{"0000",0},
{"0000:0000",0},
{"0000:0000:0000:0000:0000:0000:0000:0000",{0,0,0,0,0,0,0,0}},
{"0000:0000:0000::0000:0000",{0,0,0,0,0,0,0,0}},
{"0000::0000::0000:0000",0},
{"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",{#ffff,#ffff,#ffff,#ffff,#ffff,#ffff,#ffff,#ffff}},
{"ffff:ffff:ffff:fffg:ffff:ffff:ffff:ffff",0},
{"fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",{#fff,#ffff,#ffff,#ffff,#ffff,#ffff,#ffff,#ffff}},
{"fff:ffff:0:ffff:ffff:ffff:ffff:ffff",{#fff,#ffff,0,#ffff,#ffff,#ffff,#ffff,#ffff}},
{"2001:0db8:0:0:0:0:1428:57ab",{#2001,#0db8,0,0,0,0,#1428,#57ab}},
{"2001:0db8::1428:57ab",{#2001,#0db8,0,0,0,0,#1428,#57ab}},
{"2001:0db8:0:0:8d3:0:0:0",{#2001,#0db8,0,0,#8d3,0,0,0}},
{"2001:0db8:0:0:8d3::",{#2001,#0db8,0,0,#8d3,0,0,0}},
{"2001:0db8::8d3:0:0:0",{#2001,#0db8,0,0,#8d3,0,0,0}},
{"http://127.0.0.1/",{127,0,0,1}},
{"http:",0},
{"http:/2001:db8:3:4::127.0.2.0",{#2001,#db8,3,4,0,0,#7F00,#200}},
{"::192.168.0.1",{0,0,0,0,0,0,#C0A8,1}},
{"::ffff:0:255.255.255.255",{0,0,0,0,#ffff,0,#ffff,#ffff}},
{"",0},
{"ffffffffffffffffffffffffffffffff::",0},
{"[1::]:9999999999999999999999999999",0},
{"I think that's enough tests for now",0}}
for i=1 to length(tests) do
{string ip, object expected} = tests[i]
object actual = parse_ip(ip)
if actual!=expected then
?{ip,actual,expected}
?9/0
end if
string addr
if actual=0 then
addr = "**not a valid ip address**"
else
if remainder(length(actual),2) then
actual[$] = sprintf(", port %d",actual[$])
else
actual = append(actual,"")
end if
if length(actual)=5 then
addr = sprintf("ivp4 address: %02x%02x%02x%02x%s",actual)
elsif length(actual)=9 then
addr = sprintf("ivp6 address: %04x%04x%04x%04x%04x%04x%04x%04x%s",actual)
else
?9/0
end if
end if
printf(1,"%45s %s\n",{ip,addr})
end for