//$Id: README.TXT 1.3 1998/01/29 07:10:01 ska Exp $
Description of the implementation details of the STDIO package.

1. STDIO is also referred as the "file pointer"-based or FILE*
Input/Output or stream functions, or simply the "f"-functions. In
opposite to the IO package (the handle-based package), STDIO is ANSI
conform and implements character rewrite rules and a buffer mechanism.
Therefore it is sometimes also referred as "buffered" Input/Output.

2. Buffer Mechanisms
A buffer is associated to each stream. By default, each buffer has the
size BUFSIZ (at compile-time of the CLibrary), but the user can
dynamically change the buffer size at run-time. When the program
accesses data from the stream, they are not directly transfered to or
from the system but through the associated buffer. The buffer mechanism
tries to transfer data in chunks of the current buffer size of the stream.

STDIO knows about three types on how to buffer data:
a) "full buffering" (_IOFBF): The buffer mechanism tries to transfer
data to the system in chunks of the current buffer size.
This is the default mode for all streams created by fopen().

b) "line buffering" (_IOLBF): This is the default mode for output
streams connected to a TTY. In this mode the line-end character (usually
the ENTER key or the newline character) immediately starts transfering
data to the system. Another feature is the "link" between stdout and
stdin. If data is requested from stdin, but there is data pending in
stdout, stdout is flushed and the data is written.  Because stdout is
usually connected to a terminal, this shall ensure that the user knows
what s/he is to type in. Line-buffered input streams are behave as
full-buffered ones.

c) no buffering (_IONBF): In this mode all data is directly transferred
to or from the system at the time when the data transfer is requested by
by the program. Note: ungetc() will work for non-buffered streams, too.
"Unbuffered output stream" does not mean that there is no buffer
associated to the stream, but that the buffer, if any, is flushed after
each write into the stream.

3. Tracking of the last access type
Though, ANSI does not requires that the program can intermix read & write
accesses without a delimiting fseek(), this package allows this
feature. This will help the programmer to avoid erratic problems that
are difficult to track down, the cost for it is not that great.

4. Text vs. Binary
The STDIO package knows about character rewrite rules, that means that
the stream can automatically translate characters to convert them to
and from the system appearance. The most popular rewrite rule is the
newline mapping. C programs assume '\n' (a single character) to be the
newline character, but DOS uses '\r\n' (two characters). Streams will
convert them and make the difference invisible to the program.

To activate this translation, the "t" modifier must be specified within
the control string of fopen(). If this string contains neither "t" nor
"b", the stream is opened in textmode, if it is connected to a TTY.

^Z is currently NOT handled!

5. The FILE type
FILE is a typedef to the following structure:

struct __stdio_file {
  uchar_t *bufpos;   /* the next byte to write to or read from */
  uchar_t *bufread;  /* the end of data returned by last read() */
  uchar_t *bufwrite; /* highest address writable by macro */
  uchar_t *bufstart; /* the start of the buffer */
  uchar_t *bufend;   /* the end of the buffer; ie the byte after the last
                              malloc()ed byte */

  int fd; /* the file descriptor associated with the stream */
  int mode;

  uchar_t unbuf[8];	   /* The buffer for 'unbuffered' streams */

  struct __stdio_file * next;
};

The members are used for:

uchar_t *bufpos;   /* the next byte to write to or read from */
	This points to the byte that is to read or to be overwritten with
	the next call. bufstart <= bufpos <= bufend. One cannot assume
	that this position is valid to read from/write to wihtout
	checking the other pointers limiting the buffered data.

uchar_t *bufread;  /* the end of data returned by last read() */
	This is the first byte behind the buffered data when the stream is
	in read mode.
	bufpos <= bufread <= bufend

uchar_t *bufwrite; /* highest address writable by macro */
	This is the first byte behind the buffer when the stream is in write
	mode. The implementation ensures that bufwrite == bufstart, when the
	stream is in read mode. This will ensure that the putc() macro
	spawns fputc(), because putc() does not handle the mode change or
	the buffer overflow condition.

uchar_t *bufstart; /* the start of the buffer */
	The very first byte of the buffer.

uchar_t *bufend;   /* the end of the buffer; ie the byte after the last
						  malloc()ed byte */
	The byte immediately following the very last byte of the buffer.

int fd; /* the file descriptor associated with the stream */
	STDIO bases upon the IO package. The file descriptor is the "handle"
	to be passed to the handle-based IO functions.

int mode;
	This is a bitfield of flags describing the state the stream is in.

uchar_t unbuf[8];	   /* The buffer for 'unbuffered' streams */
	Due to internal requirements, e.g. the ungetc() function, no
	stream can be "really" unbuffered. By making the buffer very small
	the stream acts as if it were unbuffered.

struct __stdio_file * next;
	All streams created by fopen() are linked into a sinlge-linked list.
	This is necessary to automatically flush (commit) all open streams
	on exit.
	Probably this list can be droped, if we use magick numbers within
	the heap management, so that we can evaluate if a heap node is
	a FILE or not.

6. Buffer Contents
The contents of the buffer in binary mode is of no question.

The contents in text mode is another one:
a) Binary (non-translated) data in input mode
	This enables a correct seek when flushing the buffer. Though, it
	requires to translate the data each time the buffer is accessed, not
	only when the data is read from the system.
b) Text (translated) data in input mode
	If one could assume that all newlines are looking the same (e.g.
	either "\n" or "\r\n"), one could count the newlines within the
	translated buffer when to seek on flushing. Unfortunately that's a
	wrong assumption from time to time.
	One could store the beginning of the buffered data, then re-read
	and skip all the bytes & newlines until the place to seek to is
	reached. Unfortunately this method fails, if the input stream
	is a TTY or a pipe (well, not under DOS). Though, those streams
	are un-seekable and the user has to accept unpredictable results
	when seeking & flushing the stream. But will the required overhead
	be outweighted by the easier buffer requests? I think not.
c) Binary (translated) data in output mode
	This will allow a very easy method to write the data onto the output
	stream, because the whole buffer can be written at once.
d) Text (non-translated) data in output mode
	This allows to store more bytes into the buffer, but those few won't
	outwight the more problematic write of the buffer, because now the
	buffer must be written in parts than at a whole.

All in all, I think that binary data in both cases will serve the best
for now. This means to translate the data
	a) when getting it from the buffer in input mode,&
	b) when putting it into the buffer in output mode.

7. Common Notes

There are no assertation checks for:
	fopen(), fdopen(),& freopen()
except for the mode parameter. Because these functions are preprocessor
macros wrapping __fopen(), no assertation checking is possible.
