@node Operating System Interface
@section Operating System Interface

@menu
* Command line arguments::
* External processes::
* FIFO files (named pipes)::
@c * Signals and interrupts::
* Operating System Interface Reference::
@end menu

@cindex Command line processing
@node Command line arguments
@subsection Command line arguments

@lspdef ext:*help-message*
@deftypevar string ext:*help-message*
Command line help message. Initial value is ECL help message. This
variable contains the help message which is output when ECL is invoked
with the @code{--help}.
@end deftypevar

@lspdef ext:*lisp-init-file-list*
@deftypevar list-of-pathname-designators ext:*lisp-init-file-list*
ECL initialization files. Initial value is @code{'("~/.ecl"
"~/.eclrc")}. This variable contains the names of initialization files
that are loaded by ECL or embedding programs. The loading of
initialization files happens automatically in ECL unless invoked with
the option @code{--norc}. Whether initialization files are loaded or
not is controlled by the command line options rules, as described in
@coderef{ext:process-command-args}.
@end deftypevar

@lspdef ext:+default-command-arg-rules+
@deftypevar list-of-lists ext:+default-command-arg-rules+
ECL command line options. This constant contains a list of rules for
parsing the command line arguments. This list is made of all the
options which ECL accepts by default. It can be passed as first
argument to @coderef{ext:process-command-args}, and you can use it as a
starting point to extend ECL.
@end deftypevar

@lspdef ext:command-args
@defun ext:command-args
Original list of command line arguments. This function returns the
list of command line arguments passed to either ECL or the program it
was embedded in. The output is a list of strings and it corresponds to
the argv vector in a C program. Typically, the first argument is the
name of the program as it was invoked. You should not count on the
filename to be resolved.
@end defun

@lspdef ext:process-command-args
@defun ext:process-command-args &key args rules

@table @var
@item args
A list of strings. Defaults to the output of @coderef{ext:command-args}.
@item rules
A list of lists. Defaults to the value of
@coderef{ext:+default-command-arg-rules+}.
@end table

This function processes the command line arguments passed to either
ECL or the program that embeds it. It uses the list of rules rules,
which has the following syntax:

@code{(option-name nargs template [:stop | :noloadrc | :loadrc]*)}

@table @code
@item option-name
A string with the option prefix as typed by the user. For instance
@code{--help}, @code{-?}, @code{--compile}, etc.

@item nargs
A non-negative integer denoting the number of arguments taken by this
option.

@item template
A lisp form, not evaluated, where numbers from 0 to nargs will be
replaced by the corresponding option argument.

@item :stop
If present, parsing of arguments stops after this option is found and
processed. The list of remaining arguments is passed to the
rule. ECL's top-level uses this option with the @code{--} command line
option to set @code{ext:*unprocessed-ecl-command-args*} to the list of
remaining arguments.

@item :noloadrc, :loadrc
Determine whether the lisp initialization files in
@coderef{ext:*lisp-init-file-list*} will be loaded before processing
all forms.
@end table

@coderef{ext:process-command-args} works as follows. First of all, it
parses all the command line arguments, except for the first one, which
is assumed to contain the program name. Each of these arguments is
matched against the rules, sequentially, until one of the patterns
succeeds.

A special name @code{*default*}, matches any unknown command line
option. If there is no @code{*default*} rule and no match is found, an
error is signaled. For each rule that succeeds, the function
constructs a lisp statement using the template.

After all arguments have been processed,
@coderef{ext:process-command-args}, and there were no occurrences of
@code{:noloadrc}, the first existing file listed in
@coderef{ext:*lisp-init-file-list*} will be loaded. Finally, the list of
lisp statements will be evaluated.
@end defun

@cindex Parsing arguments in standalone executable
@exindex LS implementation

The following piece of code implements the ls command using
lisp. Instructions for building this program are found under
@file{examples/cmdline/ls.lsp}.

@lisp
@verbatim
(setq ext:*help-message* "
ls [--help | -?] filename*
     Lists the file that match the given patterns.
")

(defun print-directory (pathnames)
  (format t "~{~A~%~}"
          (mapcar #'(lambda (x) (enough-namestring x (si::getcwd)))
                  (mapcan #'directory (or pathnames '("*.*" "*/"))))))

(defconstant +ls-rules+
  '(("--help" 0 (progn (princ ext:*help-message* *standard-output*) (ext:quit 0)))
    ("-?" 0 (progn (princ ext:*help-message* *standard-output*) (ext:quit 0)))
    ("*DEFAULT*" 1 (print-directory 1) :stop)))

(let ((ext:*lisp-init-file-list* NIL)) ; No initialization files
  (handler-case (ext:process-command-args :rules +ls-rules+)
                (error (c)
                       (princ ext:*help-message* *error-output*)
                       (ext:quit 1))))
(ext:quit 0)
@end verbatim
@end lisp

@cindex External processes
@node External processes
@subsection External processes

ECL provides several facilities for invoking and communicating with
external processes. If one just wishes to execute some program, without
caring for its output, then probably @coderef{ext:system} is the best
function. In all other cases it is preferable to use
@coderef{ext:run-program}, which opens pipes to communicate with the
program and manipulate it while it runs on the background.

External process is a structure created with @coderef{ext:run-program}
(returned as third value). It is programmer responsibility, to call
@coderef{ext:external-process-wait} on finished processes, however during
garbage collection object will be finalized.

@lspdef ext:external-process-pid
@defun ext:external-process-pid process
Returns process PID or @code{nil} if already finished.
@end defun

@lspdef ext:external-process-status
@defun ext:external-process-status process
Updates process status. @coderef{ext:external-process-status} calls
@coderef{ext:external-process-wait} if process has not finished yet
(non-blocking call).  Returns two values:

@code{status} - member of @code{(:abort :error :exited :signalled
:stopped :resumed :running)}

@code{code} - if process exited it is a returned value, if terminated
it is a signal code. Otherwise NIL.
@end defun

@lspdef ext:external-process-wait
@defun ext:external-process-wait process wait
If the second argument is non-NIL, function blocks until external
process is finished. Otherwise status is updated. Returns two values
(see @coderef{ext:external-process-status}).
@end defun

@lspdef ext:terminate-process
@defun ext:terminate-process process &optional force
Terminates external process.
@end defun

@lspdef ext:external-process-input
@lspdef ext:external-process-output
@lspdef ext:external-process-error-stream
@defun ext:external-process-input process
@defunx ext:external-process-output process
@defunx ext:external-process-error-stream process
Process stream accessors (read-only).
@end defun

@lspdef ext:run-program
@defun ext:run-program command argv @
       &key input output error wait environ @
       if-input-does-not-exist if-output-exists if-error-exists @
       external-format #+windows escape-arguments

@coderef{ext:run-program} creates a new process specified by the
@var{command} argument. @var{argv} are the standard arguments that can
be passed to a program. For no arguments, use @code{nil} (which means
that just the name of the program is passed as arg 0).

@coderef{ext:run-program} will return three values - two-way stream for
communication, return code or @code{nil} (if process is called
asynchronously), and @code{ext:external-process} object holding
process state.

It is programmer responsibility to call
@coderef{ext:external-process-wait} on finished process, however ECL
associates @ref{Finalization, finalizer} with the object calling it
when the object is garbage collected. If process didn't finish but is
not referenced, finalizer will be invoked once more during next
garbage collection.

The @code{&key} arguments have the following meanings:

@table @var
@item input
Either @code{t}, @code{nil}, a pathname, a string, a stream or
@code{:stream}. If @code{t} the standard input for the current process
is inherited. If @code{nil}, @code{/dev/null} is used. If a pathname (or
a string), the file so specified is used. If a stream, all the input is
read from that stream and sent to the subprocess. If @code{:stream}, the
@coderef{ext:external-process-input} slot is filled in with a stream
that sends its output to the process. Defaults to @code{:stream}.

@item if-input-does-not-exist
Can be one of: @code{:error} to generate an error @code{:create} to
create an empty file @code{nil} (the default) to return nil from
@coderef{ext:run-program}

@item output
Either @code{t}, @code{nil}, a pathname, a string, a stream, or
@code{:stream}. If @code{t}, the standard output for the current process
is inherited. If @code{nil}, @code{/dev/null} is used. If a pathname (or
as string), the file so specified is used. If a stream, all the output
from the process is written to this stream. If @code{:stream}, the
@coderef{ext:external-process-output} slot is filled in with a stream
that can be read to get the output. Defaults to @code{:stream}.

@item if-output-exists
Can be one of: @code{:error} (the default) to generate an error,
@code{:supersede} to supersede the file with output from the program,
@code{:append} to append output from the program to the file or
@code{nil} to return @code{nil} from @coderef{ext:run-program}.

@item error
Same as @code{:output}, except that @code{:error} can also be
specified as @code{:output} in which case all error output is routed
to the same place as normal output. Defaults to @code{:output}.

@item if-error-exists
Same as @code{:if-output-exists}.

@item wait
If non-@code{nil} (default), wait until the created process finishes. If
@code{nil}, continue running Lisp until the program finishes.

@item environ
A list of STRINGs describing the new Unix environment (as in "man
environ"). The default is to copy the environment of the current
process. To extend existing environment (instead of replacing it),
use @code{:environ (append *my-env* (ext:environ))}.

If non-@code{nil} @code{environ} argument is supplied, then first
argument to @coderef{ext:run-program}, @var{command}, must be full path
to the file.

@item external-format
The external-format to use for @code{:input}, @code{:output}, and
@code{:error} STREAMs.
@end table

@strong{Windows specific options:}
@table @var
@item escape-arguments
Controls escaping of the arguments passed to @code{CreateProcess}.
@end table
@end defun

@cindex FIFO files (named pipes)
@node FIFO files (named pipes)
@subsection FIFO files (named pipes)

Named pipe (known as fifo) may be created on UNIX with a shell command
mkfifo. ECL opens such files in non-blocking
mode. @coderef{ext:file-kind} will return for such file
@code{:fifo}. Since it is impossible to guess how many characters are
available in this special file @code{file-length} function will return
NIL.

@node Operating System Interface Reference
@subsection Operating System Interface Reference

@c environment routines

@c Don't advertise argc and argv, we have command-args

@c @defun ext:argc
@c @end defun

@c @defun ext:argv
@c @end defun

@lspdef ext:system
@defun ext:system command
Run shell command ignoring its output. Uses fork.
@end defun

@lspdef ext:make-pipe
@defun ext:make-pipe
Creates a pipe and wraps it in a two way stream.
@end defun

@lspdef ext:quit
@defun ext:quit &optional exit-code kill-all-threads
This function abruptly stops the execution of the program in which ECL
is embedded. Depending on the platform, several other functions will
be invoked to free resources, close loaded modules, etc.

The exit code is the code seen by the parent process that invoked this
program. Normally a code other than zero denotes an error.

If @var{kill-all-threads} is non-@code{nil}, tries to gently kill and
join with running threads.
@end defun

@lspdef ext:environ
@lspdef ext:getenv
@lspdef ext:setenv
@defun ext:environ
@defunx ext:getenv variable
@defunx ext:setenv variable value
Environment accessors.
@end defun


@c UNIX shell interface

@lspdef ext:getpid
@lspdef ext:getuid
@lspdef ext:getcwd
@lspdef ext:chdir
@lspdef ext:file-kind
@lspdef ext:copy-file
@lspdef ext:chmod

@defun ext:getpid
@defunx ext:getuid
@defunx ext:getcwd &optional (change-default-pathname-defaults NIL)
@defunx ext:chdir directory &optional (change-default-pathname-defaults T)
@defunx ext:file-kind filename follow-symlinks-p
@defunx ext:copy-file filename destination-filename
@defunx ext:chmod filename mode
Common operating system functions.
@end defun

@c Internal UNIX shell interface

@c @defun si:mkdir
@c @defunx si:rmdir
@c @defunx si:mkstemp
@c @defunx si:copy-file
@c @end defun

@c @defun si:get-library-pathname
@c @end defun

@c @defun si:waitpid pid wait
@c @defunx si:kill pid signal
@c @end defun

@c @defun si:run-program-inner command argv environ
@c @end defun
