1% BEGIN LICENSE BLOCK
2% Version: CMPL 1.1
3%
4% The contents of this file are subject to the Cisco-style Mozilla Public
5% License Version 1.1 (the "License"); you may not use this file except
6% in compliance with the License.  You may obtain a copy of the License
7% at www.eclipse-clp.org/license.
8% 
9% Software distributed under the License is distributed on an "AS IS"
10% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
11% the License for the specific language governing rights and limitations
12% under the License. 
13% 
14% The Original Code is  The ECLiPSe Constraint Logic Programming System. 
15% The Initial Developer of the Original Code is  Cisco Systems, Inc. 
16% Portions created by the Initial Developer are
17% Copyright (C) 2006 Cisco Systems, Inc.  All Rights Reserved.
18% 
19% Contributor(s): 
20% 
21% END LICENSE BLOCK
22
23:- comment(alias, "Character I/O").
24:- comment(summary, "Built-ins to input and output characters or byte strings").
25:- comment(categories, ["Built-In Predicates"]).
26
27:- tool(read_token / 2).
28:- tool(read_token / 3).
29
30:- comment(read_token / 2, [
31        summary:"Succeeds if the next token from the current input stream is successfully
32read and unified with Token and its token class with Class.
33
34",
35        amode:(read_token(-,-) is det),
36        desc:html("   This predicate is an interface to the ECLiPSe tokenizer.  It can be used
37   to read terms which are not ended by a fullstop or even to build whole
38   new parsers.  The next token from the input stream is read and unified
39   with Token.  The token class of this token is unified with Class.
40
41<P>
42   read_token(Token, Class) is equivalent to read_token(input, Token,
43   Class).  See read_token/3 for details.
44
45<P>
46"),
47        args:["Token" : "Variable or constant.", "Class" : "Variable or atom."],
48        exceptions:[5 : "Class does not unify with an atom.", 190 : "End of file was encountered before reading any character.", 198 : "Trying to read even after the error 190 was raised."],
49        eg:"   See read_token/3 for examples.
50
51
52
53",
54        see_also:[get_chtab / 2, set_chtab / 2, read_token / 3]]).
55
56:- comment(read_token / 3, [
57        summary:"Succeeds if the next token from the input stream Stream is successfully
58read and unified with Token and its token class with Class.
59
60",
61        amode:(read_token(+,-,-) is det),
62        desc:html("   This predicate is an interface to the ECLiPSe tokenizer.  It can be used
63   to read terms which are not ended by a fullstop or even to build whole
64   new parsers.  The next token from the input stream Stream is read and
65   unified with Token.  The token class of this token is unified with
66   Class.
67
68<P>
69   The possible token classes with examples:
70
71<P>
72<PRE>
73   ---------------------------------------
74   | Input Example  Token    Class        |
75   |------------------------------------  |
76   | X              \"X\"      var          |
77   | _              \"_\"      anonymous    |
78   | abc            'abc'    atom         |
79   | 'a-b'          'a-b'    quoted_atom  |
80   | 123            123      integer      |
81   | 1.2            1.2      float        |
82   | 1_3            1_3      rational     |
83   | 0.9__1.1       0.9__1.1 breal        |
84   | \"abc\"          \"abc\"    string       |
85   | |              \"|\"      solo         |
86   | )              \")\"      solo         |
87   | (              \"(\"      solo         |
88   | &lt;SPACE&gt;(       \"(\"      open_par     |
89   | ,              ','      comma        |
90   | .&lt;NL&gt;          '.'      fullstop     |
91   | 1e789&lt;NL&gt;      \"1e789\"  error        |
92   ---------------------------------------|
93</PRE>
94   Note that round, square and curly brackets are solo tokens whose
95   value is returned as a string.  Opening brackets preceded by space
96   are treated specially as open_par tokens.  Comma and fullstop have
97   their own token class.  All syntax errors are reported as class
98   error, with the input string up to the error as Token.  The default
99   error handler for the event 190 (reading EOF) returns end_of_file
100   in both Class and Token.
101<P>
102   Note about signed numbers: the tokenizer returns a sign followed by a
103   number as two separate tokens.  For instance, the input \"-5\" is read
104   as two tokens, the atom '-' and the integer 5.  In the case of bounded
105   reals, this leads to \"-1.1__-0.9\" being returned as the atom '-' and
106   the bounded real 1.1__-0.9.  This is a non-canonical breal, since the
107   upper bound is lower than the lower bound.  read_token/2,3 is the only
108   predicate that can produce such objects, and it is the programmer's
109   responsibility to construct a valid breal using breal_bounds/3 and
110   breal_from_bounds/3, taking the sign into account.  Note that all
111   other arithmetic operations are undefined on non-canonical breals.
112<P>
113"),
114        args:[
115            "Stream" : "Stream handle or alias (atom)",
116            "Token" : "Variable or constant.", "Class" : "Variable or atom."],
117        exceptions:[4 : "Stream is not instantiated.", 5 : "Stream is not an atom or a stream handle.", 5 : "Class does not unify with an atom.", 190 : "End of file was encountered before reading any character.", 192 : "Stream is not an input stream.", 193 : "Stream is an illegal stream specification.", 198 : "Trying to read even after the error 190 was raised."],
118        eg:"
119Success:
120      ?- read_token(input,T,C).
121              []
122      T = []
123      C = atom
124      ?- read_token(input,T,C).
125              [
126      T = \"[\"
127      C = solo
128      ?- read_token(input, \"k\",C).
129              \"k\"
130      C = string
131      ?- read_token(input,T,C).
132              X
133      T = \"X\"
134      C = var
135      ?- read_token(input,T,C).
136              1.6e-5.
137      T = 1.6e-05
138      C = float
139
140Fail:
141      ?- read_token(input, \"[\", C).
142              &
143      no.
144
145Error:
146      ?- read_token(input, T, C).
147              ^D
148      T = end_of_file
149      C = end_of_file
150      yes. (Error 190, default handler)
151
152      read_token(S, a(b,c), C).         (Error 4).
153      read_token(\"string\", a(b,c), C).  (Error 5).
154      read_token(9, X + 2, C).          (Error 192). % stream not open
155      read_token(atom, X + 2, C).       (Error 193).
156
157
158
159
160",
161        see_also:[get_chtab / 2, set_chtab / 2, read_token / 2]]).
162
163:- comment(nl / 0, [
164        summary:"A newline is printed on the output stream.",
165        amode:(nl is det),
166        desc:html("\
167        Used to print a newline sequence on the current output stream.
168        The exact character sequence emitted depends on the setting of
169        the stream's <CODE>end_of_line</CODE> flag (lf or crlf).
170        In addition, if the stream's <CODE>flush</CODE> flag is set to
171        <CODE>end_of_line</CODE>, the stream is also flushed.
172"),
173        args:[],
174        see_also:[nl / 1, writeln/1]]).
175
176:- comment(nl / 1, [
177        summary:"A newline is printed on the output stream Stream.",
178        amode:(nl(+) is det),
179        desc:html("\
180        Used to print a newline sequence on the output stream Stream.
181        The exact character sequence emitted depends on the setting of
182        the stream's <CODE>end_of_line</CODE> flag (lf or crlf).
183        In addition, if the stream's <CODE>flush</CODE> flag is set to
184        <CODE>end_of_line</CODE>, the stream is also flushed.
185"),
186        args:[ "Stream" : "Stream handle or alias (atom)"],
187        exceptions:[4 : "Stream is not instantiated.", 5 : "Stream is neither an atom nor a number.", 192 : "Stream is not an output stream.", 193 : "Stream is an illegal stream specification."],
188        eg:"
189   Success:
190      open(file1,update,s), nl(s), close(s).
191      nl(output).
192Error:
193      nl(Stream).               (Error 4).
194      nl(7.0).                  (Error 5).
195      open(file1,read,s),nl(s). (Error 192). % read mode
196      nl(29).                   (Error 192). % stream not open
197      nl(-1).                   (Error 193). % out of range
198      nl(30).                   (Error 193). % out of range
199      nl(atom).                 (Error 193). % no such stream
200
201
202
203",
204        see_also:[nl / 0, writeln/2, flush/1, open/4, set_stream_property/3, get_stream_info/3]]).
205
206:- comment(unget / 1, [
207        summary:"Back up one character on Stream",
208        amode:(unget(+) is det),
209        desc:html("\
210    Go back one character on the given Stream. This can be used to
211    implement lookaheads.
212    <P>
213    The number of characters that can be reliably ungotten is 4, and the
214    result is only defined if these characters have been read previously.
215    <P>
216    The result of the operation is undefined if
217    <UL>
218    <LI>trying to unget more than 4 characters
219    <LI>trying to unget more characters than had been read previously
220    <LI>trying to unget after a seek operation
221    </UL>
222    In these cases, unget/1 will succeed, but subsequent read operations
223    will return undefined results.
224"),
225        args:[ "Stream" : "Stream handle or alias (atom)"],
226        exceptions:[4 : "Stream is not instantiated.",
227                5 : "Stream is neither a stream handle nor an atom.",
228                192 : "Stream not in read mode."],
229        eg:"
230% look ahead one character in Stream:
231
232    peek(Stream, X) :-
233        get(Stream, X),
234        unget(Stream).
235",
236        see_also:[get / 2, get_char/2]]).
237
238
239:- comment(get / 1, [
240        summary:"Reads the next character or byte from the current input stream",
241        amode:(get(-) is det),
242        desc:html("\
243   Takes the next character from the current input stream, and unifies its
244   integer character code with Code.  The range of possible values depends
245   on the stream's text encoding, or is 0 to 255 for binary streams.
246<P>
247   Character codes for the non-printable characters (i.e. control characters)
248   are treated like normal characters.
249<P>
250   On end-of-file, -1 is returned (via the default handler for event 190).
251"),
252        args:["Code" : "Variable or integer."],
253        exceptions:[5 : "Code is instantiated, but not to an integer.", 190 : "End of file has been reached."],
254        eg:"   Equivalent to get(input, Code).  (see get/2 for details).",
255        see_also:[get / 2, put / 1, put / 2]]).
256
257:- comment(get / 2, [
258        summary:"Reads the next character from the input stream Stream",
259        amode:(get(+, -) is det),
260        desc:html("\
261   Takes the next character from the input stream Stream, and unifies its
262   integer character code with Code.  The range of possible values depends
263   on the stream's text encoding, or is 0 to 255 for binary streams.
264<P>
265   Character codes for the non-printable characters (i.e. control characters)
266   are treated like normal characters.
267<P>
268   On end-of-file, -1 is returned (via the default handler for event 190).
269"),
270        args:[
271            "Stream" : "Stream handle or alias (atom)",
272            "Code" : "Variable or integer."],
273        exceptions:[4 : "Stream is not instantiated.", 5 : "Stream is neither a stream handle nor an atom.", 5 : "Code is instantiated, but not to an integer.", 190 : "End of file has been reached.", 192 : "Stream is not an input stream.", 193 : "Stream is an illegal stream specification."],
274        eg:"
275Success:
276      ?- get(input, X).
277       a
278      X = 97
279      yes.
280
281      ?- get(input, 0'a), get(input,97).
282       aa
283      yes.
284Fail:
285      ?- get(input,98).
286       a
287      no.
288Error:
289      get(Stream,98).                 (Error 4).
290      get(input, '98').               (Error 5).
291      get(10,A).                      (Error 192).
292      get(atom,A).                    (Error 193).
293",
294        see_also:[get / 1, put / 1, put / 2]]).
295
296:- comment(get_char / 1, [
297        summary:"Reads the next character from the current input",
298        amode:(get_char(-) is det),
299        desc:html("   Takes a single-character string from the current input and unifies it
300   with Char.
301<P>
302   Note that this predicate returns a string, while the corresponding predicate
303   iso:get_char/1 returns an atom!
304"),
305        args:["Char" : "Single character string or variable."],
306        exceptions:[5 : "Char is instantiated, but not to a string."],
307        eg:"   Equivalent to get_char(input, Char).  (see get_char/2 for details).
308",
309        see_also:[get_char / 2, iso:get_char/1, put_char / 1, put_char / 2]]).
310
311:- comment(get_char / 2, [
312        summary:"Reads the next character from the input stream Stream",
313        amode:(get_char(+,-) is det),
314        desc:html("   Takes a single character string from the input stream Stream.  and
315   unifies it with Char.
316<P>
317   Note that this predicate returns a string, while the corresponding predicate
318   iso:get_char/2 returns an atom!
319"),
320        args:[
321            "Stream" : "Stream handle or alias (atom)",
322            "Char" : "Single character string or variable."],
323        exceptions:[4 : "Stream is not instantiated.",
324	    5 : "Stream is neither a stream handle nor an atom.",
325	    5 : "Char is instantiated, but not to a single character string.",
326	    190 : "End of file has been reached.",
327	    192 : "Stream is not open for reading.",
328	    193 : "Stream is not a valid stream number."],
329        eg:"
330   Success:
331      ?- get_char(input,Char).
332       a
333      Char = \"a\"
334      yes.
335
336      ?- get_char(input, \"b\").
337       b
338      yes.
339
340      ?- sh('cat file1').
341      p
342      yes.
343      ?- open(file1, update,s),
344         get_char(s,X).
345      X = \"p\"
346      yes.
347Fail:
348      ?- get_char(input, \"b\").
349       a
350      no.
351
352Error:
353      get_char(Stream, \"b\").             (Error 4).
354      get_char(input, 'b').              (Error 5).
355      get_char(input, 98.0).             (Error 5).
356      get_char(\"string\", Char).          (Error 5).
357      get_char(null,Char).              (Error 190).
358      get_char(9,Char).                 (Error 192).
359      get_char(atom,Char).              (Error 193).
360
361
362
363",
364        see_also:[get / 1, get / 2, get_char / 1, iso:get_char/2, put / 1, put / 2, put_char / 1, put_char / 2]]).
365
366:- comment(put / 1, [
367        summary:"The character represented by the integer Code is put onto the
368buffered current output",
369        amode:(put(+) is det),
370        desc:html("\
371   Writes the character (or byte, in case of binary stream) represented by
372   the integer Code onto the buffered current output stream.  The acceptable
373   value range depends on the stream's character encoding, or is 0 to 255
374   for binary streams.
375<P>
376   Note that the output from put/1 is usually buffered, and is only output
377   to the screen when the output is flushed e.g. when returning to the
378   ECLiPSe prompt or explicitly using flush(output).
379<P>
380   Character codes for the non-printable characters (i.e. control characters)
381   are also acceptable.
382"),
383        args:["Code" : "Integer."],
384        exceptions:[4 : "Code is not instantiated.", 5 : "Code is instantiated, but not to an integer."],
385        eg:"   Equivalent to put(output, Code).  (see put/2 for details).
386
387
388
389",
390        see_also:[get / 1, get / 2, put / 2, nl/0]]).
391
392:- comment(put / 2, [
393        summary:"The character represented by the integer code Code is put onto the
394buffered output stream Stream.
395
396",
397        amode:(put(+, +) is det),
398        desc:html("\
399   Writes the character (or byte, in case of binary stream) represented by
400   the integer Code onto the output stream Stream.  The acceptable
401   value range depends on the stream's character encoding, or is 0 to 255
402   for binary streams.
403<P>
404   Note that the output from put/2 is usually buffered, and is only output
405   to the stream when the output is flushed (e.g.  using flush/1).
406<P>
407   Character codes for the non-printable characters (i.e. control characters)
408   are also acceptable.
409"),
410        args:[
411            "Stream" : "Stream handle or alias (atom)",
412            "Code" : "Integer."],
413        exceptions:[4 : "Stream is not instantiated.",
414		4 : "Code is not instantiated.",
415		5 : "Stream is neither a stream handle nor an atom.",
416		5 : "Code is instantiated, but not to an integer.",
417		192 : "Stream is not an output stream.",
418		193 : "Stream is an illegal stream specification."],
419        eg:"
420Success:
421      ?- put(output, 0'a).
422      a
423      yes.
424
425      ?- sh('cat file1').
426      a
427      yes.
428      ?- open(file1,read,s1),
429         open(file2,write,s2),repeat,
430         ( at_eof(s1) ->
431              !,
432              flush(s2),
433              close(s1),close(s2)
434         ;
435              get(s1,Char),
436              put(s2,Char),
437              fail
438         ).
439      Char = _g72
440      yes.
441      ?- sh('cat file2').
442      a
443      yes.
444
445Error:
446      put(output,A).             (Error 4).
447      put(Stream,98).            (Error 4).
448      put(output, '98').         (Error 5).
449      put(output, 98.0).         (Error 5).
450      put(\"string\" A).           (Error 5).
451      put(11,97).                (Error 192). % stream not open
452      put(atom,97).              (Error 193).
453
454
455
456",
457        see_also:[get / 1, get / 2, put / 1, nl/1]]).
458
459:- comment(put_char / 1, [
460        summary:"Puts the single character text Char onto the buffered current output.",
461        amode:(put_char(+) is det),
462        desc:html("   Puts the single-character string or atom Char onto the current output.
463"),
464        args:["Char" : "Single character string or atom."],
465        exceptions:[4 : "Char is not instantiated.", 5 : "Char is instantiated, but not to a single character string or atom."],
466        eg:"   Equivalent to put_char(output, Char).  (see put_char/2 for details).
467
468
469
470",
471        see_also:[get_char / 1, get_char / 2, put_char / 2, nl/0]]).
472
473:- comment(put_char / 2, [
474        summary:"Puts the single character text Char onto the buffered output stream Stream.",
475        amode:(put_char(+,+) is det),
476        desc:html("   Puts the single-character string or atom Char onto the output stream Stream.
477"),
478        args:[
479            "Stream" : "Stream handle or alias (atom)",
480            "Char" : "Single character string or atom."],
481        exceptions:[4 : "Stream is not instantiated.",
482	    4 : "Char is not instantiated.",
483	    5 : "Stream is neither a stream handle nor an atom.",
484	    5 : "Char is instantiated, but not to a single character string or atom.",
485	    192 : "Stream is not an output stream.",
486	    193 : "Stream is an illegal stream specification."],
487        eg:"
488Success:
489  ?- put_char(output, \"a\").
490  a
491  yes.
492
493  ?- put_char(output, '7').
494  7
495  yes.
496
497  ?- put_char(output, a).
498  a
499  yes.
500
501Error:
502  put_char(Stream,A).      (Error 4).
503  put_char(output,ab).     (Error 5).
504  put_char(output,98).     (Error 5).
505  put_char(11, \"a\").        (Error 192).
506  put_char(atom, \"a\").      (Error 193).
507
508
509
510",
511        see_also:[get_char / 1, get_char / 2, put_char / 1, nl/1]]).
512
513:- comment(read_string / 3, [
514        summary:"Reads a string from the input stream up to a delimiter or up to a specified length",
515        amode:(read_string(+,+,-) is semidet),
516        amode:(read_string(+,-,-) is semidet),
517        desc:html("   A string of characters is read from the input up to one character which
518   occurs in the delimiter string Delimiters.  This character is also
519   consumed, but does not appear in the string which is unified with
520   String.
521   
522   Two symbolic Delimiters can be specified:
523
524<P>
525<PRE>
526    end_of_line   a newline or carriage-return/newline sequence
527    end_of_file   the end of the file/input
528</PRE>
529   End of file always acts like a delimiter.
530
531<P>
532   If Length is a variable, it is unified with the length of the string
533   String.  If Length is an integer, the number of characters read from
534   the input is limited by the Length.
535
536<P>
537"),
538        args:["Delimiters" : "String or atom.", "Length" : "Integer or variable.", "String" : "String or variable."],
539        fail_if:"There is nothing to read, i.e. the stream is at end_of_file",
540        exceptions:[4 : "Delimiters is not instantiated.", 5 : "Delimiters is not a string or atom.", 5 : "Length is not an atom or an integer.", 5 : "String is not an atom or a string.", 6 : "Delimiters is an atom but not a valid symbolic delimiter.", 190 : "End of file was encountered before reading any character.", 198 : "Trying to read even after the error 190 was raised."],
541        eg:"   Equivalent to read_string(input, Delimiters, Length, String).  (see
542   read_string/4 for details).
543
544
545
546",
547        see_also:[read_string / 4, read_token / 2, read_token / 3, open / 3]]).
548
549:- comment(read_string / 4, [
550        summary:"Reads a string from the stream Stream up to a delimiter or up to a
551specified length.
552
553",
554        amode:(read_string(+,+,+,-) is semidet),
555        amode:(read_string(+,+,-,-) is semidet),
556        desc:html("   A string of characters is read from the input stream Stream up to one
557   character which occurs in the delimiter string Delimiters.  This
558   character is also consumed, but does not appear in the string which is
559   unified with String.
560
561<P>
562   Two symbolic Delimiters can be specified:
563
564<P>
565<PRE>
566    end_of_line   a newline or carriage-return/newline sequence
567    end_of_file   the end of the file/input
568</PRE>
569   End of file always acts like a delimiter.
570
571<P>
572   If Length is a variable, it is unified with the length of the string
573   String.  If Length is an integer, the number of characters read from
574   the input stream Stream is limited by Length.
575
576<P>
577"),
578        args:[
579            "Stream" : "Stream handle or alias (atom)",
580            "Delimiters" : "String or atom.", "Length" : "Integer or variable.", "String" : "String or variable."],
581        fail_if:"There is nothing to read, i.e. the stream is at end_of_file",
582        exceptions:[4 : "Delimiters is not instantiated.", 5 : "Delimiters is not a string or atom.", 5 : "Length is a non-integer number.", 5 : "String is not a variable or a string.", 6 : "Delimiters is an atom but not a valid symbolic delimiter.", 24 : "Length is not a variable or number.", 190 : "End of file was encountered before reading any character.", 192 : "Stream is not an input stream.", 193 : "Stream is an illegal stream specification.", 198 : "Trying to read even after the error 190 was raised."],
583        eg:"
584Success:
585      ?- read_string(input, \"123\", Length, String).
586       abcdef2ghi
587      Length = 6
588      String = \"abcdef\"
589      yes.
590
591      ?- read_string(input, \" \\t\", Length, String).
592       one two
593      Length = 3
594      String = \"one\"
595      yes.
596
597      ?- read_string(input, end_of_line, Length, String).
598      abcdefghi
599      Length = 9
600      String = \"abcdefghi\"
601      yes.
602
603      ?- read_string(input, end_of_line, 6, String).
604      abcdefghi
605      String = \"abcdef\"
606      yes.
607
608      ?- open(file1, read, s).
609      yes.
610      ?- system('cat file1').
611      abcd
612      yes.
613      ?- read_string(s, \"\", Length, String).
614      Length = 5
615      String = \"abcd\\n\"           % Read up to end of file
616      yes.
617
618
619% Code example: read lines from a file and return
620% a list of strings, each string containing a line
621
622    get_lines(File, Lines) :-
623        open(File, read, S),
624        stream_get_lines(S, Lines),
625        close(S).
626
627    stream_get_lines(S, Lines) :-
628        ( read_string(S, end_of_line, _, Line) ->
629            Lines = [Line|Ls],
630            stream_get_lines(S, Ls)
631        ;
632            Lines = []
633        ).
634
635
636Fail:
637      ?- open(string(\"\"),read,s), read_string(s,\"\",L,String).
638
639      no (more) solution.         % EOF - Error 190 - handler fails
640
641Error:
642    read_string(Stream, \"\", Length, String).       (Error 4).
643    read_string(stream, Dels, Length, String).     (Error 4).
644    read_string(\"stream\", \"\", Length, String).     (Error 5).
645    read_string(stream, 12, Length, String).       (Error 5).
646    read_string(stream, \"\", \"abc\", String).        (Error 5).
647    read_string(stream, \"\", Length, 12).           (Error 5).
648    read_string(stream, stop, Length, String).     (Error 6).
649    read_string(output, \"\", Length, String).       (Error 192).
650    read_string(atom, \"\", Length, String).         (Error 193).
651
652
653
654",
655        see_also:[read_string / 5, read_token / 2, read_token / 3, open / 3]]).
656
657
658:- comment(read_string / 5, [
659    summary:"Reads a string from the stream Stream up to a delimiter.",
660    amode:(read_string(+,+,+,-,-) is det),
661    args:[
662            "Stream" : "Stream handle or alias (atom)",
663            "SepChars" : "String (set of characters) or atom",
664            "PadChars" : "String (set of characters)",
665	    "Separator" : "Variable or integer character code",
666	    "String" : "Variable or string"],
667    exceptions:[
668	4 : "Stream, SepChars or PadChars is not instantiated.",
669    	5 : "SepChars is not a string or atom.",
670    	5 : "PadChars is not a string.",
671	6 : "SepChars is an atom but not a valid symbolic delimiter.",
672    	5 : "Stream is not an atom or handle.",
673	192 : "Stream is not an input stream.",
674	193 : "Stream is an illegal stream specification.",
675	198 : "Trying to read past the end of the stream."],
676    desc:html("<P>\
677    A string of characters is read from the input stream Stream,
678    up to a delimiter, ignoring any padding around the data.
679    More precisely, the predicate performs the following steps:
680<PRE>
681     * Skip all characters that match one of the PadChars.
682     * Read up to a character that matches one of SepChars or end of file.
683     * Discard trailing characters that match one of the PadChars
684       from the collected input.
685     * Unify String with a string created from the input, and Separator
686       with the code of the actual separator character consumed (or -1
687       if the input was terminated by the end of the stream).
688</PRE>
689    Both SepChars and PadChars are strings which are interpreted as sets of
690    characters.  I.e. any character that occurs in SepChars is a separator,
691    and any character that occurs in PadChars is a padding character.
692    In addition, two symbolic SepChars can be specified (as atoms):
693<PRE>
694    end_of_line   a LF or CR/LF sequence (returned Separator is LF (10))
695    end_of_file   the end of the file/input (returned Separator is -1)
696</PRE>
697    End of file always acts like a delimiter, therefore end_of_file means
698    the same as the empty Separator string.
699</P><P>
700    Once the predicate has returned a Separator of -1, the stream's end of
701    file has been consumed and subsequent reading attempts raise the error
702    'Trying to read past the end of the stream' (198).  This can be
703    changed by setting the stream's eof_action property to 'reset' (e.g.
704    during open/4), in which case the predicate will return empty strings
705    and a Separator of -1 indefinitely.
706</P><P>
707    Note: This predicate provides functionality similar to split_string/4,
708    except that SepChars and PadChars must not be partially overlapping (as
709    this would require lookahead and could cause unexpected blocking read).
710<P>
711"),
712        eg:"
713    % read one line from the input stream
714    ?- read_string(input, end_of_line, \"\", End, String).
715     hello world!
716
717    End = 10
718    String = \"hello world!\"
719    Yes (0.00s cpu)
720
721
722    % read input until end of file
723    ?- read_string(input, end_of_file, \"\", End, String).
724     abc
725     def
726    ^D	 
727    End = -1
728    String = \"abc\\ndef\\n\"
729    Yes (0.00s cpu)
730
731
732    % Separators and padding
733    ?- read_string(input, \",;\", \".\", Sep1, String1),
734       read_string(input, \",;\", \".\", Sep2, String2),
735       read_string(input, \",;\", \".\", Sep3, String3).
736     ...abc...def...;,...ghi...
737    ^D
738    Sep1 = 59
739    String1 = \"abc...def\"
740    Sep2 = 44
741    String2 = \"\"
742    Sep3 = -1
743    String3 = \"ghi...\\n\"
744    Yes (0.00s cpu)
745
746
747
748% Code example: read lines from a file and return
749% a list of strings, each string containing a line
750
751    get_lines(File, AllLines) :-
752        open(File, read, S),
753	(
754	    fromto(0,_,Sep,-1),
755	    fromto(AllLines,[Line|Lines],Lines,[]),
756	    param(S)
757	do
758	    read_string(S, end_of_line, \"\", Sep, Line)
759	),
760	close(S).
761",
762        see_also:[read_string / 4, read_token / 2, read_token / 3, open / 3, open/4]]).
763
764
765:- comment(tyi / 1, [
766        summary:"Succeeds if the code of the next character read in raw mode from the
767current input is successfully unified with Code.
768
769",
770        amode:(tyi(-) is det),
771        desc:html("   Takes the next character from the current input and unifies its integer
772   character code (in the range 0 to 255) with Code.  The input is in raw mode
773   so that no newline character must be typed.
774
775<P>
776   Character codes for the non-printable characters (i.e.  control characters)
777   are also acceptable.
778
779<P>
780"),
781        args:["Code" : "Variable or integer."],
782        exceptions:[5 : "Code is instantiated, but not to an integer.", 190 : "End of file was encountered before reading any character.", 198 : "Trying to read even after the error 190 was raised."],
783        eg:"   Equivalent to tyi(input, Code).  (see tyi/2 for details).
784
785
786
787",
788        see_also:[tyi / 2, tyo / 1, tyo / 2]]).
789
790:- comment(tyi / 2, [
791        summary:"Succeeds if the code of the next character read in raw mode from the
792input stream Stream is successfully unified with Code.
793
794",
795        amode:(tyi(+,-) is det),
796        desc:html("   Takes the next character from the unbuffered input stream Stream and
797   unifies its integer character code (in the range 0 to 255) with Code.  The
798   input is in raw mode so that no newline character must be typed, and the
799   character is not echoed on the screen.
800
801<P>
802   Character codes for the non-printable characters (i.e.  control characters)
803   are also acceptable.
804
805<P>
806Note
807   tyi/2 reads from the stream in raw mode.  If it is combined with the
808   buffered predicates, it might happen that some characters typed ahead
809   may be lost if the input device is a terminal.
810
811<P>
812"),
813        args:[
814            "Stream" : "Stream handle or alias (atom)",
815            "Code" : "Variable or integer."],
816        exceptions:[4 : "Stream is not instantiated.", 5 : "Stream is neither a stream handle nor an atom.", 5 : "Code is instantiated, but not to an integer.", 190 : "End of file has been reached.", 192 : "Stream is not an input stream.", 193 : "Stream is an illegal stream specification.", 198 : "Trying to read even after the error 190 was raised."],
817        eg:"
818Success:
819      ?- tyi(input,Code).
820      Code = 97         % press 'a'
821      yes.
822
823      ?- tyi(input,97).
824                            % press 'a'
825      yes.
826
827      ?- tyi(input,Code).
828      Code = 4          % press ^D
829      yes.
830
831Fail:
832      ?- tyi(input, 0'b).
833                            % press 'a'
834      no.
835
836Error:
837      tyi(Stream,98).             (Error 4).
838      tyi(input, '98').           (Error 5).
839      tyi(input, 98.0).           (Error 5).
840      tyi(\"string\", A).           (Error 5).
841
842      ?- open(file1,update,s), write(s,p),
843         seek(s,0), tyi(s,Code),
844      tyi(s,Code).              (Error 190).
845      tyi(9,A).                  (Error 192).
846      tyi(atom,A).               (Error 193).
847
848
849
850",
851        see_also:[tyi / 1, tyo / 1, tyo / 2]]).
852
853:- comment(tyo / 1, [
854        summary:"The character represented by the integer Code is put onto the
855current output in raw mode.
856
857",
858        amode:(tyo(+) is det),
859        desc:html("   Puts the character represented by the integer character code Code (in the
860   range 0 to 255) onto the current output in raw mode.
861
862<P>
863   If the output device is a terminal, the tyo/1 output goes directly to
864   the screen, whereas the output from put/1 is buffered first, and is only
865   output to the screen when the current output is flushed (e.g.
866   explicitly using flush(1).).
867
868<P>
869   Character codes for the non-printable characters (i.e.  control characters)
870   are also acceptable.
871
872<P>
873"),
874        args:["Code" : "Integer."],
875        exceptions:[4 : "Code is not instantiated.", 5 : "Code is instantiated, but not to an integer."],
876        eg:"   Equivalent to tyo(output, Code).  (see tyo/2 for details).
877
878
879
880",
881        see_also:[tyi / 1, tyi / 2, tyo / 2]]).
882
883:- comment(tyo / 2, [
884        summary:"The character represented by the integer Code is put onto the output
885stream Stream in raw mode.
886
887",
888        amode:(tyo(+,+) is det),
889        desc:html("   Puts the character represented by the integer character code Code (in the
890   range 0 to 255) onto the output stream Stream in raw mode.
891
892<P>
893   If the stream is a terminal, the tyo/2 output goes directly to the
894   stream, whereas the output from put/2 is buffered first, and is only
895   output to the stream when the output is flushed (e.g.  explicitly using
896   flush/1).
897
898<P>
899   If the stream is not a terminal, tyo/2 behaves like put/2.
900
901<P>
902   Character codes for the non-printable characters (i.e.  control characters)
903   are also acceptable.
904
905<P>
906"),
907        args:[
908            "Stream" : "Stream handle or alias (atom)",
909            "Code" : "Integer."],
910        exceptions:[4 : "Stream is not instantiated.", 4 : "Code is not instantiated.", 5 : "Stream is neither a stream handle nor an atom.", 5 : "Code is instantiated, but not to an integer.", 192 : "Stream is not an output stream.", 193 : "Stream is an illegal stream specification."],
911        eg:"
912   Success:
913      ?- set_stream(screen,output),
914         tyo(screen,91),tyo(screen,97),
915         tyo(screen,93).
916      [a]
917      yes.
918
919      ?- put(screen, 0'a), tyo(screen, 0'b),
920         put(screen, 0'c), tyo(screen, 0'd).
921      bdac
922      yes.
923
924      ?- write(screen,i), tyo(screen, 0'h).
925      hi
926      yes.
927
928Error:
929      tyo(Stream,A).                (Error 4).
930      tyo(output,a).                (Error 5).
931      tyo(98.0,output).             (Error 5).
932      tyo(\"string\", A).             (Error 5).
933      tyo(11,97).                   (Error 192).
934      tyo(atom,97).                 (Error 193).
935
936
937
938",
939        see_also:[tyi / 1, tyi / 2, tyo / 1]]).
940