@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
@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

@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
@code{ext:process-command-args}.
@end deftypevar

@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 @code{ext:process-command-args}, and you can use it as a
starting point to extend ECL.
@end deftypevar

@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

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

@defvr argument args
A list of strings. Defaults to the output of @code{ext:command-args}.
@end defvr
@defvr argument rules
A list of lists. Defaults to the value of
@code{ext:+default-command-arg-rules+}.
@end defvr

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]*)}

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

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

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

@defvr opt :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.
@end defvr

@defvr opt :noloadrc
@defvrx opt :loadrc
Determine whether the lisp initialization files in
@code{ext:*lisp-init-file-list*} will be loaded before processing
all forms.
@end defvr

@code{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,
@code{ext:process-command-args}, and there were no occurrences of
@code{:noloadrc}, the first existing file listed in
@code{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
@code{ecl/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
@code{ext:external-process}. If one just wishes to execute some
program, without caring for its output, then probably
@code{ext:system} is the best function. In all other cases it is
preferable to use @code{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 @code{ext:run-program}
(returned as third value). It is programmer responsibility, to call
@code{ext:external-process-wait} on finished processes, however during
garbage collection object will be finalized.

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

@defun ext:external-process-status process
Updates process status. @code{ext:external-process-status} calls
@code{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

@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 @code{ext:external-process-status}).
@end defun

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

@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

@lspindex 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

@code{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).

@code{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
@code{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:

@defvr argument 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 @code{external-process-input} slot is filled in
with a stream that sends its output to the process. Defaults to
@code{:stream}.
@end defvr

@defvr argument 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
@code{run-program}
@end defvr

@defvr argument 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 @code{external-process-output} slot is filled in
with a stream that can be read to get the output. Defaults to
@code{:stream}.
@end defvr

@defvr argument if-output-exists
@end defvr

@defvr argument 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}.
@end defvr

@defvr argument if-error-exists
Same as @code{:if-output-exists}.
@end defvr

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

@defvr argument 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-NIL @code{environ} argument is supplied, then first argument to
@code{ext:run-program} @code{command} must be full path to the file.
@end defvr

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

@emph{Windows specific options:}
@defvr argument escape-arguments
Controls escaping of the arguments passed to CreateProcess.
@end defvr
@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. @code{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

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

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


@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 @code{kill-all-threads} is non-NIL, tries to gently kill and join
with running threads.
@end defun

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


@c UNIX shell interface

@defun ext:getpid
@defunx ext:getuid
@defunx ext:getcwd &optional (change-default-pathname-defaults NIL)
@defunx ext:chdir directory (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
