   This file documents the MIT Scheme system.

   Copyright (C) 1988-2002 Massachusetts Institute of Technology

   Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.1 or
any later version published by the Free Software Foundation; with no
Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
Texts.  A copy of the license is included in the section entitled "GNU
Free Documentation License".

External Representation of Time
-------------------------------

   The normal external representation for time is the time string, as
described above.  The procedures in this section generate alternate
external representations of time which are more verbose and may be more
suitable for presentation to human readers.

 - procedure: decoded-time/date-string decoded-time
 - procedure: decoded-time/time-string decoded-time
     These procedures return strings containing external
     representations of the date and time, respectively, represented by
     DECODED-TIME.  The results are implicitly in local time.

          (decoded-time/date-string (local-decoded-time))
              => "Tuesday March 30, 1999"
          (decoded-time/time-string (local-decoded-time))
              => "11:22:38 AM"

 - procedure: day-of-week/long-string day-of-week
 - procedure: day-of-week/short-string day-of-week
     Returns a string representing the given DAY-OF-WEEK.  The argument
     must be an exact non-negative integer between `0' and `6'
     inclusive.  `day-of-week/long-string' returns a long string that
     fully spells out the name of the day.  `day-of-week/short-string'
     returns a shortened string that abbreviates the day to three
     letters.

          (day-of-week/long-string 0)  => "Monday"
          (day-of-week/short-string 0) => "Mon"
          (day-of-week/short-string 3) => "Thu"

 - procedure: month/long-string month
 - procedure: month/short-string month
     Returns a string representing the given MONTH.  The argument must
     be an exact non-negative integer between `1' and `12' inclusive.
     `month/long-string' returns a long string that fully spells out
     the name of the month.  `month/short-string' returns a shortened
     string that abbreviates the month to three letters.

          (month/long-string 1)   => "January"
          (month/short-string 1)  => "Jan"
          (month/short-string 10) => "Oct"

 - procedure: time-zone->string
     Returns a string corresponding to the given time zone.  This
     string is the same string that is used to generate RFC-822 time
     strings.

          (time-zone->string 5)    => "-0500"
          (time-zone->string -4)   => "+0400"
          (time-zone->string 11/2) => "-0530"

Machine Time
============

   The previous section dealt with procedures that manipulate clock
time.  This section describes procedures that deal with computer time:
elapsed CPU time, elapsed real time, and so forth.  These procedures
are useful for measuring the amount of time it takes to execute code.

   Some of the procedures in this section manipulate a time
representation called "ticks".  A tick is a unit of time that is
unspecified here but can be converted to and from seconds by supplied
procedures.  A count in ticks is represented as an exact integer.  At
present each tick is one millisecond, but this may change in the future.

 - procedure: process-time-clock
     Returns the amount of process time, in ticks, that has elapsed
     since Scheme was started.  Process time is measured by the
     operating system and is time during which the Scheme process is
     computing.  It does not include time in system calls, but
     depending on the operating system it may include time used by
     subprocesses.

          (process-time-clock) => 21290

 - procedure: real-time-clock
     Returns the amount of real time, in ticks, that has elapsed since
     Scheme was started.  Real time is the time measured by an ordinary
     clock.

          (real-time-clock) => 33474836

 - procedure: internal-time/ticks->seconds ticks
     Returns the number of seconds corresponding to TICKS.  The result
     is always a real number.

          (internal-time/ticks->seconds 21290) => 21.29
          (internal-time/ticks->seconds 33474836) => 33474.836

 - procedure: internal-time/seconds->ticks seconds
     Returns the number of ticks corresponding to SECONDS.  SECONDS
     must be a real number.

          (internal-time/seconds->ticks 20.88) => 20880
          (internal-time/seconds->ticks 20.83) => 20830

 - procedure: system-clock
     Returns the amount of process time, in seconds, that has elapsed
     since Scheme was started.  Roughly equivalent to:

          (internal-time/ticks->seconds (process-time-clock))

     Example:

          (system-clock) => 20.88

 - procedure: runtime
     Returns the amount of process time, in seconds, that has elapsed
     since Scheme was started.  However, it does not include time spent
     in garbage collection.

          (runtime) => 20.83

 - procedure: with-timings thunk receiver
     Calls THUNK with no arguments.  After THUNK returns, RECEIVER is
     called with three arguments describing the time spent while
     computing THUNK: the elapsed run time, the amount of time spent in
     the garbage collector, and the elapsed real time.  All three times
     are in ticks.

     This procedure is most useful for doing performance measurements,
     and is designed to have relatively low overhead.

          (with-timings
           (lambda () ...hairy computation...)
           (lambda (run-time gc-time real-time)
             (write (internal-time/ticks->seconds run-time))
             (write-char #\space)
             (write (internal-time/ticks->seconds gc-time))
             (write-char #\space)
             (write (internal-time/ticks->seconds real-time))
             (newline)))

 - procedure: measure-interval runtime? procedure
     Calls PROCEDURE, passing it the current process time, in seconds,
     as an argument.  The result of this call must be another procedure.
     When PROCEDURE returns, the resulting procedure is
     tail-recursively called with the ending time, in seconds, as an
     argument.

     If RUNTIME? is `#f', the elapsed time is deducted from the elapsed
     system time returned by `runtime'.

     While this procedure can be used for time measurement, its
     interface is somewhat clumsy for that purpose.  We recommend that
     you use `with-timings' instead, because it is more convenient and
     has lower overhead.

          (measure-interval #t
                            (lambda (start-time)
                              (let ((v ...hairy computation...))
                                (lambda (end-time)
                                  (write (- end-time start-time))
                                  (newline)
                                  v))))

Subprocesses
============

   MIT Scheme provides the ability to run and control subprocesses.
This support is divided into two parts: a low-level set of primitives
that maps onto the underlying operating system's process-control
primitives, and a high-level set of procedures for starting a
subprocess and running it to completion in a single call.  Subprocesses
that are run in the latter fashion are referred to as "synchronous",
because they are started and stopped in synchrony with a Scheme
procedure call.

   This chapter documents Scheme's high-level synchronous-subprocess
support.  The low-level support is not documented but is available for
those who are willing to read the source code.

   Synchronous-subprocess support is a run-time-loadable option.  To use
it, execute

     (load-option 'synchronous-subprocess)

once before calling it.

Subprocess Procedures
---------------------

   There are two commands for running synchronous subprocesses under
Scheme.  `run-shell-command' is very simple to use, provides access to
all shell features, and is to be preferred in most situations.
`run-synchronous-subprocess' allows direct execution of a program and
precise control of the command-line arguments passed to the program,
but does not provide file globbing, I/O redirection, or other shell
features.

 - procedure: run-shell-command command option ...
     Runs COMMAND, which must be a string.  COMMAND is passed to a
     command shell for interpretation; how the shell is chosen is
     detailed below.

     The OPTIONs are a sequence of keyword/value pairs that specify
     optional behavior.  See below for more information about options.

     `run-shell-command' waits until the subprocess completes its
     execution and returns the exit code from the subprocess.  If the
     subprocess is killed or stopped, an error is signalled and the
     procedure does not return.

 - procedure: run-synchronous-subprocess program arguments option ...
     Runs PROGRAM, passing it the given command-line ARGUMENTS.
     PROGRAM must be either the name of a program on the path, or else
     a pathname to a specific program.  ARGUMENTS must be a list of
     strings; each string is a single command-line argument to the
     program.

     The OPTIONs are a sequence of keyword/value pairs that specify
     optional behavior.  See below for more information about options.

     `run-synchronous-subprocess' waits until the subprocess completes
     its execution and returns the exit code from the subprocess.  If
     the subprocess is killed or stopped, an error is signalled and the
     procedure does not return.

Subprocess Conditions
---------------------

   If a subprocess spawned by one of the above procedures is killed or
suspended, then one of the following errors will be signalled.

 - condition type: condition-type:subprocess-signalled subprocess reason
     This condition type is a subtype of
     `condition-type:subprocess-abnormal-termination'.  It is signalled
     when the subprocess is killed.

     SUBPROCESS is an object that represents the subprocess involved.
     The internals of this object can be accessed but the interface is
     not documented at this time; see the source code for details.

     REASON is interesting only on unix systems, where it is the signal
     that killed the process.  On other systems it has a fixed value
     that conveys no useful information.

 - condition type: condition-type:subprocess-stopped subprocess reason
     This condition type is a subtype of
     `condition-type:subprocess-abnormal-termination'.  It is signalled
     when the subprocess is stopped or suspended.

     SUBPROCESS is an object that represents the subprocess involved.
     The internals of this object can be accessed but the interface is
     not documented at this time; see the source code for details.

     REASON is interesting only on unix systems, where it is the signal
     that stopped the process.  On other systems it has a fixed value
     that conveys no useful information.

 - condition type: condition-type:subprocess-abnormal-termination
          subprocess reason
     This condition type is a subtype of `condition-type:error'.  This
     is an abstract type that is never signalled.  It is provided so
     that condition handlers can be bound to it.

Subprocess Options
------------------

   The following subprocess options may be passed to
`run-shell-command' or `run-synchronous-subprocess'.  These options are
passed as alternating keyword/value pairs, for example:

     (run-shell-command "ls /"
                        'output my-output-port
                        'output-buffer-size 8192)

The example shows a shell command being run with two options specified:
`output' and `output-buffer-size'.

 - subprocess option: input port
     Specifies the standard input of the subprocess.  PORT may be an
     input port, in which case characters are read from PORT and fed to
     the subprocess until PORT reaches end-of-file.  Alternatively,
     PORT may be `#f', indicating that the subprocess has no standard
     input.

     The default value of this option is `#f'.

          (call-with-input-file "foo.in"
            (lambda (port)
              (run-shell-command "cat > /dev/null" 'input port)))

 - subprocess option: input-line-translation line-ending
     Specifies how line-endings should be translated when writing
     characters to the subprocess.  Ignored if the `input' option is
     `#f'.  LINE-ENDING must be either a string specifying the line
     ending, or the symbol `default', meaning to use the operating
     system's standard line ending.  In either case, newline characters
     to be written to the `input' port are translated to the specified
     line ending before being written.

     The default value of this option is `default'.

          (call-with-input-file "foo.in"
            (lambda (port)
              (run-shell-command "cat > /dev/null"
                                 'input port
                                 'input-line-translation "\r\n")))

 - subprocess option: input-buffer-size n
     Specifies the size of the input buffer for the standard input of
     the subprocess.  (This is the buffer on the Scheme side, and has
     nothing to do with any buffering done on the subprocess side.)
     Ignored if the `input' option is `#f'.  N must be an exact positive
     integer specifying the number of characters the buffer can hold.

     The default value of this option is `512'.

          (call-with-input-file "foo.in"
            (lambda (port)
              (run-shell-command "cat > /dev/null"
                                 'input port
                                 'input-buffer-size 4096)))

 - subprocess option: output port
     Specifies the standard output and standard error of the subprocess.
     PORT may be an output port, in which case characters are read from
     the subprocess and fed to PORT until the subprocess finishes.
     Alternatively, PORT may be `#f', indicating that the subprocess
     has no standard output or standard error.

     The default value of this option is the value of
     `(current-output-port)'.

          (call-with-output-file "foo.out"
            (lambda (port)
              (run-shell-command "ls -la /etc" 'output port)))

 - subprocess option: output-line-translation line-ending
     Specifies how line-endings should be translated when reading
     characters from the standard output of the subprocess.  Ignored if
     the `output' option is `#f'.  LINE-ENDING must be either a string
     specifying the line ending, or the symbol `default', meaning to
     use the operating system's standard line ending.  In either case,
     newline characters read from the subprocess port are translated to
     the specified line ending.

     The default value of this option is `default'.

          (call-with-output-file "foo.out"
            (lambda (port)
              (run-shell-command "ls -la /etc"
                                 'output port
                                 'output-line-translation "\r\n")))

 - subprocess option: output-buffer-size n
     Specifies the size of the output buffer for the standard output of
     the subprocess.  (This is the buffer on the Scheme side, and has
     nothing to do with any buffering done on the subprocess side.)
     Ignored if the `output' option is `#f'.  N must be an exact
     positive integer specifying the number of characters the buffer
     can hold.

     The default value of this option is `512'.

          (call-with-output-file "foo.out"
            (lambda (port)
              (run-shell-command "ls -la /etc"
                                 'output port
                                 'output-buffer-size 4096)))

 - subprocess option: redisplay-hook thunk
     Specifies that THUNK is to be run periodically when output from
     the subprocess is available.  THUNK must be a procedure of no
     arguments, or `#f' indicating that no hook is supplied.  This
     option is mostly useful for interactive systems.  For example, the
     Edwin text editor uses this to update output buffers when running
     some subprocesses.

     The default value of this option is `#f'.

          (run-shell-command "ls -la /etc"
                             'redisplay-hook
                             (lambda ()
                               (update-buffer-contents buffer)))

 - subprocess option: environment environment
     Specifies the environment variables that are to be used for the
     subprocess.  ENVIRONMENT must be either a vector of strings or
     `#f' indicating the default environment.  If it is a vector of
     strings, each string must be a name/value pair where the name and
     value are separated by an equal sign, for example, `"foo=bar"'.  To
     define a variable with no value, just omit the value, as in
     `"foo="'.

     Note that the variable `scheme-subprocess-environment' is bound to
     the default subprocess environment.

     The default value of this option is `#f'.

          (run-shell-command "ls -la /etc"
                             'environment
                             (let* ((v scheme-subprocess-environment)
                                    (n (vector-length v))
                                    (v (vector-grow v (+ n 1))))
                               (vector-set! v n "TERM=none")
                               v))

 - subprocess option: working-directory pathname
     Specifies the working directory in which the subprocess will run.

     The default value of this option is `(working-directory-pathname)'.

          (run-shell-command "ls -la" 'working-directory "/etc/")

 - subprocess option: use-pty? boolean
     This option is meaningful only on unix systems; on other systems
     it is ignored.  Specifies whether to communicate with the
     subprocess using PTY devices; if true, PTYs will be used,
     otherwise pipes will be used.

     The default value of this option is `#f'.

          (run-shell-command "ls -la /etc" 'use-pty? #t)

 - subprocess option: shell-file-name pathname
     Specifies the shell program to use for `run-shell-command'.

     The default value of this option is `(os/shell-file-name)'.  This
     is the value of the environment variable `SHELL', or if `SHELL' is
     not set, the value is operating-system dependent as follows:

        * On unix systems, `/bin/sh' is used.

        * On OS/2 systems, the value of the environment variable
          `COMSPEC' is used, or if that is not set, `cmd.exe' on the
          current path.

        * On Windows systems, the value of the environment variable
          `COMSPEC' is used.  If that is not set, `cmd.exe' is used for
          Windows NT, or `command.com' is used for Windows 9x; in each
          case the shell is found by searching the path.

          (run-shell-command "ls -la /etc"
                             'shell-file-name "/usr/local/bin/bash")

TCP Sockets
===========

   MIT Scheme provides access to "sockets", which are a mechanism for
inter-process communication.  TCP stream sockets are supported, which
communicate between computers over a TCP/IP network.  TCP sockets are
supported on all operating systems.

   TCP sockets have two distinct interfaces: one interface to implement
a "client" and another to implement a "server".  The basic protocol is
that servers set up a listening port and wait for connections from
clients.  Implementation of clients is simpler and will be treated
first.

   The socket procedures accept two special arguments, called HOST-NAME
and SERVICE.  HOST-NAME is a string which must be the name of an
internet host.  It is looked up using the ordinary lookup rules for
your computer.  For example, if your host is `foo.mit.edu' and
HOST-NAME is `"bar"', then it specifies `bar.mit.edu'.

   SERVICE specifies the service to which you will connect.  A
networked computer normally provides several different services, such as
telnet or FTP.  Each service is associated with a unique "port number";
for example, the `"www"' service is associated with port `80'.  The
SERVICE argument specifies the port number, either as a string, or
directly as an exact non-negative integer.  Port strings are decoded by
the operating system using a table; for example, on unix the table is
in `/etc/services'.  Usually you will use a port string rather than a
number.

 - procedure: open-tcp-stream-socket host-name service [buffer-size
          [line-translation]]
     `open-tcp-stream-socket' opens a connection to the host specified
     by HOST-NAME.  HOST-NAME is looked up using the ordinary lookup
     rules for your computer.  The connection is established to the
     service specified by SERVICE.  The returned value is an I/O port,
     to which you can read and write characters using ordinary Scheme
     I/O procedures such as `read-char' and `write-char'.

     BUFFER-SIZE specifies the size of the read and write buffers used
     by the port; if this is unspecified or `#f', the buffers will hold
     `4096' bytes.

     LINE-TRANSLATION specifies how end-of-line characters will be
     translated when reading or writing to the socket.  If this is
     unspecified or `#f', then lines will be terminated by CR-LF, which
     is the standard for most internet protocols.  Otherwise, it must
     be a string, which specifies the line-ending character sequence to
     use.

     When you wish to close the connection, just use `close-port'.

     As an example, here is how you can open a connection to a web
     server:

          (open-tcp-stream-socket "web.mit.edu" "www")

   Next we will treat setting up a TCP server, which is slightly more
complicated.  Creating a server is a two-part process.  First, you must
open a "server socket", which causes the operating system to listen to
the network on a port that you specify.  Once the server socket is
opened, the operating system will allow clients to connect to your
computer on that port.

   In the second step of the process, you "accept" the connection,
which completes the connection initiated by the client, and allows you
to communicate with the client.  Accepting a connection does not affect
the server socket; it continues to listen for additional client
connections.  You can have multiple client connections to the same
server socket open simultaneously.

 - procedure: open-tcp-server-socket service [address]
     This procedure opens a server socket that listens for connections
     to SERVICE; the socket will continue to listen until you close it.
     The returned value is a server socket object.

     An error is signalled if another process is already listening on
     the service.  Additionally, ports whose number is less than `1024'
     are privileged on many operating systems, and cannot be used by
     non-privileged processes; if SERVICE specifies such a port and you
     do not have administrative privileges, an error may be signalled.

     The optional argument ADDRESS specifies the IP address on which
     the socket will listen.  If this argument is not supplied or is
     given as `#f', then the socket listens on all IP addresses for
     this machine.  (This is equivalent to passing the result of
     calling `host-address-any'.)

 - procedure: tcp-server-connection-accept server-socket block?
          peer-address
     Checks to see if a client has connected to SERVER-SOCKET.  If so,
     an I/O port is returned.  The returned port can be read and
     written using ordinary Scheme I/O procedures such as `read-char'
     and `write-char'.

     The argument BLOCK? says what to do if no client has connected at
     the time of the call.  If `#f', it says to return immediately with
     two values of `#f'.  Otherwise, the call waits until a client
     connects.

     The argument PEER-ADDRESS is either `#f' or an IP address as
     allocated by `allocate-host-address'.  If it is an IP address, the
     address is modified to be the address of the client making the
     connection.

     Note that closing the port returned by this procedure does not
     affect SERVER-SOCKET; it just closes the particular client
     connection that was opened by the call.  To close SERVER-SOCKET,
     use `close-tcp-server-socket'.

 - procedure: close-tcp-server-socket server-socket
     Closes the server socket SERVER-SOCKET.  The operating system will
     cease listening for network connections to that service.  Client
     connections to SERVER-SOCKET that have already been accepted will
     not be affected.

Miscellaneous OS Facilities
===========================

   This section contains assorted operating-system facilities that don't
fit into other categories.

 - variable: microcode-id/operating-system
 - variable: microcode-id/operating-system-name
     `microcode-id/operating-system' is bound to a symbol that specifies
     the type of operating system that Scheme is running under.  There
     are three possible values: `unix', `os/2', or `nt'.

     `microcode-id/operating-system-name' is a string containing the
     same name as `microcode-id/operating-system'; the latter is created
     by interning the former as a symbol.

 - variable: microcode-id/operating-system-variant
     This variable is a string that identifies the particular variant
     of the operating system that Scheme is running under.  Here are
     some of the possible values:

          "GNU/Linux"
          "FreeBSD"
          "HP-UX"
          "SunOS"
          "OS/2 2.1"
          "OS/2 4.0"
          "Microsoft Windows NT 4.0 (Build 1381; Service Pack 3)"
          "Microsoft Windows 98 (Build 410)"

     For Windows systems, it is recommended that you match on the
     prefix of this string and ignore the `"Build"' suffix.  This is
     because the suffix may contain information about service packs or
     fixes, while the prefix will be constant for a particular version
     of Windows.

   The next few procedures provide access to the "domain name service"
(DNS), which maintains associations between internet host names such as
`"www.swiss.ai.mit.edu"' and IP addresses, such as `18.23.0.16'.  In
MIT Scheme, we represent an internet host name as a string, and an IP
address as a byte vector of length 4 (byte vectors are just character
strings that are accessed using `vector-8b-ref' rather than
`string-ref').  The bytes in an IP address read in the same order as
they do when written out:

     (get-host-by-name "www.swiss") => #("\022\027\000\020")

 - procedure: get-host-by-name host-name
     Looks up the internet host name HOST-NAME using the DNS, returning
     a vector of IP addresses for the corresponding host, or `#f' if
     there is no such host.  Usually the returned vector has only one
     element, but if a host has more than one network interface, the
     vector might have more than one element.

          (get-host-by-name "www.swiss") => #("\022\027\000\020")

 - procedure: get-host-by-address ip-address
     Does a reverse DNS lookup on IP-ADDRESS, returning the internet
     host name corresponding to that address, or `#f' if there is no
     such host.

          (get-host-by-address "\022\027\000\020") => "swissnet.ai.mit.edu"

 - procedure: canonical-host-name host-name
     Finds the "canonical" internet host name for HOST-NAME.  For
     example:

          (canonical-host-name "zurich")    => "zurich.ai.mit.edu"
          (canonical-host-name "www.swiss") => "swissnet.ai.mit.edu"

     In both examples, the default internet domain `ai.mit.edu' is added
     to HOST-NAME.  In the second example, `"www.swiss"' is an alias
     for another computer named `"swissnet"'.

 - procedure: get-host-name
     Returns the string that identifies the computer that MIT Scheme is
     running on.  Usually this is an unqualified internet host name,
     i.e.  the host name without the domain suffix:

          (get-host-name) => "aarau"

 - procedure: os/hostname
     Returns the canonical internet host name of the computer that MIT
     Scheme is running on.  So, in contrast to the example for
     `get-host-name':

          (os/hostname) => "aarau.ai.mit.edu"

 - procedure: allocate-host-address
     Allocates and returns an IP address object.  This is just a string
     of a fixed length (current 4 bytes) into which an IP address may
     be stored.  This procedure is used to generate an appropriate
     argument to be passed to `tcp-server-connection-accept'.

          (allocate-host-address) => "Xe\034\241"

 - procedure: host-address-any
     Return an IP address object that specifies "any host".  This
     object is useful only when passed as the ADDRESS argument to
     `open-tcp-server-socket'.

          (host-address-any) => "\000\000\000\000"

 - procedure: host-address-loopback
     Return an IP address object that specifies the local "loopback"
     network interface.  The loopback interface is a software network
     interface that can be used only for communicating between
     processes on the same computer.  This address object is useful
     only when passed as the ADDRESS argument to
     `open-tcp-server-socket'.

          (host-address-loopback) => "\177\000\000\001"

Error System
************

   The MIT Scheme error system provides a uniform mechanism for the
signalling of errors and other exceptional conditions.  The simplest and
most generally useful procedures in the error system are:

`error'
     is used to signal simple errors, specifying a message and some
     irritant objects (see Condition Signalling).  Errors are
     usually handled by stopping the computation and putting the user
     in an error REPL.

`warn'
     is used to signal warnings (see Condition Signalling).
     Warnings are usually handled by printing a message on the console
     and continuing the computation normally.

`ignore-errors'
     is used to suppress the normal handling of errors within a given
     dynamic extent (see Condition Handling).  Any error that
     occurs within the extent is trapped, returning immediately to the
     caller of `ignore-errors'.

   More demanding applications require more powerful facilities.  To
give a concrete example, suppose you want floating-point division to
return a very large number whenever the denominator is zero.  This
behavior can be implemented using the error system.

   The Scheme arithmetic system can signal many different kinds of
errors, including floating-point divide by zero.  In our example, we
would like to handle this particular condition specially, allowing the
system to handle other arithmetic errors in its usual way.

   The error system supports this kind of application by providing
mechanisms for distinguishing different types of error conditions and
for specifying where control should be transferred should a given
condition arise.  In this example, there is a specific object that
represents the "floating-point divide by zero" condition type, and it
is possible to dynamically specify an arbitrary Scheme procedure to be
executed when a condition of that type is signalled.  This procedure
then finds the stack frame containing the call to the division operator,
and returns the appropriate value from that frame.

   Another useful kind of behavior is the ability to specify uniform
handling for related classes of conditions.  For example, it might be
desirable, when opening a file for input, to gracefully handle a
variety of different conditions associated with the file system.  One
such condition might be that the file does not exist, in which case the
program will try some other action, perhaps opening a different file
instead.  Another related condition is that the file exists, but is
read protected, so it cannot be opened for input.  If these or any
other related conditions occur, the program would like to skip this
operation and move on to something else.

   At the same time, errors unrelated to the file system should be
treated in their usual way.  For example, calling `car' on the argument
`3' should signal an error.  Or perhaps the name given for the file is
syntactically incorrect, a condition that probably wants to be handled
differently from the case of the file not existing.

   To facilitate the handling of classes of conditions, the error system
taxonomically organizes all condition types.  The types are related to
one another by "taxonomical links", which specify that one type is a
"kind of" another type.  If two types are linked this way, one is
considered to be a "specialization" of the other; or vice-versa, the
second is a "generalization" of the first.  In our example, all of the
errors associated with opening an input file would be specializations
of the condition type "cannot open input file".

   The taxonomy of condition types permits any condition type to have no
more than one immediate generalization.  Thus, the condition types form
a forest (set of trees).  While users can create new trees, the standard
taxonomy (see Taxonomy) is rooted at
`condition-type:serious-condition', `condition-type:warning',
`condition-type:simple-condition', and `condition-type:breakpoint';
users are encouraged to add new subtypes to these condition types
rather than create new trees in the forest.

   To summarize, the error system provides facilities for the following
tasks.  The sections that follow will describe these facilities in more
detail.

Signalling a condition
     A condition may be signalled in a number of different ways.  Simple
     errors may be signalled, without explicitly defining a condition
     type, using `error'.  The `signal-condition' procedure provides the
     most general signalling mechanism.

Handling a condition
     The programmer can dynamically specify handlers for particular
     condition types or for classes of condition types, by means of the
     `bind-condition-handler' procedure.  Individual handlers have
     complete control over the handling of a condition, and
     additionally may decide not to handle a particular condition,
     passing it on to previously bound handlers.

Restarting from a handler
     The `with-restart' procedure provides a means for
     condition-signalling code to communicate to condition-handling
     code what must be done to proceed past the condition.  Handlers
     can examine the restarts in effect when a condition was signalled,
     allowing a structured way to continue an interrupted computation.

Packaging condition state
     Each condition is represented by an explicit object.  Condition
     objects contain information about the nature of the condition,
     information that describes the state of the computation from which
     the condition arose, and information about the ways the
     computation can be restarted.

Classification of conditions
     Each condition has a type, represented by a condition type object.
     Each condition type may be a specialization of some other
     condition types.  A group of types that share a common
     generalization can be handled uniformly by specifying a handler
     for the generalization.

Condition Signalling
====================

   Once a condition instance has been created using `make-condition'
(or any condition constructor), it can be "signalled".  The act of
signalling a condition is separated from the act of creating the
condition to allow more flexibility in how conditions are handled.  For
example, a condition instance could be returned as the value of a
procedure, indicating that something unusual has happened, to allow the
caller to clean up some state.  The caller could then signal the
condition once it is ready.

   A more important reason for having a separate condition-signalling
mechanism is that it allows _resignalling_.  When a signalled condition
has been caught by a particular handler, and the handler decides that
it doesn't want to process that particular condition, it can signal the
condition again.  This is one way to allow other handlers to get a
chance to see the condition.

 - procedure: error reason argument...
     This is the simplest and most common way to signal a condition that
     requires intervention before a computation can proceed (when
     intervention is not required, `warn' is more appropriate).
     `error' signals a condition (using `signal-condition'), and if no
     handler for that condition alters the flow of control (by invoking
     a restart, for example) it calls the procedure
     `standard-error-handler', which normally prints an error message
     and stops the computation, entering an error REPL.  Under normal
     circumstances `error' will not return a value (although an
     interactive debugger can be used to force this to occur).

     Precisely what condition is signalled depends on the first
     argument to `error'.  If REASON is a condition, then that
     condition is signalled and the ARGUMENTs are ignored.  If REASON
     is a condition type, then a new instance of this type is generated
     and signalled; the ARGUMENTs are used to generate the values of the
     fields for this condition type (they are passed as the FIELD-PLIST
     argument to `make-condition').  In the most common case, however,
     REASON is neither a condition nor a condition type, but rather a
     string or symbol.  In this case a condition of type
     `condition-type:simple-error' is created with the MESSAGE field
     containing the REASON and the IRRITANTS field containing the
     ARGUMENTs.

 - procedure: warn reason argument...
     When a condition is not severe enough to warrant intervention, it
     is appropriate to signal the condition with `warn' rather than
     `error'.  As with `error', `warn' first calls `signal-condition';
     the condition that is signalled is chosen exactly as in `error'
     except that a condition of type `condition-type:simple-warning' is
     signalled if REASON is neither a condition nor a condition type.
     If the condition is not handled, `warn' calls the procedure
     `standard-warning-handler', which normally prints a warning message
     and continues the computation by returning from `warn'.

     `warn' establishes a restart named `muffle-warning' before calling
     `signal-condition'.  This allows a signal handler to prevent the
     generation of the warning message by calling `muffle-warning'.
     The value of a call to `warn' is unspecified.

 - procedure: signal-condition condition
     This is the fundamental operation for signalling a condition.  The
     precise operation of `signal-condition' depends on the condition
     type of which CONDITION is an instance, the condition types set by
     `break-on-signals', and the handlers established by
     `bind-condition-handler' and `bind-default-condition-handler'.

     If the CONDITION is an instance of a type that is a specialization
     of any of the types specified by `break-on-signals', then a
     breakpoint REPL is initiated.  Otherwise (or when that REPL
     returns), the handlers established by `bind-condition-handler' are
     checked, most recent first.  Each applicable handler is invoked,
     and the search for a handler continues if the handler returns
     normally.  If all applicable handlers return, then the applicable
     handlers established by `bind-default-condition-handler' are
     checked, again most recent first.  Finally, if no handlers apply
     (or all return in a normal manner), `signal-condition' returns an
     unspecified value.

     _Note:_ unlike many other systems, the MIT Scheme runtime library
     does _not_ establish handlers of any kind.  (However, the Edwin
     text editor uses condition handlers extensively.)  Thus, calls to
     `signal-condition' will return to the caller unless there are user
     supplied condition handlers, as the following example shows:

          (signal-condition
           (make-condition
            condition-type:error
            (call-with-current-continuation (lambda (x) x))
            '()    ; no restarts
            '()))  ; no fields
          =>  unspecified

Error Messages
==============

   By convention, error messages (and in general, the reports generated
by `write-condition-report') should consist of one or more complete
sentences.  The usual rules for sentences should be followed: the first
word of the sentence should be capitalized, and the sentence should be
terminated by a period.  The message should not contain extraneous
whitespace such as line breaks or indentation.

   The error system provides a simple formatting language that allows
the programmer to have some control over the printing of error messages.
This formatting language will probably be redesigned in a future
release.

   Error messages typically consist of a string describing the error,
followed by some irritant objects.  The string is printed using
`display', and the irritants are printed using `write', typically with
a space between each irritant.  To allow simple formatting, we
introduce a "noise" object, printed using `display'.  The irritant list
may contain ordinary objects interspersed with noise objects.  Each
noise object is printed using `display', with no extra whitespace,
while each normal object is printed using `write', prefixed by a single
space character.

   Here is an example:

     (define (error-within-procedure message irritant procedure)
       (error message
              irritant
              (error-irritant/noise "within procedure")
              procedure
              (error-irritant/noise ".")))

This would format as follows:

     (error-within-procedure "Bad widget" 'widget-32 'invert-widget) error-->

     Bad widget widget-32 within procedure invert-widget.

   Here are the operations supporting error messages:

 - procedure: format-error-message message irritants port
     MESSAGE is typically a string (although this is not required),
     IRRITANTS a list of irritant objects, and PORT an output port.
     Formats MESSAGE and IRRITANTS to PORT in the standard way.  Note
     that, during the formatting process, the depth and breadth to
     which lists are printed are each limited to small numbers, to
     guarantee that the output from each irritant is not arbitrarily
     large.

 - procedure: error-irritant/noise value
     Creates and returns a noise object whose value is VALUE.