:- 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.