1 % (c) 2009-2025 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 write_file_to_stream/2]).
14
15 :- meta_predicate with_open_stream_to_codes(0,*,*,*).
16
17 :- use_module(module_information).
18 :- module_info(group,infrastructure).
19 :- module_info(description,'This module contains file io helper predicates.').
20
21 :- use_module(error_manager).
22 :- use_module(probsrc(tools_strings), [ajoin/2]).
23
24 safe_open_file(Filename,_,_,_) :-
25 (Filename=[] ; \+ atom(Filename)),!,
26 add_error(open_file,'Filename must be an atom:',Filename),fail.
27 safe_open_file(Filename,Mode,Stream,Options) :-
28 %print(opening(Filename)),nl,
29 catch(open(Filename,Mode,Stream,Options), error(A,B),
30 (ajoin(['Exception occurred opening file \'',Filename,
31 '\' (mode: ',Mode, ', options: ',Options,') :'],Msg),
32 add_error(open_file,Msg,error(A,B)),fail)).
33
34
35 safe_intelligent_open_file(Filename,Mode,Stream) :-
36 safe_intelligent_open_file(Filename,Mode,Stream,[encoding(utf8)]).
37 safe_intelligent_open_file(Filename,Mode,Stream,Options) :-
38 %print(opening(Filename)),nl,
39 catch(intelligent_open(Filename,Mode,Stream,Options), % utf8
40 error(A,B),
41 (add_error(open_file,'Exception occurred opening file:',error(A,B)),fail)).
42
43 intelligent_open(user_error,Mode,Stream,_) :- (Mode=append ; Mode=write), !, Stream=user_error.
44 intelligent_open(stderr,Mode,Stream,_) :- (Mode=append ; Mode=write), !, Stream=user_error.
45 intelligent_open(user_output,Mode,Stream,_) :- (Mode=append ; Mode=write), !, Stream=user_output.
46 intelligent_open(stdout,Mode,Stream,_) :- (Mode=append ; Mode=write), !, Stream=user_output.
47 intelligent_open(File,Mode,Stream,Options) :- open(File,Mode,Stream,Options).
48
49 % use if you have called safe_intelligent_open_file with alias(A) in options and want to call close(A)
50 safe_intelligent_close_file(user_error,_) :- !.
51 safe_intelligent_close_file(stderr,_) :- !.
52 safe_intelligent_close_file(user_output,_) :- !.
53 safe_intelligent_close_file(stdout,_) :- !.
54 safe_intelligent_close_file(_,Stream) :- close(Stream).
55
56
57 :- use_module(library(codesio), [with_output_to_codes/4]).
58 % Variant of with_output_to_codes that preserves the current output stream instead of replacing it with the codes stream.
59 % This ensures that debug prints inside Goal aren't redirected into the codes by accident.
60 with_open_stream_to_codes(Goal, Stream, S0, S) :-
61 current_output(CurrentOutput),
62 with_output_to_codes((set_output(CurrentOutput), Goal), Stream, S0, S).
63
64
65 % a utility to read bytes of a binary stream until the end of line
66 % stream is obtained e.g. by open(File,read,Stream,[type(binary)])
67 read_byte_line(Stream,Res) :- read_bytes_until(Stream,[10],Res).
68
69 % a utility to read bytes of a binary stream until the end of line, eof, tab or space
70 read_byte_word(Stream,Res) :- read_bytes_until(Stream,[8,10,32],Res).
71
72 :- use_module(library(ordsets),[ord_member/2]).
73 read_bytes_until(Stream,EndCodes,Res) :-
74 get_byte(Stream,Code),
75 (ord_member(Code,EndCodes) -> Res=[]
76 ; Code = 13 -> read_bytes_until(Stream,EndCodes,Res)
77 ; Code = -1 -> Res = [] % end of file
78 ; Res = [Code|T],
79 read_bytes_until(Stream,EndCodes,T)
80 ).
81
82
83 % utility to write a sequence of bytes to a binary stream
84 put_bytes(_,[]).
85 put_bytes(Stream,[H|T]) :- put_byte(Stream,H), put_bytes(Stream,T).
86
87
88 write_file_to_stream(File,Stream) :-
89 safe_open_file(File,read,StreamIn,[encoding(utf8)]),
90 copy_stream(StreamIn,Stream),
91 close(StreamIn).
92
93 % get_code is faster than get_char or read_line for larger SVG files
94 copy_stream(StreamIn,StreamOut) :-
95 get_code(StreamIn, Code),
96 (Code = -1 -> true
97 ; put_code(StreamOut,Code),
98 copy_stream(StreamIn,StreamOut)
99 ).