use re use str fn is-ipv4 [arg]{ if (not (re:match '^([0-9]{1,3}\.){3}[0-9]{1,3}$' $arg)) { put $false } else { use ./list not (str:split '.' $arg | list:contains [p]{ > $p 255 }) } } fn is-ipv6 [arg]{ var p = '[0-9a-fA-F]{1,4}' var g1 g2 = '('$p':)' '(:'$p')' var cases = [ $g1'{7,7}'$p $g1'{1,7}:' $g1'{1,6}:'$p $g1'{1,5}'$g2'{1,2}' $g1'{1,4}'$g2'{1,3}' $g1'{1,3}'$g2'{1,4}' $g1'{1,2}'$g2'{1,5}' $p':'$g2'{1,6}' ':'$g2'{1,7}' '::' ] var r = '^('(str:join '|' $cases)')$' put (re:match $r $arg) } fn is-ip [arg]{ or (is-ipv4 $arg) (is-ipv6 $arg) } fn -long-part6 [p]{ use str set p = (str:to-lower $p) var c = (- 4 (count $p)) put (repeat $c '0' | str:join '')$p } fn -middle-part6 [p]{ while (and (> (count $p) 1) (eq $p[0] 0)) { set p = $p[1..] } put $p } fn -find-max0 [parts]{ use ./list var idx s = -1 1 var ci cs f = -1 0 $false list:loop [i p]{ if (eq $p 0) { condition:call $f { set cs = (+ $cs 1) } { set ci cs f = $i 1 $true } } elif $f { set f = $false if (> $cs $s) { set idx s = $ci $cs } } } $parts if (and $f (> $cs $s)) { set idx s = $ci $cs } put $idx $s } fn long6 [ip]{ if (not (is-ipv6 $ip)) { fail 'Not an IPv6' } if (eq $ip '::') { repeat 8 '0000' | str:join ':' return } var c = (- 7 (str:count $ip ':')) if (> $c 0) { var i = (str:index $ip '::') var z = (repeat $c ':' | str:join '') set ip = (str:join '' [$ip[..$i] $z $ip[{$i}..]]) } str:split ':' $ip | each $-long-part6~ | str:join ':' } fn middle6 [ip]{ str:split ':' (long6 $ip) | each $-middle-part6~ | str:join ':' } fn short6 [ip]{ var parts = [(str:split ':' (middle6 $ip))] var i s = (-find-max0 $parts) if (>= $i 0) { var left right = $parts[..$i] $parts[(+ $i $s)..] if (== (count $left) 0) { set left = [''] } if (== (count $right) 0) { set right = [''] } set parts = [$@left '' $@right] } str:join ':' $parts } fn is-ip [arg]{ or (is-ipv4 $arg) (is-ipv6 $arg) } fn -cmp [e1 e2]{ use ./list use ./condition var c = 0 list:loop [i p1]{ var p2 = $e2[$i] set c = (condition:cset (< $p1 $p2) -1 (condition:cset (> $p1 $p2) 1 0)) if (!= $c 0) { break } } $e1 put $c } fn cmp4 [ip1 ip2]{ if (or (not (is-ipv4 $ip1)) (not (is-ipv4 $ip2))) { fail 'Not an IPv4 '$ip1' → '$ip2 } -cmp [(str:split . $ip1)] [(str:split . $ip2)] } fn cmp6 [ip1 ip2]{ if (or (not (is-ipv6 $ip1)) (not (is-ipv6 $ip2))) { fail 'Not an IPv6: '$ip1' → '$ip2 } -cmp [(str:split : (middle6 $ip1))] [(str:split : (middle6 $ip2))] } fn cmp [ip1 ip2]{ if (is-ipv4 $ip1) { if (is-ipv4 $ip2) { cmp4 $ip1 $ip2 } else { put -1 } } elif (is-ipv6 $ip1) { if (is-ipv4 $ip2) { put 1 } elif (is-ipv6 $ip2) { cmp6 $ip1 $ip2 } else { put -1 } } else { fail 'Not an IP: '$ip1' → '$ip2 } }