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