.c 	Wednesday, December 5, 1984   -*- bolio -*-

.chapter "Talking to NIL"

.section "Startup"

The first thing lan{nil} does when it starts up is to attempt to
figure out what kind of terminal you are using.  The way lan{nil}
figures out how to talk to a particular terminal is that it uses
"terminal capabilities" database (a lan{unix} 2termcap*
database).  The lan{vms} logical name 3term*
'cindex term logical name
'cindex logical name
is used to name the terminal type;  lan{nil} ignores lan{vms}
terminal information.  If no such logical name is defined, then
lan{nil} will assume the terminal is a simpleminded printing
terminal, and prompt you for a terminal name.

The terminal names which are both supported and known to work fairly
well are
.table 3 250 250
.item vt52
Standard lan{dec} lan{vt52}.
.item c100
Human Designed System's concept-100.  This will probably work for
their Concept-108 also.  There is a variation of this, 3c100rv*,
which is 3c100* in reverse-video (black-on-white) mode.  Also, since
the previous release, the meaning of 3c100* has changed slightly.
The original 3c100* assumed a concept with the very old (possibly
the first version) software.  The 3c100* name now refers to a
concept with newer software, which has a couple new mode settings which
enable lan{nil} to do character-insert the way it wants.  If you
suspect you have the old software, it may be referred to as
3oldc100*, or 3oldc100rv* for reverse-video.  (HDS does offer
software upgrades in the form of new ROM installation, but they may not
be worth the price just for character-insert unless you edit a lot on a
low-speed line.)  I suspect (but cannot test this) that if lan{nil}
starts up on an old c100 thinking it is a new c100, you will see the
characters "!A@" appear somewhere on the screen.
.item aaa
Ann Arbor Ambassador
.item vt100
lan{dec} vt100.  Obviously you should make sure your vt100 is in
lan{ansi} mode.  Also, auto-linewrap should be disabled.
.item t1061
Teleray 1061.
.end_table
In lan{dcl}, one might say
.lisp
$ define term "c100"
.end_lisp
if one was on a concept-100.  Or, if your terminal varied, you might
put in your 7login.com* file
.lisp
$ if f$mode() .nes. "INTERACTIVE" then goto punt
$ inquir term "Terminal type (in doublequotes, default vt52)"
$ if term .eqs. "" then term := "vt52"
$ define term "''term'"
$ punt:
.end_lisp
which would prompt for the terminal type to assign to the 3term*
logical name, defaulting it to whatever was convenient, and not
bothering at all if it was run from a batch or network job.

When lan{nil} starts up, it loads your term_i{init file} if it
exists.  This would be a file on your login (not default) directory
named 7NIL.INI*.  (Init file conventions are discussed on
(init-file-pathname-fun).)  Then it enters its standard
read-eval-print loop.

.section "The Toplevel Loop"

.defvar *
The value of this is the last thing the toplevel (or breaklevel) loop
evaluated (and presumably printed).
.end_defvar

.defvar **
The previous value of 3**.
.end_defvar

.defvar ***
The previous value of 3***.
.end_defvar

.defvar +
The value of this is the last thing read in by the toplevel (or
breaklevel) loop.
.end_defvar

.defvar ++
.defvar1 +++
Previous values.
.end_defvar

.defvar \\
This has as its value the 2vector* of values returned from the
last thing evaluated by the toplevel (or breaklevel) loop.  That is,
its first (number 0) element will be the value of 3**.

This variable is also used by the debugger the way 3** is by the
toplevel loop, but that will be changed eventually.
.end_defvar

If an evaluation error occurs and you abort back to toplevel, then
the value of the 3** variables does not get cycled, but the
3+* variables do;  thus, 3+* is the form which got the error,
but 3** is still the last thing returned by toplevel evaluation.
lan{Common lisp} intends to change this.  (What lan{nil} does is
compatible with lan{maclisp}.)

.section "Entering and Exiting NIL"

Typing the character control-Y normally exits from lan{nil}.  The
same command which started the lan{nil} initially may then be used
to resume it.  The lan{nil} can be resumed in other ways too.  For
instance, if 7nil* was the command used to start the nil,
.table 7 250 1000
.item nil
will resume the existing lan{nil},
.item nil/kill
will kill the lan{nil}, and
.item nil/proceed
will resume the lan{nil}, but not allow it to type out, and will
leave you in the command interpreter.  If the lan{nil} attempts to
type out (or, in fact, calls any of the following functions), it will
wait until it is explicitly resumed.
.end_table
If lan{nil} is reading input from the terminal, the input processor
command for "meta-altmode", which may be typed as the character
sequence 2control-\* 2altmode*, will return control to the
command interpreter.  When the lan{nil} is resumed, it will
automatically redisplay the typein it is accumulating.

Several functions are provided for returning from lan{nil} to the
lan{vms} command language interpreter (lan{cli}) in a more
programmable fashion.
In all of the following functions where a string is involved with
passing control back to the lan{cli}, the string may have a maximum
length of 256 characters.  This is checked for by lan{nil}.

.defun valret &optional command-line
3(valret)* returns control to the lan{cli}.  The lan{nil} is
suspended until later resumed.

3(valret 2command-line*)* returns to the lan{cli}
(suspending the lan{nil}), and additionally causes
2command-line* to be interpreted as a command line by the
lan{cli}.

The passall terminal mode is cleared,
'cindex passall mode
and restored when the lan{nil} is resumed.  3valret* with a
string argument works by calling the lan{vms} 3lib$do_command*
library routine.
.end_defun

.defun quit
3(quit)* exits the lan{nil}, causing it to be killed.

Currently, 3(quit 2string*)* kills the lan{nil} and causes
2string* to be printed instead of "NIL Terminated";  however this
will probably be changed so that 2string* will be interpreted as a
command line, as with 3valret*.

Passall mode is cleared on exit.

When the lan{nil} is terminated, there is a noticeable pause before
the command language interpreter returns.  This is due to the
controlling program (lan{rnil}, running in the lan{cli}) waiting
for the process to actually go away.  lan{Vms} image rundown takes a
noticeable time, and if one were to not wait after requesting process
deletion, starting up a lan{nil} of the same name immediately could
cause the new lan{rnil} to be confused.  (This is the same as
happens when 7nil/kill* is used in the lan{cli}.)
.end_defun

.defun exit-and-run-program (pathname)
Control is returned from lan{nil} to the lan{cli}, and the program
image found in 2pathname* is then run.  The lan{nil} will have
been suspended.  lan{nil} applies no defaulting to 2pathname*,
however, the command interpreter will supply a default file type of
3exe* and will default the device and directory to the lan{rms}
default.

Passall mode is cleared on exit.  3exit-and-run-program* works by
having the lan{rnil} program call the 3lib$run_program* library
routine.
.end_defun

.defun proceed-nil &optional string
Control is returned from the lan{nil} to the lan{cli}.  However,
the lan{nil} is resumed, so will continue running "without the
terminal".  If a 2string* is supplied, then that is printed (as
with 3quit*).  Similarly (as with 3quit*), the interpretation
of 2string* should probably be changed to be a command line for
the lan{cli} to execute.
.end_defun


.section "VMS"

lan{Vms} usurps control-Y as interrupt-to-superior.  Resuming your
lan{nil} gives it a tty-return interrupt which makes it frob the
cursor so that it knows where the cursor is.  (This is why it goes to
the bottom of the screen on a display tty.)

Other terminal interrupts are all performed by dispatching from
control-C;  after the control-C is typed another character is read.
("?" lists options.)  The control-C processing is performed by
Lisp code.  This means that control-C will not be processed if
interrupts are severely inhibited.  The lan{nil} system by special
dispensation will enter the lan{vms} debugger if multiple control-Cs
are typed and are being ignored;  so if something large and
uninterruptible is happening, like creating a vector with a million
elements, or something not so large but your system is slow, you might
throw the lan{nil} out to the lan{vms} debugger.

It is highly unlikely that lan{nil} will enter the lan{vms} debugger
unless explicitly told to do so. Here are two lan{vms} debugger commands
that are useful for returning back to the world. Say
.lisp
call debug
.end_lisp
and the lisp debugger will be entered.  (Exiting softly from the Lisp
debugger with "q" will return to the lan{vms} debugger.  One may also
perform a non-local exit from the Lisp debugger with control-G or X.)
One can also just
.lisp
call quit
.end_lisp
from the lan{vms} debugger, which does a 3throw* just like control-G
does from the control-C prompt.

The only problem with all this is that if the lan{vms} debugger gets
dynamically loaded into the lan{nil}, some part of it will end up
where lan{nil} thinks it is putting its heap (i.e., where it is
allocating the memory to use for consing), and the lan{nil} will die
shortly thereafter.

.defvar si:*lisp-debugger-on-exceptions*
If non-null, then error conditions and faults will trap to the
lan{lisp} error handler rather than bombing out to the lan{vms}
debugger.  This can happen from memory access violation errors,
floating overflow and underflow, integer divide by zero, etc.;  in
general, any such error.  For instance, a reserved operand fault might
occur if a variable-field byte instruction was given a bad size.
.end_defvar

If the lisp debugger is used from some exceptional condition, remember
that the stack may not be in a nice-looking state, so examination of
what the debugger thinks are local variables near the top may result
in more trouble.  Note also that the Lisp code is not run at AST
level, but rather as a continuation of the condition;  returning a
value from the debugger returns that value from the most recent lan{vax}
procedure call, which is probably the function within which the error
was signalled.  Also, the lan{lisp} code which handles such errors
binds 3si:*lisp-debugger-on-exceptions** to 3nil* when it is
running;  examination of non-lan{lisp} data by the debugger from
such an error as if it were lan{lisp} data might cause a memory
protection violation, and blow out to the lan{vms} debugger.

Note also the 3set-privileges* and 3get-privileges* functions
((get-privileges-fun)), which can be used to set or get the
privileges the lan{nil} process has enabled.

.section "How the NIL Control Works"

This section notes how some of the above stuff works, for the interest
of lan{vms} hackers, or those wishing to extend the above
functionality.

Program control of lan{nil} under lan{vms} works in a fairly
strange way (or at least so it will appear to someone used to
operating systems in which there is more explicit job/terminal
association and more "monitor" control of inferior processes).  This
is a function of lan{vms}s lack of a concept of a job "having
control of the terminal", and the fact that the lan{nil} process
does not contain a command language interpreter in its image;  the
7spawn* and 7attach* commands are only implemented by
conventions applied by the lan{cli}.

The command 7nil* typically invokes the lan{rnil} program.  This
is an image which runs within the lan{cli} process, and "controls"
the lan{nil}, which is kept in a separate process.  The 7nil*
command implicitly supplies lots of arguments to lan{rnil}, one of
which is the job name of the lan{nil} process.  lan{Rnil} will
create one if there is none, or will do something else to it (like
resuming it) depending on additional arguments given (like
7nil/proceed* or 7nil/kill*).  lan{Rnil} communicates to the
lan{nil} process with mailboxes.  When the lan{nil} is resumed,
the lan{rnil} attempts to read from one, waiting.  It returns either
when it succeeds in reading a message (as happens with 3valret*),
or if it is abnormally exited (as with typing control-Y).

lan{Vms} in its current state does not have the concept of a particular
process having "control" of the terminal it shares with the rest of
the process tree.  lan{Nil} handles this by having a number of event
and state flags which tell it whether or not it is allowed to read
from or write to the terminal.  When a lan{nil} is exited, the
lan{rnil} program clears those flags;  when it is resumed, they are
turned back on again.

Exiting from lan{nil} with control-Y works in a particularly strange
fashion.  The lan{vms} terminal driver will give a control-Y AST to any
process which has enabled it, with no conceptualization of what
program is "in control of" the terminal.  The control-Y is handled by
the lan{cli}, which then commences image rundown of the lan{rnil}
program.  lan{Rnil} has an exit handler which then sets the terminal
input and output enabled flags off in the lan{nil} process.  (As a
special case, it may also exit similarly if the lan{nil} is
terminated some other way, perhaps by 7exit* to the lan{vms} debugger
in the lan{nil} process.  It recognizes the mailbox message for
this, and prints "7NIL Terminated*".) 

Control-C has a similar control problem.  When a control-C is typed on
the terminal, the terminal driver runs the AST routines for 2all*
processes which have enabled them.  (Multiply, if a process has
enabled more than one.)  In the current implementation, the lan{nil}
process enables the control-C AST.  When the AST routine is run, it
attempts to determine if it should be the recipient of that interrupt,
by checking to see if it "has control of the terminal" (i.e., the
terminal-input-enabled flag is on).  If not, it ignores the interrupt
(and of course re-enables the control-C ast).  If it thinks it was the
recipient of the interrupt, it cancels the control-C (to help keep
other NILs on the same terminal from having to think about it, i
guess), and queues a lan{lisp} interrupt for control-C.  There is one time
when this can break down:  if the lan{nil} is suspended when the AST
is delivered, the AST will not be run until the lan{nil} is resumed.
However, when the lan{nil} is resumed, the lan{rnil} delivers it a
couple other ASTs which cause the terminal input and output flags to
be turned on!  If this manages to happen before the control-C AST
routine gets around to checking these flags (as it invariably does),
then the lan{nil} will
think that this control-C was for it, and behave accordingly.  So, if
you resume a lan{nil} and it acts like you just typed a control-C,
it is probably because of that control-C you typed at the
7display* program half an hour ago;  type "n" at the ">Interrupt>"
prompt to make it go away.

There is a design change which eliminates this problem, and
additionally allows controlled interruptibility out of arbitrary wait
operations (not just terminal input and output, which are special
cased).  It involves a sweeping change to lots of code, however, so
cannot be put in bits at a time.

