% vim: syntax=prolog :- use_module(library(clpz)). :- use_module(library(format)). :- use_module(library(charsio)). :- use_module(library(serialization/abnf)). make_ip4(A, B, C, D, Addr) :- A #>= 0, A #=< 255, B #>= 0, B #=< 255, C #>= 0, C #=< 255, D #>= 0, D #=< 255, Addr #= ((A * 2^24) + (B * 2^16) + (C * 2^8) + D), ip4(Addr). ip4(Addr) :- Addr >= 0, Addr < 2^32. ip4_range(Addr, Range) :- ip4(Addr), Range in 0..32. ip_format(ip4(Addr), Str) :- make_ip4(A, B, C, D, Addr), phrase(format_("~w.~w.~w.~w", [A, B, C, D]), Str). ip_format(ip4_range(Addr, Range), Str) :- make_ip4(A, B, C, D, Addr), phrase(format_("~w.~w.~w.~w/~w", [A, B, C, D, Range]), Str). hexd(D) --> abnf_hexdig(D). hexd('a') --> "a". hexd('b') --> "b". hexd('c') --> "c". hexd('d') --> "d". hexd('e') --> "e". hexd('f') --> "f". int_(N) --> abnf_digit(D), { number_chars(V, [D]) }, int_(V, N). int_(N, N) --> []. int_(A, N) --> abnf_digit(D), { number_chars(V, [D]), A1 is A*10+V }, int_(A1, N). xint_(N) --> hexd(D), { number_chars(V, ['0', 'x', D]) }, xint_(V, N). xint_(N, N) --> []. xint_(A, N) --> hexd(D), { number_chars(V, ['0', 'x', D]), A1 is A*16+V }, xint_(A1, N). %ip4_num(V) --> int_(Ds, Ds), { number_chars(V, Ds), V >= 0, V =< 255 }. ip4_num(V) --> int_(V), { V >= 0, V =< 255 }. ip4_syntax(A, B, C, D) --> ip4_num(A), ".", ip4_num(B), ".", ip4_num(C), ".", ip4_num(D). ip4_range_syntax(A, B, C, D, R) --> ip4_syntax(A, B, C, D), "/", int_(R), { R >= 0, R =< 32 }. ip4_parse(Str, Ip) :- phrase(ip4_syntax(A, B, C, D), Str), make_ip4(A, B, C, D, Addr), Ip = ip4(Addr). ip4_range_parse(Str, IpR) :- phrase(ip4_range_syntax(A, B, C, D, Range), Str), make_ip4(A, B, C, D, Addr), IpR = ip4_range(Addr, Range). make_ip6(A, B, C, D, E, F, G, H, Addr) :- A #>= 0, A #=< 65335, B #>= 0, B #=< 65335, C #>= 0, C #=< 65335, D #>= 0, D #=< 65335, E #>= 0, E #=< 65335, F #>= 0, F #=< 65335, G #>= 0, G #=< 65335, H #>= 0, H #=< 65335, Addr #= (A * 2^56) + (B * 2^48) + (C * 2^40) + (D * 2^32) + (E * 2^24) + (F * 2^16) + (G * 2^8) + H, ip6(Addr). ip6(Addr) :- Addr >= 0, Addr < 2^128. ip6_syntax(A, B, C, D, E, F, G, H) --> ip6_num(A), ":", ip6_num(B), ":", ip6_num(C), ":", ip6_num(D), ":", ip6_num(E), ":", ip6_num(F), ":", ip6_num(G), ":", ip6_num(H). ip6_num(D) --> xint_(D), { D >= 0, D =< 65535 }. ip6_parse(Str, Ip) :- phrase(ip6_syntax(A, B, C, D, E, F, G, H), Str), make_ip6(A, B, C, D, E, F, G, H, Addr), Ip = ip6(Addr). ip_parse(Str, Obj) :- ( phrase(ip4_syntax(A, B, C, D), Str) -> make_ip4(A, B, C, D, Addr), Obj = ip4(Addr) ; ( phrase(ip4_range_syntax(A, B, C, D, R), Str) -> make_ip4(A, B, C, D, Ip), Obj = ip4_range(Ip, R) ; phrase(ip6_syntax(A, B, C, D, E, F, G, H), Str), make_ip6(A, B, C, D, E, F, G, H, Addr), Obj = ip6(Addr) ) ).