2
3:- module(utils,
4 [
5 get_opt/3,
6 halt_success/0,
7 halt_error/0,
8 show_type/1,
9 type_of/2,
10 string_from_codes/4,
11 atom_from_codes/4,
12 code_list/4,
13 string_from_chars/4,
14 atom_from_chars/4,
15 char_list/4,
16 whitespace/2,
17 opt_whitespace/2,
18 space/2,
19 opt_space/2,
20 blank_line/2,
21 alphanum_char/3,
22 alphanum_code/3,
23 parse_num_char/3,
24 parse_num_code/3,
25 n_chars/3,
26 concat_string_list/2,
27 concat_string_list/3,
28 concat_string_list_spaced/2,
29 split_spaces/2,
30 split_newlines/2,
31 last_element/2,
32 nth_element/3,
33 slice/4,
34 find_on_path/2,
35 shell_path/1,
36 shell_quote/2,
37 shell_wrap/2,
38 shell_comment/2,
39 shell_eval/2,
40 shell_eval_str/2,
41 echo_wrap/2,
42 shell_echo_wrap/2,
43 file_directory_slash/2,
44 newlines_to_spaces/2,
45 to_string/2,
46 equal_as_strings/2,
47 makefile_var_char/3,
48 makefile_var_chars/3,
49 makefile_var_atom_from_chars/3,
50 makefile_var_string_from_chars/3,
51 makefile_var_code/3,
52 makefile_var_codes/3,
53 makefile_var_atom_from_codes/3,
54 makefile_var_string_from_codes/3,
55 biomake_private_filename/3,
56 biomake_private_filename_dir_exists/3,
57 open_biomake_private_file/4,
58 open_biomake_private_file/5
59 ]). 60
61get_opt(Name,Val,Opts) :-
62 Template =.. [Name,Val],
63 member(Template,Opts),
64 !.
65
66halt_success :- halt(0).
67halt_error :- halt(2).
68
69string_from_codes(S,XS) --> {string_codes(XS,XL)}, code_list(C,XL), {C\=[], string_codes(S,C)}.
70atom_from_codes(S,XS) --> {string_codes(XS,XL)}, code_list(C,XL), {C\=[], atom_codes(S,C)}.
71
72code_list([C|Cs],XL) --> [0'\\,C], {C\=0'\n,member(C,XL)}, !, code_list(Cs,XL). 73code_list([C|Cs],XL) --> [C], {C\=0'\n,forall(member(X,XL),C\=X)}, code_list(Cs,XL).
74code_list([],_) --> [].
75
76string_from_chars(S,XS) --> {string_chars(XS,XL)}, char_list(C,XL), {C\=[], string_chars(S,C)}.
77atom_from_chars(S,XS) --> {string_chars(XS,XL)}, char_list(C,XL), {C\=[], atom_chars(S,C)}.
78
79char_list([C|Cs],XL) --> ['\\',C], {C\='\n',member(C,XL)}, char_list(Cs,XL). 80char_list([C|Cs],XL) --> [C], {C\='\n',forall(member(X,XL),C\=X)}, char_list(Cs,XL).
81char_list([],_) --> [].
82
83whitespace --> "\\\n", !, opt_whitespace. 84whitespace --> " ", !, opt_whitespace.
85whitespace --> "\t", !, opt_whitespace.
86
87opt_whitespace --> whitespace.
88opt_whitespace --> !.
89
90space --> "\\\n", !, opt_space. 91space --> " ", !, opt_space.
92
93opt_space --> space.
94opt_space --> !.
95
96blank_line --> "\n", !.
97blank_line --> space, opt_whitespace, "\n", !.
98
99alphanum_char(X) --> [X],{X@>='A',X@=<'Z'},!.
100alphanum_char(X) --> [X],{X@>='a',X@=<'z'},!.
101alphanum_char(X) --> parse_num_char(X),!.
102parse_num_char(X) --> [X],{X@>='0',X@=<'9'}.
103
104alphanum_code(X) --> [X],{X@>=0'A,X@=<0'Z},!. 105alphanum_code(X) --> [X],{X@>=0'a,X@=<0'z},!. 106alphanum_code(X) --> parse_num_code(X),!.
107parse_num_code(X) --> [X],{X@>=0'0,X@=<0'9}. 108
109n_chars(N,_,[]) :- N =< 0, !.
110n_chars(N,C,[C|Ls]) :- Ndec is N - 1, n_chars(Ndec,C,Ls), !.
111
112concat_string_list_spaced(L,S) :- concat_string_list(L,S," ").
113concat_string_list(L,S) :- concat_string_list(L,S,"").
114concat_string_list([],"",_).
115concat_string_list([S],S,_).
116concat_string_list([L|Ls],F,Sep) :- concat_string_list(Ls,R,Sep), string_concat(L,Sep,Lsep), string_concat(Lsep,R,F).
117
118split_spaces(S,L) :-
119 split_string(S," \t"," \t",L).
120
121split_newlines(S,L) :-
122 string_codes(S,C),
123 phrase(split_unescaped_newlines(A),C),
124 maplist(string_codes,L,A).
125
126split_unescaped_newlines([['\\','\n'|Cs]|L]) --> ['\\','\n'], !, split_unescaped_newlines([Cs|L]).
127split_unescaped_newlines([[]|L]) --> ['\n'], !, split_unescaped_newlines(L).
128split_unescaped_newlines([[C|Cs]|L]) --> [C], !, split_unescaped_newlines([Cs|L]).
129split_unescaped_newlines([[]]) --> [].
130
131last_element([],"").
132last_element([X],X).
133last_element([_|Ls],X) :- last_element(Ls,X).
134
135nth_element(_,[],"").
136nth_element(1,[X|_],X).
137nth_element(N,[_|Ls],X) :- Np is N - 1, nth_element(Np,Ls,X).
138
139slice(_S,_E,[],[]).
140slice(1,E,[L|Ls],[L|Rs]) :- E > 0, En is E - 1, slice(1,En,Ls,Rs).
141slice(S,E,[_L|Ls],R) :- Sn is S - 1, En is E - 1, slice(Sn,En,Ls,R).
142
143show_type(X) :- type_of(X,T), format("Type of ~w is ~w.~n",[X,T]).
144type_of(X,"var") :- var(X), !.
145type_of(X,"integer") :- integer(X), !.
146type_of(X,"float") :- float(X), !.
147type_of(X,"rational") :- rational(X), !.
148type_of(X,"number") :- number(X), !. 149type_of(X,"string") :- string(X), !.
150type_of(X,"compound") :- compound(X), !.
151type_of(X,"atom") :- atom(X), !.
152type_of(_,"unknown").
153
154find_on_path(Exec,Path) :-
155 expand_file_search_path(path(Exec),Path),
156 exists_file(Path),
157 !.
158
159shell_path(Path) :- find_on_path(sh,Path).
160
161shell_wrap(Exec,ShellExec) :-
162 string_chars(Exec,['@'|SilentChars]),
163 !,
164 string_chars(SilentExec,SilentChars),
165 shell_wrap(SilentExec,ShellExec).
166
167shell_wrap(Exec,ShellExec) :-
168 shell_path(Sh),
169 !,
170 shell_quote(Exec,Escaped),
171 format(string(ShellExec),"~w -c ~w",[Sh,Escaped]).
172
173suppress_errors(Exec,SExec) :-
174 string_chars(Exec,['-'|RealExecChars]),
175 string_chars(RealExec,RealExecChars),
176 format(string(SExec),'(~w) || true',[RealExec]).
177
178echo_wrap(Exec,Result) :-
179 suppress_errors(Exec,SExec),
180 !,
181 echo_wrap(SExec,Result).
182
183echo_wrap(Exec,Result) :-
184 string_chars(Exec,['@'|SilentChars]),
185 !,
186 string_chars(Result,SilentChars).
187
188echo_wrap(Exec,Result) :-
189 shell_quote(Exec,Escaped),
190 format(string(Result),"echo ~w; ~w",[Escaped,Exec]).
191
192shell_echo_wrap(Exec,Result) :-
193 suppress_errors(Exec,SExec),
194 !,
195 shell_echo_wrap(SExec,Result).
196
197shell_echo_wrap(Exec,Result) :-
198 string_chars(Exec,['@'|SilentChars]),
199 !,
200 string_chars(SilentChars,SilentExec),
201 shell_wrap(SilentExec,Result).
202
203shell_echo_wrap(Exec,Result) :-
204 echo_wrap(Exec,EchoExec),
205 shell_wrap(EchoExec,Result).
206
(Comment,ShellComment) :-
208 format(string(ShellComment),"# ~w",[Comment]).
209
210shell_eval(Exec,CodeList) :-
211 shell_path(Sh),
212 working_directory(CWD,CWD),
213 setup_call_cleanup(process_create(Sh,['-c',Exec],[stdout(pipe(Stream)),
214 stderr(pipe(ErrStream)),
215 cwd(CWD),
216 process(Pid)]),
217 (read_stream_to_codes(Stream,CodeList),
218 process_wait(Pid,Status)),
219 ((Status = exit(0)
220 -> true
221 ; (read_string(ErrStream,_,Err),
222 format("biomake: ~w~n",[Err]))),
223 close(ErrStream),
224 close(Stream))).
225
226shell_eval_str(Exec,Result) :-
227 shell_eval(Exec,Rnl),
228 chomp(Rnl,Rchomp),
229 newlines_to_spaces(Rchomp,Rspc),
230 string_codes(Result,Rspc).
231
232shell_quote(S,QS) :-
233 string_chars(S,Cs),
234 phrase(escape_quotes(ECs),Cs),
235 append(['\''|ECs],['\''],QCs),
236 string_chars(QS,QCs).
237
238escape_quotes([]) --> [].
239escape_quotes(['\'','"','\'','"','\''|Cs]) --> ['\''], !, escape_quotes(Cs). 240escape_quotes([C|Cs]) --> [C], !, escape_quotes(Cs).
241
242chomp([],_) :- !.
243chomp([0'\n],_) :- !.
244chomp([C|In],[C|Out]) :- chomp(In,Out).
245
246newlines_to_spaces([],[]).
247newlines_to_spaces([0'\n|N],[0'\s|S]) :- newlines_to_spaces(N,S).
248newlines_to_spaces([C|N],[C|S]) :- newlines_to_spaces(N,S).
249
250file_directory_slash(Path,Result) :-
251 file_directory_name(Path,D),
252 string_concat(D,"/",Result). 253
254to_string(A,S) :- atomics_to_string([A],S).
255equal_as_strings(X,Y) :-
256 to_string(X,S),
257 to_string(Y,S).
258
259
263makefile_var_char(C) --> alphanum_char(C).
264makefile_var_char('_') --> ['_'].
265makefile_var_char('-') --> ['-'].
266
267makefile_var_chars([]) --> [].
268makefile_var_chars([C|Cs]) --> makefile_var_char(C), makefile_var_chars(Cs).
269
270makefile_var_atom_from_chars(A) --> makefile_var_chars(Cs), {atom_chars(A,Cs)}.
271makefile_var_string_from_chars(S) --> makefile_var_chars(Cs), {string_chars(S,Cs)}.
272
274makefile_var_code(C) --> alphanum_code(C).
275makefile_var_code(95) --> [95]. 276makefile_var_code(45) --> [45]. 277
278makefile_var_codes([]) --> [].
279makefile_var_codes([C|Cs]) --> makefile_var_code(C), makefile_var_codes(Cs).
280
281makefile_var_atom_from_codes(A) --> makefile_var_codes(Cs), {atom_codes(A,Cs)}.
282makefile_var_string_from_codes(S) --> makefile_var_codes(Cs), {string_codes(S,Cs)}.
283
284biomake_private_subdir_list(Target,Subdirs,[D,".biomake"|Subdirs]) :-
285 absolute_file_name(Target,F),
286 file_directory_name(F,D).
287
288biomake_private_dir(Target,Subdirs,Path) :-
289 biomake_private_subdir_list(Target,Subdirs,List),
290 concat_string_list(List,Path,"/").
291
292biomake_private_filename(Target,Subdirs,Filename) :-
293 biomake_private_dir(Target,Subdirs,Private),
294 absolute_file_name(Target,F),
295 file_base_name(F,N),
296 format(string(Filename),"~w/~w",[Private,N]).
297
298biomake_private_filename_dir_exists(Target,Subdirs,Filename) :-
299 biomake_private_subdir_list(Target,Subdirs,[Root|List]),
300 biomake_make_subdir_list(Root,List),
301 biomake_private_filename(Target,Subdirs,Filename).
302
303biomake_make_subdir_list(_,[]).
304biomake_make_subdir_list(Root,[Dir|Subdirs]) :-
305 format(string(Next),"~w/~w",[Root,Dir]),
306 safe_make_directory(Next),
307 biomake_make_subdir_list(Next,Subdirs).
308
309safe_make_directory(Path) :-
310 exists_directory(Path),
311 !.
312
313safe_make_directory(Path) :-
314 catch(make_directory(Path),_,fail),
315 !.
316
317safe_make_directory(Path) :-
318 absolute_file_name(Path,AbsPath),
319 format(string(Exec),"mkdir -p ~w",[AbsPath]),
320 shell(Exec).
321
322open_biomake_private_file(Target,Subdir,Filename,Stream) :-
323 open_biomake_private_file(Target,Subdir,Filename,Stream,[]).
324
325open_biomake_private_file(Target,Subdir,Filename,Stream,Options) :-
326 biomake_private_filename_dir_exists(Target,Subdir,Filename),
327 open(Filename,write,Stream,Options)