View source with raw comments or as raw
    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-2022, University of Amsterdam
    7                              VU University Amsterdam
    8                              CWI, Amsterdam
    9                              SWI-Prolog Solutions b.v.
   10    All rights reserved.
   11
   12    Redistribution and use in source and binary forms, with or without
   13    modification, are permitted provided that the following conditions
   14    are met:
   15
   16    1. Redistributions of source code must retain the above copyright
   17       notice, this list of conditions and the following disclaimer.
   18
   19    2. Redistributions in binary form must reproduce the above copyright
   20       notice, this list of conditions and the following disclaimer in
   21       the documentation and/or other materials provided with the
   22       distribution.
   23
   24    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   25    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   26    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   27    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   28    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   29    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   30    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   31    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   32    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   33    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   34    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   35    POSSIBILITY OF SUCH DAMAGE.
   36*/
   37
   38:- module(read_util,
   39          [ read_line_to_codes/2,       % +Stream, -Codes (without trailing \n)
   40            read_line_to_codes/3,       % +Stream, -Codes, ?Tail
   41            read_stream_to_codes/2,     % +Stream, -Codes
   42            read_stream_to_codes/3,     % +Stream, -Codes, ?Tail
   43            read_file_to_codes/3,       % +File, -Codes, +Options
   44
   45            read_line_to_string/2,      % +Stream, -Line (without trailing \n)
   46            read_file_to_string/3,      % +File, -Codes, +Options
   47
   48            read_file_to_terms/3        % +File, -Terms, +Options
   49          ]).   50:- autoload(library(error),[must_be/2]).   51:- autoload(library(option),[option/3]).

Read utilities

This library provides some commonly used reading predicates. As these predicates have proven to be time-critical in some applications we moved them to C. For compatibility as well as to reduce system dependency, we link the foreign code at runtime and fallback to the Prolog implementation if the shared object cannot be found.

See also
- library(pure_input) allows for processing files with DCGs.
- library(lazy_lists) for creating lazy lists from input. */
   65:- predicate_options(read_file_to_codes/3, 3,
   66                     [ tail(list_or_partial_list),
   67                       pass_to(system:open/4, 4)
   68                     ]).   69:- predicate_options(read_file_to_string/3, 3,
   70                     [ pass_to(system:open/4, 4)
   71                     ]).   72:- predicate_options(read_file_to_terms/3, 3,
   73                     [ tail(list_or_partial_list),
   74                       pass_to(read_stream_to_terms/4, 4),
   75                       pass_to(system:absolute_file_name/3, 3),
   76                       pass_to(system:open/4, 4)
   77                     ]).   78:- predicate_options(read_stream_to_terms/4, 4,
   79                     [ pass_to(read_term/3, 3)
   80                     ]).   81
   82:- volatile
   83    read_line_to_codes/2,
   84    read_line_to_codes/3,
   85    read_stream_to_codes/2,
   86    read_stream_to_codes/3.   87
   88link_foreign :-
   89    context_module(Here),
   90    catch('$syspreds':use_foreign_library_noi(Here:foreign(readutil)),
   91          error(_,_), fail),
   92    !.
   93link_foreign :-
   94    assertz((read_line_to_codes(Stream, Line) :-
   95            pl_read_line_to_codes(Stream, Line))),
   96    assertz((read_line_to_codes(Stream, Line, Tail) :-
   97            pl_read_line_to_codes(Stream, Line, Tail))),
   98    assertz((read_stream_to_codes(Stream, Content) :-
   99            pl_read_stream_to_codes(Stream, Content))),
  100    assertz((read_stream_to_codes(Stream, Content, Tail) :-
  101            pl_read_stream_to_codes(Stream, Content, Tail))),
  102    compile_predicates([ read_line_to_codes/2,
  103                         read_line_to_codes/3,
  104                         read_stream_to_codes/2,
  105                         read_stream_to_codes/3
  106                       ]).
  107
  108:- initialization(link_foreign, now).  109
  110
  111                 /*******************************
  112                 *             LINES            *
  113                 *******************************/
 read_line_to_codes(+Stream, -Line:codes) is det
Read the next line of input from Stream. Unify content of the lines as a list of character codes with Line after the line has been read. A line is ended by a newline character or end-of-file. Unlike read_line_to_codes/3, this predicate removes a trailing newline character.
  123pl_read_line_to_codes(Stream, Codes) :-
  124    get_code(Stream, C0),
  125    (   C0 == -1
  126    ->  Codes0 = end_of_file
  127    ;   read_1line_to_codes(C0, Stream, Codes0)
  128    ),
  129    Codes = Codes0.
  130
  131read_1line_to_codes(-1, _, []) :- !.
  132read_1line_to_codes(10, _, []) :- !.
  133read_1line_to_codes(13, Stream, L) :-
  134    !,
  135    get_code(Stream, C2),
  136    read_1line_to_codes(C2, Stream, L).
  137read_1line_to_codes(C, Stream, [C|T]) :-
  138    get_code(Stream, C2),
  139    read_1line_to_codes(C2, Stream, T).
 read_line_to_codes(+Stream, -Line, ?Tail) is det
Difference-list version to read an input line to a list of character codes. Reading stops at the newline or end-of-file character, but unlike read_line_to_codes/2, the newline is retained in the output. This predicate is especially useful for reading a block of lines up to some delimiter. The following example reads an HTTP header ended by a blank line:
read_header_data(Stream, Header) :-
    read_line_to_codes(Stream, Header, Tail),
    read_header_data(Header, Stream, Tail).

read_header_data("\r\n", _, _) :- !.
read_header_data("\n", _, _) :- !.
read_header_data("", _, _) :- !.
read_header_data(_, Stream, Tail) :-
    read_line_to_codes(Stream, Tail, NewTail),
    read_header_data(Tail, Stream, NewTail).
  163pl_read_line_to_codes(Stream, Codes, Tail) :-
  164    get_code(Stream, C0),
  165    read_line_to_codes(C0, Stream, Codes0, Tail),
  166    Codes = Codes0.
  167
  168read_line_to_codes(-1, _, Tail, Tail) :-
  169    !,
  170    Tail = [].
  171read_line_to_codes(10, _, [10|Tail], Tail) :- !.
  172read_line_to_codes(C, Stream, [C|T], Tail) :-
  173    get_code(Stream, C2),
  174    read_line_to_codes(C2, Stream, T, Tail).
 read_line_to_string(+Stream, -String) is det
Read the next line from Stream into String. String does not contain the line terminator. String is unified with the atom end_of_file if the end of the file is reached.
See also
- read_string/5 can be used to read lines with separated records without creating intermediate strings.
  186read_line_to_string(Stream, String) :-
  187    read_string(Stream, '\n', '\r', Sep, String0),
  188    (   Sep \== -1
  189    ->  String = String0
  190    ;   String0 == ""
  191    ->  String = end_of_file
  192    ;   String = String0
  193    ).
  194
  195
  196                 /*******************************
  197                 *     STREAM (ENTIRE INPUT)    *
  198                 *******************************/
 read_stream_to_codes(+Stream, -Codes) is det
 read_stream_to_codes(+Stream, -Codes, ?Tail) is det
Read input from Stream to a list of character codes. The version read_stream_to_codes/3 creates a difference-list.
  206pl_read_stream_to_codes(Stream, Codes) :-
  207    pl_read_stream_to_codes(Stream, Codes, []).
  208pl_read_stream_to_codes(Stream, Codes, Tail) :-
  209    get_code(Stream, C0),
  210    read_stream_to_codes(C0, Stream, Codes0, Tail),
  211    Codes = Codes0.
  212
  213read_stream_to_codes(-1, _, Tail, Tail) :- !.
  214read_stream_to_codes(C, Stream, [C|T], Tail) :-
  215    get_code(Stream, C2),
  216    read_stream_to_codes(C2, Stream, T, Tail).
 read_stream_to_terms(+Stream, -Terms, ?Tail, +Options) is det
  221read_stream_to_terms(Stream, Terms, Tail, Options) :-
  222    read_term(Stream, C0, Options),
  223    read_stream_to_terms(C0, Stream, Terms0, Tail, Options),
  224    Terms = Terms0.
  225
  226read_stream_to_terms(end_of_file, _, Tail, Tail, _) :- !.
  227read_stream_to_terms(C, Stream, [C|T], Tail, Options) :-
  228    read_term(Stream, C2, Options),
  229    read_stream_to_terms(C2, Stream, T, Tail, Options).
  230
  231
  232                 /*******************************
  233                 *      FILE (ENTIRE INPUT)     *
  234                 *******************************/
 read_file_to_codes(+Spec, -Codes, +Options) is det
Read the file Spec into a list of Codes. Options is split into options for absolute_file_name/3 and open/4. In addition, the following option is provided:
tail(?Tail)
Read the data into a difference list Codes\Tail.
See also
- phrase_from_file/3 and read_file_to_string/3.
  247read_file_to_codes(Spec, Codes, Options) :-
  248    must_be(list, Options),
  249    option(tail(Tail), Options, []),
  250    absolute_file_name(Spec,
  251                       [ access(read)
  252                       | Options
  253                       ],
  254                       Path),
  255    setup_call_cleanup(
  256        open(Path, read, Stream, Options),
  257        read_stream_to_codes(Stream, Codes, Tail),
  258        close(Stream)).
 read_file_to_string(+Spec, -String, +Options) is det
Read the file Spec into a the string String. Options is split into options for absolute_file_name/3 and open/4.
See also
- phrase_from_file/3 and read_file_to_codes/3.
  267read_file_to_string(Spec, Codes, Options) :-
  268    must_be(list, Options),
  269    absolute_file_name(Spec,
  270                       [ access(read)
  271                       | Options
  272                       ],
  273                       Path),
  274    setup_call_cleanup(
  275        open(Path, read, Stream, Options),
  276        read_string(Stream, _Len, Codes),
  277        close(Stream)).
 read_file_to_terms(+Spec, -Terms, +Options) is det
Read the file Spec into a list of terms. Options is split over absolute_file_name/3, open/4 and read_term/3. In addition, the following option is processed:
tail(?Tail)
If present, Terms\Tail forms a difference list.

Note that the output options of read_term/3, such as variable_names or subterm_positions will cause read_file_to_terms/3 to fail if Spec contains multiple terms because the values for the different terms will not unify.

  293read_file_to_terms(Spec, Terms, Options) :-
  294    must_be(list, Options),
  295    option(tail(Tail), Options, []),
  296    absolute_file_name(Spec,
  297                       [ access(read)
  298                       | Options
  299                       ],
  300                       Path),
  301    setup_call_cleanup(
  302        open(Path, read, Stream, Options),
  303        read_stream_to_terms(Stream, Terms, Tail, Options),
  304        close(Stream))