Merge branch 'emacs' of http://git.hacks-galore.org/jao/factor
[factor/jcg.git] / core / io / io-docs.factor
blobd7534ddb5083080c12e3148e7a3644e6d45891af
1 USING: help.markup help.syntax quotations hashtables kernel
2 classes strings continuations destructors math byte-arrays ;
3 IN: io
5 HELP: stream-readln
6 { $values { "stream" "an input stream" } { "str/f" "a string or " { $link f } } }
7 { $contract "Reads a line of input from the stream. Outputs " { $link f } " on stream exhaustion." }
8 { $notes "Most code only works on one stream at a time and should instead use " { $link readln } "; see " { $link "stdio" } "." }
9 $io-error ;
11 HELP: stream-read1
12 { $values { "stream" "an input stream" } { "elt" "an element or " { $link f } } }
13 { $contract "Reads an element from the stream. Outputs " { $link f } " on stream exhaustion." }
14 { $notes "Most code only works on one stream at a time and should instead use " { $link read1 } "; see " { $link "stdio" } "." }
15 $io-error ;
17 HELP: stream-read
18 { $values { "n" "a non-negative integer" } { "stream" "an input stream" } { "seq" { $or byte-array string f } } }
19 { $contract "Reads " { $snippet "n" } " elements from the stream. Outputs a truncated string or " { $link f } " on stream exhaustion." }
20 { $notes "Most code only works on one stream at a time and should instead use " { $link read } "; see " { $link "stdio" } "." }
21 $io-error ;
23 HELP: stream-read-until
24 { $values { "seps" string } { "stream" "an input stream" } { "seq" { $or byte-array string f } } { "sep/f" "a character or " { $link f } } }
25 { $contract "Reads elements from the stream, until the first occurrence of a separator character, or stream exhaustion. In the former case, the separator is pushed on the stack, and is not part of the output string. In the latter case, the entire stream contents are output, along with " { $link f } "." }
26 { $notes "Most code only works on one stream at a time and should instead use " { $link read-until } "; see " { $link "stdio" } "." }
27 $io-error ;
29 HELP: stream-read-partial
30 { $values
31      { "n" "a non-negative integer" } { "stream" "an input stream" }
32      { "seq" { $or byte-array string f } } }
33 { $description "Reads at most " { $snippet "n" } " elements from a stream and returns up to that many characters without blocking. If no characters are available, blocks until some are and returns them." } ;
35 HELP: stream-write1
36 { $values { "elt" "an element" } { "stream" "an output stream" } }
37 { $contract "Writes an element to the stream. If the stream does buffering, output may not be performed immediately; use " { $link stream-flush } " to force output." }
38 { $notes "Most code only works on one stream at a time and should instead use " { $link write1 } "; see " { $link "stdio" } "." }
39 $io-error ;
41 HELP: stream-write
42 { $values { "seq" "a byte array or string" } { "stream" "an output stream" } }
43 { $contract "Writes a sequence of elements to the stream. If the stream does buffering, output may not be performed immediately; use " { $link stream-flush } " to force output." }
44 { $notes "Most code only works on one stream at a time and should instead use " { $link write } "; see " { $link "stdio" } "." }
45 $io-error ;
47 HELP: stream-flush
48 { $values { "stream" "an output stream" } }
49 { $contract "Waits for any pending output to complete." }
50 { $notes "With many output streams, written output is buffered and not sent to the underlying resource until either the buffer is full, or this word is called." }
51 { $notes "Most code only works on one stream at a time and should instead use " { $link flush } "; see " { $link "stdio" } "." }
52 $io-error ;
54 HELP: stream-nl
55 { $values { "stream" "an output stream" } }
56 { $contract "Writes a line terminator. If the stream does buffering, output may not be performed immediately; use " { $link stream-flush } " to force output." }
57 { $notes "Most code only works on one stream at a time and should instead use " { $link nl } "; see " { $link "stdio" } "." }
58 $io-error ;
60 HELP: stream-print
61 { $values { "str" string } { "stream" "an output stream" } }
62 { $description "Writes a newline-terminated string." }
63 { $notes "Most code only works on one stream at a time and should instead use " { $link print } "; see " { $link "stdio" } "." }
64 $io-error ;
66 HELP: stream-copy
67 { $values { "in" "an input stream" } { "out" "an output stream" } }
68 { $description "Copies the contents of one stream into another, closing both streams when done." } 
69 $io-error ;
71 HELP: input-stream
72 { $var-description "Holds an input stream for various implicit stream operations. Rebound using " { $link with-input-stream } " and " { $link with-input-stream* } "." } ;
74 HELP: output-stream
75 { $var-description "Holds an output stream for various implicit stream operations. Rebound using " { $link with-output-stream } " and " { $link with-output-stream* } "." } ;
77 HELP: error-stream
78 { $var-description "Holds an error stream." } ;
80 HELP: readln
81 { $values { "str/f" "a string or " { $link f } } }
82 { $description "Reads a line of input from " { $link input-stream } ". Outputs " { $link f } " on stream exhaustion." }
83 $io-error ;
85 HELP: read1
86 { $values { "elt" "an element or " { $link f } } }
87 { $description "Reads an element from " { $link input-stream } ". Outputs " { $link f } " on stream exhaustion." }
88 $io-error ;
90 HELP: read
91 { $values { "n" "a non-negative integer" } { "seq" { $or byte-array string f } } }
92 { $description "Reads " { $snippet "n" } " elements from " { $link input-stream } ". If there is no input available, outputs " { $link f } ". If there are less than " { $snippet "n" } " elements available, outputs a sequence shorter than " { $snippet "n" } " in length." }
93 $io-error ;
95 HELP: read-until
96 { $values { "seps" string } { "seq" { $or byte-array string f } } { "sep/f" "a character or " { $link f } } }
97 { $contract "Reads elements from " { $link input-stream } ". until the first occurrence of a separator, or stream exhaustion. In the former case, the separator character is pushed on the stack, and is not part of the output. In the latter case, the entire stream contents are output, along with " { $link f } "." }
98 $io-error ;
100 HELP: read-partial
101 { $values { "n" integer } { "seq" { $or byte-array string f } } }
102 { $description "Reads at most " { $snippet "n" } " elements from " { $link input-stream } " and returns them in a sequence. This word should be used instead of " { $link read } " when processing the entire element a chunk at a time, since on some stream implementations it may be slightly faster." } ;
104 HELP: write1
105 { $values { "elt" "an element" } }
106 { $contract "Writes an element to " { $link output-stream } ". If the stream does buffering, output may not be performed immediately; use " { $link flush } " to force output." }
107 $io-error ;
109 HELP: write
110 { $values { "seq" { $or byte-array string f } } }
111 { $description "Writes a sequence of elements to " { $link output-stream } ". If the stream does buffering, output may not be performed immediately; use " { $link flush } " to force output." }
112 $io-error ;
114 HELP: flush
115 { $description "Waits for any pending output on " { $link output-stream } " to complete." }
116 $io-error ;
118 HELP: nl
119 { $description "Writes a line terminator to " { $link output-stream } ". If the stream does buffering, output may not be performed immediately; use " { $link flush } " to force output." }
120 $io-error ;
122 HELP: print
123 { $values { "str" string } }
124 { $description "Writes a newline-terminated string to " { $link output-stream } "." }
125 $io-error ;
127 HELP: with-input-stream
128 { $values { "stream" "an input stream" } { "quot" quotation } }
129 { $description "Calls the quotation in a new dynamic scope, with " { $link input-stream } " rebound to  " { $snippet "stream" } ". The stream is closed if the quotation returns or throws an error." } ;
131 HELP: with-output-stream
132 { $values { "stream" "an output stream" } { "quot" quotation } }
133 { $description "Calls the quotation in a new dynamic scope, with " { $link output-stream } " rebound to  " { $snippet "stream" } ". The stream is closed if the quotation returns or throws an error." } ;
135 HELP: with-streams
136 { $values { "input" "an input stream" } { "output" "an output stream" } { "quot" quotation } }
137 { $description "Calls the quotation in a new dynamic scope, with " { $link input-stream } " rebound to  " { $snippet "input" } " and " { $link output-stream } " rebound to  " { $snippet "output" } ". The stream is closed if the quotation returns or throws an error." } ;
139 HELP: with-streams*
140 { $values { "input" "an input stream" } { "output" "an output stream" } { "quot" quotation } }
141 { $description "Calls the quotation in a new dynamic scope, with " { $link input-stream } " rebound to  " { $snippet "input" } " and " { $link output-stream } " rebound to  " { $snippet "output" } "." }
142 { $notes "This word does not close the stream. Compare with " { $link with-streams } "." } ;
144 { with-input-stream with-input-stream* } related-words
146 { with-output-stream with-output-stream* } related-words
148 HELP: with-input-stream*
149 { $values { "stream" "an input stream" } { "quot" quotation } }
150 { $description "Calls the quotation in a new dynamic scope, with " { $link input-stream } " rebound to  " { $snippet "stream" } "." }
151 { $notes "This word does not close the stream. Compare with " { $link with-input-stream } "." } ;
153 HELP: with-output-stream*
154 { $values { "stream" "an output stream" } { "quot" quotation } }
155 { $description "Calls the quotation in a new dynamic scope, with " { $link output-stream } " rebound to  " { $snippet "stream" } "." }
156 { $notes "This word does not close the stream. Compare with " { $link with-output-stream } "." } ;
158 HELP: bl
159 { $description "Outputs a space character (" { $snippet "\" \"" } ") to " { $link output-stream } "." }
160 $io-error ;
162 HELP: lines
163 { $values { "stream" "an input stream" } { "seq" "a sequence of strings" } }
164 { $description "Reads lines of text until the stream is exhausted, collecting them in a sequence of strings." } ;
166 HELP: each-line
167 { $values { "quot" { $quotation "( str -- )" } } }
168 { $description "Calls the quotation with successive lines of text, until the current " { $link input-stream } " is exhausted." } ;
170 HELP: each-block
171 { $values { "quot" { $quotation "( block -- )" } } }
172 { $description "Calls the quotation with successive blocks of data, until the current " { $link input-stream } " is exhausted." } ;
174 HELP: contents
175 { $values { "stream" "an input stream" } { "seq" "a string, byte array or " { $link f } } }
176 { $description "Reads the entire contents of a stream. If the stream is empty, outputs"  { $link f } "." }
177 $io-error ;
179 ARTICLE: "stream-protocol" "Stream protocol"
180 "The stream protocol consists of a large number of generic words, many of which are optional."
182 "Stream protocol words are rarely called directly, since code which only works with one stream at a time should be written use " { $link "stdio" } " instead, wrapping I/O operations such as " { $link read } " and " { $link write } " in " { $link with-input-stream } " and " { $link with-output-stream } "."
184 "All streams must implement the " { $link dispose } " word in addition to the stream protocol."
186 "These words are required for binary and string input streams:"
187 { $subsection stream-read1 }
188 { $subsection stream-read }
189 { $subsection stream-read-until }
190 { $subsection stream-read-partial }
191 "This word is only required for string input streams:"
192 { $subsection stream-readln }
193 "These words are required for binary and string output streams:"
194 { $subsection stream-flush }
195 { $subsection stream-write1 }
196 { $subsection stream-write }
197 "This word is only required for string output streams:"
198 { $subsection stream-nl }
199 "For a discussion of the distinction between binary and string streams, see " { $link "stream-elements" } "."
200 { $see-also "io.timeouts" } ;
202 ARTICLE: "stdio-motivation" "Motivation for default streams"
203 "Most I/O code only operates on one stream at a time. The " { $link input-stream } " and " { $link output-stream } " variables are implicit parameters used by many I/O words. Using this idiom improves code in three ways:"
204 { $list
205     { "Code becomes simpler because there is no need to keep a stream around on the stack." }
206     { "Code becomes more robust because " { $link with-input-stream } " and " { $link with-output-stream } " automatically close the streams if there is an error." }
207     { "Code becomes more reusable because it can be written to not worry about which stream is being used, and instead the caller can use " { $link with-input-stream } " or " { $link with-output-stream } " to specify the source or destination for I/O operations." }
209 "For example, here is a program which reads the first line of a file, converts it to an integer, then reads that many characters, and splits them into groups of 16:"
210 { $code
211     "USING: continuations kernel io io.files math.parser splitting ;"
212     "\"data.txt\" utf8 <file-reader>"
213     "dup stream-readln number>string over stream-read 16 group"
214     "swap dispose"
216 "This code has two problems: it has some unnecessary stack shuffling, and if either " { $link stream-readln } " or " { $link stream-read } " throws an I/O error, the stream is not closed because " { $link dispose } " is never reached. So we can add a call to " { $link with-disposal } " to ensure the stream is always closed:"
217 { $code
218     "USING: continuations kernel io io.files math.parser splitting ;"
219     "\"data.txt\" utf8 <file-reader> ["
220     "    dup stream-readln number>string over stream-read"
221     "    16 group"
222     "] with-disposal"
224 "This code is robust however it is more complex than it needs to be since. This is where the default stream words come in; using them, the above can be rewritten as follows:"
225 { $code
226     "USING: continuations kernel io io.files math.parser splitting ;"
227     "\"data.txt\" utf8 <file-reader> ["
228     "    readln number>string read 16 group"
229     "] with-input-stream"
231 "An even better implementation that takes advantage of a utility word:"
232 { $code
233     "USING: continuations kernel io io.files math.parser splitting ;"
234     "\"data.txt\" utf8 ["
235     "    readln number>string read 16 group"
236     "] with-file-reader"
237 } ;
239 ARTICLE: "stdio" "Default input and output streams"
240 { $subsection "stdio-motivation" }
241 "The default input stream is stored in a dynamically-scoped variable:"
242 { $subsection input-stream }
243 "Unless rebound in a child namespace, this variable will be set to a console stream for reading input from the user."
245 "Words reading from the default input stream:"
246 { $subsection read1 }
247 { $subsection read }
248 { $subsection read-until }
249 { $subsection read-partial }
250 "If the default input stream is a string stream (" { $link "stream-elements" } "), lines of text can be read:"
251 { $subsection readln }
252 "A pair of combinators for rebinding the " { $link input-stream } " variable:"
253 { $subsection with-input-stream }
254 { $subsection with-input-stream* }
255 "The default output stream is stored in a dynamically-scoped variable:"
256 { $subsection output-stream }
257 "Unless rebound in a child namespace, this variable will be set to a console stream for showing output to the user."
259 "Words writing to the default input stream:"
260 { $subsection flush }
261 { $subsection write1 }
262 { $subsection write }
263 "If the default output stream is a string stream (" { $link "stream-elements" } "), lines of text can be written:"
264 { $subsection readln }
265 { $subsection print }
266 { $subsection nl }
267 { $subsection bl }
268 "A pair of combinators for rebinding the " { $link output-stream } " variable:"
269 { $subsection with-output-stream }
270 { $subsection with-output-stream* }
271 "A pair of combinators for rebinding both default streams at once:"
272 { $subsection with-streams }
273 { $subsection with-streams* } ;
275 ARTICLE: "stream-utils" "Stream utilities"
276 "There are a few useful stream-related words which are not generic, but merely built up from the stream protocol."
278 "First, a simple composition of " { $link stream-write } " and " { $link stream-nl } ":"
279 { $subsection stream-print }
280 "Processing lines one by one:"
281 { $subsection lines }
282 { $subsection each-line }
283 "Processing blocks of data:"
284 { $subsection contents }
285 { $subsection each-block }
286 "Copying the contents of one stream to another:"
287 { $subsection stream-copy } ;
289 ARTICLE: "stream-elements" "Stream elements"
290 "There are two types of streams:"
291 { $list
292   { { $strong "Binary streams" } " - the elements are integers between 0 and 255, inclusive; they represent bytes. Reading a sequence of elements produces a " { $link byte-array } "." }
293   { { $strong "String streams" } " - the elements are non-negative integers, representing Unicode code points. Reading a sequence of elements produces a " { $link string } "." }
295 "Most external streams are binary streams, and can be wrapped in string streams once a suitable encoding has been provided; see " { $link "io.encodings" } "." ;
297 ARTICLE: "streams" "Streams"
298 "Input and output centers on the concept of a " { $emphasis "stream" } ", which is a source or sink of elements."
299 { $subsection "stream-elements" }
300 "A stream can either be passed around on the stack or bound to a dynamic variable and used as one of the two implicit " { $emphasis "default streams" } "."
301 { $subsection "stream-protocol" }
302 { $subsection "stdio" }
303 { $subsection "stream-utils" }
304 { $see-also "io.streams.string" "io.streams.plain" "io.streams.duplex" } ;
306 ABOUT: "streams"