View source with formatted 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]).   52
   53/** <module> Read utilities
   54
   55This library provides some commonly used   reading  predicates. As these
   56predicates have proven to be time-critical in some applications we moved
   57them to C. For compatibility as well  as to reduce system dependency, we
   58link  the  foreign  code  at  runtime    and   fallback  to  the  Prolog
   59implementation if the shared object cannot be found.
   60
   61@see library(pure_input) allows for processing files with DCGs.
   62@see library(lazy_lists) for creating lazy lists from input.
   63*/
   64
   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                 *******************************/
  114
  115%!  read_line_to_codes(+Stream, -Line:codes) is det.
  116%
  117%   Read the next line of input from  Stream. Unify content of the lines
  118%   as a list of character codes  with   Line  _after_ the line has been
  119%   read. A line is ended by a  newline character or end-of-file. Unlike
  120%   read_line_to_codes/3, this predicate  removes   a  trailing  newline
  121%   character.
  122
  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).
  140
  141%!  read_line_to_codes(+Stream, -Line, ?Tail) is det.
  142%
  143%   Difference-list version to read an input line to a list of character
  144%   codes. Reading stops at the newline   or  end-of-file character, but
  145%   unlike read_line_to_codes/2, the newline is  retained in the output.
  146%   This predicate is especially useful for reading  a block of lines up
  147%   to some delimiter. The following example  reads an HTTP header ended
  148%   by a blank line:
  149%
  150%   ```
  151%   read_header_data(Stream, Header) :-
  152%       read_line_to_codes(Stream, Header, Tail),
  153%       read_header_data(Header, Stream, Tail).
  154%
  155%   read_header_data("\r\n", _, _) :- !.
  156%   read_header_data("\n", _, _) :- !.
  157%   read_header_data("", _, _) :- !.
  158%   read_header_data(_, Stream, Tail) :-
  159%       read_line_to_codes(Stream, Tail, NewTail),
  160%       read_header_data(Tail, Stream, NewTail).
  161%   ```
  162
  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).
  175
  176
  177%!  read_line_to_string(+Stream, -String) is det.
  178%
  179%   Read the next line from Stream into  String. String does not contain
  180%   the line terminator. String is unified with the _atom_ `end_of_file`
  181%   if the end of the file is reached.
  182%
  183%   @see    read_string/5 can be used to read lines with separated
  184%           records without creating intermediate strings.
  185
  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                 *******************************/
  199
  200%!  read_stream_to_codes(+Stream, -Codes) is det.
  201%!  read_stream_to_codes(+Stream, -Codes, ?Tail) is det.
  202%
  203%   Read input from Stream to a list of character codes. The version
  204%   read_stream_to_codes/3 creates a difference-list.
  205
  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).
  217
  218
  219%!  read_stream_to_terms(+Stream, -Terms, ?Tail, +Options) is det.
  220
  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                 *******************************/
  235
  236%!  read_file_to_codes(+Spec, -Codes, +Options) is det.
  237%
  238%   Read the file Spec into a list   of Codes. Options is split into
  239%   options for absolute_file_name/3 and open/4.   In  addition, the
  240%   following option is provided:
  241%
  242%     * tail(?Tail)
  243%     Read the data into a _difference list_ Codes\Tail.
  244%
  245%   @see phrase_from_file/3 and read_file_to_string/3.
  246
  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)).
  259
  260%!  read_file_to_string(+Spec, -String, +Options) is det.
  261%
  262%   Read the file Spec into a the   string  String. Options is split
  263%   into options for absolute_file_name/3 and open/4.
  264%
  265%   @see phrase_from_file/3 and read_file_to_codes/3.
  266
  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)).
  278
  279%!  read_file_to_terms(+Spec, -Terms, +Options) is det.
  280%
  281%   Read the file Spec into a list   of terms. Options is split over
  282%   absolute_file_name/3, open/4 and  read_term/3.  In addition, the
  283%   following option is processed:
  284%
  285%     * tail(?Tail)
  286%     If present, Terms\Tail forms a _difference list_.
  287%
  288%   Note  that  the  _output_  options    of  read_term/3,  such  as
  289%   =variable_names=    or    =subterm_positions=      will    cause
  290%   read_file_to_terms/3 to fail if  Spec   contains  multiple terms
  291%   because the values for the different terms will not unify.
  292
  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))