goosh 1.0: A small process-control library for Guile.

   Goosh is a library for execution of other programs from Guile.  It
also allows communication using pipes (or a pseudo terminal device, but
that's not currently implemented).  This was part of goonix in one of
Guile's past lives.

   To load the library use:
     (use-modules (goosh))

   The following will hold when starting programs:

  1. If the name of the program does not contain a `/' then the
     directories listed in the current `PATH' environment variable are
     searched to locate the program.

  2. Unlike for the corresponding primitive exec procedures, e.g.,
     `execlp', the name of the program can not be set independently of
     the path to execute: the zeroth and first members of the argument
     vector are combined into one.

 - Function: tail-call-program prog arg ...
     Replace the current process image by executing PROG with the
     supplied list of arguments.

     This procedure will reset the signal handlers, flush output buffers
     and set up file descriptors as follows, but does not close any
     ports.

       1. File descriptor 0 is set from (current-input-port).

       2. File descriptor 1 is set from (current-output-port).

       3. File descriptor 2 is set from (current-error-port).

     If a port can not be used then the file descriptor is opened on
     the file specified by `*null-device*' instead.

     Examples:
          (tail-call-program "cat" "/etc/passwd")

          (with-input-from-file "/etc/passwd"
            (lambda ()
              (tail-call-program "cat")))

 - Function: tail-call-pipeline (prog arg ...) ...
     Replace the current process image with a pipeline of connected
     processes.

     The expressions in the pipeline are run in new background
     processes.  The foreground process waits for them all to
     terminate.  The exit status is derived from the status of the
     process at the tail of the pipeline: its exit status if it
     terminates normally, otherwise 128 plus the number of the signal
     that caused it to terminate.

     The signal handlers will be reset, output buffers flushed and file
     descriptors set up as for `tail-call-program'.  Like
     `tail-call-program' it does not close open ports.

     Example:
          (tail-call-pipeline ("ls" "/etc") ("grep" "passwd"))

 - Function: tail-call-pipeline+ expr connections expr ...
     Replace the current process image with a pipeline of connected
     processes.

     Each process is specified by an expression and each pair of
     processes has a connection list with pairs of file descriptors.
     E.g., `((1 0) (2 0))' specifies that file descriptors 1 and 2 are
     to be connected to file descriptor 0.  This may also be written as
     `((1 2 0))'.

     The expressions in the pipeline are run in new background
     processes.  The foreground process waits for them all to
     terminate.  The exit status is derived from the status of the
     process at the tail of the pipeline: its exit status if it
     terminates normally, otherwise 128 plus the number of the signal
     that caused it to terminate.

     The signal handlers will be reset, output buffers flushed and file
     descriptors set up as for `tail-call-program'.  Like
     `tail-call-program' it does not close open ports.

     Example:
          (tail-call-pipeline+ (tail-call-program "ls" "/etc") ((1 0))
                               (tail-call-program "grep" "passwd"))

 - Function: run prog arg ...
     Execute PROG in a new foreground process and wait for its
     completion.  The value returned is the exit status of the new
     process as returned by the `waitpid' procedure.

     Example:
          (run "cat" "/etc/passwd")

 - Function: run+ expr keywords connections ...
     Evaluate an expression in a new foreground process and wait for its
     completion.  If no connection terms are specified, then all ports
     except `current-input-port', `current-output-port' and
     `current-error-port' will be closed in the new process.  The file
     descriptors underlying these ports will not be changed.

     The value returned is the exit status from the new process as
     returned by the `waitpid' procedure.

     The KEYWORDS and CONNECTIONS arguments are optional: see
     `run-concurrently+', which is documented below.  The
     `#:foreground' keyword is implied.

          (run+ (begin (write (+ 2 2)) (newline) (quit 0)))

          (run+ (tail-call-program "cat" "/etc/passwd"))

 - Function: run-with-pipe mode prog arg ...
     Start PROG running in a new background process.  The value
     returned is a pair: the CAR is the pid of the new process and the
     CDR is either a port or a pair of ports (with the CAR containing
     the input port and the CDR the output port).  The port(s) can be
     used to read from the standard output of the process and/or write
     to its standard input, depending on the MODE setting.  The value
     of MODE should be one of "r", "w" or "r+".

     When the process terminates its exit status can be collected using
     the `waitpid' procedure.

     Example:
          (define catport (cdr (run-with-pipe "r" "cat" "/etc/passwd")))

 - Function: run-with-pty prog arg ...
     This procedure is not currently implemented.

     Start PROG running in a new background process, with communication
     through a newly allocated pseudo terminal device (pty).  The value
     returned is a pair containing the pid of the new process and the
     read/write port corresponding to the master side of the pty.

     When the process terminates its exit status can be collected using
     the `waitpid' procedure.

     Example:
          (define telport (cdr (run-with-pty "telnet")))

 - Function: run-concurrently prog arg ...
     Start a program running in a new background process.  The value
     returned is the pid of the new process.

     When the process terminates its exit status can be collected using
     the `waitpid' procedure.

     Example:
          (run-concurrently "cat" "/etc/passwd")

 - Function: run-concurrently+ expr keywords connections ...
     Evaluate an expression in a new background process.  If no
     connection terms are specified, then all ports except
     `current-input-port', `current-output-port' and
     `current-error-port' will be closed in the new process.  The file
     descriptors underlying these ports will not be changed.

     The value returned in the parent is the pid of the new process.

     When the process terminates its exit status can be collected using
     the `waitpid' procedure.

     Keywords can be specified before the connection list:

     `#:slave' causes the new process to be put into a new session.  If
     `current-input-port' (after redirections) is a tty it will be
     assigned as the controlling terminal.  This option is used when
     controlling a process via a pty.

     `#:no-auto-close' prevents the usual closing of ports which occurs
     by default.

     `#:foreground' makes the new process the foreground job of the
     controlling terminal, if the current process is using job control.
     (not currently implemented).  The default is to place it into the
     background

     The optional connection list can take several forms:

     `(port)' usually specifies that a given port not be closed.
     However if `#:no-auto-close' is present it specifies instead a
     port which should be closed.

     `(port 0)' specifies that a port be moved to a given file
     descriptor (e.g., 0) in the new process.  The order of the two
     components is not significant, but one must be a number and the
     other must evaluate to a port.  If the file descriptor is one of
     the standard set `(0, 1, 2)' then the corresponding standard port
     (e.g., `current-input-port') will be set to the specified port.

     Example:
          (let ((p (open-input-file "/etc/passwd")))
            (run-concurrently+ (tail-call-program "cat") (p 0)))