# 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< ( -- ?a ?u f )
  Read input stream, accumulating a maximum of STR_MAXSZ characters into the
  string pool [lib/str] until LF or EOF is met or until the buffer is full.

  If at least one character could be read before EOF is met, or if EOF was never
  met, f=1 and "a u" represents the range of the accumulated characters. The
  final LF is not included.

  If the first character that was read was a EOF, f=0 and "a u" are absent.

  If PREVWS was LF, no accumulation occur and we "fake read" an empty range.
  Therefore, f=1, u=0, a is present. PREVWS is reset, so this condition can only
  occur once.

readline<# ( -- a u )
  Same as readline<, but abort with error instead of yielding f=0.

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".
