.c	Thursday  Dec 1,1983  23:27  LQ+4D.17H.34M.20S.  -*- Bolio -*-

.chapter "Input, Output, and Streams"

Input and output in lan{nil} is performed by operations on
term_i{streams}.  Some streams can operate in only one direction
(input or output), and some can operate in both.

.defun streamp x
Returns 3t* if 2x* is a stream, 3nil* otherwise.
.end_defun

Most operations on streams are performed by functions which take the
stream as one of its arguments, possibly defaulted.  Although
ultimately the stream operations turn into message-passing using the
flavor system, these functions are the perferred way to do things, as
they perform what mediation might be necessary between the desired
effect and the stream's capabilities.

.section "Standard Streams"

The following variables have as their values streams used for various
purposes.  In the future, the names will be changed to have 3**
characters at both ends;  e.g., 3standard-input* will become
3*standard-input**.

.defvar standard-input
This is used as the default stream for various input functions, and
for the toplevel and breaklevel loops.
.end_defvar

.defvar standard-output
This is used as the default stream for various output functions, and
for the toplevel and breaklevel loops.
.end_defvar

.defvar terminal-io
The value of var{terminal-io} is ordinarily the stream which
connects to the user's console.
.end_defvar

.defvar error-output
This is the stream to which error messages should be sent.  Normally,
it directs output through the value of var{terminal-io} (but see
comments below), but it could be made to send them to a file, for
instance.  (This may not be used properly yet.)
.end_defvar

.defvar query-io
This stream is used to ask questions of the user.  Normally it
uses the terminal, but could be made to (for instance) log both the
input and the output of the transactions.
.end_defvar

.defvar *trace-output*
This is the stream to which output from tracing (see the
fun_i{trace} function, (trace-fun)) is sent.
.end_defvar

All of the above streams, with the exception of var{terminal-io},
are initially bound to synonym streams which pass all operations on to
the stream which is the value of var{terminal-io}.

The value of var{terminal-io} should not normally be changed;  to
change where various input and output is sent, the appropriate other
stream(s) should be modified.  There are occasions when it might be
reasonable to change the value of var{terminal-io}, however, which
is why the other streams are supposed to indirect through the value of
it:  fancy graphics or window hacking might necessitate making a
completely new stream for it.  This type of thing will be dealt with
in some later version of this document.

lan{Nil} additionally defines the following streams, which should
probably be flushed, or at least renamed with something more in line
with the above variables.

.defvar msgfiles
This is used for random kinds of message printout which will not
require interaction on the part of the user.  The compiler, for
instance, prints its notifications here.
.end_defvar

.defvar si:debug-input
.defvar1 si:debug-output
These are the input and output streams used by the current interactive
debugger.  When the next debugger is in use, it will be using some
combination of 3error-output* and 3query-io*.
.end_defvar


.section "Stream Creation and Operations"

.defun open what &rest keyworded-arguments
The 3open* function is the function used for creating streams
which interface to I/O devices in lan{nil}.  It is likely that this
will change in the future, such that each specific type of "opening"
has its own specialized function (e.g., for "files", "terminals",
possibly other devices), in which case 3open* will be for "files".

First, 2keyworded-arguments* is put into a canonicalized form.
Essentially,
fun{open} is considered to take alternating keyword/value arguments.
However, for lan{maclisp} compatibility, if fun{open} is given
exactly two arguments, the second is interpreted as either a single
keyword, or a list of single keywords, which are mapped specially into
the standard fun{open} keyword arguments.  Thus, in lan{nil},
.lisp
(open 2pathname* 'out)
.end_lisp
opens 2pathname* as a standard buffered ascii output file, and 
.lisp
(open 2pathname*)
.end_lisp
opens 2pathname* as an ordinary buffered ascii input file.

fun{open} attempts to determine the way in which to actually perform
the open by looking at the options.  I am being very vague about this
because it is going to change somewhat, but hopefully will remain
upwards compatible.  If there is a kwd{:type} keyword, then the
argument to that is used to tell fun{open} what type of open is
being performed.  The interesting ones right now are
.table 3 250 250
.item :dsk
which says that 2what* should be interpreted as a pathname, and
the fun{open} will refer to a file in some filesystem.  The
specifics of this for lan{vms} are discussed later in
((vms-open-specifics)).
.item :tty
which says that 2what* is the name of a terminal (it may be
(false), meaning use the logical name 3TT*), or a
string with or without a 3:* terminating it, or a pathname in
which the device is used), and the open should behave accordingly.
This tty may actually be quite useless, and you probably want instead
.item :display-tty
which is like kwd{:tty} but sets things up so that
fun_i{cursorpos} will work on it.  This is discussed more thoroughly
in (display-tty-section-page).
.end_table

If no kwd{:type} is specified and 2what* is a stream, it is sent
the msg_i{:open} message with
arguments 2keyworded-arguments*.  The normal use of this is to
re-open a stream which has been closed, and in this case no arguments
are normally needed (and often are illegal).
Not all streams necessarily support this, but all currently
defined lan{nil} streams which might be returned by fun{open} and
to which fun{close} is meaningful, do.  Many streams which support
this support the msg_i{:set-pathname} message, which is the
primitive form of the lan{maclisp} fun_i{cnamef} function;  this
allows changing the pathname which will be opened when a closed stream
is reopened.
.end_defun

.defspec with-open-file (var what &rest gubble) body...
This binds 2var* to the result of opening 2what* with options
2gubble*, and executes 2body* in that environment.  When the
2body* is exited, the file is closed.  (You cannot fool
fun{with-open-file} by fun{setq}ing 2var*.)  If the form is
exited abnormally, by an error, quit, or fun{*throw}, the file is
closed in kwd{:abort} mode;  for a freshly written output file, this
means it is deleted.

The behaviour of fun{with-open-file} with respect to treatment of
2what* and 2gubble*, and to errors in opening, is identical to
fun{open} otherwise.

fun{with-open-file} should be used wherever that scoping is
reasonable, so that stray open files are not left around by buggy
programs.  There is also potential for it to be somewhat more storage
efficient due to use of resources, since the extent of the created
stream is known to be dynamic (it is not valid to pass it back outside
of the fun{with-open-file} form).  This is not done yet, but will
be someday.
.end_defspec

.defun close stream &optional abort-flag
Closes 2stream*.

You may close an already closed stream;  3close* will return
3nil* if the stream is already closed (or does not support
closing), 3t* otherwise.

If 2abort-flag* is not (false), then (in principal) this is an
error close, as perhaps performed by abnormal exit from a
fun{with-open-file} form.  For an output file, this 2might* mean
that the file gets deleted.  This is done with ordinary "disk"
type output streams.

2abort-flag* will probably be changed to be a keyworded argument
in the future.
.end_defun

.defun make-synonym-stream symbol
This makes a term_i{synonym stream}.  Such a stream directs (most)
operations on it to the current dynamic binding of the variable
2symbol*.  In this way, the stream produced can always be
indirecting to another stream, even when the value of 2symbol*
changes by its being bound or 3setq*ed.
.end_defun

.defun make-string-output-stream &optional &key (:line-length 79) (:line-number 1) (:page-length 60) (:page-number 1) (:character-position 0)
This creates a stream which will accumulate all output given to it.
This output may be obtained as a string by
fun{get-output-stream-string}, below.

The 2options* are used to initialize various parameters of the
stream, so that formatting may be performed to it.  By special
dispensation to lan{common lisp}, if
fun{make-string-output-stream} is given exactly one argument, that
is the line length.
.end_defun

.defun get-output-stream-string string-output-stream
2string-output-stream* should be a stream created by
fun{make-string-output-stream}.  This returns all of the text
accumulated since the last call to fun{get-output-stream-string} on
this stream, or the stream's creation, as a string.
.end_defun

.defspec with-output-to-string (var . options) body...
This binds 2var* to a stream which will accumulate all output sent
to it as a string, which will be returned when
fun{with-output-to-string} returns.  The 2options* which the
stream may be created with are passed directly to
fun{make-string-output-stream}, q.v.  The stream so created has
only 2dynamic* extent;  it is allocated as a resource, and
deallocated on exit from fun{with-output-to-string}.  As such,
fun{with-output-to-string} can be more efficient than calling
fun{make-string-output-stream} and
fun{get-string-output-stream-string} yourself.
.end_defspec

.defun make-string-input-stream string &optional &key (:start 0) :end
This returns a stream which, when read from, will produce the
characters of 2string* from 2start* to 2end* (defaultly
the end of the string).  The behaviour of the stream is undefined if
2string* is modified during the reading.
.end_defun

.defspec with-input-from-string (var string . options) body...
This evaluates 2body* in an environment in which 2var* is
bound to a stream created by fun{make-string-input-stream} with a
string of 2string* and extra options 2options*.

The stream so created, however, has only 2dynamic* extent.  The
stream is allocated on entry and deallocated on exit for later reuse,
so fun{with-input-from-string} can be more efficient than doing this
yourself.
.end_defspec


.section "Input Functions"

First some functions not specific to ascii input streams
(necessarily).  fun{listen} and fun{clear-input} could conceivably
be meaningful on strange peripheral devices (dreamer, aren't i?).


.defun listen &optional input-stream
This will return (false) if there is no input immediately available
from 2input-sream*, non-null otherwise.  On a terminal, the intent
is that it tells whether the user has typed some input which has not
been read yet.  On non-interactive streams it should be true except at
end-of-file;  most streams probably don't support it yet.
.end_defun

.defun clear-input &optional input-stream
Flushes buffered input from 2input-stream*.  This only works on
the terminal right now.  (It isn't really meaningful for
non-interactive streams.)
.end_defun


.subsection "Ascii Input"

Most of the functions which read input take arguments
2input-stream* and 2eof-value*.  In general, if
2input-stream* is 3nil* or not supplied, it defaults to the
value of var{standard-input};  if it is the atom 3t*, the value
of var{terminal-io} will be used.

If no 2eof-value* is specified, then an error will be signalled at
end-of-file, otherwise the 2eof-value* will be returned.
Specifying an 2eof-value* of (false) is 2not* equivalent to
specifying no 2eof-value*.

When input is read from an interactive stream, the characters typed
will be echoed at the user.  For those functions which do some
significant amount of reading, such as fun{readline} or fun{read},
rubout processing will be provided.  In this case, specifying an
2eof-value* means that if the user attempts to "rub out" past the
beginning of what he was typing, the function will return
2eof-value*, instead of requiring him to type a complete
expression (line, s-expression, whatever the function calls for).

What actually happens right now is that specifying an 2eof-value*
when reading from an interactive stream, dies.

.defun read-char &optional input-stream eof-value
Reads one character from 2input-stream*.

This doesn't seem to take 2eof-value* yet?
.end_defun

.defun peek-char &optional input-stream eof-value
This definition is wrong.  The arguments should be 2peek-type*,
2input-stream*, 2eof-value*.  It will eventually be fixed.

Peek at a character in the input stream.  Like fun{read-char}, but
the next call to fun{read-char} will return the same character.
.end_defun

.defun unread-char character &optional input-stream
Undoes a fun{read-char}.  fun{peek-char}, in the simple case,
could have been (sometimes, is) defined as being a fun{read-char}
followed by an fun{unread-char} of the character just read.

Input streams are only required to support the ability to back up one
character:  multiple fun{unread-char}s without intervening
fun{read-char}s are an error.
.end_defun

.defun readline &optional input-stream eof-value
Reads a line of text from 2input-stream* and returns it, as a
string.  A second value is returned, which is (true) if end-of-file
was reached, (false) otherwise.
.end_defun

.defun read &optional input-stream eof-value
Reads one s-expression from 2input-stream*, and returns it.
Reading and reader syntax is discussed in (syntax-section-page).
.end_defun

.subsection "Binary Input"

The semantics of binary input are stream specific.  In
general, integers of some significance are read, and lan{nil} places
no special interpretation on any particular values.  The only sort of
binary input lan{nil} supports, however, only reads unsigned
eight-bit bytes from disk files.

.defun read-byte input-stream &optional eof-value
Reads one byte from 2input-stream* and returns it as an integer,
unless end of file is reached, in which case the normal end-of-file
behaviour occurs.
.end_defun


.section "Output Functions"

Similar to the input functions, if an optional 2output-stream*
argument is not supplied to an output function, it defaults to the
value of var{standard-output}.

First some functions applicable to both ascii and binary streams.  

.defun force-output output-stream
The purpose of fun{force-output} is to ensure that no output which
may have been produced is sitting around in anyone's buffers.  If
2output-stream* is buffered by lan{nil}, the output should be
sent to the operating system (or whatever), and if necessary, the
operating system told to send the contents of its buffers off to their
eventual destination.

In practice this doesn't do anything yet in lan{nil}.
.end_defun

.defun finish-output output-stream
This is like fun{force-output}, and additionally does not return
until the output has actually reached its destination.

If a stream does not handle this, which no currently implemented
lan{nil} streams do, a fun{force-output} is done, q.v.
.end_defun

.defun clear-output output-stream
The purpose of this is to cause as 2little* as possible of any
output already sent to 2output-stream* to reach its destination;  just
as fun{force-output} attempts to get all buffers sent off,
fun{clear-output} attempts to get all buffers flushed.

This is primarily intended for terminals, although it could be
meaningful for random other devices (ascii and binary).  It does not
do anything, and is not really expected to, to a random disk file.

It doesn't do anything to anything in lan{nil}.
.end_defun

.subsection "Ascii Output"

.defun write-char char &optional output-stream
Writes 2char* to 2output-stream*.
.end_defun

.defun terpri &optional output-stream
.defun1 fresh-line &optional output-stream
fun{terpri} performs a newline on 2output-stream*.

fun{fresh-line} does so, unless it can determine that the "cursor"
is at the left margin.

fun{fresh-line} is supposed to return (true) if it performed a
newline, (false) otherwise.  3terpri* always returns 3nil*,
for historical reasons.
.end_defun

.defun oustr string &optional output-stream (start 0) count
Standard lan{nil} string-output.  Outputs the characters of
2string*, starting at index 2start* and proceeding for
2count* characters, to 2output-stream*.  This is not defined
by lan{common lisp}, but has been in lan{nil} for some time and is
extremely useful for doing efficient output because it passes a
pseudo-substring defined by 2start* and 2count* along to the
stream.  Most lan{nil} streams do this more efficiently than
single-character output, especially the terminal stream.
.end_defun

.defun write-string string &optional stream
.defun1 write-line string &optional stream
Writes the characters of 2string* to 2stream*.
2write-line* follows them by a newline (3terpri*,
(terpri-fun)).  In lan{nil} this is almost always faster than
using a loop of 3write-char*s.
.end_defun

.defun princ object &optional output-stream
.defun1 prin1 object &optional output-stream
.defun1 print object &optional output-stream
Standard Maclisp-style printing functions.

fun{prin1} is the basic printing function, which attempts to output
the printed representation of 2object* to 2output-stream* in
such a way that it might be reconstructable with fun{read}.  No
newline or whitespace of any kind is output before or after, so
delimiters of some sort might be needed between successive calls.

fun{print} adds those necessary delimiters:  it does a fun{terpri}
first, and writes a space character afterwards.

fun{princ} is pretty much the same as fun{prin1} except it does
not try to make the output readable with fun{read}, but rather outputs
things "literally" insofar as that is possible with arbitrary Lisp
objects.  Strings, for example, are written as if by
fun{oustr}--simply their contents.  Symbols have their print-names
written as for strings, etc.  Numbers are generally printed the same
as they are by 3prin1*.
.end_defun


.subsection "Binary Output"

.defun write-byte integer binary-output-stream
Writes the byte 2integer* to 2binary-output-stream*.

2Note that the order of arguments here is the reverse of what the
1lan{maclisp}* 3out* function takes.  Because of earlier
confusion, the 3write-byte* function accepts its arguments in
either order right now.*

It is an error if 2integer* does not fit in the byte size the
stream deals with.  2How is this defined?  Probably by the stream,
i.e. the bytes could be signed or not, the current ones are not and
are 8-bits, so 1integer* can range from 0 to 255.*
.end_defun

.defun write-bits binary-output-stream bits
Writes the bit-vector 2bits* to 2binary-output-stream*.  The
intent of this is that 2bits* is taken to be a concatenation of
many bytes of data of whatever size the stream deals with.

It is an error for the size (in bits) of 2bits* to not be an exact
multiple of the byte size of the stream.

This function is provided primarily to help speed up the lan{nil}
compiler in creating lan{vasl} files.  The semantics may change some
as additional forms of binary streams are added to lan{nil}.

This may in fact be flushed.
.end_defun


.section "Formatted Output"
.setq formatted-output-section-page section-page

See also 3format*, which is sufficiently complex (and, in
lan{nil}, somewhat programmable) that it a separate section devoted
to it ((format-section-page)).

.defun pretty-prin1 object &optional stream
Similar to 3prin1*, but outputs 2object* in (what is hoped to
be) a significantly more aesthetic format, with indentation showing
nesting depth etc.  The output starts wherever the cursor happens to
be on 2stream*;  3pretty-print* may be used to do this on a
new line.

3pretty-prin1* assumes that 2object* is actually lan{lisp}
code, and bases its formatting behaviour on stylistic conventions used
for indenting various program constructs.  3pretty-prin1-datum*
may be used if 2object* should not have these heuristics applied.

In lan{nil}, 3pretty-prin1* attempts to determine the existence
of circular structure, and show this somehow without blowing up.

The pretty-printer itself is described in much more detail in
ref{Pretty-Print}.
.end_defun

.defun pretty-print object &optional stream
3pretty-prin1*, with a 3terpri* first and output of a space
character after.  This, 3pretty-print* is to 3pretty-prin1* as
3print* is to 3prin1*.
.end_defun

.defun pretty-prin1-datum object &optional stream
Like 3pretty-prin1*, but does 2not* assume that 2object*
is lan{lisp} code.
.end_defun

.defun pretty-print-datum object &optional stream
Similar.
.end_defun

.c .Section all its own
.insert format

.section "Querying the User"

The following routines are built on the fun_i{fquery} function,
which is modeled after that of lan{lispm}.  3fquery* is
complicated and subject to change, however, and is not itself
documented here.  Of the following routines, 3y-or-n-p* and
3yes-or-no-p* are defined by lan{common lisp};  the others are
not.

.defun y-or-n-p &optional message stream
This prints 2message* to 2stream* (which defaults to the value
of 3query-io*), and then reads a character from 2stream*.  It
returns 3t* or 3nil* depending on whether the character
signified a positive or negative response:  space and rubout are
accepted in place of 3y* and 3n*.  Because it is so easy to
get a mistaken response from this routine, it should be used for
anticipated questions only.

Because it is used for both input and output, 2stream* must be
bi-directional.
.end_defun

.defun yes-or-no-p &optional message stream
This is similar to 3y-or-n-p*, but requires a more complete
answer.  Typeahead to 2stream* is flushed (with 3clear-input*,
(clear-input-fun)), and it feeps, before reading a complete "yes" or
"no" followed by a newline.
.end_defun

.defun format-y-or-n-p format-string &rest format-args
Most the time when fun{y-or-n-p} is used, people seem to want to use
a format string with some arguments.  This does that.  Input and
output is done to var{query-io}.  Otherwise, it behaves like
3y-or-n-p*.
.end_defun

.defun format-yes-or-no-p format-string &rest fomrat-args
Similar.
.end_defun


.section "Filesystem Interface"

The lan{nil} filesystem interface is designed to allow it to refer
to more than one filesystem.  The names of files are not represented
as just strings or lists of components, but are objects of type
3pathname*.  The pathname objects for different filesystems or
term_i{hosts} would
be of different types, and operations on files in the filesystem are
performed with respect to that type.  For instance, we have under
development facilities to allow use of the filesystems of
lan{tops-20} and lan{its} through lan{chaosnet}.  At the moment,
only the local lan{vms} filesystem is supported.

.subsection "Pathnames"

A pathname has six criterial components.
.table 3 250 250 
.item host
This component always contains an object which describes the
filesystem the pathname refers to.  All pathnames have such a
component;  no pathname may be formed without such a component.  Thus,
pathname interpretation is always performed with respect to some
host.
.item device
This is normally a string, naming a device.
.item directory
A string naming a directory, or a list of strings, if the directory is
structured (that is, if the pathname is in a subdirectory).
.item name
A string, the "primary" or "root" name of the file.
.item type
A string, the "type" of the file.  This is not necessarily as the
2extension* which will be used to form the host-specific pathname
string;  e.g., for a lan{vms} filesystem, a file type of
7LISP* corresponds to the extension 7LSP*.
.item version
This is the version of the pathname;  usually it is an integer.
.end_table

A pathname need not refer to an actual file in a filesystem, nor need
all the components (other than the host) be present.  An unspecified
component is represented by 3nil*.  Such a component may be
supplied by later defaulting operations.  Components may also contain
certain keywords which are interpreted specially:
.table 3 250 250
.item :wild
A "wildcard" component.
.item :newest
.item1 :oldest
These are only applicable to the 3version* component of a
pathname.  They cause the reference to the filesystem to refer to the
newest or oldest version present.  Only 3:newest* is actually
supported by the lan{vms} filesystem interface.
.item :unspecific
If any component in a pathname has this as its value, then the
pathname does not refer to a specific file in the filesystem, but
rather to the group of files which match the other components.  This
is normally only used for the 3type* or 3version* components,
so that one may refer to the entire group of files with the same
device, directory, and name.  This doesn't have any use in lan{nil}
yet;  when lan{nil} pathnames gain the ability to have arbitrary
attributes (properties) associated with them, it will be significant.
.item :implied
If a pathname has this as a component, it means that the 3device*
component is a logical name which will supply the value for that
component.  This is used as a placeholder for "pathname merging".  All
components other than the host and device components may take on this
as their value.
.item :relative
This can only occur within a structured directory component.  It is
used in the representation of lan{vms} rooted directories.  For
instance, the lan{vms} pathname 7__DBA0:[NIL259.]* parses into a
pathname with the string 7"__DBA0"* as its device component,
and the list 7("NIL259" . :relative)* as its directory
component.  lan{nil} uses this in pathname merging.
.item :elipsis
This is used in representing things like 7nil$disk:[nil...]*.
Parsing that into a pathname would produce a directory component of
7("NIL" . :elipsis)*.  It will probably be flushed in favor of
utilizing just 3:wild* instead.
.end_table

.subsubsection "Pathname Functions"

.defun pathname thing
2thing* is coerced into a pathname.

If it is a pathname, it is returned.

If it is a list, then it is assumed to be a lan{maclisp} namelist;
interpretation of this, and lan{maclisp} compatible pathname
handling, is discussed in (maclisp-pathname-section-page).

If it is a string (or symbol), then the text is examined for a prefix
or suffix component, followed by a ":", which is a host string;  if
one is found, then that is the host used, otherwise a host is
defaulted (the handling of this is pretty spastic right now, but
hardly matters as there is only one host).  The string is then parsed
in the manner specific to that host, and the resultant pathname
returned.
.end_defun

.defun pathname-host pathname
.defun1 pathname-device pathname
.defun1 pathname-directory pathname
.defun1 pathname-name pathname
.defun1 pathname-type pathname
.defun1 pathname-version pathname
These return the components of 2pathname*, which is coerced to a
pathname with the fun{pathname} function.
.end_defun


.defun namestring pathname
2pathname* is coerced to a pathname with the fun{pathname}
function, and its "standard printed representation" returned, as a
string.
.end_defun

.defun user-homedir-pathname &optional host
Returns the user's home directory, as a pathname:  the kwd{name},
kwd{type}, and kwd{version} components will be unspecified.

The home directory is where files specific to the user are looked for
(or defaulted to).  See, for instance, fun{init-file-pathname},
(init-file-pathname-fun).

Under lan{vms}, this is obtained by translating the logical name
7SYS$LOGIN*.
.end_defun

.defun user-workingdir-pathname &optional host
Returns the user's working directory, as a pathname:  the kwd{name},
kwd{type}, and kwd{version} components will be unspecified.

For lan{vms}, this is obtained from the lan{rms} default directory
string, and the 7SYS$DISK* logical name.  Note that the lan{rms}
default is copied from the command interpreter when the lan{nil}
process is created;  temporarily exiting the lan{nil} and changing
the default will 2not* change the value of this.
.end_defun

.defun user-scratchdir-pathname &optional host
Returns, as a pathname, the directory of the directory which should be
used by programs for writing "scratch" files.

The local-vms host uses the value of the logical name
7SYS$SCRATCH* if that exists, otherwise the user's home directory.
If for some reason the device field is absent, 7SYS$DISK* is
supplied.  Note that the value of the logical name is copied from the
command interpreter when the lan{nil} is created.  Temporarily
exiting from the lan{nil} and changing the logical name definition
will have no effect.
.end_defun

.defun init-file-pathname program-name &optional host
This returns the pathname of the user's init file for
2program-name* on 2host*.  2program-name* should be a
string.

For lan{nil} under lan{vms}, the init file is on the user's home
directory, and has name lan{nil} and extension lan{ini} (the file
type is lan{init}).  This
same convention is used in general by this function;  for an arbitrary
program name, the init file is named, essentially,
.lisp
SYS$LOGIN:2program-name*.INI
.end_lisp
In the lan{nil} programming environment, this is more for the use of
lan{lisp} subsystems than a general facility (which could do things
like determine the init file for logging into the vax).  For example,
if you had a system lan{lsb} which people loaded into their
lan{nil}, or which was dumped out in a lan{nil}, it might load an
lan{lsb} init file.  Note that there is a problem here if
2program-name* is not valid as a pathname kwd{name} component
for the particular host.
.end_defun

.subsubsection "Merging and Defaulting"
.cindex merging and defaulting of pathnames
Merging and defaulting are the actions used to fill in components
missing from a pathname specification, usually when the pathname is
about to be used to reference something in the filesystem.  For the
most part, this involves supplying the components missing in one
pathname from another.  The algorithm used is slightly more
complicated, and is described under fun{merge-pathname-defaults},
below.

In lan{nil}, the pathname defaults for a specific application are
maintained in a term_i{pathname defaults} object (it will probably
be of type kwd{fs:pathname-defaults}).  This enables modular
handling of supplying of defaults for multiple hosts, pathname
"stickiness" for sets of commands, etc.  The defaults are often used
to supply the host with respect to which some operation must be
performed, such as pathname parsing.

.defun merge-pathname-defaults pathname &optional defaults default-type default-version
This is the main merger.  2pathname* may be anything coercible to
a pathname.  2defaults* may be a pathname defaults object, a
pathname, or a string or symbol (which will be coerced to a pathname
first).  2default-type* and 2default-version* may be whatever is
allowable for types and versions.

If it is necessary, 2pathname* will be parsed with respect to a
host determined from 2defaults*.  If the directory field of it is
missing, then that will be supplied by 2defaults*.  There is some
question as to what should happen if the device field of
2pathname* is missing:  currently, it is simply filled in from
2defaults*.  In the Lisp Machine implementation of this function,
it is supplied as the default device for the host (perhaps
inconsistently, for instance only when parsed from a string?);
probably what should happen is that whether the device comes from
2defaults* or not is determined by the host, so that it would if
the devices were really structured (with directories in them etc.),
and would not otherwise (which in Lisp Machine Lisp appears to be
mainly for the sake of the ITS operating system).

If 2pathname* has a name supplied, then if the type and version of
the resulting pathname are defaulted from 2default-type* and
2default-version*, as necessary.  Otherwise, the name, type, and
version are defaulted from 2defaults*.  Thus:
.lisp
(merge-pathname-defaults
   "[nil.vas]foo" "sys$disk:[gsb]zz.lsp;3" "vasl")
  => #<local-vms-pathname "node:sys$disk:[nil.vas]foo.vas">
(merge-pathname-defaults
   "[nil.vas]" "sys$disk:[gsb]zz.lsp;3" "vasl")
  => #<local-vms-pathname "node:sys$disk:[nil.vas]zz.lsp;3">
(merge-pathname-defaults
   "[nil.vas]=.inp" "sys$disk:[gsb]zz.lsp;3" "lisp")
  => #<local-vms-pathname "node:sys$disk:[nil.vas]zz.inp;3">
.end_lisp
In the above, it is worth noting that "=" as a pathname component is
used as a placeholder for an unspecified component, and that a file
type of 3lisp* is mapped (by the lan{vms} pathname code) into an
extension of 3lsp*, and 3vasl* to 3vas*.  The specifics of
the syntax and file-type/extension mapping are described elsewhere.

The default value of 2default-version* is 3:newest*.  The
default value of 2default-type* is 3"lisp"*;  however, it is
highly recommended that this 2not* be depended upon, as it may be
changed to come from 2defaults*.
.end_defun


Here are some of the pathname defaults in use in lan{nil}.

.defvar *load-pathname-defaults*
This is used to provide pathname defaults for fun{load},
fun{compile-file}, and any similar functions.  It is initialized to
the user's working directory with name 7FOO* and type 7LISP*
(see fun{user-workingdir-pathname},
(user-workingdir-pathname-fun)).
.end_defvar

.defvar *default-pathname-defaults*
This provides super-defaults for anything that needs them, such as
fun{open}, fun{with-open-file}, and parsing a pathname string out
of context.  It is initialized to the user's working directory with
name 7FOO* and type 7LISP* (see
fun{user-workingdir-pathname}, (user-workingdir-pathname-fun)).
.end_defvar

.defvar *scratch-pathname-defaults*
This is used by things which must write out "temporary" files.
Things which use this should not modify it;  it should be left to the
user to set default pathnames for hosts (primarily for the sake of the
device and directory) to say where such files should be written. See
fun{user-scratchdir-pathname}, (user-scratchdir-pathname-fun).

For example, the current lan{nil} fun{compile} function creates a
file named 3aaafoo.vas*, and supplies the device and directory
from var{*scratch-pathname-defaults*}.
.end_defvar


.subsection "Opening Files"

.setq vms-open-specifics page
Files are opened with the 3open* function ((open-fun)), or
3with-open-file* ((with-open-file-fun)), and may be closed with
3close* ((close-fun)).  3open* by default assumes that the
open is a reference to a file, so coerces its first argument to a
pathname, and then creates a stream to the specified file in the
filesystem.  lan{Nil} currently employs only two modes of file
opening.  These are kwd{:ascii} and kwd{:byte} modes.

kwd{:ascii} will cause the file to be written as variable-length
records, with record-attribute of carriage-return.  The existing disk
I/O code does not have the intelligence to deal with records longer
than 512 bytes, however, so is forced to terminate records when that
limit is reached.  To compensate, so that spurious newlines do not get
inserted into lan{lisp} files, records exactly 512 long are assumed
to not actually be terminated, but "continued" with the next record, when
read as input.

kwd{:fixnum} simply uses fixed-length 512-byte records;  this is
what 7vasl* files use.

.defun fs:close-all-files
In case you ido* mess up and lose track of some files, this will
close all open files (which have been really opened as streams, not
just kludgey temporary opens).  Every known host object is supposed to
keep track of all streams which it has open, in such a way as to be
secure against timing screws, so that this may at least be done.

Doing 3(exhibit fs:*host-instances*)* should give one a
handle on the open files, as the host instances should point to the
files they have open.  var_i{fs:*host-instances*} is the list of all
known hosts, and is used to (among other things) drive host-name
lookup.
.end_defun

.subsection "Other File Operations"

.defun probe-file pathname
If 2pathname* (which is coerced to a pathname with the
3pathname* function) can be opened, its truename is returned;
otherwise,  3nil* is returned.  This may be used to see if
2pathname* exists and is accessible.  (If a file protection error
occurs, 3probe-file* returns 3nil*, although that may change,
as the intent is to see if the file exists.)
.end_defun

Note fun_i{file-length} and fun_i{filepos} are missing from
lan{nil}.

All of the remaining functions in this section deal with either a
stream, or with a pathname.  For the former, they perform the
operation on the open stream;  for the latter, on the file in the
filesystem, which may involve opening the file temporarily.  At
present, none of them work on streams.  A future edition of the
filesystem code will contain more code written in lan{lisp}, and be
much more versatile in this regard.

For the functions which are described as returning an error
description, this is probably a string, but may change to be a more
complicated object in the future.  (That object should, however, have
the property that it will print with fun{princ} as the error
message.)  Tests made on the return result should be made accordingly;
that is, be based on fun{null}, or fun{streamp}, or fun{listp}
or whatever.  Signalled errors are typically signalled as proceedable
kwd{:io-lossage} errors;  returning a value from the error should
cause the function to return that as its value.

.defun rename-file file new-name &optional (error-p t)
Renames 2file*, a filename or a stream open to a file, to
2new-name*, which must be coercible to a pathname.  If
2error-p* is not (false), then a file-system error will be
signaled as a lan{lisp} error;  if it is (false), then an error
description will be returned.  If everything goes fine, (false) is
returned.
.end_defun

.defun delete-file file &optional (error-p t)
The file named by 2file*, or the file open on the stream
2file*, is deleted.  If an error occurs, then a lan{lisp} error
will be signaled if 2error-p* is not (false), otherwise an error
description will be returned.  If all goes well, (false) is
returned.
.end_defun

.defun file-creation-date file
This returns the creation date of the file as an integer in universal
time format (see (time-package-section-page)), or (false) if this
cannot be determined.
.end_defun

.defun file-author file
Returns the name of the author of the file as a string, or (false).
For lan{vms} files, the string is a UIC, e.g. 3"[200,007]"*, and
the group and member numbers are guaranteed to be padded with leading
zeros to at least three digits.
.end_defun

.subsection "File Matching"

.defun allfiles list-of-pathnames
Returns a list of pathnames matching all of those in
2list-of-pathnames*.  This is done, of course, by appending
together the lists of pathnames which match each of the pathnames in
2list-of-pathnames*.

By convention, this matches over all those components not specified in
each pathname.  lan{vms} does not allow matching all devices,
however, so the device should be specified, or will be defaulted from
somewhere (where?  rms default but it shouldn't be).  Newest versions
can be matched also, by using the appropriate pathname syntax.
Note that elipsis specifications in directories, and star
specifications in names, all work (fortuitously, perhaps, but they
work):  e.g., 3(allfiles "[nil...]286*.*;")* returns a list of
pathnames of the files with
highest version number of all the files in the lan{nil} hierarchy
with first three characters of their name being "286".
.end_defun

.defun mapallfiles function list-of-pathnames
Calls 2function* on each pathname which matches pathnames in
2list-of-pathnames*.  This is essentially equivalent to
.lisp
(mapc 2function* (allfiles 2list-of-pathnames*))
.end_lisp
but calls 2function* on each as it is generated rather than
consing up the list.

In fact, fun{allfiles} is implemented in terms of
fun{mapallfiles}.
.end_defun

fun{mapallfiles} (and hence fun{allfiles}) accept a single
symbol/string/pathname in place of a list.  It is unclear what should
be done about this;  it is (currently at least) of no use to
lan{nil} to deal with multiple specifications at once, and in fact
the original fun{allfiles} function in lan{multics maclisp} did
not take a list, but only a single pathname.

There is also no kludgy testing in lan{nil} such that if a namelist
is specified it must be a fully-specified namelist (insofar as
explicit "*" components are specified).  Thus using a namelist as a
single pathname will be interpreted as a list of pathnames,
potentially resulting (incorrectly) in a match over all the files on
the current device...  (That was the reason for the kludgey check in
lan{maclisp}, you see...)

.subsection "Loading Files"

.defun load filename &key :verbose :package :set-default-pathname :static :default-pathname :characters :binary :defaults :print
.table 3 250 250
.item :verbose
Boolean:  print out lots of gubbish about loading.  Default is value of
var{*load-verbose*}.
.item :package
override the package specification (if any) obtained from the file.
.item :set-default-pathname
Boolean:  set the default pathname of the pathname-defaults used (see
kwd{:defaults} and kwd{:default-pathname}, below).
Default is value of var{*load-set-default-pathname*}.
.item :defaults
Specified pathname-defaults to use in place of the value of
var{*load-pathname-defaults*}.  (This one isn't in lan{common
lisp}.  Not clear it should be heavily used, but i can see it has
application.)
.item :default-pathname
Use this for defaulting, in preference to the pathname-defaults.  The
defaults are still set in the defaults specified by kwd{:defaults}
(or its absence).
.item :characters
.item1 :binary
Boolean.  kwd{:binary t} implies that the file is a lan{vasl}
file;  lan{:characters t} implies that the file is lan{lisp} text.
By default, the file is examined to determine which it is.  And, if no
kwd{type} is specified in 2filename*, first a file with type
3vasl* and then a file with type 3lisp* will be looked for.
.item :static
Boolean;  says to load the file into the static heap.  Default is
value of var{*load-in-static-area*}.
.item :print
Boolean;  if not (false), says that the results of evaluation of
forms in the file are to be printed.  Default is (false), and it
probably doesn't work anyway;  certainly not for 3vasl* files.
.end_table
.end_defun

.subsection "File Attribute Lists"
.setq file-attribute-section-page section-page
.setq file-attribute-list-section-page section-page
.setq file-plist-section-page section-page
.setq file-property-list-section-page section-page

Not too much detail yet...  However, it's necessary to use it.

If, on the first line of a source file the characters "-*-" appear,
then the text from the first "-*-" to the next is parsed as a
term_i{file attribute list}.  (Funnyness with multiple lines?  Well,
anyway, it works easily on one line.)  This text is logically a list
of keyword/value pairs, with the values being either single values or
lists of values.  The entire construct is made invisible to the
processing language by being placed within its commenting construct.
.lisp
; -*- Mode:Lisp; Package:Compiler; Base:10; Readtable:NIL -*-
.end_lisp
might occur as the first line in a lan{nil} compiler source file.
It says that the 3mode* of the file is 3lisp* (this being for
the benefit of text editors), and that the file should be read and
processed in the 3compiler* package, decimal radix, and using the
lan{nil} readtable.  "Lists" of values are provided for by
separating the individual items by commas, as in
.lisp
; -*-  Mode:Lisp;  LSB:ppdef,pretty-print-definition  -*-
.end_lisp
The parsing of tokens in such a construct is pretty rudimentary and
crufty, but essentially things are symbols except for a series of
digits (optionally followed by a decimal point) which is a decimal
integer.

File attributes typically translate into some special binding
environment needed for the processing of the file (in some context).
The following are pre-defined in lan{nil}:
.table 3 250 250
.item package 2package-name*
The file is processed in the package named 2package-name*.
.item readtable 2readtable-name*
The file is read in using the readtable named 2readtable-name*.
Syntax, and readtable naming, is described in (syntax-section-page).
.item base 2radix*
Binds both the input and output radices, no matter what those damned
variables are named.
.item radix 2radix*
For those who are confused by 3base* and will be even moreso when
the variable is named 3*base**.
.item patch-file 2yes-or-no*
If 2yes-or-no* is 3yes* (it shouldn't be specified otherwise),
then a variable proclaiming the patch-file-ness of this file is bound,
so that various things can see it and be clever, like the helpful
function which warns you about redefining a function defined by
someone else in another file (said function not existing yet).
.item lsb 2module-name*,2system-name*
This is defined by lan{lsb} ref{LSBMan}, not lan{nil} (q.v.).
.end_table

When a file attribute list is parsed, the attribute names are
keywords, and the values are either keywords or integers (or lists of
keywords or integers).

.defmessage :file-plist pathname
If 2pathname* can be opened, then this returns a disembodied
property list with the file attributes in the 3cdr*, and the
truename of the file in the 3car*.  Otherwise, it returns
(false).

This probably should be renamed 3:file-attribute-list*.
.end_defmessage

.defun fs:process-in-load-environment plist funct pathname &rest args
2plist* should be a parsed file attribute list (with an 2even*
number of elements;  the 3cdr* of what is returned by the
3:file-plist* message).  2pathname* should be the pathname
which the file attributes were obtained from.

The environment which is specified by that attribute list is
established, and then 2funct* called with arguments of
2pathname* and whatever 2args* were given.

This is what is used by both 3load* and the compiler.  It enables
a stable interface to how bindings and other environment modifications
are obtained from the file attributes.
.end_defun

Examination of the source code (the file 7[NIL.IO]PATHN.LSP*) will
show the convention which is used for defining additional file
attributes.  It is basically an extension of that defined by
lan{lisp machine lisp}.

.subsection "Internals for VMS Record Management Services"

lan{nil} contains some primitive routines and datastructure
definitions with which I/O can be performed entirely from lan{lisp}
code.  In fact, recently a special-purpose stream type was written so
that the editor could do very fast record I/O.  This is the
3local-vms-editor-stream* stream, which is in the source file
7nil$disk:[nil.io]vlocal.lsp*, and can serve as an example of how
some of these things are used.  Some of the other primitives which
interface to the filesystem are also written in lan{lisp}, but are
hidden from the stream code by a functional interface;  these are in
the file 7nil$disk:[nil.vmlisp]vmsfile.lsp*.

.subsubsection "Data Structures"

The datastructures used for lan{rms} fab, rab, nam, and xab blocks
are all just simple bit vectors of the appropriate size.  There are
lan{lisp} macros and constants defined to deal with them;  these
definitions were generated from the lan{vms} lan{mdl} files.  For
instance, 3(si:fab$b_rfm 2fab*)* returns the record-format
field of a fab.  3(setf (si:fab$b_rfm 2fab*) si:fab$c_var)*
sets it to the code which says that the record format is
variable-length records.  Generally, fields of type 3byte* and
3word* are fetched/set as fixnums.  3longword* and
3quadword* fields are extracted into (freshly consed)
simple-bit-vectors of the appropriate length;  the setting operation
replaces the bits of the structure (in the right position) with the
bits of the object it is being set to, so the operation is invertible.
See also the files 7nil$disk:[nil.vmlisp]rmsstr.lsp* and
7nil$disk:[nil.vmlisp]rmssub.lsp*.

Creation of these structures, whether by 
.defun si:make-fab
.end_defun
.defun si:make-rab
.end_defun
.defun si:make-nam
.end_defun
.defun si:make-xab code length
Because xab structures vary, one must specify the xab code and its
length.  For instance,
.lisp
(si:make-xab si:xab$c_fhc si:xab$c_fhclen)
.end_lisp
creates a xab block used for hacking file header stuff.
.end_defun

Resources are defined for fab, rab, nam, and xab structures.
.defresource si:fab
.end_defresource
.defresource si:rab
.end_defresource
.defresource si:nam
.end_defresource
.defresource si:xab code length
Because 3xab* structures can vary in code and length, they must be
supplied to the resource constructor.  The appropriate constants are
defined, of course.  For instance,
.lisp
(using-resource (si:xab xabdat si:xab$c_dat si:xab$c_datlen)
  . . .)
.end_lisp
binds 3xabdat* to a xab structure used for obtaining creation and
revision dates.
.end_defresource

.subsubsection "RMS and Related Hacking"

The following functions perform the obvious operation on their
argument(s).  A status code is returned.

.defun si:rms$close fab
.end_defun

.defun si:rms$create fab
.end_defun

.defun si:rms$display fab
.end_defun

.defun si:rms$erase fab
.end_defun

.defun si:rms$extend fab
.end_defun

.defun si:rms$open fab
.end_defun

.defun si:rms$connect rab
.end_defun

.defun si:rms$delete rab
.end_defun

.defun si:rms$disconnect rab
.end_defun

.defun si:rms$find rab
.end_defun

.defun si:rms$flush rab
.end_defun

.defun si:rms$free rab
.end_defun

.defun si:rms$get rab
.end_defun

.defun si:rms$nxtvol rab
.end_defun

.defun si:rms$put rab
.end_defun

.defun si:rms$release rab
.end_defun

.defun si:rms$rewind rab
.end_defun

.defun si:rms$trunc rab
.end_defun

.defun si:rms$update rab
.end_defun

.defun si:rms$wait rab
.end_defun

.defun si:rms$read rab
.end_defun

.defun si:rms$space rab
.end_defun

.defun si:rms$write rab
.end_defun

.defun si:rms$enter fab
.end_defun

.defun si:rms$parse fab
.end_defun

.defun si:rms$remove fab
.end_defun

.defun si:rms$rename fab1 fab2
.end_defun

.defun si:rms$search fab
.end_defun


.defun si:rms$setddir new-directory-specification
Returns, and maybe updates, the lan{rms} default directory.  If
2new-directory-specification* is (false), the lan{rms} default
is not modified;  otherwise, it is set to
2new-directory-specification*, which must be a simple string.  This is a
fairly direct interface to the 7SYS$SETDDIR* system service.

If the return status is not normal (the value of
3si:rms$_normal*), it is returned in place of the string.
.end_defun

.defun si:trnlog logical-name
This performs the 3trnlog* system service on the simple string
2logical-name*.  It returns a simple-string which is the
translation, or 3nil*.
.end_defun


.section "Terminal I/O"

The current lan{nil} system contains a terminal stream which is
translates general operations into terminal-specific display codes.
Characters output to it (via the 3:write-char* message
'c message_index :write-char
or the fun{write-char} function)
are interpreted as either display operations (e.g., carriage-return
moves the cursor to the next line or wraps to the top of the screen,
and clears the line it moves to), or as graphic characters
(causing certain characters which are 2not* graphic on typical
ascii terminals to to be printed with certain conventions).  Line
wraparound is performed also.

The best way in which this can be accessed is with the 3cursorpos*
function, which is lan{maclisp} compatible.  In fact, the behaviour
of the cursorposable tty stream emulates the behaviour of terminals
under the ITS operating system, down to the terminal-width fencepost
behaviour due to the use of the last column to hold the continuation
character.  (The "keyword character" argument to 3cursorpos*, as
defined by lan{maclisp}, in fact derives from the second character
in the escape sequence used perform that cursor operation under ITS.
Ah well.)

.defun cursorpos &optional arg1 arg2 arg3
3cursorpos* is a lan{maclisp} compatibility function, but it
offers an interface to the display terminal code which may be safely
and reliably used.  Note that the arguments are interpreted in rather
strange manners...  As a general rule, 3cursorpos* is supposed to
return (false) if it was not capable of performing that
particular operation on the particular stream involved, (true)
otherwise.  It is 2not* the case, however, that it may be used on
non-terminal streams;  that is an error.

.lisp
(cursorpos)
.end_lisp
returns the cursor position of 3terminal-io* as a pair,
3(2vertical-position* . 2horizontal-position*)*.  Both
positions are measured zero-origined, from the top-left corner of the
screen.  (false) should be returned if the stream does not have a
generally movable cursor.

.lisp
(cursorpos 2vpos* 2hpos*)
.end_lisp
Positions the cursor of the stream 3terminal-io* at that position.
Either 2vpos* or 2hpos* may be (false), in which case the
current value is used.

Otherwise, the first arg to 3cursorpos* should be a symbol (or
character object), which may take an additional argument.  The case is
irrelevant.
.table 3 250 250
.item C
Clears the screen.  The cursor moves to the "home" position (top left
corner).  On a non-display, this outputs a newline, so always
succeeds.
.item A
Fresh-line.  In this instance, the 3fresh-line* function
((fresh-line-fun)) is preferred.
.item T
"Top."  The cursor is homed, moved to the top left corner.
.item Z
Home down.  Bottom left corner.
.item L
Clear-to-end-of-line.  From the current position to the right margin
is cleared.  The cursor does not move.
.item E
Clear-to-end-of-screen.  Current position to right margin, and all
following lines, are cleared.  The cursor does no move.
.item U
Move Up a line.  Wraps around the screen, does not scroll.
.item D
Move Down a line.  Wraps around the screen, does not scroll.
.item F
Move Forward a character position.
.item B
Move Backward a character position.  If at the left margin,
effectively does U then moves to the column to the left of the
continuation-character column (i.e., it backs up the amount by which
the cursor would have moved for a single-position printing character).
.item K
Erase the character the cursor is over (this would not be the last one
typed normally, see below:)
.item X
B, then K.  Simpleminded way to rubout the last character typed.
.item H 2hpos*
Set the horizontal position to 2hpos*.
.item V 2vpos*
Set the vertical position to 2vpos*.
.item ]
The insert-line operation
.item \
The delete-line operation
.item ^
The insert-char operation
.item _
the delete-char operation
.end_table

Additionally, one may specify a stream to 3cursorpos* by giving
that as the 2last* argument.  The atom 3t* as a stream means,
as with other printing functions, the terminal (the value of
3terminal-io*).  Note, however, that 2no* stream 2also*
uses the value of 3terminal-io*, rather than
3standard-output*.  Note also that the form
.lisp
(cursorpos 't)
.end_lisp
is interpreted as requesting the cursor position of 3terminal-io*;
to do a home-up, one must use some alternate form like
.lisp
(cursorpos 'top)
(cursorpos #\t)
(cursorpos 't 't)
.end_lisp
This strangeness is also lan{maclisp} compatible...
.end_defun

.subsection "Modifying the Terminal Characteristics"

.defun set-terminal-type terminal-name
Resets the terminal characteristics from the termcap entry found for
2terminal-name*.  See (termcap-section-page).
.end_defun

.defun si:determine-and-set-terminal-type
This is the routine called on startup which either defaults or asks
for your terminal type.
.end_defun

.defmethod si:display-cursorpos-mixin :init-with-termcap termcap-struct
2termcap-struct* is what would be returned by
3si:make-termcap*.
.end_defmethod

.subsection "Making More Terminal Streams"

As noted elsewhere ((open-fun)), fun_i{open} is what may be used
to open terminal streams in lan{nil}.  The 3:type* keyword
specifies that a terminal stream is requested:
.table 3 25 250
.item :display-tty
This produces a terminal stream just like that lan{nil} starts up
with.  Additional options fed to 3open* may be used to
parameterize it;  these are described below.
.item :cold-load
This produces a "raw" tty which has no display capability.  It does
perform some ascii-ification of non-display characters output, but
performs no functions like line wraparound.
.item :tty
what does this do?  is it left-over from something?
.end_table

Interesting additional 3open* keyword arguments which may be
specified when opening a 3:display-tty*:
.table 3 250 250
.item :terminal-type 2terminal-type-name*
The terminal capabilities description is obtained from the termcap
entry for 2terminal-type-name*.  Since one of these is necessary,
you might as well specify the right one rather than letting it default
(the lookup in the database may still be necessary).
.item :cold-load-stream 2cold-load-stream*
The first arg to 3open* is ignored, and the innards of
2cold-load-stream* (which 2must* be a tty stream as created by
the 3:cold-load* open-type) is extracted to get to the real
terminal, rather than opening a new one.  (In the lan{nil} loadup
process, first the terminal streams are set to be a cold-load stream,
and then later they are reset to be real display-tty streams using
this.  This is less important now than it used to be, but still comes
in handy on occasion.  It's not clear what use it might be to users.)
.end_table

.subsection "Display TTY Messages"

In case you want to hack graphics on another terminal or something...
See also the source code in 7nil$disk:[nil.io]cursor.lsp*.

.defmethod si:display-cursorpos-mixin :write-char char
This is what implements 3write-char* to a display terminal, with
all the interpretation of 2char* described earlier.
.end_defmethod

.defmethod si:display-cursorpos-mixin :oustr string start count
Note 2start* and 2count* are not optional.  Using this results
in a significant efficiency gain over individual 3:write-char*
messages, because the stream attempts to pass along as many block-mode
operations as possible to lan{vms}.
.end_defmethod

.defmethod si:display-cursorpos-mixin :write-raw-char char
This is not actually provided by 3si:display-cursorpos-mixin*, but
is 2required* to be supported by flavors which mix that in.  It is
how 3si:display-cursorpos-mixin* expects to get raw codes out to
the terminal.  Obviously, then, if you also wish to get raw codes to
the terminal, you may use this message on display tty streams.
.end_defmethod

.defmethod si:display-cursorpos-mixin :raw-oustr string start count
Analogous.
.end_defmethod

