# Input/Output

The io/stream subsystem offers a unified API to read and write from and to any
device or filesystem. All words in this API revolve around a structure that we
call the "stream". This stream represent one "place" we read and write to,
and if needed save any state needed to fulfill the API's specification.

I/O operations are byte based.

When "EOF" is mentioned, it means "end of file". In some cases, it's a misnomer,
but the idea is the same: if all possible data from the I/O source have been
consumed, we're in EOF condition.

## IO API

Methods:

readbuf ( n stream -- a? read-n )
  Try to read "n" bytes from stream at current position. Unless EOF is reached,
  at least 1 byte must be read, but otherwise "read-n" can be lower than n, even
  if that doesn't take the stream to EOF. The idea is to take the stream, at
  most, to the end of its internal buffer. Return the number of bytes read and,
  if it was nonzero, return an address to the beginning of that buffer.

  After the read operation, advance current position by "read-n" bytes.

  The returned buffer must stay valid as long as a "buffer invalidating"
  operation isn't made on the same stream, that is, readbuf, writebuf, close.

writebuf ( a n stream -- written-n )
  Try to write "n" bytes from buffer "a" to stream at current position, growing
  the file if needed. The idea is the same as with readbuf: the filesystem can
  proceed as is best for its implementation, as long as it writes at least 1
  byte. If no data can be written, return 0.

  After the write operation, advance current position by "written-n" bytes.

close ( stream -- )
  Close stream and free its resources. When a stream is closed, operations on
  it become noops (read return 0, writes/seeks do nothing). The default
  implementation is a noop.

Words:

write ( a n stream -- written-n )
  Repeatedly call writebuf until at most "n" bytes have been written from
  buffer "a". Yields "written-n", the number of bytes that have actually been
  written.

write# ( a n stream -- )
  Call write and abort if "written-n" is not the same as "n".

read ( a n stream -- read-n )
  Repeatedly call readbuf until at most "n" bytes have been read into buffer
  "a" (which of course must be big enough). Yields "read-n", the number of bytes
  that have actually been read.

:read# ( a n stream -- )
  Call read and abort if "read-n" is not the same as "n".

:getc ( stream -- c )
  Read 1 byte from stream an return it. Advance position by 1 byte. Return -1 on
  EOF. This can be used to poll an interactive (keyboard, serial link, etc) I/O
  device: -1 is returned as long as there's nothing to return.

putc ( c stream -- )
  Write 1 byte to stream. Advance position by 1 byte. Aborts if unable to write.

puts ( str stream -- )
  Write str to stream.

spit ( dst stream -- )
  Until EOF is reached, read "stream" and write its contents to other stream
  "dst".

exec< ( w stream -- )
  Call "w" after having changed the input stream so that it spits "stream"'s
  contents. When "w" returns, restore input stream and closes stream.

  Note that the stream is read using "readbuf" with a "-1" argument (read as
  much as possible at once). It's efficient, but it means that "exec<" is only
  suitable for "w" consuming the whole stream.

exec1< ( w stream -- )
  Same as "exec<", but passes "1" to readbuf instead of "-1" (read one character
  at once). This is less efficient, but is suitable for "w" which partially
  reads the stream. Also, unlike "exec<", it doesn't close the stream.

readline ( stream -- ?a ?u f )
  Calls "readline<" with "stream" as the input. "exec1<" is used for this, which
  means partial reads are ok.

readline# ( stream -- a u )
  Same as readline, but with "readline<#" instead.

interpretstream ( stream -- )
  Run "interpret" with exec<.

capture ( w stream -- )
  Execute "w" with "emit" being overridden to "stream"'s "putc". Can be safely
  called from another capture.

## Console

This unit provides a "console" constant which is a stream that wraps "in<" and
"emit". This allows the operator to conveniently use stream words with data
coming from "in<" or going to "emit".
