# Input/Output

## The input stream

Our main loop feeds itself from what we call the input stream. It's an endless
stream of characters exposed by the "in< ( -- c )" word. This word is a consumer
for what we call the "input buffer", which is a range of characters in memory
represented by the INPTR and INSZ system variables.

When "in<" is called, the character that INPTR points to is read, INPTR is
increased and INSZ is decreased... unless one of these two conditions occur:

1. The read character is a 0.
2. INSZ is zero.

If one of those two conditions occur, we "rotate" the input stream by calling
an indirect word pointer NEXTIN< ( -- ?a u ). This word must return replacement
values for INPTR and INSZ, which just ran out of steam. The originating "in<"
call will then yield from that new stream.

NEXTIN< can also return u=0, in which case the originating "in<" call will yield
EOF (-1), which leads "word expected" abort in a regular interpret loop, but
can be used to control the end of other kinds of sub-interpret loops.

The "regular" input stream is provided by sys/rdln and makes NEXTIN< point to
a word that prompts for a line and then yields that line.

Overriding the input stream is generally made thus:

1. Save current INPTR, INSZ and NEXTIN< values.
2. Set new INPTR and INSZ values and NEXTIN< to the "endofstream" word, which
   simply yields u=0.
3. Run a word that consumes "in<" until EOF is encountered.
4. Restore INPTR, INSZ and NEXTIN<.

Words like "f<<" temporarily plug NEXTIN< into the opened file's :readbuf making
it yield u=0 at the end of the file. It then runs "interpret" with that input,
which is an interpret loop that runs until it encounters EOF. At that point,
the old INPTR, INSZ and NEXTIN< values are restored.

### Stepping back

It's a common pattern to want to "peek" the next character of the input stream
with the possibility to tell the system "alright, that character wan't mine to
process, I wash my hands of it". Having this ability greatly simplifies some
parsing patterns.

In Dusk, this possibility is realized through "stepback ( -- )". What this does
is that it "rewinds" the input stream by one character, which means that the
next "in<" will yield the same character it did last time.

This shouldn't be called more than once for a given "in<" because it might mess
with macros [doc/lib/macro].

When in EOF condition (if the last "in<" yielded -1), calling "stepback" has no
effect. We *don't* rewind into our old stream.

## Output

On the other side of the input stream pond, there's "emit ( c -- )" which wraps
the EMIT variable and spits a character at the operator's face (or the screen
they're looking at). Once it's set up, it rarely changes.

Then, over this, there's the "console" structbind which provides an IO interface
over both "in<" and "emit".
