Copyright © 1992-2003 by Bruno Haible
Copyright © 1998-2003 by Sam Steingold
These notes are covered by the GNU GFDL:
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License (GFDL), Version 1.2 or any later version published by the Free Software Foundation (FSF); with no Invariant Sections, with no Front-Cover Text, and with no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License."
These notes discuss the CLISP implementation of Common Lisp by
and
Dr Bruno Haible
Louisenstraße 103
Bad Homburg
D-61348 Germany
http://www.haible.de/bruno/
The current maintainers are
Dr Michael Stoll
Westerwaldweg 22
Remagen-Oberwinter
D-53424 Germany
http://www.math.uni-duesseldorf.de/~stoll/
and
Dr Bruno Haible
Dr Sam Steingold
http://www.podval.org/~sds/
This implementation is mostly conforming to the [ANSI CL standard] available on-line as the [Common Lisp HyperSpec] (but the printed ANSI document remains the authoritative source of information). [ANSI CL standard] supersedes the earlier specifications [CLtL1] and [CLtL2].
The first part of these notes is indexed in parallel to the [Common Lisp HyperSpec] and documents how CLISP implements the standard [ANSI CL standard].
The second part documents the CLISP extensions, i.e., the functionality that goes beyond the [ANSI CL standard] requirements.
The third part is intended mostly for developers as it documents the CLISP internals, e.g., garbage-collection, adding new built-ins, and the bytecodes generated by the compiler (i.e., what is printed by DISASSEMBLE).
The final delimiter of an interactive stream: On UNIX, the user has to type Control-D at the beginning of a line. On DOS or Win32, the user has to type Control-Z, followed by Return. This final delimiter is never actually seen by programs; no need to test for #\^D or #\^Z - use READ-CHAR-NO-HANG to check for end of stream. Calling CLEAR-INPUT on the stream removes the end-of-stream state, thus making it available for further input.
A newline character can be entered by the user by pressing the Newline key or, on the numeric keypad, the Enter key.
Safety settings are ignored; therefore where the standard uses the phrase "should signal an error", an ERROR is SIGNALed.
The class precedence lists of the system classes CLASS BUILT-IN-CLASS, STRUCTURE-CLASS, STANDARD-CLASS, STANDARD-METHOD contain the class STRUCTURE-OBJECT instead of the class STANDARD-OBJECT.
The 6 symbols missing from the "COMMON-LISP" package (out of 978 specified by the [ANSI CL standard]):
CALL-METHOD | DEFINE-METHOD-COMBINATION | INVALID-METHOD-ERROR |
MAKE-METHOD | METHOD-COMBINATION-ERROR | METHOD-COMBINATION |
The requirement of step 4 that a "reader macro function may return zero values or one value" is enforced. You can use the function VALUES to control the number of values returned.
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.
When creating a symbol from a token, no character attributes are removed.
When a token with package markers is read, then 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.
Reader macros are also defined for the following:
Table 2-1. Additional reader macros
Macro | Meaning |
---|---|
#, | load-time evaluation |
#Y | function objects and file EXT:ENCODINGs |
#"" | pathname |
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).
Macro EXT:THE-ENVIRONMENT. As in Scheme, the macro (EXT:THE-ENVIRONMENT) returns the current lexical environment. This works only in interpreted code and is not compilable!
Function (EXT:EVAL-ENV form &OPTIONAL env). evaluates a form in a given lexical environment, just as if the form had been a part of the program that the environment came from.
Compiler macros are expanded in the compiled code only, and ignored by the interpreter.
The declarations (TYPE type variable ...), (FTYPE type function ...), (OPTIMIZE (quality value) ...) are ignored by the interpreter and the compiler.
The [ANSI CL standard] declaration (OPTIMIZE (debug ...)) is legal.
The [ANSI CL standard] declaration (IGNORABLE variable ...) affects the variable binding for the variable variable. The compiler will not warn about the variable, regardless whether it is used or not.
The declaration (COMPILE) has the effect that the current form is compiled prior to execution. Examples:
(LOCALLY (DECLARE (compile)) form) |
(LET ((x 0)) (FLET ((inc () (DECLARE (compile)) (INCF x)) (dec () (DECF x))) (VALUES #'inc #'dec))) |
The type assertion (THE value-type form) enforces a type check in interpreted code. No type check is done in compiled code. See also the EXT:ETHE macro.
The initial value of an &AUX variable in a boa lambda list is the value of the corresponding slot's initial form.
(PROCLAIM '(SPECIAL variable)) declarations cannot 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.
constant variables may not be bound dynamically or lexically.
Function EXT:SPECIAL-VARIABLE-P. You can use the function (EXT:SPECIAL-VARIABLE-P symbol &OPTIONAL env) to check whether the symbol is a special variable. env of NIL or omitted means use the global environment, T means use current lexical environment. You can also obtain the current lexical environment using the macro EXT:THE-ENVIRONMENT (interpreted code only). This function will always return T for global special variables and constants. Note that this function will not work in compiled code as you expect: when called with NIL env, it will be called at run time and check for globally special variables, but when env is T, it will be called at compile time and the value will be used as a constant in the code.
Function CONSTANTP fully complies with [ANSI CL standard]. Additionally, some non-trivial forms are identified as constants, e.g., (CONSTANTP '(+ 1 2 3)) returns T.
EVAL-WHEN also accepts the situations (NOT EVAL) and (NOT COMPILE).
![]() | Note that the situations EVAL, LOAD and COMPILE are deprecated by the spec, and they are not equivalent to the new standard situations :EXECUTE, :LOAD-TOPLEVEL and :COMPILE-TOPLEVEL in that they ignore the top-level versus non-top-level distinction. |
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).
The [ANSI CL standard] type specifier (REAL low high) denotes the real numbers between low and high.
DEFTYPE lambda lists are subject to destructuring (nested lambda lists are allowed, as in DEFMACRO) and may contain a &WHOLE marker, but not an &ENVIRONMENT marker.
Function (EXT:TYPE-EXPAND typespec &OPTIONAL once-p). If typespec is a user-defined type, this will expand it recursively until it is no longer a user-defined type (unless once-p is supplied and non-NIL). Two values are returned - the expansion and an indicator (T or NIL) of whether the original typespec was a user-defined type.
The possible results of TYPE-OF
FIXNUM, BIGNUM, RATIONAL, SHORT-FLOAT, SINGLE-FLOAT, DOUBLE-FLOAT, LONG-FLOAT, COMPLEX
(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)
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
SPECIAL-OPERATOR, LOAD-TIME-EVAL, SYMBOL-MACRO, EXT:ENCODING, FFI:FOREIGN-POINTER, FFI:FOREIGN-ADDRESS, FFI:FOREIGN-VARIABLE;, FFI:FOREIGN-FUNCTION
EXT:WEAK-POINTER, READ-LABEL, FRAME-POINTER, SYSTEM-INTERNAL
ADDRESS (should not occur)
any other SYMBOL (structure types or CLOS classes)
a class object (CLOS classes without a proper name)
The CLOS symbols are EXPORTed from the package "CLOS". "COMMON-LISP" uses (as in USE-PACKAGE) "CLOS" and EXT:RE-EXPORTs the [ANSI CL standard] standard exported symbols (the CLISP extensions, e.g., CLOS:CLASS-PROTOTYPE, are not EXT:RE-EXPORTed). Since the default :USE argument to MAKE-PACKAGE is "COMMON-LISP", the standard CLOS symbols are normally visible in all user-defined packages. If you do not want them (for example, if you want to use the PCL implementation of CLOS instead of the native one), do the following:
(DEFPACKAGE "CL-NO-CLOS" (:use "CL")) (DO-EXTERNAL-SYMBOLS (symbol "COMMON-LISP") (SHADOW symbol "CL-NO-CLOS")) (DO-SYMBOLS (symbol "CL-NO-CLOS") (EXPORT symbol "CL-NO-CLOS")) (IN-PACKAGE "CL-NO-CLOS") (LOAD "pcl") ; or whatever (DEFPACKAGE "MY-USER" (:use "CL-NO-CLOS")) (IN-PACKAGE "MY-USER") ;; your code which uses PCL goes here |
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.
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.
There is a generic function CLOS:NO-PRIMARY-METHOD (similar 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.
CLOS:GENERIC-FLET and CLOS:GENERIC-LABELS are implemented as macros, not as special operators (as permitted by Section 3.1.2.1.2.2). They are not imported into the packages "COMMON-LISP-USER" and "COMMON-LISP" because of the [ANSI CL standard] issue GENERIC-FLET-POORLY-DESIGNED:DELETE.
ADD-METHOD can put methods into other generic functions than the one the method came from.
PRINT-OBJECT is only called on objects of type STANDARD-OBJECT and STRUCTURE-OBJECT. It is not called on other objects, like CONSes and NUMBERs, due to the performance concerns.
Among those classes listed in Figure 4-8, only the following are instances of BUILT-IN-CLASS:
DEFCLASS supports the :METACLASS option. Possible values are STANDARD-CLASS (the default) and STRUCTURE-CLASS (which creates structure classes, like DEFSTRUCT does).
It is not required that the superclasses of a class are defined before the DEFCLASS form for the class is evaluated. Use [Metaobject Protocol] generic functions CLOS:CLASS-FINALIZED-P to check whether the class has been finalized and thus its instances can be created, and CLOS:FINALIZE-INHERITANCE to force class finalization.
Trivial changes, e.g., those that can occur when doubly loading the same code, do not require updating the instances. These are the changes that do not modify the set of local slots accessible in instances, e.g., changes to slot options :INITFORM, :DOCUMENTATION, and changes to class options :DEFAULT-INITARGS, :DOCUMENTATION.
The instances are updated when they are first accessed, not at the time when the class is redefined or MAKE-INSTANCES-OBSOLETE is called. When the class has been redefined several times since the instance was last accessed, UPDATE-INSTANCE-FOR-REDEFINED-CLASS is still called just once.
FIXNUM is not a character designator in [ANSI CL standard], although CODE-CHAR provides an obvious venue to COERCE a FIXNUM to a CHARACTER. When CUSTOM:*COERCE-FIXNUM-CHAR-ANSI* is NIL, CLISP COERCEs FIXNUMs to CHARACTERs via CODE-CHAR. When CUSTOM:*COERCE-FIXNUM-CHAR-ANSI* is non-NIL, FIXNUMs cannot be COERCEd to CHARACTERs.
Function FUNCTION-LAMBDA-EXPRESSION. The name of a FFI:FOREIGN-FUNCTION is a string (the name of the underlying C function), not a lisp function name.
Macro DESTRUCTURING-BIND. This macro does not perform full error checking.
Macros PROG1, PROG2, AND, OR, PSETQ, WHEN, UNLESS, COND, CASE, MULTIPLE-VALUE-LIST, MULTIPLE-VALUE-BIND, MULTIPLE-VALUE-SETQ. These macros are implemented as special operators (as permitted by Section 3.1.2.1.2.2) and, as such, are rather efficient.
Macro DEFCONSTANT. The initial value is not evaluated at compile time, just like with DEFVAR and DEFPARAMETER. Use EVAL-WHEN if you need the value at compile time.
This macro allows specifying the test for CASE, e.g.,
(fcase string= (subseq foo 0 (position #\Space foo)) ("first" 1) (("second" "two") 2) (("true" "yes") t) (otherwise nil)) |
(let ((var (subseq foo 0 (position #\Space foo)))) (cond ((string= var "first") 1) ((or (string= var "second") (string= var "two")) 2) ((or (string= var "true") (string= var "yes")) t) (t nil))) |
This function checks that exactly one of its arguments is non-NIL and, if this is the case, returns its value and index in the argument list as multiple values, otherwise returns NIL.
EQ compares CHARACTERs and FIXNUMs as EQL does. No unnecessary copies are made of CHARACTERs and NUMBERs. Nevertheless, one should use EQL as it is more portable across Common Lisp implementations.
(let ((x y)) (eq x x)) always returns T, regardless of y.
Note that (eq x x) might not be T for a FFI:FOREIGN-VARIABLE x.
(SETF (SYMBOL-FUNCTION symbol) object) requires object to be either a function, a SYMBOL-FUNCTION return value or a lambda expression. The lambda expression is thereby immediately converted to a FUNCTION.
Additional places:
(SETF (FUNCALL #'symbol ...) object) and (SETF (FUNCALL 'symbol ...) object) are equivalent to (SETF (symbol ...) object).
(SETF (GET-DISPATCH-MACRO-CHARACTER ...) ...) calls SET-DISPATCH-MACRO-CHARACTER.
(SETF (EXT:LONG-FLOAT-DIGITS) digits) sets the default mantissa length of long floats to digits bits.
(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-EXPANSION form &OPTIONAL env), (EXT:GET-SETF-METHOD form &OPTIONAL env), and (EXT:GET-SETF-METHOD-MULTIPLE-VALUE form &OPTIONAL env) receive as optional argument env the environment necessary for macro expansions. In DEFINE-SETF-EXPANDER and EXT: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-EXPANSION, EXT:GET-SETF-METHOD and EXT:GET-SETF-METHOD-MULTIPLE-VALUE. If this is done, even local macros will be interpreted as places correctly.
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 strings, not for conses, other kinds of arrays, and user-defined data types.
(FUNCTION symbol) returns the local function definition established by FLET or LABELS, if it exists, otherwise the global function definition.
(SPECIAL-OPERATOR-P symbol) returns NIL or T. If it returns T, then (SYMBOL-FUNCTION symbol) returns the (useless) special operator handler.
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 EXT:SYMBOL-MACRO-EXPAND tests for a SYMBOL-MACRO: If symbol is defined as a SYMBOL-MACRO, (EXT:SYMBOL-MACRO-EXPAND symbol) returns two values, T and the expansion; otherwise it returns NIL.
Calling BOUNDP on a symbol defined as a SYMBOL-MACRO returns T.
Calling SYMBOL-VALUE on a symbol defined as a SYMBOL-MACRO returns the value of the expansion. Calling SET on a symbol defined as a SYMBOL-MACRO calls SETF on the expansion.
Calling MAKUNBOUND on a symbol defined as a SYMBOL-MACRO removes the SYMBOL-MACRO definition.
Constant LAMBDA-LIST-KEYWORDS. (&OPTIONAL &REST &KEY &ALLOW-OTHER-KEYS &AUX &BODY &WHOLE &ENVIRONMENT)
Table 5-1. Function call limits
CALL-ARGUMENTS-LIMIT | 212=4096 |
MULTIPLE-VALUES-LIMIT | 27=128 |
LAMBDA-PARAMETERS-LIMIT | 212=4096 |
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)))) |
Variable CUSTOM:*SUPPRESS-CHECK-REDEFINITION*. When CUSTOM:*SUPPRESS-CHECK-REDEFINITION* is NIL, CLISP issues a WARNING when a function (macro, variable, class, etc) is redefined in a different file than its original definition. It is not a good idea to set this variable to T.
Only the STANDARD method combination is implemented.
User-defined method combination is not supported. The macros DEFINE-METHOD-COMBINATION, CALL-METHOD and the functions INVALID-METHOD-ERROR, METHOD-COMBINATION-ERROR are not implemented.
The [Metaobject Protocol] generic function CLOS:CLASS-PROTOTYPE is implemented. This allows non-consing access to slots with allocation :CLASS:
(defclass counter () ((count :allocation :class :initform 0 :reader how-many))) (defmethod initialize-instance :after ((obj counter) &rest args) (incf (slot-value obj 'count))) (defclass counted-object (counter) ((name :initarg :name))) |
(make-instance 'counted-object :name 'foo) #<COUNTED-OBJECT #x203028C9> (how-many (clos:class-prototype 'counter)) 1 (make-instance 'counted-object :name 'bar) #<COUNTED-OBJECT #x20306CB1> (how-many (clos:class-prototype 'counter)) 2 |
The :PRINT-FUNCTION option should contain a lambda expression (LAMBDA (object stream depth) (declare (ignore depth)) ...) This lambda expression names a FUNCTION whose task is to output the external representation of the STRUCTURE-OBJECT object onto the STREAM 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 value of *PRINT-ESCAPE* must be respected.
The treatment of *PRINT-PRETTY* is up to you.
The value of *PRINT-CIRCLE* need not be respected. This is managed by the system. (But the print-circle mechanism handles only those objects that are direct or indirect components of the structure.)
The value of *PRINT-LEVEL* is respected by WRITE, PRIN1, PRINC, PRINT, PPRINT, FORMAT instructions ~A, ~S, ~W, and FORMAT instructions ~R, ~D, ~B, ~O, ~X, ~F, ~E, ~G, ~$ with not-numerical arguments. Therefore the print-level mechanism works automatically if only these functions are used for outputting objects and if they are not called on objects with nesting level > 1. (The print-level mechanism does not recognize how many parentheses you have output. It only counts how many times it was called recursively.)
The value of *PRINT-LENGTH* must be respected, especially if you are outputting an arbitrary number of components.
The value of *PRINT-READABLY* must be respected. Remember that the values of *PRINT-ESCAPE*, *PRINT-LEVEL*, *PRINT-LENGTH* are ignored if *PRINT-READABLY* is true. The value of *PRINT-READABLY* is respected by PRINT-UNREADABLE-OBJECT, WRITE, PRIN1, PRINC, PRINT, PPRINT, FORMAT instructions ~A, ~S, ~W, and FORMAT instructions ~R, ~D, ~B, ~O, ~X, ~F, ~E, ~G, ~$ with not-numerical arguments. Therefore *PRINT-READABLY* will be respected automatically if only these functions are used for printing objects.
You need not worry about the values of *PRINT-BASE*, *PRINT-RADIX*, *PRINT-CASE*, *PRINT-GENSYM*, *PRINT-ARRAY*, CUSTOM:*PRINT-CLOSURE*, CUSTOM:*PRINT-RPARS*, CUSTOM:*PRINT-INDENT-LISTS*.
The :INHERIT option is exactly like :INCLUDE except that it does not create new accessors for the inherited slots (this is a CLISP extension).
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.
Macro EXT:MUFFLE-CERRORS. The macro (EXT:MUFFLE-CERRORS {form}*) executes the forms. When a continuable error occurs, no message is printed, instead, the CONTINUE RESTART is invoked.
Macro EXT:APPEASE-CERRORS. The macro (EXT:APPEASE-CERRORS {form}*) executes the forms. Continuable errors are reported as warnings and the CONTINUE RESTART is invoked.
Macro EXT:EXIT-ON-ERROR. The macro (EXT:EXIT-ON-ERROR {form}*) executes the forms. When a non-continuable error or a Control-C interrupt occurs, the error message is printed and CLISP terminates with an error status.
Macro EXT:WITH-RESTARTS. The macro EXT: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 with any CONDITION. (EXT:WITH-RESTARTS ({restart-clause}*) {form}*) is therefore equivalent to (RESTART-CASE (PROGN {form}*) {restart-clause}*).
The error message prefix for the first line is "*** - ". There is no prefix for subsequent error lines. The aesthetics of CONDITION reports containing an object which requires newlines when pretty printing is enabled, is undefined.
Macro RESTART-CASE. In RESTART-CASE clauses the argument list can also be specified after the keyword/value pairs instead of before them. The syntax therefore is
Macro (RESTART-CASE form {restart-clause}*)
(restart-name arglist {keyword-value}* {form}*) | (restart-name {keyword-value}* arglist {form}*) |
Function COMPUTE-RESTARTS. COMPUTE-RESTARTS and FIND-RESTART behave as specified in [ANSI CL standard]: If the optional condition argument is non-NIL, only restarts associated with that condition and restarts associated with 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.
The [ANSI CL standard] packages present in CLISP
with the nicknames "CL" and "LISP"
with the nicknames "CL-USER" and "USER"
with the nickname ""
The package "COMMON-LISP" EXPORTs only those symbols from the [ANSI CL standard] that are actually implemented.
Function EXT:PACKAGE-LOCK. Packages can be "locked". When a package is locked, attempts to change its symbol table or redefine functions which its symbols name result in a continuable ERROR (continuing overrides locking for this operation). When CUSTOM:*SUPPRESS-CHECK-REDEFINITION* is T (not a good idea!), the ERROR is not SIGNALed for redefine operations. Function (EXT:PACKAGE-LOCK package) returns the generalized boolean indicating whether the package is locked. A package (or a list thereof) can be locked using (SETF (EXT:PACKAGE-LOCK package-or-list) T). CLISP locks its system packages (specified in the variable CUSTOM:*SYSTEM-PACKAGE-LIST*).
Macro EXT:WITHOUT-PACKAGE-LOCK. If you want to evaluate some forms with certain packages unlocked, you can use EXT:WITHOUT-PACKAGE-LOCK :
(EXT:WITHOUT-PACKAGE-LOCK ("LISP" "EXT" "CLOS") (defun restart () ...)) |
(EXT:WITHOUT-PACKAGE-LOCK ("LISP") (trace read-line)) |
Discussion - see also the USENET posting by Steven M. Haflich. This should prevent you from accidentally hosing yourself with
(DEFSTRUCT instance ...) |
The "COMMON-LISP-USER" package uses the "COMMON-LISP" and "EXT" packages.
The following additional packages exist:
Implementation-Defined Packages
EXPORTs all CLOS-specific symbols, including some additional symbols.
has the nicknames "SYS" and "COMPILER", and has no EXPORTed symbols. It defines many system internals.
is the umbrella package for all extensions: it imports and EXT:RE-EXPORTs all the external symbols in all CLISP extensions, so a simple (USE-PACKAGE "EXT") is enough to make all the extensions available in the current package. This package uses packages (in addition to "COMMON-LISP"): "LDAP", "POSIX", "SOCKET", "GSTREAM", "GRAY", "I18N", "CUSTOM".
defines and EXPORTs some character sets, for use with EXT:MAKE-ENCODING and as :EXTERNAL-FORMAT argument.
implements the foreign function interface. Some platforms only.
defines an API for random screen access. Some platforms only.
All pre-existing packages except "COMMON-LISP-USER" belong to the implementation, in the sense that the programs that do not follow Section 11.1.2.1.2 ("Constraints on the "COMMON-LISP" Package for Conforming Programs") cause undefined behavior.
For MAKE-PACKAGE, the default value of the :USE argument is ("COMMON-LISP").
MAKE-PACKAGE accepts 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.
The function (EXT:RE-EXPORT FROM-PACK TO-PACK) re-EXPORTs all external SYMBOLs from FROM-PACK also from TO-PACK, provided it already uses FROM-PACK; and SIGNALs an ERROR otherwise.
The type NUMBER is the disjoint union of the types REAL and COMPLEX ("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.
Byte specifiers are objects of built-in type BYTE, not INTEGERs.
When a mathematical function may return an exact (rational) or inexact (floating-point) result, it always returns the exact result.
There are four floating point types: SHORT-FLOAT, SINGLE-FLOAT, DOUBLE-FLOAT and LONG-FLOAT:
type | sign | mantissa | exponent | comment |
---|---|---|---|---|
SHORT-FLOAT | 1 bit | 16+1 bits | 8 bits | immediate |
SINGLE-FLOAT | 1 bit | 23+1 bits | 8 bits | IEEE 754 |
DOUBLE-FLOAT | 1 bit | 52+1 bits | 11 bits | IEEE 754 |
LONG-FLOAT | 1 bit | >=64 bits | 32 bits | variable length |
The single and double float formats are those of the IEEE 754 "Standard for Binary Floating-Point Arithmetic", except that CLISP does not support features like ±0, ±inf, NaN, gradual underflow, etc. (Common Lisp does not make use of these features.) This is why *FEATURES* does not contain the :IEEE-FLOATING-POINT keyword.
Arbitrary Precision Floats. 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 (EXT:LONG-FLOAT-DIGITS). It can be set by (SETF (EXT:LONG-FLOAT-DIGITS) n), where n is a positive integer. E.g., (SETF (EXT:LONG-FLOAT-DIGITS) 3322) sets the default precision of long floats to about 1000 decimal digits.
The floating point contagion is controlled by the variable CUSTOM:*FLOATING-POINT-CONTAGION-ANSI*. When it is non-NIL, contagion is done as per the [ANSI CL standard]: SHORT-FLOAT → SINGLE-FLOAT → DOUBLE-FLOAT → LONG-FLOAT.
See it pragmatically: save what you can and let others worry about the rest.
Common Lisp 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.
A computer 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 CL standard] 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 traditional CLISP way does lie about the mean: the mean is 3.25 and nothing else, while the standard 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 Common Lisp has no way of knowing the actual accuracy, [ANSI CL standard] (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.
Rounding errors accumulate, and if a computation is conducted with insufficient precision, an outright incorrect result can be returned. (E.g., E(x2) - E(x)2 can be negative!) The user should not mix floats of different precision (that's what CUSTOM:*WARN-ON-FLOATING-POINT-CONTAGION* is for), but one should not be penalized for this too harshly.
When CUSTOM:*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 12.1.4.4 Rule of Float Precision Contagion!)
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.
Do not suggest accuracy of a result by giving it a precision that is greater than its accuracy.
(- (+ 1.7 PI) PI) should not return 1.700000726342836417234L0, it should return 1.7f0 (or 1.700001f0 if there were rounding errors).
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.
Variable CUSTOM:*WARN-ON-FLOATING-POINT-CONTAGION*. If the variable CUSTOM:*WARN-ON-FLOATING-POINT-CONTAGION* is non-NIL, a warning is emitted for every coercion involving different floating-point types. As explained above, float precision contagion is not a good idea, this is why CUSTOM:*WARN-ON-FLOATING-POINT-CONTAGION* is set to T initially. You can avoid the contagion by doing all your computations with the same floating-point type (and using FLOAT to convert all constants, e.g., PI, to your preferred type). Set it to ERROR to have CLISP SIGNAL an ERROR on float precision contagion.
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).
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.
This has the advantage that (let ((x (sqrt -9.0))) (* x x)) - instead of evaluating 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).
Function UPGRADED-COMPLEX-PART-TYPE. When the argument is not a recognizable subtype or REAL, UPGRADED-COMPLEX-PART-TYPE SIGNALs an ERROR, otherwise it returns REAL, since a COMPLEX number in CLISP can always have REALPART and IMAGPART of any type.
Variable CUSTOM:*DEFAULT-FLOAT-FORMAT*. 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 CUSTOM:*DEFAULT-FLOAT-FORMAT*.
Macro EXT:WITHOUT-FLOATING-POINT-UNDERFLOW. The macro (EXT: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.
Function EXT:! (EXT:! n) returns the factorial of n, n being a nonnegative INTEGER.
Function EXT:EXQUO. (EXT:EXQUO x y) returns the integer quotient x/y of two integers x,y, and SIGNALs an ERROR when the quotient is not integer. (This is more efficient than /.)
Function EXT:XGCD. (EXT:XGCD x1 ... xn) returns the values l, k1, ..., kn, where l is the greatest common divisor of the integers x1, ..., xn, and k1, ..., kn are the integer coefficients such that
l = (GCD x1 ... xn) = (+ (* k1 x1) ... (* kn xn)) |
Constant PI. The value of PI is a LONG-FLOAT with the precision given by (EXT:LONG-FLOAT-DIGITS). When this precision is changed, the value of PI is automatically recomputed. Therefore PI is not a constant variable.
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 always evaluates to T:
(>= (FLOAT-DIGITS (FLOAT-DIGITS number digits)) digits) |
Table 12-1. Boolean Operations
constant | value |
---|---|
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 |
Table 12-2. Fixnum limits
CPU type | 16-bit CPU | 32-bit CPU | 64-bit CPU |
---|---|---|---|
MOST-POSITIVE-FIXNUM | 224-1 = 16777215 | 232-1 = 4294967295 | |
MOST-NEGATIVE-FIXNUM | -224 = -16777216 | -232 = -4294967296 |
Together with PI, the other long float constants LEAST-NEGATIVE-LONG-FLOAT LEAST-NEGATIVE-NORMALIZED-LONG-FLOAT LEAST-POSITIVE-LONG-FLOAT LEAST-POSITIVE-NORMALIZED-LONG-FLOAT LONG-FLOAT-EPSILON LONG-FLOAT-NEGATIVE-EPSILON MOST-NEGATIVE-LONG-FLOAT MOST-POSITIVE-LONG-FLOAT are recomputed whenever (EXT:LONG-FLOAT-DIGITS) is SETFed. They are not constant variables.
The characters are ordered according to a superset of the ASCII character set.
More precisely, CLISP uses the IBM PC character set (code page 437):
#x0 | #x1 | #x2 | #x3 | #x4 | #x5 | #x6 | #x7 | #x8 | #x9 | #xA | #xB | #xC | #xD | #xE | #xF | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
#x00 | ** | ** | ** | ** | ** | ** | ** | ** | ¶ | § | ||||||
#x10 | ** | ** | ||||||||||||||
#x20 | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / | |
#x30 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? |
#x40 | @ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O |
#x50 | P | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ |
#x60 | ` | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o |
#x70 | p | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ | |
#x80 | Ç | ü | é | â | ä | à | å | ç | ê | ë | è | ï | î | ì | Ä | Å |
#x90 | É | æ | Æ | ô | ö | ò | û | ù | ÿ | Ö | Ü | ¢ | £ | ¥ | ₧ | ƒ |
#xA0 | á | í | ó | ú | ñ | Ñ | ª | º | ¿ | ⌐ | ¬ | ½ | ¼ | ¡ | « | » |
#xB0 | ░ | ▒ | ▓ | │ | ┤ | ╡ | ╢ | ╖ | ╕ | ╣ | ║ | ╗ | ╝ | ╜ | ╛ | ┐ |
#xC0 | └ | ┴ | ┬ | ├ | ─ | ┼ | ╞ | ╟ | ╚ | ╔ | ╩ | ╦ | ╠ | ═ | ╬ | ╧ |
#xD0 | ╨ | ╤ | ╥ | ╙ | ╘ | ╒ | ╓ | ╛ | ╚ | ┘ | ┌ | █ | ▄ | ▌ | ▐ | ▀ |
#xE0 | α | ß | Γ | π | Σ | σ | µ | τ | Φ | Θ | Ω | δ | ∞ | φ | ∊ | ∩ |
#xF0 | ≡ | ± | ≥ | ≤ | ⌠ | ⌡ | ÷ | ≍ | ° | ∙ | · | √ | ⁿ | ² | ■ |
More precisely, CLISP uses the ISO Latin-1 (ISO 8859-1) character set:
#x0 | #x1 | #x2 | #x3 | #x4 | #x5 | #x6 | #x7 | #x8 | #x9 | #xA | #xB | #xC | #xD | #xE | #xF | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
#x00 | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** |
#x10 | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** |
#x20 | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / | |
#x30 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? |
#x40 | @ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O |
#x50 | P | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ |
#x60 | ` | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o |
#x70 | p | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ | |
#x80 | ||||||||||||||||
#x90 | ||||||||||||||||
#xA0 | ¡ | ¢ | £ | ¤ | ¥ | ¦ | § | ¨ | © | ª | « | ¬ | | ® | ¯ | |
#xB0 | ° | ± | ² | ³ | ´ | µ | ¶ | · | ¸ | ¹ | º | » | ¼ | ½ | ¾ | ¿ |
#xC0 | À | Á | Â | Ã | Ä | Å | Æ | Ç | È | É | Ê | Ë | Ì | Í | Î | Ï |
#xD0 | Ð | Ñ | Ò | Ó | Ô | Õ | Ö | × | Ø | Ù | Ú | Û | Ü | Ý | Þ | ß |
#xE0 | à | á | â | ã | ä | å | æ | ç | è | é | ê | ë | ì | í | î | ï |
#xF0 | ð | ñ | ò | ó | ô | õ | ö | ÷ | ø | ù | ú | û | ü | ý | þ | ÿ |
More precisely, CLISP uses the NeXTstep character set:
#x0 | #x1 | #x2 | #x3 | #x4 | #x5 | #x6 | #x7 | #x8 | #x9 | #xA | #xB | #xC | #xD | #xE | #xF | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
#x00 | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** |
#x10 | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** | ** |
#x20 | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / | |
#x30 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? |
#x40 | @ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O |
#x50 | P | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ |
#x60 | ` | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o |
#x70 | p | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ | |
#x80 | À | Á | Â | Ã | Ä | Å | Ç | È | É | Ê | Ë | Ì | Í | Î | Ï | |
#x90 | Ð | Ñ | Ò | Ó | Ô | Õ | Ö | Ù | Ú | Û | Ü | Ý | Þ | µ | × | ÷ |
#xA0 | © | ¡ | ¢ | £ | ⁄ | ¥ | ƒ | § | ¤ | ’ | “ | « | ‹ | › | fi | fl |
#xB0 | ® | – | † | ‡ | · | ¦ | ¶ | • | ‚ | „ | ” | » | … | ‰ | ¬ | ¿ |
#xC0 | ¹ | ˋ | ´ | ^ | ˜ | ¯ | ˘ | ˙ | ¨ | ² | ˚ | ¸ | ³ | ˝ | ˛ | ˇ |
#xD0 | — | ± | ¼ | ½ | ¾ | à | á | â | ã | ä | å | ç | è | é | ê | ë |
#xE0 | ì | Æ | í | ª | î | ï | ð | ñ | Ł | Ø | Œ | º | ò | ó | ô | õ |
#xF0 | ö | æ | ù | ú | û | ı | ü | ý | ł | ø | œ | ß | þ | ÿ |
Table 13-2. Semi-standard characters
character | code |
---|---|
#\Backspace | #x08 |
#\Tab | #x09 |
#\Linefeed | #x0A |
#\Page | #x0C |
#\Return | #x0D |
#\Newline is the line terminator.
Table 13-4. Additional syntax for characters with code from #x00 to #x1F:
character | code |
---|---|
#\^@ | #x00 |
#\^A … #\^Z | #x01 … #x1A |
#\^[ | #x1B |
#\^\ | #x1C |
#\^] | #x1D |
#\^^ | #x1E |
#\^_ | #x1F |
See also the section Character I/O.
Characters do not have the [CLtL1] font and bits attributes. For backward compatibility, there is a class SYS::INPUT-CHARACTER representing either a character with font and bits, or a keystroke. The following functions work with objects of types CHARACTER and SYS::INPUT-CHARACTER. Note that EQL or EQUAL cannot be used to compare objects of type SYS::INPUT-CHARACTER.
The system uses only font 0.
Character bits:
key | value |
---|---|
:CONTROL | EXT:CHAR-CONTROL-BIT |
:META | EXT:CHAR-META-BIT |
:SUPER | EXT:CHAR-SUPER-BIT |
:HYPER | EXT:CHAR-HYPER-BIT |
returns the font of a CHARACTER or SYS::INPUT-CHARACTER.
returns the bits of a CHARACTER or SYS::INPUT-CHARACTER.
returns a new SYS::INPUT-CHARACTER, or NIL if such a character cannot be created.
returns a new SYS::INPUT-CHARACTER with the named bit set or unset, depending on the boolean newvalue.
The system itself uses this SYS::INPUT-CHARACTER type only to mention special keys and Control/Alternate/Shift key status on return from (READ-CHAR EXT:*KEYBOARD-INPUT*).
The only defined character script is the type CHARACTER itself.
Characters have no implementation-defined attributes. All characters are simple characters.
The graphic characters are those UNICODE characters which are defined by the UNICODE standard, excluding the ranges U0000 … U001F and U007F … U009F.
The alphabetic characters are those UNICODE characters which are defined as letters by the UNICODE standard.
The characters with case are those UNICODE characters c, for which the upper case mapping uc and the lower case mapping lc have the following properties:
uc and lc are different
c is one of uc and lc
the upper case mapping of uc and of lc is uc
the lower case mapping of uc and of lc is lc
The titlecase property of UNICODE characters has no equivalent in Common Lisp.
The numeric characters are those UNICODE characters which are defined as digits by the UNICODE standard.
The characters are ordered according to their UNICODE code.
Newlines are written according to the stream's EXT:ENCODING, see the function STREAM-EXTERNAL-FORMAT and the description of EXT:ENCODINGs, in particular, line terminators. The default behavior is as follows:
When reading from a file, CR/LF is converted to #\Newline (the usual convention on DOS), and CR not followed by LF is converted to #\Newline as well (the usual conversion on MacOS, also used by some programs on Win32).
The integer returned by CHAR-INT is the same as the character's code.
See the description of EXT:ENCODINGs.
CHAR-CODE takes values from 0 (inclusive) to CHAR-CODE-LIMIT (exclusive), i.e., the implementation supports exactly CHAR-CODE-LIMIT characters.
Table 13-5. Number of characters
binaries built | without UNICODE support | with UNICODE support |
---|---|---|
CHAR-CODE-LIMIT | 28 = 256 | 17 * 216 = 1114112 |
The types EXT:STRING-CHAR and BASE-CHAR are equivalent to CHARACTER.
The graphic characters have been described above.
The standard characters are #\Newline and the graphic characters with a code between 32 and 126 (inclusive).
The alphabetic characters are these characters:
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜßáíóúñѪºãõØøÀÃÕ 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.
Function (EXT:CHAR-WIDTH char). returns the number of screen columns occupied by char. This is 0 for non-spacing characters (such as control characters and many combining characters), 2 for double-width East Asian characters, and 1 for all other characters. See also function EXT:STRING-WIDTH.
The characters that are not graphic chars and the space character have names:
Table 13-6. Platform dependent characters: Amiga platforms.
code | char | ||
---|---|---|---|
(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 |
Table 13-7. Platform dependent characters: DOS, OS/2, Win32 platforms.
code | char | |
---|---|---|
(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 |
Table 13-8. Platform dependent characters: UNIX, Acorn platforms.
code | char | ||
---|---|---|---|
(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 |
Table 13-9. Character bit constants (obsolete)
constant | value |
---|---|
EXT:CHAR-CONTROL-BIT | 1 |
EXT:CHAR-META-BIT | 2 |
EXT:CHAR-SUPER-BIT | 4 |
EXT:CHAR-HYPER-BIT | 8 |
The function EXT:MAPCAP is like MAPCAN, except that it concatenates the resulting lists with APPEND instead of NCONC:
(EXT:MAPCAP function x1 ... xn) == (APPLY #'APPEND (MAPCAR function x1 ... xn))
(Actually a bit more efficient that this would have been.)
The function EXT:MAPLAP is like MAPCON, except that it concatenates the resulting lists with APPEND instead of NCONC:
(EXT:MAPLAP function x1 ... xn) == (APPLY #'APPEND (MAPLIST function x1 ... xn))
(Actually a bit more efficient that this would have been.)
Function MAKE-ARRAY. MAKE-ARRAY can return specialized arrays for the ARRAY-ELEMENT-TYPEs (UNSIGNED-BYTE 2), (UNSIGNED-BYTE 4), (UNSIGNED-BYTE 8), (UNSIGNED-BYTE 16), (UNSIGNED-BYTE 32), and, of course, the required specializations NIL, BIT and CHARACTER.
Table 15-1. Array limits
CPU type | 16-bit CPU | 32-bit CPU | 64-bit CPU |
---|---|---|---|
ARRAY-RANK-LIMIT | 212 = 4096 | ||
ARRAY-DIMENSION-LIMIT | 224 = 16777216 | 232 = 4294967296 | |
ARRAY-TOTAL-SIZE-LIMIT | 224 = 16777216 | 232 = 4294967296 |
Note that ARRAY-DIMENSION-LIMIT and ARRAY-TOTAL-SIZE-LIMIT are not fixnums (they are equal to (1+ MOST-POSITIVE-FIXNUM)), contrary to the [ANSI CL standard] Issue ARRAY-DIMENSION-LIMIT-IMPLICATIONS:ALL-FIXNUM.
Function ADJUST-ARRAY for displaced arrays. 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!
String comparison is based on the function CHAR<=. Therefore diphthongs do not obey the usual national rules. Example: o < oe < z < ö.
Function EXT:STRING-WIDTH. (EXT:STRING-WIDTH string &KEY start end) returns the number of screen columns occupied by string. This is computed as the sum of all EXT:CHAR-WIDTHs of all of the string's characters.
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.
Variable CUSTOM:*SEQUENCE-COUNT-ANSI*. Contrary to the [ANSI CL standard] issue 283 RANGE-OF-COUNT-KEYWORD:NIL-OR-INTEGER, negative :COUNT keyword arguments are not allowed unless you set CUSTOM:*SEQUENCE-COUNT-ANSI* to a non-NIL value, in which case "using a negative integer value is functionally equivalent to using a value of zero", as per the [ANSI CL standard] issue.
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. Worst case complexity: O(n*log(n)) comparisons, where n is the LENGTH of the subsequence bounded by the :START and :END arguments.
MAKE-HASH-TABLE supports additional keywords :INITIAL-CONTENTS and :WEAK:
(MAKE-HASH-TABLE &KEY :test :initial-contents :size :rehash-size :rehash-threshold :weak) |
The :INITIAL-CONTENTS argument is an alist that is used to initialize the new hash table. The :REHASH-THRESHOLD argument is ignored.
The :WEAK can take the following values:
NIL (default) |
:KEY |
:VALUE |
:EITHER |
:BOTH |
The SETFable predicate EXT:HASH-TABLE-WEAK-P checks whether the HASH-TABLE is weak.
Just like EXT:WEAK-POINTERs, weak HASH-TABLEs cannot be printed readably.
You can define a new hash table test using the macro EXT:DEFINE-HASH-TABLE-TEST: (EXT:DEFINE-HASH-TABLE-TEST test-name test-function hash-function), after which test-name can be passed as the :TEST argument to MAKE-HASH-TABLE. E.g.:
(EXT:DEFINE-HASH-TABLE-TEST string STRING= SXHASH) (MAKE-HASH-TABLE :test 'string) |
The fundamental requirement is that the test-function and hash-function are consistent:
(FUNCALL test-function x y) ==> (= (FUNCALL hash-function x) (FUNCALL hash-function y)) |
(EXT:DEFINE-HASH-TABLE-TEST number = SXHASH) ; BAD! |
(EXT:DEFINE-HASH-TABLE-TEST number = (LAMBDA (x) (SXHASH (COERCE x 'SHORT-FLOAT)))) |
Function HASH-TABLE-TEST returns either one of the four standard symbols EQ, EQL, EQUAL, EQUALP, or, for HASH-TABLEs created with a user-defined HASH-TABLE-TEST (see macro EXT:DEFINE-HASH-TABLE-TEST), a CONS cell (test-function . hash-function).
For iteration through a HASH-TABLE, a macro EXT:DOHASH, similar to DOLIST, can be used instead of MAPHASH:
(EXT:DOHASH (key-var value-var hash-table-form [resultform]) {declaration}* {tag|form}*) |
EXT:DOHASH forms are iteration forms.
For most operations, pathnames denoting files and pathnames denoting directories cannot be used interchangeably.
For example, #P"foo/bar" denotes the file #P"bar" in the directory #P"foo", while #P"foo/bar/" denotes the subdirectory #P"bar" of the directory #P"foo".
For example, #P"foo\\bar" denotes the file #P"bar" in the directory #P"foo", while #P"foo\\bar\\" denotes the subdirectory #P"bar" of the directory #P"foo".
For example, #P"foo.bar" denotes the file #P"foo" in the directory #P"bar", while #P"foo.bar." denotes the subdirectory #P"bar" of the directory #P"foo".
User variable CUSTOM:*DEVICE-PREFIX* controls translation between Cygwin pathnames (e.g., #P"/cygdrive/c/gnu/clisp/") and native Win32 pathnames (e.g., #P"C:\\gnu\\clisp\\") When it is set to NIL, no translations occur and the Cygwin port will not understand the native paths and the native Win32 port will not understand the Cygwin paths. When its value is a string, it is used by PARSE-NAMESTRING to translate into the appropriate platform-specific representation, so that on Cygwin, (PARSE-NAMESTRING "c:/gnu/clisp/") returns #P"/cygdrive/c/gnu/clisp/", while on Win32 (PARSE-NAMESTRING "/cygdrive/c/gnu/clisp/") returns #P"C:/gnu/clisp/". The initial value is "cygdrive", you should edit #P"config.lisp" to change it.
This is especially important for the directory-handling functions.
Table 19-1. The minimum filename syntax that may be used portably
pathname | meaning |
---|---|
"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 or with name .yy and no type, depending on the value of CUSTOM:*PARSE-NAMESTRING-DOT-FILE*. |
Hereby xxx denotes 1 to 8 characters, and yy denotes 1 to 3 characters, each of which being either an alphanumeric character or the underscore #\_. Other properties of pathname syntax vary between operating systems.
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 EQ NIL may not be allowed either.
Pathname components
always NIL
NIL or a SIMPLE-STRING
element | values | meaning |
---|---|---|
startpoint | :RELATIVE | :ABSOLUTE | |
subdirs | () | (subdir . subdirs) | |
subdir | :WILD-INFERIORS | ** or ..., all subdirectories |
subdir | SIMPLE-STRING, may contain wildcard characters "?" and "*" (may also be specified as :WILD) | |
subdir | :PARENT | "/" instead of "subdir/" |
NIL or SIMPLE-STRING, may contain wildcard characters "?" and "*" (may also be specified as :WILD)
NIL or SIMPLE-STRING, may contain wildcard characters "?" and "*" (may also be specified as :WILD)
always NIL (may also be specified as :WILD or :NEWEST)
Constraint: startpoint = :RELATIVE only if device is NIL. If the device is specified, the pathname must be absolute!
An Amiga filename is split into name and type.
Case is ignored in the strings on comparison. No case conversions are performed.
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*.lisp" |
or similar. |
Formal specification of the external notation
any character except ':','/' and '*','?'
{ch}+
[ <empty> | ':' | name ':' ]
[ <empty> | name ]
device { subdir '/' }* name
Examples:
String | Device | Directory | our pathname |
---|---|---|---|
"c:foo" | 'C' | "device->foo" | "c" (:ABSOLUTE #P"foo") |
"c:foo/" | 'C' | "device->foo" | "c" (:ABSOLUTE #P"foo") |
"c:foo/bar" | 'C' | "device->foo->bar" | "c" (:ABSOLUTE #P"foo" #P"bar") |
"c:/foo" | 'C' | "device->up->foo" | "c" (:ABSOLUTE :PARENT #P"foo") |
"c:" | 'C' | "device" | "c" (:ABSOLUTE) |
":foo" | current | "device->root->foo" | NIL (:ABSOLUTE #P"foo") |
#P"foo" | current | "device->foo" | NIL (:RELATIVE #P"foo") |
"/foo" | current | "device->up->foo" | NIL (:RELATIVE :PARENT #P"foo") |
"//foo/bar" | current | "device->up->up->foo->bar" | NIL (:RELATIVE :PARENT :PARENT #P"foo" #P"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 both name and type being NIL).
Pathname components
always NIL
always NIL
element | values | meaning |
---|---|---|
startpoint | :RELATIVE | :ABSOLUTE | |
subdirs | () | (subdir . subdirs) | |
subdir | :WILD-INFERIORS | ** or ..., all subdirectories |
subdir | SIMPLE-STRING, may contain wildcard characters "?" and "*" (may also be specified as :WILD) |
NIL or SIMPLE-STRING, may contain wildcard characters "?" and "*" (may also be specified as :WILD)
NIL or SIMPLE-STRING, may contain wildcard characters "?" and "*" (may also be specified as :WILD)
always NIL (may also be specified as :WILD or :NEWEST)
A UNIX filename is split into name and type.
Pathname components
always NIL
NIL or :WILD or A|...|Z
element | values | meaning |
---|---|---|
startpoint | :RELATIVE | :ABSOLUTE | |
subdirs | () | (subdir . subdirs) | |
subdir | :WILD-INFERIORS | ** or ..., all subdirectories |
subdir | SIMPLE-STRING, may contain wildcard characters "?" and "*" (may also be specified as :WILD) |
NIL or SIMPLE-STRING, may contain wildcard characters "?" and "*" (may also be specified as :WILD)
NIL or SIMPLE-STRING, may contain wildcard characters "?" and "*" (may also be specified as :WILD)
always NIL (may also be specified as :WILD or :NEWEST)
An OS/2 filename is split into name and type.
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*.lisp" |
or similar. |
Instead of "\" one may use "/", as usual for DOS calls.
Pathname components
NIL or SIMPLE-STRING, wildcard characters may occur but do not act as wildcards
NIL or :WILD or A|...|Z
element | values | meaning |
---|---|---|
startpoint | :RELATIVE | :ABSOLUTE | |
subdirs | () | (subdir . subdirs) | |
subdir | :WILD-INFERIORS | ** or ..., all subdirectories |
subdir | SIMPLE-STRING, may contain wildcard characters "?" and "*" (may also be specified as :WILD) |
NIL or SIMPLE-STRING, may contain wildcard characters "?" and "*" (may also be specified as :WILD)
NIL or SIMPLE-STRING, may contain wildcard characters "?" and "*" (may also be specified as :WILD)
always NIL (may also be specified as :WILD or :NEWEST)
If host is non-NIL, device must be NIL.
A Win32 filename is split into name and type.
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*.lisp" |
or similar. |
Instead of "\" one may use "/", as usual for DOS calls.
If host is non-NIL and the directory's startpoint is not :ABSOLUTE, (PARSE-NAMESTRING (NAMESTRING pathname)) will not be the same as pathname.
A filename is split into name and type according to the following rule:
if there is no "." in the filename, then the name is everything, type is NIL;
if there is a ".", then name is the part before and type the part after the last dot.
if the only "." is the first character, then the behavior depends on the value of the user variable CUSTOM:*PARSE-NAMESTRING-DOT-FILE* which can be either
Due to this name/type splitting rule, there are pathnames that cannot 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 "foo.bar").
RISC OS provides several file systems as standard (ADFS, IDEFS, NetFS, RamFS, NetPrint) and support for extra file systems (DOSFS, ResourceFS and DeviceFS).
A module called FileSwitch is at the center of all file system operation in RISC OS. FileSwitch provides a common core of functions used by all file systems. It only provides the parts of these services that are device independent. The device dependent services that control the hardware are provided by separate modules, which are the actual file systems. FileSwitch keeps track of active file systems and switches between them as necessary.
One of the file system modules that RISC OS provides is FileCore. It takes the normal calls that FileSwitch sends to a file 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 file system modules imposes a more rigid structure on it, as more of the file system is predefined.
As well as standard file systems, FileSwitch supports image file 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 file systems to do so. DOSFS is an example of an image file system used to handle DOS format discs.
A pathname may include a file 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.
Filename `elements' may be up to ten characters in length on FileCore-based file systems and on NetFS. These characters may be digits or letters. FileSwitch makes no distinction between upper and lower case, although file systems can do so. As a general rule, you should not use top-bit-set characters in filenames, although some file 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 file 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)
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"
Files may also be accessed on file systems other than the current one by prefixing the filename with a file system specification. A file 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 are used to supply more information to the file 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 hyphen you may only use the first two syntaxes given above.
These two special variables control exactly where a file will be looked for, according to the operation being performed on it.
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 file system reference, e.g., executing "adfs:file" will not use "Run$Path".
You can set up other path variables and use them as pseudo file systems. For example if you typed:
*Set Source$Path adfs:$.src.,adfs:$.public.src.
, you could then refer to the pseudo file 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.
No swapping. #P"foo.lisp" means file type #P".lisp" and file name #P"foo". This is pseudo-BNF:
any ISO latin-1 graphic character ≥ ' ' except '.' ':' '*' '#' '$' '&' '@' '^' '%' '\' '?'
any ISO latin-1 graphic character ≥ ' ' except ':' '"' '|'
legal char | '*' | '#' | '?'
'-' { extended legal char except '-' }+ '-' | { extended legal char except '-' } { extended legal char }* ':' | empty
':' { legal char }+ '.' | empty
{ '$' | '&' | '@' | '%' | '\' } '.' { subdirectory }* | { subdirectory }+ | empty
{ '^' | { legal-wild char }+ } '.'
{ { legal-wild char }+ | empty }
{ '.' { legal-wild char }+ | empty }
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) | #P"foo" | NIL |
#P"foo" | NIL | NIL | (:RELATIVE) | #P"foo" | NIL |
"^." | NIL | NIL | (:RELATIVE :PARENT) | NIL | NIL |
"@.^." | NIL | NIL | (:ABSOLUTE :CURRENT :PARENT) | NIL | NIL |
"foo.bar" | NIL | NIL | (:RELATIVE) | #P"foo" | #P"bar" |
"foo.bar.baz" | NIL | NIL | (:RELATIVE #P"foo") | #P"bar" | "baz" |
"foo.bar." | NIL | NIL | (:RELATIVE #P"foo" #P"bar") | NIL | NIL |
"foo.@." | illegal |
with swapping only of name/type components.
Hostname | Device | Directory | Name | Type | RISCOS String |
---|---|---|---|---|---|
"net" | "disc1" | (:ABSOLUTE :ROOT) | #P"foo" | NIL | "net::disc1.$.foo" |
"net#MJ" | "disc1" | (:ABSOLUTE :ROOT #P"foo") | #P"bar" | "baz" | "net#MJ::disc1.$.foo.baz.bar" |
"adfs" | "4" | (:ABSOLUTE :ROOT #P"foo" #P"bar") | NIL | NIL | "adfs::4.$.foo.bar" |
NIL | "disc1" | (:ABSOLUTE :ROOT #P"foo") | #P"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) | #P"foo" | NIL | "$.foo" |
NIL | NIL | (:ABSOLUTE :CURRENT) | #P"foo" | NIL | "@.foo" |
NIL | NIL | (:RELATIVE) | #P"foo" | #P"bar" | "bar.foo" |
NIL | NIL | (:RELATIVE #P"foo") | #P"bar" | "baz" | "foo.baz.bar" |
NIL | NIL | (:ABSOLUTE :LIBRARY) | #P"bar" | NIL | "%.bar" |
NIL | NIL | (:ABSOLUTE :LIBRARY #P"foo") | #P"bar" | NIL | "%.foo.bar" |
NIL | NIL | (:RELATIVE) | #P"foo" | #P"bar" | "bar.foo" |
NIL | NIL | (:RELATIVE #P"foo") | #P"bar" | NIL | "foo.bar" |
NIL | NIL | (:RELATIVE #P"foo") | NIL | #P"bar" | illegal here |
That is, the RISCOS string is the flattening-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)))) |
Pathname components
NIL or a SIMPLE-STRING
NIL or a SIMPLE-STRING
element | values |
---|---|
startpoint | :RELATIVE | :ABSOLUTE anchor |
anchor | :ROOT | :HOME | :CURRENT | :LIBRARY | :PRECIOUS |
subdirs | () | (subdir . subdirs) |
subdir | :PARENT |
subdir | SIMPLE-STRING, may contain wildcard characters "?", "#" and "*" |
SIMPLE-STRING or NIL, may contain wildcard characters "?","#" and "*" (may also be specified as :WILD)
NIL or SIMPLE-STRING, may contain wildcard characters "?","#" and "*" (may also be specified as :WILD)
always NIL (may also be specified as :WILD or :NEWEST)
Constraint: startpoint is not :ABSOLUTE :ROOT only if device is 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 cannot result from PARSE-NAMESTRING. To get a pathname whose type is NIL, MAKE-PATHNAME must be used. Example: (MAKE-PATHNAME :directory "!Clisp." :NAME "README").
The symbol :UNSPECIFIC is not permitted as a pathname component for any slot of any pathname. It is also illegal to pass it as an argument to MAKE-PATHNAME.
External notation of pathnames (cf. PARSE-NAMESTRING and NAMESTRING), of course without spaces, [,],{,}:
[ [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 STRINGs of any LENGTH (consisting of alphanumeric characters and "-", "_"). They are shortened to 8 (respectively 3) characters and converted to upper case. A single "*" is allowed for :WILD.
see above.
[ "/" ] | "/" denotes absolute pathnames |
{ name "/" } | each one a subdirectory |
[ name ["." type] ] | filename with type (extension) |
Name and type may be STRINGs of any LENGTH (consisting of printing ASCII characters, except "/").
[ [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 STRINGs of any LENGTH (consisting of printing ASCII characters, except "/", "\", ":").
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.
The function USER-HOMEDIR-PATHNAME is not implemented.
If you really need that function, you can define it like this:
(defun user-homedir-pathname (&OPTIONAL host) (declare (ignore host)) (or (EXT:GETENV "HOME") "\\")) |
When the argument of the function TRANSLATE-LOGICAL-PATHNAME is a string, it is interpreted as a logical pathname string.
Pathname Designators. When CUSTOM:*PARSE-NAMESTRING-ANSI* is NIL, SYMBOL is also treated as a pathname designator, namely its SYMBOL-NAME is converted to the operating system's preferred pathname case.
Function PATHNAME-MATCH-P. 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.
(PARSE-NAMESTRING string &OPTIONAL host defaults &KEY start end junk-allowed) 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.
The [ANSI CL standard] behavior of recognizing logical pathnames when the string begins with some alphanumeric characters followed by a colon (#\:) can be very confusing (cf. "c:/autoexec.bat", "home:.clisprc" and "prep:/pub/gnu") and therefore is disabled by default. To enable the [ANSI CL standard] behavior, you should set CUSTOM:*PARSE-NAMESTRING-ANSI* to non-NIL.
(MERGE-PATHNAMES pathname [default-pathname]) returns a logical pathname only if default-pathname is a logical pathname. To construct a logical pathname from a string, the function LOGICAL-PATHNAME can be used.
When both pathname and default-pathname are relative pathnames, the behavior depends on CUSTOM:*MERGE-PATHNAMES-ANSI*: when it is NIL, then CLISP retains its traditional behavior: (MERGE-PATHNAMES #P"x/" #P"y/") evaluates to #P"x/"
Rationale. MERGE-PATHNAMES is used to specify default components for pathnames, so there is some analogy between (MERGE-PATHNAMES a b) and (OR a b). Obviously, putting in the same default a second time should do the same as putting it in once: (OR a b b) is the same as (OR a b), so (MERGE-PATHNAMES (MERGE-PATHNAMES a b) b) should be the same as (MERGE-PATHNAMES a b).
(This question actually does matter because in Common Lisp there is no distinction between "pathnames with defaults merged-in" and "pathnames with defaults not yet applied".)
Now, (MERGE-PATHNAMES (MERGE-PATHNAMES #P"x/" #P"y/") #P"y/") and (MERGE-PATHNAMES #P"x/" #P"y/") are EQUAL in CLISP (when CUSTOM:*MERGE-PATHNAMES-ANSI* is NIL), but not in implementations that strictly follow the [ANSI CL standard] spec. In fact, the above twice-default = once-default rule holds for all pathnames in CLISP.
Reversely, when CUSTOM:*MERGE-PATHNAMES-ANSI* is non-NIL, the normal [ANSI CL standard] behavior is exhibited: (MERGE-PATHNAMES #P"x/" #P"y/") evaluates to #P"y/x/".
Rationale. "merge" is merge and not or.
When the host argument to LOAD-LOGICAL-PATHNAME-TRANSLATIONS is not a defined logical host yet, we proceed as follows:
If both environment variables LOGICAL_HOST_host_FROM and LOGICAL_HOST_host_TO exist, then their values define the map of the host.
If the environment variable LOGICAL_HOST_host exists, its value is read from, and the result is passed to (SETF LOGICAL-PATHNAME-TRANSLATIONS).
Variable CUSTOM:*LOAD-LOGICAL-PATHNAME-TRANSLATIONS-DATABASE* is consulted. Its value should be a list of files and/or directories, which are searched for in the CUSTOM:*LOAD-PATHS*, just like for LOAD. When the element is a file, it is READ from, Allegro CL-style, odd objects being host names and even object being their LOGICAL-PATHNAME-TRANSLATIONS. When the element is a directory, a file, named host or host.host, in that directory, is READ from once, CMUCL-style, the object read being the LOGICAL-PATHNAME-TRANSLATIONS of the host.
Function RENAME-FILE. RENAME-FILE always returns a non-logical pathname as its first value.
Function PROBE-FILE. PROBE-FILE cannot be used to check whether a directory exists. Use functions EXT:PROBE-DIRECTORY or DIRECTORY for this.
Function FILE-AUTHOR. FILE-AUTHOR always returns NIL, because the operating systems CLISP is ported to do not store a file's author in the file system. Some operating systems, such as Unix, have the notion of a file's owner, and some other Common Lisp implementations return the user name of the file owner. CLISP does not do this, because owner and author are not the same; in particular, authorship is preserved by copying, while ownership is not.
Function EXT:PROBE-DIRECTORY. (EXT: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 does not exist.
Function DELETE-FILE. (DELETE-FILE pathname) deletes the pathname pathname, not its TRUENAME, and returns the absolute pathname it actually removed or NIL if pathname did not exist. When pathname points to a file which is currently open in CLISP, an ERROR is SIGNALled.
(DIRECTORY &OPTIONAL pathname &KEY :FULL :CIRCLE :IF-DOES-NOT-EXIST) can run in two modes:
If pathname contains no name or type component, a list of all matching directories is produced. E.g., (DIRECTORY "/etc/*/") lists all subdirectories in the directory #P"/etc/".
Otherwise a list of all matching files is returned. E.g., (DIRECTORY "/etc/*") lists all regular files in the directory #P"/etc/". If the :FULL argument is non-NIL, additional information is returned: for each matching file you get a list of at least four elements (file-pathname file-truename file-write-date-as-decoded-time file-length).
discard the bad directory entries
SIGNAL an ERROR on bad directory entries (this corresponds to the default behavior of DIRECTORY in CMU CL)
keep bad directory entries in the returned list (this roughly corresponds to the (DIRECTORY ... :TRUNAMEP NIL) call in CMU CL)
Similar to :DISCARD, but also do not signal an error when a directory is unaccessible (contrary to the [ANSI CL standard] specification).
Function EXT:DIR. (EXT:DIR &OPTIONAL pathname) is like DIRECTORY, but displays the pathnames instead of returning them. (EXT:DIR) shows the contents of the current directory.
Function EXT:CD. (EXT:CD pathname) sets it, (EXT:CD) returns it.
(EXT:CD [pathname]) manages the current directory.
(EXT:CD [pathname]) manages the current host, current device and the current directory.
(EXT:CD [pathname]) manages the current device and the current directory.
Function EXT:DEFAULT-DIRECTORY. (EXT:DEFAULT-DIRECTORY) is equivalent to (EXT:CD). (SETF (EXT:DEFAULT-DIRECTORY) pathname) is equivalent to (EXT:CD pathname), except for the return value.
Function EXT:MAKE-DIR. (EXT:MAKE-DIR directory-pathname) creates a new subdirectory.
Function EXT:DELETE-DIR. (EXT:DELETE-DIR directory-pathname) removes an (empty) subdirectory.
Interactive streams are those whose next input might depend on a prompt one might output.
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 name or PATHNAME that is being typed. See readline user manual for general details and CLISP manual for CLISP-specific extensions. The GNU readline library is not used if standard input and standard output do not both refer to the same terminal.
Macro EXT:WITH-KEYBOARD
*TERMINAL-IO* is not the only stream that communicates directly with the user: During execution of the body of a (EXT:WITH-KEYBOARD . body) form, EXT:*KEYBOARD-INPUT* is the stream that reads the keystrokes from the keyboard. It returns every keystroke in detail, as CHARACTER or SYS::INPUT-CHARACTER with the following bits:
(Platform dependent: DOS, OS/2, Win32, Amiga platforms only.) if a non-standard key. These keys are: [DOS, OS/2, Win32]: Function keys, cursor keypads, numeric keypad. [Amiga]:Function keys, cursor keypad.
the key name, for non-standard keys:
the ASCII code for standard keys
(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.
if pressed together with the Control key.
(Platform dependent: DOS, OS/2, Win32 platforms only.) if pressed together with the Alternate key.
See also Random Screen Access.
STREAM-ELEMENT-TYPE is SETFable. The STREAM-ELEMENT-TYPE of STREAMs created by the functions OPEN, EXT:MAKE-PIPE-INPUT-STREAM EXT:MAKE-PIPE-OUTPUT-STREAM, EXT:MAKE-PIPE-IO-STREAM, SOCKET:SOCKET-ACCEPT, SOCKET:SOCKET-CONNECT can be modified, if the old and the new STREAM-ELEMENT-TYPEs are either
both equivalent to CHARACTER or (UNSIGNED-BYTE 8) or (SIGNED-BYTE 8); or
both equivalent to (UNSIGNED-BYTE n) or (SIGNED-BYTE n), with the same n.
Functions STREAM-ELEMENT-TYPE and (SETF STREAM-ELEMENT-TYPE) are GENERIC-FUNCTIONs, see section "Gray streams".
Note that you cannot change STREAM-ELEMENT-TYPE for some built-in streams, such as terminal streams, which is normally the value of *TERMINAL-IO*. Since *STANDARD-INPUT* normally is a SYNONYM-STREAM pointing to *TERMINAL-IO*, you cannot use READ-BYTE in the it.
Since CGI (Common Gateway Interface) provides the form data for METHOD="POST" on the stdin, and the server will not send you an end-of-stream on the end of the data, you will need to use (EXT:GETENV "CONTENT_LENGTH") to determine how much data you should read from stdin. CLISP will detect that stdin is not a terminal and create a regular FILE-STREAM which can be passed to (SETF STREAM-ELEMENT-TYPE). To test this functionality interactively, you will need to open the standard input in the binary mode:
(let ((buf (MAKE-ARRAY (PARSE-INTEGER (EXT:GETENV "CONTENT_LENGTH")) :element-type (UNSIGNED-BYTE 8)))) (WITH-OPEN-STREAM (in (EXT:MAKE-STREAM :INPUT :ELEMENT-TYPE (UNSIGNED-BYTE 8))) (READ-SEQUENCE buf in)) buf) |
Function EXT:MAKE-STREAM creates a Lisp stream out of an OS file handle: (EXT:MAKE-STREAM object :DIRECTION :ELEMENT-TYPE :EXTERNAL-FORMAT :BUFFERED)
object designates an OS handle (a file descriptor), and should be one of the following:
denotes the file descriptor of this value
denotes CLISP process standard input
denotes CLISP process standard output
denotes CLISP process standard error
denotes the handle of this stream, which should be a FILE-STREAM or a SOCKET:SOCKET-STREAM
The handle is duplicated (with dup/dup2), so it is safe to CLOSE a STREAM returned by EXT:MAKE-STREAM.
The function (EXT:READ-INTEGER stream element-type &OPTIONAL ENDIANNESS eof-error-p eof-value) reads a multi-byte INTEGER from stream. stream should be a stream with STREAM-ELEMENT-TYPE (UNSIGNED-BYTE 8). element-type should be type equivalent to (UNSIGNED-BYTE n), where n is a multiple of 8.
(EXT:READ-INTEGER stream element-type) is like (READ-BYTE stream) if stream's STREAM-ELEMENT-TYPE were set to element-type, except that stream's FILE-POSITION will increase by n/8 instead of 1.
Together with (SETF STREAM-ELEMENT-TYPE), this function permits mixed character/binary input from a stream.
The function (EXT:READ-FLOAT stream element-type &OPTIONAL ENDIANNESS eof-error-p eof-value) reads a floating-point number in IEEE 754 binary representation from stream. stream should be a STREAM with STREAM-ELEMENT-TYPE (UNSIGNED-BYTE 8). element-type should be type equivalent to SINGLE-FLOAT or DOUBLE-FLOAT.
Endianness. ENDIANNESS can be :LITTLE or :BIG. The default is :LITTLE, which corresponds to the READ-BYTE behavior in CLISP.
The function (EXT:WRITE-INTEGER integer stream element-type &OPTIONAL ENDIANNESS) writes a multi-byte integer to stream. stream should be a STREAM with STREAM-ELEMENT-TYPE (UNSIGNED-BYTE 8). element-type should be type equivalent to (UNSIGNED-BYTE n), where n is a multiple of 8.
(EXT:WRITE-INTEGER integer stream element-type) is like (WRITE-BYTE integer stream) if stream's STREAM-ELEMENT-TYPE were set to element-type, except that stream's FILE-POSITION will increase by n/8 instead of 1.
Together with (SETF STREAM-ELEMENT-TYPE), this function permits mixed character/binary output to a STREAM.
The function (EXT:WRITE-FLOAT float stream element-type &OPTIONAL ENDIANNESS) writes a floating-point number in IEEE 754 binary representation to stream. stream should be a STREAM with STREAM-ELEMENT-TYPE (UNSIGNED-BYTE 8). element-type should be type equivalent to SINGLE-FLOAT or DOUBLE-FLOAT.
Function READ-SEQUENCE. In addition to READ-SEQUENCE, the following two functions are provided:
(EXT:READ-BYTE-SEQUENCE sequence stream &KEY :START :END :NO-HANG) 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). When :NO-HANG is non-NIL, does not block: treat input unavailability as end-of-stream.
This function is especially efficient if sequence is a (VECTOR (UNSIGNED-BYTE 8)) and stream is a file/pipe/socket STREAM with STREAM-ELEMENT-TYPE (UNSIGNED-BYTE 8).
(EXT:READ-CHAR-SEQUENCE sequence stream &KEY :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/pipe/socket stream with STREAM-ELEMENT-TYPE CHARACTER or an input STRING-STREAM.
Function WRITE-SEQUENCE. In addition to WRITE-SEQUENCE, the following two functions are provided:
(EXT:WRITE-BYTE-SEQUENCE sequence stream &KEY :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/pipe/socket STREAM with STREAM-ELEMENT-TYPE (UNSIGNED-BYTE 8).
(EXT:WRITE-CHAR-SEQUENCE sequence stream &KEY :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/pipe/socket STREAM with STREAM-ELEMENT-TYPE CHARACTER.
Rationale. The rationale for EXT:READ-CHAR-SEQUENCE, EXT:READ-BYTE-SEQUENCE, EXT:WRITE-CHAR-SEQUENCE and EXT:WRITE-BYTE-SEQUENCE is that some STREAMs support both character and binary i/o, and when you read into a SEQUENCE that can hold both (e.g., LIST or SIMPLE-VECTOR) you cannot determine which kind of input to use. In such situation READ-SEQUENCE and WRITE-SEQUENCE SIGNAL an ERROR, while EXT:READ-CHAR-SEQUENCE, EXT:READ-BYTE-SEQUENCE, EXT:WRITE-CHAR-SEQUENCE and EXT:WRITE-BYTE-SEQUENCE work just fine.
In addition to the standard functions LISTEN and READ-CHAR-NO-HANG, CLISP provides the following functionality facilitating non-blocking input and output, both binary and character.
EXT:READ-CHAR-WILL-HANG-P queries the stream's input status. It returns NIL if READ-CHAR and PEEK-CHAR with a peek-type of NIL will return immediately. Otherwise it returns T. (In the latter case the standard LISTEN function would return NIL.)
Note the difference with (NOT (LISTEN stream)): When the end-of-stream is reached, LISTEN returns NIL, whereas EXT:READ-CHAR-WILL-HANG-P returns NIL.
Note also that EXT:READ-CHAR-WILL-HANG-P is not a good way to test for end-of-stream: If EXT:READ-CHAR-WILL-HANG-P returns T, this does not mean that the stream will deliver more characters. It only means that it is not known at this moment whether the stream is already at end-of-stream, or will deliver more characters.
To be called only if stream's STREAM-ELEMENT-TYPE is (UNSIGNED-BYTE 8) or (SIGNED-BYTE 8). Returns T if READ-BYTE would return immediately with an INTEGER result. Returns :EOF if the end-of-stream is already known to be reached. If READ-BYTE's value is not available immediately, returns NIL instead of waiting.
To be called only if stream's STREAM-ELEMENT-TYPE is (UNSIGNED-BYTE 8) or (SIGNED-BYTE 8). Returns NIL if READ-BYTE will return immediately. Otherwise it returns true.
To be called only if stream's STREAM-ELEMENT-TYPE is (UNSIGNED-BYTE 8) or (SIGNED-BYTE 8). Returns an INTEGER or does end-of-stream handling, like READ-BYTE, if that would return immediately. If READ-BYTE's value is not available immediately, returns NIL instead of waiting.
FILE-POSITION works on any buffered file stream. When a #\Newline is output to (respectively input from) a file stream, its file position is increased by 2 since #\Newline is encoded as CR/LF in the file.
OPEN cannot handle files of size ≥ 4 GB.
OPEN accepts an additional keyword :BUFFERED.
The acceptable values for the arguments to the file/pipe/socket functions
types equivalent to CHARACTER or (UNSIGNED-BYTE n), (SIGNED-BYTE n); if the stream is to be un:BUFFERED, n must be a multiple of 8.
If n is not a multiple of 8, CLISP will use the specified number of bits for i/o, and write the file length (as a number of n-bit bytes) in the preamble.
This is done to ensure the input/output consistency: suppose you open a file with :ELEMENT-TYPE of (UNSIGNED-BYTE 3) and write 7 bytes (i.e., 21 bit) there. The underlying OS can do input/output only in whole 8-bit bytes. Thus the OS will report the size of the file as 3 (8-bit) bytes. Without the preamble CLISP will have no way to know how many 3-bit bytes to read from this file - 6, 7 or 8.
EXT:ENCODINGs, (constant) SYMBOLs in the "CHARSET" package, STRINGs (denoting iconv-based encodings), the symbol :DEFAULT, and the line terminator keywords :UNIX, :MAC, :DOS. The default encoding is CUSTOM:*DEFAULT-FILE-ENCODING*.
for functions that create SOCKET:SOCKET-STREAMs and pipes, :DEFAULT is equivalent to NIL;
for functions that open files, :DEFAULT means that buffered file streams will be returned for regular files and (on Unix) block-devices, and unbuffered file streams for special files.
Function CLOSE is a GENERIC-FUNCTION, see section "Gray streams".
CLOSE ignores its :ABORT argument.
GET-OUTPUT-STREAM-STRING returns the same value after CLOSE as it would before it.
CLOSE on an already closed STREAM does nothing and returns T.
If you do not CLOSE your STREAM explicitly, it will be closed at garbage-collection time automatically. This is not recommended though because garbage-collection is not deterministic. Please use WITH-OPEN-STREAM etc.
Function OPEN-STREAM-P is a GENERIC-FUNCTION, see section "Gray streams".
INPUT-STREAM-P and INTERACTIVE-STREAM-P return false for BROADCAST-STREAMs.
(EXT:MAKE-BUFFERED-OUTPUT-STREAM function) returns a buffered output STREAM. function is a FUNCTION expecting one argument, a SIMPLE-STRING. WRITE-CHAR collects the CHARACTERs in a STRING, until a newline character is written or FORCE-OUTPUT/FINISH-OUTPUT is called. Then function is called with a SIMPLE-STRING as argument, that contains the characters collected so far. CLEAR-OUTPUT dicards the characters collected so far.
(EXT:MAKE-BUFFERED-INPUT-STREAM function mode) returns a buffered input STREAM. function is a FUNCTION of 0 arguments that returns either NIL (stands for end-of-stream) or up to three values string, start, end. READ-CHAR returns the CHARACTERs of the current string one after another, as delimited by start and end, which default to 0 and NIL, respectively. When the string is consumed, function is called again. The string returned by function should not be changed, otherwise function should copy the string with COPY-SEQ or SUBSEQ beforehand. mode determines the behavior of LISTEN when the current string buffer is empty:
the stream acts like a FILE-STREAM, i.e. function is called
the stream acts like an interactive stream without end-of-stream, i.e. one can assume that further characters will always arrive, without calling function
this FUNCTION tells, upon call, if further non-empty strings are to be expected.
Variable CUSTOM:*PRINT-CLOSURE*. An additional variable CUSTOM:*PRINT-CLOSURE* controls whether compiled and interpreted functions (closures) are output in detailed form. If CUSTOM:*PRINT-CLOSURE* is non-NIL, compiled closures are output in #Y syntax which the reader understands. CUSTOM:*PRINT-CLOSURE* is initially set to NIL.
Variable CUSTOM:*PRINT-RPARS*. An additional variable CUSTOM:*PRINT-RPARS* controls the output of the right (closing) parentheses. If CUSTOM:*PRINT-RPARS* is non-NIL, closing parentheses which do not fit onto the same line as the the corresponding opening parenthesis are output just below their corresponding opening parenthesis, in the same column. CUSTOM:*PRINT-RPARS* is initially set to NIL.
Variable CUSTOM:*PRINT-INDENT-LISTS*. An additional variable CUSTOM:*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. CUSTOM:*PRINT-INDENT-LISTS* is initially set to 1.
Variable CUSTOM:*PPRINT-FIRST-NEWLINE*. An additional variable CUSTOM:*PPRINT-FIRST-NEWLINE* controls pretty-printing of multi-line objects. When CUSTOM:*PPRINT-FIRST-NEWLINE* is non-NIL, and the current line already has some characters on it, and the next object will be printed on several lines, and it does not start with a #\Newline, then a #\Newline is printed before the object. CUSTOM:*PPRINT-FIRST-NEWLINE* has no effect if *PRINT-PRETTY* is NIL. CUSTOM:*PPRINT-FIRST-NEWLINE* is initially set to T.
When *PRINT-READABLY* is true, other vectors are written as follows: if the ARRAY-ELEMENT-TYPE is T, the syntax #(x0 ... xn-1) is used. Otherwise, the syntax #A(element-type dimensions contents) is used.
When *PRINT-READABLY* is true, other arrays are written as follows: if the ARRAY-ELEMENT-TYPE is T, the syntax #rankA contents is used. Otherwise, the syntax #A(element-type dimensions contents) is used.
The Lisp Pretty Printer implementation is not perfect yet. PPRINT-LOGICAL-BLOCK does not respect *PRINT-LINES*.
A pprint dispatch table is a CONS of a symbol *PRINT-PPRINT-DISPATCH* an alist which maps types into priorities and print functions. Their use is strongly discouraged because of the performance issues: when *PRINT-PPRINT-DISPATCH* is non-trivial and *PRINT-PRETTY* is non-NIL, printing of every object requires a lookup in the table, which entails many calls to TYPEP (which cannot be made fast enough).
Functions WRITE & WRITE-TO-STRING. The functions WRITE and WRITE-TO-STRING have an additional keyword argument :closure which is used to bind CUSTOM:*PRINT-CLOSURE*.
The additional FORMAT instruction ~! is similar to ~/, but avoids putting a function name into a string, thus, even if the function is not interned in the "COMMON-LISP-USER" package, you might not need to specify the package explicitly. (FORMAT stream "~args!" function object) is equivalent to (FUNCALL function stream object colon-modifier-p atsign-modifier-p args).
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* does not matter if *PRINT-READABLY* is true.
FORMAT ~T can determine the current column of any built-in stream.
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 standard] Issue 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 CL standard]. Therefore, in this case, CLISP's behavior is determined by the value of CUSTOM:*PRINT-PATHNAMES-ANSI*: when it is NIL, we print pathnames like this: #-CLISP #P"" #+CLISP #S(PATHNAME ...). Otherwise, when the variable CUSTOM:*PRINT-PATHNAMES-ANSI* is non-NIL, the #P"" notation is used as per 1.5.1.4.1 Resolution of Apparent Conflicts in Exceptional Situations.
*PRINT-CASE* controls the output not only of symbols, but also of characters and some #<...> objects.
In the absence of SYS::WRITE-FLOAT-DECIMAL , floating point numbers are output in radix 2. This function is defined in "floatpri.lisp" and is not available if you run CLISP without a memory image (which you should never do anyway!)
If *PRINT-READABLY* is true, *READ-DEFAULT-FLOAT-FORMAT* has no influence on the way floating point numbers are printed.
*PRINT-PRETTY* is initially NIL but set to T in #P"config.lisp". This makes screen output prettier.
*PRINT-PRETTY* is initially NIL but set to T in #P"config.lisp". This makes unbuffered screen output both much faster and prettier.
*PRINT-ARRAY* is initially set to T.
This is the list of objects whose external representation cannot be meaningfully read in:
Table 23-1. Unreadable objects
format | meaning |
---|---|
#<type ...> | all STRUCTURE-OBJECTs lacking a keyword constructor |
#<ARRAY type dimensions> | all ARRAYs except STRINGs, if *PRINT-ARRAY* is NIL |
#<SYSTEM-FUNCTION name> | built-in function written in C |
#<ADD-ON-SYSTEM-FUNCTION name> | other function written in C |
#<SPECIAL-OPERATOR name> | special operator handler |
#<COMPILED-CLOSURE name> | compiled function, if CUSTOM:*PRINT-CLOSURE* is 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* is NIL |
#<READTABLE #x...> | READTABLE |
#<SYMBOL-MACRO form> | SYMBOL-MACRO handler |
#<MACRO function> | macro expander (defined by DEFMACRO and friends) |
#<FFI:FOREIGN-POINTER #x...> | foreign pointer (Platform dependent: UNIX, Win32, Amiga platforms only.) |
#<FFI:FOREIGN-ADDRESS #x...> | foreign address (Platform dependent: UNIX, Win32, Amiga platforms only.) |
#<FFI:FOREIGN-VARIABLE name #x...> | foreign variable (Platform dependent: UNIX, Win32, Amiga platforms only.) |
#<FFI:FOREIGN-FUNCTION name #x...> | foreign function (Platform dependent: UNIX, Win32, Amiga 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 |
#\Code allows input of characters of arbitrary code: e.g., #\Code231 reads as the character (CODE-CHAR 231.).
#Y is used to read compiled functions and to set the current input STREAM's EXT:ENCODING.
#"" is used to read pathnames: #"test.lisp" is the value of (PATHNAME "test.lisp")
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 of MAKE-PACKAGE and DEFPACKAGE.
The compiler can be called not only by the functions COMPILE, COMPILE-FILE and DISASSEMBLE, but also by the declaration (compile).
(COMPILE-FILE input-file &KEY :OUTPUT-FILE :LISTING :WARNINGS :VERBOSE :PRINT :EXTERNAL-FORMAT) compiles a file to platform-independent bytecode.
should be a pathname designator.
should be NIL or T or a pathname designator or an output STREAM. The default is T.
should be NIL or T or a pathname designator or an output STREAM. The default is NIL.
specifies whether warnings should also appear on the screen.
specifies whether error messages should also appear on the screen.
specifies whether an indication which forms are being compiled should appear on the screen.
The variables CUSTOM:*COMPILE-WARNINGS*, *COMPILE-VERBOSE*, *COMPILE-PRINT* provide defaults for the :WARNINGS, :VERBOSE, :PRINT keyword arguments, respectively, and are bound by COMPILE-FILE to the values of the arguments, i.e., these arguments are recursive.
For each input file (default file type: #P".lisp") the following files are generated:
File | When | Default file type | Contents |
---|---|---|---|
output file | only if :OUTPUT-FILE is not NIL | #P".fas" | can be loaded using the LOAD function |
auxiliary output file | only if :OUTPUT-FILE is not NIL | #P".lib" | used by COMPILE-FILE when compiling a REQUIRE form referring to the input file |
listing file | only if :LISTING is not NIL | #P".lis" | disassembly of the output file |
C output file | only if :OUTPUT-FILE is not NIL | #P".c" | foreign function interface; this file is deleted if it is empty |
The default for the :OUTPUT-FILE argument is T, which means #P".fas".
The function REQUIRE receives as the optional argument either a PATHNAME or a LIST of PATHNAMEs: files to be LOADed if the required module is not already present.
At compile time, (REQUIRE #P"foo") forms are treated specially: CUSTOM:*LOAD-PATHS* is searched for #P"foo.lisp" and #P"foo.lib". If the latest such file is a #P".lisp", it is compiled; otherwise the #P".lib" is loaded.
The #P".lib" is a "header" file which contains the constant, variable, inline and macro definitions necessary for compilation of the files that REQUIRE this file, but not the function definitions and calls that are not necessary for that. Thus it is not necessary to either enclose REQUIRE forms in EVAL-WHEN or to load the required files in the makefiles: if you have two files, #P"foo.lisp" and #P"bar.lisp", and the latter requires the former, you can write in your #P"Makefile":
all: foo.fas bar.fas foo.fas: foo.lisp clisp -c foo bar.fas: bar.lisp foo.fas clisp -c bar |
bar.fas: bar.lisp foo.fas clisp -i foo -c bar |
LOAD has four additional keywords :ECHO, :COMPILING, :EXTRA-FILE-TYPES, and :OBSOLETE-ACTION.
(LOAD filename &KEY :VERBOSE :PRINT :ECHO :IF-DOES-NOT-EXIST :COMPILING :EXTRA-FILE-TYPES :OBSOLETE-ACTION)
causes LOAD to emit a short message that a file is being loaded. The default is *LOAD-VERBOSE*, which is initially T.
causes LOAD to print the value of each form. The default is *LOAD-PRINT*, which is initially NIL.
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 CUSTOM:*LOAD-ECHO*, which is initially NIL.
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 CUSTOM:*LOAD-COMPILING*, which is initially NIL.
Specifies the additional file types considered for loading, in addition to CUSTOM:*SOURCE-FILE-TYPES* (which is initially ("lisp" "lsp" "cl")) and CUSTOM:*COMPILED-FILE-TYPES* (which is initially ("fas")).
When filename does not spefify a unique file (e.g., filename is #P"foo" and both #P"foo.lisp" and #P"foo.fas" are found in the CUSTOM:*LOAD-PATHS*), then the newest file is loaded.
Specifies the action to take when loading a #P".fas" with a different bytecode version from the one supported by this CLISP version. The possible actions are :DELETE to delete the #P".fas" and :ERROR to SIGNAL an ERROR. The default action is to WARN and look for another matching file. If no file can be loaded and :IF-DOES-NOT-EXIST is non-NIL, an ERROR is SIGNALed. The default is CUSTOM:*LOAD-OBSOLETE-ACTION*, which is initially NIL.
The variables *LOAD-VERBOSE*, *LOAD-PRINT*, CUSTOM:*LOAD-OBSOLETE-ACTION*, CUSTOM:*LOAD-COMPILING*, and CUSTOM:*LOAD-ECHO* are bound by LOAD when it receives a corresponding keyword argument (:VERBOSE, :PRINT, :OBSOLETE-ACTION, :COMPILING, and :ECHO), i.e., these arguments are recursive, just like the arguments :WARNINGS, :VERBOSE, and :PRINT for COMPILE-FILE.
Variable CUSTOM:*LOAD-PATHS*. The variable CUSTOM:*LOAD-PATHS* contains a list of directories where the files are looked for - in addition to the specified or current directory - by LOAD, REQUIRE, COMPILE-FILE and LOAD-LOGICAL-PATHNAME-TRANSLATIONS.
The variable *FEATURES* initially contains the symbols
Table 24-1. *FEATURES* content
keyword | meaning |
---|---|
:CLISP | the name of this implementation |
:ANSI-CL | |
:COMMON-LISP | |
:INTERPRETER | |
:COMPILER | |
:SOCKETS | see SOCKET:SOCKET-STREAMs |
:GENERIC-STREAMS | see Defining new kinds of Streams |
:SYSCALLS | see System Calls |
:DIR-KEY | see Directory Access |
:LOGICAL-PATHNAMES | |
:FFI | if a foreign function interface (see "FFI") is supported (Platform dependent: many UNIX, Win32 platforms only) |
:GETTEXT | if internationalization (see "I18N") using the GNU gettext package is supported (Platform dependent: most UNIX platforms only) |
:UNICODE | if UNICODE (ISO 10646) characters are supported (see "CHARSET") |
: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 95/98/NT/Me/2000/XP) |
:PC386 | if hardware = PC (clone) with a 386/486/586/686 CPU |
:UNIX | if operating system = Unix (in this case the hardware is irrelevant!) |
:CYGWIN | if CLISP is using the Cygwin UNIX compatibility layer on top of Win32 (in that case :UNIX is also present) |
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 loop (called "break loops") which are similar 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. Each command has a keyword abbreviation, indicated in the second column.
Table 25-1. Commands common to the main loop, the debugger and the stepper
command | abbreviation | operation |
---|---|---|
Help | :h | prints a list of available commands |
Table 25-2. Commands common to the debugger and the stepper
command | abbreviation | operation |
---|---|---|
Abort | :a | abort to the next most recent read-eval-print loop |
Unwind | :uw | abort to the next most recent read-eval-print loop |
Quit | :q | quit to the top 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.
Table 25-3. Commands common to the debugger and the stepper
command | abbreviation | operation |
---|---|---|
Error | :e | print the last error message. |
Inspect | :i | inspect the last error message. |
Mode-1 | :m1 | sets the current mode to 1: all the stack elements are considered. This mode works fine for debugging compiled functions. |
Mode-2 | :m2 | sets the current mode to 2: all the frames are considered. |
Mode-3 | :m3 | sets the current mode to 3: only lexical frames (frames that correspond to special forms that modify the lexical environment) are considered. |
Mode-4 | :m4 | 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 | :m5 | sets the current mode to 5: only APPLY frames are considered. Every invocation of an interpreted function corresponds to one APPLY frame. |
Where | :w | shows the current stack frame. |
Up | :u | goes up one frame, i.e., to the caller if in mode-5 |
Down | :d | does down one frame, i.e., to the callee if in mode-5 |
Top | :t | goes to top frame, i.e., to the top-level form if in mode-4 |
Bottom | :b | goes to bottom (most recent) frame, i.e., most probably to the form or function that caused the debugger to be entered. |
Backtrace | :bt | lists the stack in current mode, bottom frame first, top frame last. |
Backtrace-1 | :bt1 | lists the stack in mode 1. |
Backtrace-2 | :bt2 | lists the stack in mode 2. |
Backtrace-3 | :bt3 | lists the stack in mode 3. |
Backtrace-4 | :bt4 | lists the stack in mode 4. |
Backtrace-5 | :bt5 | lists the stack in mode 5. |
Frame-limit | :fl | set the frame-limit: this many frames will be printed in a backtrace at most. |
Backtrace-l | :bl | limit of frames to print will be prompted for. |
If the current stack frame is an EVAL or APPLY frame, the following commands are available as well:
Table 25-4. Commands specific to EVAL/APPLY
command | abbreviation | operation |
---|---|---|
Break+ | :br+ | 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 EXT:*TRACE-VALUES* containing a list of its values. |
Break- | :br- | removes a breakpoint from the current frame. |
Redo | :rd | re-evaluates the corresponding form or function call. This command can be used to restart parts of a computation without aborting it entirely. |
Return | :rt | leaves the current frame. You will be prompted for the return values. |
Table 25-5. Commands specific to the debugger
command | abbreviation | operation |
---|---|---|
Continue | :c | continues evaluation of the program. |
Table 25-6. Commands specific to the stepper
command | abbreviation | operation |
---|---|---|
Step | :s | step into a form: evaluate this form in single step mode |
Next | :n | step over a form: evaluate this form at once |
Over | :o | step over this level: evaluate at once up to the next return |
Continue | :c | 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.
DISASSEMBLE can disassemble to machine code, provided that GNU gdb is present. In that case the argument may be a EXT:SYSTEM-FUNCTION, a FFI:FOREIGN-FUNCTION, a special operator indicator, a symbol denoting one of these, a number, or a string.
The function EXT:UNCOMPILE does the converse of COMPILE: (EXT:UNCOMPILE function) reverts a compiled function (name), that has been entered or loaded in the same session and then compiled, back to its interpreted form.
No on-line documentation is available for the system functions (yet).
Function EXT:CLHS. [Common Lisp HyperSpec] access is provided via (EXT:CLHS symbol &KEY :BROWSER) function, which uses your web browser. browser (defaults to CUSTOM:*BROWSER*) should be a valid keyword in the CUSTOM:*BROWSERS* alist.
(TRACE function ...) makes the functions function, ... traced. function should be either a symbol or a list (symbol &KEY :suppress-if :step-if :pre :post :pre-break-if :post-break-if :pre-print :post-print :PRINT), where
no trace output as long as form is true
invokes the stepper as soon as form is true
evaluates form before calling the function
evaluates form after return from the function
goes into the break loop before calling the function if form is true
goes into the break loop after return from the function if form is true
prints the values of form before calling the function
prints the values of form after return from the function
prints the values of form both before calling and after return from the function
In all these forms you can access the following variables:
the function itself
the arguments to the function
the function/macro call as form
after return from the function: the list of return values from the function call
TRACE and UNTRACE are also applicable to functions (SETF symbol) and to macros, but not to locally defined functions and macros.
Variable CUSTOM:*TRACE-INDENT*. If you want the TRACE level to be indicated by the indentation in addition to the printed numbers, set CUSTOM:*TRACE-INDENT* to non-NIL. Initially it is NIL since many nested traced calls will easily exhaust the available line length.
The function INSPECT takes a keyword argument :frontend, which specifies the way CLISP will interact with the user.
Available :frontends for INSPECT in CLISP
The interaction is conducted via the *TERMINAL-IO* stream. Please use the :h command to get the list of all available commands.
A window in your Web browser (specified by the :BROWSER keyword argument) is opened and it is controlled by CLISP via a SOCKET:SOCKET-STREAM, using the HTTP protocol. You should be able to use all the standard browser features.
Since CLISP is not multitasking at this time, you will not be able to do anything else during an INSPECT session. Please click on the quit link to terminate the session.
Please be aware though, that once you terminate an INSPECT session, all links in all INSPECT windows in your browser will become obsolete and using them in a new INSPECT session will result in unpredictable behavior.
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 EXT:GC starts a global garbage-collection and its return value has the same meaning as the second value of ROOM.
The timing data printed by the macro TIME includes:
the real time ("wall" time), |
the run time (processor time for this process), |
the number of bytes allocated, and |
the number of garbage-collections performed, if any. |
The macro EXT:TIMES (mnemonic: "TIME and Space") is like the macro TIME: (EXT:TIMES form) evaluates the form, and, as a side effect, outputs detailed information about the memory allocations caused by this evaluation. It also prints everything printed by TIME.
The function ED calls the external editor specified by the value of (EXT:GETENV "EDITOR") or, failing that, the value of the variable CUSTOM:*EDITOR* (see #P"config.lisp"). If the argument is a function name which was defined in the current session (not loaded from a file), the program text to be edited is a pretty-printed version (without comments) of the text which was used to define the function.
The variable CUSTOM:*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 time zone in a decoded time must not necessarily be an INTEGER, but (as FLOAT or RATIONAL number) it should be a multiple of 1/3600.
Table 25-7. Time granularity
platform | Acorn, DOS, OS/2 | Amiga | UNIX | Win32 |
---|---|---|---|---|
INTERNAL-TIME-UNITS-PER-SECOND | 100 | 50 | 1,000,000 | 10,000,000 |
GET-INTERNAL-RUN-TIME returns the amount of run time consumed by the current CLISP process since its startup.
The functions SHORT-SITE-NAME, LONG-SITE-NAME should be defined in a site-specific #P"config.lisp" file. The default implementations try to read the value of the environment variable ORGANIZATION, and, failing that, call uname.
The functions SHORT-SITE-NAME, LONG-SITE-NAME should be defined in a site-specific #P"config.lisp" file. The default implementations try to read the registry.
The functions MACHINE-TYPE, MACHINE-VERSION, MACHINE-INSTANCE and SHORT-SITE-NAME, LONG-SITE-NAME should be defined by every user in his user-specific #P"config.lisp" file.
The search performed by APROPOS and APROPOS-LIST is case-insensitive.
If DRIBBLE is called with an argument, and dribbling is already enabled, a warning is printed, and the new dribbling request is ignored.
Dribbling is implemented via a kind (but not recognizable subtype) of TWO-WAY-STREAM, named EXT:DRIBBLE-STREAM. If you have a source bidirectional STREAM x and you want all transactions (input and output) on x to be copied to the target output STREAM y, you can do
(DEFVAR *loggable* x) (SETQ x (MAKE-SYNONYM-STREAM '*loggable*)) (DEFUN toggle-logging (&OPTIONAL s) (MULTIPLE-VALUE-BIND (so ta) (dribble-toggle *loggable* s) (WHEN (STREAMP so) (SETQ *loggable* so)) ta)) (toggle-logging y) ; start logging ... (toggle-logging) ; finish logging ... (toggle-logging y) ; restart logging ... (toggle-logging) ; finish logging (CLOSE y) |
When stream is a EXT:DRIBBLE-STREAM, returns two values: the source and the target streams. Otherwise returns NIL.
When stream is a EXT:DRIBBLE-STREAM, returns T, otherwise returns NIL.
When stream is a EXT:DRIBBLE-STREAM, returns its source stream, otherwise signals a TYPE-ERROR.
When stream is a EXT:DRIBBLE-STREAM, returns its target stream, otherwise signals a TYPE-ERROR.
Create a new EXT:DRIBBLE-STREAM.
When stream is a EXT:DRIBBLE-STREAM and pathname is NIL, writes a dribble termination note to the stream's target STREAM and returns stream's source and target STREAMs; when stream is not a EXT:DRIBBLE-STREAM and pathname is non-NIL, creates a new EXT:DRIBBLE-STREAM, dribbling from stream to pathname, writes a dribble initialization note to pathname, and return the EXT:DRIBBLE-STREAM (the second value is the target STREAM); otherwise WARN that no appropriate action may be taken. pathname may be an open output STREAM or a pathname designator. See above for the sample usage. See also #P"src/dribble.lisp" in the CLISP source tree.
LISP-IMPLEMENTATION-VERSION returns the numeric version (like 3.14), and the release date (like "1999-07-21"). When running on the same machine on which CLISP was built, it appends the binary build and memory image dump date in universal time (like 3141592654). When running on a different machine, it appends the MACHINE-INSTANCE of the machine on which it was built.
This is the list of ANSI CL issues and their current status in CLISP, i.e., whether CLISP supports code that makes use of the functionality specified by the vote.
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes, except for argument list checking in CALL-NEXT-METHOD in compiled code (items 11,12)
yes
no
yes
yes
yes
yes
yes
yes
no
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
no
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
no
yes
yes
yes
yes
yes
yes
yes
yes
yes
no
yes
yes
yes
yes
??
yes
yes
yes
yes
yes
no
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
no
yes
yes
yes
yes, actually implement MEDIUM
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes, except that ~F, ~E, ~G, ~$ also bind *PRINT-BASE* to 10 and *PRINT-RADIX* to NIL
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
no
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
obsolete
yes
yes
yes
yes
yes
no
yes
yes
yes
yes
yes
yes
yes
obsolete
yes
no
yes
yes
yes
yes
yes
yes
yes
yes
yes
no
no
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
no
yes when CUSTOM:*PARSE-NAMESTRING-ANSI* is non-NIL
yes
yes
yes
yes
yes
yes when CUSTOM:*PARSE-NAMESTRING-ANSI* is non-NIL
yes
no
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes, when CUSTOM:*SEQUENCE-COUNT-ANSI* is non-NIL; otherwise negative :COUNT values are not allowed.
yes
yes
yes
no
yes, except that READ-DELIMITED-LIST still constructs a list
yes
yes
yes
yes
yes
yes
yes, except that REQUIRE wants a pathname, not a list of pathnames
superseded by REQUIRE-PATHNAME-DEFAULTS-AGAIN:X3J13-DEC-91
yes
yes
yes
yes
yes
yes
no
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
no
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes, but no warning
yes
yes
yes
no
yes
yes, except for class METHOD-COMBINATION
yes
yes
yes
yes, could add error checking
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
The function (EXT:SAVEINITMEM &OPTIONAL (filename "lispinit.mem") &KEY :QUIET :INIT-FUNCTION :LOCKED-PACKAGES :START-PACKAGE) saves the running CLISP's memory to the file filename; extension #P".mem" is recommended (when filename does not have an extension, #P".mem" extension is automatically added).
If this argument is not NIL, the startup banner and the good-bye message will be suppressed.
This argument specifies a function that will be executed at startup of the saved image, before entering the standard read-eval-print loop; thus, if you want to avoid the read-eval-print loop, you have to call EXT:EXIT at the end of the init function yourself.
See the manual for passing command line arguments to this function.
This argument specifies the packages to lock before saving the image; this is convenient for application delivery, when you do not want your users to mess up your product. This argument defaults to CUSTOM:*SYSTEM-PACKAGE-LIST*.
This argument specifies the starting value of *PACKAGE* in the image being saved, and defaults to the current value of *PACKAGE*.
The functions (EXT:EXIT [errorp]), (EXT:QUIT [errorp]) and (EXT:BYE [errorp]) - all synonymous - terminate CLISP. If errorp is non-NIL, CLISP aborts with the supplied numeric error status, i.e., the OS environment is informed that the CLISP session did not succeed.
"Internationalization" means to prepare a program so that it can use multiple national languages and national cultural conventions without requiring further source code changes. Localization means providing the data - mostly textual translations - necessary for an internationalized program to work in a particular language and with particular cultural conventions.
CLISP is internationalized, and is localized for the languages English, German, French, Spanish, Dutch and Russian. CLISP also supports internationalized Lisp programs, through GNU gettext.
GNU gettext is a set of functions, included in CLISP or the C library, which permit looking up translations of strings through message catalogs. It is also a set of tools which makes the translation maintenance easy for the translator and the program maintainer.
The GNU gettext functions are available in CLISP in the "I18N" package, which is EXT:RE-EXPORTed from the "EXT" package.
returns the translation of the message MSGID, in the given DOMAIN, depending on the given CATEGORY. MSGID should be an ASCII string, and is normally the English message.
returns the plural form of the translation for of MSGID and n in the given DOMAIN, depending on the given CATEGORY. MSGID and msgid_plural should be ASCII strings, and are normally the English singular and English plural variant of the message, respectively.
The DOMAIN is a string identifier denoting the program that is requesting the translation. The pathname of the message catalog depends on the DOMAIN: usually it is located at TEXTDOMAINDIR/l/LC_MESSAGES/domain.mo, where l is the ISO 639 code of the language. The notion of DOMAIN allows several Lisp programs running in the same image to request translations independently of each other.
Function I18N:TEXTDOMAIN. (I18N:TEXTDOMAIN) is a place that returns the default DOMAIN, used when no DOMAIN argument is passed to the I18N:GETTEXT and I18N:NGETTEXT functions. It is SETFable. (SETF I18N:TEXTDOMAIN) is usually used during the startup phase of a program. Note that the default DOMAIN is not saved in a memory image. The use of (SETF I18N:TEXTDOMAIN) is recommended only for programs that are so simple that they will never need more than one DOMAIN.
Function I18N:TEXTDOMAINDIR. (I18N:TEXTDOMAINDIR DOMAIN) is a place that returns the base directory, called TEXTDOMAINDIR above, where the message catalogs for the given DOMAIN are assumed to be installed. It is SETFable. (SETF I18N:TEXTDOMAINDIR) is usually used during the startup phase of a program, and should be used because only the program knows where its message catalogs are installed. Note that the TEXTDOMAINDIRs are not saved in a memory image.
The CATEGORY argument of the I18N:GETTEXT and I18N:NGETTEXT functions denotes which locale facet the result should depend on. The default value is :LC_MESSAGES. Other possible values are :LC_CTYPE, :LC_TIME, :LC_COLLATE, :LC_MONETARY. The use of these values is useful for users who have a character/time/collation/money handling set differently from the usual message handling. Note that when a CATEGORY argument is used, the message catalog location depends on the CATEGORY: it will be expected at TEXTDOMAINDIR/ll/category/domain.mo.
A non-internationalized program simulating a restaurant dialogue might look as follows.
Example 29-1. prog.lisp
(setq n (parse-integer (first EXT:*ARGS*))) (format t "~A~%" "'Your command, please?', asked the waiter.") (format t "~@?~%" (if (= n 1) "a piece of cake" "~D pieces of cake") n) |
After being internationalized, all strings are wrapped in I18N:GETTEXT calls, and I18N:NGETTEXT is used for plurals. Also, I18N:TEXTDOMAINDIR is assigned a value; in our case, for simplicity, the current directory.
Example 29-2. prog.lisp
(setf (textdomain) "prog") (setf (textdomaindir "prog") "./") (setq n (parse-integer (first EXT:*ARGS*))) (format t "~A~%" (gettext "'Your command, please?', asked the waiter.")) (format t "~@?~%" (ngettext "a piece of cake" "~D pieces of cake" n) n) |
For ease of reading, it is customary to define an abbreviation for the I18N:GETTEXT function. An underscore is customary.
Example 29-3. prog.lisp
(setf (textdomaindir "prog") "./") (defun _ (msgid) (gettext msgid "prog")) (setq n (parse-integer (first EXT:*ARGS*))) (format t "~A~%" (_"'Your command, please?', asked the waiter.")) (format t "~@?~%" (ngettext "a piece of cake" "~D pieces of cake" n "prog") n) |
Now the program's maintainer creates a message catalog template through the command
bash$ xgettext -o prog.pot prog.lisp |
The message catalog template looks roughly like this.
Example 29-4. prog.pot
msgid "'Your command, please?', asked the waiter." msgstr "" msgid "a piece of cake" msgid_plural "%d pieces of cake" msgstr[0] "" msgstr[1] "" |
Then a French translator creates a French message catalog
Example 29-5. prog.fr.po
msgid "" msgstr "" "Content-Type: text/plain; charset=ISO-8859-1\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" msgid "'Your command, please?', asked the waiter." msgstr "«Votre commande, s'il vous plait», dit le garçon." # Les gateaux allemands sont les meilleurs du monde. msgid "a piece of cake" msgid_plural "%d pieces of cake" msgstr[0] "un morceau de gateau" msgstr[1] "%d morceaux de gateau" |
and sends it to the program's maintainer.
The program's maintainer compiles the catalog as follows:
bash$ mkdir -p ./fr/LC_MESSAGES bash$ msgfmt -o ./fr/LC_MESSAGES/prog.mo prog.fr.po |
When a user in a french locale then runs the program
bash$ clisp prog.lisp 2 |
«Votre commande, s'il vous plait», dit le garçon. 2 morceaux de gateau |
![]() | Note that the facilities described in this section will work only for the languages for which CLISP itself is already localized. |
The language CLISP uses to communicate with the user can be one of
ENGLISH |
DEUTSCH (i.e., German) |
FRANÇAIS (i.e., French) |
ESPAÑOL (i.e., Spanish) |
NEDERLANDS (i.e., Dutch) |
РУССКИЙ (i.e. Russian) |
This is controlled by the SYMBOL-MACRO CUSTOM:*CURRENT-LANGUAGE*, which can be set at run time as well as using -L start-up option. If you wish to change the locale directory at run time too, you can do that by setting CUSTOM:*CURRENT-LANGUAGE* to a CONS cell, whose CAR is the language (a SYMBOL, one of the above), and whose CDR is the new locale directory.
More languages can be defined through the macro I18N:DEFLANGUAGE: (I18N:DEFLANGUAGE language). For such an additional language to take effect, you must install the corresponding message catalog, or translate the messages yourself, using GNU gettext and Emacs (or XEmacs) po-mode.
This works only for strings. For arbitrary language-dependent Lisp objects, you define one through the macro I18N:DEFINTERNATIONAL: (I18N:DEFINTERNATIONAL symbol &OPTIONAL (default-language T)) and add language-dependent values through the macro I18N:DEFLOCALIZED: (I18N:DEFLOCALIZED symbol language value-form) (One such form for each language. Languages without an assigned value will be treated like the default-language.) You can then access the localized value by calling I18N:LOCALIZED: (I18N:LOCALIZED symbol &OPTIONAL language)
An encoding describes the correspondence between CHARACTERs and raw bytes during input/output via STREAMs with STREAM-ELEMENT-TYPE CHARACTER.
An EXT:ENCODING is an object composed of the following facets:
This denotes both the set of characters that can be represented and passed through the I/O channel, and the way these characters translate into raw bytes. In this context, for example, "UTF-8" and "UCS-4" are considered different, although they can represent the same set of characters.
This denotes the way newline characters are represented.
Encodings are also types. As such, they represent the set of characters encodable in the character set. In this context, the way characters are translated into raw bytes is ignored, and the line terminator mode is ignored as well. TYPEP and SUBTYPEP can be used on encodings.
Only one character set is understood: the platform's native (8-bit) character set. See Chapter 13.
The following character sets are supported, as values of the corresponding (constant) symbol in the "CHARSET" package:
UCS-2 = UNICODE-16 = UNICODE-16-BIG-ENDIAN, the 16-bit basic multilingual plane of the UNICODE character set. Every character is represented as two bytes.
UNICODE-16-LITTLE-ENDIAN
UCS-4 = UNICODE-32 = UNICODE-32-BIG-ENDIAN, the 21-bit UNICODE character set. Every character is represented as four bytes.
UNICODE-32-LITTLE-ENDIAN
UTF-8, the 21-bit UNICODE character set. Every character is represented as one to four bytes. ASCII characters represent themselves and need one byte per character. Most Latin/Greek/Cyrillic/Hebrew characters need two bytes per character. Most other characters need three bytes per character, and the rarely used remaining characters need four bytes per character. This is therefore, in general, the most space-efficient encoding of all of Unicode.
UTF-16, the 21-bit UNICODE character set. Every character in the 16-bit basic multilingual plane is represented as two bytes, and the rarely used remaining characters need four bytes per character. This character set is only available on platforms with GNU libc or GNU libiconv.
UTF-7, the 21-bit UNICODE character set. This is a stateful 7-bit encoding. Not all ASCII characters represent themselves. This character set is only available on platforms with GNU libc or GNU libiconv.
JAVA, the 21-bit UNICODE character set. ASCII characters represent themselves and need one byte per character. All other characters of the basic multilingual plane are represented by \unnnn sequences (nnnn a hexadecimal number) and need 6 bytes per character. The remaining characters are represented by \uxxxx\uyyyy and need 12 bytes per character. While this encoding is very comfortable for editing Unicode files using only ASCII-aware tools and editors, it cannot faithfully represent all UNICODE text. Only text which does not contain \u (backslash followed by lowercase Latin u) can be faithfully represented by this encoding.
ASCII, the well-known US-centric 7-bit character set (American Standard Code for Information Interchange - ASCII).
ISO-8859-1, an extension of the ASCII character set, suitable for the Afrikaans, Albanian, Basque, Breton, Catalan, Cornish, Danish, Dutch, English, Faeroese, Finnish, French, Frisian, Galician, German, Greenlandic, Icelandic, Irish, Italian, Latin, Luxemburgish, Norwegian, Portuguese, Raeto-Romanic, Scottish, Spanish, and Swedish languages.
ISO-8859-2, an extension of the ASCII character set, suitable for the Croatian, Czech, German, Hungarian, Polish, Slovak, Slovenian, and Sorbian languages.
ISO-8859-3, an extension of the ASCII character set, suitable for the Esperanto and Maltese languages.
ISO-8859-4, an extension of the ASCII character set, suitable for the Estonian, Latvian, Lithuanian and Sami (Lappish) languages.
ISO-8859-5, an extension of the ASCII character set, suitable for the Bulgarian, Byelorussian, Macedonian, Russian, Serbian, and Ukrainian languages.
ISO-8859-6, suitable for the Arabic language.
ISO-8859-7, an extension of the ASCII character set, suitable for the Greek language.
ISO-8859-8, an extension of the ASCII character set, suitable for the Hebrew language (without punctuation).
ISO-8859-9, an extension of the ASCII character set, suitable for the Turkish language.
ISO-8859-10, an extension of the ASCII character set, suitable for the Estonian, Icelandic, Inuit (Greenlandic), Latvian, Lithuanian, and Sami (Lappish) languages.
ISO-8859-13, an extension of the ASCII character set, suitable for the Estonian, Latvian, Lithuanian, Polish and Sami (Lappish) languages.
ISO-8859-14, an extension of the ASCII character set, suitable for the Irish Gaelic, Manx Gaelic, Scottish Gaelic, and Welsh languages.
ISO-8859-15, an extension of the ASCII character set, suitable for the ISO-8859-1 languages, with improvements for French, Finnish and the Euro.
ISO-8859-16 an extension of the ASCII character set, suitable for the Rumanian language.
KOI8-R, an extension of the ASCII character set, suitable for the Russian language (very popular, especially on the internet).
KOI8-U, an extension of the ASCII character set, suitable for the Ukrainian language (very popular, especially on the internet).
KOI8-RU, an extension of the ASCII character set, suitable for the Russian language. This character set is only available on platforms with GNU libiconv.
JIS_X0201, a character set for the Japanese language.
MAC-ARABIC, a platform specific extension of the ASCII character set.
MAC-CENTRAL-EUROPE, a platform specific extension of the ASCII character set.
MAC-CROATIAN, a platform specific extension of the ASCII character set.
MAC-CYRILLIC, a platform specific extension of the ASCII character set.
MAC-DINGBAT, a platform specific character set.
MAC-GREEK, a platform specific extension of the ASCII character set.
MAC-HEBREW, a platform specific extension of the ASCII character set.
MAC-ICELAND, a platform specific extension of the ASCII character set.
MAC-ROMAN = MACINTOSH, a platform specific extension of the ASCII character set.
MAC-ROMANIA, a platform specific extension of the ASCII character set.
MAC-SYMBOL, a platform specific character set.
MAC-THAI, a platform specific extension of the ASCII character set.
MAC-TURKISH, a platform specific extension of the ASCII character set.
MAC-UKRAINE, a platform specific extension of the ASCII character set.
CP437, a DOS oldie, a platform specific extension of the ASCII character set.
CP437-IBM, an IBM variant of CP437.
CP737, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for the Greek language.
CP775, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for some Baltic languages.
CP850, a DOS oldie, a platform specific extension of the ASCII character set.
CP852, a DOS oldie, a platform specific extension of the ASCII character set.
CP852-IBM, an IBM variant of CP852.
CP855, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for the Russian language.
CP857, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for the Turkish language.
CP860, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for the Portuguese language.
CP860-IBM, an IBM variant of CP860.
CP861, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for the Icelandic language.
CP861-IBM, an IBM variant of CP861.
CP862, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for the Hebrew language.
CP862-IBM, an IBM variant of CP862.
CP863, a DOS oldie, a platform specific extension of the ASCII character set.
CP863-IBM, an IBM variant of CP863.
CP864, a DOS oldie, meant to be suitable for the Arabic language.
CP864-IBM, an IBM variant of CP864.
CP865, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for some Nordic languages.
CP865-IBM, an IBM variant of CP865.
CP866, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for the Russian language.
CP869, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for the Greek language.
CP869-IBM, an IBM variant of CP869.
CP874, a DOS oldie, a platform specific extension of the ASCII character set, meant to be suitable for the Thai language.
CP874-IBM, an IBM variant of CP874.
WINDOWS-1250 = CP1250, a platform specific extension of the ASCII character set, heavily incompatible with ISO-8859-2.
WINDOWS-1251 = CP1251, a platform specific extension of the ASCII character set, heavily incompatible with ISO-8859-5, meant to be suitable for the Russian language.
WINDOWS-1252 = CP1252, a platform specific extension of the ISO-8859-1 character set.
WINDOWS-1253 = CP1253, a platform specific extension of the ASCII character set, gratuitously incompatible with ISO-8859-7, meant to be suitable for the Greek language.
WINDOWS-1254 = CP1254, a platform specific extension of the ISO-8859-9 character set.
WINDOWS-1255 = CP1255, a platform specific extension of the ASCII character set, gratuitously incompatible with ISO-8859-8, suitable for the Hebrew language. This character set is only available on platforms with GNU libc or GNU libiconv.
WINDOWS-1256 = CP1256, a platform specific extension of the ASCII character set, meant to be suitable for the Arabic language.
WINDOWS-1257 = CP1257, a platform specific extension of the ASCII character set.
WINDOWS-1258 = CP1258, a platform specific extension of the ASCII character set, meant to be suitable for the Vietnamese language. This character set is only available on platforms with GNU libc or GNU libiconv.
HP-ROMAN8, a platform specific extension of the ASCII character set.
NEXTSTEP, a platform specific extension of the ASCII character set.
EUC-JP, a multibyte character set for the Japanese language. This character set is only available on platforms with GNU libc or GNU libiconv.
SHIFT-JIS, a multibyte character set for the Japanese language. This character set is only available on platforms with GNU libc or GNU libiconv.
CP932, a Microsoft variant of SHIFT-JIS. This character set is only available on platforms with GNU libc or GNU libiconv.
ISO-2022-JP, a stateful 7-bit multibyte character set for the Japanese language. This character set is only available on platforms with GNU libc or GNU libiconv.
ISO-2022-JP-2, a stateful 7-bit multibyte character set for the Japanese language. This character set is only available on platforms with GNU libc 2.3 or newer or GNU libiconv.
ISO-2022-JP-1, a stateful 7-bit multibyte character set for the Japanese language. This character set is only available on platforms with GNU libiconv.
EUC-CN, a multibyte character set for simplified Chinese. This character set is only available on platforms with GNU libc or GNU libiconv.
HZ, a stateful 7-bit multibyte character set for simplified Chinese. This character set is only available on platforms with GNU libiconv.
GBK, a multibyte character set for Chinese, This character set is only available on platforms with GNU libc or GNU libiconv.
CP936, a Microsoft variant of GBK. This character set is only available on platforms with GNU libc or GNU libiconv.
GB18030, a multibyte character set for Chinese, This character set is only available on platforms with GNU libc or GNU libiconv.
EUC-TW, a multibyte character set for traditional Chinese. This character set is only available on platforms with GNU libc or GNU libiconv.
BIG5, a multibyte character set for traditional Chinese. This character set is only available on platforms with GNU libc or GNU libiconv.
CP950, a Microsoft variant of BIG5. This character set is only available on platforms with GNU libc or GNU libiconv.
BIG5-HKSCS, a multibyte character set for traditional Chinese. This character set is only available on platforms with GNU libc or GNU libiconv.
ISO-2022-CN, a stateful 7-bit multibyte character set for Chinese. This character set is only available on platforms with GNU libc or GNU libiconv.
ISO-2022-CN-EXT, a stateful 7-bit multibyte character set for Chinese. This character set is only available on platforms with GNU libc or GNU libiconv.
EUC-KR, a multibyte character set for Korean. This character set is only available on platforms with GNU libc or GNU libiconv.
CP949, a Microsoft variant of EUC-KR. This character set is only available on platforms with GNU libc or GNU libiconv.
ISO-2022-KR, a stateful 7-bit multibyte character set for Korean. This character set is only available on platforms with GNU libc or GNU libiconv.
JOHAB, a multibyte character set for Korean used mostly on DOS. This character set is only available on platforms with GNU libc or GNU libiconv.
ARMSCII-8, an extension of the ASCII character set, suitable for the Armenian. This character set is only available on platforms with GNU libc or GNU libiconv.
GEORGIAN-ACADEMY, an extension of the ASCII character set, suitable for the Georgian. This character set is only available on platforms with GNU libc or GNU libiconv.
GEORGIAN-PS, an extension of the ASCII character set, suitable for the Georgian. This character set is only available on platforms with GNU libc or GNU libiconv.
TIS-620, an extension of the ASCII character set, suitable for the Thai. This character set is only available on platforms with GNU libc or GNU libiconv.
MULELAO-1, an extension of the ASCII character set, suitable for the Laotian. This character set is only available on platforms with GNU libiconv.
CP1133, an extension of the ASCII character set, suitable for the Laotian. This character set is only available on platforms with GNU libc or GNU libiconv.
VISCII, an extension of the ASCII character set, suitable for the Vietnamese. This character set is only available on platforms with GNU libc or GNU libiconv.
TCVN, an extension of the ASCII character set, suitable for the Vietnamese. This character set is only available on platforms with GNU libc or GNU libiconv.
The character sets provided by the library function iconv can also be used as encodings. To create such an encoding, call EXT:MAKE-ENCODING with the character set name (a string) as the :CHARSET argument.
When an EXT:ENCODING is available both as a built-in and through iconv, the built-in is used, because it is more efficient and available across all platforms.
These encodings are not assigned to global variables, since there is no portable way to get the list of all character sets supported by iconv.
On GNU systems (such as GNU/Linux and GNU/Hurd) and on systems with GNU libiconv you get this list by calling the program iconv: iconv -l.
The reason we use only GNU libc 2.2 or GNU libiconv is that the other iconv implementations are broken in various ways and we do not want to deal with random CLISP crashes caused by those bugs. If your system supplies an iconv implementation which passes the GNU libiconv's test suite, please report that to <clisp-list@sf.net> and a future CLISP version will use iconv on your system.
The line terminator mode can be one of the following three keywords:
keyword | newline representation |
---|---|
:UNIX | Newline is represented by the ASCII LF character (U000A). |
:MAC | Newline is represented by the ASCII CR character (U000D). |
:DOS | Newline is represented by the ASCII CR followed by the ASCII LF. |
Windows programs typically use the :DOS line terminator, sometimes they also accept :UNIX line terminators or produce :MAC line terminators.
The line terminator mode is relevant only for output (writing to a file/pipe/socket). During input, all three kinds of line terminators are recognized. If you do not want this, i.e., if you really want to distinguish LF, CR and CR/LF, you have to resort to binary input (function READ-BYTE).
See also 13.1.8 Treatment of Newline during Input and Output.
The function (EXT:MAKE-ENCODING &KEY :CHARSET :LINE-TERMINATOR :INPUT-ERROR-ACTION :OUTPUT-ERROR-ACTION) returns an EXT:ENCODING. The :CHARSET argument may be an encoding, a string, or :DEFAULT. The possible values for the line terminator argument are the keywords :UNIX, :MAC, :DOS.
The :INPUT-ERROR-ACTION argument specifies what happens when an invalid byte sequence is encountered while converting bytes to characters. Its value can be :ERROR, :IGNORE or a character to be used instead. The UNICODE character #\uFFFD is typically used to indicate an error in the input sequence.
The :OUTPUT-ERROR-ACTION argument specifies what happens when an invalid character is encountered while converting characters to bytes. Its value can be :ERROR, :IGNORE, a byte to be used instead, or a character to be used instead. The UNICODE character #\uFFFD can be used here only if it is encodable in the character set.
The function (EXT:ENCODING-CHARSET encoding) returns the charset of the encoding, as a SYMBOL or a STRING. Note that (STRING (EXT:ENCODING-CHARSET encoding)) is not necessarily a valid MIME name.
Besides every file/pipe/socket stream containing an encoding, the following SYMBOL-MACRO places contain global EXT:ENCODINGs:
Macro CUSTOM:*DEFAULT-FILE-ENCODING*. The SYMBOL-MACRO place CUSTOM:*DEFAULT-FILE-ENCODING* is the encoding used for new file/pipe/socket streams, when no :EXTERNAL-FORMAT argument was specified.
The following are SYMBOL-MACRO places.
is the encoding used for pathnames in the file system. Normally, this is a 1:1 encoding. Its line terminator mode is ignored.
is the encoding used for communication with the terminal, in particular by *TERMINAL-IO*.
is the encoding used for access to environment variables, command line options, and the like. Its line terminator mode is ignored.
is the encoding for characters and strings passed through the "FFI" (some plaforms only). Its value must be a 1:1 encoding, i.e., an encoding in which every character is represented by one byte.
The default encoding objects are initialized as described in the CLISP manual page
Encodings can also be used to convert directly between strings and their corresponding byte vector representation according to that encoding.
converts the subsequence of byte-vector from start to end to a STRING, according to the given encoding, and returns the resulting string.
converts the subsequence of string from start to end to a (VECTOR (UNSIGNED-BYTE 8)), according to the given encoding, and returns the resulting byte vector.
Two mechanisms are supported for creating new streams with user-defined behavior:
You can create a new subclass of GRAY:FUNDAMENTAL-STREAM and define methods for the elementary stream operations on it. These generic functions all have a name starting with the prefix "stream-".
You can create a new subclass of GSTREAM:GENERIC-STREAM-CONTROLLER and define methods for the elementary stream operations on it. These generic functions all have a name starting with the prefix "generic-stream-". The stream itself is a different object, created using the function gstream:make-generic-stream.
The FUNDAMENTAL-STREAM API is based on the STREAM-DEFINITION-BY-USER:GENERIC-FUNCTIONS proposal by David N. Gray and is supported by most Common Lisp implementations currently in use. The GSTREAM:GENERIC-STREAM-CONTROLLER API is CLISP-specific and is now obsolete.
This interface permits the definition of new classes of streams, and programming their behavior by defining methods for the elementary stream operations. It is based on the proposal STREAM-DEFINITION-BY-USER:GENERIC-FUNCTIONS of David N. Gray to X3J13.
All symbols defined by this interface, starting with the prefix "fundamental-" or "stream-", are exported from the package "GRAY" and re-exported from "EXT".
Defined classes
This is a superclass of all user-defined streams. It is a subclass of STREAM and of STANDARD-OBJECT. Its metaclass is STANDARD-CLASS.
This is a superclass of all user-defined input STREAMs. It is a subclass of GRAY:FUNDAMENTAL-STREAM. The built-in function INPUT-STREAM-P returns true on instances of this class. This means that when you define a new stream class capable of doing input, you have to make it a subclass of GRAY:FUNDAMENTAL-INPUT-STREAM.
This is a superclass of all user-defined output STREAMs. It is a subclass of GRAY:FUNDAMENTAL-STREAM. The built-in function OUTPUT-STREAM-P returns true on instances of this class. This means that when you define a new stream class capable of doing output, you have to make it a subclass of GRAY:FUNDAMENTAL-OUTPUT-STREAM.
This is a superclass of all user-defined streams whose STREAM-ELEMENT-TYPE is CHARACTER. It is a subclass of GRAY:FUNDAMENTAL-STREAM. It defines a method on STREAM-ELEMENT-TYPE that returns CHARACTER.
This is a superclass of all user-defined streams whose STREAM-ELEMENT-TYPE is a subtype of INTEGER. It is a subclass of GRAY:FUNDAMENTAL-STREAM. When you define a subclass of GRAY:FUNDAMENTAL-BINARY-STREAM, you have to provide a method on STREAM-ELEMENT-TYPE.
This is a convenience class inheriting from both GRAY:FUNDAMENTAL-CHARACTER-STREAM and GRAY:FUNDAMENTAL-INPUT-STREAM.
This is a convenience class inheriting from both GRAY:FUNDAMENTAL-CHARACTER-STREAM and GRAY:FUNDAMENTAL-OUTPUT-STREAM.
This is a convenience class inheriting from both GRAY:FUNDAMENTAL-BINARY-STREAM and GRAY:FUNDAMENTAL-INPUT-STREAM.
This is a convenience class inheriting from both GRAY:FUNDAMENTAL-BINARY-STREAM and GRAY:FUNDAMENTAL-OUTPUT-STREAM.
general generic functions defined on streams
Returns the stream's element type, normally a subtype of CHARACTER or INTEGER.
The method for GRAY:FUNDAMENTAL-CHARACTER-STREAM returns CHARACTER.
Changes the stream's element type.
The default method SIGNALs an ERROR.
This function is a CLISP extension (see setting STREAM-ELEMENT-TYPE).
Closes the stream and flushes any associated buffers.
When you define a primary method on this function, do not forget to CALL-NEXT-METHOD.
Returns true before the stream has been closed, and NIL after the stream has been closed.
You do not need to add methods to this function.
generic functions for character input
If a character was pushed back using GRAY:STREAM-UNREAD-CHAR, returns and consumes it. Otherwise returns and consumes the next character from the stream. Returns :EOF if the end-of-stream is reached.
You must define a method for this function.
Pushes char, which must be the last character read from the stream, back onto the front of the stream.
You must define a method for this function.
Returns a character or :EOF, like GRAY:STREAM-READ-CHAR, if that would return immediately. If GRAY:STREAM-READ-CHAR's value is not available immediately, returns NIL instead of waiting.
The default method simply calls GRAY:STREAM-READ-CHAR; this is sufficient for streams whose GRAY:STREAM-READ-CHAR method never blocks.
If a character was pushed back using GRAY:STREAM-UNREAD-CHAR, returns it. Otherwise returns the next character from the stream, avoiding any side effects GRAY:STREAM-READ-CHAR would do. Returns :EOF if the end-of-stream is reached.
The default method calls GRAY:STREAM-READ-CHAR and GRAY:STREAM-UNREAD-CHAR; this is sufficient for streams whose GRAY:STREAM-READ-CHAR method has no side-effects.
If a character was pushed back using GRAY:STREAM-UNREAD-CHAR, returns it. Otherwise returns the next character from the stream, if already available. If no character is available immediately, or if end-of-stream is reached, returns NIL.
The default method calls GRAY:STREAM-READ-CHAR-NO-HANG and GRAY:STREAM-UNREAD-CHAR; this is sufficient for streams whose GRAY:STREAM-READ-CHAR method has no side-effects.
Returns NIL if GRAY:STREAM-READ-CHAR will return immediately. Otherwise it returns true.
The default method calls GRAY:STREAM-READ-CHAR-NO-HANG and GRAY:STREAM-UNREAD-CHAR; this is sufficient for streams whose GRAY:STREAM-READ-CHAR method has no side-effects.
This function is a CLISP extension (see EXT:READ-CHAR-WILL-HANG-P).
Fills the subsequence of sequence specified by :START and :END with characters consecutively read from stream. Returns the index of the first element of sequence that was not updated (= end or < end if the stream reached its end).
sequence is an ARRAY of CHARACTERs, i.e. a STRING. start is a nonnegative INTEGER and defaults to 0. end is a nonnegative INTEGER or NIL and defaults to NIL, which stands for (LENGTH sequence).
The default method repeatedly calls GRAY:STREAM-READ-CHAR; this is always sufficient if speed does not matter.
This function is a CLISP extension (see EXT:READ-CHAR-SEQUENCE).
Reads a line of characters, and return two values: the line (a STRING, without the terminating #\Newline character), and a BOOLEAN value which is true if the line was terminated by end-of-stream instead of #\Newline.
The default method repeatedly calls GRAY:STREAM-READ-CHAR; this is always sufficient.
Clears all pending interactive input from the stream, and returns true if some pending input was removed.
The default method does nothing and returns NIL; this is sufficient for non-interactive streams.
generic functions for character output
Writes char.
You must define a method for this function.
Returns the column number where the next character would be written (0 stands for the first column), or NIL if that is not meaningful for this stream.
You must define a method for this function.
Returns true if the next character would be written at the start of a new line.
The default method calls GRAY:STREAM-LINE-COLUMN and compares its result with 0; this is sufficient for streams whose GRAY:STREAM-LINE-COLUMN never returns NIL.
Outputs the subsequence of sequence specified by :START and :END to stream.
sequence is an ARRAY of CHARACTERs, i.e. a STRING. start is a nonnegative INTEGER and defaults to 0. end is a nonnegative integer or NIL and defaults to NIL, which stands for (LENGTH sequence).
The default method repeatedly calls GRAY:STREAM-WRITE-CHAR; this is always sufficient if speed does not matter.
This function is a CLISP extension (see EXT:WRITE-CHAR-SEQUENCE).
Outputs the subsequence of string specified by :START and :END to stream. Returns string.
string is a string. start is a nonnegative integer and default to 0. end is a nonnegative integer or NIL and defaults to NIL, which stands for (LENGTH string).
The default method calls GRAY:STREAM-WRITE-CHAR-SEQUENCE; this is always sufficient.
Outputs a #\Newline character.
The default method calls GRAY:STREAM-WRITE-CHAR; this is always sufficient.
Possibly outputs a #\Newline character, so as to ensure that the next character would be written at the start of a new line. Returns true if it did output a #\Newline character.
The default method calls GRAY:STREAM-START-LINE-P and then GRAY:STREAM-TERPRI if necessary; this is always sufficient.
Ensures that any buffered output has reached its destination, and then returns.
The default method does nothing.
Brings any buffered output on its way towards its destination, and returns without waiting until it has reached its destination.
The default method does nothing.
Attempts to discard any buffered output which has not yet reached its destination.
The default method does nothing.
Ensures that the next character will be written at column at least.
The default method outputs an appropriate amount of space characters; this is sufficient for non-proportional output.
generic functions for binary input
Returns and consumes the next integer from the stream. Returns :EOF if the end-of-stream is reached.
You must define a method for this function.
To be called only if stream's STREAM-ELEMENT-TYPE is (UNSIGNED-BYTE 8) or (SIGNED-BYTE 8). Returns T if GRAY:STREAM-READ-BYTE would return immediately with an INTEGER result. Returns :EOF if the end-of-stream is already known to be reached. If GRAY:STREAM-READ-BYTE's value is not available immediately, returns NIL instead of waiting.
You must define a method for this function.
This function is a CLISP extension (see EXT:READ-BYTE-LOOKAHEAD).
To be called only if stream's STREAM-ELEMENT-TYPE is (UNSIGNED-BYTE 8) or (SIGNED-BYTE 8). Returns NIL if GRAY:STREAM-READ-BYTE will return immediately. Otherwise it returns true.
The default method calls GRAY:STREAM-READ-BYTE-LOOKAHEAD; this is always sufficient.
This function is a CLISP extension (see EXT:READ-BYTE-WILL-HANG-P).
To be called only if stream's STREAM-ELEMENT-TYPE is (UNSIGNED-BYTE 8) or (SIGNED-BYTE 8). Returns an INTEGER or :EOF, like GRAY:STREAM-READ-BYTE, if that would return immediately. If GRAY:STREAM-READ-BYTE's value is not available immediately, returns NIL instead of waiting.
The default method calls GRAY:STREAM-READ-BYTE if GRAY:STREAM-READ-BYTE-LOOKAHEAD returns true; this is always sufficient.
This function is a CLISP extension (see EXT:READ-BYTE-NO-HANG).
Fills the subsequence of sequence specified by :START and :END with integers consecutively read from stream. Returns the index of the first element of sequence that was not updated (= end or < end if the stream reached its end).
sequence is an ARRAY of INTEGERs. start is a nonnegative INTEGER and defaults to 0. end is a nonnegative INTEGER or NIL and defaults to NIL, which stands for (LENGTH sequence).
The default method repeatedly calls GRAY:STREAM-READ-BYTE; this is always sufficient if speed does not matter.
This function is a CLISP extension (see EXT:READ-BYTE-SEQUENCE).
generic functions for binary output
Writes integer.
You must define a method for this function.
Outputs the subsequence of sequence specified by :START and :END to stream
sequence is an ARRAY of INTEGERs. start is a nonnegative INTEGER and defaults to 0. end is a nonnegative INTEGER or NIL and defaults to NIL, which stands for (LENGTH sequence).
The default method repeatedly calls GRAY:STREAM-WRITE-BYTE; this is always sufficient if speed does not matter.
This function is a CLISP extension (see EXT:WRITE-BYTE-SEQUENCE).
This interface is CLISP-specific and now obsolete. Please use the Gray streams interface instead.
Generic streams are user programmable streams. The programmer interface:
returns a generic 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 gstream:make-generic-stream.
determines whether a stream is a generic stream, returning T if it is, NIL otherwise.
In order to specify the behavior of a generic stream, the user must define CLOS methods on the following CLOS generic functions. The function gstream:generic-stream-xyz corresponds to the Common Lisp function xyz. They all take a controller and some number of arguments.
Returns and consumes the next character, NIL at end of file. Takes one argument, the controller object.
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.
Returns and consumes the next integer, NIL at end of file. Takes one argument, the controller object.
This generic function is used to query the stream's input status. It returns NIL if gstream:generic-stream-read-char and gstream:generic-stream-peek-char will certainly return immediately. Otherwise it returns true.
The first argument is the controller object. The second argument is the character to be written.
The first argument is the controller object. The second argument is the integer to be written.
Writes the subsequence of string starting from start of length length. The first argument is the controller object.
Take one argument, the controller object.
A weak pointer is an object holding a reference to a given object, without keeping the latter from being garbage-collected.
returns a fresh weak pointer referring to value.
returns true if the object is of type EXT:WEAK-POINTER.
returns two values: The original value and T, if the value has not yet been garbage-collected, else NIL and NIL. It is SETF-able: you can change the value that the weak pointer points to.
CLISP also has weak HASH-TABLE.
Calling (EXT:FINALIZE object function) has the effect that when the specified object is being garbage-collected, (FUNCALL function object) will be executed.
Calling (EXT: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 "the object is being garbage-collected" is not defined deterministically. (Actually, it might possibly never occur.) It denotes a moment at which no references to object exist from other Lisp objects. When the function is called, object (and possibly guardian) enter the "arena of live Lisp objects" again.
No finalization request will be executed more than once.
The variable CUSTOM:*PROMPT* controls the appearance of the prompt. When its value is a function, it is called and its value is printed with PRINC. Otherwise, the value itself is printed with PRINC. The default value of CUSTOM:*PROMPT* prints "package[n]> " where package is the shortest (nick)name of the current package *PACKAGE* if it is not the same as it was in the beginning or if it does not contain symbol T (it is assumed that in the latter case you would want to keep in mind that your current package is something weird); and n is the ordinal number of the current prompt (hopefully, it will remain finite). To help you in constructing your own fancy prompts, two functions and one variable are provided:
returns *PACKAGE* or NIL if the current package is the same as it was initially
takes one argument, a package, and returns its shortest name or nickname
contains the current prompt number; it is your responsibility to increment it (this variable is bound to 0 before saving the memory image).
Some [ANSI CL standard] features are turned off by default for backwards compatibility. They can be switched on, all at once, by setting the SYMBOL-MACRO CUSTOM:*ANSI* to T, or they can be switched on individually. Setting CUSTOM:*ANSI* to T implies the following:
Setting CUSTOM:*PRINT-PATHNAMES-ANSI* to T.
Setting CUSTOM:*COERCE-FIXNUM-CHAR-ANSI* to T.
Setting CUSTOM:*SEQUENCE-COUNT-ANSI* to T.
Setting CUSTOM:*MERGE-PATHNAMES-ANSI* to T.
Setting CUSTOM:*PARSE-NAMESTRING-ANSI* to T.
Setting CUSTOM:*FLOATING-POINT-CONTAGION-ANSI* to T.
Note that if you run CLISP with the -ansi switch or set the SYMBOL-MACRO CUSTOM:*ANSI* to T and then save memory image, then all subsequent invocations of CLISP with this image will be as if with -ansi (regardless whether you actually supply the -ansi switch). You can always set the SYMBOL-MACRO CUSTOM:*ANSI* to NIL, or invoke CLISP with the -traditional switch, reversing the above settings, i.e.,
Setting CUSTOM:*PRINT-PATHNAMES-ANSI* to NIL.
Setting CUSTOM:*COERCE-FIXNUM-CHAR-ANSI* to NIL.
Setting CUSTOM:*SEQUENCE-COUNT-ANSI* to NIL.
Setting CUSTOM:*MERGE-PATHNAMES-ANSI* to NIL.
Setting CUSTOM:*PARSE-NAMESTRING-ANSI* to NIL.
Setting CUSTOM:*FLOATING-POINT-CONTAGION-ANSI* to NIL.
CLISP comes with some extension macros, mostly defined in the file macros3.lisp and loaded from the file init.lisp during make:
Macro EXT:ETHE. (EXT:ETHE value-type form) enforces a type check in both interpreted and compiled code.
Macros EXT:LETF & EXT:LETF*. These macros are similar to LET and LET*, respectively, except that they can bind places, even places with multiple values. Example:
(letf (((values a b) form)) ...) |
(multiple-value-bind (a b) form ...) |
(letf (((first l) 7)) ...) |
(LET* ((#:g1 l) (#:g2 (first #:g1))) (UNWIND-PROTECT (PROGN (SETF (first #:g1) 7) ...) (SETF (first #:g1) #:g2))) |
Macro EXT:WITH-COLLECT. Similar to the LOOP's collect construct, except that it is looks more "Lispy" and can appear arbitrarily deep. It defines local macros (with MACROLET) which collect objects given to it into lists, which are then returned as multiple values. E.g.,
(ext:with-collect (c0 c1) (dotimes (i 10) (if (oddp i) (c0 i) (c1 i)))) |
Macro EXT:WITH-GENSYMS. Similar to its namesake from Paul Graham's book "On Lisp", this macro is useful for writing other macros:
(with-gensyms ("FOO-" bar baz zot) ...) |
(let ((bar (gensym "FOO-BAR-")) (baz (gensym "FOO-BAZ-")) (zot (gensym "FOO-ZOT-"))) ...) |
Function EXT:REMOVE-PLIST. Similar to REMOVE and REMF, this function removes some properties from a property list. It is non-destructve and thus can be used on &REST arguments to remove some keyword parameters, e.g.,
(defmacro with-foo ((&KEY foo1 foo2) &BODY body) `(... ,foo1 ... ,foo2 ... ,@body)) (defmacro with-foo-bar ((&REST opts &KEY bar1 bar2 &ALLOW-OTHER-KEYS) &BODY body) `(with-foo (,@(remove-plist opts :bar1 :bar2) ... ,bar1 ... ,bar2 ... ,@body))) (defun foo-bar () (with-foo-bar (:bar1 1 :foo2 2) ...)) |
Macros EXT:WITH-HTML-OUTPUT and EXT:WITH-HTTP-OUTPUT. Defined in inspect.lisp, these macros are useful for the rudimentary HTTP server defined there.
The user-customizable variables are located in the package "CUSTOM" and thus can be listed using (APROPOS "" "CUSTOM"):
You should set these variables (and do whatever other customization you see fit) in the file #P"config.lisp" in the build directory before building CLISP. Alternatively, after building CLISP, or if you are using a binary distribution of CLISP, you can modify #P"config.lisp", compile and load it, and then save the memory image. Finally, you can create an "RC" (run control) file which is loaded whenever CLISP is started (see the documentation for option -norc in your platform-specific copy of the manual page).
You can use EXT:EXPAND-FORM to expand all the macros, SYMBOL-MACROs, etc, in a single form:
(expand-form '(macrolet ((bar (x) `(print ,x))) (macrolet ((baz (x) `(bar ,x))) (symbol-macrolet ((z 3)) (baz z))))) |
This is sometimes called a code walker, except that the code walker would probably leave the MACROLET and SYMBOL-MACROLET forms intact and just do the expansion.
returns a WINDOW-STREAM. As long as this stream is open, the terminal is in cbreak/noecho mode. *TERMINAL-IO* should not be used for input or output during this time. (Use EXT:WITH-KEYBOARD and EXT:*KEYBOARD-INPUT* instead.)
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* should not be used, as above.
returns the window's size, as two values: height (= ymax+1) and width (= xmax+1).
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).
sets the position of the cursor in the window.
clears the window's contents and puts the cursor in the upper left corner.
clears the window's contents from the cursor position to the end of window.
clears the window's contents from the cursor position to the end of line.
removes the cursor's line, moves the lines below it up by one line and clears the window's last line.
inserts a line at the cursor's line, moving the lines below it down by one line.
switches highlighted output on.
switches highlighted output off.
makes the cursor visible, a cursor block in most implementations.
makes the cursor invisible, in implementations where this is possible.
![]() | Modules on Win32. |
---|---|
Everything described in the section will work verbatim on Win32 when using Cygwin or MinGW, except for one thing - you will need to replace the run extension in lisp.run with the Win32 executable extension exe. For historical reasons, all examples appear to assume UNIX and use the run file type ("extension") for the CLISP run-time. This does not mean that they will not work on Win32. |
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 operates on CLISP linking sets and on module sets.
linking set. A linking set is a directory containing:
some /bin/sh commands, setting the variables
the C compiler
flags for the C compiler, when compiling
flags for the C compiler, when linking
libraries to use when linking
additional X Window System libraries to use
the ranlib command
the list of files needed when linking
the list of modules contained in this linking set
the compiled list of modules contained in this linking set
listed in makevars
the executable
the memory image
To run a CLISP contained in some linking set dir, call dir/lisp.run -M dir/lispinit.mem
module set. A module set is a directory containing:
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
needed by link.sh
Note that in link.sh the module set directory is referred to as $modulename/.
the space-separated list of files that belong to the module set and will belong to every new linking set.
the 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 space-separated list of the module names belonging to the module set. Normally, every #P".c" file in the module set defines a module of its own. The module name is derived from the file name.
the space-separated list of Lisp files to load before building the #P"lispinit.mem" belonging to a new linking set.
the space-separated list of Lisp files to load into an intermediate #P"lispinit.mem" file, before building the #P"lispinit.mem" belonging to a new linking set. This variable is usually used for defining Lisp packages which must be present when the new #P".c" files are initialized. E.g., the FFI:DEF-CALL-IN functions must reside in already defined packages; see the call-in example.
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.
Function (EXT:MODULE-INFO &OPTIONAL name verbose) allows one to inquire about what modules are available in the currently running image. When called without arguments, it returns the list of module names, starting with "clisp". When name is supplied and names a module, 3 values are returned - name, subr-count, object-count. When verbose is non-NIL, the full list of module lisp function names written in C (Subrs) and the full list of internal lisp objects available in C code are additionally returned for the total of 5 values.
Note that dynamic loading does not work on all operating systems (dlopen is required), and that --with-dynamic-modules precludes some efficiency optimizations which are on by default.
Function (SYS::DYNLOAD-MODULES filename ({name}+)) loads a shared object file or library containing a number of named external CLISP modules. This facility cannot be used to dlopen and access arbitrary shared libraries.
External modules for CLISP are those which contain a module__name__subr_tab, among others. This serves to register external functions which operate on Lisp-level structures with CLISP.
To use dlopen with modules, you should add -fPIC to the module's compilation options. Something like cc -shared -o name.so name.o may be needed to produce the shared object file.
To link in the "FFI" bindings for the GNU/Linux operating system, the following steps are needed. (Step 1 and step 2 need not be executed in this order.)
Create a new module set:
$ clisp-link create-module-set linux /somewhere/bindings/linux.c |
NEW_LIBS="$file_list" |
NEW_LIBS="$file_list -lm" |
TO_LOAD='' |
TO_LOAD='/somewhere/bindings/linux.fas' |
Compile linux.lisp, creating linux.c:
$ clisp -c /somewhere/bindings/linux.lisp |
Create a new linking set:
$ clisp-link add-module-set linux base base+linux |
Run and try it:
$ base+linux/lisp.run -M base+linux/lispinit.mem > (linux::stat "/tmp") |
The following modules come with the distribution of CLISP:
Call the operating system functions from CLISP. The following platforms are supported:
Call Xlib functions from CLISP. Two implementations are supplied:
mit-clx, from MIT ftp://ftp.x.org/R5contrib/CLX.R5.02.tar.Z - the standard implementation
new-clx, by Gilbert Baumann - faster, with additional features, but not quite complete yet.
Access PostgreSQL from CLISP.
Compute the number of solutions to the n-queens problem on a n*n checkboard (a toy example for the users to explore).
Directory Access
The POSIX Regular Expressions matching, compiling, executing.
Use some system calls in a platform-independent way.
Shell (/bin/sh) globbing
This module provides some directory access from lisp, in package "LDAP". 3 types of directory keys may exist, depending on the compilation environment.
valid directory key types
Win32 registry access
gnome-config access
LDAP interface via OpenLDAP or compatible
The following functions and macros are exported (please note that these features are experimental and the API may be modified in the future).
Open the directory key under dkey, which should be either an open directory key or a valid directory key type. The meaning of the :DIRECTION and :IF-DOES-NOT-EXIST keyword arguments is the same as for OPEN.
Close the directory key. The preferred way is to use the LDAP:WITH-DIR-KEY-OPEN macro.
Open the directory key (by calling LDAP:DIR-KEY-OPEN on dkey, pathname and options), bind it to variable, execute body, then close it with LDAP:DIR-KEY-CLOSE.
Return the directory key type of the directory key
Return the path of this directory key, which is the pathname argument of LDAP:DIR-KEY-OPEN if dkey was a directory key type or the concatenation of the pathname argument and the ldap:dir-key-path of dkey.
One of :INPUT, :OUTPUT and :IO, indicating the permitted operation on this key and its derivatives.
Check whether the key has been closed. It is not an error to close a closed key.
Delete the specified subkey or attribute.
Return the list of the subkeys or attributes.
Return the value of the specified attribute, similar to GETHASH and SETFable just like GETHASH.
Return some information about the directory key. This is highly platform-dependent and will probably be removed or replaced or modified in the future.
This is the main way to iterate over the subtree under the key dkey+pathname.
key-iter is a non-NIL symbol and is bound via MACROLET to a macro, each call of which returns the next subkey.
atribute-iter is a symbol and is bound, when non-NIL, to a macro, each call of which returns two values - the next attribute and its value.
The :scope keyword argument specifies the scope of the search and can be
iterate over the key itself
iterate over the children of the key
iterate over the subtree
LDAP:WITH-DIR-KEY-SEARCH is used to implement LDAP:DIR-KEY-VALUES, LDAP:DIR-KEY-CHILDREN and LDAP:DIR-KEY-DUMP-TREE in dirkey.lisp.
The "REGEXP" module implements the POSIX regular expressions by calling the standard C system facilities. The syntax of these regular expressions is described in many places, such as your local regex.h manual and Emacs info pages.
The "REGEXP" package exports the following 9 symbols:
REGEXP:MATCH | REGEXP:MATCH-START | REGEXP:MATCH-END |
REGEXP:MATCH-STRING | REGEXP:REGEXP-QUOTE | REGEXP:REGEXP-COMPILE |
REGEXP:REGEXP-EXEC | REGEXP:REGEXP-SPLIT | REGEXP:WITH-LOOP-SPLIT |
API
This macro returns as first value a REGEXP:MATCH structure containing the indices of the start and end of the first match for the regular expression pattern in string; or NIL if there is no match. Additionally, a REGEXP:MATCH structure is returned for every matched "\(...\)" group in pattern, in the order that the open parentheses appear in pattern. If start is non-NIL, the search starts at that index in string. If end is non-NIL, only (SUBSEQ string start end) is considered.
Example 30-1. REGEXP:MATCH
(REGEXP:MATCH "quick" "The quick brown fox jumped quickly.") #S(REGEXP:MATCH :START 4 :END 9) (REGEXP:MATCH "quick" "The quick brown fox jumped quickly." :start 8) #S(REGEXP:MATCH :START 27 :END 32) (REGEXP:MATCH "quick" "The quick brown fox jumped quickly." :start 8 :end 30) NIL (REGEXP:MATCH "\\([a-z]*\\)[0-9]*\\(bar\\)" "foo12bar") #S(REGEXP:MATCH :START 0 :END 8) ; #S(REGEXP:MATCH :START 0 :END 3) ; #S(REGEXP:MATCH :START 5 :END 8) |
Extracts the start index of match; SETF-able.
Extracts the end index of match; SETF-able.
Extracts the substring of string corresponding to the given pair of start and end indices of match. The result is shared with string. If you want a freshly consed STRING, use COPY-SEQ or (COERCE (REGEXP:MATCH-STRING ...) 'SIMPLE-STRING).
This function returns a regular expression string that matches exactly string and nothing else. This allows you to request an exact string match when calling a function that wants a regular expression.
One use of REGEXP:REGEXP-QUOTE is to combine an exact string match with context described as a regular expression. When extended is non-NIL, also quote #\+ and #\?.Compile the regular expression string into an object suitable for REGEXP:REGEXP-EXEC.
Execute the pattern, which must be a compiled regular expression returned by REGEXP:REGEXP-COMPILE, against the appropriate portion of the string.
Return a list of substrings of string (all sharing the structure with string) separated by pattern (a regular expression string or a return value of REGEXP:REGEXP-COMPILE)
Read lines from stream, split them with REGEXP:REGEXP-SPLIT on pattern, and bind the resulting list to variable.
These options control compilation of a pattern. You can specify cflags directly by combining REGEXP::REG_EXTENDED, REGEXP::REG_ICACE, REGEXP::REG_NEWLINE, and REGEXP::REG_NOSUB. See regex.h for their meaning.
These options constrol execution of a pattern. You can specify eflags directly by combining REGEXP::REG_NOTBOL, and REGEXP::REG_NOTEOL. See regex.h for their meaning.
The following code computes the number of people who use a particular shell:
(DEFPACKAGE "REGEXP-TEST" (:use "LISP" "REGEXP")) (IN-PACKAGE "REGEXP-TEST") (let ((h (make-hash-table :test #'equal :size 10)) (n 0)) (with-open-file (f "/etc/passwd") (with-loop-split (s f ":") (incf (gethash (seventh s) h 0)))) (with-hash-table-iterator (i h) (loop (multiple-value-bind (r k v) (i) (unless r (return)) (format t "[~d] ~s~30t== ~5:d~%" (incf n) k v))))) |
For comparison, the same can be done by the following Perl:
#!/usr/local/bin/perl -w use diagnostics; use strict; my $IN = $ARGV[0]; open(INF,"< $IN") || die "$0: cannot read file [$IN]: $!\n;"; my %hash; while (<INF>) { chop; my @all = split($ARGV[1]); my $shell = ($#all >= 6 ? $all[6] : ""); if ($hash{$shell}) { $hash{$shell} ++; } else { $hash{$shell} = 1; } } my $ii = 0; for my $kk (keys(%hash)) { print "[",++$ii,"] \"",$kk,"\" -- ",$hash{$kk},"\n"; } close(INF); |
The "POSIX" module makes some system calls available from lisp.
Returns the hostent struct (name, list of aliases, list of IP addresses as dotted quads (for IPv4) or coloned octets (for IPv6), address type - IPv4 or IPv6). When host is omitted or :DEFAULT, return the data for the current host. When host is given and is NIL, all the host database is returned as a list (this would be the contents of the /etc/hosts file on a UNIX system or ${windir}/system32/etc/hosts on a Win32 system). This is an interface to gethostbyname/gethostbyaddr.
Return the file-stat struct. pathname can be a STREAM, a PATHNAME, a STRING or a NUMBER (on a UNIX system, meaning file descriptor). The first slot of the struct returned is the string or the number on which stat/fstat/lstat was called. The other 13 slots are numbers, members of the stat struct: device, inode, protection, number of hard links, owner's UID, owner's GID, device type, total size (bytes), blocksize for filesystem I/O, number of blocks allocated, atime, mtime, ctime (as the number of seconds since 1900-01-01). If the system does not support a particular field (e.g., Win32 does not have hard links), NIL (or the default, like 1 for the number of hard links for Win32 or DOS) is returned.
[UNIX systems only at this time, patches are welcome.]
Return the file-info struct. pathname should be a pathname designator. The 8 slots are attributes, ctime, atime, wtime, high and low sizes, name and short name.
[Win32 systems only at this time, patches are welcome.]
Return the passwd struct (name, encoded password, UID, GID, full name, home directory, shell). When user is NIL, return all users. When user is :DEFAULT or not supplied, return the information about the current user. If the system does not support a particular field (e.g., Win32 does not have a concept of a shell), NIL (or the default, like c:\command.com for DOS) is returned.
[UNIX systems only at this time, patches are welcome.]
Return a struct describing the OS, derived from uname.
Return a struct describing the system configuration, derived from sysconf.
Return a struct describing the resource limits, derived from getrlimit.
Return 2 structs describing the resource usage by the lisp process its children, derived from getrusage.
Compute the error functions, Bessel functions and Gamma. These functions are required by the POSIX standard and should be available in libm.so. Please note that these functions do not provide lisp-style error handling and precision, and do all the computations at the double float level.
This is an interface to the fcntl system call. It sets or removes a file lock for the (portion of the) file associated with stream, depending on lock-p. When block is NIL, the call is non-blocking, and when the file is already locked, it SIGNALs an ERROR. When shared is non-NIL, then lock can be shared between several callers. Several processes can set a shared (i.e., read) lock, but only one can set an exclusive (i.e., write, or non-shared) lock.
This is an interface to the symlink (when method is :SYMLINK), link (when it is :HARDLINK), and rename (when it is :RENAME) system calls, as well as, you guessed it, a generic file copy utility (when method is :COPY).
Both source-path and destination-path may be wild.
This is an interface to the dup/dup2 system calls on UNIX systems and to DuplicateHandle system call on Win32.
Return information about a Win32 shortcut (#P".lnk") file contents in a shortcut-info struct.
Create (or modify the properties of an existing one) a Win32 shortcut (#P".lnk") file.
A foreign function description is written as a Lisp file, and when compiled it produces a #P".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.
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.
special "FFI" forms; name is any Lisp SYMBOL; c-name is a STRING.
This form makes name a shortcut for c-type. Note that c-type may already refer to name. Forward declarations of types are not possible, however.
option ::== | ||
---|---|---|
(:NAME c-name) | ||
| | (:TYPE c-type) | |
| | (:READ-ONLY boolean) | |
| | (:ALLOC ALLOCATION) | |
| | (:LIBRARY STRING) |
This form defines a FFI: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 FFI:C-STRING, FFI:C-PTR, FFI:C-PTR-NULL, FFI: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.
:LIBRARY is the (optional) dynamic library which contains the variable.
option ::== | ||
---|---|---|
(:NAME c-name) | ||
| | (:ARGUMENTS {(argument c-type [PARAM-MODE [ALLOCATION]])}*) | |
| | (:RETURN-TYPE c-type [ALLOCATION]) | |
| | (:LANGUAGE language) | |
| | (:BUILT-IN BOOLEAN) | |
| | (:LIBRARY STRING) |
This form defines a named call-out function (a foreign function called from Lisp: control flow temporarily leaves Lisp). Any Lisp function call to #'name is redirected to call the C function c-name. :LIBRARY is the (optional) dynamic library which contains the function. When the function is a C built-in, the full prototype will be output (unless suppressed by FFI:*OUTPUT-C-FUNCTIONS*).
option ::== | ||
---|---|---|
(:NAME c-name) | ||
| | (:ARGUMENTS {(argument c-type [PARAM-MODE [ALLOCATION]])}*) | |
| | (:RETURN-TYPE c-type [ALLOCATION]) | |
| | (:LANGUAGE language) |
This form defines a named call-in function (i.e., a Lisp function called from the foreign language: control flow temporary enters Lisp). Any C function call to the C function c-name is redirected to call the Common Lisp function #'name.
This is equivalent to FFI:DEF-CALL-OUT with :LANGUAGE :STDC. deprecated.
This is equivalent to FFI:DEF-CALL-IN with :LANGUAGE :STDC. deprecated.
This form defines name to be both a STRUCTURE-CLASS and a foreign C type with the given slots. name is a SYMBOL (structure name) or a LIST whose FIRST element is the structure name and the REST is options. Two options are supported at this time:
means that the name of this structure is a C type defined with typedef elsewhere.
means that this structure is defined in a #P".c" file that you include with, e.g., (FFI:C-LINES "#include <filename.h>").
This form defines symbols as constants, similarly to the C declaration enum { symbol [= value], ... };
You can use (FFI:ENUM-FROM-VALUE name value) and (FFI:ENUM-TO-VALUE name symbol) to convert between the numeric and symbolic representations (of course, the latter function boils down to SYMBOL-VALUE plus a check that the symbol is indeed a constant defined in the FFI:DEF-C-ENUM name).
This form outputs the string (FORMAT NIL format-string {argument}*) to the C output file. This is a rarely needed low-level facility.
Array element: If c-place is of foreign type (FFI:C-ARRAY c-type (dim1 ... dimn)) and 0 ≤ index1 < dim1, ..., 0 ≤ indexn < dimn, this will be the place corresponding to (AREF c-place index1 ... indexn) or c-place[index1]...[indexn]. It is a place of type c-type. If c-place is of foreign type (FFI:C-ARRAY-MAX c-type dim) and 0 ≤ index < dim, this will be the place corresponding to (AREF c-place index) or c-place[index]. It is a place of type c-type.
Dereference pointer: If c-place is of foreign type (FFI:C-PTR c-type) or (FFI:C-PTR-NULL c-type), this will be the place the pointer points to. It is a place of type c-type. For (FFI:C-PTR-NULL c-type), the c-place may not be NULL.
Struct or union component: If c-place is of foreign type (FFI:C-STRUCT class ... (slot-name c-type) ...) or of type (FFI:C-UNION ... (slot-name c-type) ...), this will be of type c-type.
Type change: A place denoting the same memory locations as the original c-place, but of type c-type.
Type change and displacement: return a place denoting a memory locations displaced from the original c-place by an offset counted in bytes, with type c-type. This can be used to resize an array, e.g. of c-type (FFI:C-ARRAY uint16 n) via (FFI:OFFSET c-place 0 '(FFI:C-ARRAY uint16 k)).
Return the address of c-place as a Lisp object of type FFI:FOREIGN-ADDRESS. This is useful as an argument to foreign functions expecting a parameter of C type FFI:C-POINTER.
Return the FFI:FOREIGN-VARIABLE object underlying the c-place. This is also an acceptable argument type to a FFI:C-POINTER declaration.
returns the c-type corresponding to the c-place.
The first form returns the size and alignment of a C type c-type, measured in bytes.
The second form returns the size and alignment of the C type of c-place, measured in bytes.
The first form returns the size and alignment of the C type c-type, measured in bits.
The second form returns the size and alignment of the C type of c-place, measured in bits.
This predicate returns T if the foreign-entity refers to the NULL address (and thus foreign-entity should probably not be passed to most foreign functions).
FFI:FOREIGN-ADDRESS-UNSIGNED returns the INTEGER address embodied in the Lisp object of type FFI:FOREIGN-ADDRESS, FFI:FOREIGN-POINTER, FFI:FOREIGN-VARIABLE or FFI:FOREIGN-FUNCTION.
FFI:UNSIGNED-FOREIGN-ADDRESS returns a FFI:FOREIGN-ADDRESS object pointing to the given INTEGER address.
FFI:FOREIGN-ADDRESS is both a type name and a selector/constructor function. It is the Lisp object type corresponding to a FFI:C-POINTER external type declaration, e.g. a call-out function with (:RETURN-TYPE FFI:C-POINTER) yields a Lisp object of type FFI:FOREIGN-ADDRESS.
The function extracts the object of type FFI:FOREIGN-ADDRESS living within any FFI:FOREIGN-VARIABLE or FFI:FOREIGN-FUNCTION object. If the foreign-entity already is a FFI:FOREIGN-ADDRESS, it returns it. If it is a FFI:FOREIGN-POINTER (e.g. a base foreign library address), it encapsulates it into a FFI:FOREIGN-ADDRESS object, as suitable for use with a FFI:C-POINTER external type declaration. It does not construct addresses out of NUMBERs, FFI:UNSIGNED-FOREIGN-ADDRESS must be used for that purpose.
This predicate returns NIL if the foreign-entity (e.g. the Lisp equivalent of a FFI: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 (thus it returns T for all non-foreign arguments).
You can invalidate a foreign object using (SETF FFI:VALIDP). You cannot resurrect a zombie, nor can you kill a non-foreign object.
FFI:FOREIGN-POINTER returns the FFI:FOREIGN-POINTER associated with the Lisp object of type FFI:FOREIGN-ADDRESS, FFI:FOREIGN-POINTER, FFI:FOREIGN-VARIABLE or FFI:FOREIGN-FUNCTION.
(SETF FFI:FOREIGN-POINTER) changes the FFI:FOREIGN-POINTER associated with the Lisp object of type FFI:FOREIGN-ADDRESS, FFI:FOREIGN-VARIABLE or FFI:FOREIGN-FUNCTION to that of the other entity. When foreign-pointer is :COPY, a fresh FFI:FOREIGN-POINTER is allocated. foreign-entity still points to the same object. This is particularly useful with (SETF FFI:VALIDP).
These forms allocate space on the C execution stack, bind respectively a FFI:FOREIGN-VARIABLE object or a local SYMBOL-MACRO to variable and execute body.
When initarg is not supplied, they allocate space only for (FFI:SIZEOF c-type) bytes. This space is filled with zeroes. E.g., using a c-type of FFI:C-STRING or even (FFI:C-PTR (FFI:C-ARRAY uint8 32)) (!) both allocate place for a single pointer, initialized to NULL.
When initarg is supplied, they allocate space for an arbitrarily complex set of structures rooted in c-type. Therefore, FFI:C-ARRAY-MAX, #() and "" are your friends for creating a pointer to the empty arrays:
(with-c-var (v '(c-ptr (c-array-max uint8 32)) #()) (setf (element (deref v) 0) 127) v) |
(with-c-var (fv `(c-array uint8 ,(length my-vector)) my-vector) (print fv)) |
This forms converts a Lisp string according to the encoding, allocating space on the C execution stack. encoding can be any EXT:ENCODING, e.g. CHARSET:UTF-16 or CHARSET:UTF-8, circumventing the usual 1:1 limit imposed on CUSTOM:*FOREIGN-ENCODING*.
body is then executed with the three variables foreign-address, char-count and byte-count respectively bound to an untyped FFI:FOREIGN-ADDRESS (as known from the FFI:C-POINTER foreign type specification) pointing to the stack location, the number of CHARACTERs of the Lisp string that were considered and the number of (UNSIGNED-BYTE 8) bytes that were allocated for it on the C stack.
When null-terminated-p is true, which is the default, a variable number of zero bytes is appended, depending on the encoding, e.g. 2 for CHARSET:UTF-8, and accounted for in byte-count, and char-count is incremented by one.
The FFI:FOREIGN-ADDRESS object bound to foreign-address is invalidated upon the exit from the form.
A stupid example (a quite costly interface to mblen):
(with-foreign-string (fv elems bytes string :encoding charset:jis... :null-terminated-p nil :end 5) (declare (ignore fv elems)) (format t "This string would take ~D bytes." bytes)) |
Convert between the external (LIST) and internal (VECTOR) C type representations (used by DESCRIBE).
Macro FFI:ALLOCATE-SHALLOW allocates (FFI:SIZEOF c-type) bytes on the C heap and zeroes them out (like calloc). When :COUNT is supplied, c-type is substituted with (FFI:C-ARRAY c-type count), except when c-type is CHARACTER, in which case (FFI:C-ARRAY-MAX CHARACTER count) is used instead. When :READ-ONLY is supplied, the Lisp side is prevented from modifying the memory contents. This can be used as an indication that some foreign side is going to fill this memory (e.g. via read).
Returns a FFI:FOREIGN-VARIABLE object of the actual c-type, whose address part points to the newly allocated memory.
FFI:ALLOCATE-DEEP will call C malloc as many times as necessary to build a structure on the C heap of the given c-type, initialized from the given contents.
E.g., (FFI:ALLOCATE-DEEP 'FFI:C-STRING "ABCDE") performs 2 allocations: one for a C pointer to a string, another for the contents of that string. This would be useful in conjunction with a char** C type declaration. (FFI:ALLOCATE-SHALLOW 'FFI:C-STRING) allocates room for a single pointer (probably 4 bytes).
(FFI:ALLOCATE-DEEP 'CHARACTER "ABCDEF" :count 10) allocates and initializes room for the type (FFI:C-ARRAY-MAX CHARACTER 10), corresponding to char* or, more specifically, char[10] in C.
Function FFI:FOREIGN-FREE deallocates memory at the address held by the given foreign-entity. If :FULL is supplied and the argument is of type FFI:FOREIGN-VARIABLE, recursively frees the whole complex stucture pointed to by this variable.
If given a FFI:FOREIGN-FUNCTION object that corresponds to a CLISP callback, deallocates it. Callbacks are automatically created each time you pass a Lisp function via the "FFI".
Use (SETF FFI:VALIDP) to disable further references to this address from Lisp. This is currently not done automatically. If the given pointer is already invalid, FFI:FOREIGN-FREE (currently) signals an ERROR. This may change to make it easier to integrate with EXT:FINALIZE.
Function FFI:FOREIGN-ALLOCATE is a lower-level interface as it requires an internal C type descriptor as returned by FFI:PARSE-C-TYPE.
Create a place out of the given FFI:FOREIGN-VARIABLE object so operations on places (e.g. FFI:CAST, FFI:DEREF, FFI:SLOT etc.) can be used within body. FFI:WITH-C-VAR appears as a composition of FFI:WITH-FOREIGN-OBJECT and FFI:WITH-C-PLACE.
Such a place can be used to access memory referenced by a foreign-entity object:
(setq foo (allocate-deep '(c-array uint8 3) rgb)) (with-c-place (place foo) (element place 0)) |
CLISP will write the extern declarations for foreign functions (defined with FFI:DEF-CALL-OUT) and foreign variables (defined with FFI:DEF-C-VAR) into the output #P".c" unless these variables are NIL. They are NIL by default, so the extern declarations are not not written; you are encouraged to use FFI:C-LINES to include the appropriate C headers. Set these variables to non-NIL if the headers are not available or not usable.
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 FFI:DEF-C-TYPE.
the predefined C types (c-type)
the simple C types
Lisp name | Lisp equivalent | C equivalent | ILU equivalent | 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 |
This type corresponds to what C calls void*, an opaque pointer. When used as an argument, NIL is accepted as a FFI:C-POINTER and treated as NULL; when a function wants to return a NULL FFI:C-POINTER, it actually returns NIL.
This type corresponds to what C calls char*, a zero-terminated string. Its Lisp equivalent is a string, without the trailing zero character.
This type is equivalent to what C calls struct { c-type1 ident1; ...; c-typen identn; }. Its Lisp equivalent is: if class is VECTOR, a SIMPLE-VECTOR; if class is LIST, a proper list; if class is a symbol naming a structure or CLOS class, an instance of this class, with slots of names ident1, ..., identn.
class may also be a CONS of a SYMBOL (as above) and a LIST of FFI:DEF-C-STRUCT options.
This type is equivalent to what C calls union { c-type1 ident1; ...; c-typen identn; }. Conversion to and from Lisp assumes that a value is to be viewed as being of c-type1.
This type is equivalent to what C calls c-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 (FFI:C-PTR (FFI:C-ARRAY ...)) for this argument's type.
This type is equivalent to what C calls c-type [maxdimension], an array containing up to maxdimension elements. The array is zero-terminated if it contains less than maxdimension elements. Conversion from Lisp of an array with more than maxdimension elements silently ignores the superfluous elements.
This type designates a C function that can be called according to the given prototype (r-c-type (*) (a-c-type1, ...)). Conversion between C functions and Lisp functions is transparent, and NULL/NIL is recognized and accepted.
This type is equivalent to what C calls c-type *: a pointer to a single item of the given c-type.
This type is also equivalent to what C calls c-type *: a pointer to a single item of the given c-type, with the exception that C NULL corresponds to Lisp NIL.
This type is equivalent to what C calls c-type (*)[]: a pointer to a zero-terminated array of items of the given c-type.
CUSTOM:*FOREIGN-ENCODING* governs conversion for any c-type involving FFI:C-STRING or CHARACTER (but not char).
FFI:C-FUNCTION, FFI:DEF-CALL-IN, FFI:DEF-CALL-OUT take :LANGUAGE argument. The language is either :C (denotes K&R C) or :STDC (denotes ANSI C) or :STDC-STDCALL (denotes ANSI C with the stdcall calling convention). It specifies whether the C function (caller or callee) has been compiled by a K&R C compiler or by an ANSI C compiler, and possibly the calling convention.
The default language is set using the macro FFI:DEFAULT-FOREIGN-LANGUAGE. If this macro has not been called in the current compilation unit (usually a file), a warning is issued and :STDC is used for the rest of the unit.
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 fresh Lisp value. Foreign variables are defined using FFI:DEF-C-VAR.
A FFI:FOREIGN-VARIABLE name defined by FFI:DEF-C-VAR, FFI:WITH-C-VAR or FFI:WITH-C-PLACE 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: FFI:ELEMENT, FFI:DEREF, FFI:SLOT, FFI:CAST, FFI:OFFSET, FFI:C-VAR-ADDRESS, FFI:C-VAR-OBJECT, FFI:TYPEOF, FFI:SIZEOF, FFI:BITSIZEOF.
Foreign functions are functions which are defined in the foreign language. There are named foreign functions (imported via FFI:DEF-CALL-OUT or created via FFI:DEF-CALL-IN) and anonymous foreign functions; they arise through conversion of function pointers.
A "call-out" function is a foreign function called from Lisp: control flow temporarily leaves Lisp. A "call-in" function is a Lisp function called from the foreign language: control flow temporary enters Lisp.
The following forms define foreign functions: FFI:DEF-CALL-IN, FFI:DEF-CALL-OUT, FFI:DEF-C-CALL-IN, FFI:DEF-C-CALL-OUT.
When passed to and from functions, allocation of arguments and results is handled as follows:
Values of SIMPLE-C-TYPE, FFI:C-POINTER are passed on the stack, with dynamic extent. The ALLOCATION is effectively ignored.
Values of type FFI:C-STRING, FFI:C-PTR, FFI:C-PTR-NULL, FFI:C-ARRAY-PTR need storage. The ALLOCATION specifies the allocation policy:
ALLOCATION | meaning |
---|---|
:NONE | no storage is allocated. |
:ALLOCA | allocation of storage on the stack, which has dynamic extent. |
:MALLOC-FREE | 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 FFI:C-STRING and FFI:C-PTR and FFI:C-PTR-NULL and FFI: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.
Lisp allocates the storage using malloc and never deallocates it. The C function is supposed to call free when done with it.
Lisp allocates the storage on the stack, with dynamic extent. It is freed when the C function returns.
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.
Lisp calls free on it when done.
Lisp does nothing.
Lisp calls free on it when done.
Lisp does nothing.
Lisp allocates the storage using malloc and never deallocates it. The C function is supposed to call free when done with it.
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.
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, FFI:C-STRING, FFI:C-FUNCTION.
![]() | Passing FFI:C-STRUCT, FFI:C-UNION, FFI:C-ARRAY, FFI: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 and win32) have problems with this. The recommended workaround is to pass pointers; this is fully supported. See also this <clisp-list@sf.net> message. |
A function parameter's PARAM-MODE may be
The caller passes information to the callee.
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.
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.]
Example 30-3. Simple declarations and access
The C declaration
struct foo { int a; struct foo * b[100]; }; |
(def-c-struct foo (a int) (b (c-array (c-ptr foo) 100))) |
The element access
struct foo f; f.b[7].a |
(declare (type foo f)) (foo-a (aref (foo-b f) 7)) or (slot-value (aref (slot-value f 'b) 7) 'a) |
Example 30-4. 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; |
(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))) |
Example 30-5. Calling an external function
On CUSTOM:*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); |
(def-c-struct (div_t :typedef) (quot int) (rem int)) (default-foreign-language :stdc) (def-call-out div (:arguments (numer int) (denom int)) (:return-type div_t)) |
> (div 20 3) #S(DIV_T :QUOT 6 :REM 2) |
Example 30-6. 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 (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; } |
(DEFPACKAGE "TEST-C-CALL" (:use "LISP" "FFI")) (IN-PACKAGE "TEST-C-CALL") (def-c-struct cfunr (x int) (s c-string)) (default-foreign-language :stdc) (def-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))) |
$ 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.lisp $ 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 malloced but never freed. Specifying
(:return-type (c-ptr cfunr) :malloc-free) |
Example 30-7. Calling Lisp from C
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); } |
(DEFPACKAGE "FFI-TEST" (:use "LISP" "FFI")) (IN-PACKAGE "FFI-TEST") (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 #'<)) |
(def-call-out sort10 (:name "lispsort_double") (:language :stdc) (:arguments (n int) (array (c-ptr (c-array double-float 10)) :in-out))) |
$ clisp-link create-module-set sort sort2.c sorttest.c $ cc -O -c sort1.c $ cd sort $ ln -s ../sort1.o sort1.o |
$ cd .. $ base/lisp.run -M base/lispinit.mem -c sort2.lisp sorttest.lisp $ 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 |
Example 30-8. Variable size arguments: calling gethostname from CLISP
follows a typical pattern of C "out"-parameter convention - it expects a pointer to a buffer it is going to fill. So you must view this parameter as either :OUT or :IN-OUT. Additionaly, one must tell the function the size of the buffer. Here namelen is just an :IN parameter. Sometimes this will be an :IN-OUT parameter, returning the number of bytes actually filled in.So name is actually a pointer to an array of up to namelen characters, regardless of what the poor char* C prototype says, to be used like a C string (0-termination). UNIX specifies that "kost names are limited to HOST_NAME_MAX bytes", which is, of course, system dependent, but it appears that 256 is a common value.
In the present example, you can use allocation :ALLOCA, like you would do in C: stack-allocate a temporary.
(FFI:DEF-C-CALL-OUT gethostname (:arguments (name (FFI:C-PTR (FFI:C-ARRAY-MAX ffi:char 256)) :OUT :ALLOCA) (len ffi:int)) (:return-type ffi:int)) (defun myhostname () (multiple-value-bind (success name) ;; :OUT and :IN-OUT parameters are returned as multiple values (gethostname 256) (if (zerop success) name (error ...)))) ;; strerror(errno) (defvar hostname (myhostname)) |
You can find more information and examples of the CLISP "FFI" in the following <clisp-list@sf.net> messages:
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").
"AFFI" was designed to be small in size but powerful enough to use most library functions. Lisp files may be compiled to #P".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 λ yourself), name spaces are separate.
The "AFFI" does no tracking of resources. Use EXT:FINALIZE.
These are the "AFFI" forms:
(declare-library-base keyword-base library-name)
(require-library-functions library-name [(:import {string-name}*)])
(open-library base-symbol)
(close-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 is much safer to use.
A function is contained in a library. Every function is referred to by a symbol. A function is defined through defflibfun or declare-library-function by giving the function name, the library-base, an offset into the library, a mask (or NIL) for register-based library calls, the result type and all parameter-types. require-library-functions loads the complete set of functions defined in a library file. Symbols are created in the package "AFFI" and imported into the current package.
flibcall and mlibcall call library functions. mlibcall is a macro that does a few checks at macroexpansion time and allows the compiler to inline the call, not requiring the foreign function to be defined again at load or execution time. The use of this macro is advertised wherever possible.
mem-read reads an arbitrary address (with offset for structure references) and returns the given type.
mem-write writes an arbitrary address. mem-write-vector copies the content of a Lisp STRING or (VECTOR (UNSIGNED-BYTE 8)) into memory.
nzero-pointer-p tests for non-NULL pointers in all recognized representations (NULL, UNSIGNED-BYTE and FFI:FOREIGN-POINTER).
declare-library-base ought to be wrapped in an (EVAL-WHEN (compile eval load) ...) form and come before any function is referenced, because the library base symbol must be known.
open-library tries to open the library referenced by the base symbol. Therefore it must have been preceded with declare-library-base. The call returns NIL on failure. open-library calls nest. Every successful call must be matched by close-library. with-open-library does this for you and also allows you to specify the library by name, provided that its base has been declared. It is recommended to use this macro and to reference the library by name.
CLISP will not close libraries for you at program exit. [A previous version did so but now "AFFI" is a module and there are no module exit functions.] Programmers, watch AFFI::*LIBRARIES-ALIST*.
The following foreign C types are used in "AFFI". They are not regular Common Lisp types or CLOS classes.
"AFFI" name | Lisp equivalent | C equivalent | 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 NULL-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 NULL-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 FFI:FOREIGN-POINTER are always acceptable where a STRING or :IO type is specified.
See also CUSTOM:*FOREIGN-ENCODING*.
To meet the design goals, predefined types and objects were used. As such, pointers were represented as integers. Now that there is the FFI: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 are declared either through defflibfun or declare-library-function. The former is closer to the low-level implementation of the interface, the latter is closer to the other "FFI".
defflibfun requires the library base symbol and register mask to be specified, declare-library-function requires the library name and computes the mask from the declaration of the arguments.
The value of mask is implementation-dependent. On the Amiga, it is an integer whose hexadecimal value is the reverse of the function argument register numbers, where d0 has number 1 and a6 number #xF. A NIL mask is reserved for stack-based calls (unimplemented).
The "AFFI" type 0 is only acceptable as a function result type and yields either T or NIL. The difference between * and :EXTERNAL is the following: * uses integers, :EXTERNAL uses FFI:FOREIGN-POINTER as function result-type (except from NIL for a NULL pointer) and refuses objects of type STRING or (VECTOR (UNSIGNED-BYTE 8)) as input. Thus :EXTERNAL provides some security on the input and the ability to use EXT:FINALIZE for resource-tracking on the output side.
(declare-library-function name library-name {option}*)
:d0 | :d1 | ... | :d7 | :a0 | ... | :a6
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.
(affi: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 NULL-terminated string (string) or, if the type argument is of type STRING or (VECTOR (UNSIGNED-BYTE 8)), it can fill this vector. :EXTERNAL is not an acceptable type as no object can be created by using affi:mem-read.
(affi: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.
(affi:mem-write-vector address vector [offset]) can write memory from the given vector (of type STRING or (VECTOR (UNSIGNED-BYTE 8))).
affi:require-library-functions will REQUIRE a file of name derived from thelibrary name and with type affi. It may be used to import all names into the current package or only a given subset identified by string names, using the :import keyword (recommended use). Some definition files for standard Amiga libraries are provided. See example 1 below.
As affi: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.lisp 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).
By using appropriate EVAL-WHEN forms for affi:declare-library-base and affi:require-library-functions and not using affi: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 EXT:FINALIZE to free resources for you, as CLISP does not call finalizers when it exits, use UNWIND-PROTECT.
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.lisp) were to change, the low-level part (affi.d) should remain untouched as all it knows are INTEGERs and FFI: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!
Example 30-9. Using a predefined library function file
(DEFPACKAGE "AFFI-TEST" (:use "LISP" "AFFI")) (IN-PACKAGE "AFFI-TEST") ;; 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))) |
Example 30-10. Using flibcall
(DEFPACKAGE "AFFI-TEST" (:use "LISP" "AFFI")) (IN-PACKAGE "AFFI-TEST") (eval-when (compile eval load) ;; keyword avoids name conflicts (declare-library-base :SysBase "exec.library")) ;; The load situation permits the use of flibcall (eval-when (eval compile load) (require-library-functions "exec.library")) (unless (open-library 'SysBase) (error "No library for SysBase")) (flibcall (if t 'FindTask 'Debug) 0) (close-library 'SysBase) |
Example 30-11. Be fully dynamic, defining library bases ourselves
(DEFPACKAGE "AFFI-TEST" (:use "LISP" "AFFI")) (IN-PACKAGE "AFFI-TEST") (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))) |
Example 30-12. Some sample function definitions
(defflibfun 'FindTask 'SysBase -294 #xA '* 'string) (eval-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 NULL-terminated-string (mlibcall SetVar name value -1 GVF_LOCAL_ONLY))) |
CLISP comes with a small yet extensible and powerful ARexx interface.
tells you the name of the CLISP ARexx port. The default extension for CLISP ARexx scripts is cl.
-> arexx-msg-handle, or NIL on failure
-> no return, use the exit-loop.cl ARexx script to abort the loop
command may be a string denoting a command with optional arguments or a vector of strings thus denoting an ARexx function call. The first element in the vector is the function name, the others are the up to 15 arguments.
Messages may be sent to an arbitrary ARexx host, special cases are NIL (meaning "REXX", the default) and T ("AREXX" for asynchronous execution).
ARexx server mode: Like Ispell, Csh and SKsh, you can run it in server mode by calling (rexx-loop). You can then only exit with the ARexx exit-loop.cl script.
Restrictions: Currently CLISP is not able to wait for input from several sources, e.g. both a console and ARexx, at the same time.
This function creates a socket an binds a port to the socket. The server exists to watch for client connect attempts. The optional argument is either a port (positive FIXNUM) or a SOCKET:SOCKET-STREAM (from whose peer the connections will be made).
Closes down the server socket. Just like streams, SOCKET:SOCKET-SERVERs are closed at garbage-collection. You should not rely on this however, because garbage-collection times are not deterministic.
Returns the host mask indicating which hosts can connect to this server and the port which was bound using SOCKET:SOCKET-SERVER.
Wait for a fixed time for a connection on the socket-server (a SOCKET:SOCKET-SERVER). Without a timeout argument, SOCKET:SOCKET-WAIT blocks indefinitely. When timeout is zero, poll. Returns T when a connection is available (i.e., SOCKET:SOCKET-ACCEPT will not block) and NIL on timeout.
Creates the server-side two-way stream for the connection. Waits for an attempt to connect to the server for no more than :TIMEOUT seconds (which may be a non-negative real number or a list (sec usec) or a pair (sec . usec)). SIGNALs an ERROR if no connection is made in that time.
Attempts to create a client-side two-way SOCKET:SOCKET-STREAM. Blocks until the server accepts the connection, for no more than :TIMEOUT seconds. If it is 0, returns immediately and (probably) blocks on the next i/o operation (you can use SOCKET:SOCKET-STATUS to check whether it will actually block).
Checks whether it is possible to read from or write to a SOCKET:SOCKET-STREAM or whether a connection is available on a SOCKET:SOCKET-SERVER without blocking.
For the cognoscenti: this is the interface to select, so it will work for any CLISP STREAM which is based on a file descriptor, e.g., file/pipe/socket and EXT:*KEYBOARD-INPUT*.
This is similar to LISTEN, which checks only one STREAM and only for input, and SOCKET:SOCKET-WAIT, which works only with SOCKET:SOCKET-SERVERs.
We define "status" for a SOCKET:SOCKET-SERVER or a SOCKET:SOCKET-STREAM to be :ERROR if any i/o operation will cause an error.
Additionally, for a SOCKET:SOCKET-SERVER, we define "status" to be T if a connection is available, i.e., is SOCKET:SOCKET-ACCEPT will not block, and NIL otherwise.
Additionally, for a SOCKET:SOCKET-STREAM, we define "status" in the given direction (one of :INPUT, :OUTPUT, and :IO) to be
Possible status values for various directions:
Possible values of socket-stream-or-list:
Returns the appropriate status, as defined above (:IO status for SOCKET:SOCKET-STREAM)
Return the status in the specified direction
Return a list of values, one for each element of the argument list (a la MAPCAR)
If you want to avoid CONSing up a fresh list, you can make the elements of socket-stream-or-list to be (socket-stream direction . x) or (socket-server . x). Then SOCKET:SOCKET-STATUS will destructively modify its argument and replace x or NIL with the status and return the modified list. You can pass this modified list to SOCKET:SOCKET-STATUS again.
The optional arguments specify the timeout. NIL means wait forever, 0 means poll.
The second value returned is the number of objects with non-NIL status, i.e., "actionable" objects. SOCKET:SOCKET-STATUS returns either due to a timeout or when this number is positive, i.e., if the timeout was NIL and SOCKET:SOCKET-STATUS did return, then the second value is positive.
These two functions return information about the SOCKET:SOCKET-STREAM.
A convenience function for looking up a port given the service name. It returns the servent struct as multiple values (name, list of aliases, port, protocol) for the given service-name and protocol, or all services as the list of (SIMPLE-VECTOR 4) if service-name is not given or is :DEFAULT or NIL.
Given a socket 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.
When the optional second argument is non-NIL, the hostname resolution is disabled and just the IP address is returned, without the FQDN (Fully Qualified Domain Name).
The dual to SOCKET:SOCKET-STREAM-PEER - same information, host name and port number, but for the local host. The difference from SOCKET:SOCKET-STREAM-HOST and SOCKET:SOCKET-STREAM-PORT is that this function asks the OS (and thus returns the correct trusted values) while the other two are just accessors to the internal data structure, and basically return the arguments given to the function which created the socket-stream.
Some Internet protocols, such as HTTP, provide for closing the connection in one direction using shutdown. This function provides an interface to this UNIX system call. direction should be :INPUT or :OUTPUT. Note that you should still call CLOSE after you are done with your socket-stream; this is best accomplished by using WITH-OPEN-STREAM.
All SOCKET:SOCKET-STREAMs are bidirectional STREAMs (i.e., both INPUT-STREAM-P and OUTPUT-STREAM-P return T for them). SOCKET:SOCKET-STREAM-SHUTDOWN breaks this and turns its argument stream into an input STREAM (if direction is :OUTPUT) or output STREAM (if direction is :INPUT). Thus, the following important invariant is preserved: whenever
a STREAM is open (i.e., OPEN-STREAM-P returns T) and
a STREAM is an input STREAM (i.e., INPUT-STREAM-P returns T)
Query and, optionally, set socket options using getsockopt and setsockopt. An option is a keyword, optionally followed by the new value. When the new value is not supplied, setsockopt is not called. For each option the old (or current, if new value was not supplied) value is returned. E.g., (SOCKET:SOCKET-OPTIONS socket-server :SO-LINGER 1 :SO-RCVLOWAT) returns 2 values: NIL, the old value of the :SO-LINGER option, and 1, the current value of the :SO-RCVLOWAT option.
This section describes four ways to turn CLISP programs into executable programs, which can be started as quickly as executables written in other languages.
CLISP can act as a script interpreter.
Files created with CLISP can be associated with the CLISP executables so that clicking on them would make CLISP execute the appropriate code.
Associate the extensions #P".fas" and #P".lisp" with CLISP; then you can make the files executable and run them from the command line.
Files created with CLISP can be associated with a Workbench project icon so that clicking on them would make CLISP execute the appropriate code. Note that several #P".fas" files can be concatenated (using Join) into one file.
These four techniques apply to a single #P".lisp" or #P".fas" file. If your application is made up of several #P".lisp" or #P".fas" files, you can simply concatenate them (using cat) into one file; the techniques then apply to that concatenated file.
On Unix, a text file (#P".fas" or #P".lisp") can be made executable by adding a first line of the form
#!interpreter [interpreter-arguments] |
The interpreter must be the full pathname of CLISP. The recommended path is /usr/local/bin/clisp, and if CLISP is actually installed elsewhere, making /usr/local/bin/clisp be a symbolic link to the real CLISP.
The interpreter must be a real executable, not a script. Unfortunately, in the binary distributions of CLISP on Solaris, clisp is a shell script because a C compiler cannot be assumed to be installed on this platform. If you do have a C compiler installed, build CLISP from the source yourself; make install will install clisp as a real executable.
On some platforms, the first line which specifies the interpreter is limited in length:
max. 32 characters on SunOS 4,
max. 80 characters on HP-UX,
max. 127 characters on Linux.
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-arguments must still be a normal space!) CLISP will split the interpreter-arguments at hard spaces and at normal spaces.
The script should contain Lisp forms, except in the #! line.
The file is loaded normally, through the function LOAD (in particular, the name of the script file, which is $0 in /bin/sh, can be found in *LOAD-TRUENAME* and *LOAD-PATHNAME*).
Before it is loaded, the variable EXT:*ARGS* is bound to a list of strings, representing the arguments given to the Lisp script (i.e., $1 in /bin/sh becomes (CAR EXT:*ARGS*) etc).
*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 (using EXT:APPEASE-CERRORS).
Non-continuable errors and Control-C interrupts will terminate the execution of the Lisp script with an error status (using EXT:EXIT-ON-ERROR).
If you wish the script's contents to be compiled during loading, add -C to the interpreter-arguments.
If nothing works. Another, quite inferior, alternative is to put the following into a file:
#!/bin/sh exec clisp <<EOF (lisp-form) (another-lisp-form) (yet-another-lisp-form) EOF |
There are two different ways to make CLISP "executables" for Windows platforms.
Associate the #P".mem" extension with c:\clisp\lisp.exe -B c:\clisp -M %s.
Associate the #P".fas" extension with c:\clisp\lisp.exe -B c:\clisp -M c:\clisp\lispinit.mem -i %s. Alternatively, you may want to have a function main in your #P".fas" files and associate the #P".fas" extension with c:\clisp\lisp.exe -B c:\clisp -M c:\clisp\lispinit.mem -i %s -x (main).
Then clicking on the compiled lisp file (with #P".fas" extension) will load the file (thus executing all the code in the file), while the clicking on a CLISP memory image (with #P".mem" extension) will start clisp with the given memory image.
Note that CLISP is distributed with a file install.bat, which creates a file clisp.bat on your desktop and also associates #P".fas", #P".lisp", and #P".mem" files with CLISP.
You have to build your kernel with CONFIG_BINFMT_MISC=y and CONFIG_PROC_FS=y. Then you will have a /proc/sys/fs/binfmt_misc/ directory and you will be able to do (as root; you might want to put these lines into /etc/rc.d/rc.local):
bash# echo ":CLISP:E::fas::/usr/local/bin/clisp:" >> /proc/sys/fs/binfmt_misc/register bash# echo ":CLISP:E::lisp::/usr/local/bin/clisp:" >> /proc/sys/fs/binfmt_misc/register |
Then you can do the following:
bash$ cat << EOF > hello.lisp (print "hello, world!") EOF bash$ clisp -c hello.lisp Compiling file hello.lisp ... Compilation of file hello.lisp is finished. 0 errors, 0 warnings bash$ chmod +x hello.fas bash$ hello.fas "hello, world!" bash$ |
Please read /usr/src/linux/Documentation/binfmt_misc.txt for details.
Using a Workbench project file, the memory images, source and binary files can be made "executable".
Using IconEdit, create a project icon.
Set the tool to lisp:lisp.run (or wherever the binary is located).
Define a tooltype named ARGS set to -M * for a memory image project icon or to -M lisp:lispinit.mem -i * for a source or compiled lisp file. The startup code will replace an isolated * token with the file name.
Alternatively, you may want to have a function main in your files and set the ARGS tooltype to -M lisp:lispinit.mem -i * -x (main).
You might want to add more command line options to the ARGS tooltype.
You might want to add a tooltype named WINDOW which names the console window that *TERMINAL-IO* will be bound to, for example CON:0/0/500/300/CLISP-Listener/AUTO/CLOSE, or TCP:20002.
Some ways of packaging CLISP programs are discussed in the section Quickstarting delivery with CLISP.
CLISP is Free Software, covered by the GNU GPL, with special terms governing the distribution of applications that run in CLISP. The precise terms can be found in the COPYRIGHT file contained in the source and binary distributions of CLISP. Here is an informal clarification what these terms mean in practice. Please refer to the said COPYRIGHT file when in doubt.
In many cases, CLISP does not force an application to be covered by the GNU GPL. Nevertheless, we encourage you to release your software under an open source copyright. The benefits of such a copyright for your users are numerous, in particular they are free to modify the application when their needs/requirements change, and they are free to recompile the application when they upgrade their machine or operating system.
CLISP extensions, i.e. programs which need to access non-portable CLISP internal symbols (in the packages "SYSTEM", "CLOS", "FFI", ...), must be covered by GNU GPL as well.
Other programs running in CLISP have to or need not to be placed under GNU GPL, depending on their distribution form:
Programs distributed as Lisp source or #P".fas" files can be distributed without restrictions coming from CLISP.
Programs distributed as CLISP memory images can be distributed only if accompanied with the non-CLISP #P".fas" files which make up the memory image, and a #P"Makefile" for rebuilding the memory image.
If you need to distribute a modified CLISP executable (for example, incorporating additional modules written in C), you must distribute its full source under GNU GPL. If you are not satisfied with this, you can instead put the additional modules into a separate (non-CLISP) program, with which your Lisp program will communicate via SOCKET:SOCKET-STREAMs.
(EXT:EXECUTE program arg1 arg2 ...) executes an external program. Its name is program (a full pathname). It is given the strings arg1, arg2, ... as arguments.
(EXT:EXECUTE command) executes a given command using the operating system's shell.
(EXT:SHELL [command]) calls the operating system's shell. (EXT:SHELL) calls the shell for interactive use. (EXT:SHELL command) calls the shell only for execution of the one given command.
The functions EXT:RUN-SHELL-COMMAND and EXT:RUN-PROGRAM are the general interface to EXT:SHELL and the above:
(EXT:RUN-SHELL-COMMAND command &KEY :INPUT :OUTPUT :IF-OUTPUT-EXISTS :WAIT) runs a shell command (including shell built-in commands, like DIR on Win32/OS/2 and for/do/done on UNIX).
(EXT:RUN-PROGRAM program &KEY :ARGUMENTS :INPUT :OUTPUT :IF-OUTPUT-EXISTS :WAIT) runs an external program.
the shell command.
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. The directories listed in the environment variable PATH will be searched for it.
a list of arguments (strings) that are given to the program.
where the program's input is to come from: either :TERMINAL (the standard input, default) or :STREAM (a Lisp stream to be created) or a pathname (an input file) or NIL (no input at all).
where the program's output is to be sent to: either :TERMINAL (the standard output, default) or :STREAM (a Lisp stream to be created) or a pathname (an output file) or NIL (ignore the output).
what to do if the :OUTPUT file already exists. The possible values are :OVERWRITE, :APPEND, :ERROR, with the same meaning as for OPEN. The default is :OVERWRITE.
whether to wait for program termination or not (this is useful when no i/o to the process is needed); the default is T, i.e., synchronous execution.
pass exec to the underlying shell (UNIX only).
use a shell to run the command, e.g., (EXT:RUN-PROGRAM "dir" :indirectp T) will run the shell built-in command DIR. (Win32/OS/2 only).
If :STREAM was specified for :INPUT or :OUTPUT, a Lisp STREAM is returned. If :STREAM was specified for both :INPUT and :OUTPUT, three Lisp STREAMs are returned, as for the function EXT:MAKE-PIPE-IO-STREAM. This use of EXT:RUN-PROGRAM can cause deadlocks, see EXT:MAKE-PIPE-IO-STREAM.
returns an input STREAM that will supply the output from the execution of the given operating system command.
returns an output STREAM that will pass its output as input to the execution of the given operating system 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 bidirectional STREAM, respectively.
![]() | Note that these three streams must be closed individually. |
![]() | Note that improper use of this function can lead to deadlocks. Use it at your own risk! A deadlock occurs if the command and your Lisp 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, SOCKET:SOCKET-STATUS instead of READ-LINE and READ on the input side, and complete every output operation by a FINISH-OUTPUT. The same precautions must apply to the called command as well. |
The macro EXT:WITH-OUTPUT-TO-PRINTER:
(EXT:WITH-OUTPUT-TO-PRINTER (variable [:EXTERNAL-FORMAT]) {declaration}* {form}*) |
Most modern operating systems support environment variables that associate strings ("variables") with other strings ("values"). These variables are somewhat similar to the SPECIAL variables in Common Lisp: their values are inherited by the processes from their parent process.
You can access your OS environment variables using the function (EXT:GETENV &OPTIONAL string), where string is the name of the environment variable. When string is omitted or NIL, all the environment variables and their values are returned in an alist.
You can change the value of existing environment variables or create new ones using (SETF (EXT:GETENV string) new-value).
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))) |
When running under the X Window System, you can create a bidirectional STREAM, which uses a new dedicated xterm, using the function EXT:MAKE-XTERM-IO-STREAM:
(SETQ *ERROR-OUTPUT* (SETQ *DEBUG-IO* (EXT:MAKE-XTERM-IO-STREAM))) |
Knowing that most malloc implementations are buggy and/or slow, and because CLISP needs to perform garbage collection, CLISP has its own memory management subsystem in files #P"spvw*.d".
Three kinds of storage are distinguished:
CLISP data (the "heap"), i.e. storage which contains Lisp objects and is managed by the garbage collector.
A CLISP object is one word, containing a tag (partial type information) and either immediate data (e.g. FIXNUMs or SHORT-FLOATs) or a pointer to storage. Pointers to C data have tag = machine_type = 0, pointers to CLISP stack have tag = system_type, most other pointers point to CLISP data.
Let us turn to these CLISP objects that consume regular CLISP memory. Every CLISP object has a size which is determined when the object is allocated (using one of the allocate_*() routines). The size can be computed from the type tag and - if necessary - the length field of the object's header. The length field always contains the number of elements of the object. The number of bytes is given by the function objsize().
CLISP objects which contain exactly 2 CLISP objects (i.e. CONSes, COMPLEX numbers, RATIOs) are stored in a separate area and occupy 2 words each. All other CLISP objects have "varying length" (more precisely, not a fixed length) and include a word for garbage collection purposes at their beginning.
The garbage collector is invoked by allocate_*() calls according to certain heuristics. It marks all objects which are "live" (may be reached from the "roots"), compacts these objects and unmarks them. Non-live objects are lost; their storage is reclaimed.
2-pointer objects are compacted by a simple hole-filling algorithm: fill the most-left object into the most-right hole, and so on, until the objects are contiguous at the right and the hole is contiguous at the left.
Variable-length objects are compacted by sliding them down (their address decreases).
There are 6 memory models. Which one is used, depends on the operating system and is determined at build time.
Memory Models
The heap consists of one block of fixed length (allocated at startup). The variable-length objects are allocated from the left, the 2-pointer objects are allocated from the right. There is a hole between them. When the hole shrinks to 0, garbage-collect is invoked. garbage-collect slides the variable-length objects to the left and concentrates the 2-pointer objects at the right end of the block again. When no more room is available, some reserve area beyond the right end of the block is halved, and the 2-pointer objects are moved to the right accordingly.
overview
Simple management.
No fragmentation at all.
The total heap size is limited.
The heap consists of two big blocks, one for variable-length objects and one for 2-pointer objects. The former one has a hole to the right and is extensible to the right, the latter one has a hole to the left and is extensible to the left. Similar to the previous model, except that the hole is unmapped.
overview
Total heap size grows depending on the application's needs.
No fragmentation at all.
Works only when SINGLEMAP_MEMORY is possible as well.
The heap consists of two big blocks, one for variable-length objects and one for 2-pointer objects. Both have a hole to the right, but are extensible to the right.
overview
Total heap size grows depending on the application's needs.
No fragmentation at all.
Works only when SINGLEMAP_MEMORY is possible as well.
The heap consists of many small pages (usually around 8 KB). There are two kinds of pages: one for 2-pointer objects, one for variable-length objects. The set of all pages of a fixed kind is called a "Heap". Each page has its hole (free space) at its end. For every heap, the pages are kept sorted according to the size of their hole, using AVL trees. Garbage collection is invoked when the used space has grown by 25% since the last GC; until that point new pages are allocated from the operating system. The GC compacts the data in each page separately: data is moved to the left. Emptied pages are given back to the OS. If the holes then make up more than 25% of the occupied storage, a second GC turn moves objects across pages, from nearly empty ones to nearly full ones, with the aim to free as many pages as possible.
overview
every allocation requires AVL tree operations, thus slower
Total heap size grows depending on the application's needs.
Works on operating systems which do not provide large contiguous areas.
Just like SPVW_MIXED_PAGES, except that every page contains data of only a single type tag, i.e. there is a Heap for every type tag.
overview
every allocation requires AVL tree operations, thus slower
Total heap size grows depending on the application's needs.
Works on operating systems which do not provide large contiguous areas.
More fragmentation because objects of different type never fit into the same page.
There is a big block of storage for each type tag. Each of these blocks has its data to the left and the hole to the right, but these blocks are extensible to the right (because there is enough room between them). A garbage collection is triggered when the allocation amount since the last GC reaches 50% of the amount of used space at the last GC, but at least 512 KB. The garbage collection cleans up each block separately: data is moved left.
overview
Total heap size grows depending on the application's needs.
No 16 MB total size limit.
Works only in combination with SINGLEMAP_MEMORY.
In page based memory models, an object larger than a page is the only object carried by its pages. There are no small objects in pages belonging to a big object.
The following combinations of memory model and mmap tricks are possible (the number indicates the order in which the respective models have been developed):
Every subroutine marked with can trigger GC may invoke garbage-collect. garbage-collect moves all the CLISP objects and updates the pointers. But the garbage-collect looks only on the STACK and not in the C variables. (Anything else would not be portable.) Therefore at every "unsafe" point, i.e. every call to such a subroutine, all the C variables of type object MUST BE ASSUMED TO BECOME GARBAGE. (Except for objects that are known to be unmovable, e.g. immediate data or Subrs.) Pointers inside CLISP data (e.g. to the characters of a STRING or to the elements of a SIMPLE-VECTOR) become INVALID as well.
The workaround is usually to allocate all the needed CLISP data first and do the rest of the computation with C variables, without calling unsafe routines, and without worrying about garbage-collect.
Run-time GC-safety checking is available when you build CLISP with a C++ compiler, e.g.:
bash$ CC=g++ ./configure --with-debug build-g-gxx |
Pointers to C functions and to malloced data can be hidden in CLISP objects of type machine_type; garbage-collect will not modify its value. But one should not dare to assume that a C stack pointer or the address of a C function in a shared library satisfies the same requirements.
If another pointer is to be viewed as a CLISP object, it is best to box it, e.g. in a SIMPLE-BIT-VECTOR or in an Fpointer (using allocate_fpointer().)
Common Lisp is a programmable programming language | |
John Foderaro |
CLISP can be easily extended the same way any other Common Lisp implementation can: create a lisp file with your variables, functions, macros, etc.; LOAD it into a running CLISP, and save the memory image.
This method does not work when you need to use some functionality not available in CLISP, e.g., you want to call a C function. CLISP comes with an "FFI" which allows you to access C libraries in an easy way.
In the rare cases when you really need to modify CLISP internals and add a truly built-in function, you should read the CLISP sources for inspiration and enlightenment, choose a file where your brand-new built-in function should go to, and then ...
add the LISPFUN form and the implementation there;
add the LISPFUN header to file #P"subr.d";
declare the function name in file #P"constsym.d" in the appropriate package (probably "EXT", if there is no specific package);
if your function accepts keyword arguments, then an appropriate pair of forms must be added to #P"subrkw.d" and you must make sure that the keyword symbols are declared in #P"constsym.d";
export your function name from the appropriate package in file #P"init.lisp";
when you are done, you should run make check-sources in your build directory: this will check that the definitions (source files) and the declarations (#P"subr.d", #P"subrkw.d" and #P"fsubr.d") are in sync.
![]() | Be very careful with the GC-unsafe functions! Always remember about GC-safety! |
These instructions are intentionally terse - you are encouraged to use "FFI" instead of adding built-ins directly.
If you must be able to access the variable in the C code, follow these steps:
declare the variable name in #P"constsym.d" in the appropriate package (probably "CUSTOM", if there is no specific package);
add a define_variable() call in function init_symbol_values() in file #P"spvw.d";
export your variable name from the appropriate package in file #P"init.lisp";
Any change that forces make to remake #P"lisp.run", will force recompilation of all #P".lisp" files and re-dumping of #P"lispinit.mem", which may be time-consuming. This is not always necessary, depending on what kind of change you introduced.
On the other hand, if you change any of the following files:
#P"constobj.d" |
#P"constsym.d" |
#P"fsubr.d" |
#P"subr.d" |
#P"subrkw.d" |
The CLISP compiler compiles Common Lisp programs into instruction codes for a virtual processor. This bytecode is optimized for saving space in the most common cases of Common Lisp programs. The main advantages/drawbacks of this approach, compared to native code compilation, are:
Bytecode compiled programs are a lot smaller than when compiled to native code. This results in better use of CPU caches, and in less virtual memory paging. Users perceive this as good responsiveness.
Maximum execution speed (throughput in tight loops) is limited.
Since no bytecode instructions are provided for "unsafe" operations (like unchecked array accesses, or "fast" CAR/CDR), programs run with all safety checks enabled even when compiled.
Execution speed of a program can easily be understood by looking at the output of the DISASSEMBLE function. A rule of thumb is that every elementary instruction costs 1 time unit, whereas a function call costs 3 to 4 time units.
Needing to do no type inference, the compiler is pretty straightforward and fast. As a consequence, the definition of CLOS generic functions, which needs to compile small pieces of generated code, is not perceived to be slow.
The compiler is independent from the hardware CPU. Different back-ends, one for each hardware CPU, are not needed. As a consequence, the compiler is fairly small (and would have been easily maintainable if it were written in a less kludgey way...), and it is impossible for the compiler writer to introduce CPU dependent bugs.
The bytecode can be thought of as being interpreted by a virtual processor. The engine which actually interprets the bytecode (the "implementation of the virtual machine") is actually a C function, but it could as well be a just-in-time compiler which translates a function's bytecode into hardware CPU instructions the first time said function is called.
The virtual machine is a stack machine with two stacks:
This two-stack architecture permits to save an unlimited number of CLISP objects on the STACK (needed for handling of Common Lisp multiple values), without consing. Also, in a world with a compacting no-ambiguous-roots garbage collector, STACK must only hold CLISP objects, and SP can hold all the other data belonging to a frame, which would not fit into STACK without tagging/untagging overhead.
The scope of STACK and SP is only valid for a given function invocation. Whereas the amount of STACK space needed for executing a function (excluding other function calls) is unlimited, the amount of SP space needed is known a priori, at compile time. When a function is called, no relation is specified between the caller's STACK and the callee's STACK, and between the caller's SP and the callee's SP. The bytecode is designed so that outgoing arguments on the caller's STACK can be shared by the caller's incoming arguments area (on the callee's STACK), but a virtual machine implementation may also copy outgoing arguments to incoming arguments instead of sharing them.
The virtual machine has a special data structure, values, containing the "top of stack", specially adapted to Common Lisp multiple values:
The contents of values is short-lived. It does not survive a function call, not even a garbage collection.
The interpretation of some bytecode instructions depends on a constant, jmpbufsize. This is a CPU-dependent number, the value of SYSTEM::*JMPBUF-SIZE*. In C, it is defined as ceiling(sizeof(jmp_buf),sizeof(void*)).
A compiled function consists of two objects: The function itself, containing the references to all CLISP objects needed for the bytecode, and a byte vector containing only immediate data, including the bytecode proper.
Typically, the byte vector is about twice as large as the function vector. The separation thus helps the garbage collector (since the byte vector does not need to be scanned for pointers).
A function looks like this (cf. the C type Cclosure):
This is the name of the function, normally a symbol or a list of the form (SETF symbol). It is used for printing the function and for error messages. This field is immutable.
This is the byte vector. It is a SIMPLE-BIT-VECTOR (because that's the simplest type in CLISP which contains immediate data -- note that (SIMPLE-ARRAY (UNSIGNED-BYTE 8)) is more complex than this). This field is immutable.
The remaining fields in the function object are references to other CLISP objects. These references are immutable, which is why they are called "constants". (The referenced CLISP objects can be mutable objects, such as conses or vectors, however.)
There is actually one exception to the immutability rule: When a generic function's dispatch code is installed, the codevec and consts fields are destructively modified.
Some of the consts can play special roles. A function looks like this, in more detail:
see above
see above
At most one object, representing the closed-up variables, representing the variables of the lexical environment in which this function was defined. It is a SIMPLE-VECTOR, which looks like this: #(next value1 ... valuen) where value1, ..., valuen are the values of the closed-up variables, and next is either NIL or a SIMPLE-VECTOR having the same structure.
Objects representing closed-up BLOCK tags, representing the BLOCK tags of the lexical environment in which this function was defined. Each is a CONS containing in the CDR part: either a frame pointer to the block frame, or #<DISABLED>. The CAR is the block's name, only for error message purposes.
Objects representing closed-up TAGBODY tags, representing the TAGBODY tags of the lexical environment in which this function was defined. Each is a CONS containing in the CDR part: either a frame pointer to the TAGBODY frame, or #<DISABLED> if the TAGBODY has already been left. The CAR is a SIMPLE-VECTOR containing the names of the TAGBODY tags, only for the error message purposes.
If the function was defined with a lambda list containing &KEY, here come the symbols ("keywords"), in their correct order. They are used by the interpreter during function call.
Other objects needed by the function's bytecode.
If venv-const, block-const, tagbody-const are all absent, the function is called autonomous. This is the case if the function does not refer to lexical variables, blocks or tags defined in compile code outside of the function. In particular, it is the case if the function is defined in a null lexical environment.
If some venv-const, block-const, or tagbody-const are present, the function (a "closure") is created at runtime. The compiler only generates a prototype, containing NIL values instead of each venv-const, block-const, tagbody-const. At runtime, a function is created by copying this prototype and replacing the NIL values by the definitive ones.
The list (keyword-const* other-const*) normally does not contain duplicates, because the compiler removes duplicates when possible. (Duplicates can occur nevertheless, through the use of LOAD-TIME-VALUE.)
The codevec looks like this (cf. the C type Codevec):
The 1st part of the maximal SP depth.
The jmpbufsize part of the maximal SP depth. The maximal SP depth (precomputed by the compiler) is given by spdepth_1 + spdepth_jmpbufsize * jmpbufsize.
Number of required parameters.
Number of optional parameters.
set if the function has an &REST parameter
set if the function has &KEY parameters
set if the function has &ALLOW-OTHER-KEYS
set if the function is a generic function
set if the function is a generic function and its effective method shall be returned (instead of being executed)
An abbreviation code depending on numreq, numopt, flags. It is used for speeding up the function call.
The number of &KEY parameters.
The offset of the keyword-const in the function.
The bytecode instructions.
All instructions consist of one byte, denoting the opcode, and some number of operands.
The conversion from a byte (in the range 0..255) to the opcode is performed by lookup in the table contained in the file #P"bytecode.d".
There are the following types of operands, denoted by different letters:
A (nonnegative) numeric operand. The next byte is read. If its bit 7 is zero, then the bits 6..0 give the value (7 bits). If its bit 7 is one, then the bits 6..0 and the subsequent byte together form the value (15 bits).
A (nonnegative) 1-byte operand. The next byte is read and is the value.
A label operand. A signed numeric operand is read: The next byte is read. If its bit 7 is zero, then the bits 6..0 give the value (7 bits, sign-extended). If its bit 7 is one, then the bits 6..0 and the subsequent byte together form the value (15 bits, sign-extended). If the latter 15-bit result is zero, then four more bytes are read and put together (32 bits, sign-extended). Finally, the bytecode pointer for the target is computed as the current bytecode pointer (pointing after the operand just read), plus the signed numeric operand.
mnemonic | description | semantics |
---|---|---|
(NIL) | Load NIL into values. | value1 := NIL, mv_count := 1 |
(PUSH-NIL n) | Push n NILs into the STACK. | n times do: *--STACK := NIL, values undefined |
(T) | Load T into values. | value1 := T, mv_count := 1 |
(CONST n) | Load the function's nth constant into values. | value1 := consts[n], mv_count := 1 |
mnemonic | description | semantics |
---|---|---|
(LOAD n) | Load a directly accessible local variable into values. | value1 := *(STACK+n), mv_count := 1 |
(LOADI k1 k2 n) | Load an indirectly accessible local variable into values. | k := k1 + jmpbufsize * k2, value1 := *(*(SP+k)+ n), mv_count := 1 |
(LOADC n m) | Load a closed-up variable, defined in the same function and directly accessible, into values. | value1 := SVREF(*(STACK+n),1+m), mv_count := 1 |
(LOADV k m) | Load a closed-up variable, defined in an outer function, into values. | v := venv-const, m times do: v := SVREF(v,0), value1 := SVREF(v,m), mv_count := 1 |
(LOADIC k1 k2 n m) | Load a closed-up variable, defined in the same function and indirectly accessible, into values. | k := k1 + jmpbufsize * k2, value1 := SVREF(*(*(SP+k)+n),1+m), mv_count := 1 |
(STORE n) | Store values into a directly accessible local variable. | *(STACK+n) := value1, mv_count := 1 |
(STOREI k1 k2 n) | Store values into an indirectly accessible local variable. | k := k1 + jmpbufsize * k2, *(*(SP+k)+ n) := value1, mv_count := 1 |
(STOREC n m) | Store values into a closed-up variable, defined in the same function and directly accessible. | SVREF(*(STACK+n),1+m) := value1, mv_count := 1 |
(STOREV k m) | Store values into a closed-up variable, defined in an outer function. | v := venv-const, m times do: v := SVREF(v,0), SVREF(v,m) := value1, mv_count := 1 |
(STOREIC k1 k2 n m) | Store values into a closed-up variable, defined in the same function and indirectly accessible. | k := k1 + jmpbufsize * k2, SVREF(*(*(SP+k)+n),1+m) := value1, mv_count := 1 |
mnemonic | description | semantics |
---|---|---|
(GETVALUE n) | Load a symbol's value into values. | value1 := symbol-value(consts[n]), mv_count := 1 |
(SETVALUE n) | Store values into a symbol's value. | symbol-value(consts[n]) := value1, mv_count := 1 |
(BIND n) | Bind a symbol dynamically. | Bind the value of the symbol consts[n] to value1, implicitly STACK -= 3, values undefined |
(UNBIND1) | Dissolve one binding frame. | Unbind the binding frame STACK is pointing to, implicitly STACK += 3 |
(UNBIND n) | Dissolve n binding frames. | n times do: Unbind the binding frame STACK is pointing to, thereby incrementing STACK Thus, STACK += 1+2*n |
(PROGV) | Bind a set of symbols dynamically to a set of values. | symbols := *STACK++, *--SP := STACK, build a single binding frame binding the symbols in symbols to the values in value1, values undefined |
mnemonic | description | semantics |
---|---|---|
(PUSH) | Push one object onto the STACK. | *--STACK := value1, values undefined |
(POP) | Pop one object from the STACK, into values. | value1 := *STACK++, mv_count := 1 |
(SKIP n) | Restore a previous STACK pointer. Remove n objects from the STACK. | STACK := STACK + n |
(SKIPI k1 k2 n) | Restore a previous STACK pointer. Remove an unknown number of objects from the STACK. | k := k1 + jmpbufsize * k2, STACK := *(SP+k), SP := SP+k+1 |
(SKIPSP k1 k2) | Restore a previous SP pointer. | k := k1 + jmpbufsize * k2, SP := SP+k |
mnemonic | description | semantics |
---|---|---|
(SKIP&RET n) | Clean up the STACK, and return from the function. | STACK := STACK+n, return from the function, returning values. |
(SKIP&RETGF n) | Clean up the STACK, and return from the generic function. | If bit 3 is set in the function's flags, then STACK := STACK+n, mv_count := 1, and return from the function. Otherwise: if the current function has no &REST argument, then STACK := STACK+n-numreq, apply value1 to the numreq arguments still on the STACK, and return from the function. Else STACK := STACK+n-numreq-1, apply value1 to the numreq arguments and the &REST argument, all still on the STACK, and return from the function. |
(JMP label) | Jump to label. | PC := label. |
(JMPIF label) | Jump to label, if value1 is true. | If value1 is not NIL, PC := label. |
(JMPIFNOT label) | Jump to label, if value1 is false. | If value1 is NIL, PC := label. |
(JMPIF1 label) | Jump to label and forget secondary values, if value1 is true. | If value1 is not NIL, mv_count := 1, PC := label. |
(JMPIFNOT1 label) | Jump to label and forget secondary values, if value1 is false. | If value1 is NIL, mv_count := 1, PC := label. |
(JMPIFATOM label) | Jump to label, if value1 is not a cons. | If value1 is not a cons, PC := label. values undefined |
(JMPIFCONSP label) | Jump to label, if value1 is a cons. | If value1 is a cons, PC := label. values undefined |
(JMPIFEQ label) | Jump to label, if value1 is EQ to the top-of-stack. | If eq(value1,*STACK++), PC := label. values undefined |
(JMPIFNOTEQ label) | Jump to label, if value1 is not EQ to the top-of-stack. | If not eq(value1,*STACK++), PC := label. values undefined |
(JMPIFEQTO n label) | Jump to label, if the top-of-stack is EQ to a constant. | If eq(*STACK++,consts[n]), PC := label. values undefined |
(JMPIFNOTEQTO n label) | Jump to label, if the top-of-stack is not EQ to a constant. | If not eq(*STACK++,consts[n]), PC := label. values undefined |
(JMPHASH n label) | Table-driven jump, depending on value1. | Lookup value1 in the hash table consts[n]. (The hash table's test is either EQ or EQL.) If found, the hash table value is a signed FIXNUM, jump to it: PC := PC + value. Else jump to label. values undefined |
(JMPHASHV n label) | Table-driven jump, depending on value1, inside a generic function. | Lookup value1 in the hash table SVREF(consts[0],n). (The hash table's test is either EQ or EQL.) If found, the hash table value is a signed FIXNUM, jump to it: PC := PC + value. Else jump to label. values undefined |
(JSR label) | Subroutine call. | *--STACK := function. Then start interpreting the bytecode at label, with values undefined. When a (RET) is encountered, program execution is resumed at the instruction after (JSR label). |
(JMPTAIL m n label) | Tail subroutine call. | n >= m. The STACK frame of size n is reduced to size m: {*(STACK+n-m), ..., *(STACK+n-1)} := {*STACK, ..., *(STACK+m-1)}. STACK += n-m. *--STACK := function. Then jump to label, with values undefined. |
mnemonic | description | semantics |
---|---|---|
(VENV) | Load the venv-const into values. | value1 := consts[0], mv_count := 1. |
(MAKE-VECTOR1&PUSH n) | Create a SIMPLE-VECTOR used for closed-up variables. | v := new SIMPLE-VECTOR of size n+1. SVREF(v,0) := value1. *--STACK := v. values undefined |
(COPY-CLOSURE m n) | Create a closure by copying the prototype and filling in the lexical environment. | f := copy-function(consts[m]). For i=0,..,n-1: f_consts[i] := *(STACK+n-1-i). STACK += n. value1 := f, mv_count := 1 |
mnemonic | description | semantics |
---|---|---|
(CALL k n) | Calls a constant function with k arguments. | The function consts[n] is called with the arguments *(STACK+k-1), ..., *(STACK+0). STACK += k. The returned values go into values. |
(CALL0 n) | Calls a constant function with 0 arguments. | The function consts[n] is called with 0 arguments. The returned values go into values. |
(CALL1 n) | Calls a constant function with 1 argument. | The function consts[n] is called with one argument *STACK. STACK += 1. The returned values go into values. |
(CALL2 n) | Calls a constant function with 2 arguments. | The function consts[n] is called with two arguments *(STACK+1) and *(STACK+0). STACK += 2. The returned values go into values. |
(CALLS1 b) | Calls a system function with no &REST. | Calls the system function FUNTAB[b]. The right number of arguments is already on the STACK (including #<UNBOUND>s in place of absent &OPTIONAL or &KEY parameters). The arguments are removed from the STACK. The returned values go into values. |
(CALLS2 b) | Calls a system function with no &REST. | Calls the system function FUNTAB[256+b]. The right number of arguments is already on the STACK (including #<UNBOUND>s in place of absent &OPTIONAL or &KEY parameters). The arguments are removed from the STACK. The returned values go into values. |
(CALLSR m b) | Calls a system function with &REST. | Calls the system function FUNTABR[b]. The minimum number of arguments is already on the STACK, and m additional arguments as well. The arguments are removed from the STACK. The returned values go into values. |
(CALLC) | Calls a computed compiled function with no &KEY. | Calls the compiled function value1. The right number of arguments is already on the STACK (including #<UNBOUND>s in place of absent &OPTIONAL parameters). The arguments are removed from the STACK. The returned values go into values. |
(CALLCKEY) | Calls a computed compiled function with &KEY. | Calls the compiled function value1. The right number of arguments is already on the STACK (including #<UNBOUND>s in place of absent &OPTIONAL or &KEY parameters). The arguments are removed from the STACK. The returned values go into values. |
(FUNCALL n) | Calls a computed function. | Calls the function *(STACK+n) with the arguments *(STACK+n-1), ..., *(STACK+0). STACK += n+1. The returned values go into values. |
(APPLY n) | Calls a computed function with an unknown number of arguments. | Calls the function *(STACK+n) with the arguments *(STACK+n-1), ..., *(STACK+0) and a list of additional arguments value1. STACK += n+1. The returned values go into values. |
mnemonic | description | semantics |
---|---|---|
(PUSH-UNBOUND n) | Push n #<UNBOUND>s into the STACK. | n times do: *--STACK := #<UNBOUND>. values undefined |
(UNLIST n m) | Destructure a proper list. | 0 ≤ m ≤ n. n times do: *--STACK := CAR(value1), value1 := CDR(value1). During the last m iterations, the list value1 may already have reached its end; in this case, *--STACK := #<UNBOUND>. At the end, value1 must be NIL. values undefined |
(UNLIST* n m) | Destructure a proper or dotted list. | 0 ≤ m ≤ n, n > 0. n times do: *--STACK := CAR(value1), value1 := CDR(value1). During the last m iterations, the list value1 may already have reached its end; in this case, *--STACK := #<UNBOUND>. At the end, after n CDRs, *--STACK := value1. values undefined |
(JMPIFBOUNDP n label) | Jump to label, if a local variable is not unbound. | If *(STACK+n) is not #<UNBOUND>, value1 := *(STACK+n), mv_count := 1, PC := label. Else: values undefined. |
(BOUNDP n) | Load T or NIL into values, depending on whether a local variable is bound. | If *(STACK+n) is not #<UNBOUND>, value1 := T, mv_count := 1. Else: value1 := NIL, mv_count := 1. |
(UNBOUND->NIL n) | If a local variable is unbound, assign a default value NIL to it. | If *(STACK+n) is #<UNBOUND>, *(STACK+n) := NIL. |
mnemonic | description | semantics |
---|---|---|
(VALUES0) | Load no values into values. | value1 := NIL, mv_count := 0 |
(VALUES1) | Forget secondary values. | mv_count := 1 |
(STACK-TO-MV n) | Pop the first n objects from STACK into values. | Load values(*(STACK+n-1),...,*(STACK+0)) into values. STACK += n. |
(MV-TO-STACK) | Save values on STACK. | Push the mv_count values onto the STACK (in order: value1 comes first). STACK -= mv_count. values undefined |
(NV-TO-STACK n) | Save n values on STACK. | Push the first n values onto the STACK (in order: value1 comes first). STACK -= n. values undefined |
(MV-TO-LIST) | Convert multiple values into a list. | value1 := list of values, mv_count := 1 |
(LIST-TO-MV) | Convert a list into multiple values. | Call the function VALUES-LIST with value1 as argument. The returned values go into values. |
(MVCALLP) | Start a MULTIPLE-VALUE-CALL invocation. | *--SP := STACK. *--STACK := value1. |
(MVCALL) | Finish a MULTIPLE-VALUE-CALL invocation. | newSTACK := *SP++. Call the function *(newSTACK-1), passing it *(newSTACK-2), ..., *(STACK+0) as arguments. STACK := newSTACK. The returned values go into values. |
mnemonic | description | semantics |
---|---|---|
(BLOCK-OPEN n label) | Create a BLOCK frame. | Create a BLOCK frame, STACK -= 3, SP -= 2+jmpbufsize. The topmost (third) object in the block frame is CONS(consts[n],frame-pointer) (its block-cons). Upon a RETURN-FROM to this frame, execution will continue at label. values undefined. |
(BLOCK-CLOSE) | Dissolve a BLOCK frame. | Dissolve the BLOCK frame at STACK, STACK += 3, SP += 2+jmpbufsize. Mark the block-cons as invalid. |
(RETURN-FROM n) | Leave a BLOCK whose block-cons is given. | block-cons := consts[n]. If CDR(block-cons) = #<DISABLED>, SIGNAL an ERROR. Else CDR(block-cons) is a frame-pointer. Unwind the stack up to this frame, pass it values. |
(RETURN-FROM-I k1 k2 n) | Leave a BLOCK whose block-cons is indirectly accessible. | k := k1 + jmpbufsize * k2, block-cons := *(*(SP+k)+n). If CDR(block-cons) = #<DISABLED>, SIGNAL an ERROR. Else CDR(block-cons) is a frame-pointer. Unwind the stack up to this frame, pass it values. |
mnemonic | description | semantics |
---|---|---|
(TAGBODY-OPEN n label1 ... labeln) | Create a TAGBODY frame. | Fetch consts[n], this is a SIMPLE-VECTOR with m elements, then decode m label operands. Create a TAGBODY frame, STACK -= 3+m, SP -= 1+jmpbufsize. The third object in the TAGBODY frame is CONS(consts[n],frame-pointer) (the tagbody-cons) Upon a GO to tag label of this frame, execution will continue at labell. values undefined |
(TAGBODY-CLOSE-NIL) | Dissolve a TAGBODY frame, and load NIL into values. | Dissolve the TAGBODY frame at STACK, STACK += 3+m, SP += 1+jmpbufsize. Mark the tagbody-cons as invalid. value1 := NIL, mv_count := 1. |
(TAGBODY-CLOSE) | Dissolve a TAGBODY frame. | Dissolve the TAGBODY frame at STACK, STACK += 3+m, SP += 1+jmpbufsize. Mark the tagbody-cons as invalid. |
(GO n label) | Jump into a TAGBODY whose tagbody-cons is given. | tagbody-cons := consts[n]. If CDR(tagbody-cons) = #<DISABLED>, SIGNAL an ERROR. Else CDR(tagbody-cons) is a frame-pointer. Unwind the stack up to this frame, pass it the number label. |
(GO-I k1 k2 n label) | Jump into a TAGBODY whose tagbody-cons is indirectly accessible. | k := k1 + jmpbufsize * k2, tagbody-cons := *(*(SP+k)+n). If CDR(tagbody-cons) = #<DISABLED>, SIGNAL an ERROR. Else CDR(tagbody-cons) is a frame-pointer. Unwind the stack up to this frame, pass it the number label. |
mnemonic | description | semantics |
---|---|---|
(CATCH-OPEN label) | Create a CATCH frame. | Create a CATCH frame, with value1 as tag. STACK -= 3, SP -= 2+jmpbufsize. Upon a THROW to this tag execution continues at label. |
(CATCH-CLOSE) | Dissolve a CATCH frame. | Dissolve the CATCH frame at STACK. STACK += 3, SP += 2+jmpbufsize. |
(THROW) | Non-local exit to a CATCH frame. | tag := *STACK++. Search the innermost CATCH frame with tag tag on the STACK, unwind the stack up to it, pass it values. |
mnemonic | description | semantics |
---|---|---|
(UNWIND-PROTECT-OPEN label) | Create an UNWIND-PROTECT frame. | Create an UNWIND-PROTECT frame. STACK -= 2, SP -= 2+jmpbufsize. When the stack will be unwound by a non-local exit, values will be saved on STACK, and execution will be transferred to label. |
(UNWIND-PROTECT-NORMAL-EXIT) | Dissolve an UNWIND-PROTECT frame, and start the cleanup code. | Dissolve the UNWIND-PROTECT frame at STACK. STACK += 2, SP += 2+jmpbufsize. *--SP := 0, *--SP := 0, *--SP := STACK. Save the values on the STACK, STACK -= mv_count. |
(UNWIND-PROTECT-CLOSE) | Terminate the cleanup code. | newSTACK := *SP++. Load values(*(newSTACK-1), ..., *(STACK+0)) into values. STACK := newSTACK. SPword1 := *SP++, SPword2 := *SP++. Continue depending on SPword1 and SPword2. If both are 0, simply continue execution. If SPword2 is 0 but SPword1 is nonzero, interpret it as a label and jump to it. |
(UNWIND-PROTECT-CLEANUP) | Dissolve an UNWIND-PROTECT frame, and execute the cleanup code like a subroutine call. | Dissolve the UNWIND-PROTECT frame at STACK, get label out of the frame. STACK += 2, SP += 2+jmpbufsize. *--SP := 0, *--SP := PC, *--SP := STACK. Save the values on the STACK, STACK -= mv_count. PC := label. |
mnemonic | description | semantics |
---|---|---|
(HANDLER-OPEN n) | Create a handler frame. | Create a handler frame, using consts[n] which contains the CONDITION types, the corresponding labels and the current SP depth (= function entry SP - current SP). |
(HANDLER-BEGIN&PUSH) | Start a handler. | Restore the same SP state as after the HANDLER-OPEN. value1 := the CONDITION that was passed to the handler, mv_count := 1. *--STACK := value1. |
mnemonic | description | semantics |
---|---|---|
(NOT) | Inlined call to NOT. | value1 := not(value1), mv_count := 1. |
(EQ) | Inlined call to EQ. | value1 := eq(*STACK++,value1), mv_count := 1. |
(CAR) | Inlined call to CAR. | value1 := CAR(value1), mv_count := 1. |
(CDR) | Inlined call to CDR. | value1 := CDR(value1), mv_count := 1. |
(CONS) | Inlined call to CONS. | value1 := cons(*STACK++,value1), mv_count := 1. |
(SYMBOL-FUNCTION) | Inlined call to SYMBOL-FUNCTION. | value1 := SYMBOL-FUNCTION(value1), mv_count := 1. |
(SVREF) | Inlined call to SVREF. | value1 := SVREF(*STACK++,value1), mv_count := 1. |
(SVSET) | Inlined call to SYSTEM::SVSTORE. | arg1 := *(STACK+1), arg2 := *(STACK+0), STACK += 2. SVREF(arg2,value1) := arg1. value1 := arg1, mv_count := 1. |
(LIST n) | Inlined call to LIST. | value1 := LIST(*(STACK+n-1),...,*(STACK+0)), mv_count := 1, STACK += n. |
(LIST* n) | Inlined call to LIST*. | value1 := LIST*(*(STACK+n-1),..., *(STACK+0),value1), mv_count := 1, STACK += n. |
The most frequent short sequences of instructions have an equivalent combined instruction. They are only present for space and speed optimization. The only exception is FUNCALL&SKIP&RETGF, which is needed for generic functions.
mnemonic | equivalent |
---|---|
(NIL&PUSH) | (NIL) (PUSH) |
(T&PUSH) | (T) (PUSH) |
(CONST&PUSH n) | (CONST n) (PUSH) |
(LOAD&PUSH n) | (LOAD n) (PUSH) |
(LOADI&PUSH k1 k2 n) | (LOADI k1 k2 n) (PUSH) |
(LOADC&PUSH n m) | (LOADC n m) (PUSH) |
(LOADV&PUSH k m) | (LOADV k m) (PUSH) |
(POP&STORE n) | (POP) (STORE n) |
(GETVALUE&PUSH n) | (GETVALUE n) (PUSH) |
(JSR&PUSH label) | (JSR label) (PUSH) |
(COPY-CLOSURE&PUSH m n) | (COPY-CLOSURE m n) (PUSH) |
(CALL&PUSH k n) | (CALL k n) (PUSH) |
(CALL1&PUSH n) | (CALL1 n) (PUSH) |
(CALL2&PUSH n) | (CALL2 n) (PUSH) |
(CALLS1&PUSH b) | (CALLS1 b) (PUSH) |
(CALLS2&PUSH b) | (CALLS2 b) (PUSH) |
(CALLSR&PUSH m n) | (CALLSR m n) (PUSH) |
(CALLC&PUSH) | (CALLC) (PUSH) |
(CALLCKEY&PUSH) | (CALLCKEY) (PUSH) |
(FUNCALL&PUSH n) | (FUNCALL n) (PUSH) |
(APPLY&PUSH n) | (APPLY n) (PUSH) |
(CAR&PUSH) | (CAR) (PUSH) |
(CDR&PUSH) | (CDR) (PUSH) |
(CONS&PUSH) | (CONS) (PUSH) |
(LIST&PUSH n) | (LIST n) (PUSH) |
(LIST*&PUSH n) | (LIST* n) (PUSH) |
(NIL&STORE n) | (NIL) (STORE n) |
(T&STORE n) | (T) (STORE n) |
(LOAD&STOREC k n m) | (LOAD k) (STOREC n m) |
(CALLS1&STORE b k) | (CALLS1 b) (STORE k) |
(CALLS2&STORE b k) | (CALLS2 b) (STORE k) |
(CALLSR&STORE m n k) | (CALLSR m n) (STORE k) |
(LOAD&CDR&STORE n) | (LOAD n) (CDR) (STORE n) |
(LOAD&CONS&STORE n) | (LOAD n+1) (CONS) (STORE n) |
(LOAD&INC&STORE n) | (LOAD n) (CALL1 #'1+) (STORE n) |
(LOAD&DEC&STORE n) | (LOAD n) (CALL1 #'1-) (STORE n) |
(LOAD&CAR&STORE m n) | (LOAD m) (CAR) (STORE n) |
(CALL1&JMPIF n label) | (CALL1 n) (JMPIF label) |
(CALL1&JMPIFNOT n label) | (CALL1 n) (JMPIFNOT label) |
(CALL2&JMPIF n label) | (CALL2 n) (JMPIF label) |
(CALL2&JMPIFNOT n label) | (CALL2 n) (JMPIFNOT label) |
(CALLS1&JMPIF b label) | (CALLS1 b) (JMPIF label) |
(CALLS1&JMPIFNOT b label) | (CALLS1 b) (JMPIFNOT label) |
(CALLS2&JMPIF b label) | (CALLS2 b) (JMPIF label) |
(CALLS2&JMPIFNOT b label) | (CALLS2 b) (JMPIFNOT label) |
(CALLSR&JMPIF m n label) | (CALLSR m n) (JMPIF label) |
(CALLSR&JMPIFNOT m n label) | (CALLSR m n) (JMPIFNOT label) |
(LOAD&JMPIF n label) | (LOAD n) (JMPIF label) |
(LOAD&JMPIFNOT n label) | (LOAD n) (JMPIFNOT label) |
(LOAD&CAR&PUSH n) | (LOAD n) (CAR) (PUSH) |
(LOAD&CDR&PUSH n) | (LOAD n) (CDR) (PUSH) |
(LOAD&INC&PUSH n) | (LOAD n) (CALL1 #'1+) (PUSH) |
(LOAD&DEC&PUSH n) | (LOAD n) (CALL1 #'1-) (PUSH) |
(CONST&SYMBOL-FUNCTION n) | (CONST n) (SYMBOL-FUNCTION) |
(CONST&SYMBOL-FUNCTION&PUSH n) | (CONST n) (SYMBOL-FUNCTION) (PUSH) |
(CONST&SYMBOL-FUNCTION&STORE n k) | (CONST n) (SYMBOL-FUNCTION) (STORE k) |
(APPLY&SKIP&RET n k) | (APPLY n) (SKIP&RET k) |
(FUNCALL&SKIP&RETGF n k) | (FUNCALL n) (SKIP&RETGF k) |
Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
The purpose of this License is to make a manual, textbook, or other functional and useful document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.
This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.
We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.
This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.
A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.
A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.
The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.
The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.
A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not "Transparent" is called "Opaque".
Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.
The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text.
A section "Entitled XYZ" means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as "Acknowledgements", "Dedications", "Endorsements", or "History".) To "Preserve the Title" of such a section when you modify the Document means that it remains a section "Entitled XYZ" according to this definition.
The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.
You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, and you may publicly display copies.
If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.
If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.
If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.
It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.
You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:
Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission.
List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement.
State on the Title page the name of the publisher of the Modified Version, as the publisher.
Preserve all the copyright notices of the Document.
Add an appropriate copyright notice for your modifications adjacent to the other copyright notices.
Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below.
Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice.
Include an unaltered copy of this License.
Preserve the section Entitled "History", Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence.
Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission.
For any section Entitled "Acknowledgements" or "Dedications", Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein.
Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles.
Delete any section Entitled "Endorsements". Such a section may not be included in the Modified Version.
Do not retitle any existing section to be Entitled "Endorsements" or to conflict in title with any Invariant Section.
Preserve any Warranty Disclaimers.
If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles.
You may add a section Entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.
You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.
The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.
You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.
The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.
In the combination, you must combine any sections Entitled "History" in the various original documents, forming one section Entitled "History"; likewise combine any sections Entitled "Acknowledgements", and any sections Entitled "Dedications". You must delete all sections Entitled "Endorsements".
You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.
You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.
A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an "aggregate" if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.
If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.
Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.
If a section in the Document is Entitled "Acknowledgements", "Dedications", or "History", the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.
You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See http://www.gnu.org/copyleft/.
Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation.
To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page:
Copyright (c) YEAR YOUR NAME. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the "with...Texts." line with this:
with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation.
If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.
[CLtL1] Guy L. Steele, Jr., Common Lisp: the Language (1st Edition), 1984, 465, 0-201-10088-6, Digital Press.
[CLtL2] Guy L. Steele, Jr., Common Lisp: the Language (2nd Edition), 1990, 1032, 0-201-10088-6, Digital Press.
[Metaobject Protocol] AMOP, Gregor Kiczales, Jim des Rivieres, and Daniel G. Bobrow, The Art of the Metaobject Protocol, 1991, 335, 0-262-61074-4, MIT Press.
[ANSI CL standard] ANSI CL, 1994, ANSI Common Lisp standard X3.226-1994 - Information Technology - Programming Language - Common Lisp.
[Common Lisp HyperSpec] CLHS, Common Lisp HyperSpec.