1 % (c) 2009-2023 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
2 % Heinrich Heine Universitaet Duesseldorf
3 % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
4
5 :- module(tools_io,[safe_open_file/4,
6 intelligent_open/4,
7 safe_intelligent_open_file/3, safe_intelligent_open_file/4,
8 safe_intelligent_close_file/2,
9 with_open_stream_to_codes/4,
10 read_byte_line/2,
11 read_byte_word/2,
12 put_bytes/2]).
13
14 :- meta_predicate with_open_stream_to_codes(0,*,*,*).
15
16 :- use_module(module_information).
17 :- module_info(group,infrastructure).
18 :- module_info(description,'This module contains file io helper predicates.').
19
20 :- use_module(error_manager).
21 :- use_module(probsrc(tools_strings), [ajoin/2]).
22
23 safe_open_file(Filename,_,_,_) :-
24 (Filename=[] ; \+ atom(Filename)),!,
25 add_error(open_file,'Filename must be an atom:',Filename),fail.
26 safe_open_file(Filename,Mode,Stream,Options) :-
27 %print(opening(Filename)),nl,
28 catch(open(Filename,Mode,Stream,Options), error(A,B),
29 (ajoin(['Exception occurred opening file \'',Filename,
30 '\' (mode: ',Mode, ', options: ',Options,') :'],Msg),
31 add_error(open_file,Msg,error(A,B)),fail)).
32
33
34 safe_intelligent_open_file(Filename,Mode,Stream) :-
35 safe_intelligent_open_file(Filename,Mode,Stream,[encoding(utf8)]).
36 safe_intelligent_open_file(Filename,Mode,Stream,Options) :-
37 %print(opening(Filename)),nl,
38 catch(intelligent_open(Filename,Mode,Stream,Options), % utf8
39 error(A,B),
40 (add_error(open_file,'Exception occurred opening file:',error(A,B)),fail)).
41
42 intelligent_open(user_error,Mode,Stream,_) :- (Mode=append ; Mode=write), !, Stream=user_error.
43 intelligent_open(stderr,Mode,Stream,_) :- (Mode=append ; Mode=write), !, Stream=user_error.
44 intelligent_open(user_output,Mode,Stream,_) :- (Mode=append ; Mode=write), !, Stream=user_output.
45 intelligent_open(stdout,Mode,Stream,_) :- (Mode=append ; Mode=write), !, Stream=user_output.
46 intelligent_open(File,Mode,Stream,Options) :- open(File,Mode,Stream,Options).
47
48 % use if you have called safe_intelligent_open_file with alias(A) in options and want to call close(A)
49 safe_intelligent_close_file(user_error,_) :- !.
50 safe_intelligent_close_file(stderr,_) :- !.
51 safe_intelligent_close_file(user_output,_) :- !.
52 safe_intelligent_close_file(stdout,_) :- !.
53 safe_intelligent_close_file(_,Stream) :- close(Stream).
54
55
56 :- use_module(library(codesio), [with_output_to_codes/4]).
57 % Variant of with_output_to_codes that preserves the current output stream instead of replacing it with the codes stream.
58 % This ensures that debug prints inside Goal aren't redirected into the codes by accident.
59 with_open_stream_to_codes(Goal, Stream, S0, S) :-
60 current_output(CurrentOutput),
61 with_output_to_codes((set_output(CurrentOutput), Goal), Stream, S0, S).
62
63
64 % a utility to read bytes of a binary stream until the end of line
65 % stream is obtained e.g. by open(File,read,Stream,[type(binary)])
66 read_byte_line(Stream,Res) :- read_bytes_until(Stream,[10],Res).
67
68 % a utility to read bytes of a binary stream until the end of line, eof, tab or space
69 read_byte_word(Stream,Res) :- read_bytes_until(Stream,[8,10,32],Res).
70
71 :- use_module(library(ordsets),[ord_member/2]).
72 read_bytes_until(Stream,EndCodes,Res) :-
73 get_byte(Stream,Code),
74 (ord_member(Code,EndCodes) -> Res=[]
75 ; Code = 13 -> read_bytes_until(Stream,EndCodes,Res)
76 ; Code = -1 -> Res = [] % end of file
77 ; Res = [Code|T],
78 read_bytes_until(Stream,EndCodes,T)
79 ).
80
81
82 % utility to write a sequence of bytes to a binary stream
83 put_bytes(_,[]).
84 put_bytes(Stream,[H|T]) :- put_byte(Stream,H), put_bytes(Stream,T).