1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: J.Wielemaker@vu.nl 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 2001-2013, University of Amsterdam 7 VU University Amsterdam 8 All rights reserved. 9 10 Redistribution and use in source and binary forms, with or without 11 modification, are permitted provided that the following conditions 12 are met: 13 14 1. Redistributions of source code must retain the above copyright 15 notice, this list of conditions and the following disclaimer. 16 17 2. Redistributions in binary form must reproduce the above copyright 18 notice, this list of conditions and the following disclaimer in 19 the documentation and/or other materials provided with the 20 distribution. 21 22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 POSSIBILITY OF SUCH DAMAGE. 34*/ 35 36:- module(read_util, 37 [ read_line_to_codes/2, % +Stream, -Codes (without trailing \n) 38 read_line_to_codes/3, % +Stream, -Codes, ?Tail 39 read_stream_to_codes/2, % +Stream, -Codes 40 read_stream_to_codes/3, % +Stream, -Codes, ?Tail 41 read_file_to_codes/3, % +File, -Codes, +Options 42 43 read_line_to_string/2, % +Stream, -Line (without trailing \n) 44 read_file_to_string/3, % +File, -Codes, +Options 45 46 read_file_to_terms/3 % +File, -Terms, +Options 47 ]). 48:- use_module(library(shlib)). 49:- use_module(library(error)). 50:- use_module(library(option)). 51 52/** <module> Read utilities 53 54This library provides some commonly used reading predicates. As these 55predicates have proven to be time-critical in some applications we moved 56them to C. For compatibility as well as to reduce system dependency, we 57link the foreign code at runtime and fallback to the Prolog 58implementation if the shared object cannot be found. 59 60@see library(pure_input) allows for processing files with DCGs. 61*/ 62 63:- predicate_options(read_file_to_codes/3, 3, 64 [ tail(list_or_partial_list), 65 pass_to(system:open/4, 4) 66 ]). 67:- predicate_options(read_file_to_string/3, 3, 68 [ pass_to(system:open/4, 4) 69 ]). 70:- predicate_options(read_file_to_terms/3, 3, 71 [ tail(list_or_partial_list), 72 pass_to(read_stream_to_terms/4, 4), 73 pass_to(system:absolute_file_name/3, 3), 74 pass_to(system:open/4, 4) 75 ]). 76 77:- volatile 78 read_line_to_codes/2, 79 read_line_to_codes/3, 80 read_stream_to_codes/2, 81 read_stream_to_codes/3. 82 83link_foreign :- 84 catch(load_foreign_library(foreign(readutil)), _, fail), 85 !. 86link_foreign :- 87 assertz((read_line_to_codes(Stream, Line) :- 88 pl_read_line_to_codes(Stream, Line))), 89 assertz((read_line_to_codes(Stream, Line, Tail) :- 90 pl_read_line_to_codes(Stream, Line, Tail))), 91 assertz((read_stream_to_codes(Stream, Content) :- 92 pl_read_stream_to_codes(Stream, Content))), 93 assertz((read_stream_to_codes(Stream, Content, Tail) :- 94 pl_read_stream_to_codes(Stream, Content, Tail))), 95 compile_predicates([ read_line_to_codes/2, 96 read_line_to_codes/3, 97 read_stream_to_codes/2, 98 read_stream_to_codes/3 99 ]). 100 101:- initialization(link_foreign, now). 102 103 104 /******************************* 105 * LINES * 106 *******************************/ 107 108%! read_line_to_codes(+In:stream, -Line:codes) is det. 109% 110% Read a line of input from In into a list of character codes. 111% Trailing newline and or return are deleted. Upon reaching 112% end-of-file Line is unified to the atom =end_of_file=. 113 114pl_read_line_to_codes(Stream, Codes) :- 115 get_code(Stream, C0), 116 ( C0 == -1 117 -> Codes0 = end_of_file 118 ; read_1line_to_codes(C0, Stream, Codes0) 119 ), 120 Codes = Codes0. 121 122read_1line_to_codes(-1, _, []) :- !. 123read_1line_to_codes(10, _, []) :- !. 124read_1line_to_codes(13, Stream, L) :- 125 !, 126 get_code(Stream, C2), 127 read_1line_to_codes(C2, Stream, L). 128read_1line_to_codes(C, Stream, [C|T]) :- 129 get_code(Stream, C2), 130 read_1line_to_codes(C2, Stream, T). 131 132%! read_line_to_codes(+Stream, -Line, ?Tail) is det. 133% 134% Read a line of input as a difference list. This should be used 135% to read multiple lines efficiently. On reaching end-of-file, 136% Tail is bound to the empty list. 137 138pl_read_line_to_codes(Stream, Codes, Tail) :- 139 get_code(Stream, C0), 140 read_line_to_codes(C0, Stream, Codes0, Tail), 141 Codes = Codes0. 142 143read_line_to_codes(-1, _, Tail, Tail) :- 144 !, 145 Tail = []. 146read_line_to_codes(10, _, [10|Tail], Tail) :- !. 147read_line_to_codes(C, Stream, [C|T], Tail) :- 148 get_code(Stream, C2), 149 read_line_to_codes(C2, Stream, T, Tail). 150 151 152%! read_line_to_string(+Stream, -String) is det. 153% 154% Read the next line from Stream into String. String does not 155% contain the line terminator. String is unified with the _atom_ 156% end_of_file if the end of the file is reached. 157% 158% @see read_string/5 can be used to read lines with separated 159% records without creating intermediate strings. 160 161read_line_to_string(Stream, String) :- 162 read_string(Stream, '\n', '\r', Sep, String0), 163 ( Sep \== -1 164 -> String = String0 165 ; String0 == "" 166 -> String = end_of_file 167 ; String = String0 168 ). 169 170 171 /******************************* 172 * STREAM (ENTIRE INPUT) * 173 *******************************/ 174 175%! read_stream_to_codes(+Stream, -Codes) is det. 176%! read_stream_to_codes(+Stream, -Codes, ?Tail) is det. 177% 178% Read input from Stream to a list of character codes. The version 179% read_stream_to_codes/3 creates a difference-list. 180 181pl_read_stream_to_codes(Stream, Codes) :- 182 pl_read_stream_to_codes(Stream, Codes, []). 183pl_read_stream_to_codes(Stream, Codes, Tail) :- 184 get_code(Stream, C0), 185 read_stream_to_codes(C0, Stream, Codes0, Tail), 186 Codes = Codes0. 187 188read_stream_to_codes(-1, _, Tail, Tail) :- !. 189read_stream_to_codes(C, Stream, [C|T], Tail) :- 190 get_code(Stream, C2), 191 read_stream_to_codes(C2, Stream, T, Tail). 192 193 194%! read_stream_to_terms(+Stream, -Terms, ?Tail, +Options) is det. 195 196read_stream_to_terms(Stream, Terms, Tail, Options) :- 197 read_term(Stream, C0, Options), 198 read_stream_to_terms(C0, Stream, Terms0, Tail, Options), 199 Terms = Terms0. 200 201read_stream_to_terms(end_of_file, _, Tail, Tail, _) :- !. 202read_stream_to_terms(C, Stream, [C|T], Tail, Options) :- 203 read_term(Stream, C2, Options), 204 read_stream_to_terms(C2, Stream, T, Tail, Options). 205 206 207 /******************************* 208 * FILE (ENTIRE INPUT) * 209 *******************************/ 210 211%! read_file_to_codes(+Spec, -Codes, +Options) is det. 212% 213% Read the file Spec into a list of Codes. Options is split into 214% options for absolute_file_name/3 and open/4. In addition, the 215% following option is provided: 216% 217% * tail(?Tail) 218% Read the data into a _difference list_ Codes\Tail. 219% 220% @see phrase_from_file/3 and read_file_to_string/3. 221 222read_file_to_codes(Spec, Codes, Options) :- 223 must_be(list, Options), 224 option(tail(Tail), Options, []), 225 absolute_file_name(Spec, 226 [ access(read) 227 | Options 228 ], 229 Path), 230 setup_call_cleanup( 231 open(Path, read, Stream, Options), 232 read_stream_to_codes(Stream, Codes, Tail), 233 close(Stream)). 234 235%! read_file_to_string(+Spec, -String, +Options) is det. 236% 237% Read the file Spec into a the string String. Options is split 238% into options for absolute_file_name/3 and open/4. 239% 240% @see phrase_from_file/3 and read_file_to_codes/3. 241 242read_file_to_string(Spec, Codes, Options) :- 243 must_be(list, Options), 244 absolute_file_name(Spec, 245 [ access(read) 246 | Options 247 ], 248 Path), 249 setup_call_cleanup( 250 open(Path, read, Stream, Options), 251 read_string(Stream, _Len, Codes), 252 close(Stream)). 253 254%! read_file_to_terms(+Spec, -Terms, +Options) is det. 255% 256% Read the file Spec into a list of terms. Options is split over 257% absolute_file_name/3, open/4 and read_term/3. In addition, the 258% following option is processed: 259% 260% * tail(?Tail) 261% If present, Terms\Tail forms a _difference list_. 262% 263% Note that the `output' options of read_term/3, such as 264% =variable_names= or =subterm_positions= will cause 265% read_file_to_terms/3 to fail if Spec contains multiple terms 266% because the values for the different terms will not unify. 267 268read_file_to_terms(Spec, Terms, Options) :- 269 must_be(list, Options), 270 option(tail(Tail), Options, []), 271 absolute_file_name(Spec, 272 [ access(read) 273 | Options 274 ], 275 Path), 276 setup_call_cleanup( 277 open(Path, read, Stream, Options), 278 read_stream_to_terms(Stream, Terms, Tail, Options), 279 close(Stream))