:- use_module(library(dcg/basics)).
:- use_module(library(unicode)).
:- set_prolog_flag(double_quotes, codes).
cr_lf --> "\r\n". % [13, 10].
tab --> "\t". % [9].
null --> [0].
call_with_arg1(Arg, Callable) :- call(Callable, Arg).
ascii([C]) :- between(0, 127, C).
ascii_string([]).
ascii_string([C|Cs]) :- ascii([C]), ascii_string(Cs).
contains_substring([], []).
contains_substring(_, []).
contains_substring([X|Xs], [Y|Ys]) :-
(X = Y -> contains_substring(Xs, Ys)
; contains_substring(Xs, [Y|Ys])), !.
ascii_contains_substring([], []).
ascii_contains_substring(Xs, []) :- ascii_string(Xs).
ascii_contains_substring([X|Xs], [Y|Ys]) :-
ascii([X]),
(X = Y -> ascii_contains_substring(Xs, Ys)
; ascii_contains_substring(Xs, [Y|Ys])), !.
unascii([C|Cs]) -->
[C|Cs],
{
\+ascii_contains_substring([C|Cs], "\r\n"),
\+ascii_contains_substring([C|Cs], "\t"),
\+ascii_contains_substring([C|Cs], [0])
}.
unascii_without([C|Cs], ExcludedSubStrings), [C|Cs] -->
{
\+maplist(
ascii_contains_substring([C|Cs]),
ExcludedSubStrings)
},
unascii([C|Cs]), !.
last_line --> ".", cr_lf.
last_line(L) :- phrase(last_line, L).
text_block(Blk) -->
{
last_line(L),
\+ascii_contains_substring(Blk, L)
}, Blk.
type(T) --> { T = [_] }, unascii(T).
red_type --> "+".
user_name([]) --> [].
user_name(U) --> unascii(U).
selector([]) --> [].
selector(S) --> unascii(S).
host_part([H|Hs]) --> string_without(".\t", [H|Hs]).
host([H]) --> host_part(H).
host([H|Hs]) --> host_part(H), ".", host(Hs).
port(P) --> digits(P), { number_codes(N, P), N >= 0, N =< 65536 }.
dir_entity(
[type-Type, user-User, selector-Selector, host-Host, port-Port]
) -->
type(Type), user_name(User),
tab,
selector(Selector),
tab,
host(Host),
tab,
port(Port), cr_lf.
dir_entity(
[type-"+", user-User, selector-Selector, host-Host, port-Port]
) -->
red_type, user_name(User),
tab,
selector(Selector),
tab,
host(Host),
tab,
port(Port), cr_lf.
dir_entity([]) --> [].
menu_entity([]) --> last_line.
menu_entity([D|Ds]) --> dir_entity(D), dir_entity(Ds), last_line.