1 | % (c) 2009-2024 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). |