Implementation Notes for CLISP

Last modified: 15 September 1997.

This implementation is mostly compatible to the standard reference

Guy L. Steele Jr.: Common Lisp - The Language (1st ed.).
Digital Press 1984, 465 pages.
("CLtL1" for short)

and to the older parts of

Guy L. Steele Jr.: Common Lisp - The Language (2nd ed.).
Digital Press 1990, 1032 pages.
("CLtL2" for short)
http://www.cs.cmu.edu/afs/cs.cmu.edu/project/ai-repository/ai/html/cltl/cltl2.html

These notes document the differences of the CLISP implementation of Common Lisp to the standard CLtL1, and some implementation details. The differences between CLtL1 and CLtL2 are made up of X3J13 votes. CLISP's position with respect to these votes is listed in cltl2.txt.

Chapter 1: Introduction

No notes.

Chapter 2: Data Types

All the data types are implemented: numbers, characters, symbols, lists, arrays, hash tables, readtables, packages, pathnames, streams, random states, structures and functions.

2.1.3.

There are four floating point types: short-float, single-float, double-float and long-float:
sign mantissa exponent comment
short-float 1 bit 16+1 bits 8 bits  
single-float 1 bit 23+1 bits 8 bits CLISP uses IEEE format
double-float 1 bit 52+1 bits 11 bits CLISP uses IEEE format
long-float 1 bit >=64 bits 32 bits  

The single and double float formats are those of the IEEE standard (1981), except that CLISP does not support features like +0, -0, +inf, -inf, gradual underflow, NaN, etc. (Common Lisp does not make use of these features.)

Long floats have variable mantissa length, which is a multiple of 16 (or 32, depending on the word size of the processor). The default length used when long floats are read is given by the place (long-float-digits). It can be set by (setf (long-float-digits) nnn), where nnn is a positive integer.

2.1.4.

Complex numbers can have a real part and an imaginary part of different types. For example, (sqrt -9.0) evaluates to the number #C(0 3.0), which has a real part of exactly 0, not only 0.0 (which would mean "approximately 0"). The type specifier for this is (complex integer single-float), and (complex type-of-real-part type-of-imaginary-part) in general. The type specifier (complex type) is equivalent to (complex type type).

2.2.1.

The characters are ordered according to the ASCII encoding.
Platform dependent: DOS, OS/2 platforms only.
More precisely, CLISP uses the IBM PC character set (code page 437):
$0 $1 $2 $3 $4 $5 $6 $7 $8 $9 $A $B $C $D $E $F
$00 ** ** ** ** ** ** ** ** §
$10 ** **
$20   ! " # $ % & ' ( ) * + , - . /
$30 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
$40 @ A B C D E F G H I J K L M N O
$50 P Q R S T U V W X Y Z [ \ ] ^ _
$60 ` a b c d e f g h i j k l m n o
$70 p q r s t u v w x y z { | } ~ 
$80 Ç ü é â ä à å ç ê ë è ï î ì Ä Å
$90 É æ Æ ô ö ò û ù ÿ Ö Ü ¢ £ ¥
$A0 á í ó ú ñ Ñ ª º ¿ ¬ ½ ¼ ¡ « »
$B0
$C0
$D0
$E0 ß µ
$F0 ± ÷ ° · ²
Here ** are control characters, not graphic characters. (The characters left blank here cannot be represented in this character set).
Platform dependent: UNIX (except NeXTstep), Win32, Amiga, Acorn platforms only.
More precisely, CLISP uses the ISO Latin-1 (ISO 8859-1) character set:
$0 $1 $2 $3 $4 $5 $6 $7 $8 $9 $A $B $C $D $E $F
$00 ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
$10 ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
$20   ! " # $ % & ' ( ) * + , - . /
$30 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
$40 @ A B C D E F G H I J K L M N O
$50 P Q R S T U V W X Y Z [ \ ] ^ _
$60 ` a b c d e f g h i j k l m n o
$70 p q r s t u v w x y z { | } ~
$80
$90
$A0   ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ­ ® ¯
$B0 ° ± ² ³ ´ µ · ¸ ¹ º » ¼ ½ ¾ ¿
$C0 À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï
$D0 Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß
$E0 à á â ã ä å æ ç è é ê ë ì í î ï
$F0 ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ
Here ** are control characters, not graphic characters. (The characters left blank here cannot be represented in this character set).
Platform dependent: NeXTstep platforms only.
More precisely, CLISP uses the NextStep character set:
$0 $1 $2 $3 $4 $5 $6 $7 $8 $9 $A $B $C $D $E $F
$00 ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
$10 ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
$20   ! " # $ % & ' ( ) * + , - . /
$30 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
$40 @ A B C D E F G H I J K L M N O
$50 P Q R S T U V W X Y Z [ \ ] ^ _
$60 ` a b c d e f g h i j k l m n o
$70 p q r s t u v w x y z { | } ~
$80   À Á Â Ã Ä Å Ç È É Ê Ë Ì Í Î Ï
$90 Ð Ñ Ò Ó Ô Õ Ö Ù Ú Û Ü Ý Þ µ × ÷
$A0 © ¡ ¢ £ ¥ § ¤ «
$B0 ® · ¦ » ¬ ¿
$C0 ¹ ´ ¯ ¨ ² ° ¸ ³
$D0 ± ¼ ½ ¾ à á â ã ä å ç è é ê ë
$E0 ì Æ í ª î ï ð ñ Ø º ò ó ô õ
$F0 ö æ ù ú û ü ý ø ß þ ÿ
Here ** are control characters, not graphic characters. (The characters left blank here cannot be represented in this character set).
The following are standard characters:
#\Space $20
#\Newline $0A
The following are semi-standard characters:
#\Backspace $08
#\Tab $09
#\Linefeed $0A
#\Page $0C
#\Return $0D
Platform dependent: DOS, OS/2, Win32 platforms only.
#\Rubout $08
Platform dependent: UNIX, Amiga, Acorn platforms only.
#\Rubout $7F

2.2.2.

#\Newline is the delimiter between lines.

Platform dependent: DOS, OS/2, Win32 platforms only.
When writing to a file, #\Newline is converted to CR/LF. (This is the usual convention on DOS.) For example, #\Return #\Newline is written as CR/CR/LF.
When reading from a file, CR/LF is converted to #\Newline, and CR not followed by LF is read as #\Return.

2.2.3.

There are the following additional characters with names:
#\Null $00
#\Bell $07
#\Escape $1B

Additionally, the following syntax is defined for characters with code from $00 to $1F:
#\^@ $00
#\^A .. #\^Z $01 .. $1A
#\^[ $1B
#\^\ $1C
#\^] $1D
#\^^ $1E
#\^_ $1F

See also sec. 22.1.4.

2.2.4.

The code of a character is >=0, <256. char-code-limit = 256. There are fonts 0 to 15, and char-font-limit = 16. But the system itself uses only font 0. The following bits attributes are implemented: :control, :meta, :super, :hyper. Therefore char-bits-limit = 16.
Platform dependent: UNIX, DOS, OS/2, Win32, Acorn platforms only.
The system itself uses these bits only to mention special keys and Control/Alternate/Shift key status on return from (read-char *keyboard-input*).

2.5.

The maximum rank (number of dimensions) of an array is either 65535 or 4294967295.

2.10.

The CLtL2 types broadcast-stream, concatenated-stream, echo-stream, synonym-stream, string-stream, file-stream, two-way-stream are implemented.

2.13.

All the functions built by function, compile and the like are atoms. There are built-in functions written in C, compiled functions (both of type compiled-function) and interpreted functions (of type function). The possible function names (CLtL1 p. 59) are symbols and lambda expressions.

2.14.

This is the list of objects whose external representation can not be meaningfully read in:
#<type ...> all structures lacking a keyword constructor
#<ARRAY type dimensions> all arrays except strings, if *print-array* = nil
#<SYSTEM-FUNCTION name> built-in function written in C
#<ADD-ON-SYSTEM-FUNCTION name> other function written in C
#<SPECIAL-FORM name> special form handler
#<COMPILED-CLOSURE name> compiled function, if *print-closure* = nil
#<CLOSURE name ...> interpreted function
#<FRAME-POINTER #x...> pointer to a stack frame
#<DISABLED POINTER> frame pointer which has become invalid on exit from the corresponding block or tagbody
#<...-STREAM ...> stream
#<PACKAGE name> package
#<HASH-TABLE #x...> hash table, if *print-array* = nil
#<READTABLE #x...> readtable
#<SYMBOL-MACRO form> symbol-macro handler
#<FOREIGN-POINTER #x...> foreign pointer
(Platform dependent: UNIX, Win32, Amiga platforms only.)
#<FOREIGN-ADDRESS #x...> foreign address
(Platform dependent: UNIX, Win32 platforms only.)
#<FOREIGN-VARIABLE name #x...> foreign variable
(Platform dependent: UNIX, Win32 platforms only.)
#<FOREIGN-FUNCTION name #x...> foreign function
(Platform dependent: UNIX, Win32 platforms only.)
#<UNBOUND> "value" of a symbol without value, "value" of an unsupplied optional or keyword argument
#<SPECIAL REFERENCE> environment marker for variables declared special
#<DOT> internal read result for "."
#<END OF FILE> internal read result, when the end of file is reached
#<READ-LABEL ...> intermediate read result for #n#
#<ADDRESS #x...> machine address, should not occur
#<SYSTEM-POINTER #x...> should not occur

2.15.

The type number is the disjoint union of the types real and complex. (CLtL wording: "exhaustive partition")
The type real is the disjoint union of the types rational and float.
The type rational is the disjoint union of the types integer and ratio.
The type integer is the disjoint union of the types fixnum and bignum.
The type float is the disjoint union of the types short-float, single-float, double-float and long-float.

Chapter 3: Scope and Extent

is implemented as described.

Chapter 4: Type Specifiers

4.4.

The CLtL2 type specifier (eql object) denotes the singleton set {object}.

4.5.

The general form of the complex type specifier is (complex type-of-real-part type-of-imaginary-part). The type specifier (complex type) is equivalent to (complex type type).

4.6.

The CLtL2 type specifier (real low high) denotes the real numbers between low and high.

4.7.

deftype lambda lists are subject to destructuring (nested lambda lists are allowed, as in defmacro) and may contain a &whole marker, but no &environment marker.

(type-expand-1 typespec): If typespec is a user-defined type, type-expand-1 will expand it once and return two values: the expansion and t. If typespec is not a user-defined type, then the two values typespec and nil are returned.

(type-expand typespec): This is similar to (type-expand-1 typespec), but repeatedly expands typespec until it is no longer a user-defined type. A second value of t or nil is returned as for type-expand-1, indicating whether the original typespec was a user-defined type.

4.9.

The possible results of type-of are:
cons
symbol null boolean
fixnum bignum ratio short-float single-float double-float long-float complex
character base-char
(array element-type dimensions), (simple-array element-type dimensions)
(vector t size), (simple-vector size)
(string size), (simple-string size)
(base-string size), (simple-base-string size)
(bit-vector size), (simple-bit-vector size)
function compiled-function
stream file-stream synonym-stream broadcast-stream concatenated-stream two-way-stream echo-stream string-stream
package hash-table readtable pathname logical-pathname random-state byte
load-time-eval symbol-macro foreign-variable foreign-function read-label
frame-pointer system-internal
address (should not occur)
any other symbol (structure types or CLOS classes)
a class (CLOS classes without proper name)

Chapter 5: Program Structure

5.1.3.

In addition to the 24 special forms listed on p. 57 (CLtL2: p. 73), the CLtL2 special forms locally, symbol-macrolet, load-time-value are implemented, and the macros psetq, prog1, prog2, when, unless, cond, case, multiple-value-list, multiple-value-bind, multiple-value-setq, and, or are implemented as special forms.

Constants may not be bound dynamically or lexically.

5.2.2.

lambda-list-keywords = (&optional &rest &key &allow-other-keys &aux &body &whole &environment)

lambda-parameters-limit is 65536 on 16-bit processors, 4294967296 on 32-bit processors.

5.3.

defun and defmacro are allowed in non-toplevel positions. As an example, consider the old (CLtL1) definition of gensym:
(let ((gensym-prefix "G")
      (gensym-count 1))
  (defun gensym (&optional (x nil s))
    (when s
      (cond ((stringp x) (setq gensym-prefix x))
            ((integerp x)
             (if (minusp x)
               (error "~S: index ~S is negative" 'gensym x)
               (setq gensym-count x)
            ))
            (t (error "~S: argument ~S of wrong type" 'gensym x))
    ) )
    (prog1
      (make-symbol
        (concatenate 'string
          gensym-prefix
          (write-to-string gensym-count :base 10 :radix nil)
      ) )
      (incf gensym-count)
) ) )

5.3.2.

(proclaim '(special var)) declarations may not be undone. The same holds for defvar, defparameter and defconstant declarations.

It is an error if a defconstant variable is bound at the moment the defconstant is executed, but defconstant does not check this.

Constants may not be bound dynamically or lexically.

5.3.3.

eval-when also accepts the situations (not eval) and (not compile).

Chapter 6: Predicates

6.2.2.

realp returns t is its argument is a real number, nil otherwise. compiled-function-p returns t on built-in functions written in C, compiled functions and special form handlers. Therefore compiled-function is not a subtype of function.

6.3.

eq compares characters and fixnums as eql does. No unnecessary copies are made of characters and numbers. Nevertheless, one should use eql.

(let ((x y)) (eq x x)) always returns t, regardless of y.

6.4.

and and or are implemented as special forms and, as such, rather efficient.

Chapter 7: Control Structure

7.1.1.

Platform dependent: UNIX platforms only, and only in clisp binaries built with compile-time flag IMMUTABLE.
Attempts to modify read-only data will signal an error. Program text and quoted constants loaded from files are considered read-only data. This check is only performed for conses and arrays, not for user-defined data types.

(function symbol) returns the local function definition established by flet or labels, if it exists, otherwise the global function definition.

The CLtL2 place (fdefinition function-name) is implemented.

(special-form-p symbol) returns nil or t. If it returns t, then (symbol-function symbol) returns the (useless) special form handler.

7.1.2.

psetq is implemented as a special form and, as such, rather efficient.

7.2.

(setf (symbol-function symbol) object) requires object to be either a function, a symbol-function return value or a lambda expression. A lambda expression is thereby immediately converted to a function.

setf also accepts places yielding multiple values.

Additional places:

funcall:
(setf (funcall #'symbol ...) object) and (setf (funcall 'symbol ...) object) are equivalent to (setf (symbol ...) object).
get-dispatch-macro-character:
(setf (get-dispatch-macro-character ...) ...) performs a set-dispatch-macro-character.
long-float-digits:
(setf (long-float-digits) digits) sets the default mantissa length of long floats to digits bits.
values:
(setf (values place1 ... placek) form) is approximately equivalent to

     (multiple-value-bind (dummy1 ... dummyk) form
       (setf place1 dummy1 ... placek dummyk)
       (values dummy1 ... dummyk)
     )

Example: (setf (values a b) (values b a)) interchanges the values of a and b.

values-list:
(setf (values-list list) form) is equivalent to (values-list (setf list (multiple-value-list form)))

&key markers in defsetf lambda lists are supported, but the corresponding keywords must appear literally in the program text.

(get-setf-method form &optional env) and (get-setf-method-multiple-value form &optional env) receives as optional argument the environment necessary for macro expansions. In define-setf-method lambda lists, one can specify &environment and a variable, which will be bound to the environment. This environment should be passed to all calls of get-setf-method and get-setf-method-multiple-value. If this is done, even local macros will be interpreted as places correctly.

7.3.

call-arguments-limit is 65536 on 16-bit processors, 4294967296 on 32-bit processors.

7.4.

prog1 and prog2 are implemented as special forms and, as such, rather efficient.

7.5.

The CLtL2 special form symbol-macrolet is implemented.

The macro define-symbol-macro establishes symbol macros with global scope (as opposed to symbol macros defined with symbol-macrolet, which have local scope): (define-symbol-macro symbol expansion).
The function symbol-macro-expand tests for a symbol macro: If symbol is defined as symbol macro, (symbol-macro-expand symbol) returns two values, t and the expansion, else it returns nil.
Calling boundp on a symbol defined as symbol macro returns t.
Calling symbol-value on a symbol defined as symbol macro returns the value of the expansion. Calling set on a symbol defined as symbol macro calls setf on the expansion.
Calling makunbound on a symbol defined as symbol macro removes the symbol macro definition.

If using the optional package macros3:
The macros letf and letf* are like let and let*, resp., 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 ...)
(letf (((first l) 7)) ...)
is approximately equivalent to
    (let* ((#:g1 l) (#:g2 (first #:g1)))
      (unwind-protect (progn (setf (first #:g1) 7) ...)
                      (setf (first #:g1) #:g2)
    ) )
    

7.6.

when, unless, cond, case are implemented as special forms and, as such, rather efficient.

7.8.4.

The function mapcap is like mapcan, except that it concatenates the resulting lists with append instead of nconc:
(mapcap fun x1 ... xn) == (apply #'append (mapcar fun x1 ... xn))
(Actually a bit more efficient that this would be.)

The function maplap is like mapcon, except that it concatenates the resulting lists with append instead of nconc:
(maplap fun x1 ... xn) == (apply #'append (maplist fun x1 ... xn))
(Actually a bit more efficient that this would be.)

7.9.1.

multiple-values-limit = 128

multiple-value-list, multiple-value-bind, multiple-value-setq are implemented as special forms and, as such, rather efficient.

The macro nth-value: (nth-value n form) returns the (n+1)st value (n>=0) of form.

Chapter 8: Macros

8.3.

The CLtL2 macro destructuring-bind is implemented. It does not perform full error checking.

Chapter 9: Declarations

9.1.

The CLtL2 macro declaim is implemented.

9.2.

The declarations (type type var ...), (ftype type fun ...), (function name arglist result-type), (optimize (quality value) ...) are ignored by the interpreter and the compiler.

The CLtL2 declaration (optimize (debug ...)) is legal.

Additional declarations:

9.3.

The type assertion (the value-type form) enforces a type check in interpreted code. No type check is done in compiled code.

If using the optional package macros3:
The macro ethe: (ethe value-type form) enforces a type check in both interpreted and compiled code.

Chapter 10: Symbols

No notes.

Chapter 11: Packages

11.6.

The package SYSTEM has the nicknames "SYS" and, additionally, "COMPILER".

The CLtL2 packages

are implemented. The package COMMON-LISP exports only those symbols from the ANSI CL standard that are actually implemented.

11.7.

For make-package, the default value of the :use argument is ("LISP" "CLOS").

The CLtL2 macro defpackage is implemented.

make-package and in-package accept a keyword argument :case-sensitive. Similarly, defpackage accepts an option :case-sensitive. When its value is non-nil, the package will be case sensitive, i.e. the reader will not case-convert symbol names before looking them up or creating them in this package. The package names are still subject to (readtable-case *readtable*), though.

11.8.

The function require receives as optional argument either a pathname or a list of pathnames: files to be loaded if the required module is not already in memory.

Chapter 12: Numbers

The single and double float formats are those of the IEEE standard (1981), except that CLISP does not support features like +0, -0, +inf, -inf, gradual underflow, NaN, etc. (Common Lisp does not make use of these features.)

The default number of mantissa bits in long floats is given by the place (long-float-digits). Example: (setf (long-float-digits) 3322) sets the default precision of long floats to 1000 decimal digits.

12.1.

Complex numbers can have a real part and an imaginary part of different types. If the imaginary part is eql to 0, the number is automatically converted to a real number. (Cf. CLtL1 p. 195) This has the advantage that (let ((x (sqrt -9.0))) (* x x)) - instead of evaluting to #C(-9.0 0.0), with x = #C(0.0 3.0) - evaluates to #C(-9.0 0) = -9.0, with x = #C(0 3.0).

Coercions on operations involving different types:

The floating point contagion is controlled by the variable *FLOATING-POINT-CONTAGION-ANSI*. When it is non-nil, contagion is done as per the ANSI CL standard: short->single->double->long.
Rationale:
See it pragmatically: save what you can and let others worry about the rest.
Short:
CL knows the number's precision, not accuracy, so preserving the precision can be accomplished reliably, while anything relating to the accuracy is just a speculation - only the user (programmer) knows what it is in each case.
Long:
A float is an approximation of a real number. One can think of it as a random variable with the mean equal to itself and standard deviation equal to half the last significant digit. E.g., 1.5 is actually 1.5+-0.05. Consider adding 1.5 and 1.75. ANSI requires that (+ 1.5 1.75) return 3.25, while traditional CLISP would return 3.3. The implied random variables are: 3.25+-0.005 and 3.3+-0.05. Note that the CLISP's way DOES lies about the mean: the mean IS 3.25 and nothing else, while the ANSI's way COULD be lying about the deviation (accuracy): if the implied accuracy of 1.5 (0.05) is its actual accuracy, then the accuracy of the result cannot be smaller that that. Therefore, since CL has no way of knowing the actual accuracy, ANSI CL (and all the other standard engineering programming languages, like C, FORTRAN etc) decides that keeping the accuracy correct is the business of the programmer, while the language should preserve what it can - the precision.
Experience:
Rounding errors accumulate, and if a computation is conducted with insufficient precision, an outright incorrect result can be returned. (E.g., E(x^2)-E(x)^2 can be negative!) The user should not mix floats of different precision (that's what *WARN-ON-FLOATING-POINT-CONTAGION* is for), but s/he should not be penalized for this too harshly.

When *FLOATING-POINT-CONTAGION-ANSI* is nil, the traditional CLISP method is used, namely:

The result of an arithmetic operation whose arguments are of different float types is rounded to the float format of the shortest (least precise) of the arguments. rational -> long float -> double float -> single float -> short float (in contrast to CLtL1 p. 195!)

Rationale:
See it mathematically. Add intervals: {1.0 ± 1e-8} + {1.0 ± 1e-16} = {2.0 ± 1e-8} So, if we add 1.0s0 and 1.0d0, we should get 2.0s0.
Shortly:
Do not suggest accuracy of a result by giving it a precision that is greater than its accuracy.
Example:
(- (+ 1.7 pi) pi) should not return 1.700000726342836417234L0, it should return 1.7f0 (or 1.700001f0 if there were rounding errors).
Experience:
If in a computation using thousands of short floats, a long float (like pi) happens to be used, the long precision should not propagate throughout all the intermediate values. Otherwise, the long result would look precise, but its accuracy is only that of a short float; furthermore much computation time would be lost by calculating with long floats when only short floats would be needed.

If the variable *warn-on-floating-point-contagion* is true, a warning is emitted for every coercion involving different floating-point types.

When rational numbers are to be converted to floats (due to float, coerce, sqrt or a transcendental function), the result type is given by the variable *default-float-format*.

The macro without-floating-point-underflow: (without-floating-point-underflow {form}*) executes the forms, with errors of type floating-point-underflow inhibited. Floating point operations will silently return zero instead of signalling an error of type floating-point-underflow.

12.4.

(lcm), called without arguments, returns 1, which is the neutral element of composition with lcm.

(! n) returns the factorial of n, n a nonnegative integer.

(exquo x y) returns the quotient x/y of two integers x,y, and checks that it is an integer. (This is more efficient than /.)

(xgcd x1 ... xn) returns the values g, c1, ..., cn, where g is the greatest common divisor of the integers x1,...,xn, and c1,...,cn are integer coefficients such that g = (gcd x1 ... xn) = (+ (* c1 x1) ... (* cn xn))

12.5.1.

(expt base exponent) is not very precise if exponent has large absolute value.

(log number base) signals an error if base = 1.

12.5.2.

The value of pi is a long float with the precision given by (long-float-digits). When this precision is changed, the value of pi is automatically recomputed. Therefore pi is a variable, not a constant.

12.6.

float-radix always returns 2.

(float-digits number digits) coerces number (a real number) to a floating point number with at least digits mantissa digits. The following holds:
(>= (float-digits (float-digits number digits)) digits)

12.7.

boole-clr = 0
boole-set = 15
boole-1 = 10
boole-2 = 12
boole-c1 = 5
boole-c2 = 3
boole-and = 8
boole-ior = 14
boole-xor = 6
boole-eqv = 9
boole-nand = 7
boole-nor = 1
boole-andc1 = 4
boole-andc2 = 2
boole-orc1 = 13
boole-orc2 = 11

12.10.

most-positive-fixnum = 224-1 = 16777215
most-negative-fixnum = -224 = -16777216

Together with pi, the other long float constants most-positive-long-float, least-positive-long-float, least-negative-long-float, most-negative-long-float, least-positive-normalized-long-float, least-negative-normalized-long-float, long-float-epsilon, long-float-negative-epsilon are recomputed whenever (long-float-digits) is changed. They are variables, not constants.

Chapter 13: Characters

See first above: 2.2.

13.1.

char-code-limit = 256
char-font-limit = 16
char-bits-limit = 16

13.2.

String-chars are those characters with font = 0 and bits = 0.

The graphic characters have been described above.

The standard characters are #\Newline and those graphic characters with a code between 32 and 126 (inclusive).

The alphabetic characters are these characters:

             ABCDEFGHIJKLMNOPQRSTUVWXYZ
             abcdefghijklmnopqrstuvwxyz
and the international alphabetic characters from the character set:
             ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜßáíóúñѪºãõØøÀÃÕ etc.

The functions char-equal, char-not-equal, char-lessp, char-greaterp, char-not-greaterp, char-not-lessp ignore bits and font attributes of their arguments.

13.4.

The characters that are not graphic chars and the space character have names:
Platform dependent: Amiga platforms only.
(code-char #x00) = #\Null
(code-char #x01) = #\Code1
(code-char #x02) = #\Code2
(code-char #x03) = #\Code3
(code-char #x04) = #\Code4
(code-char #x05) = #\Code5
(code-char #x06) = #\Code6
(code-char #x07) = #\Bell = #\Bel
(code-char #x08) = #\Backspace = #\Bs
(code-char #x09) = #\Tab = #\Ht
(code-char #x0A) = #\Newline = #\Linefeed = #\Lf
(code-char #x0B) = #\Vt
(code-char #x0C) = #\Page = #\Ff
(code-char #x0D) = #\Return = #\Cr
(code-char #x0E) = #\So
(code-char #x0F) = #\Si
(code-char #x10) = #\Code16
(code-char #x11) = #\Code17
(code-char #x12) = #\Code18
(code-char #x13) = #\Code19
(code-char #x14) = #\Code20
(code-char #x15) = #\Code21
(code-char #x16) = #\Code22
(code-char #x17) = #\Code23
(code-char #x18) = #\Code24
(code-char #x19) = #\Code25
(code-char #x1A) = #\Code26
(code-char #x1B) = #\Escape = #\Esc
(code-char #x1C) = #\Code28
(code-char #x1D) = #\Code29
(code-char #x1E) = #\Code30
(code-char #x1F) = #\Code31
(code-char #x20) = #\Space
(code-char #x7F) = #\Rubout
(code-char #x9B) = #\Csi
Platform dependent: DOS, OS/2, Win32 platforms only.
(code-char #x00) = #\Null
(code-char #x07) = #\Bell
(code-char #x08) = #\Backspace = #\Rubout
(code-char #x09) = #\Tab
(code-char #x0A) = #\Newline = #\Linefeed
(code-char #x0B) = #\Code11
(code-char #x0C) = #\Page
(code-char #x0D) = #\Return
(code-char #x1A) = #\Code26
(code-char #x1B) = #\Escape
(code-char #x20) = #\Space
Platform dependent: UNIX, Acorn platforms only.
(code-char #x00) = #\Null = #\Nul
(code-char #x01) = #\Soh
(code-char #x02) = #\Stx
(code-char #x03) = #\Etx
(code-char #x04) = #\Eot
(code-char #x05) = #\Enq
(code-char #x06) = #\Ack
(code-char #x07) = #\Bell = #\Bel
(code-char #x08) = #\Backspace = #\Bs
(code-char #x09) = #\Tab = #\Ht
(code-char #x0A) = #\Newline = #\Nl = #\Linefeed
(code-char #x0B) = #\Vt
(code-char #x0C) = #\Page = #\Np
(code-char #x0D) = #\Return = #\Cr
(code-char #x0E) = #\So
(code-char #x0F) = #\Si
(code-char #x10) = #\Dle
(code-char #x11) = #\Dc1
(code-char #x12) = #\Dc2
(code-char #x13) = #\Dc3
(code-char #x14) = #\Dc4
(code-char #x15) = #\Nak
(code-char #x16) = #\Syn
(code-char #x17) = #\Etb
(code-char #x18) = #\Can
(code-char #x19) = #\Em
(code-char #x1A) = #\Sub
(code-char #x1B) = #\Escape = #\Esc
(code-char #x1C) = #\Fs
(code-char #x1D) = #\Gs
(code-char #x1E) = #\Rs
(code-char #x1F) = #\Us
(code-char #x20) = #\Space = #\Sp
(code-char #x7F) = #\Rubout = #\Delete = #\Del

13.5.

char-control-bit = 1
char-meta-bit = 2
char-super-bit = 4
char-hyper-bit = 8

Chapter 14: Sequences

The CLtL2 function complement is implemented.

14.1.

The result of nreverse is always eq to the argument. nreverse on a vector swaps pairs of elements. nreverse on a list swaps the first and the last element and reverses the list chaining between them.

14.2.

For iteration through a sequence, a macro doseq, analogous to dolist, may be used instead of map : (doseq (var seqform [resultform]) {declaration}* {tag|statement}* )

The CLtL2 function map-into is implemented.

14.3.

remove, remove-if, remove-if-not, remove-duplicates return their argument unchanged, if no element has to be removed. delete, delete-if, delete-if-not, delete-duplicates destructively modify their argument: If the argument is a list, the cdr parts are modified. If the argument is a vector with fill pointer, the fill pointer is lowered and the remaining elements are compacted below the new fill pointer.

14.5.

sort and stable-sort have two additional keywords :start and :end :

  (sort sequence predicate &key :key :start :end)
  (stable-sort sequence predicate &key :key :start :end)

sort and stable-sort are identical. They implement the mergesort algorithm.

Chapter 15: Lists

15.4.

sublis and nsublis apply the :key argument to the nodes of the cons tree and not to the keys of the alist.

Chapter 16: Hash Tables

16.1.

make-hash-table has an additional keyword :initial-contents : (make-hash-table &key :test :initial-contents :size :rehash-size :rehash-threshold) The :initial-contents argument is an alist that is used to initialize the new hash table. The :rehash-threshold argument is ignored.

For iteration through a hash table, a macro dohash, analogous to dolist, can be used instead of maphash :

(dohash (key-var value-var hash-table-form [resultform])
  {declaration}* {tag|statement}*
)

Chapter 17: Arrays

17.1.

make-array can return specialized arrays for the element types (unsigned-byte 2), (unsigned-byte 4), (unsigned-byte 8), (unsigned-byte 16), (unsigned-byte 32) and of course bit and character.

array-rank-limit is either 65536 or 4294967296.

array-dimension-limit = 224 = 16777216
array-total-size-limit = 224 = 16777216

17.6.

An array to which another array is displaced should not be shrunk (using adjust-array) in such a way that the other array points into void space. This is not checked at the time adjust-array is called!

Chapter 18: Strings

18.2.

String comparison is based on the function char<=. Therefore diphtongs do not obey the usual national rules. Example: "o" < "oe" < "z" < "ö".

Chapter 19: Structures

19.5.

The :print-function option should contain a lambda expression (lambda (structure stream depth) (declare (ignore depth)) ...) This lambda expression names a function whose task is to output the external representation of structure onto the stream. This may be done by outputting text onto the stream using write-char, write-string, write, prin1, princ, print, pprint, format and the like. The following rules must be obeyed:

The :inherit option is exactly like :include except that it doesn't create new accessors for the inherited slots.

Chapter 20: The Evaluator

As in Scheme, the Macro (the-environment) returns the current lexical environment. This works only in interpreted code and is not compilable!

(eval-env form [env]) evaluates a form in a given lexical environment, just if the form had been part of the program text that environment came from.

Chapter 21: Streams

21.1.

Platform dependent: UNIX, DOS, OS/2 platforms only, and only in clisp binaries built without compile-time flag NO_READLINE.
Input through *terminal-io* uses the GNU readline library. Arrow keys can be used to move within the input history. The Tab key completes the symbol's name that is being typed. See readline.dvi for a complete description of the key bindings. The GNU readline library is not used if standard input and standard output do not both refer to the same terminal.

Platform dependent: UNIX, DOS, OS/2, Win32, Amiga, Acorn platforms only.
*terminal-io* is not the only stream that communicates directly with the user: During execution of the body of a (with-keyboard . body) form, *keyboard-input* is the stream that reads the keystrokes from the keyboard. It returns every keystroke in detail, as character with the following bits:
hyper
(Platform dependent: DOS, OS/2, Win32, Amiga platforms only.) if a non-standard key. These are: Function keys, cursor keypads, numeric keypad (Platform dependent: DOS, OS/2, Win32 platforms only). Function keys, cursor keypad (Platform dependent: Amiga platforms only).
char-code
the Ascii code for standard keys, for non-standard keys:
Platform dependent: DOS, OS/2 platforms only.
F1 -> #\F1, ..., F10 -> #\F10, F11 -> #\F11, F12 -> #\F12, Insert -> #\Insert, Delete -> #\Delete, Home -> #\Home, End -> #\End, PgUp -> #\PgUp, PgDn -> #\PgDn, Arrow keys -> #\Up, #\Down, #\Left, #\Right.
Platform dependent: UNIX, Win32 platforms only.
F1 -> #\F1, ..., F10 -> #\F10, F11 -> #\F11, F12 -> #\F12, Insert -> #\Insert, Delete -> #\Delete, Center -> #\Center, Home -> #\Home, End -> #\End, PgUp -> #\PgUp, PgDn -> #\PgDn, Arrow keys -> #\Up, #\Down, #\Left, #\Right.
Platform dependent: Amiga platforms only.
F1 -> #\F1, ..., F9 -> #\F9, F10 -> #\F10, Help -> #\Help, Arrow keys -> #\Up, #\Down, #\Left, #\Right.
super
(Platform dependent: DOS, OS/2, Win32, Amiga platforms only.) if pressed together with Shift key(s) and if the keystroke would have been an other without Shift.
control
if pressed together with the Control key.
meta
(Platform dependent: DOS, OS/2, Win32 platforms only.) if pressed together with the Alternate key.
This keyboard input is not echoed on the screen. During execution of a (with-keyboard . body) form, no input from *terminal-io* or any synonymous stream should be requested.

21.2.

The macro with-output-to-printer:
(with-output-to-printer (var) {declaration}* {form}*) binds the variable var to an output stream that sends its output to the printer.

Platform dependent: UNIX, OS/2, Win32 platforms only.
(make-pipe-input-stream command) returns an input stream that will supply the output from the execution of the given operating system command. See also (shell command).

(make-pipe-output-stream command) returns an output stream that will pass its output as input to the execution of the given operating system command. See also (shell command).

(make-pipe-io-stream command) 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. You 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. See also (shell command).

Generic streams

Generic streams are user programmable streams. The programmer interface:
(make-generic-stream controller)
returns a generic stream.
(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 make-generic-stream.
(generic-stream-p stream)
determines whether a stream is a generic stream, returning t if it is, nil otherwise.
In order to specify the behaviour of a generic stream, the user must define CLOS methods on the following CLOS generic functions. The function generic-stream-xyz corresponds to the Common Lisp function xyz. They all take a controller and some number of arguments.
(generic-stream-read-char controller)
Returns and consumes the next character, nil at end of file. Takes one argument, the controller object.
(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.
(generic-stream-read-byte controller)
Returns and consumes the next integer, nil at end of file. Takes one argument, the controller object.
(generic-stream-listen controller)

This generic function is used to query the stream's input status. The possible return values are the same as for the sys::real-listen function.

:eof
means EOF
:input-available
means a character (or byte) pending
:wait
means no input available.
(generic-stream-write-char controller ch)
First argument is the controller object. Second argument is the character to be written.
(generic-stream-write-byte controller by)
First argument is the controller object. Second argument is the integer to be written.
(generic-stream-write-string controller string start len)
Called with argument list (controller string start len), this function shall write (subseq (the string string) start (+ start len)) First argument is the controller object.
(generic-stream-clear-input controller)
(generic-stream-clear-output controller)
(generic-stream-finish-output controller)
(generic-stream-force-output controller)
(generic-stream-close controller)
Takes one argument, the controller object.

21.3.

The CLtL2 function open-stream-p is implemented.

close ignores its :abort argument.

The CLtL2 functions broadcast-stream-streams, concatenated-stream-streams, echo-stream-input-stream, echo-stream-output-stream, synonym-stream-symbol, two-way-stream-input-stream, two-way-stream-output-stream are implemented.

Chapter 22: Input/Output

22.1.2.

A "reserved token", i.e. a token that has potential number syntax but cannot be interpreted as a number, is interpreted as symbol when being read. (CLtL1 p. 341)

When a token with package markers is read, then (CLtL1 p. 343/344) no checking is done whether the package part and the symbol-name part do not have number syntax. (What's the purpose of this check?) So we consider tokens like USER:: or :1 or LISP::4711 or 21:3 as symbols.

22.1.3.

The backquote read macro also works when nested. Example:
   (eval ``(,#'(lambda () ',a) ,#'(lambda () ',b)))
 = (eval `(list #'(lambda () ',a) #'(lambda () ',b)))
 = (eval (list 'list (list 'function (list 'lambda nil (list 'quote a)))
                     (list 'function (list 'lambda nil (list 'quote b)))
   )     )

Multiple backquote combinations like ,,@ or ,@,@ are not implemented. Their use would be confusing anyway.

22.1.4.

#\ allows inputting characters of arbitrary code: #\Code231 yields the character (code-char 231.).

Additional read dispatch macros:

22.1.5.

The CLtL2 place readtable-case is implemented. When the value of (readtable-case readtable) is :invert, it applies to the package name and the symbol name of a symbol separately (not to the entire token at once). An alternative to the use of readtable-case is the use of the :case-sensitive option to make-package, in-package and defpackage.

22.1.6.

In absence of sys::write-float, floating point numbers are output in radix 2.

If *print-readably* is true, *read-default-float-format* has no influence on the way floating point numbers are printed.

Pathnames are printed as follows: If *print-escape* is nil, only the namestring is printed; otherwise it is printed with #P"" syntax, as per ANSI CL <PRINT-READABLY-BEHAVIOR:CLARIFY>. But, if *print-readably* is true, we are in trouble as #P"" is ambiguous (which is verboten when *print-readably* is true), while being mandated by the ANSI. Therefore, in this case, we print it like this:

#-CLISP #P"..." #+CLISP #S(PATHNAME ...)

*print-case* controls the output not only of symbols, but also of characters and some #<...> objects.

Platform dependent: UNIX, DOS, OS/2, Win32, Acorn platforms only.
*print-pretty* is initially = nil but set to t in config.lsp. This makes screen output prettier.
Platform dependent: Amiga platforms only.
*print-pretty* is initially = nil but set to t in config.lsp. This makes unbuffered screen output much faster.

*print-array* is initially = t.

An additional variable *print-closure* controls whether compiled and interpreted functions (closures) are output in detailed form. If *print-closure* /= nil, compiled closures are output in #Y syntax the reader understands. *print-closure* is initially = nil.

An additional variable *print-rpars* controls the output of right (closing) parentheses. If *print-rpars* /= nil, closing parentheses which don't fit onto the same line as the the corresponding opening parenthesis are output just below their corresponding opening parenthesis, in the same column. *print-rpars* is initially = t.

An additional variable *print-indent-lists* controls the indentation of lists that span more than one line. It specifies by how many characters items within the list will be indented relative to the beginning of the list. *print-indent-lists* is initially = 2.

The CLtL2 macro with-standard-io-syntax is implemented.

22.2.1.

The function read-char-sequence performs multiple read-char operations: (read-char-sequence sequence stream [:start] [:end]) fills the subsequence of sequence specified by :start and :end with characters consecutively read from stream. It returns the index of the first element of sequence that was not updated (= end or < end if the stream reached its end). This function is especially efficient if sequence is a string and stream is a file stream with element type character or string-char, a pipe stream or a string input stream.
(system::real-listen stream)

sys::real-listen is a variant of the standard listen function, which returns more detailed information about the stream's input status. The return value is one of:

:eof
means EOF
:input-available
means a character (or byte) pending
:wait
means no input available.

The return values are the same as for the generic-stream-listen method, so this function is a good fit to define some generic streams based upon other CLISP streams.

22.2.2.

The function read-byte-sequence performs multiple read-byte operations: (read-byte-sequence sequence stream [:start] [:end]) fills the subsequence of sequence specified by :start and :end with integers consecutively read from stream. It returns the index of the first element of sequence that was not updated (= end or < end if the stream reached its end). This function is especially efficient if sequence is a (vector (unsigned-byte 8)) and stream is a file stream with element type (unsigned-byte 8) or a pipe stream.

22.3.1.

The functions write and write-to-string have an additional keyword :closure that can be used to bind *print-closure*.

The CLtL2 macro print-unreadable-object is implemented.

The function write-char-sequence performs multiple write-char operations: (write-char-sequence sequence stream [:start] [:end]) outputs the characters of the subsequence of sequence specified by :start and :end to stream. It returns sequence. This function is especially efficient if sequence is a string and stream is a file stream with element type character or string-char or a pipe stream.

22.3.2.

The function write-byte-sequence performs multiple write-byte operations: (write-byte-sequence sequence stream [:start] [:end]) outputs the integers of the subsequence of sequence specified by :start and :end to stream. It returns sequence. This function is especially efficient if sequence is a (vector (unsigned-byte 8)) and stream is a file stream with element type (unsigned-byte 8) or a pipe stream.

22.3.3.

The format option ~W is analogous to ~A and ~S, but avoids binding of *print-escape*. (format stream "~W" object) is equivalent to (write object :stream stream).

The format option ~! is analogous to ~/, but avoids putting a function name into a string. (format stream "~!" function object) is equivalent to (funcall function stream colon-modifier-p atsign-modifier-p object).

format ~R and format ~:R can output only integers in the range |n| < 1066. The output is in English, according to the American conventions, and these conventions are identical to the British conventions only in the range |n| < 109.

format ~:@C does not output the character itself, only the instruction how to type the character.

For format ~E and format ~G, the value of *read-default-float-format* doesn't matter if *print-readably* is true.

format ~T can determine the current column of any stream.

Chapter 23: File System Interface

23.1.

For most operations, pathnames denoting files and pathnames denoting directories can not be used interchangeably.
Platform dependent: UNIX, Amiga platforms only.
For example, #"FOO/BAR" denotes the file BAR in the directory FOO, while #"FOO/BAR/" denotes the subdirectory BAR of the directory FOO.
Platform dependent: DOS, OS/2, Win32 platforms only.
For example, #"FOO\\BAR" denotes the file BAR in the directory FOO, while #"FOO\\BAR\\" denotes the subdirectory BAR of the directory FOO.
Platform dependent: Acorn platforms only.
For example, #"FOO.BAR" denotes the file FOO in the directory BAR, while #"FOO.BAR." denotes the subdirectory BAR of the directory FOO.
This is especially important for the functions directory, dir, cd, make-dir, delete-dir.

The minimum filename syntax that may be used portably is:
"xxx" for a file with name xxx,
"xxx.yy" for a file with name xxx and type yy,
".yy" for a pathname with type yy and no name specified.
Hereby xxx denote 1 to 8 characters, and yy denote 1 to 3 characters, each of which being either alphanumerical or the underscore #\_. Other properties of pathname syntax vary between operating systems.

23.1.1.

Platform dependent: DOS platforms only.
Pathname components:
host
always nil
device
nil or :wild or "A"|...|"Z"
directory
(startpoint . subdirs) where
startpoint = :relative | :absolute
subdirs = () | (subdir . subdirs)
subdir = :current (means ".") or
subdir = :parent (means "..") or
subdir = :wild-inferiors (means "...", all subdirectories) or
subdir = (name . type)
name = :wild or a simple string with 8 characters maximum
type = :wild or a simple string with 3 characters maximum
name
nil or :wild or a simple string with 8 characters maximum
type
nil or :wild or a simple string with 3 characters maximum
version
always nil (may also be specified as :wild or :newest)

When a pathname is to be fully specified (no wildcards), that means that no :wild, :wild-inferiors is allowed, and name = nil may not be allowed either.

External notation: A:\sub1.typ\sub2.typ\name.typ
using defaults: \sub1.typ\sub2.typ\name.typ
or name.typ
or *:\sub1.typ\*.*\name.*
or similar.

Instead of '\' one may use '/', as usual for DOS calls.

Platform dependent: Amiga platforms only.
Pathname components:
host
always nil
device
nil or a simple string
directory
(startpoint . subdirs) where
startpoint = :relative | :absolute
subdirs = () | (subdir . subdirs)
subdir = :wild-inferiors (means "**" or "...", all subdirectories) or
subdir = :parent (means "/" instead of "subdir/") or
subdir = simple string, may contain wildcard characters ? and *
name
nil or simple string, may contain wildcard characters ? and * (may also be specified as :wild)
type
nil or simple string, may contain wildcard characters ? and * (may also be specified as :wild)
version
always nil (may also be specified as :wild or :newest)

Constraint: startpoint = :relative only if device = nil. If the device is specified, the pathname must be absolute!

A filename from AMIGAOS is split into name and type according to the following rule:

Case is ignored in the strings on comparison. No case conversions are performed.

When a pathname is to be fully specified (no wildcards), that means that no :wild, :wild-inferiors is allowed, no wildcard characters are allowed in the strings, and name = nil may not be allowed either.

External notation: dev:sub1.typ/sub2.typ/name.typ
using defaults: sub1.typ/sub2.typ/name.typ
or name.typ
or sub1.typ/**/sub3.typ/x*.lsp
or similar.

Formal specification of the external notation:

ch ::=
any character except ':','/' and '*','?'
name ::=
{ch}+
device ::=
[ <empty> | ':' | name ':' ]
; empty = current device, relative to current directory
; ':' = current device, absolute (relative to root for disks)
; name ':' = specified device, absolute (relative to root for disks)
subdir ::=
[ <empty> | name ]
; empty means parent directory
pathname ::=
device { subdir '/' }* name

Examples:
String Device Directory our pathname
'c:foo' 'C' device->foo "c" (:absolute "foo")
'c:foo/' 'C' device->foo "c" (:absolute "foo")
'c:foo/bar' 'C' device->foo->bar "c" (:absolute "foo" "bar")
'c:/foo' 'C' device->up->foo "c" (:absolute :parent "foo")
'c:' 'C' device "c" (:absolute)
':foo' current device->root->foo nil (:absolute "foo")
'foo' current device->foo nil (:relative "foo")
'/foo' current device->up->foo nil (:relative :parent "foo")
'//foo/bar' current device->up->up->foo->bar nil (:relative :parent :parent "foo" "bar")
'' current device nil (:relative)

Appending a '/' to a path string that is non-empty and does not end with ':' or '/' does not change its meaning. This '/' must be appended before another non-empty component can be appended. But appending a '/' to a path string that is empty or ends with ':' or '/' means going up to the parent directory!
We interpret any path string that is empty or ends with ':' or '/' as pathname of a directory (with name = nil and type = nil).

Platform dependent: UNIX platforms only.
Pathname components:
host
always nil
device
always nil
directory
(startpoint . subdirs) where
startpoint = :relative | :absolute
subdirs = () | (subdir . subdirs)
subdir = :wild-inferiors (means "**" or "...", all subdirectories) or
subdir = simple string, may contain wildcard characters ? and *
name
nil or simple string, may contain wildcard characters ? and * (may also be specified as :wild)
type
nil or simple string, may contain wildcard characters ? and * (may also be specified as :wild)
version
always nil (may also be specified as :wild or :newest)

A UNIX filename is split into name and type according to the following rule:

When a pathname is to be fully specified (no wildcards), that means that no :wild, :wild-inferiors is allowed, no wildcard characters are allowed in the strings, and name = nil may not be allowed either.

External notation: server:sub1.typ/sub2.typ/name.typ
using defaults: sub1.typ/sub2.typ/name.typ
or name.typ
or sub1.typ/**/sub3.typ/x*.lsp
or similar.

Platform dependent: OS/2, Win32 platforms only.
Pathname components:
host
always nil
device
nil or :wild or "A"|...|"Z"
directory
(startpoint . subdirs) where
startpoint = :relative | :absolute
subdirs = () | (subdir . subdirs)
subdir = :wild-inferiors (means "**" or "...", all subdirectories) or
subdir = simple string, may contain wildcard characters ? and *
name
nil or simple string, may contain wildcard characters ? and * (may also be specified as :wild)
type
nil or simple string, may contain wildcard characters ? and * (may also be specified as :wild)
version
always nil (may also be specified as :wild or :newest)

An OS/2 filename is split into name and type according to the following rule:

When a pathname is to be fully specified (no wildcards), that means that no :wild, :wild-inferiors is allowed, no wildcard characters are allowed in the strings, and name = nil may not be allowed either.

External notation: A:\sub1.typ\sub2.typ\name.typ
using defaults: \sub1.typ\sub2.typ\name.typ
or name.typ
or *:\sub1.typ\**\sub3.typ\x*.lsp
or similar.

Instead of '\' one may use '/', as usual for DOS calls.

Platform dependent: UNIX, OS/2, Win32, Amiga platforms only.
The wildcard characters: '*' matches any sequence of characters, '?' matches any one character.
Platform dependent: UNIX, OS/2, Win32, Amiga platforms only.
Due to the name/type splitting rule, there are pathnames that can't result from parse-namestring. To get a pathname whose type contains a dot or whose name contains a dot and whose type is nil, make-pathname must be used. Example: (make-pathname :name ".profile").
Platform dependent: Acorn platforms only.

The Acorn file system and CLISP's interface to it

RISC OS provides several filing systems as standard (ADFS, IDEFS, NetFS, RamFS, NetPrint) and support for extra filing systems (DOSFS, ResourceFS and DeviceFS).

A module called FileSwitch is at the centre of all filing system operation in RISC OS. FileSwitch provides a common core of functions used by all filing systems. It only provides the parts of these services that are device independent. The device dependant services that control the hardware are provided by separate modules, which are the actual filing systems. FileSwitch keeps track of active filing systems and switches betwen them as necessary.

One of the filing system modules that RISC OS provides is FileCore. It takes the normal calls that FileSwitch sends to a filing system module, and converts them to a simpler set of calls to modules that control the hardware. Unlike FileSwitch it creates a fresh instantiation of itself for each module that it supports. Using FileCore to build filing system modules imposes a more rigid structure on it, as more of the filing system is predefined.

As well as standard filing systems, FileSwitch supports image filing systems. These provide facilities for RISC OS to handle media in foreign formats, and to support `image files' (or partitions) in those formats. Rather than accessing the hardware directly they rely on standard RISC OS filing systems to do so. DOSFS is an example of an image filing system used to handle DOS format discs.

Terminology
A pathname may include a filing system name, a special field, a media name (e.g., a disc name), directory name(s), and the name of the object itself; each of these parts of a pathname is known as an `element' of the pathname.

Filenames
Filename `elements' may be up to ten characters in length on FileCore-based filing systems and on NetFS. These characters may be digits or letters. FileSwitch makes no distinction between upper and lower case, although filing systems can do so. As a general rule, you should not use top-bit-set characters in filenames, although some filing systems (such as FileCore-based ones) support them. Other characters may be used provided they do not have a special significance. Those that do are listed below :
.
Separates directory specifications, e.g., $.fred
:
Introduces a drive or disc specification, e.g., :0, :bigdisc. It also marks the end of a filing system name, e.g., adfs:
*
Acts as a `wildcard' to match zero or more characters.
#
Acts as a `wildcard' to match any single character.
$
is the name of the root directory of the disc.
&
is the user root directory (URD)
@
is the currently selected directory (CSD)
^
is the `parent' directory
%
is the currently selected library (CSL)
\
is the previously selected directory (PSD)

Directories
The root directory, $, forms the top of the directory hierarchy of the media which contains the CSD. $ does not have a parent directory, trying to access its parent will just access $. Each directory name is separated by a '.' character. For example:
$.Documents.Memos
%.cc

Filing Systems
Files may also be accessed on filing systems other than the current one by prefixing the filename with a filing system specification. A filing system name may appear between '-' characters, or suffixed by a ':', though the latter is advised since '-' can also be used to introduce a parameter on a command line, or as part of a file name. For example:
-net-$.SystemMesg
adfs:%.aasm

Special Fields
Special fields are used to supply more information to the filing system than you can using standard path names; for example NetFS and NetPrint use them to specify server addresses or names. They are introduced by a '#' character; a variety of syntaxes are possible:
net#MJHardy::disc1.mike
#MJHardy::disc1.mike
-net#MJHardy-:disc1.mike
-#MJHardy-:disc1.mike
The special fields here are all MJHardy, and give the name of the fileserver to use. Special fields may use any character except for control characters, double quote '"', solidus '|' and space. If a special field contains a hypen you may only use the first two syntaxes given above.

File$Path and Run$Path
These two special variables control exactly where a file will be looked for, according to the operation being performed on it.
File$Path for read operations
Run$Path for execute operations
The contents of each variable should expand to a list or prefixes, separated by commas. When a read operation is performed then the prefixes in File$Path are used in the order in which they are listed. The first object that matches is used, whether it be a file or directory. Similarly any execute operation uses the prefixes in Run$Path. These search paths are only used when the pathname does not contain an explicit filing system reference, e.g., executing adfs:file will not use Run$Path.

Other path variables
You can set up other path variables and use them as pseudo filing systems. For example if you typed:
*Set Source$Path adfs:$.src.,adfs:$.public.src.
you could then refer to the pseudo filing system as Source: or (less preferable) as -Source-. These path variables work in the same was as File$Path and Run$Path.

NOTE: Path variables are not implemented in this version of CLISP. A workaround for this is to use "<Foo$Path>" instead of "Foo:" until they are made available.

from Lisp-string notation to internal representation
No swapping. "foo.lsp" means file type "lsp" and file name "foo". This is pseudo-BNF:
legal character ::=
any ISO latin-1 graphic character >= ' ' except '.' ':' '*' '#' '$' '&' '@' '^' '%' '\' '?'
extended legal character ::=
any ISO latin-1 graphic character >= ' ' except ':' '"' '|'
legal-wild char ::=
legal char | '*' | '#' | '?'
host ::=
'-' { extended legal char except '-' }+ '-' | { extended legal char except '-' } { extended legal char }* ':' | empty
device ::=
':' { legal char }+ '.' | empty
directory ::=
{ '$' | '&' | '@' | '%' | '\' } '.' { subdirectory }* | { subdirectory }+ | empty
'$' -> :absolute :root
'&' -> :absolute :home
'@' -> :absolute :current
'%' -> :absolute :library
'\' -> :absolute :previous
else :relative
subdirectory ::=
{ '^' | { legal-wild char }+ } '.'
'^' -> :parent
filename ::=
{ { legal-wild char }+ | empty }
filetype ::=
{ '.' { legal-wild char }+ | empty }
pathname ::=
host device directory filename filetype
Examples:
String Hostname Device Directory Name Type
-net-$.SystemMesg "net" nil (:absolute :root) "SystemMesg" nil
net#MJHardy::disc1.mike "net#MJHardy" "disc1" (:absolute :root) "mike" nil
#MJHardy::disc1.mike "#MJHardy" "disc1" (:absolute :root) "mike" nil
-net#MJHardy-:disc1.mike "net#MJHardy" "disc1" (:absolute :root) "mike" nil
-#MJHardy-:disc1.mike "#MJHardy" "disc1" (:absolute :root) "mike" nil
@.foo nil nil (:absolute :current) "foo" nil
foo nil nil (:relative) "foo" nil
^. nil nil (:relative :parent) nil nil
@.^. nil nil (:absolute :current :parent) nil nil
foo.bar nil nil (:relative) "foo" "bar"
foo.bar.baz nil nil (:relative "foo") "bar" "baz"
foo.bar. nil nil (:relative "foo" "bar") nil nil
foo.@. illegal

from internal representation to RISCOS string
with swapping only of name/type components.

Hostname Device Directory Name Type RISCOS String
"net" "disc1" (:absolute :root) "foo" nil "net::disc1.$.foo"
"net#MJ" "disc1" (:absolute :root "foo") "bar" "baz" "net#MJ::disc1.$.foo.baz.bar"
"adfs" "4" (:absolute :root "foo" "bar") nil nil "adfs::4.$.foo.bar"
nil "disc1" (:absolute :root "foo") "bar" nil ":disc1.$.foo.bar"
nil "disc1" (:absolute :current) nil nil illegal here
nil "disc1" (:relative) nil nil ":disc1."
nil "disc1" nil nil nil ":disc1."
nil nil (:absolute :root) "foo" nil "$.foo"
nil nil (:absolute :current) "foo" nil "@.foo"
nil nil (:relative) "foo" "bar" "bar.foo"
nil nil (:relative "foo") "bar" "baz" "foo.baz.bar"
nil nil (:absolute :library) "bar" nil "%.bar"
nil nil (:absolute :library "foo") "bar" nil "%.foo.bar"
nil nil (:relative) "foo" "bar" "bar.foo"
nil nil (:relative "foo") "bar" nil "foo.bar"
nil nil (:relative "foo") nil "bar" illegal here

That is, the RISCOS string is the flattenation-concatenation of


  (append
    (if (null hostname) "" (append hostname ":"))
    (if (null device) "" (append ":" device "."))
    (case (pop directory)
      (:absolute (case (pop directory)
                         (:root "$.")
                         (:home "&.")
                         (:current "@.")
                         (:library "%.")
                         (:previous "\\.")
      )          )
      (:relative "")
    )
    (mapcar (lambda (subdir) (append subdir ".")) directory)
    (if (null name)
      (if (null type) "" (error "type with name illegal here"))
      (if (null type)
        name
        (append type "." name)
  ) ) )

internal representation
Pathname components:
host
Simple-String or nil
device
Simple-String or nil
directory
(Startpoint . Subdirs) where
Startpoint = :relative | :absolute anchor
anchor = :root | :home | :current | :library | :previous
Subdirs = () | (subdir . Subdirs)
subdir = :parent or
subdir = simple string, may contain wildcard characters ?,# and *
name
nil or simple string, may contain wildcard characters ?,# and * (may also be specified as :wild)
type
nil or simple string, may contain wildcard characters ?,# and * (may also be specified as :wild)
version
always nil (may also be specified as :wild or :newest)

Constraint: startpoint /= :absolute :root only if device = nil. If the device is specified, the pathname must be :absolute :root.

The wildcard characters: '*' matches any sequence of characters, '#' or '?' matches any one character.

Due to the name/type swapping rule, there are pathnames that can't result from parse-namestring. To get a pathname whose type is nil, make-pathname must be used. Example: (make-pathname :directory "!Clisp." :name "README").

23.1.2.

External notation of pathnames (cf. parse-namestring and namestring), of course without spaces, [,],{,}:
Platform dependent: DOS platforms only.
[ [drivespec] : ] a letter '*'|'A'|...|'Z'|'a'|...|'z'
{ name [. type] \ } each one a subdirectory, '\' may be replaced by '/'
[ name [. type] ] filename with type (extension)

Name and type may be character sequences of any length (consisting of alphanumeric characters and '-', '_'). They are shortened to 8 resp. 3 characters and converted to upper case. A single '*' is allowed for :wild.

Platform dependent: Amiga platforms only.
see above.
Platform dependent: UNIX platforms only.
[ / ] / denotes absolute pathnames
{ name / } each one a subdirectory
[ name [. type] ] filename with type (extension)

Name and type may be character sequences of any length (consisting of printing ASCII characters, except '/').

Platform dependent: OS/2, Win32 platforms only.
[ [drivespec] : ] a letter '*'|'A'|...|'Z'|'a'|...|'z'
{ name [. type] \ } each one a subdirectory, '\' may be replaced by '/'
[ name [. type] ] filename with type (extension)

Name and type may be character sequences of any length (consisting of printing ASCII characters, except '/', '\', ':').

Platform dependent: Acorn platforms only.
see above.

namestring has an optional flag argument: (namestring pathname t) returns an external notation suitable for passing to the operating system or other programs.

Platform dependent: DOS, OS/2, Acorn platforms only.
The function user-homedir-pathname is not implemented.
Platform dependent: DOS, OS/2 platforms only.
If you really need that function, you might define it like this:
  (defun user-homedir-pathname (&optional host)
    (declare (ignore host))
    (or (system::getenv "HOME") "\\")
  )

23.1.4.

The CLtL2 functions wild-pathname-p, pathname-match-p and translate-pathname are implemented.

pathname-match-p does not interpret missing components as wild.

translate-pathname has two additional keywords:
(translate-pathname source from-wildname to-wildname &key :all :merge)
If :all is specified and non-nil, a list of all resulting pathnames, corresponding to all matches of (pathname-match-p source from-wildname), is returned. If :merge is specified and nil, unspecified pieces of to-pathname are not replaced by corresponding pieces of source.

23.1.5.

The functions logical-pathname, translate-logical-pathname, logical-pathname-translations, (setf logical-pathname-translations), load-logical-pathname-translations, compile-file-pathname are implemented.

When the argument of the function translate-logical-pathname is a string, it is interpreted as a logical pathname string.

rename-file always returns a non-logical pathname as its first value.

23.1.6.

(parse-namestring string [host [defaults]]) returns a logical pathname only if host is a logical host or host is nil and defaults is a logical pathname. To construct a logical pathname from a string, the function logical-pathname can be used.

(merge-pathnames string [defaults]) returns a logical pathname only if defaults is a logical pathname. To construct a logical pathname from a string, the function logical-pathname can be used.

23.2.

open cannot handle files of size >= 4 GB.
Platform dependent: UNIX, DOS, OS/2, Win32, Amiga platforms only.
The file streams returned by open are buffered for regular files and unbuffered for special files.
Platform dependent: Acorn platforms only.
The file streams returned by open are always buffered.

23.3.

probe-file can not be used to check whether a directory exists. Use the function probe-directory or the function directory for this purpose.

file-author always returns nil.

Platform dependent: DOS, OS/2, Win32 platforms only.
file-position works on any file stream. When a Newline is output to resp. input from a file stream, its file position is increased by 2 since Newline is encoded as CR/LF in the file.

23.4.

load has two additional keywords :echo and :compiling.
(load filename &key :verbose :print :echo :if-does-not-exist :compiling)
:verbose t
causes load to emit a short message that a file is being loaded. The default is *load-verbose*, which is initially = t.
:print t
causes load to print the value of each form. The default is *load-print*, which is initially = nil.
:echo t
causes the input from the file to be echoed to *standard-output* (normally to the screen). Should there be an error in the file, you can see at one glance where it is. The default is *load-echo*, which is initially = nil.
:compiling t
causes each form read to be compiled on the fly. The compiled code is executed at once and - in contrast to compile-file - not written to a file. The default is *load-compiling*, which is initially = nil.

The CLtL2 variables *load-pathname* and *load-truename* are implemented.

The variable *load-paths* contains a list of directories where program files are searched - additionally to the specified or current directory - by load, require, compile-file.

23.5.

(probe-directory pathname) tests whether pathname exists and is a directory. It will, unlike probe-file or truename, not signal an error if the parent directory of pathname doesn't exist.

The ANSI CL function ensure-directories-exist is implemented.

(directory [pathname [:full] [:circle]]) can run in two modes:

Platform dependent: UNIX platforms only.
If the :circle argument is /= nil, the function avoids endless loops that may result from symbolic links.

(dir [pathname]) is like directory, but displays the pathnames instead of returning them. (dir) shows the contents of the current directory.

Platform dependent: UNIX, Amiga platforms only.
(cd [pathname]) manages the current directory.
Platform dependent: Acorn platforms only.
(cd [pathname]) manages the current host, current device and the current directory.
Platform dependent: DOS, OS/2, Win32 platforms only.
(cd [pathname]) manages the current device and the current directory.
(cd pathname) sets it, (cd) returns it.

(default-directory) is equivalent to (cd), (setf (default-directory) pathname) is equivalent to (cd pathname).

(make-dir directory-pathname) creates a new subdirectory.

(delete-dir directory-pathname) removes an (empty) subdirectory.

Platform dependent: UNIX, DOS, OS/2, Acorn platforms only.
(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.
(execute command) executes a given command using the operating system's shell.
Platform dependent: UNIX, DOS, OS/2, Win32, Amiga, Acorn platforms only.
(shell [command]) calls the operating system's shell. (shell) calls the shell for interactive use. (shell command) calls the shell only for execution of the one given command.
Platform dependent: UNIX, OS/2, Win32 platforms only.
The functions run-shell-command and run-program are a general interface to shell and the above:

(run-shell-command command [:input] [:output] [:if-output-exists]) runs a shell command.

(run-program program [:arguments] [:input] [:output] [:if-output-exists]) runs an external program.

The command argument
specifies 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).
The program argument
specifies the program. The directories listed in the PATH environment variable will be searched for it.
The :arguments argument
specifies a list of arguments (strings) that are given to the program.
The :input argument
specifies where the program's input is to come from: either :terminal (the standard input) or :stream (a Lisp stream to be created) or a pathname (an input file) or nil (no input at all).
The :output argument
specifies where the program's output is to be sent to: either :terminal (the standard output) or :stream (a Lisp stream to be created) or a pathname (an output file) or nil (ignore the output).
The :if-output-exists argument
specifies what to do if the :output file already exists. The possible values are :overwrite, :append, :error, with the same meaning as for open.
If :stream was specified for :input or :output, a Lisp stream is returned. If :stream was specified for :input and :output, three Lisp streams are returned, as for the function make-pipe-io-stream. This use of run-program can cause deadlocks, see make-pipe-io-stream.

Chapter 24: Errors

24.1.

When an error occurred, you are in a break loop. You can evaluate forms as usual. The help command (or help key if there is one) lists the available debugging commands.

Chapter 25: Miscellaneous Features

25.1.

The compiler can be called not only by the functions compile, compile-file and disassemble, also by the declaration (compile).

(compile-file input-file [:output-file] [:listing] [:warnings] [:verbose] [:print]) compiles a file to bytecode.

input-file
should be a pathname/string/symbol.
The :output-file argument
should be nil or t or a pathname/string/symbol or an output-stream. The default is t.
The :listing argument
should be nil or t or a pathname/string/symbol or an output-stream. The default is nil.
The :warnings argument
specifies whether warnings should also appear on the screen.
The :verbose argument
specifies whether error messages should also appear on the screen.
The :print argument
specifies whether an indication which forms are being compiled should appear on the screen.
The variables *compile-warnings*, *compile-verbose*, *compile-print* provide defaults for the :warnings, :verbose, :print keyword arguments, respectively. For each input file (default file type: #".lsp") the following files are generated:
File When Default file type Contents
output file only if :output-file is not nil #".fas" can be loaded using the load function.
auxiliary output file only if :output-file is not nil #".lib" used by compile-file when compiling a require form referring to the input file.
listing file only if :listing is not nil #".lis" disassembly of the output file.
C output file only if :output-file is not nil #".c" foreign function interface; this file is deleted if it is empty.

The CLtL2 variables *compile-file-pathname* and *compile-file-truename* are implemented.

The CLtL2 special form load-time-value is implemented. (load-time-value form) is like (quote #,form) except that the former can be generated by macros.

Platform dependent: UNIX platforms only.
disassemble can disassemble to machine code, provided that GNU gdb is present. In that case the argument may be a system-function, a foreign-function, a special form indicator, a symbol denoting one of these, a number, or a string.

The CLtL2 function function-lambda-expression is implemented. (function-lambda-expression function) returns information about the source of an interpreted function: lambda-expression, lexical environment, name.

25.2.

No on-line documentation is available for the system functions (yet).

25.3.

(TRACE fun ...) makes the functions fun, ... traced. Syntax of fun: Either a symbol: symbol or a list of a symbol and some keywords and arguments (which must come in pairs!): (symbol
[:suppress-if form] no trace output as long as form is true
[:step-if form] invokes the stepper as soon as form is true
[:pre form] evaluates form before calling the function
[:post form] evaluates form after return from the function
[:pre-break-if form] goes into the break loop before calling the function if form is true
[:post-break-if form] goes into the break loop after return from the function if form is true
[:pre-print form] prints the values of form before calling the function
[:post-print form] prints the values of form after return from the function
[:print form] prints the values of form both before calling and after return from the function
)
In all these forms you can access
the function itself as *trace-function*,
the arguments to the function as *trace-args*,
the function/macro call as form as *trace-form*,
after return from the function: the list of return values from the function call as *trace-values*,
and you can leave the function call with specified values by using return.

trace and untrace are also applicable to functions (setf symbol) and to macros, but not to locally defined functions and macros.

The macro space is like the macro time: (space form) evaluates the form, and, as a side effect, outputs information about the memory allocations caused by this evaluation.

The function inspect is not implemented.

The function room returns two values: the number of bytes currently occupied by Lisp objects, and the number of bytes that can be allocated before the next regular garbage collection occurs.

The function ed calls the external editor specified by the variable *editor* (see config.lsp).

Platform dependent: UNIX, DOS, OS/2, Amiga platforms only.
If using the optional package editor:
ed behaves like this only if the variable *use-ed* is nil. Otherwise ed uses a screen editor with multiple windows.

The function uncompile does the converse of compile: (uncompile function-name) reverts an interpreted function that has been entered or loaded in the same session and then compiled back to its interpreted form.

25.4.1.

Platform dependent: DOS, OS/2, Amiga, Acorn platforms only.
The variable *default-time-zone* contains the default time zone used by encode-universal-time and decode-universal-time. It is initially set to -1 (which means 1 hour east of Greenwich, i.e. Mid European Time).

The timezone in a decoded time must not necessarily be an integer, but (as float or rational number) it should be a multiple of 1/4.

Platform dependent: DOS, OS/2, Acorn platforms only.
internal-time-units-per-second = 100.
Platform dependent: Amiga platforms only.
internal-time-units-per-second = 50.
Platform dependent: most UNIX platforms only.
internal-time-units-per-second = 1000000.
Platform dependent: Win32 platforms only.
internal-time-units-per-second = 10000000.

25.4.2.

Platform dependent: UNIX, Win32 platforms only.
The functions short-site-name, long-site-name should be defined in a site-specific config.lsp file.
Platform dependent: DOS, OS/2, Amiga, Acorn platforms only.
The functions machine-type, machine-version, machine-instance and short-site-name, long-site-name should be defined by every user in his site-specific config.lsp file.

The variable *features* initially contains the symbols
:CLISP this implementation
:COMMON-LISP
:CLTL2
:INTERPRETER
:COMPILER
:LOGICAL-PATHNAMES
:FFI if a foreign function interface is supported (Platform dependent: many UNIX, Win32 platforms only)
:GETTEXT if internationalization using the GNU gettext package is supported (Platform dependent: most UNIX platforms only)
:LOOP
:CLOS
:AMIGA if hardware = Amiga and operating system = Exec/AmigaDOS
:DOS if hardware = PC (clone) and operating system = DOS
:OS/2 if hardware = PC (clone) and operating system = OS/2
:WIN32 if hardware = PC (clone) and operating system = Win32 (Windows NT or Windows 95)
:PC386 if hardware = PC (clone) with a 386/486/586/686
:UNIX if operating system = Unix (yes, in this case the hardware is irrelevant!)

Chapter 26: Loop

The CLtL2 macros loop and loop-finish are implemented.

Chapter 27: Pretty Printing

The CLtL2 macro formatter is implemented.

Chapter 28: Common Lisp Object System

The CLOS symbols are exported from the package "CLOS" and thus normally visible in all user packages. If you don't want them (for example, if you want to use PCL instead of CLOS), do (unuse-package "CLOS").

The functions
slot-value, slot-boundp, slot-makunbound, slot-exists-p, find-class, (setf find-class), class-of, call-next-method, next-method-p, class-name, (setf class-name), no-applicable-method, no-next-method, find-method, add-method, remove-method, compute-applicable-methods, method-qualifiers, function-keywords, slot-missing, slot-unbound, print-object, describe-object, make-instance, initialize-instance, reinitialize-instance, shared-initialize,
the macros
with-slots, with-accessors, defclass, defmethod, defgeneric, generic-function, generic-flet, generic-labels,
the classes
standard-class, structure-class, built-in-class, standard-object, standard-generic-function, standard-method and all predefined classes,
and the method combination
standard
are implemented.

Deviations from CLtL2 chapter 28:

defclass : It is required that the superclasses of a class be defined before the defclass form for the class is evaluated.

defclass supports the option :metaclass structure-class. This option is necessary in order to define a subclass of a defstruct-defined structure type using defclass instead of defstruct.

The real type is added to the predefined classes listed in table 28-1.

Only standard method combination is implemented.

When call-next-method is called with arguments, the rule that the ordered set of applicable methods must be the same as for the original arguments is enforced by the implementation only in interpreted code.

call-next-method and next-method-p are local macros, not local functions. Use #'(lambda () (call-next-method)) instead of #'call-next-method if you really need it as a function.

There is a generic function no-primary-method (analogous to no-applicable-method) which is called when a generic function of the class standard-generic-function is invoked and no primary method on that generic function is applicable.

generic-flet and generic-labels are implemented as macros, not as special forms.

The function ensure-generic-function is not implemented.

add-method can put methods into other generic functions than the one the method came from.

print-object and describe-object are only called on objects of type standard-object.

describe-object should not call describe recursively as this would produce more information than is likely to be useful to a human reader.

documentation still has the CLtL1 implementation.

User-defined method combination is not supported. The sections 28.1.7.3., 28.1.7.4., the macros define-method-combination, call-method and the functions invalid-method-error, method-combination-error, method-qualifiers are not implemented.

The special form with-added-methods is not implemented.

Redefining classes is not supported. The sections 28.1.10., 28.1.10.1., 28.1.10.2., 28.1.10.3., 28.1.10.4. and the function update-instance-for-redefined-class are not implemented.

Changing the class of a given instance is not supported. The sections 28.1.11., 28.1.11.1., 28.1.11.2., 28.1.11.3. and the functions change-class, update-instance-for-different-class, make-instances-obsolete are not implemented.

Chapter 29: Conditions

29.4.1.

The default condition type for conditions created by signal is simple-condition, not simple-error.

29.4.4.

The macro (muffle-cerrors {form}*) executes the forms. When a continuable error occurs, no message is printed. Instead, the continue restart is invoked.

The macro (appease-cerrors {form}*) executes the forms. When a continuable error occurs, the error is printed as a warning and the continue restart is invoked.

The macro (exit-on-error {form}*) executes the forms. When a non-continuable error or a Ctrl-C interrupt occurs, the error is printed and CLISP terminates with error status.

29.4.7.

In restart-case clauses the argument list can also be specified after the keyword/value pairs instead of before them. The syntax therefore is (restart-case form {restart-clause}*) with
restart-clause ::= (restart-name arglist {keyword value}* {form}*)
| (restart-name {keyword value}* arglist {form}*)

The macro with-restarts is like restart-case, except that the forms are specified after the restart clauses instead of before them, and the restarts created are not implicitly associated to any condition. (with-restarts ({restart-clause}*) {form}*) is therefore equivalent to (restart-case (progn {form}*) {restart-clause}*).

29.4.8.

compute-restarts and find-restart behave as specified in ANSI CL: If the optional condition argument is not nil, only restarts associated with that condition and restarts associated to no condition at all are considered. Therefore the effect of associating a restart to a condition is not to activate it, but to hide it from other conditions. This makes the syntax dependent implicit association performed by restart-case nearly obsolete.

29.4.9.

The default condition type for conditions created by warn is simple-warning, not simple-error.

Chapter 90: Platform independent Extensions

90.1. Saving an Image

The function (saveinitmem [filename [:quiet] [:init-function]]) saves the running CLISP's memory to a file. The filename defaults to "lispinit.mem". 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.

90.2. Quitting Lisp

The functions (exit [errorp]), (quit [errorp]) and (bye [errorp]) - all synonymous - terminate CLISP. If errorp is not nil, CLISP aborts with error status, i.e. the environment is informed that the CLISP session didn't succeed.

90.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 deflanguage: (deflanguage lang) For such an additional language to take effect, you must install the corresponding message catalog, or translate the messages yourself, by use of 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 definternational:
(definternational symbol [(t default-language)]),
and add language-dependent values through the macro deflocalized:
(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 through the function call (localized symbol [language]).

90.4. Finalization

Calling (finalize object function) has the effect that when the specified object is being garbage collected, (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 garbage collected: When object is being garbage collected, (funcall function object guardian) will be executed. If the guardian is garbage collected before object is, nothing happens.

Note: The time when "object is being garbage collected" is not defined deterministically. (Actually, it possibly never occurs.) 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.

90.5. The Prompt

The variable sys::*prompt* controls the appearance of the prompt. When its value is a function, it is called and it's 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* if it is the same as it was in the beginning or if it doesn't 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, 2 functions are provided: sys::prompt-new-package, returning *package* 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 (you might also want to reset it).

Chapter 91: The Debugger and Stepper

The debugger may be invoked through the functions invoke-debugger, break, signal, error, cerror, warn. The stepper is invoked through the macro step. Debugger and stepper execute subordinate read - eval - print loops (called "break loops") which are analogous to the main read - eval - print loop except for the prompt and the set of available commands. Commands must be typed literally, without surrounding quotes or white space.

Commands common to the main loop, the debugger and the stepper:
Help prints a list of available commands.

Commands common to the debugger and the stepper:
Abort abort to the next most recent read - eval - print loop.
Unwind abort to the next most recent read - eval - print loop.

The stack is organized into frames and other stack elements. Usually every invocation of an interpreted function and every evaluation of an interpreted form corresponds to one stack frame. Special forms such as let, let*, unwind-protect and catch produce special kinds of stack frames.

In a break loop there is a current stack frame, which is initially the most recent stack frame but can be moved using the debugger commands Up and Down.

Evaluation of forms in a break loop occurs in the lexical environment of the current stack frame but in the dynamic environment of the debugger's caller. This means that to inspect or modify a lexical variable all you have to do is to move to the current stack frame just below the frame that corresponds to the form or the function call that binds that variable.

There is a current "stack mode" which defines in how much detail the stack is shown by the stack related debugger commands.

Commands common to the debugger and the stepper:
Mode-1 sets the current mode to 1: all the stack elements are considered. This mode is fine for debugging compiled functions.
Mode-2 sets the current mode to 2: all the frames are considered.
Mode-3 sets the current mode to 3: only lexical frames (frames that correspond to special forms that modify the lexical environment) are considered.
Mode-4 sets the current mode to 4 (the default): only eval and apply frames are considered. Every evaluation of a form in the interpreter corresponds to an EVAL frame.
Mode-5 sets the current mode to 5: only apply frames are considered. Every invocation of an interpreted function corresponds to one apply frame.
Where shows the current stack frame.
Up goes up one frame, i.e. to the caller if in mode-5
Down does down one frame, i.e. to the callee if in mode-5
Top goes to top frame, i.e. to the top-level form if in mode-4
Bottom goes to bottom (most recent) frame, i.e. most probably to the form or function that caused the debugger to be entered.
Backtrace lists the stack in current mode, bottom frame first, top frame last.
Backtrace-1 lists the stack in mode 1.
Backtrace-2 lists the stack in mode 2.
Backtrace-3 lists the stack in mode 3.
Backtrace-4 lists the stack in mode 4.
Backtrace-5 lists the stack in mode 5.
If the current stack frame is an eval or apply frame, the following commands are available as well:
Break+ sets a breakpoint in the current frame. When the corresponding form or function will be left, the debugger will be entered again, with the variable *trace-values* containing a list of its values.
Break- removes a breakpoint from the current frame.
Redo re-evaluates the corresponding form or function call. This command can be used to restart parts of a computation without aborting it entirely.
Return leaves the current frame. You will be prompted for the return values.

Commands specific to the debugger:
Continue continues evaluation of the program.

Commands specific to the stepper:
Step step into a form: evaluate this form in single step mode
Next step over a form: evaluate this form at once
Over step over this level: evaluate at once up to the next return
Continue switch off single step mode, continue evaluation

The stepper is usually used like this: If some form returns a strange value or results in an error, call (step form) and navigate using the commands Step and Next until you reach the form you regard as responsible. If you are too fast (execute Next once and get the error), there is no way back; you have to restart the entire stepper session. If you are too slow (stepped into a function or a form which certainly is OK), a couple of Next commands or one Over command will help.

Chapter 99: Platform specific Extensions

99.1. The Editor

Undocumented.

99.2. Random Screen Access

Platform dependent: UNIX, DOS, OS/2, Amiga 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* shouldn't be used for input or output during this time. (Use with-keyboard and *keyboard-input* 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* shouldn't 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.

99.3. External Modules

Platform dependent: UNIX platforms only.

CLISP has a facility for adding external modules (written in C, 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 compiler
CFLAGS
flags for the C compiler, when compiling
CLFLAGS
flags for the C 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
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"/.
The NEW_FILES variable
shall contain a space-separated list of files that belong to the module set and will belong to every new linking set.
The NEW_LIBS variable
shall contain a space-separated list of files or C compiler switches that need to be passed to the C compiler when linking the lisp.run belonging to a new linking set.
The NEW_MODULES variable
shall contain a 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.
The TO_LOAD variable
shall contain a space-separated list of Lisp files to load before building the lispinit.mem belonging to a new linking set.
The TO_PRELOAD variable, if defined,
shall contain a 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:
       NEW_LIBS="$file_list"
       -->
       NEW_LIBS="$file_list -lm"
    
    Modify the newly created linux/link.sh to load linux.fas before saving the memory image:
       TO_LOAD=''
       -->
       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")
    

99.4. 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 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 and ANSI C.

(def-c-type name c-type)

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

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

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

(def-c-call-out name {option}*)
option ::=
(:name c-name)
| (:arguments {(arg-name c-type [param-mode [allocation]])}*)
| (:return-type c-type [allocation])

(def-c-call-in name {option}*)
option ::=
(:name c-name)
| (:arguments {(arg-name c-type [param-mode [allocation]])}*)
| (:return-type c-type [allocation])

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

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

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

(element c-place {index}*)
(deref c-place)
(slot c-place slot-name)
(cast c-place c-type)

(typeof c-place)
(sizeof c-place), (sizeof c-type)
(bitsizeof c-place), (bitsizeof c-type)

(validp foreign-entity)

name is any Lisp symbol.

c-name is a string.

(Foreign) C types

Foreign C types are used in the FFI. They are not regular Common Lisp types or CLOS classes.

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

The simple C types are these:
Lisp name Lisp equiv C equiv ILU equiv Comment
nil nil void as a result type only
boolean boolean int BOOLEAN
character character char SHORT CHARACTER
char integer signed char
uchar integer unsigned char
short integer short
ushort integer unsigned short
int integer int
uint integer unsigned int
long integer long
ulong integer unsigned long
uint8 (unsigned-byte 8) uint8 BYTE
sint8 (signed-byte 8) sint8
uint16 (unsigned-byte 16) uint16 SHORT CARDINAL
sint16 (signed-byte 16) sint16 SHORT INTEGER
uint32 (unsigned-byte 32) uint32 CARDINAL
sint32 (signed-byte 32) sint32 INTEGER
uint64 (unsigned-byte 64) uint64 LONG CARDINAL does not work on all platforms
sint64 (signed-byte 64) sint64 LONG INTEGER does not work on all platforms
single-float single-float float
double-float double-float double

The predefined C types are:
c-type ::=
simple-c-type
| c-pointer
| c-string
| (c-struct class (ident c-type)*)
| (c-union (ident c-type)*)
| (c-array c-type dimensions)
dimensions ::= number | ({number}*)
| (c-array-max c-type maxdimension)
maxdimension ::= number
| (c-function {option}*)
option ::=
  (:arguments {(arg-name c-type [param-mode [allocation]])}*)
| (:return-type c-type [allocation])
| (:language language)
| (c-ptr c-type)
| (c-ptr-null c-type)
| (c-array-ptr c-type)

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

The type c-pointer corresponds to what C calls "void*", an opaque pointer.

The type c-string corresponds to what C calls "char*", a zero-terminated string. Its Lisp equivalent is a string, without the trailing zero character.

The type (c-struct class (ident1 type1) ... (identn typen)) is equivalent to what C calls "struct { type1 ident1; ...; typen identn; }". Its Lisp equivalent is: if class is vector, a simple-vector; if class is list, a list; if class is a symbol naming a structure or CLOS class: an instance of this class, with slots of names ident1,...,identn.

The type (c-union (ident1 type1) ... (identn typen)) is equivalent to what C calls "union { type1 ident1; ...; typen identn; }". Conversion to and from Lisp assumes that a value is to be viewed as being of type1.

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

The type (c-array-max type maxdim) is equivalent to what C calls "type [maxdim]", an array containing up to maxdim elements. The array is zero-terminated if it contains less than maxdim elements. Conversion from Lisp of an array with more than maxdim elements silently ignores the superfluous elements.

The type (c-ptr type) is equivalent to what C calls "type *": a pointer to a single item of the given type.

The type (c-ptr-null type) is also equivalent to what C calls "type *": a pointer to a single item of the given type, with the exception that C NULL corresponds to Lisp nil.

The type (c-array-ptr type) is equivalent to what C calls "type (*)[]": a pointer to a zero-terminated array of items of the given type.

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

(def-c-struct name (ident c-type)*) defines name to be both a defstruct structure type and a foreign C type with the given slots.

(def-c-enum name {ident | (ident [value])}*) defines idents as constants, similarly to the C declaration enum { ident [= value], ... };

(c-lines format-string {argument}*) outputs the string (format nil format-string {argument}*) to the C output file. This is a rarely needed low-level facility.

The form (sizeof c-type) returns the size and alignment of a C type, measured in bytes.

The form (bitsizeof c-type) returns the size and alignment of a C type, measured in bits.

The predicate (validp foreign-entity) 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 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.

(def-c-var name {option}*)
option ::=
(:name c-name)
| (:type c-type)
| (:read-only boolean)
| (:alloc allocation)
defines a foreign variable. name is the Lisp name, a regular Lisp symbol.

The :name option specifies the name, as seen from C, 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 or :malloc-free and defaults to :none. If it is :malloc-free, 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, 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.

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 terminology.) The following operations are available on foreign places:

(element place index1 ... indexn)
Array element: If 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 place index1 ... indexn) or place[index1]...[indexn]. It is a place of type c-type. If place is of foreign type (c-array-max c-type dim) and 0 <= index < dim, this will be the place corresponding to (aref place index) or place[index]. It is a place of type c-type.

(deref place)
Dereference pointer: If 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 place may not be NULL.

(slot place slot-name)
Struct or union component: If 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 place c-type)
Type change: A place denoting the same memory locations as the original place, but of type c-type.

(typeof place)
returns the c-type corresponding to the place.

(sizeof place)
returns the size and alignment of the C type of place, measured in bytes.

(bitsizeof place)
returns the size and alignment of the C type of place, measured in bits.

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.

(def-call-out name {option}*)
option ::=
(:name c-name)
| (:arguments {(arg-name c-type [param-mode [allocation]])}*)
| (:return-type c-type [allocation])
| (:language language)
defines a named call-out function. Any Lisp function call to #'name is redirected to call the C function c-name.

def-c-call-out is equivalent to def-call-out with :language :c.

(def-call-in name {option}*)
option ::=
(:name c-name)
| (:arguments {(arg-name c-type [param-mode [allocation]])}*)
| (:return-type c-type [allocation])
| (:language language)
defines a named call-in function. Any C function call to the C function c-name is redirected to call the Lisp function #'name.

def-c-call-in is equivalent to def-call-in with :language :c.

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 is :none means that no storage is allocated.
allocation is :alloca means allocation of storage on the stack, which has dynamic extent.
allocation is :malloc-free means that storage will be allocated via malloc() and freed via free().
If no allocation is specified, the default allocation is :none for most types, but :alloca for c-string and (c-ptr ...) and (c-ptr-null ...) and (c-array-ptr ...) and for :out arguments. [Subject to change!] The :malloc-free 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:
If allocation is :malloc-free,
Lisp allocates the storage using malloc() and never deallocates it. The C function is supposed to call free() when done with it.
If allocation is :alloca,
Lisp allocates the storage on the stack, with dynamic extent. It is freed when the C function returns.
If allocation is :none,
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 to Lisp:
If allocation is :malloc-free,
Lisp calls free() on it when done.
If allocation is :none,
Lisp does nothing.
For call-in functions:
For arguments passed from C to Lisp:
If allocation is :malloc-free,
Lisp calls free() on it when done.
If allocation is :alloca or :none,
Lisp does nothing.
For results passed from Lisp to C:
If allocation is :malloc-free,
Lisp allocates the storage using malloc() and never deallocates it. The C function is supposed to call free() when done with it.
If allocation is :none,
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 param-mode may be

either :in (means: read-only):
The caller passes information to the callee.
or :out (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.
or :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" value is returned as an additional multiple value.
The default is :in.

[Currently, only :in is fully implemented. :out works only with allocation = :alloca.]

Platform dependent: Amiga platforms only.
allocation may not be :malloc-free 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 compiler supports it. Most C compilers do it right, but some C compilers (such as gcc on hppa) have problems with this.

Examples

Ex. 1: The C 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)
Ex. 2: Here is an example of an external C 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)))
Ex. 3: An example for calling an external function: On ANSI C 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)
Ex. 4: 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" (don't 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.

Ex. 5: To sort an array of double-floats using the Lisp function sort instead of the C 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

99.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 or linker support. Memory images can be created, provided that the function libraries are opened at run-time.

Therefore, AFFI supports only primitive C 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 KEYWORD 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's 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 cheks 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 or unsigned-byte vector into memory.

nzero-pointer-p tests for non-NULL pointers in all recognized representations (null, unsigned-byte 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 preceeded 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 types

The following foreign C types are used in AFFI. They are not regular Common Lisp types or CLOS classes.

AFFI name Lisp equiv C equiv Comment
nil nil void as a result type for functions only
4 (unsigned-byte 32) unsigned long
2 (unsigned-byte 16) unsigned short
1 (unsigned-byte 8) unsigned char
-4 (signed-byte 32) long
-2 (signed-byte 16) short
-1 (signed-byte 8) signed char
0 boolean BOOL as a result type for functions only
* opaque void*
:external opaque void*
string string or vector char*
:io string or vector char*

Objects of type string 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 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 (or string) type parameters). Arguments of type integer and foreign-pointer are always acceptable where a string or :io type is specified.

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's 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 is the following: * uses integers, :external uses foreign-pointer as function result-type (except from nil for a NULL pointer) and refuses objects of type string or unsigned byte vector as input. Thus :external 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 funtion 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 or unsigned byte vector, it can fill this vector. :external 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 the library 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 keword (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, string or :external 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.

1. 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.

2. Using flibcall

(use-package "AFFI")

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

;; 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)

3. Be fully dynamic, defining library bases ourselves

(use-package "AFFI")

(eval-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)))

4. Some sample function definitions

(defflibfun 'FindTask 'SysBase -294 #xA '* 'string)
(declare-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)))

99.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 :string :result :token :io :host)
-> (RC &optional result), or nil on failure

(REXX-RUN-COMMAND command &KEY :string :token)
-> t, or nil on failure

(REXX-SEND-COMMAND command &KEY :string :result :token :io :host)
-> arexx-msg-handle, or nil on failure

(REXX-WAIT-SENT-COMMAND arexx-msg-handle)
-> (RC &optional 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 asynchronouns 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.

99.6. Graphics Primitives

Platform dependent: Linux/x86, DOS, OS/2 platforms only.

In CLISP 1994-01-07 or newer,

there are some pixel graphics primitives in the SYSTEM package. They operate on a VGA card.

Similar pixel graphics primitives can be used in the

by use of the small xterm package available on ftp2.cons.org.

This is the description of the PC/VGA graphics primitives:

(system::graph-init [width [height [colors]]])
initializes the graphics system. The width, height parameters are hints for the size of the desired graphics screen (positive integers). The colors parameter is a hint for the number of colors. The actual width, height is implementation dependent, currently up to 640x480 on VGA cards and up to 1024x768 on ET4000 SVGA cards. Returns an alist ((color-value color-keyword) ...) which lists the available colours and their numerical equivalents.
(system::graph-show)
switches the graphics hardware so that the graphics screen is visible. The text screen is activated on any text output.
(system::graph-clear [color])
fills the entire graphics screen with a single color.
(system::graph-dims)
returns two values: the actual width and the actual height of the graphics screen (in pixels).
If (system::graph-dims) returns the values w and h, then valid screen coordinates are pairs (x,y) with 0 <= x < w and 0 <= y < h. x=0 denotes the left edge, y=0 the top edge.
(system::graph-dot x y)
returns the colour of the pixel (x,y).
(system::graph-dot x y color)
sets the colour of the pixel (x,y) to color.
(system::graph-box x1 y1 x2 y2 color)
draws a box (= filled rectangle) in colour color, the vertices being the pixels
(x1,y1) (x2,y1)
(x1,y2) (x2,y2)
(system::graph-line x1 y1 x2 y2 color)
Draws a line in colour color from pixel (x1,y1) to pixel (x2,y2).
(system::graph-text x y dir string color)
Paints the text contained in string, starting at (x,y), in colour color, and returns as values the end coordinates (x,y). dir is the direction: 0 goes to the right, 90 vertically up, 180 to the left, 270 vertically down.

This specification is subject to change.

99.7 Socket Streams

Platform dependent: UNIX, Win32 platforms only.
(socket-server [port-or-socket])
This function creates a socket, and binds a port 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) or a socket-stream (from whose peer the connections will be made).
(socket-server-close socket-server)
Closes down the server socket.
(socket-server-port socket-server)
Returns the port which was bound using socket-server.
(socket-wait socket-server [seconds [microseconds]])
Given time argument(s), waits for (possibly zero) fixed duration for a connect on the socket-server. Without an argument, socket-wait blocks indefinitely.
(socket-accept socket-server)
Creates the server-side two-way stream for the connection.
(socket-connect port [host])
Attempts to create a client-side two-way stream. Blocks until the server accepts the connections.
(socket-stream-host socket-stream)
(socket-stream-port socket-stream)
These two functions return information about the socket stream. For a server, socket-stream-host returns nil.
(socket-service-port "service-name")
A convenience function for looking up a port given the service name.
(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.
(socket-stream-local socket-stream)
The dual to socket-stream-peer - same information, host name and port number, but for the local host.

99.8. CLISP as a script interpreter

Platform dependent: UNIX platforms only.

On Unix, a script can be made executable by adding a first line of the form

#!interpreter [interpreter-args]
and chmoding the script to be executable. CLISP can be used as a script interpreter under the following circumstances:
  1. The interpreter must be a full pathname of CLISP. I recommend using /usr/local/bin/clisp, and if CLISP is actually installed elsewhere, letting /usr/local/bin/clisp be a symbolic link to the real CLISP.

  2. The CLISP 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 compiler cannot be assumed to be installed on this platform. If you have a C compiler installed, build CLISP from source yourself; "make install" will install clisp as a real executable.

  3. On some platforms, the first line "#!interpreter [interpreter-args]" 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.

  4. 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 *args* is bound to a list of strings, representing the arguments given to the Lisp script. *standard-input* and *standard-output* are bound, as usual, to the Unix standard input and output. *error-output* 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.

99.9. Other

Platform dependent: Amiga platforms only.
To have *debug-io* and *error-output* point to separate console windows (thus keeping your standard console window clean from error messages) you can use
  (setq *error-output*
    (setq *debug-io*
      (open "CON:0/0/500/300/CLISP-Debugger/AUTO/CLOSE" :direction :io)
  ) )
at startup.

Authors

Bruno Haible Michael Stoll
17, rue Danton Westerwaldweg 22
F - 94270 Le Kremlin-Bicêtre D - 53424 Remagen-Oberwinter
France Germany

Maintainer


CLISP implementation notes
Bruno Haible <haible@clisp.cons.org>

Last modified: 13 December 1997.