ref: 04d647955b3d83e2fb3731d63887ae499809141e
dir: /libstd/ipparse.myr/
use "die.use" use "intparse.use" use "option.use" use "strfind.use" use "types.use" use "chartype.use" use "fmt.use" use "slcp.use" use "slfill.use" use "sleq.use" /* FIXME: needed for decls which should be pulled in as hidden */ use "hasprefix.use" use "utf.use" pkg std = type netaddr = union `Ipv4 byte[4] `Ipv6 byte[16] ;; const ipparse : (ip : byte[:] -> option(netaddr)) const ip4parse : (ip : byte[:] -> option(netaddr)) const ip6parse : (ip : byte[:] -> option(netaddr)) ;; const ipparse = {ip match strfind(ip, ":") | `Some _: -> ip6parse(ip) | `None: -> ip4parse(ip) ;; } const ip4parse = {ip var a, b, c, d var ok /* var addr var last : size var x : option(int32) var val : int32 /* need int32 to check for overflow */ var i var j : size */ (a, ip, ok) = num(ip, 0, 255, 10, '.', true) (ip, ok) = delim(ip, '.', ok) (b, ip, ok) = num(ip, 0, 255, 10, '.', ok) (ip, ok) = delim(ip, '.', ok) (c, ip, ok) = num(ip, 0, 255, 10, '.', ok) (ip, ok) = delim(ip, '.', ok) (d, ip, ok) = num(ip, 0, 255, 10, '.', ok) if ok && ip.len == 0 -> `Some (`Ipv4 [a, b, c, d]) else -> `None ;; } const ip6parse = {ip var val : byte[16] var expand, split var v, ok var i, nseg ok = true expand = false split = 0 if ip.len > 2 && std.sleq(ip[:2], "::") expand = true split = 0 ;; nseg = 0 for i = 0; ip.len > 0 && ok; i++ /* parse 'num' segment */ (v, ip, ok) = num(ip, 0, 65536, 16, ':', ok) nseg++ if ip.len == 0 || nseg == 8 break ;; (ip, ok) = delim(ip, ':', ok) /* only one '::' allowed once */ if ip.len > 0 && ip[0] == ':'castto(byte) && !expand expand = true split = i (ip, ok) = delim(ip, ':', ok) ;; /* pack it into the bytes */ val[i*2] = ((v & 0xff00) >> 8) castto(byte) val[i*2 + 1] = (v & 0xff) castto(byte) ;; if ok && ip.len == 0 if expand expandsplit(val[:], split, i) elif nseg != 8 -> `None ;; -> `Some `Ipv6 val else -> `None ;; } /* take "a:b::c:d" and expand it to "a:b:0:0:...:0:c:d" */ const expandsplit = {ip, split, len var width width = 16 - len std.slcp(ip[split:len], ip[split+width:len+width]) std.slfill(ip[len:len+width], 0) } const delim = {ip, sep, ok if ip.len > 0 && ip[0] == sep castto(byte) -> (ip[1:], ok) else -> ("", false) ;; } generic num = {ip, lo, hi, base, sep, ok -> (@a::(numeric,integral), byte[:], bool) var len if !ok -> (0, "", false) ;; for len = 0; len < ip.len; len++ if ip[len] == sep castto(byte) break ;; ;; match intparsebase(ip[:len], base) | `std.Some v: if v < lo || v > hi -> (0, "", false) ;; -> (v castto(@a::(numeric,integral)), ip[len:], true) | `std.None: -> (0, "", false) ;; }