elvish_config/lib/moi/util/ip.elv

154 lines
3.0 KiB
Plaintext

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
}
}