# Extensions

## Extensions-1: Platform independent Extensions

### Extensions-1.1. Saving an Image

The function `(`lisp:saveinitmem` &optional-amp; (filename "lispinit.mem") &key-amp; :quiet :init-function)` saves the running &clisp;'s memory to a file. If the `:quiet` argument is not &nil;, the startup banner and the good-bye message will be suppressed. The `:init-function` argument specifies a function that will be executed at startup of the saved image. The starting package of the new image is the one in which you were when you invoked `lisp:saveinitmem`.

### Extensions-1.2. Quitting Lisp

The functions `(`lisp:exit` [errorp])`, `(`lisp:quit` [errorp])` and `(`lisp:bye` [errorp])` - all synonymous - terminate &clisp;. If errorp is non-&nil;, &clisp; aborts with error status, i.e., the environment is informed that the &clisp; session did not succeed.

### Extensions-1.3. The Language

The language &clisp; uses to communicate with the user can be either `ENGLISH` or `DEUTSCH` (i.e., German) or `FRANCAIS` (i.e., French) or `ESPAÑOL` (i.e. Spanish). More languages can be defined through the macro `lisp:deflanguage`: `(`lisp:deflanguage` lang)`. For such an additional language to take effect, you must install the corresponding message catalog, or translate the messages yourself, using &gnu; gettext and Emacs po-mode.

The macros `ENGLISH`, `DEUTSCH`, `FRANCAIS` produce strings that depends on the language: `(ENGLISH english-string DEUTSCH deutsch-string FRANCAIS francais-string)` - and all permutations of this - evaluates all of english-string, deutsch-string, francais-string in no particular order and returns the evaluation result corresponding to the user language, be it among these three or not.

This works only for strings. For arbitrary language-dependent Lisp objects, you define one through the macro `lisp:definternational`: `(`lisp:definternational` symbol &optional-amp; (default-language &t;))` and add language-dependent values through the macro `lisp:deflocalized`: `(`lisp:deflocalized` symbol language value-form)`

(One such form for each language. Languages without an assigned value will be treated like the default-language.) You can then access the localized value by calling `lisp:localized`: `(`lisp:localized` symbol &optional-amp; language)`

### Extensions-1.4. Encodings

#### Introduction

An encoding describes the correspondence between characters and raw bytes during input/output via streams with element-type &character-class;.

An encoding is an object composed of the following facets:

- A character set. This denotes both the set of characters that can be represented and passed through the I/O channel, and the way these characters translate into raw bytes. In this context, for example, "UTF-8" and "UCS-4" are considered different, although they can represent the same set of characters.

- A line terminator mode. This denotes the way newline characters are represented.

#### Character Sets

Platform dependent: Only in &clisp; built &without; compile-time flag &unicode;.

  Only one character set is understood: the platform's native (8-bit) character set. See Chapter 13.

Platform dependent: Only in &clisp; built &with; compile-time flag &unicode;.

  The following character sets are supported, as values of the corresponding (constant) symbol in the CHARSET package:

  - `UCS-2` = `UNICODE-16` = `UNICODE-16-BIG-ENDIAN`, the 16-bit Unicode character set. Every character is represented as two bytes.

  - `UNICODE-16-LITTLE-ENDIAN`

  - `UCS-4` = `UNICODE-32` = `UNICODE-32-BIG-ENDIAN`, the 32-bit Unicode character set. Every character is represented as four bytes. Note that &clisp; understands only those characters which are already contained in the 16-bit Unicode character set.

  - `UNICODE-32-LITTLE-ENDIAN`

  - `UTF-8`, the 16-bit Unicode character set. Every character is represented as one to three bytes. ASCII characters represent themselves and need one byte per character. Most Latin/Greek/Cyrillic/Hebrew characters need two bytes per character, and the remaining characters need three bytes per character. This is therefore, in general, the most space-efficient encoding of all of Unicode-16.

  - `UTF-16`, the 16-bit Unicode character set. Every character is represented as two bytes.

  - `UTF-7`, the 16-bit Unicode character set. This is a stateful 7-bit encoding. Not all ASCII characters represent themselves.

  - `JAVA`, the 16-bit Unicode character set. ASCII characters represent themselves and need one byte per character. All other characters are represented by `\unnnn` sequences (nnnn a hexadecimal number) and need 6 bytes per character. While this encoding is very comfortable for editing Unicode files using only ASCII aware tools and editors, it cannot faithfully represent all Unicode text. Only text which does not contain `\u` (backslash followed by lowercase Latin u) can be faithfully represented by this encoding.

  - `ASCII`, the well-known US-centric 7-bit character set (American Standard Code for Information Interchange).

  - `ISO-8859-1`, an extension of the ASCII character set, suitable for the Afrikaans, Albanian, Basque, Breton, Catalan, Cornish, Danish, Dutch, English, Faeroese, Finnish, French, Frisian, Galician, German, Greenlandic, Icelandic, Irish, Italian, Latin, Luxemburgish, Norwegian, Portuguese, Raeto-Romanic, Scottish, Spanish, and Swedish languages.

  - `ISO-8859-2`, an extension of the ASCII character set, suitable for the Croatian, Czech, German, Hungarian, Polish, Slovak, Slovenian, and Sorbian languages.

  - `ISO-8859-3`, an extension of the ASCII character set, suitable for the Esperanto and Maltese languages.

  - `ISO-8859-4`, an extension of the ASCII character set, suitable for the Estonian, Latvian, Lithuanian and Sami (Lappish) languages.

  - `ISO-8859-5`, an extension of the ASCII character set, suitable for the Bulgarian, Byelorussian, Macedonian, Russian, Serbian, and Ukrainian languages.

  - `ISO-8859-6`, suitable for the Arabic language.

  - `ISO-8859-7`, an extension of the ASCII character set, suitable for the Greek language.

  - `ISO-8859-8`, an extension of the ASCII character set, suitable for the Hebrew language (without punctuation).

  - `ISO-8859-9`, an extension of the ASCII character set, suitable for the Turkish language.

  - `ISO-8859-10`, an extension of the ASCII character set, suitable for the Estonian, Icelandic, Inuit (Greenlandic), Latvian, Lithuanian, and Sami (Lappish) languages.

  - `ISO-8859-13`, an extension of the ASCII character set, suitable for the Estonian, Latvian, Lithuanian, Polish and Sami (Lappish) languages.

  - `ISO-8859-14`, an extension of the ASCII character set, suitable for Irish Gaelic, Manx Gaelic, Scottish Gaelic, and Welsh languages.

  - `ISO-8859-15`, an extension of the ASCII character set, suitable for the ISO-8859-1 languages, with improvements for French, Finnish and the Euro.

  - `ISO-8859-16` an extension of the ASCII character set, suitable for the Rumanian language.

  - `KOI8-R`, an extension of the ASCII character set, a popular character set for the Russian language.

  - `KOI8-U`, an extension of the ASCII character set, a popular character set for the Ukrainian language.

  - `KOI8-RU`, an extension of the ASCII character set, suitable for Russian (this is the standard Russian encoding on the Internet)

  - `JIS_X0201`, a character set for the Japanese language.

  - `MAC-ARABIC`, a platform specific extension of the ASCII character set.

  - `MAC-CENTRAL-EUROPE`, a platform specific extension of the ASCII character set.

  - `MAC-CROATIAN`, a platform specific extension of the ASCII character set.

  - `MAC-CYRILLIC`, a platform specific extension of the ASCII character set.

  - `MAC-DINGBAT`, a platform specific character set.

  - `MAC-GREEK`, a platform specific extension of the ASCII character set.

  - `MAC-HEBREW`, a platform specific extension of the ASCII character set.

  - `MAC-ICELAND`, a platform specific extension of the ASCII character set.

  - `MAC-ROMAN` = `MACINTOSH`, a platform specific extension of the ASCII character set.

  - `MAC-ROMANIA`, a platform specific extension of the ASCII character set.

  - `MAC-SYMBOL`, a platform specific character set.

  - `MAC-THAI`, a platform specific extension of the ASCII character set.

  - `MAC-TURKISH`, a platform specific extension of the ASCII character set.

  - `MAC-UKRAINE`, a platform specific extension of the ASCII character set.

  - `CP437`, a DOS oldie, a platform specific extension of the ASCII character set.

  - `CP437-IBM`, an IBM variant of `CP437`.

  - `CP737`, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for the Greek language.

  - `CP775`, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for some Baltic languages.

  - `CP850`, a DOS oldie, a platform specific extension of the ASCII character set.

  - `CP852`, a DOS oldie, a platform specific extension of the ASCII character set.

  - `CP852-IBM`, an IBM variant of `CP852`.

  - `CP855`, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for the Russian language.

  - `CP857`, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for the Turkish language.

  - `CP860`, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for the Portuguese language.

  - `CP860-IBM`, an IBM variant of `CP860`.

  - `CP861`, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for the Icelandic language.

  - `CP861-IBM`, an IBM variant of `CP861`.

  - `CP862`, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for the Hebrew language.

  - `CP862-IBM`, an IBM variant of `CP862`.

  - `CP863`, a DOS oldie, a platform specific extension of the ASCII character set.

  - `CP863-IBM`, an IBM variant of `CP863`.

  - `CP864`, a DOS oldie, meant to be suitable for the Arabic language.

  - `CP864-IBM`, an IBM variant of `CP864`.

  - `CP865`, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for some Nordic languages.

  - `CP865-IBM`, an IBM variant of `CP865`.

  - `CP866`, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for the Russian language.

  - `CP869`, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for the Greek language.

  - `CP869-IBM`, an IBM variant of `CP869`.

  - `CP874`, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for the Thai language.

  - `CP874-IBM`, an IBM variant of `CP874`.

  - `WINDOWS-1250` = `CP1250`, a platform specific extension of the ASCII character set, heavily incompatible with ISO-8859-2.

  - `WINDOWS-1251` = `CP1251`, a platform specific extension of the ASCII character set, heavily incompatible with ISO-8859-5, meant to be suitable for the Russian language.

  - `WINDOWS-1252` = `CP1252`, a platform specific extension of the ISO-8859-1 character set.

  - `WINDOWS-1253` = `CP1253`, a platform specific extension of the ASCII character set, gratuitously incompatible with ISO-8859-7, meant to be suitable for the Greek language.

  - `WINDOWS-1254` = `CP1254`, a platform specific extension of the ISO-8859-9 character set.

  - `WINDOWS-1255` = `CP1255`, a platform specific extension of the ASCII character set, gratuitously incompatible with ISO-8859-8, suitable for the Hebrew language.

  - `WINDOWS-1256` = `CP1256`, a platform specific extension of the ASCII character set, meant to be suitable for the Arabic language.

  - `WINDOWS-1257` = `CP1257`, a platform specific extension of the ASCII character set.

  - `WINDOWS-1258` = `CP1258`, a platform specific extension of the ASCII character set.

  - `HP-ROMAN8`, a platform specific extension of the ASCII character set.

  - `NEXTSTEP`, a platform specific extension of the ASCII character set.

  - `EUC-JP`, a multibyte character set for the Japanese language.

  - `SHIFT-JIS`, a multibyte character set for the Japanese language.

  - `CP932`, a Microsoft variant of `SHIFT-JIS`.

  - `ISO-2022-JP`, a stateful 7-bit multibyte character set for the Japanese language.

  - `ISO-2022-JP-2`, a stateful 7-bit multibyte character set for the Japanese language.

  - `ISO-2022-JP-1`, a stateful 7-bit multibyte character set for the Japanese language.

  - `EUC-CN`, a multibyte character set for simplified Chinese.

  - `HZ`, a stateful 7-bit multibyte character set for simplified Chinese.

  - `GBK`, a multibyte character set for Chinese,

  - `CP936`, a Microsoft variant of `GBK`.

  - `GB18030`, a multibyte character set for Chinese,

  - `EUC-TW`, a multibyte character set for traditional Chinese.

  - `BIG5`, a multibyte character set for traditional Chinese.

  - `CP950`, a Microsoft variant of `BIG5`.

  - `BIG5HKSCS`, a multibyte character set for traditional Chinese.

  - `ISO-2022-CN`, a stateful 7-bit multibyte character set for Chinese.

  - `ISO-2022-CN-EXT`, a stateful 7-bit multibyte character set for Chinese.

  - `EUC-KR`, a multibyte character set for Korean.

  - `CP949`, a Microsoft variant of `EUC-KR`.

  - `ISO-2022-KR`, a stateful 7-bit multibyte character set for Korean.

  - `ARMSCII-8`, an extension of the ASCII character set, suitable for Armenian.

  - `GEORGIAN-ACADEMY`, an extension of the ASCII character set, suitable for Georgian.

  - `GEORGIAN-PS`, an extension of the ASCII character set, suitable for Georgian.

  - `TIS-620`, an extension of the ASCII character set, suitable for Thai.

  - `MULELAO-1`, an extension of the ASCII character set, suitable for Laotian.

  - `CP1133`, an extension of the ASCII character set, suitable for Laotian.

  - `VISCII`, an extension of the ASCII character set, suitable for Vietnamese.

  - `TCVN`, an extension of the ASCII character set, suitable for Vietnamese.

  &clisp; comes with it own implementation of `iconv()`, so the following is more or less obsolete now. (Platform dependent: Only on &unix; systems having the &c-lang; library function iconv()).

    The character sets provided by the library function iconv() can also be used as encodings. To create such an encoding, call `make-encoding` with the character set name (a string) as `:charset` argument.

    These encodings are not assigned to global variables, since there is no portable way to get the list of all character sets supported by `iconv()`.

    On Linux and &gnu; systems, you get this list by calling the program iconv: `iconv --list`. &gnu; glibc-2.1 supports in particular, among others:

    - `EUC-JP` and `SHIFT-JIS`, for the Japanese language,

    - `EUC-CN`, `EUC-TW`, `BIG5` and `GB`, for the Chinese language,

    - `EUC-KR` and `ISO-2022-KR`, for the Korean language.

    HP-UX systems support in particular, among others:

    - `eucJP` and `sjis`, for the Japanese language,

    - `eucTW`, `big5` and `chinese-gb`, for the Chinese language,

    - `eucKR`, for the Korean language.

    AIX 4.2 systems support in particular, among others:

    - `IBM-eucJP`, for the Japanese language,

    - `IBM-eucTW`, for the Chinese language,

    - `IBM-eucKR`, for the Korean language.

    On Solaris systems, you can forget about iconv-based encodings, because all the possible encodings are already built-in. (Solaris knows about Japanese, Chinese and Korean encodings, but can convert them only to/from UTF-8, not to/from UCS-2, which is &clisp;'s internal encoding.)

    On IRIX systems, you can forget about iconv-based encodings as well, because all the interesting possible encodings are already built-in.

    On OSF/1 systems, iconv-based encodings are not usable at all.

    When an encoding is available as a built-in (see the list above) and through iconv(), the built-in is preferred, because it is more efficient and available across platforms.

#### Line Terminators

The line terminator mode can be one of the following three keywords

keyword newline representation
- `:unix` Newline is represented by the ASCII LF character (U000A).
- `:mac` Newline is represented by the ASCII CR character (U000D).
- `:dos` Newline is represented by ASCII CR followed by ASCII LF.

Windows programs typically use the `:dos` line terminator, sometimes they also accept `:unix` line terminators or produce `:mac` line terminators.

The line terminator mode is relevant only for output (writing to a &file-pipe-socket;). During input, all three kinds of line terminators are recognized. If you do not want this, i.e., if you really want to distinguish LF, CR and CR/LF, you have to resort to binary input (function &read-byte;).

See also 13.1.8 Treatment of Newline during Input and Output.

#### lisp:make-encoding

The function `(`lisp:make-encoding` &key-amp; :charset :line-terminator :input-error-action :output-error-action)` returns an encoding. The `:charset` argument may be an encoding, a string, or `:default`. The possible values for the `:line-terminator` argument are the keywords `:unix`, `:mac`, `:dos`.

The `:input-error-action` specifies what happens when an invalid byte sequence is encountered while converting bytes to characters. Its value can be &error-k;, &ignore-k; or a character to be used instead. The Unicode character #\uFFFD is typically used to indicate an error in the input sequence.

The `:output-error-action` specifies what happens when an invalid character is encountered while converting characters to bytes. Its value can be &error-k;, &ignore-k;, a byte to be used instead, or a character to be used instead. The Unicode character #\uFFFD can be used here only if it is encodable in the character set.

Encodings are types. As such, they represent the set of characters encodable in the character set. In this context, the way characters are translated into raw bytes is ignored, and the line terminator mode is ignored as well. &typep; and &subtypep; can be used on encodings.

Besides every &file-pipe-socket; stream containing an encoding, the following &symbol-macro; places contain global encodings:

`lisp:*default-file-encoding*` is the encoding used for new &file-pipe-socket; streams, when no &extfmt; argument was specified.

Platform dependent: Only in &clisp; built &with; compile-time flag &unicode;.
  `lisp:*pathname-encoding*`

    is the encoding used for pathnames in the file system. Normally, this is a 1:1 encoding. Its line terminator mode is ignored.

  `lisp:*terminal-encoding*`

    is the encoding used for communication with the terminal, in particular by &terminal-io-var;.

  `lisp:*misc-encoding*`

    is the encoding used for access to environment variables, command line options, and the like. Its line terminator mode is ignored.

#### Converting between strings and byte vectors

Encodings can also be used to convert directly between strings and their corresponding byte vector representation according to that encoding.

`(`lisp:convert-string-from-bytes` byte-vector encoding &key-amp; :start :end)`

  converts the subsequence of byte-vector from start to end to a string, according to the given encoding, and returns the resulting string.

`(`lisp:convert-string-to-bytes` string encoding &key-amp; :start :end)`

  converts the subsequence of string from start to end to a vector of `(unsigned-byte 8)`, according to the given encoding, and returns the resulting byte vector.

### Extensions-1.5. Defining new kinds of Streams

Two mechanisms are supported for creating new streams with user-defined behavior:

- You can create a new subclass of lisp:fundamental-stream and define methods for the elementary stream operations on it. These generic functions all have a name starting with the prefix "stream-".

- You can create a new subclass of lisp:generic-stream-controller and define methods for the elementary stream operations on it. These generic functions all have a name starting with the prefix "generic-stream-". The stream itself is a different object, created using the function `lisp:make-generic-stream`.

The `fundamental-stream` API is based on a proposal by David N. Gray and is supported by most &cl; implementations currently in use. The generic-stream-controller API is &clisp; specific and is now obsolete.

#### Gray streams

This interface permits the definition of new classes of streams, and programming their behavior by defining methods for the elementary stream operations. It is based on the proposal &gray-streams; of David N. Gray to X3J13.

All symbols defined by this interface, starting with the prefix "fundamental-" or "stream-", are exported from the package LISP.

Defined classes

lisp:fundamental-stream

  This is a superclass of all user-defined streams. It is a subclass of &stream-class; and of &standard-object-class;. Its metaclass is &standard-class;.

lisp:fundamental-input-stream

  This is a superclass of all user-defined input streams. It is a subclass of lisp:fundamental-stream. The built-in function &input-stream-p; returns true on instances of this class. This means that when you define a new stream class capable of doing input, you have to make it a subclass of lisp:fundamental-input-stream.

lisp:fundamental-output-stream

  This is a superclass of all user-defined output streams. It is a subclass of lisp:fundamental-stream. The built-in function &output-stream-p; returns true on instances of this class. This means that when you define a new stream class capable of doing output, you have to make it a subclass of lisp:fundamental-output-stream.

lisp:fundamental-character-stream

  This is a superclass of all user-defined streams whose element-type is &character-class;. It is a subclass of lisp:fundamental-stream. It defines a method on &stream-element-type; that returns &character-class;.

lisp:fundamental-binary-stream

  This is a superclass of all user-defined streams whose element-type is a subtype of &integer-class;. It is a subclass of lisp:fundamental-stream. When you define a subclass of lisp:fundamental-binary-stream, you have to provide a method on &stream-element-type;.

lisp:fundamental-character-input-stream

  This is a convenience class inheriting from both lisp:fundamental-character-stream and lisp:fundamental-input-stream.

lisp:fundamental-character-output-stream

  This is a convenience class inheriting from both lisp:fundamental-character-stream and lisp:fundamental-output-stream.

lisp:fundamental-binary-input-stream

  This is a convenience class inheriting from both lisp:fundamental-binary-stream and lisp:fundamental-input-stream.

lisp:fundamental-binary-output-stream

  This is a convenience class inheriting from both lisp:fundamental-binary-stream and lisp:fundamental-output-stream.

general generic functions defined on streams

`(&stream-element-type; stream)`

  Returns the stream's element type, normally a subtype of &character-class; or &integer-class;.

  The method for lisp:fundamental-character-stream returns &character-class;.

`((&setf; &stream-element-type;) new-element-type stream)`

  Changes the stream's element type.

  The default method signals an error.

  This function is a &clisp; extension.

`(&close; stream &key-amp; &abort-k;)`

  Closes the stream and flushes any associated buffers.

  When you define a primary method on this function, do not forget to &call-next-method;.

`(&open-stream-p; stream)`

  Returns true before the stream has been closed, and &nil; after the stream has been closed.

  You do not need to add methods to this function.

generic functions for character input

`(`lisp:stream-read-char` stream)`

  If a character was pushed back using `lisp:stream-unread-char`, returns and consumes it. Otherwise returns and consumes the next character from the stream. Returns &eof-k; if the &eos; is reached.

  You must define a method for this function.

`(`lisp:stream-unread-char` stream character)`

  Pushes character, which must be the last character read from the stream, back onto the front of the stream.

  You must define a method for this function.

`(`stream-read-char-no-hang` stream)`

  Returns a character or &eof-k;, like `lisp:stream-read-char`, if that would return immediately. If `lisp:stream-read-char`'s value is not available immediately, returns &nil; instead of waiting.

  The default method simply calls `lisp:stream-read-char`; this is sufficient for streams whose `lisp:stream-read-char` method never blocks.

`(`lisp:stream-peek-char` stream)`

  If a character was pushed back using `lisp:stream-unread-char`, returns it. Otherwise returns the next character from the stream, avoiding any side effects `lisp:stream-read-char` would do. Returns &eof-k; if the &eos; is reached.

  The default method calls `lisp:stream-read-char` and `lisp:stream-unread-char`; this is sufficient for streams whose `lisp:stream-read-char` method has no side-effects.

`(`lisp:stream-listen` stream)`

  If a character was pushed back using `lisp:stream-unread-char`, returns it. Otherwise returns the next character from the stream, if already available. If no character is available immediately, or if &eos; is reached, returns &nil;.

  The default method calls `lisp:stream-read-char-no-hang` and `lisp:stream-unread-char`; this is sufficient for streams whose `lisp:stream-read-char` method has no side-effects.

`(`lisp:stream-read-char-will-hang-p` stream)`

  Returns &nil; if `lisp:stream-read-char` will return immediately. Otherwise it returns true.

  The default method calls `lisp:stream-read-char-no-hang` and `lisp:stream-unread-char`; this is sufficient for streams whose `lisp:stream-read-char` method has no side-effects.

  This function is a &clisp; extension.

`(`lisp:stream-read-char-sequence` stream sequence &optional-amp; [start [end]])`

  Fills the subsequence of sequence specified by &start-k; and &end-k; with characters consecutively read from stream. Returns the index of the first element of sequence that was not updated (= end or < end if the stream reached its end).

  sequence is an array of characters, i.e. a string. start is a nonnegative integer and default to 0. end is a nonnegative integer or &nil; and defaults to &nil;, which stands for `(&length; sequence)`.

  The default method repeatedly calls `lisp:stream-read-char`; this is always sufficient if speed does not matter.

  This function is a &clisp; extension.

`(`lisp:stream-read-line` stream)`

  Reads a line of characters, and return two values: the line (a string, without the terminating #\Newline character), and a boolean value which is true if the line was terminated by &eos; instead of #\Newline.

  The default method repeatedly calls `lisp:stream-read-char`; this is always sufficient.

`(`lisp:stream-clear-input` stream)`

  Clears all pending interactive input from the stream, and returns true if some pending input was removed.

  The default method does nothing and returns &nil;; this is sufficient for non-interactive streams.

generic functions for character output

`(`lisp:stream-write-char` stream character)`

  Writes character.

  You must define a method for this function.

`(`lisp:stream-line-column` stream)`

  Returns the column number where the next character would be written (0 stands for the first column), or &nil; if that is not meaningful for this stream.

  You must define a method for this function.

`(`lisp:stream-start-line-p` stream)`

  Returns true if the next character would be written at the start of a new line.

  The default method calls `lisp:stream-line-column` and compares its result with 0; this is sufficient for streams whose `lisp:stream-line-column` never returns &nil;.

`(`lisp:stream-write-char-sequence` stream sequence &optional-amp; [start [end]])`

  Outputs the subsequence of sequence specified by &start-k; and &end-k; to stream.

  sequence is an array of characters, i.e. a string. start is a nonnegative integer and default to 0. end is a nonnegative integer or &nil; and defaults to &nil;, which stands for `(&length; sequence)`.

  The default method repeatedly calls `lisp:stream-write-char`; this is always sufficient if speed does not matter.

  This function is a &clisp; extension.

`(`lisp:stream-write-string` stream string &optional-amp; [start [end]])`

  Outputs the subsequence of string specified by &start-k; and &end-k; to stream. Returns string.

  string is a string. start is a nonnegative integer and default to 0. end is a nonnegative integer or &nil; and defaults to &nil;, which stands for `(&length; string)`.

  The default method calls `lisp:stream-write-char-sequence`; this is always sufficient.

`(`lisp:stream-terpri` stream)`

  Outputs a #\Newline character.

  The default method calls `lisp:stream-write-char`; this is always sufficient.

`(`lisp:stream-fresh-line` stream)`

  Possibly outputs a #\Newline character, so as to ensure that the next character would be written at the start of a new line. Returns true if it did output a #\Newline character.

  The default method calls `lisp:stream-start-line-p` and then `lisp:stream-terpri` if necessary; this is always sufficient.

`(`lisp:stream-finish-output` stream)`

  Ensures that any buffered output has reached its destination, and then returns.

  The default method does nothing.

`(`lisp:stream-force-output` stream)`

  Brings any buffered output on its way towards its destination, and returns without waiting until it has reached its destination.

  The default method does nothing.

`(`lisp:stream-clear-output` stream)`

  Attempts to discard any buffered output which has not yet reached its destination.

  The default method does nothing.

`(`lisp:stream-advance-to-column` stream column)`

  Ensures that the next character will be written at column at least.

  The default method outputs an appropriate amount of space characters; this is sufficient for non-proportional output.

generic functions for binary input

`(`lisp:stream-read-byte` stream)`

  Returns and consumes the next integer from the stream. Returns &eof-k; if the &eos; is reached.

  You must define a method for this function.

`(`stream-read-byte-lookahead` stream)`

  To be called only if stream's element-type is `(unsigned-byte 8)` or `(signed-byte 8)`. Returns &t; if `lisp:stream-read-byte` would return immediately with an integer result. Returns &eof-k; if the &eos; is already known to be reached. If `lisp:stream-read-byte`'s value is not available immediately, returns &nil; instead of waiting.

  You must define a method for this function.

`(`stream-read-byte-will-hang-p` stream)`

  To be called only if stream's element-type is `(unsigned-byte 8)` or `(signed-byte 8)`. Returns &nil; if `lisp:stream-read-byte` will return immediately. Otherwise it returns true.

  The default method calls `lisp:stream-read-byte-lookahead`; this is always sufficient.

`(`stream-read-byte-no-hang` stream)`

  To be called only if stream's element-type is `(unsigned-byte 8)` or `(signed-byte 8)`. Returns an integer or &eof-k;, like `lisp:stream-read-byte`, if that would return immediately. If `lisp:stream-read-byte`'s value is not available immediately, returns &nil; instead of waiting.

  The default method calls `lisp:stream-read-byte` if `lisp:stream-read-byte-lookahead` returns true; this is always sufficient.

`(`lisp:stream-read-byte-sequence` stream sequence &optional-amp; [start [end]])`

  Fills the subsequence of sequence specified by &start-k; and &end-k; with integers consecutively read from stream. Returns the index of the first element of sequence that was not updated (= end or < end if the stream reached its end).

  sequence is an array of integers. start is a nonnegative integer and default to 0. end is a nonnegative integer or &nil; and defaults to &nil;, which stands for `(&length; sequence)`.

  The default method repeatedly calls `lisp:stream-read-byte`; this is always sufficient if speed does not matter.

  This function is a &clisp; extension.

generic functions for binary output

`(`lisp:stream-write-byte` stream integer)`

  Writes integer.

  You must define a method for this function.

`(`lisp:stream-write-byte-sequence` stream sequence &optional-amp; [start [end]])`

  Outputs the subsequence of sequence specified by &start-k; and &end-k; to stream.

  sequence is an array of integers. start is a nonnegative integer and default to 0. end is a nonnegative integer or &nil; and defaults to &nil;, which stands for `(&length; sequence)`.

  The default method repeatedly calls `lisp:stream-write-byte`; this is always sufficient if speed does not matter.

  This function is a &clisp; extension.

#### Generic streams

This interface is &clisp; specific and now obsolete. Please use the Gray streams interface instead.

Generic streams are user programmable streams. The programmer interface:

`(`lisp:make-generic-stream` controller)`

  returns a generic stream.

`(`lisp:generic-stream-controller` stream)`

  returns a private object to which generic stream methods dispatch. The typical usage is to retrieve the object originally provided by the user in `lisp:make-generic-stream`.

`(`lisp:generic-stream-p` stream)`

  determines whether a stream is a generic stream, returning &t; if it is, &nil; otherwise.

In order to specify the behavior of a generic stream, the user must define &clos; methods on the following &clos; generic functions. The function `lisp:generic-stream-xyz` corresponds to the &cl; function `xyz`. They all take a controller and some number of arguments.

`(`lisp:generic-stream-read-char` controller)`

  Returns and consumes the next character, &nil; at end of file. Takes one argument, the controller object.

`(`lisp:generic-stream-peek-char` controller)`

  Returns the next character, &nil; at end of file. A second value indicates whether the side effects associated with consuming the character were executed: &t; means that a full &read-char; was done, &nil; means that no side effects were done. Takes one argument, the controller object.

`(`lisp:generic-stream-read-byte` controller)`

  Returns and consumes the next integer, &nil; at end of file. Takes one argument, the controller object.

`(`lisp:generic-stream-read-char-will-hang-p` controller)`

  This generic function is used to query the stream's input status. It returns &nil; if `lisp:generic-stream-read-char` and `lisp:generic-stream-peek-char` will certainly return immediately. Otherwise it returns true.

`(`lisp:generic-stream-write-char` controller ch)`

  The first argument is the controller object. The second argument is the character to be written.

`(`lisp:generic-stream-write-byte` controller by)`

  The first argument is the controller object. The second argument is the integer to be written.

`(`lisp:generic-stream-write-string` controller string start len)`

  Writes the subsequence of string starting from start of length len. The first argument is the controller object.

`(`lisp:generic-stream-clear-input` controller)` `(`lisp:generic-stream-clear-output` controller)` `(`lisp:generic-stream-finish-output` controller)` `(`lisp:generic-stream-force-output` controller)` `(`lisp:generic-stream-close` controller)`

  Take one argument, the controller object.

### Extensions-1.6. Weak Pointers

A weak pointer is an object holding a reference to a given object, without keeping the latter from being &gc;ed.

`(`lisp:make-weak-pointer` value)`

  returns a fresh weak pointer referring to value.

`(`lisp:weak-pointer-p` object)`

  returns true if the object is of type weak-pointer.

`(`lisp:weak-pointer-value` weak-pointer)`

  returns two values: The original value and &t;, if the value has not yet been &gc;ed, else &nil; and &nil;.

### Extensions-1.7. Finalization

Calling `(&finalize; object function)` has the effect that when the specified object is being &gc;ed, `(&funcall; function object)` will be executed.

Calling `(&finalize; object function guardian)` has a similar effect, but only as long as the "guardian" has not been &gc;ed: When object is being &gc;ed, `(&funcall; function object guardian)` will be executed. If the guardian is &gc;ed before object is, nothing happens.

Note: The time when the object is being &gc;ed is not defined deterministically. (Actually, it might possibly never occur.) It denotes a moment at which no references to object exist from other Lisp objects. When the function is called, object (and possibly guardian) enter the "arena of live Lisp objects" again.

No finalization request will be executed more than once.

### Extensions-1.8. The Prompt

The variable `sys::*prompt*` controls the appearance of the prompt. When its value is a function, it is called and its value is printed with &princ;. Otherwise, the value itself is printed with &princ;. The default value of `sys::*prompt*` prints "package[nn]> " where package is the shortest (nick)name of the current package &package-var; if it is the same as it was in the beginning or if it does not contain symbol &t; (it is assumed that in the latter case you would want to keep in mind that your current package is something weird); and nn is the ordinal number of the current prompt (hopefully, it will remain finite). To help you in constructing your own fancy prompts, two functions are provided: `sys::prompt-new-package`, returning &package-var; or &nil; if the current package is the same as it was initially; and `sys::package-short-name` taking one argument, a package, and returning its shortest name or nickname. Also, a variable `sys::*command-index*` contains the current prompt number, it is your responsibility to increment it (this variable is bound to 0 before saving the image).

### Extensions-1.9. Maximum ANSI CL compliance

A few &ansi-cl; features are turned off by default, because they would hurt in every-day use. They can be switched on, all at once by setting the &symbol-macro; &ansi; to &t;, or they can be switched on individually. Setting &ansi; to &t; implies the following:

- Setting &pathprint; to &t; for &ansi-cl; compliant &pathname-class; printing.

- Setting `lisp:*coerce-fixnum-char-ansi*` to &t; so that &fixnum-type;s cannot be &coerce;d to &character-class;s (because a &fixnum-type; is not a character designator in &ansi-cl;.)

- Setting &count-ansi; to &t; so that negative &count-k; keyword parameter is equivalent to 0 as per the RANGE-OF-COUNT-KEYWORD:NIL-OR-INTEGER &ansi-cl; Issue 283.

- Setting &pathmerge; to &t;.

- Setting &parsename; to &t;.

- Setting &flocont; to &t;.

- Adding `:ansi-cl` to &features-var;.

Please note that if you run &clisp; with the `-a` switch or set the &symbol-macro; &ansi; to &t; and save image, then all subsequent invocations of &clisp; with this image will be as if with `-a` (regardless whether you actually supply the `-a` switch). You can always set the &symbol-macro; &ansi; to &nil;, reversing the above settings, i.e.,

- Setting &pathprint; to &nil; for readable &pathname-class; printing.

- Setting `lisp:*coerce-fixnum-char-ansi*` to &nil; so that &fixnum-type;s can be &coerce;d to &character-class;s (via &code-char;).

- Setting &count-ansi; to &nil; to signal an error on negative &count-k; keyword parameter, contrary to the RANGE-OF-COUNT-KEYWORD:NIL-OR-INTEGER &ansi-cl; Issue 283.

- Setting &pathmerge; to &nil;.

- Setting &parsename; to &nil;.

- Setting &flocont; to &nil;.

- Deleting `:ansi-cl` from &features-var;.

### Extensions-1.10. Additional Fancy Macros

If you uncomment the `(&load; "macros3")` line in the file `init.lsp` before doing `make`, or load the file `macros3.lsp`into a running &clisp;, you gain access to the following macros:

`lisp:ethe`

`(`lisp:ethe` value-type form)` enforces a type check in both interpreted and compiled code.

`lisp:letf` & `lisp:letf*`

These macros are similar to &let; and &let-star;, respectively, except that they can bind places, even places with multiple values. Example:

     (letf (((values a b) form)) ...)

is equivalent to

     (multiple-value-bind (a b) form ...)

while

    (letf (((first l) 7)) ...)

is approximately equivalent to

     (&let-star; ((#:g1 l) (#:g2 (first #:g1)))
       (&unwind-protect; (&progn; (&setf; (first #:g1) 7) ...)
          (&setf; (first #:g1) #:g2)))

`lisp:with-collect`

Similar to the &loop;'s `collect` instruction, except that it is more "Lispy" in appearance and can appear arbitrarily deep. It defines local macros (with ¯olet;) which collect objects given to it in lists, which are then returned as multiple values. E.g.,

     (lisp:with-collect (c0 c1)
       (dotimes (i 10) (if (oddp i) (c0 i) (c1 i))))

returns two lists `(1 3 5 7 9)` and `(0 2 4 6 8)` as multiple values.

You might want to add a `(&load; "macros3")` statement to your `.clisprc` file if you do not want to dump your own image.

## Extensions-2: Platform specific Extensions

### Extensions-2.1. Random Screen Access

Platform dependent: &unix;, &amiga;, &dos;, &os2; platforms only.

`(`screen:make-window`)`

  returns a "window stream". As long as this stream is open, the terminal is in cbreak/noecho mode. &terminal-io-var; should not be used for input or output during this time. (Use &with-kbd; and &kbd-in; instead.)

`(`screen:with-window` . body)`

  binds `screen:*window*` to a window stream and executes body. The stream is guaranteed to be closed when the body is left. During its execution, &terminal-io-var; should not be used, as above.

`(`screen:window-size` window-stream)`

  returns the window's size, as two values: height (= ymax+1) and width (= xmax+1).

`(`screen:window-cursor-position` window-stream)`

  returns the position of the cursor in the window, as two values: line (≥0, ≤ymax, 0 means top), column (≥0, ≤xmax, 0 means left margin).

`(`screen:set-window-cursor-position` window-stream line column)`

  sets the position of the cursor in the window.

`(`screen:clear-window` window-stream)`

  clears the window's contents and puts the cursor in the upper left corner.

`(`screen:clear-window-to-eot` window-stream)`

  clears the window's contents from the cursor position to the end of window.

`(`screen:clear-window-to-eol` window-stream)`

  clears the window's contents from the cursor position to the end of line.

`(`screen:delete-window-line` window-stream)`

  removes the cursor's line, moves the lines below it up by one line and clears the window's last line.

`(`screen:insert-window-line` window-stream)`

  inserts a line at the cursor's line, moving the lines below it down by one line.

`(`screen:highlight-on` window-stream)`

  switches highlighted output on.

`(`screen:highlight-off` window-stream)`

  switches highlighted output off.

`(`screen:window-cursor-on` window-stream)`

  makes the cursor visible, a cursor block in most implementations.

`(`screen:window-cursor-off` window-stream)`

  makes the cursor invisible, in implementations where this is possible.

### Extensions-2.2. External Modules

Platform dependent: &unix; platforms only.

&clisp; has a facility for adding external modules (written in &c-lang;, for example). It is invoked through `clisp-link`.

A module is a piece of external code which defines extra Lisp objects, symbols and functions. A module name must consist of the characters `A`-`Z`, `a`-`z`, `_`, `0`-`9`. The module name clisp is reserved. Normally a module name is derived from the corresponding file name.

`clisp-link` needs a directory containing:

- `modules.d`

- `modules.c`

- `clisp.h`

`clisp-link` expects to find these files in a subdirectory `linkkit/` of the current directory. This can be overridden by the environment variable `CLISP_LINKKIT`.

`clisp-link` operates on &clisp; linking sets and on module sets.

A linking set is a directory containing:

`makevars`

  some `/bin/sh` commands, setting the variables

  `CC`

    the &c-lang; compiler

  `CFLAGS`

    flags for the &c-lang; compiler, when compiling

  `CLFLAGS`

    flags for the &c-lang; compiler, when linking

  `LIBS`

    libraries to use when linking

  `X_LIBS`

    additional X window system libraries to use

  `RANLIB`

    the ranlib command

  `FILES`

    the list of files needed when linking

`modules.h`

  the list of modules contained in this linking set

`modules.o`

  the compiled list of modules contained in this linking set

all the `FILES`

  listed in `makevars`

`lisp.run`

  the executable

`lispinit.mem`

  the memory image

To run a &clisp; contained in some linking set `dir`, call `dir/lisp.run -M dir/lispinit.mem`

A module set is a directory containing:

`link.sh`

  some `/bin/sh` commands, which prepare the directory before linking, and set the variables `NEW_FILES`, `NEW_LIBS`, `NEW_MODULES`, `TO_LOAD` and optionally `TO_PRELOAD`

and any other files

  needed by `link.sh`

Note that in `link.sh` the module set directory is referred to as `$modulename/`.

`NEW_FILES`

  the space-separated list of files that belong to the module set and will belong to every new linking set.

`NEW_LIBS`

  the space-separated list of files or &c-lang; compiler switches that need to be passed to the &c-lang; compiler when linking the lisp.run belonging to a new linking set.

`NEW_MODULES`

  the space-separated list of the module names belonging to the module set. Normally, every `.c` file in the module set defines a module of its own. The module name is derived from the file name.

`TO_LOAD`

  the space-separated list of Lisp files to load before building the `lispinit.mem` belonging to a new linking set.

`TO_PRELOAD` (optional)

  the space-separated list of Lisp files to load into an intermediate `lispinit.mem` file, before building the `lispinit.mem` belonging to a new linking set. This variable is usually used for defining Lisp packages which must be present when the new `.c` files are initialized.

The command `clisp-link create-module-set module-dir file1.c ...` creates a module set in module-dir which refers (via symbolic links) to file1.c etc. The files are expected to be modules of their own.

The command `clisp-link add-module-set module-dir source-dir destination-dir` combines a linking set in source-dir and a module in module-dir to a new linking set, in a directory destination-dir which is newly created.

The command `clisp-link run source-dir module-dir ...` runs the linking set in source-dir, with the module in module-dir loaded. More than one module can be specified. If &clisp; has been built with the configuration option `--with-dynamic-modules`, the loading will be performed through dynamic loading. Otherwise - this is much slower - a temporary linking set will be created and deleted afterwards. Note that dynamic loading does not work on all operating systems, and that `--with-dynamic-modules` precludes some efficiency optimizations which are on by default.

#### Example

To link in the FFI bindings for the Linux operating system, the following steps are needed. (Step 1 and step 2 need not be executed in this order.)

1. Create a new module set:

       $ clisp-link create-module-set linux /somewhere/bindings/linux.c

   Modify the newly created `linux/link.sh` to add `-lm`; to the libraries: replace

       NEW_LIBS="$file_list"

   with

       NEW_LIBS="$file_list -lm"

   Modify the newly created `linux/link.sh` to load `linux.fas` before saving the memory image: replace

       TO_LOAD=''

   with

       TO_LOAD='/somewhere/bindings/linux.fas'

2. Compile `linux.lsp`, creating `linux.c`:

       $ clisp -c /somewhere/bindings/linux.lsp

3. Create a new linking set:

       $ clisp-link add-module-set linux base base+linux

4. Run and try it:

       $ base+linux/lisp.run -M base+linux/lispinit.mem > (linux::stat "/tmp")

#### Modules included in the distribution.

The following modules come with the distribution of &clisp;:

bindings

  Call the operating system functions from &clisp;. The following platforms are supported:

  - AmigaOS

  - Linux/libc5

  - Linux/libc6

CLX

  Call Xlib functions from &clisp;. Two implementations are supplied:

  - mit-clx, from MIT ftp://ftp.x.org/R5contrib/CLX.R5.02.tar.Z

  - new-clx, by Gilbert Baumann unk6@rz.uni-karlsruhe.de.

postgresql632, postgresql642

  Access PostgreSQL from &clisp;.

queens

  Compute the number of solutions to the n-queens problem on a n*n checkboard.

regexp

  The POSIX Regular Expressions matching, compiling, executing.

  The following code computes the number of people who use a particular shell:

      (use-package :regexp)
      (sexp ((h (make-hash-table :test #'equal :size 10)) (n 0))
        (with-open-file (f "/etc/passwd")
          (with-loop-split (s f ":")
            (let ((sh (seventh s)))
              (if (gethash sh h)
                  (incf (gethash sh h))
                  (setf (gethash sh h) 1)))))
        (with-hash-table-iterator (i h)
          (loop (multiple-value-bind (r k v) (i)
                  (unless r (return))
                  (format t "[~d] ~s~30t== ~5:d~%" (incf n) k v)))))

  The same is done by the following Perl:

      #!/usr/local/bin/perl -w

      use diagnostics;
      use strict;

      my $IN = $ARGV[0];
      open(INF,"< $IN") || die "$0: cannot read file [$IN]: $!\n;";
      my %hash;
      while (<INF>) {
        chop;
        my @all = split($ARGV[1]);
        my $shell = ($#all >= 6 ? $all[6] : "");
        if ($hash{$shell}) { $hash{$shell} ++; }
        else { $hash{$shell} = 1; }
      }
      my $ii = 0;
      for my $kk (keys(%hash)) {
        print "[",++$ii,"] \"",$kk,"\"  --  ",$hash{$kk},"\n";
      }

wildcard

  Shell globbing

### Extensions-2.3. The Foreign Function Call Facility

Platform dependent: many &unix;, &win32; platforms only.

A foreign function description is written as a Lisp file, and when compiled it produces a `.c` file which is then compiled by the &c-lang; compiler and may be linked together with `lisp.a`.

All symbols relating to the foreign function interface are exported from the package FFI. To use them, `(&use-package; "FFI")`.

Special FFI forms may appear anywhere in the Lisp file.

#### Overview

These are the special FFI forms. We have taken a pragmatic approach: the only foreign languages we support for now are &c-lang; and ANSI &c-lang;.

special FFI forms; name is any Lisp symbol; c-name is a string.

`(`def-c-type` name c-type)`

  This form makes name a shortcut for c-type. Note that c-type may already refer to name. Forward declarations of types are not possible, however.

`(`def-c-var` name {option}*)`
  option ::==
  - `(:name c-name)`
  - |`(:type c-type)`
  - |`(:read-only boolean)`
  - |`(:alloc &allocation;)`

  This form defines a foreign variable. name is the Lisp name, a regular Lisp symbol.

  The `:name` option specifies the name, as seen from &c-lang;, as a string. If not specified, it is derived from the print name of the Lisp name.

  The `:type` option specifies the variable's foreign type.

  If the `:read-only` option is specified and non-&nil;, it will be impossible to change the variable's value from within Lisp (using &setq; or similar).

  The `:alloc` option can be either &none-k; or &malloc-free-k; and defaults to &none-k;. If it is &malloc-free-k;, any values of type &c-string;, &c-ptr;, &c-ptr-null;, &c-array-ptr; within the foreign value are assumed to be pointers to `malloc()`-allocated storage, and when &setq; replaces an old value by a new one, the old storage is freed using `free()` and the new storage allocated using `malloc()`. If it is &none-k;, &setq; assumes that the pointers point to good storage (not `NULL`!) and overwrites the old values by the new ones. This is dangerous (just think of overwriting a string with a longer one or storing some data in a `NULL` pointer...) and deprecated.

`(`def-call-out` name {option}*)`
  option ::==
  - `(:name c-name)`
  - `(:arguments {(arg-name c-type [¶m-mode; [&allocation;]])}*)` |
  - |`(:return-type c-type [&allocation;])`
  - |`(:language language)`

  This form defines a named call-out function (a foreign function called from Lisp: control flow temporarily leaves Lisp). Any Lisp function call to `#'name` is redirected to call the &c-lang; function c-name. The language is either `:C` (denotes K&R &c-lang;) or `:STDC` (denotes ANSI &c-lang;) or `:stdc-stdcall` (denotes ANSI &c-lang; with stdcall calling convention). It specifies whether the &c-lang; function has been compiled by a K&R &c-lang; compiler or by an ANSI &c-lang; compiler, and possibly the calling convention.

`(`def-call-in` name {option}*)`
  option ::==
  - `(:name c-name)` |
  - `(:arguments {(arg-name c-type [¶m-mode; [&allocation;]])}*)`
  - |`(:return-type c-type [&allocation;])`
  - |`(:language language)`

  This form defines a named call-in function (i.e., a Lisp function called from the foreign language: control flow temporary enters Lisp). Any &c-lang; function call to the &c-lang; function c-name is redirected to call the Lisp function `#'name`. The language is either `:c` (denotes K&R &c-lang;) or `:stdc` (denotes ANSI &c-lang;) or `:stdc-stdcall` (denotes ANSI &c-lang; with stdcall calling convention). It specifies whether the calling code has been compiled by a K&R &c-lang; compiler or by an ANSI &c-lang; compiler, and possibly the calling convention.

`(`def-c-call-out` name {option}*)`

  This is equivalent to &def-call-out; with `:language` `:stdc`.

`(`def-c-call-in` name {option}*)`

  This is equivalent to &def-call-in; with `:language` `:stdc`.

`(`def-c-struct` name (ident c-type)*)`

  This form defines name to be both a defstruct structure type and a foreign &c-lang; type with the given slots.

`(`def-c-enum` name {ident | (ident [value])}*)`

  This form defines idents as constants, similarly to the &c-lang; declaration enum { ident [= value], ... };

`(`c-lines` format-string {argument}*)`

  This form outputs the string `(&format; &nil; format-string {argument}*)` to the &c-lang; output file. This is a rarely needed low-level facility.

`(`element` c-place index1 ... indexn)`

  Array element: If c-place is of foreign type `(c-array c-type dim1 ... dimn)` and 0 ≤ index1 < dim1, ..., 0 ≤ indexn < dimn, this will be the place corresponding to `(&aref; c-place index1 ... indexn)` or `c-place[index1]...[indexn]`. It is a place of type c-type. If c-place is of foreign type `(c-array-max c-type dim)` and 0 ≤ index < dim, this will be the place corresponding to `(&aref; c-place index)` or `c-place[index]`. It is a place of type c-type.

`(`deref` c-place)`

  Dereference pointer: If c-place is of foreign type `(&c-ptr; c-type)` or `(&c-ptr-null; c-type)`, this will be the place the pointer points to. It is a place of type c-type. For `(&c-ptr-null; c-type)`, the c-place may not be `NULL`.

`(`slot` c-place slot-name)`

  Struct or union component: If c-place is of foreign type `(&c-struct; class ... (slot-name c-type) ...)` or of type `(&c-union; ... (slot-name c-type) ...)`, this will be of type c-type.

`(`cast` c-place c-type)`

  Type change: A place denoting the same memory locations as the original c-place, but of type c-type.

`(`typeof` c-place)`

  returns the c-type corresponding to the c-place.

`(`sizeof` c-type)`, `(`sizeof` c-place)`

  The first form returns the size and alignment of a &c-lang; type c-type, measured in bytes.

  The second form returns the size and alignment of the &c-lang; type of c-place, measured in bytes.

`(`bitsizeof` c-type)`, `(`bitsizeof` c-place)`

  The first form returns the size and alignment of the &c-lang; type c-type, measured in bits.

  The second form returns the size and alignment of the &c-lang; type of c-place, measured in bits.

`(`validp` foreign-entity)`

  This predicate returns &nil; if the foreign-entity (e.g. the Lisp equivalent of a `c-pointer`) refers to a pointer which is invalid because it comes from a previous Lisp session. It returns &t; if foreign-entity can be used within the current Lisp process.

#### (Foreign) &c-lang; types

Foreign &c-lang; types are used in the FFI. They are not regular &cl; types or &clos; classes.

A c-type is either a predefined &c-lang; type or the name of a type defined by &def-c-type;.

the predefined &c-lang; types (c-type)

simple-c-type

  the simple &c-lang; types

  Lisp name Lisp equivalent &c-lang; equivalent ILU equivalent Comment
  - &nil;&nil; void as a result type only
  - &boolean-type;&boolean-type; int BOOLEAN
  - &character-class;&character-class; char SHORT CHARACTER
  - char&integer-class; signed char
  - uchar&integer-class; unsigned char
  - short&integer-class; short
  - ushort&integer-class; unsigned short
  - int&integer-class; int
  - uint&integer-class; unsigned int
  - long&integer-class; long
  - ulong&integer-class; unsigned long
  - uint8 `(&unsigned-byte-type; 8)` uint8 BYTE
  - sint8 `(&signed-byte-type; 8)` sint8
  - uint16 `(&unsigned-byte-type; 16)` uint16 SHORT CARDINAL
  - sint16 `(&signed-byte-type; 16)` sint16 SHORT INTEGER
  - uint32 `(&unsigned-byte-type; 32)` uint32 CARDINAL
  - sint32 `(&signed-byte-type; 32)` sint32 INTEGER
  - uint64 `(&unsigned-byte-type; 64)` uint64 LONG CARDINAL does not work on all platforms
  - sint64 `(&signed-byte-type; 64)` sint64 LONG INTEGER does not work on all platforms
  - &single-float-type;&single-float-type; float
  - &double-float-type;&double-float-type; double
c-pointer

  This type corresponds to what &c-lang; calls void*, an opaque pointer.

c-string

  This type corresponds to what &c-lang; calls char*, a zero-terminated string. Its Lisp equivalent is a string, without the trailing zero character.

`(c-struct class (ident1 c-type1) ... (identn c-typen))`

  This type is equivalent to what &c-lang; calls struct { c-type1 ident1; ...; c-typen identn; }. Its Lisp equivalent is: if class is &vector-class;, a &simple-vector-type;; if class is &list-class;, a list; if class is a symbol naming a structure or &clos; class, an instance of this class, with slots of names ident1, ... ,identn.

`(c-union (ident1 c-type1) ... (identn c-typen))`

  This type is equivalent to what &c-lang; calls union { c-type1 ident1; ...; c-typen identn; }. Conversion to and from Lisp assumes that a value is to be viewed as being of c-type1.

`(c-array c-type dim1 ... dimn)`

  This type is equivalent to what &c-lang; calls c-type [dim1] ... [dimn]. Note that when an array is passed as an argument to a function in &c-lang;, it is actually passed as a pointer; you therefore have to write `(&c-ptr; (&c-array; ...))` for this argument's type.

`(c-array-max c-type maxdimension)`

  This type is equivalent to what &c-lang; calls c-type [maxdimension], an array containing up to maxdimension elements. The array is zero-terminated if it contains less than maxdimension elements. Conversion from Lisp of an array with more than maxdimension elements silently ignores the superfluous elements.

`(c-function (`:arguments` {(arg-name a-c-type [¶m-mode; [&allocation;]])}*) (`:return-type` r-c-type [&allocation;]) (`:language` language))`

  This type designates a &c-lang; function that can be called according to the given prototype `(r-c-type (*) (a-c-type1, ...))`. The language is either `:c` (denotes K&R &c-lang;) or `:stdc` (denotes ANSI &c-lang;) or `:stdc-stdcall` (denotes ANSI &c-lang; with stdcall calling convention). It specifies whether the &c-lang; function has been compiled by a K&R &c-lang; compiler or by an ANSI &c-lang; compiler, and possibly the calling convention. Conversion between &c-lang; functions and Lisp functions is transparent.

`(c-ptr c-type)`

  This type is equivalent to what &c-lang; calls c-type *: a pointer to a single item of the given c-type.

`(c-ptr-null c-type)`

  This type is also equivalent to what &c-lang; calls c-type *: a pointer to a single item of the given c-type, with the exception that &c-lang; `NULL` corresponds to Lisp &nil;.

`(c-array-ptr c-type)`

  This type is equivalent to what &c-lang; calls c-type (*)[]: a pointer to a zero-terminated array of items of the given c-type.

#### Foreign variables

Foreign variables are variables whose storage is allocated in the foreign language module. They can nevertheless be evaluated and modified through &setq;, just as normal variables can, except that the range of allowed values is limited according to the variable's foreign type. Note that for a foreign variable x the form `(&eql; x x)` is not necessarily true, since every time x is evaluated its foreign value is converted to a freshly created Lisp value. Foreign variables are defined using &def-c-var;.

#### Operations on foreign places

A foreign variable name defined by &def-c-var; defines a "place", i.e., a form which can also be used as argument to &setf;. (An "lvalue" in &c-lang; terminology.) The following operations are available on foreign places: &element;, &deref;, &slot;, &cast;, &typeof;, &sizeof;, &bitsizeof;.

#### Foreign functions

Foreign functions are functions which are defined in the foreign language. There are named foreign functions (imported via &def-call-out; or created via &def-call-in;) and anonymous foreign functions; they arise through conversion of function pointers.

A "call-out" function is a foreign function called from Lisp: control flow temporarily leaves Lisp. A "call-in" function is a Lisp function called from the foreign language: control flow temporary enters Lisp.

The following forms define foreign functions: &def-call-in;, &def-call-out;, &def-c-call-in;, &def-c-call-out;.

#### Argument and result passing conventions

When passed to and from functions, allocation of arguments and results is handled as follows:

Values of &simple-c-type;, &c-pointer; are passed on the stack, with dynamic extent. The &allocation; is effectively ignored.

Values of type &c-string;, &c-ptr;, &c-ptr-null;, &c-array-ptr; need storage. The &allocation; specifies the allocation policy:

&allocation; meaning
- &none-k; no storage is allocated.
- &alloca-k; allocation of storage on the stack, which has dynamic extent.
- &malloc-free-k; storage will be allocated via `malloc()` and freed via `free()`.

If no &allocation; is specified, the default &allocation; is &none-k; for most types, but &alloca-k; for &c-string; and &c-ptr; and &c-ptr-null; and &c-array-ptr; and for &out-k; arguments. [Subject to change!] The &malloc-free-k; policy provides the ability to pass arbitrarily nested structs containing pointers pointing to structs ... within a single conversion.

For call-out functions:
  For arguments passed from Lisp to &c-lang;:
    If &allocation; is &malloc-free-k;:

      Lisp allocates the storage using malloc() and never deallocates it. The &c-lang; function is supposed to call free() when done with it.

    If &allocation; is &alloca-k;:

      Lisp allocates the storage on the stack, with dynamic extent. It is freed when the &c-lang; function returns.

    If &allocation; is &none-k;:

      Lisp assumes that the pointer already points to a valid area of the proper size and puts the result value there. This is dangerous! and deprecated.

  For results passed from &c-lang; to Lisp:
    If &allocation; is &malloc-free-k;:

      Lisp calls free() on it when done.

    If &allocation; is &none-k;:

      Lisp does nothing.

For call-in functions:
  For arguments passed from &c-lang; to Lisp:
    If &allocation; is &malloc-free-k;:

      Lisp calls free() on it when done.

    If &allocation; is &alloca-k; or &none-k;:

      Lisp does nothing.

  For results passed from Lisp to &c-lang;:
    If &allocation; is &malloc-free-k;:

      Lisp allocates the storage using malloc() and never deallocates it. The &c-lang; function is supposed to call free() when done with it.

    If &allocation; is &none-k;:

      Lisp assumes that the pointer already points to a valid area of the proper size and puts the result value there. This is dangerous! and deprecated.

A function parameter's ¶m-mode; may be

&in-k; (means: read-only):

  The caller passes information to the callee.

&out-k; (means: write-only):

  The callee passes information back to the caller on return. When viewed as a Lisp function, there is no Lisp argument corresponding to this, instead it means an additional return value.

`:in-out` (means: read-write):

  Information is passed from the caller to the callee and then back to the caller. When viewed as a Lisp function, the &out-k; value is returned as an additional multiple value.

The default is &in-k;.

[Currently, only &in-k; is fully implemented. &out-k; works only with &allocation; = &alloca-k;.]

Platform dependent: &amiga; platforms only.

  &allocation; may not be &malloc-free-k; because there is no commonly used `malloc()/free()` library function.

  The &allocation; may be followed by a register specification, any of the symbols `:d0`, `:d1`, `:d2`, `:d3`, `:d4`, `:d5`, `:d6`, `:d7`, `:a0`, `:a1`, `:a2`, `:a3`, `:a4`, `:a5`, `:a6`, each representing one 680x0 register. This works only for integral types: integers, pointers, &c-string;, &c-function;.

Passing &c-struct;, &c-union;, &c-array;, &c-array-max; values as arguments (not via pointers) is only possible to the extent the &c-lang; compiler supports it. Most &c-lang; compilers do it right, but some &c-lang; compilers (such as gcc on hppa) have problems with this.

Platform dependent: only in &clisp; built &with; compile-time flag &unicode;.

  A &symbol-macro; place `lisp:*foreign-encoding*` contains the encoding for characters and strings passed through the FFI. Its value must be a 1:1 encoding, i.e., an encoding in which every character is represented by one byte.

#### Examples

Simple declarations and access

The &c-lang; declaration

    struct foo {
        int a;
        struct foo * b[100];
    };

corresponds to

    (def-c-struct foo
      (a int)
      (b (c-array (c-ptr foo) 100)))

The element access

    struct foo f;
    f.b[7].a

corresponds to

    (declare (type foo f))
    (foo-a (aref (foo-b f) 7)) or (slot-value (aref (slot-value f 'b) 7) 'a)

external &c-lang; variable and some accesses

    struct bar {
        short x, y;
        char a, b;
        int z;
        struct bar * n;
    };

    extern struct bar * my_struct;

    my_struct->x++;
    my_struct->a = 5;
    my_struct = my_struct->n;

corresponds to

    (def-c-struct bar
      (x short)
      (y short)
      (a char)
      (b char) ; or (b character) if it represents a character, not a number
      (z int)
      (n (c-ptr bar)))

    (def-c-var my_struct (:type (c-ptr bar)))

    (setq my_struct (let ((s my_struct)) (incf (slot-value s 'x)) s))
    or (incf (slot my_struct 'x))
    (setq my_struct (let ((s my_struct)) (setf (slot-value s 'a) 5) s))
    or (setf (slot my_struct 'a) 5)
    (setq my_struct (slot-value my_struct 'n))
    or (setq my_struct (deref (slot my_struct 'n)))

Calling an external function

On ANSI &c-lang; systems, `stdlib.h` contains the declarations:

    typedef struct {
      int quot;   /* Quotient */
      int rem;    /* Remainder */
    } div_t;
    extern div_t div (int numer, int denom);

This translates to

    (def-c-struct div_t
      (quot int)
      (rem int))
    (def-c-call-out div (:arguments (numer int) (denom int))
                        (:return-type div_t))

Sample call from within Lisp:

    > (div 20 3)
    #S(DIV :QUOT 6 :REM 2)

Another example for calling an external function

Suppose the following is defined in a file `cfun.c`:

    struct cfunr { int x; char *s; };
    struct cfunr * cfun (i,s,r,a)
        int i;
        char *s;
        struct cfunr * r;
        int a[10];
    {
        int j;
        struct cfunr * r2;
        printf("i = %d\n", i);
        printf("s = %s\n", s);
        printf("r->x = %d\n", r->x);
        printf("r->s = %s\n", r->s);
        for (j = 0; j < 10; j++) printf("a[%d] = %d.\n", j, a[j]);
        r2 = (struct cfunr *) malloc (sizeof (struct cfunr));
        r2->x = i+5;
        r2->s = "A C string";
        return r2;
    }

It is possible to call this function from Lisp using the file `callcfun.lsp` (do not call it `cfun.lsp` - &compile-file; would overwrite `cfun.c`) whose contents is:

    (in-package "TEST-C-CALL" :use '("LISP" "FFI"))
    (def-c-struct cfunr (x int) (s c-string))
    (def-c-call-out cfun (:arguments (i int)
                                     (s c-string)
                                     (r (c-ptr cfunr) :in :alloca)
                                     (a (c-ptr (c-array int 10)) :in :alloca))
                         (:return-type (c-ptr cfunr)))
    (defun call-cfun ()
      (cfun 5 "A Lisp string" (make-cfunr :x 10 :s "Another Lisp string")
            '#(0 1 2 3 4 5 6 7 8 9)))

Use the module facility:

    $ clisp-link create-module-set cfun callcfun.c
    $ cc -O -c cfun.c
    $ cd cfun
    $ ln -s ../cfun.o cfun.o
    Add cfun.o to NEW_LIBS and NEW_FILES in link.sh.
    $ cd ..
    $ base/lisp.run -M base/lispinit.mem -c callcfun.lsp
    $ clisp-link add-module-set cfun base base+cfun
    $ base+cfun/lisp.run -M base+cfun/lispinit.mem -i callcfun
    > (test-c-call::call-cfun)
    i = 5
    s = A Lisp string
    r->x = 10
    r->s = Another Lisp string
    a[0] = 0.
    a[1] = 1.
    a[2] = 2.
    a[3] = 3.
    a[4] = 4.
    a[5] = 5.
    a[6] = 6.
    a[7] = 7.
    a[8] = 8.
    a[9] = 9.
    #S(TEST-C-CALL::CFUNR :X 10 :S "A C string")
    >
    $ rm -r base+cfun

Note that there is a memory leak here: The return value `r2` of `cfun()` is `malloc()`ed but never `free()`d. Specifying

    (:return-type (c-ptr cfunr) :malloc-free)

is not an alternative because this would also `free(r2->x)` but `r2->x` is a pointer to static data.

call-in

To sort an array of double-floats using the Lisp function `sort` instead of the &c-lang; library function `qsort()`, one can use the following interface code `sort1.c`. The main problem is to pass a variable-sized array.

    extern void lispsort_begin (int);
    void* lispsort_function;
    void lispsort_double (int n, double * array)
    {
        double * sorted_array;
        int i;
        lispsort_begin(n); /* store #'sort2 in lispsort_function */
        sorted_array = ((double * (*) (double *)) lispsort_function) (array);
        for (i = 0; i < n; i++) array[i] = sorted_array[i];
        free(sorted_array);
    }

This is accompanied by `sort2.lsp`:

    (use-package "FFI")
    (def-call-in lispsort_begin (:arguments (n int))
                                (:return-type nil)
                                (:language :stdc))
    (def-c-var lispsort_function (:type c-pointer))
    (defun lispsort_begin (n)
      (setf (cast lispsort_function
                  `(c-function
                     (:arguments (v (c-ptr (c-array double-float ,n))))
                     (:return-type (c-ptr (c-array double-float ,n))
                                   :malloc-free)))
            #'sort2))
    (defun sort2 (v)
      (declare (type vector v))
      (sort v #'<))

To test this, use the following test file `sorttest.lsp`:

    (def-call-out sort10
                  (:name "lispsort_double")
                  (:language :stdc)
                  (:arguments (n int)
                              (array (c-ptr (c-array double-float 10))
                                     :in-out)))

Now try

    $ clisp-link create-module-set sort sort2.c sorttest.c
    $ cc -O -c sort1.c
    $ cd sort
    $ ln -s ../sort1.o sort1.o
    Add sort1.o to NEW_LIBS and NEW_FILES in link.sh.
    $ cd ..
    $ base/lisp.run -M base/lispinit.mem -c sort2.lsp sorttest.lsp
    $ clisp-link add-module-set sort base base+sort
    $ base+sort/lisp.run -M base+sort/lispinit.mem -i sort2 sorttest
    > (sort10 10 '#(0.501d0 0.528d0 0.615d0 0.550d0 0.711d0
                    0.523d0 0.585d0 0.670d0 0.271d0 0.063d0))
    #(0.063d0 0.271d0 0.501d0 0.523d0 0.528d0 0.55d0 0.585d0 0.615d0 0.67d0 0.711d0)
    $ rm -r base+sort

### Extensions-2.4. The Amiga Foreign Function Call Facility

Platform dependent: &amiga; platforms only.

Another Foreign Function Interface

All symbols relating to the simple foreign function interface are exported from the package AFFI. To use them, `(&use-package; "AFFI")`.

#### Design issues

AFFI was designed to be small in size but powerful enough to use most library functions. Lisp files may be compiled to `.fas` files without the need to load function definition files at run-time and without external &c-lang; or linker support. Memory images can be created, provided that the function libraries are opened at run-time.

Therefore, AFFI supports only primitive &c-lang; types (integers 8, 16 and 32 bits wide, signed or unsigned, pointers) and defines no new types or classes. Foreign functions are not first-class objects (you can define a lambda yourself), name spaces are separate.

The AFFI does no tracking of resources. Use &finalize;.

#### Overview

These are the AFFI forms:

`(declare-library-base keyword-base library-name)`

`(require-library-functions library-name [(:import {string-name}*)])`

`(open-library base-symbol)`

`(clos-library base-symbol)`

`(with-open-library (base-symbol | library-name) {form}*)`

`(defflibfun function-name base-symbol offset mask result-type {argument-type}*)`

`(declare-library-function function-name library-name {option}*)`

`(flibcall function-name {argument}*)`

`(mlibcall function-name {argument}*)`

`(mem-read address result-type [offset])`

`(mem-write address type value [offset])`

`(mem-write-vector address vector [offset])`

`(nzero-pointer-p value)`

Except for `with-open-library`, `declare-library-function` and `mlibcall`, all of the above are functions.

A library contains a collection of functions. The library is referred to by a symbol referred as library-base at the AFFI level. This symbol is created in the package AFFI. The link between this symbol and the OS-level library name is established by `declare-library-base`. To avoid multiple package conflicts, this and only this function requires the symbol-name to be in the &kwd-pac; package. The function returns the library-base.

A library may be opened by `open-library` and closed by `close-library`. An opened library must be closed. `with-open-library` is provided to automatically close the library for you, thus it is much safer to use.

A function is contained in a library. Every function is referred to by a symbol. A function is defined through `defflibfun` or `declare-library-function` by giving the function name, the library-base, an offset into the library, a mask (or &nil;) for register-based library calls, the result type and all parameter-types. `require-library-functions` loads the complete set of functions defined in a library file. Symbols are created in the package AFFI and imported into the current package.

`flibcall` and `mlibcall` call library functions. `mlibcall` is a macro that does a few checks at macroexpansion time and allows the compiler to inline the call, not requiring the foreign function to be defined again at load or execution time. The use of this macro is advertised wherever possible.

`mem-read` reads an arbitrary address (with offset for structure references) and returns the given type.

`mem-write` writes an arbitrary address. `mem-write-vector` copies the content of a Lisp &string-class; or &unsigned-byte-type; &vector-class; into memory.

`nzero-pointer-p` tests for non-`NULL` pointers in all recognized representations (&null-class;, &unsigned-byte-type; and `foreign-pointer`).

#### Foreign Libraries

`declare-library-base` ought to be wrapped in an `(&eval-when; (compile eval load) ...)` form and come before any function is referenced, because the library base symbol must be known.

`open-library` tries to open the library referenced by the base symbol. Therefore it must have been preceded with `declare-library-base`. The call returns &nil; on failure. `open-library` calls nest. Every successful call must be matched by `close-library`. `with-open-library` does this for you and also allows you to specify the library by name, provided that its base has been declared. It is recommended to use this macro and to reference the library by name.

&clisp; will not close libraries for you at program exit. [A previous version did so but now AFFI is a module and there are no module exit functions.] Programmers, watch `affi::*libraries-alist*`.

#### (Foreign) &c-lang; types

The following foreign &c-lang; types are used in AFFI. They are not regular &cl; types or &clos; classes.

foreign &c-lang; types used in AFFI

AFFI name Lisp equivalent &c-lang; equivalent Comment
- &nil;&nil; void as a result type for functions only
- 4 `(&unsigned-byte-type; 32)` unsigned long
- 2 `(&unsigned-byte-type; 16)` unsigned short
- 1 `(&unsigned-byte-type; 8)` unsigned char
- -4 `(&signed-byte-type; 32)` long
- -2 `(&signed-byte-type; 16)` short
- -1 `(&signed-byte-type; 8)` signed char
- 0&boolean-type; BOOL as a result type for functions only
- *opaque void*
- &external-k; opaque void*
- &string-class; &string-class; or &vector-class; char*
- &io-k; &string-class; or &vector-class; char*

Objects of type &string-class; are copied and passed NUL-terminated on the execution stack. On return, a Lisp string is allocated and filled from the address returned (unless NULL). Functions with &io-k; parameters are passed the address of the Lisp string or unsigned byte vector. These are not NUL-terminated! This is useful for functions like like `read()` which do not need an array at a constant address longer than the dynamic extent of the call (it is dangerous to define callback functions with &io-k; (or &string-class;) type parameters). Arguments of type &integer-class; and `foreign-pointer` are always acceptable where a &string-class; or &io-k; type is specified.

Platform dependent: Only in &clisp; built &with; compile-time flag &unicode;.

  A &symbol-macro; place `lisp:*foreign-encoding*` contains the encoding for characters and strings passed through the FFI. Its value must be a 1:1 encoding, i.e., an encoding in which every character is represented by one byte.

To meet the design goals, predefined types and objects were used. As such, pointers were represented as integers. Now that there is the `foreign-pointer` type, both representations may be used on input. The pointer type should be therefore considered as opaque. Use `nzero-pointer-p` for NULL tests.

#### Foreign functions

Foreign Functions are declared either through `defflibfun` or `declare-library-function`. The former is closer to the low-level implementation of the interface, the latter is closer to the other FFI.

`defflibfun` requires the library base symbol and register mask to be specified, `declare-library-function` requires the library name and computes the mask from the declaration of the arguments.

The value of mask is implementation-dependent. On the Amiga, it is an integer whose hexadecimal value is the reverse of the function argument register numbers, where d0 has number `1` and a6 number `#xF`. A &nil; mask is reserved for stack-based calls (unimplemented).

The AFFI type `0` is only acceptable as a function result type and yields either &t; or &nil;. The difference between `*` and &external-k; is the following: `*` uses integers, &external-k; uses `foreign-pointer` as function result-type (except from &nil; for a NULL pointer) and refuses objects of type &string-class; or &unsigned-byte-type; &vector-class; as input. Thus &external-k; provides some security on the input and the ability to use &finalize; for resource-tracking on the output side.

`(declare-library-function name library-name {option}*)`

option ::==
  - `(:offset library-offset)`
  - |`(:arguments {(arg-name AFFI-type register)}*)`
  - |`(:return-type AFFI-type)`
register ::==

  `:d0` | `:d1` | ... | `:d7` | `:a0` | ... | `:a6`

declares a named library function for further reference through `flibcall` and `mlibcall`.

`mlibcall` should be the preferred way of calling foreign functions (when they are known at compile-time) as macroexpansion-time checks may be performed and the call can be sort of inlined.

#### Memory access

`(mem-read address type offset)` can read 8, 16 and 32 bit signed or unsigned integers (AFFI types -4, -2, -1, 1, 2, 4), a pointer (*), a NUL-terminated string (string) or, if the type argument is of type &string-class; or &unsigned-byte-type; &vector-class;, it can fill this vector. &external-k; is not an acceptable type as no object can be created by using `mem-read`.

`(mem-write address type value [offset])` writes integers (AFFI type -4, -2, -1, 1, 2 and 4) or pointer values (type *), but not vectors to the specified memory address.

`(mem-write-vector address vector [offset])` can write memory from the given vector (of type string or unsigned byte vector).

#### Function Definition Files

`require-library-functions` will &require; a file of name derived from thelibrary name and with type `affi`. It may be used to import all names into the current package or only a given subset identified by string names, using the `:import` keyword (recommended use). Some definition files for standard Amiga libraries are provided. See example 1 below.

As `require-library-functions` loads a global file which you, the programmer, may have not defined, you may consider declaring every function yourself to be certain what the return and argument types are. See example 4 below.

The file `read-fd.lsp` defines the function `make-partial-fd-file` with which the provided `.affi` files have been prepared from the original Amiga FD files (located in the directory `FD:`). They must still be edited as the function cannot know whether a function accepts a `*`, &io-k;, `string` or &external-k; argument and because files in `FD:` only contain a register specification, not the width of integer arguments (`-4`, `-2`, `-1`, `1`, `2`, or `4`).

#### Hints

By using appropriate &eval-when; forms for `declare-library-base` and `require-library-functions` and not using `flibcall`, it is possible to write code that only loads library function definition files at compile-time. See example 1 below.

Do not rely on &finalize; to free resources for you, as &clisp; does not call finalizers when it exits, use &unwind-protect;.

#### Caveats

You can consider the library bases being symbols in need of being imported from the package AFFI originating from a brain-damage, causing the usual symbol headaches when using foreign functions calls within macros. Luckily, even if the high-level interface (or its implementation in `affi1.lsp`) were to change, the low-level part (`affi.d`) should remain untouched as all it knows are integers and foreign-pointers, no symbols. The difficulty is just to get the library base value at run-time. Feel free to suggest enhancements to this facility!

#### Examples

NB: These examples are somewhat specific to the Amiga.

Using a predefined library function file

    (use-package "AFFI")

    ;; SysBase is the conventional name for exec.library
    ;; It is only enforced by the file loaded by REQUIRE-LIBRARY-FUNCTIONS
    (eval-when (compile eval load)
      (declare-library-base :SysBase "exec.library")) ;keyword avoids name conflicts

    ;; using only MLIBCALL allows not to load definitions at load-time
    (eval-when (compile eval)
      (require-library-functions "exec.library"
        :import '("FindTask")))

    (with-open-library ("exec.library")
      (print (mlibcall FindTask 0)))

This file can be used in interpreted and compiled mode. Compiled, it will have inlined the library function calls.

Using flibcall

    (use-package "AFFI")

    (sexp-when (compile eval load)
      ;; keyword avoids name conflicts
      (declare-library-base :SysBase "exec.library"))

    ;; The load situation permits the use of flibcall
    (eval-when (eval compile load)
      (require-library-functions "exec.library"))

    (unless (open-library 'SysBase) (error "No library for SysBase"))
    (flibcall (if t 'FindTask 'Debug) 0)
    (close-library 'SysBase)

Be fully dynamic, defining library bases ourselves

    (use-package "AFFI")

    (sexp-when (compile eval load)
      (defvar mylib (declare-library-base :foobase "foo.library")))
    (eval-when (eval compile load)          ;eval allows mlibcall, load flibcall
      (defflibfun 'foo1 mylib -30 '#xA '* 'string)
      (defflibfun 'foo2 mylib -36 '#x21 0 * 4))

    (defun foo (name)
      (when (open-library mylib)
        (list (mlibcall foo1 name) (flibcall 'foo2 name 123213))
        (close-library mylib)))

Some sample function definitions

    (defflibfun 'FindTask 'SysBase -294 #xA '* 'string)
    (sexp-library-function FindTask "exec.library"
      (:offset -294)
      (:return-type *)
      (:arguments
       (name   string   :A1)))
    (declare-library-function NameFromLock "dos.library"
      (:offset -402)
      (:return-type 0)
      (:arguments
       (lock   4   :D1)
       (buffer :io :D2)
       (len    4   :D3)))

    (eval-when (compile eval)
      (defconstant GVF_LOCAL_ONLY (ash 1 9))
      (defflibfun 'SetVar 'DosBase -900 #x5432 0 'string 'string -4 4))
    (defun setvar (name value)
      (with-open-library (DosBase)
        ;; length of -1 means find length of NUL-terminated-string
        (mlibcall SetVar name value -1 GVF_LOCAL_ONLY)))

### Extensions-2.5. ARexx

Platform dependent: &amiga; platforms only.

&clisp; comes with a small yet extensible and powerful ARexx interface.

`(rexx-do-command "return address()" :string &t; :result &t;)`

  tells you the name of the &clisp; ARexx port. The default extension for &clisp; ARexx scripts is `cl`.

`(rexx-do-command command &key-amp; :string :result :token :io :host)`

  -> `(RC &optional-amp; result)`, or &nil; on failure

`(rexx-run-command command &key-amp; :string :token)`

  -> &t;, or &nil; on failure

`(rexx-send-command command &key-amp; :string :result :token :io :host)`

  -> arexx-msg-handle, or &nil; on failure

`(rexx-wait-sent-command arexx-msg-handle)`

  -> `(RC &optional-amp; result)`, or &nil; on failure

`(rexx-loop)`

  -> no return, use the `exit-loop.cl` ARexx script to abort the loop

command may be a string denoting a command with optional arguments or a vector of strings thus denoting an ARexx function call. The first element in the vector is the function name, the others are the up to 15 arguments.

Messages may be sent to an arbitrary ARexx host, special cases are &nil; (meaning `"REXX"`, the default) and &t; (`"AREXX"` for asynchronous execution).

ARexx server mode: Like Ispell, Csh and SKsh, you can run it in server mode by calling `(rexx-loop)`. You can then only exit with the ARexx `exit-loop.cl` script.

Restrictions: Currently &clisp; is not able to wait for input from several sources, e.g. both a console and ARexx, at the same time.

### Extensions-2.6. Socket Streams

Platform dependent: &unix;, &win32; platforms only.

`(`lisp:socket-server` &optional-amp; [port-or-socket])`

  This function creates a socket, binds a port to the socket, and then listens for connect attempts. The server exists to watch for client connect attempts. The optional argument is either a port (positive &fixnum-type;) or a &socket-stream; (from whose peer the connections will be made).

`(`lisp:socket-server-close` socket-server)`

  Closes down the server socket.

`(`lisp:socket-server-port` socket-server)`

  Returns the port which was bound using `lisp:socket-server`.

`(`lisp:socket-wait` socket-server &optional-amp; [seconds [microseconds]])`

  Given time argument(s), waits for (possibly zero) fixed duration for a connect on the socket-server. Without an argument, `lisp:socket-wait` blocks indefinitely.

`(`lisp:socket-accept` socket-server &key-amp; &eltype; &extfmt; &buffered;)`

  Creates the server-side two-way stream for the connection.

`(`lisp:socket-connect` port &optional-amp; [host] &key-amp; &eltype; &extfmt; &buffered;)`

  Attempts to create a client-side two-way &socket-stream;. Blocks until the server accepts the connections.

`(`lisp:socket-status` socket-stream-or-list &optional-amp; [seconds [microseconds]])`

  Checks whether it is possible to read from or write to a &socket-stream; without blocking. This is similar to &listen;, which checks only one stream and only for input.

  socket-stream-or-list is an open &socket-stream; (one symbol is returned) or a list of streams (a list of symbols, one for each stream, is returned).

  The optional arguments specify the timeout. &nil; means wait forever, 0 means poll. Note that this function never waits for input or output to arrive, only for information on input or output presense (so that &read-char; or &write-char; will not block) to become available.

  For each &socket-stream; this function returns

  Return values of `lisp:socket-status`

  &nil;

    when no information is available or no operation is possible

  &error-k;

    when an i/o operation will cause an error

  &input-k;

    when you can only read from the stream

  &output-k;

    when you can only write to the stream

  &io-k;

    when you can both read from and write to the stream

`(`lisp:socket-stream-host` socket-stream)`, `(`lisp:socket-stream-port` socket-stream)`

  These two functions return information about the &socket-stream;. For a server, `lisp:socket-stream-host` returns &nil;.

`(`lisp:socket-service-port` &optional-amp; service-name (protocol "tcp"))`

  A convenience function for looking up a port given the service name. It returns the servent struct as multiple values (name, list of aliases, port, protocol) for the given service-name and protocol, or all services as the list of vectors of &length; 4, if service-name is not given or is `:default` or &nil;.

`(`lisp:socket-stream-peer` socket-stream)`

  Given a stream, this function returns the name of the host on the opposite side of the connection and its port number; the server-side can use this to see who connected.

`(`lisp:socket-stream-local` socket-stream)`

  The dual to `lisp:socket-stream-peer` - same information, host name and port number, but for the local host. The difference from `lisp:socket-stream-host` and `lisp:socket-stream-port` is that this function asks the OS (and thus returns the correct trusted values) while the other two are just accessors to the internal data structure, and basically return the arguments given to the function which created the &socket-stream;.

### Extensions-2.7. System Calls

When &clisp; is configured with an option `--with-export-syscalls`, some system calls are available from lisp, in package POSIX.

`(`posix:resolve-host-ipaddr` &optional-amp; host)`

  Returns the hostent struct (name, list of aliases, list of IP addresses as dotted quads (for IPv4) or coloned octets (for IPv6), address type - IPv4 or IPv6). When host is omitted or `:default`, return the data for the current host. When host is given and is &nil;, all the host database is returned as a list (this would be the contents of the `/etc/hosts` file on a UNIX system or `${windir}/system32/etc/hosts` on a Win32 system).

`(`posix:file-stat` file &optional-amp; link-p)`

  Return the stat struct. `file` can be a stream, a pathname, a string or a number (on a UNIX system, meaning file descriptor). The first slot of the struct returned is the string or the number on which `stat(2)`/`fstat(2)`/`lstat(2)` was called. The other 13 slots are numbers, members of the stat struct: device, inode, protection, number of hard links, owner's UID, owner's GID, device type, total size (bytes), blocksize for filesystem I/O, number of blocks allocated, atime, mtime, ctime (as the number of seconds since 1900-01-01). If the system does not support a particular field (e.g., Win32 does not have hard links), &nil; (or the default, like 1 for the number of hard links for Win32 or DOS) is returned.

  [UNIX systems only at this time, patches are welcome.]

`(`posix:user-data` &optional-amp; user)`>

  Return the passwd struct (name, encoded password, UID, GID, full name, home directory, shell). When user is &nil;, return all users. When user is `:default` or not supplied, return the information about the current user. If the system does not support a particular field (e.g., Win32 does not have a concept of a shell), &nil; (or the default, like `c:\command.com` for DOS) is returned.

  [UNIX systems only at this time, patches are welcome.]

`(`posix:sysinfo`)`

  Return a struct describing the OS, derived from `uname(2)` and `sysconf(3)`.

`(`posix:resource-usage-limits`)`

  Return 3 structs describing the resources usage and limits, derived from `getrlimit(2)` and `getrusage(3)`.

`(`posix:erf` real)` `(`posix:erfc` real)` `(`posix:j0` real)` `(`posix:j1` real)` `(`posix:jn` int real)` `(`posix:y0` real)` `(`posix:y1` real)` `(`posix:yn` int real)` `(`posix:gamma` real)` `(`posix:lgamma` real)`

  Compute the error functions, Bessel functions and Gamma. These functions are required by the POSIX standard and should be available in libm.so. Please note that these functions do not provide lisp-style error handling and precision, and do all the computations at the double float level.

  [UNIX systems only at this time, patches are welcome.]

### Extensions-2.8. Quickstarting delivery with &clisp;

This section describes four ways to turn &clisp; programs into executable programs, which can be started as quickly as executables written in other languages.

UNIX

  &clisp; can act as a script interpreter.

Desktop environments such as KDE, GNOME, or Windows.

  Files created with &clisp; can be associated with the &clisp; executables so that clicking on them would make &clisp; execute the appropriate code.

Linux with `CONFIG_BINFMT_MISC=y`

  Associate the extensions `fas` and `lsp` with &clisp;; then you can make the files executable and run them from the command line.

Amiga

  Files created with &clisp; can be associated with a Workbench project icon so that clicking on them would make &clisp; execute the appropriate code. Note that several `fas` files can be concatenated (using `Join`) into one file.

These three techniques apply to a single `lsp` or `fas` file. If your application is made up of several `lsp` or `fas` files, you can simply concatenate them (using `cat`(1)) into one file; the techniques then apply to that concatenated file.

Platform dependent: &unix; platforms only.

  On Unix, a text file (`fas` or `lsp`) can be made executable by adding a first line of the form

      #!interpreter [interpreter-args]

  and using `chmod`(1) to make the script executable. &clisp; can be used as a script interpreter under the following circumstances:

  - The interpreter must be the full pathname of &clisp;. The recommended path is `/usr/local/bin/clisp`, and if &clisp; is actually installed elsewhere, making `/usr/local/bin/clisp` be a symbolic link to the real &clisp;.

  - The interpreter must be a real executable, not a script. Unfortunately, in the binary distributions of &clisp; on Solaris, `clisp` is a shell script because a &c-lang; compiler cannot be assumed to be installed on this platform. If you do have a &c-lang; compiler installed, build &clisp; from the source yourself; `make install` will install `clisp` as a real executable.

  - On some platforms, the first line which specifies the interpreter is limited in length:

    - max. 32 characters on SunOS 4,

    - max. 80 characters on HP-UX,

    - max. 127 characters on Linux.

    Characters exceeding this limit are simply cut off by the system. At least 128 characters are accepted on Solaris, IRIX, AIX, OSF/1. There is no workaround: You have to keep the interpreter pathname and arguments short.

  - On Solaris and HP-UX, only the first interpreter-arg is passed to the interpreter. In order to pass more than one option (for example, `-Msomewhere.mem` and `-C`) to &clisp;, separate them by hard spaces (ISO Latin-1 character 160) instead of normal spaces. (But the separator between interpreter and interpreter-args must still be a normal space!) &clisp; will split the interpreter-args at hard spaces and at normal spaces.

  The script should contain Lisp forms, except in the #! line. The file is normally loaded, through the function &load;. Before it is loaded, the variable `lisp:*args*` is bound to a list of strings, representing the arguments given to the Lisp script. &standard-input-var; and &standard-output-var; are bound, as usual, to the Unix standard input and output. &error-output-var; is bound to the Unix error output. Continuable errors will be turned to warnings. Non-continuable errors and Ctrl C interrupts will terminate the execution of the Lisp script with error status. If you wish the script's contents to be compiled during loading, add `-C` to the interpreter-args.

  Another, quite inferior, alternative is to put the following into a file:

      #!/bin/sh
      exec clisp <<EOF
      (lisp-form)
      (another-lisp-form)
      (yet-another-lisp-form)
      EOF

  The problem with this approach is that the return values of each form will be printed to the standard output. Another problem is that no user input will be available.

Platform dependent: &win32; platforms only.

  There are two different ways to make &clisp; "executables" for Windows platforms.

  - Associate the `mem` extension with `c:\clisp\lisp.exe -m 10M -M %s -N c:\clisp\locale`.

  - Associate the `fas` extension with `c:\clisp\lisp.exe -m 10M -M c:\clisp\lispinit.mem -N c:\clisp\locale -i %s`. Alternatively, you may want to have a function `main` in your files and associate the `fas` extension with `c:\clisp\lisp.exe -m 10M -M c:\clisp\lispinit.mem -N c:\clisp\locale -i %s -x (main)`.

  Then clicking on the compiled lisp file (with `fas` extension) will load the file (thus executing all the code in the file), while the clicking on a &clisp; memory image (with `mem` extension) will start clisp with the given memory image.

Platform dependent: &linux; platforms only.

  You have to build your kernel with `CONFIG_BINFMT_MISC=y` and `CONFIG_PROC_FS=y`. Then you will have a `/proc/sys/fs/binfmt_misc/` directory and you will be able to do (as `root`; you might want to put these lines into `/etc/rc.d/rc.local`):

      bash# echo ":CLISP:E::fas::/usr/bin/clisp:" >> /proc/sys/fs/binfmt_misc/register
      bash# echo ":CLISP:E::lsp::/usr/bin/clisp:" >> /proc/sys/fs/binfmt_misc/register

  Then you can do the following:

      bash$ cat << EOF > hello.lsp
      (print "hello, world!")
      EOF
      bash$ clisp -c hello.lsp

      Compiling file /home/sds/hello.lsp ...

      Compilation of file /home/sds/hello.lsp is finished.
      0 errors, 0 warnings
      bash$ chmod +x hello.fas
      bash$ hello.fas

      "hello, world!"
      bash$

  Please read `/usr/src/linux/Documentation/binfmt_misc.txt` for details.

Platform dependent: Amiga platforms only.

  Using a Workbench project file, the memory images, source and binary files can be made "executable".

  - Using IconEdit, create a project icon.

  - Set the tool to `lisp:lisp.run` (or wherever the binary is located).

  - Define a tooltype named ARGS set to `-M *` for a memory image project icon or to `-M lisp:lispinit.mem -i *` for a source or compiled lisp file. The startup code will replace an isolated * token with the file name.

  - Alternatively, you may want to have a function `main` in your files and set the ARGS tooltype to `-M lisp:lispinit.mem -i * -x (main)`.

  - You might want to add more command line options to the ARGS tooltype.

  Clicking on the compiled lisp file (with `fas` suffix) will load the image and the file (thus executing all the code in the file), while clicking on the &clisp;'s memory image (with `mem` suffix) with start clisp with the given memory image.

  You might want to add a tooltype named WINDOW which names the console window that &terminal-io-var; will be bound to, for example `CON:0/0/500/300/CLISP-Listener/AUTO/CLOSE`, or `TCP:20002`.

### Extensions-2.9. Application delivery with &clisp;

Some ways of packaging &clisp; programs are discussed in the section Quickstarting delivery with &clisp;.

&clisp; is Free Software, covered by the &gnu; &gpl;, with special terms governing the distribution of applications that run in &clisp;. The precise terms can be found in the `COPYRIGHT` file contained in the source and binary distributions of &clisp;. Here is an informal clarification what these terms mean in practice. Please refer to the said `COPYRIGHT` file when in doubt.

In many cases, &clisp; does not force an application to be covered by the &gnu; &gpl;. Nevertheless, we encourage you to release your software under an open source copyright. The benefits of such a copyright for your users are numerous, in particular they are free to modify the application when their needs/requirements change, and they are free to recompile the application when they upgrade their machine or operating system.

&clisp; extensions, i.e. programs which need to access non-portable &clisp; internal symbols (in the packages SYSTEM, COMPILER, CLOS, FFI, ...), must be covered by &gnu; &gpl; as well.

Other programs running in &clisp; have to or need not to be placed under &gnu; &gpl;, depending on their distribution form:

- Programs distributed as Lisp source of `.fas` files can be distributed without restrictions coming from &clisp;.

- Programs distributed as &clisp; memory images can be distributed only if accompanied with the non-&clisp; `.fas` files which make up the memory image, and a `Makefile` for rebuilding the memory image.

- If you need to distribute a modified &clisp; executable (for example, incorporating additional modules written in &c-lang;), you must distribute its full source under &gnu; &gpl;. If you are not satisfied with this, you can instead put the additional modules into a separate (non-&clisp;) program, with which your Lisp program will communicate via &socket-stream;s.

### Extensions-2.10. Shell, Pipes and Printing

#### Shell

Platform dependent: &unix;, &acorn;, &dos;, &os2;, platforms only.

  `(`lisp:execute` programfile arg1 arg2 ...)` executes an external program. Its name is programfile. It is given the strings arg1, arg2, ... as arguments.

Platform dependent: &amiga; platforms only.

  `(`lisp:execute` command)` executes a given command using the operating system's shell.

Platform dependent: &unix;, &amiga;, &acorn;, &dos;, &os2;, &win32; platforms only.

  `(`lisp:shell` [command])` calls the operating system's shell. `(`lisp:shell`)` calls the shell for interactive use. `(`lisp:shell` command)` calls the shell only for execution of the one given command.

Platform dependent: &unix;, &os2;, &win32; platforms only.

  The functions `lisp:run-shell-command` and `lisp:run-program` are the general interface to `lisp:shell` and the above:

  `(`lisp:run-shell-command` command &input-k; &output-k; &if-output-exists;)` runs a shell command.

  `(`lisp:run-program` program `:arguments` &input-k; &output-k; &if-output-exists;)` runs an external program.

  command

    the shell command.

    Platform dependent: &unix; platforms only.

      The shell the command is passed to is the value of the environment variable `SHELL`, which normally is `/bin/sh`. The command should be a ``simple command''; a ``command list'' should be enclosed in "{ ... ; }" (for `/bin/sh`) or "( ... )" (for `/bin/csh`).

  program

    the program. The directories listed in the `PATH` environment variable will be searched for it.

  `:arguments`

    a list of arguments (strings) that are given to the program.

  &input-k;

    where the program's input is to come from: either `:terminal` (the standard input) or &stream-k; (a Lisp stream to be created) or a pathname (an input file) or &nil; (no input at all).

  &output-k;

    where the program's output is to be sent to: either `:terminal` (the standard output) or &stream-k; (a Lisp stream to be created) or a pathname (an output file) or &nil; (ignore the output).

  &if-output-exists;

    what to do if the &output-k; file already exists. The possible values are &overwrite-k;, &append-k;, &error-k;, with the same meaning as for &open;.

  If &stream-k; was specified for &input-k; or &output-k;, a Lisp stream is returned. If &stream-k; was specified for &input-k; and &output-k;, three Lisp streams are returned, as for the function `lisp:make-pipe-io-stream`. This use of `lisp:run-program` can cause deadlocks, see `lisp:make-pipe-io-stream`.

#### Pipes

Platform dependent: &unix;, &os2;, &win32; platforms only.
  `(`lisp:make-pipe-input-stream` command &key-amp; &eltype; &extfmt; &buffered;)`

    returns an input stream that will supply the output from the execution of the given operating system command.

  `(`lisp:make-pipe-output-stream` command &key-amp; &eltype; &extfmt; &buffered;)`

    returns an output stream that will pass its output as input to the execution of the given operating system command.

  `(`lisp:make-pipe-io-stream` command &key-amp; &eltype; &extfmt; &buffered;)`

    returns three values. The first value is a bidirectional stream that will simultaneously pass its output as input to the execution of the given operating system command and supply the output from this command as input. The second and third value will be the input stream and the output stream that make up the I/O stream, respectively. Note that they must be closed individually.

    Warning: Improper use of this function can lead to deadlocks. Use it at your own risk!

    A deadlock occurs if the command and your program either both try to read from each other at the same time or both try to write to each other at the same time. To avoid deadlocks, it is recommended that you fix a protocol between the command and your program and avoid any hidden buffering: use &read-char;, &read-char-no-hang;, &listen; instead of &read-line; and &read; on the input side, and complete every output operation by a &finish-output;. The same cautions must apply to the called command as well.

#### Printing

The macro `lisp:with-output-to-printer`:

    (lisp:with-output-to-printer (var [&extfmt;])
      {declaration}*
      {form}*)

binds the variable var to an output stream that sends its output to the printer.

### Extensions-2.11. Directory Access

When &clisp; is configured with an option `--with-dir-key`, some directory access is available from lisp, in package LISP. 3 types of directory keys may exist, depending on the compilation environment.

valid directory key types

:win32

  &win32; registry access

:gnome

  Gnome-config access

:ldap

  LDAP interface via OpenLDAP.

The following functions and macros are exported (please note that these features are experimental and the API may be modified in the future).

`(`lisp:dir-key-open` dkey path &key-amp; (&direction-k; &input-k;) &if-does-not-exist;`

  Open the directory key under dkey, which should be either an open directory key or a valid directory key type. The meaning of the &direction-k; and &if-does-not-exist; keyword arguments is the same as for &open;.

`(`lisp:dir-key-close` dkey)`

  Close the directory key. The preferred way is to use the `lisp:with-dir-key-open` macro.

`(`lisp:with-dir-key-open` (var dkey path &rest-amp; options) &body-amp; body)`

  Open the directory key (by calling `lisp:dir-key-open` on dkey, path and options), bind it to var, execute body, then close it with `lisp:dir-key-close`.

`(`lisp:dir-key-type` dkey)`

  Return the type of the directory key

`(`lisp:dir-key-path` dkey)`

  Return the path of this directory key, which is the path argument of `lisp:dir-key-open` if dkey was a type or the concatenation of the path argument and the `lisp:dir-key-path` of dkey.

`(`lisp:dir-key-direction` dkey)`

  One of &input-k;, &output-k; and &io-k;, indicating the permitted operation on this key and its derivatives.

`(`lisp:dir-key-closed-p` dkey)`

  Check whether the key has been closed. It is not an error to close a closed key.

`(`lisp:dir-key-subkey-delete` dkey subkey)` `(`lisp:dir-key-value-delete` dkey attribute)`

  Delete the specified subkey or attribute.

`(`lisp:dir-key-subkey` dkey)` `(`lisp:dir-key-attributes` dkey)`

  Return the list of the subkeys or attributes.

`(`lisp:dir-key-value` dkey attribute &optional-amp; default)`

  Return the value of the specified attribute, similar to &gethash; and &setf;able just like &gethash;.

`(`lisp:dir-key-info` dkey)`

  Return some information about the directory key. This is highly platform-dependent and will probably be removed or replaced or modified in the future.

`(`with-dir-key-search` (key-iter atribute-iter dkey path &key-amp; `:scope`) &body-amp; body)`

  This is the main way to iterate over the subtree under the key dkey+path.

  key-iter is a non-&nil; symbol and is bound via ¯olet; to a macro, each call of which returns the next subkey.

  atribute-iter is a symbol and is bound, when non-&nil;, to a macro, each call of which returns two values - the next attribute and its value.

  The `:scope` keyword argument specifies the scope of the search and can be

  `:self`

    iterate over the key itself

  `:level`

    iterate over the children of the key

  `:tree`

    iterate over the subtree

  `with-dir-key-search` is used to implement `dir-key-values`, `dir-key-childred` and `dir-key-dump-tree` in `dirkey.lisp`.

### Extensions-2.12. Other

Platform dependent: &amiga; platforms only.

  To have &debug-io-var; and &error-output-var; point to separate console windows (thus keeping your standard console window clean from error messages) you can use

        (&setq; &error-output-var;
          (&setq; &debug-io-var;
            (&open; "CON:0/0/500/300/CLISP-Debugger/AUTO/CLOSE"
                    &direction-k; &io-k;)))

  at startup.