This implementation is mostly conforming to the
ANSI Common Lisp standard X3.226-1994available on-line as the
"Information Technology - Programming Language - Common Lisp"
Common Lisp HyperSpec(but the printed ANSI document remains the authoritative source of information).
http://www.harlequin.com/education/books/HyperSpec/
("CLHS" for short)
ANSI CL supersedes the earlier specifications
Guy L. Steele Jr.: Common Lisp - The Language (2nd ed.).and
Digital Press 1990, 1032 pages.
("CLtL2" for short) available on-line
Guy L. Steele Jr.: Common Lisp - The Language (1st ed.).
Digital Press 1984, 465 pages.
("CLtL1" for short)
These notes document the differences between the CLISP implementation of Common Lisp and the ANSI CL standard, and some implementation details. This document is indexed in parallel to CLHS.
The final delimiter of an interactive stream: On Unix, the user has
to type Ctrl-D at the beginning of a line. On DOS or Win32, the user has
to type Ctrl-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, in 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.
class
,
built-in-class
,
structure-class
,
standard-class
,
standard-method
contain the class
structure-object
instead of the class
standard-object
.
Symbols missing from the COMMON-LISP
package:
*print-lines*
*print-miser-width*
*print-pprint-dispatch*
call-method
change-class
compiler-macro
compiler-macro-function
copy-pprint-dispatch
define-compiler-macro
define-method-combination
ensure-generic-function
invalid-method-error
make-instances-obsolete
make-load-form
make-load-form-saving-slots
make-method
method-combination
method-combination-error
pprint-dispatch
pprint-exit-if-list-exhausted
pprint-fill
pprint-indent
pprint-linear
pprint-logical-block
pprint-newline
pprint-pop
pprint-tab
pprint-tabular
set-pprint-dispatch
simple-condition-format-control
style-warning
unbound-slot
unbound-slot-instance
update-instance-for-different-class
update-instance-for-redefined-class
upgraded-complex-part-type
with-compilation-unit
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.
When a string is read, no character attributes are removed.
The backquote read macro also works when nested. Example:
(eval ``(,#'(lambda () ',a) ,#'(lambda () ',b)))
=(eval `(list #'(lambda () ',a) #'(lambda () ',b)))
=(eval (list 'list (list 'function (list 'lambda nil (list 'quote a))) (list 'function (list 'lambda nil (list 'quote b))) ) )
Multiple backquote combinations like ,,@
or
,@,@
are not implemented. Their use would be confusing
anyway.
#, | load-time evaluation |
#Y | function objects and file encoding |
#" | 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
).
As in Scheme, the macro (lisp:the-environment)
returns the current lexical environment. This works only in interpreted code
and is not compilable!
(lisp:eval-env form
&optional env)
evaluates a form in a given lexical environment, just if the form had
been part of the program text that environment came from.
CLISP compiles to platform-independent byte-code.
Hash tables are externalizable objects.
The declarations (type
type var ...)
, (ftype type fun
...)
, (function name
arglist result-type)
, (optimize (quality
value) ...)
are ignored by the interpreter and the
compiler.
The ANSI CL declaration
(optimize
(debug ...))
is legal.
Additional declarations:
(ignorable
var ...)
affects the variable binding
for the variable var. The compiler will not warn about the
variable, regardless whether it is used or not.
(compile)
has the effect that the current
form is compiled prior to execution.
Examples:
(locally (declare (compile)) form)
executes a compiled version of form.
(let ((x 0))
(flet ((inc () (declare (compile)) (incf x))
(dec () (decf x)))
(values #'inc #'dec)
) )
returns two functions. The first is compiled and increments
x
, the second is interpreted (slower) and decrements the
same x
.
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 lisp:ethe
macro.
The initial value of an &aux
variable in a boa lambda
list is the value of the corresponding slot's initial form.
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 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.
(lisp:type-expand-1
typespec)
: If typespec is a user-defined
type, type-expand-1
will expand it once and return two
values: the expansion and
t
. If typespec is not
a user-defined type, then the two values typespec and
nil
are returned.
(lisp:type-expand typespec)
:
This is similar to (type-expand-1 typespec)
, but
repeatedly expands typespec until it is no longer a
user-defined type. A second value of
t
or
nil
is returned as for type-expand-1
,
indicating whether the original typespec was a user-defined
type.
The possible results of
type-of
are:
cons
symbol
,
null
,
boolean
fixnum
,
bignum
,
ratio
,
short-float
,
single-float
,
double-float
,
long-float
,
complex
character
,
base-char
(array
element-type dimensions)
,
(simple-array
element-type dimensions)
(vector
t size)
,
(simple-vector
size)
(string
size)
,
(simple-string
size)
(base-string
size)
,
(simple-base-string
size)
(bit-vector
size)
,
(simple-bit-vector
size)
function
,
compiled-function
stream
,
file-stream
,
synonym-stream
,
broadcast-stream
,
concatenated-stream
,
two-way-stream
,
echo-stream
,
string-stream
,
package
,
hash-table
,
readtable
,
pathname
,
logical-pathname
,
random-state
,
byte
special-operator
, load-time-eval
,
symbol-macro
,
encoding
,
foreign-pointer
, foreign-address
,
foreign-variable
, foreign-function
weak-pointer
,
read-label
,
frame-pointer
,
system-internal
address
(should not occur)
The CLOS symbols are exported from the package "CLOS"
and thus normally visible in all user 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 (unuse-package
"CLOS")
.
defclass
: It is required that the superclasses
of a class be defined before the defclass
form for the
class is evaluated.
defclass
supports the option :metaclass
structure-class
. This option is necessary in order to define a
subclass of a
defstruct
-defined structure type using
defclass
instead of
defstruct
.
When
call-next-method
is called with arguments, the rule
that the ordered set of applicable methods must be the same as for the
original arguments is enforced by the implementation only in interpreted
code.
call-next-method
and
next-method-p
are
local macros, not local functions. Use #'(lambda ()
(call-next-method))
instead of #'call-next-method
if
you really need it as a function.
There is a generic function
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. They are not
imported into the packages COMMON-LISP-USER
and
COMMON-LISP
because of the ANSI CL issue GENERIC-FLET-POORLY-DESIGNED:DELETE.
The function
ensure-generic-function
is not implemented.
add-method
can put methods into other generic functions
than the one the method came from.
print-object
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.
documentation
still has the CLtL1 implementation.
Among those classes listed in
Figure 4-8, only the following are instances of
built-in-class
:
t
,
character
,
number
,
complex
,
real
,
float
,
rational
,
ratio
,
integer
,
sequence
,
array
,
vector
,
bit-vector
,
string
,
list
,
cons
,
symbol
,
null
,
function
,
generic-function
,
standard-generic-function
,
hash-table
,
package
,
pathname
,
logical-pathname
,
random-state
,
readtable
,
stream
,
synonym-stream
,
broadcast-stream
,
concatenated-stream
,
two-way-stream
,
echo-stream
,
string-stream
,
file-stream
.
defclass
supports the :metaclass
option. Possible values are
standard-class
(the default) and
structure-class
(which creates structure classes, like
defstruct
does).
Redefining classes is not supported. The function
update-instance-for-redefined-class
is not
implemented.
The class
method-combination
is not implemented.
prog1
,
prog2
,
and
,
or
,
psetq
,
when
,
unless
,
cond
,
case
,
multiple-value-list
,
multiple-value-bind
,
multiple-value-setq
are implemented as special operators
and, as such, rather efficient.
The ANSI CL macro
destructuring-bind
does not perform full error checking.
compiled-function-p
returns t
on built-in
functions written in C, compiled functions and special operator
handlers. Therefore
compiled-function
is not a subtype of
function
.
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 CL implementations.
(let ((x y)) (eq x x))
always returns t
, regardless of
y
.
(setf (symbol-function
symbol) object)
requires object
to be either a function, a
symbol-function
return value or a
lambda expression. A
lambda expression is thereby immediately converted to a function.
Additional places:
funcall
:
(setf (funcall #'symbol ...) object)
and
(setf (funcall 'symbol ...) object)
are equivalent to
(setf (symbol ...) object)
.
get-dispatch-macro-character
:
(setf (get-dispatch-macro-character ...) ...)
performs a
set-dispatch-macro-character
.
long-float-digits
:
(setf (long-float-digits) digits)
sets the
default mantissa length of long floats to digits bits.
values-list
:
(setf (values-list list) form)
is
equivalent to
(values-list (setf list (multiple-value-list
form)))
&key
markers in
defsetf
lambda lists are supported, but the
corresponding keywords must appear literally in the program text.
(get-setf-expansion
form &optional
env)
, (lisp:get-setf-method form
&optional env)
, and
(lisp:get-setf-method-multiple-value form &optional
env)
receive as optional argument the environment
necessary for macro expansions. In
define-setf-expander
and
lisp: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
, lisp:get-setf-method
and lisp: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.
See also the lisp:letf and lisp:letf* macros.
(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 lisp:symbol-macro-expand
tests for a symbol macro: If symbol is defined as symbol
macro, (lisp:symbol-macro-expand symbol)
returns two
values,
t
and the expansion, else it returns
nil
.
Calling
boundp
on a symbol defined as symbol macro
returns t
.
Calling
symbol-value
on a symbol defined as symbol
macro returns the value of the expansion. Calling
set
on a symbol defined as symbol macro calls
setf
on the expansion.
Calling
makunbound
on a symbol defined as symbol macro
removes the symbol macro definition.
lambda-list-keywords
=
(&optional
&rest
&key
&allow-other-keys
&aux
&body
&whole
&environment)
Platform dependent: | 16-bit CPU | 32-bit CPU | 64-bit CPU |
---|---|---|---|
call-arguments-limit
| 216=65536 | 232=4294967296 | |
multiple-values-limit
| 27=128 | ||
lambda-parameters-limit
| 216=65536 | 232=4294967296 |
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)
) ) )
(proclaim '(special
var))
declarations may not be undone. The same holds
for
defvar
,
defparameter
and
defconstant
declarations.
It is an error if a
defconstant
variable is bound at the
moment the
defconstant
is executed, but
defconstant
does not check this.
Constants may not be bound dynamically or lexically.
eval-when
also accepts the situations (not
eval)
and (not compile)
.
No notes.
Changing
the class of a given instance is not supported. The
functions
change-class
,
update-instance-for-different-class
,
make-instances-obsolete
are not implemented.
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
,
method-qualifiers
are not implemented.
The :print-function
option should contain a
lambda expression
(lambda (structure stream depth) (declare (ignore depth)) ...)
This
lambda expression names a function whose task is to output the
external representation of structure onto the stream. This may be done
by outputting text onto the stream using
write-char
,
write-string
,
write
,
prin1
,
princ
,
print
,
pprint
,
format
and the
like. The following rules must be obeyed:
*print-escape*
must be respected.
*print-pretty*
should not and cannot be
respected, since the pretty-print mechanism is not accessible from
outside.
*print-circle*
need not to be
respected. This is managed by the system. (But the print-circle
mechanism handles only those objects that are (direct or indirect)
components of structure.)
*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.)
*print-length*
must be respected,
especially if you are outputting an arbitrary number of components.
*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.
*print-base*
,
*print-radix*
,
*print-case*
,
*print-gensym*
,
*print-array*
,
lisp:*print-closure*
,
lisp:*print-rpars*
,
lisp:*print-indent-lists*
.
The :inherit
option is exactly like
:include
except that it does not create
new accessors for the inherited slots.
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.
The macro (lisp:muffle-cerrors
{form}*)
executes the forms. When a
continuable error occurs, no message is printed. Instead, the
continue
restart is invoked.
The macro (lisp:appease-cerrors
{form}*)
executes the forms. When a
continuable error occurs, the error is printed as a warning and the
continue
restart is invoked.
The macro (lisp:exit-on-error
{form}*)
executes the forms. When a
non-continuable error or a Ctrl-C interrupt occurs, the error is printed
and CLISP terminates with error status.
The macro lisp:with-restarts
is like
restart-case
, except that the forms are specified after
the restart clauses instead of before them, and the restarts created are
not implicitly associated to any condition.
(lisp: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.
signal
is
simple-condition
, not
simple-error
.
In
restart-case
clauses the argument list can also
be specified after the keyword/value pairs instead of before them. The
syntax therefore is
(restart-case
form {restart-clause}*)
with
restart-clause ::= | (restart-name arglist
{keyword value}* {form}*)
|
| (restart-name {keyword
value}* arglist {form}*)
|
compute-restarts
and
find-restart
behave as specified in ANSI CL: If the
optional condition argument is non-nil
, only restarts associated with
that condition and restarts associated to no condition at all are
considered. Therefore the effect of associating a restart to a
condition is not to activate it, but to hide it from other
conditions. This makes the syntax dependent implicit association
performed by
restart-case
nearly obsolete.
The default condition type for conditions created by
warn
is
simple-warning
, not
simple-error
.
No notes.
The standard ANSI CL packages
COMMON-LISP
with the nickname
CL
;
COMMON-LISP-USER
with the nickname
CL-USER
and
KEYWORD
are implemented. The package
COMMON-LISP
exports only
those symbols from the ANSI CL standard that are actually implemented.
COMMON-LISP-USER
package uses only the
COMMON-LISP
package.
LISP
exports all symbols needed for a
CLtL1/CltL2 environment, excluding CLOS.
CLOS
exports all CLOS specific
symbols needed for a CLtL1/CltL2 environment.
USER
is the default user's package for a
CLtL1/CltL2 environment.
SYSTEM
, with the nicknames
SYS
and
COMPILER
, has no exported symbols.
It defines many system internals.
CHARSET
defines and exports some character sets, for use with
make-encoding
and as :external-format
argument.
FFI
implements the foreign function interface. Some platforms only.
SCREEN
defines an API for random screen access. Some platforms only.
All pre-existing packages except USER
and COMMON-LISP-USER
belong to the
implementation, in the sense that doing side-effects on them or on their
symbols causes undefined behavior.
make-package
For
common-lisp:make-package
, the default value of the
:use
argument is ("COMMON-LISP")
.
For lisp:make-package
, the default value of the
:use
argument is ("LISP" "CLOS")
.
make-package
and
lisp:in-package
accept a
keyword argument :case-sensitive
. Similarly,
defpackage
accepts an option
:case-sensitive
. When its value is non-nil
, the package will
be case sensitive, i.e., the reader will not case-convert symbol names
before looking them up or creating them in this package. The package
names are still subject to (readtable-case *readtable*)
, though.
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
, not integers.
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 | |
single-float | 1 bit | 23+1 bits | 8 bits | CLISP uses IEEE format |
double-float | 1 bit | 52+1 bits | 11 bits | CLISP uses IEEE format |
long-float | 1 bit | >=64 bits | 32 bits | variable length |
The single and double float formats are those of the IEEE standard
(1981), except that CLISP does not support features like +0, -0, +inf,
-inf, gradual underflow, NaN, etc. (Common Lisp does not make use of
these features.) This is why *features*
does not contain the
:IEEE-FLOATING-POINT keyword.
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 (lisp:long-float-digits)
.
It can be set by (setf (lisp:long-float-digits)
nnn)
, where nnn is a positive integer.
Example: (setf (lisp:long-float-digits) 3322)
sets the
default precision of long floats to 1000 decimal digits.
The floating point contagion is controlled by the variable
lisp:*floating-point-contagion-ansi*
.
When it is non-nil, contagion is done as per the ANSI CL standard:
short->single->double->long.
1.5
is actually 1.5+-0.05
. Consider adding
1.5
and 1.75
. ANSI CL requires that (+
1.5 1.75)
return 3.25
, while traditional CLISP
would return 3.3
. The implied random variables are:
3.25+-0.005
and 3.3+-0.05
. Note that the
CLISP's way DOES lie about the mean: the mean
IS 3.25
and nothing else, while the ANSI
CL's way COULD be lying about the deviation
(accuracy): if the implied accuracy of 1.5 (0.05)
is its
actual accuracy, then the accuracy of the result cannot be smaller that
that. Therefore, since CL has no way of knowing the actual accuracy,
ANSI CL (and all the other standard engineering programming languages,
like C, FORTRAN etc) decides that keeping the accuracy correct is the
business of the programmer, while the language should preserve what it
can - the precision.
E(x^2)-E(x)^2
can be negative!) The user should not
mix floats of different precision (that's what
lisp:*warn-on-floating-point-contagion*
is for), but one
should not be penalized for this too harshly.
When lisp:*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!)
1.0s0
and 1.0d0
, we should get
2.0s0
.
(- (+ 1.7 pi) pi)
should not return
1.700000726342836417234L0
, it should return
1.7f0
(or 1.700001f0
if there were
rounding errors).
If the variable
lisp:*warn-on-floating-point-contagion*
is
true, a warning is emitted for every coercion involving different
floating-point types.
When rational numbers are to be converted to
floats (due to
float
,
coerce
,
sqrt
or a transcendental function), the result type is
given by the variable
lisp:*default-float-format*
.
The macro
lisp:without-floating-point-underflow
:
(without-floating-point-underflow {form}*)
executes the forms, with errors of type
floating-point-underflow
inhibited. Floating point
operations will silently return zero instead of signalling an error of
type
floating-point-underflow
.
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)
.
(lisp:! n)
returns the factorial
of n, n a nonnegative integer.
(lisp:exquo x y)
returns the quotient x/y of two integers x,y,
and checks that it is an integer. (This is more efficient than
/
.)
(lisp:xgcd x1
... xn)
returns the values g,
c1, ..., cn, where
g is the greatest common divisor of the integers
x1,...,xn, and
c1,...,cn are integer
coefficients such that
g
= (gcd x1
... xn)
= (+ (*
c1 x1) ... (*
cn xn))
(expt
base exponent)
is not very precise if exponent has large absolute value.
(log
number base)
signals an error if base = 1
.
The value of
pi
is a long float with the precision given by (lisp:long-float-digits)
. When this
precision is changed, the value of
pi
is automatically recomputed. Therefore pi
is a variable, not
a constant.
float-radix
always returns 2
.
(float-digits
number digits)
coerces number (a real number) to a floating point number
with at least digits mantissa digits. The following holds:
(>=
(float-digits
(float-digits
number digits)) digits)
constant name | 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 |
Platform dependent: | 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
most-positive-long-float
,
least-positive-long-float
,
least-negative-long-float
,
most-negative-long-float
,
least-positive-normalized-long-float
,
least-negative-normalized-long-float
,
long-float-epsilon
,
long-float-negative-epsilon
are recomputed whenever (lisp:long-float-digits)
is changed. They
are variables, not constants.
This condition is never signaled by CLISP.
This condition is never signaled by CLISP.
The characters are ordered according to a superset of the ASCII encoding.
UNICODE
.
UNICODE
.
#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 | ≡ | ± | ≥ | ≤ | ⌠ | ⌡ | ÷ | ≈ | ° | ∙ | · | √ | ⁿ | ² | ■ |
Here ** are control characters, not graphic characters. (The characters left blank here cannot be represented in this character set).
UNICODE
.
#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 | ð | ñ | ò | ó | ô | õ | ö | ÷ | ø | ù | ú | û | ü | ý | þ | ÿ |
UNICODE
.
#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 | ö | æ | ù | ú | û | ı | ü | ý | ł | ø | œ | ß | þ | ÿ |
Here ** are control characters, not graphic characters. (The characters left blank here cannot be represented in this character set).
#\Space | #x20 |
---|---|
#\Newline | #x0A |
#\Backspace | #x08 |
---|---|
#\Tab | #x09 |
#\Linefeed | #x0A |
#\Page | #x0C |
#\Return | #x0D |
#\Rubout | #x08 |
---|
#\Rubout | #x7F |
---|
#\Newline
is the delimiter between
lines.
There are the following additional characters with names:
#\Null | #x00 |
---|---|
#\Bell | #x07 |
#\Escape | #x1B |
Additionally, the following syntax is defined for characters with code from #x00 to #x1F:
#\^@ | #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
can not be used to compare objects of type
sys::input-character
.
lisp:char-font-limit
= 16
lisp:char-bits-limit
= 16
:control | lisp:char-control-bit
|
:meta | lisp:char-meta-bit
|
:super | lisp:char-super-bit
|
:hyper | lisp:char-hyper-bit
|
(lisp:char-font object)
sys::input-character
.
(lisp:char-bits object)
sys::input-character
.
(lisp:make-char char [bits
[font]])
sys::input-character
, or
nil
if
such a character cannot be created.
(lisp:char-bit object name)
t
if the named bit is set in object, else
nil
.
(lisp:set-char-bit object name
newvalue)
sys::input-character
with the named bit set
or unset, depending on the boolean newvalue.
sys::input-character
type
only to mention special keys and Control/Alternate/Shift key status
on return from
(read-char
lisp:*keyboard-input*)
.
character
itself.
U0000..U001F
and
U007F..U009F
.
stream-external-format
and the description of encodings, in particular, line
terminators. The default behavior is as follows:
#\Newline
is converted to
CR/LF. (This is the usual convention on DOS.) For example,
#\Return #\Newline
is written as CR/CR/LF.
When reading from a file, CR/LF is converted to #\Newline
(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).
char-int
is the same as the character's code.
char-code
takes values from 0 (inclusive) to
char-code-limit
(exclusive), i.e., the implementation
supports exactly
char-code-limit
characters.
binaries built ... | without UNICODE support | with UNICODE support |
---|---|---|
char-code-limit
| 256 | 65536 |
The types lisp: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 abcdefghijklmnopqrstuvwxyzand the international alphabetic characters from the character set:
ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜßáíóúñѪºãõØøÀÃÕ etc.
The functions
char-equal
,
char-not-equal
,
char-lessp
,
char-greaterp
,
char-not-greaterp
,
char-not-lessp
ignore bits
and font attributes of their arguments.
(lisp:char-width
character)
returns the number of screen columns occupied by character.
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 string-width
.
The characters that are not graphic chars and the space character have names:
(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
|
(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
|
(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
|
lisp:char-control-bit | 1 |
---|---|
lisp:char-meta-bit | 2 |
lisp:char-super-bit | 4 |
lisp:char-hyper-bit | 8 |
sublis
and nsublis
apply the :key
argument to the nodes of the cons tree and not
to the keys of the alist.
The function lisp:mapcap
is like
mapcan
, except that it concatenates the resulting lists
with append
instead of nconc
:
(mapcap fun x1
... xn)
==
(apply #'append (mapcar fun x1
... xn))
(Actually a bit more efficient that this would be.)
The function lisp:maplap
is like
mapcon
, except that it concatenates the resulting lists
with append
instead of nconc
:
(maplap fun x1
... xn)
==
(apply #'append (maplist fun x1
... xn))
(Actually a bit more efficient that this would be.)
make-array
can return specialized arrays for the element types (unsigned-byte 2)
,
(unsigned-byte
4)
, (unsigned-byte 8)
,
(unsigned-byte
16)
, (unsigned-byte 32)
and
of course bit
and
character
.
Platform dependent: | 16-bit CPU | 32-bit CPU | 64-bit CPU |
---|---|---|---|
array-rank-limit
| 216=65536 | 232=4294967296 | |
array-dimension-limit
| 224=16777216 | 232=4294967296 | |
array-total-size-limit
| 224=16777216 | 232=4294967296 |
Note that these constants are not fixnums, contrary to the ANSI CL Issue ARRAY-DIMENSION-LIMIT-IMPLICATIONS:ALL-FIXNUM.
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"
<
"ö"
.
(lisp:string-width
string)
returns the number of screen columns occupied by string. This is
computed as the sum of all char-width
s
of all of the string's characters.
For iteration through a sequence, a macro
lisp:doseq
, similar to
dolist
, may be used instead of
map
:
(lisp:doseq (var seqform
[resultform]) {declaration}*
{tag|statement}* )
lisp:doseq
forms are
iteration forms.
The result of
nreverse
is always
eq
to the argument.
nreverse
on a vector swaps pairs of elements.
nreverse
on a list swaps the first and the last
element and reverses the list chaining between them.
The result of
nreconc
is
eq
to the first argument unless it is
nil
,
in which case the result is
eq
to the second argument.
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.
Contrary to the ANSI CL issue 283
RANGE-OF-COUNT-KEYWORD:NIL-OR-INTEGER, negative :count
keyword arguments are not allowed unless you set
lisp:*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 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
has an additional keyword
:initial-contents
:
(make-hash-table &key :test :initial-contents :size
:rehash-size :rehash-threshold)
The :initial-contents
argument is an alist that is used
to initialize the new hash table. The :rehash-threshold
argument is ignored.
For iteration through a hash table, a macro
lisp:dohash
, similar to
dolist
, can be used instead of
maphash
:
(lisp:dohash (key-var value-var hash-table-form [resultform])
{declaration}* {tag|statement}*
)
lisp:dohash
forms are
iteration forms.
For most operations, pathnames denoting files and pathnames denoting directories can not be used interchangeably.
#p"FOO/BAR"
denotes the file
BAR
in the directory FOO
, while
#p"FOO/BAR/"
denotes the subdirectory
BAR
of the directory FOO
.
#p"FOO\\BAR"
denotes the file
BAR
in the directory FOO
, while
#p"FOO\\BAR\\"
denotes the subdirectory
BAR
of the directory FOO
.
#p"FOO.BAR"
denotes the file
FOO
in the directory BAR
, while
#p"FOO.BAR."
denotes the subdirectory
BAR
of the directory FOO
.
directory
, lisp:dir
,
lisp:cd
, lisp:make-dir
,
lisp:delete-dir
.
The minimum filename syntax that may be used portably is:
"xxx"
| for a file with name xxx, |
"xxx.yy"
| for a file with name xxx and type yy, |
".yy"
| for a pathname with type yy and no name specified. |
Hereby xxx 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.
host
nil
device
nil
or :wild
or
"A"
|...|"Z"
directory
(startpoint . subdirs)
where
:relative
|
:absolute
()
|
(subdir . subdirs)
:current
(means
"."
) or
:parent
(means
".."
) or
:wild-inferiors
(means
"..."
, all subdirectories) or
(name
. type)
:wild
or a
simple-string
of length at most 8
:wild
or a
simple-string
of length at most 3
name
nil
or
:wild
or a
simple-string
of length at most 8
type
nil
or
:wild
or a
simple-string
of length at most 3
version
nil
(may also be specified as
:wild
or :newest
)
When a pathname is to be fully specified (no wildcards), that means
that no :wild
, :wild-inferiors
is allowed, and
name =
nil
may not be allowed either.
External notation: | A:\sub1.typ\sub2.typ\name.typ
|
using defaults: | \sub1.typ\sub2.typ\name.typ
|
or | name.typ
|
or | *:\sub1.typ\*.*\name.*
|
or similar. |
Instead of '\'
one may use '/'
, as usual
for DOS calls.
host
nil
device
nil
or a
simple-string
directory
(startpoint . subdirs)
where
:relative
| :absolute
()
|
(subdir . subdirs)
:wild-inferiors
(means "**"
or "..."
,
all subdirectories) or
:parent
(means "/"
instead of
"subdir/"
) or
simple-string
, may contain wildcard
characters ?
and *
name
nil
or
simple-string
, may contain wildcard
characters ?
and *
(may also be specified
as :wild
)
type
nil
or
simple-string
, may contain wildcard
characters ?
and *
(may also be specified
as :wild
)
version
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!
A filename from AMIGAOS is split into name and type according to the following rule:
'.'
in the filename, then the
name is everything, type is
nil
;
'.'
, then name is the part
before and type the part after the last dot.
Case is ignored in the strings on comparison. No case conversions are performed.
When a pathname is to be fully specified (no wildcards), that means
that no :wild
, :wild-inferiors
is allowed, no
wildcard characters are allowed in the strings, and name =
nil
may not be allowed either.
External notation: | dev:sub1.typ/sub2.typ/name.typ
|
using defaults: | sub1.typ/sub2.typ/name.typ
|
or | name.typ
|
or | sub1.typ/**/sub3.typ/x*.lsp
|
or similar. |
Formal specification of the external notation:
Examples:
String | Device | Directory | our pathname |
---|---|---|---|
'c:foo'
| 'C' | device->foo
| "c" (:absolute "foo")
|
'c:foo/'
| 'C' | device->foo
| "c" (:absolute "foo")
|
'c:foo/bar'
| 'C' | device->foo ->bar
| "c" (:absolute "foo" "bar")
|
'c:/foo'
| 'C' | device->up->foo
| "c" (:absolute :parent "foo")
|
'c:'
| 'C' | device | "c" (:absolute)
|
':foo'
| current | device->root->foo
| nil (:absolute "foo")
|
'foo'
| current | device->foo
| nil (:relative "foo")
|
'/foo'
| current | device->up->foo
| nil (:relative :parent "foo")
|
'//foo/bar'
| current | device->up->up->foo ->bar
| nil (:relative :parent :parent
"foo" "bar")
|
''
| current | device | nil (:relative)
|
Appending a '/'
to a path string that is non-empty and
does not end with ':'
or '/'
does not change
its meaning. This '/'
must be appended before another
non-empty component can be appended. But appending a '/'
to a path string that is empty or ends with ':'
or
'/'
means going up to the parent directory!
We interpret any path string that is empty or ends with
':'
or '/'
as pathname of a directory (with
both name and type being
nil
).
host
nil
device
nil
directory
(startpoint . subdirs)
where
:relative
| :absolute
()
|
(subdir . subdirs)
:wild-inferiors
(means "**"
or "..."
,
all subdirectories) or
simple-string
, may contain wildcard characters
?
and *
name
nil
or
simple-string
, may contain wildcard characters
?
and *
(may also be specified as
:wild
)
type
nil
or
simple-string
, may contain wildcard characters
?
and *
(may also be specified as
:wild
)
version
nil
(may also be specified as
:wild
or :newest
)
A UNIX filename is split into name and type according to the following rule:
'.'
in the filename, then the
name is everything, type is nil
;
'.'
, then name is the part
before and type the part after the last dot.
When a pathname is to be fully specified (no wildcards), that means
that no :wild
, :wild-inferiors
is allowed, no
wildcard characters are allowed in the strings, and name =
nil
may not be allowed either.
External notation: | server:sub1.typ/sub2.typ/name.typ
|
using defaults: | sub1.typ/sub2.typ/name.typ
|
or | name.typ
|
or | sub1.typ/**/sub3.typ/x*.lsp
|
or similar. |
host
nil
device
nil
or :wild
or "A"
|...|"Z"
directory
(startpoint . subdirs)
where
:relative
| :absolute
()
|
(subdir . subdirs)
:wild-inferiors
(
means "**"
or "..."
, all
subdirectories) or
simple-string
, may contain wildcard characters
?
and *
name
nil
or
simple-string
, may contain wildcard characters
?
and *
(may also be specified as
:wild
)
type
nil
or
simple-string
, may contain wildcard characters
?
and *
(may also be specified as
:wild
)
version
nil
(may also be specified as
:wild
or :newest
)
An OS/2 filename is split into name and type according to the following rule:
'.'
in the filename, then the
name is everything, type is
nil
;
'.'
, then name is the part
before and type the part after the last dot.
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.
External notation: | A:\sub1.typ\sub2.typ\name.typ
|
using defaults: | \sub1.typ\sub2.typ\name.typ
|
or | name.typ
|
or | *:\sub1.typ\**\sub3.typ\x*.lsp
|
or similar. |
Instead of '\' one may use '/', as usual for DOS calls.
'*'
matches any sequence of
characters, '?'
matches any one character.
parse-namestring
. To get a pathname whose type
contains a dot or whose name contains a dot and whose type is
nil
,
make-pathname
must be used. Example:
(make-pathname
:name ".profile")
.
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.
$.Documents.Memos |
%.cc |
-net-$.SystemMesg |
adfs:%.aasm |
net#MJHardy::disc1.mike |
#MJHardy::disc1.mike |
-net#MJHardy-:disc1.mike |
-#MJHardy-:disc1.mike |
File$Path | for read operations |
Run$Path | for execute operations |
*Set Source$Path adfs:$.src.,adfs:$.public.src. |
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.
'$' -> | :absolute :root
|
'&' -> | :absolute :home
|
'@' -> | :absolute :current
|
'%' -> | :absolute :library
|
'\' -> | :absolute :previous
|
else | :relative
|
'^' -> | :parent
|
String | Hostname | Device | Directory | Name | Type |
---|---|---|---|---|---|
-net-$.SystemMesg
| "net"
| nil
| (:absolute :root)
| "SystemMesg"
| nil
|
net#MJHardy::disc1.mike
| "net#MJHardy"
| "disc1"
| (:absolute :root)
| "mike"
| nil
|
#MJHardy::disc1.mike
| "#MJHardy"
| "disc1"
| (:absolute :root)
| "mike"
| nil
|
-net#MJHardy-:disc1.mike
| "net#MJHardy"
| "disc1"
| (:absolute :root)
| "mike"
| nil
|
-#MJHardy-:disc1.mike
| "#MJHardy"
| "disc1"
| (:absolute :root)
| "mike"
| nil
|
@.foo
| nil
| nil
| (:absolute :current)
| "foo"
| nil
|
foo
| nil
| nil
| (:relative)
| "foo"
| nil
|
^.
| nil
| nil
| (:relative :parent)
| nil
| nil
|
@.^.
| nil
| nil
| (:absolute :current :parent)
| nil
| nil
|
foo.bar
| nil
| nil
| (:relative)
| "foo"
| "bar"
|
foo.bar.baz
| nil
| nil
| (:relative "foo")
| "bar"
| "baz"
|
foo.bar.
| nil
| nil
| (:relative "foo" "bar")
| nil
| nil
|
foo.@.
| illegal |
Hostname | Device | Directory | Name | Type | RISCOS String |
---|---|---|---|---|---|
"net"
| "disc1"
| (:absolute :root)
| "foo"
| nil
| "net::disc1.$.foo"
|
"net#MJ"
| "disc1"
| (:absolute :root "foo")
| "bar"
| "baz"
| "net#MJ::disc1.$.foo.baz.bar"
|
"adfs"
| "4"
| (:absolute :root "foo" "bar")
| nil
| nil
| "adfs::4.$.foo.bar"
|
nil
| "disc1"
| (:absolute :root "foo")
| "bar"
| nil
| ":disc1.$.foo.bar"
|
nil
| "disc1"
| (:absolute :current)
| nil
| nil
| illegal here |
nil
| "disc1"
| (:relative)
| nil
| nil
| ":disc1."
|
nil
| "disc1"
| nil
| nil
| nil
| ":disc1."
|
nil
| nil
| (:absolute :root)
| "foo"
| nil
| "$.foo"
|
nil
| nil
| (:absolute :current)
| "foo"
| nil
| "@.foo"
|
nil
| nil
| (:relative)
| "foo"
| "bar"
| "bar.foo"
|
nil
| nil
| (:relative "foo")
| "bar"
| "baz"
| "foo.baz.bar"
|
nil
| nil
| (:absolute :library)
| "bar"
| nil
| "%.bar"
|
nil
| nil
| (:absolute :library "foo")
| "bar"
| nil
| "%.foo.bar"
|
nil
| nil
| (:relative)
| "foo"
| "bar"
| "bar.foo"
|
nil
| nil
| (:relative "foo")
| "bar"
| nil
| "foo.bar"
|
nil
| nil
| (:relative "foo")
| nil
| "bar"
| illegal here |
That is, the RISCOS string is the 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)
) ) )
host
simple-string
or
nil
device
simple-string
or
nil
directory
(Startpoint . Subdirs)
where
:relative
|
:absolute
anchor
:root
| :home
|
:current
| :library
| :previous
()
|
(subdir . Subdirs)
:parent
or
simple-string
, may contain wildcard
characters ?
,#
and *
name
nil
or
simple-string
, may contain wildcard characters
?
,#
and *
(may also be specified
as :wild
)
type
nil
or
simple-string
, may contain wildcard characters
?
,#
and *
(may also be specified
as :wild
)
version
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")
.
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 character sequences of any length (consisting of
alphanumeric characters and '-'
, '_'
). They
are shortened to 8 resp. 3 characters and converted to upper case. A
single '*'
is allowed for :wild
.
[ / ] | / denotes absolute pathnames |
{ name / } | each one a subdirectory |
[ name [. type] ] | filename with type (extension) |
Name and type may be character sequences of any length (consisting of
printing ASCII characters, except '/'
).
[ [drivespec] : ] | a letter '*'|'a'|...|'z'|'a'|...|'z' |
{ name [. type] \ } | each one a subdirectory, '\' may be replaced by '/' |
[ name [. type] ] | filename with type (extension) |
Name and type may be character sequences of any length (consisting of
printing ASCII characters, except '/'
, '\'
,
':'
).
namestring
has an optional flag argument:
(namestring pathname t)
returns an external
notation suitable for passing to the operating system or other programs.
user-homedir-pathname
is not implemented.
(defun user-homedir-pathname (&optional host)
(declare (ignore host))
(or (system::getenv "HOME") "\\")
)
When the argument of the function
translate-logical-pathname
is a string, it is
interpreted as a logical pathname string.
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.
This function seems to be buggy at this time. Sorry.
(parse-namestring
string &optional
host defaults)
returns a logical pathname only if host is a logical host or host is
nil
and defaults is a logical pathname. To construct a
logical pathname from a string, the function
logical-pathname
can be used.
(merge-pathnames
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
lisp:*merge-pathnames-ansi*
: when it is
nil
, then CLISP retains its traditional behavior:
(merge-pathnames #p"x/" #p"y/")
==> #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 matters 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 lisp:*merge-pathnames-ansi*
is
nil
), but not in implementations that strictly follow the
Common Lisp spec. In fact, the above twice-default = once-default rule
holds for all pathnames in CLISP.
When lisp:*merge-pathnames-ansi*
is
non-nil
, the normal
ANSI CL behavior is exhibited:
(merge-pathnames #p"x/" #p"y/")
==> #p"y/x/"
The rationale is that "merge" is "merge" and not "or".
rename-file
always returns a non-logical pathname as
its first value.
probe-file
can not be used to check whether a directory
exists. Use the function lisp:probe-directory
or the
function
directory
for this purpose.
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 CL
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.
(lisp: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.
(directory
&optional pathname &key :full :circle)
can run in two modes:
:full
argument is non-
nil
, this contains
additional information: 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)
.
:circle
argument is
non-nil
,
the function avoids endless loops that may result from symbolic links.
(lisp:dir &optional
pathname)
is like directory
, but
displays the pathnames instead of returning
them. (lisp:dir)
shows the contents of the current
directory.
(lisp:cd [pathname])
manages the current directory.
(lisp:cd [pathname])
manages the current host, current device and the current directory.
(lisp:cd [pathname])
manages the current device and the current directory.
(lisp:cd pathname)
sets it,
(lisp:cd)
returns it.
(lisp:default-directory)
is equivalent
to (cd)
. (setf (lisp:default-directory)
pathname)
is equivalent to (cd
pathname)
, except for the return value.
(lisp:make-dir
directory-pathname)
creates a new subdirectory.
(lisp:delete-dir
directory-pathname)
removes an (empty) subdirectory.
Interactive streams are those whose next input might depend on a prompt one might output.
NO_READLINE
.
*terminal-io*
uses the GNU readline
library. Arrow keys can be used to move within the input history. The
Tab key completes the symbol's name that is being typed. See
clreadline.html or
clreadline.dvi for a complete
description of the key bindings. The GNU readline library is not used
if standard input and standard output do not both refer to the same
terminal.
*terminal-io*
is not the only stream that communicates
directly with the user: During execution of the body of a
(lisp:with-keyboard . body)
form,
lisp:*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:
:hyper
key
:F1
, ..., F10 ->
:F10
, F11 -> :F11
, F12 ->
:F12
, Insert -> :Insert
,
Delete -> :Delete
, Home ->
:Home
, End -> :End
, PgUp ->
:PgUp
, PgDn -> :PgDn
, Arrow
keys -> :Up
, :Down
,
:Left
, :Right
.
:F1
, ..., F10 ->
:F10
, F11 -> :F11
, F12 ->
:F12
, Insert -> :Insert
,
Delete -> :Delete
, Center ->
:Center
, Home -> :Home
, End
-> :End
, PgUp -> :PgUp
,
PgDn -> :PgDn
, Arrow keys ->
:Up
, :Down
, :Left
,
:Right
.
:F1
, ..., F9 ->
:F9
, F10 -> :F10
, Help ->
:Help
, Arrow keys -> :Up
,
:Down
, :Left
,
:Right
.
char
:super
:control
:meta
(lisp:with-keyboard . body)
form, no input from
*terminal-io*
or any synonymous stream should be requested.
See also (shell command)
.
The macro lisp:with-output-to-printer
:
(lisp:with-output-to-printer (var
[:external-format])
{declaration}* {form}*)
binds the variable var to an output stream that sends its
output to the printer.
(lisp:make-pipe-input-stream
command &key
:element-type
:external-format
:buffered)
(lisp:make-pipe-output-stream
command &key
:element-type
:external-format
:buffered)
(lisp:make-pipe-io-stream
command &key
:element-type
:external-format
:buffered)
read-char
,
read-char-no-hang
,
listen
instead of
read-line
and
read
on the input side, and complete every output
operation by a
finish-output
. The same cautions must apply to the
called command as well.
For all functions that accept these keywords, the acceptable values are:
:element-type
character
or
(unsigned-byte
n)
,
(signed-byte
n)
; if the
stream is to be unbuffered, n must be a multiple of 8.
:external-format
CHARSET
package, strings (denoting
iconv() based encodings), the symbol
:default
, and the line terminator
keywords :unix
, :mac
, :dos
.
The default encoding is
lisp:*default-file-encoding*
.
:buffered
nil
,
t
,
or :default
.
stream-element-type
is
setf
able. The element type of streams created by the
functions
open
,
lisp:make-pipe-input-stream
,
lisp:make-pipe-output-stream
,
lisp:make-pipe-io-stream
,
lisp:socket-accept
,
lisp:socket-connect
can be modified,
if the old and the new element type are either
character
or
(unsigned-byte
8)
or (signed-byte 8)
,
or
(unsigned-byte
n)
or
(signed-byte
n)
, with the same n.
The function
(lisp: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 element-type (unsigned-byte 8)
.
element-type should be a type equivalent to
(unsigned-byte
n)
, where n is a multiple of 8.
(lisp:read-integer stream element-type)
is like (read-byte
stream)
if stream's element type were set
to element-type, except that stream's file-position will increase
by n/8 instead of 1.
endianness can be :little
or :big
.
The default is :little
, which corresponds to the
read-byte
behavior in CLISP.
Together with (setf
stream-element-type)
, this function permits mixed
character/binary input from a stream.
The function
(lisp:read-float stream
element-type &optional endianness
eof-error-p eof-value)
reads a floating-point number in IEEE binary representation from
stream. stream should be a stream with element-type
(unsigned-byte 8)
.
element-type should be a type equivalent to
single-float
or
double-float
.
endianness can be :little
or :big
.
The default is :little
, which corresponds to the
read-byte
behavior in CLISP.
The function
(lisp:write-integer integer
stream element-type
&optional endianness)
writes a multi-byte integer to stream. stream
should be a stream with element-type (unsigned-byte 8)
.
element-type should be a type equivalent to
(unsigned-byte
n)
, where n is a multiple of 8.
(lisp:write-integer integer stream
element-type)
is like (write-byte
integer stream)
if stream's element
type were set to element-type, except that stream's
file-position will
increase by n/8 instead of 1.
endianness can be :little
or :big
.
The default is :little
, which corresponds to the
write-byte
behaviour in CLISP.
Together with (setf
stream-element-type)
, this function
permits mixed character/binary output to a stream.
The function
(lisp:write-float float
stream element-type
&optional endianness)
writes a floating-point number in IEEE binary representation to
stream. stream should be a stream with element-type
(unsigned-byte 8)
.
element-type should be a type equivalent to
single-float
or
double-float
.
endianness can be :little
or :big
.
The default is :little
, which corresponds to the
write-byte
behaviour in CLISP.
In addition to read-sequence
, the following two
functions are provided:
lisp:read-byte-sequence
performs multiple
read-byte
operations:
(lisp:read-byte-sequence sequence stream
&key :start :end)
fills the subsequence of sequence
specified by :start
and
:end
with integers consecutively read from
stream. It returns the index of the first element of
sequence that was not updated (= end or <
end if the stream reached its end).
This function is especially efficient if sequence is a
(vector (unsigned-byte 8))
and
stream is a file/pipe/socket stream with element
type (unsigned-byte
8)
.
lisp:read-char-sequence
performs multiple
read-char
operations:
(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 element type
character
or an
input
string stream.
In addition to
write-sequence
, the following two
functions are provided:
lisp:write-byte-sequence
performs multiple
write-byte
operations:
(lisp: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 element
type (unsigned-byte
8)
.
lisp:write-char-sequence
performs multiple
write-char
operations:
(lisp: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 element type
character
.
file-position
works on any buffered file stream. When
a Newline is output to resp. input from a file stream, its file
position is increased by 2 since Newline is encoded as CR/LF in the file.
open
cannot handle files of size >= 4 GB.
open
accepts three additional keywords:
:external-format
,
:element-type
, and
:buffered
.
close
ignores its :abort
argument.
input-stream-p
and
interactive-stream-p
return false for
broadcast streams.
An additional variable
lisp:*print-closure*
controls whether
compiled and interpreted functions (closures) are output in detailed
form. If lisp:*print-closure*
is
non-nil
, compiled
closures are output in #Y
syntax which the reader
understands. lisp:*print-closure*
is initially set to
nil
.
An additional variable
lisp:*print-rpars*
controls the output of
the right (closing) parentheses. If lisp:*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. lisp:*print-rpars*
is
initially set to t
.
An additional variable
lisp:*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. lisp:*print-indent-lists*
is
initially set to 2
.
*print-readably*
is true, other vectors are written as
follows: If the element-type is t
, the syntax
#(x0 ... xn-1)
is used. Otherwise, the syntax #A(element-type
dimensions contents)
is used.
*print-readably*
is true, other arrays are written as
follows: If the element-type is t
, the syntax
#rankA contents
is used. Otherwise,
the syntax #A(element-type dimensions
contents)
is used.
The functions
write
and
write-to-string
have an additional keyword
:closure
that can be used to bind
lisp:*print-closure*
.
The
format
instruction
~W
is similar to
~A
and
~S
,
but avoids binding of
*print-escape*
.
(format stream
"~W" object)
is equivalent to
(write
object :stream stream)
.
The
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.
(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 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, we print it like this
#-CLISP #P"" #+CLISP #S(PATHNAME ...)
When the variable
lisp:*print-pathnames-ansi*
is not set,
otherwise 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.lsp
and is not available if you run CLISP
without a memory image.
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 config.lsp
. This makes screen output
prettier.
*print-pretty*
is initially
nil
but set to
t
in config.lsp
. This makes unbuffered screen
output much faster.
*print-array*
is initially set to
t
.
This is the list of objects whose external representation can not be meaningfully read in:
#<type ...>
| all structures lacking a keyword constructor |
#<ARRAY type
dimensions>
| all arrays except strings, if
*print-array* 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 lisp:*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 |
#<FOREIGN-POINTER #x...>
| foreign pointer
(Platform dependent: UNIX, Win32, Amiga platforms only.) |
#<FOREIGN-ADDRESS #x...>
| foreign address
(Platform dependent: UNIX, Win32 platforms only.) |
#<FOREIGN-VARIABLE name #x...>
| foreign variable
(Platform dependent: UNIX, Win32 platforms only.) |
#<FOREIGN-FUNCTION name #x...>
| foreign function
(Platform dependent: UNIX, Win32 platforms only.) |
#<UNBOUND>
| "value" of a symbol without value, "value" of an unsupplied optional or keyword argument |
#<SPECIAL REFERENCE>
| environment marker for variables declared special
|
#<DOT>
| internal
read result for "."
|
#<END OF FILE>
| internal
read result, when the end of file is reached
|
#<READ-LABEL ...>
| intermediate
read result for #n#
|
#<ADDRESS #x...>
| machine address, should not occur |
#<SYSTEM-POINTER #x...>
| should not occur |
#\
allows inputting characters of arbitrary code:
#\Code231
yields the character
(code-char 231.)
.
#Y
is used to read compiled functions and to set the
current input stream's encoding.
#""
is used to read pathnames: #"test.lsp"
is the value of (pathname "test.lsp")
#"A:\\programs\\test.lsp"
#"\\.test.lsp"
When the value of (readtable-case readtable)
is :invert
, it applies to the package name and the symbol
name of a symbol separately (not to the entire token at once). An
alternative to the use of readtable-case
is the use of the
:case-sensitive
option to
make-package
,
in-package
and
defpackage
.
(lisp:read-char-will-hang-p
stream)
lisp: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 true.
Note the difference with the standard
listen
function:
When the end-of-stream is reached, listen
returns
nil
, whereas lisp:read-char-will-hang-p
returns
true.
Note also that lisp:read-char-will-hang-p
is not a good mean
to test for end-of-stream: If lisp: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.
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)
compiles a file to platform-independent bytecode.
:output-file
nil
or
t
or a pathname/string/symbol or an output-stream.
The default is
t
.
:listing
nil
or
t
or a pathname/string/symbol or an output-stream.
The default is
nil
.
:warnings
:verbose
:print
The variables lisp:*compile-warnings*
,
*compile-verbose*
,
*compile-print*
provide
defaults for the :warnings
, :verbose
,
:print
keyword arguments, respectively. For each input
file (default file type: #p".lsp"
) 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. |
:output-file
argument is
t
,
which means #p".fas"
.
The function
require
receives as optional argument
either a pathname or a list of pathnames: files to be loaded if the
required module is not already in memory.
load
has two additional keywords :echo
and
:compiling
.
(load filename &key :verbose :print :echo
:if-does-not-exist :compiling)
:verbose t
load
to emit a short message that a file is
being loaded. The default is
*load-verbose*
, which is
initially t
.
:print t
load
to print the value of each form. The
default is
*load-print*
, which is initially
nil
.
:echo t
*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 lisp:*load-echo*
, which is
initially nil
.
:compiling t
compile-file
- not written to a
file. The default is
lisp:*load-compiling*
,
which is initially
nil
.
The variable lisp:*load-paths*
contains
a list of directories where program files are searched - additionally to
the specified or current directory - by
load
,
require
,
compile-file
.
The variable
*features*
initially contains the symbols
:CLISP
| the name of this implementation |
---|---|
:ANSI-CL
| if invoked with -a
command line option.
|
:COMMON-LISP
| |
:CLTL2
| |
:INTERPRETER
| |
:COMPILER
| |
:LOGICAL-PATHNAMES
| |
:FFI
| if a foreign function interface is supported (Platform dependent: many UNIX, Win32 platforms only) |
:GETTEXT
| if internationalization using the GNU gettext package is supported (Platform dependent: most UNIX platforms only) |
:UNICODE
| if Unicode (ISO 10646) characters are supported |
: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) |
:PC386
| if hardware = PC (clone) with a 386/486/586/686 CPU |
:UNIX
| if operating system = Unix (yes, in this case the hardware is irrelevant!) |
The debugger may be invoked through the functions
invoke-debugger
,
break
,
signal
,
error
,
cerror
,
warn
. The stepper is invoked through the macro
step
. Debugger and stepper execute subordinate read-eval-print loops (called
"break loops") which are 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.
Commands common to the main loop, the debugger and the stepper:
Help
| prints a list of available commands. |
---|
Commands common to the debugger and the stepper:
Abort
| abort to the next most recent read-eval-print loop. |
---|---|
Unwind
| abort to the next most recent read-eval-print loop. |
The stack is organized into frames and other stack elements. Usually
every invocation of an interpreted function and every evaluation of an
interpreted form corresponds to one stack frame. Special forms such as
let
,
let*
,
unwind-protect
and
catch
produce special kinds of stack frames.
In a break loop there is a current stack frame, which is initially
the most recent stack frame but can be moved using the debugger commands
Up
and Down
.
Evaluation of forms in a break loop occurs in the lexical environment of the current stack frame but in the dynamic environment of the debugger's caller. This means that to inspect or modify a lexical variable all you have to do is to move to the current stack frame just below the frame that corresponds to the form or the function call that binds that variable.
There is a current "stack mode" which defines in how much detail the stack is shown by the stack related debugger commands.
Commands common to the debugger and the stepper:
Mode-1
| sets the current mode to 1: all the stack elements are considered. This mode is fine for debugging compiled functions. |
---|---|
Mode-2
| sets the current mode to 2: all the frames are considered. |
Mode-3
| sets the current mode to 3: only lexical frames (frames that correspond to special forms that modify the lexical environment) are considered. |
Mode-4
| sets the current mode to 4 (the default): only eval
and apply frames are considered. Every evaluation
of a form in the interpreter corresponds to an EVAL frame.
|
Mode-5
| sets the current mode to 5: only apply frames are
considered. Every invocation of an interpreted function
corresponds to one apply frame.
|
Where
| shows the current stack frame. |
Up
| goes up one frame, i.e., to the caller if in mode-5 |
Down
| does down one frame, i.e., to the callee if in mode-5 |
Top
| goes to top frame, i.e., to the top-level form if in mode-4 |
Bottom
| goes to bottom (most recent) frame, i.e., most probably to the form or function that caused the debugger to be entered. |
Backtrace
| lists the stack in current mode, bottom frame first, top frame last. |
Backtrace-1
| lists the stack in mode 1. |
Backtrace-2
| lists the stack in mode 2. |
Backtrace-3
| lists the stack in mode 3. |
Backtrace-4
| lists the stack in mode 4. |
Backtrace-5
| lists the stack in mode 5. |
If the current stack frame is an
eval
or
apply
frame, the following commands are available as well:
Break+
| sets a breakpoint in the current frame. When the corresponding
form or function will be left, the debugger will be entered again,
with the variable *trace-values* containing a list of
its values.
|
---|---|
Break-
| removes a breakpoint from the current frame. |
Redo
| re-evaluates the corresponding form or function call. This command can be used to restart parts of a computation without aborting it entirely. |
Return
| leaves the current frame. You will be prompted for the return values. |
Commands specific to the debugger:
Continue
| continues evaluation of the program. |
---|
Commands specific to the stepper:
Step
| step into a form: evaluate this form in single step mode |
---|---|
Next
| step over a form: evaluate this form at once |
Over
| step over this level: evaluate at once up to the next return |
Continue
| switch off single step mode, continue evaluation |
The stepper is usually used like this: If some form returns a strange
value or results in an error, call (step form)
and
navigate using the commands Step
and Next
until you reach the form you regard as responsible. If you are too fast
(execute Next
once and get the error), there is no way
back; you have to restart the entire stepper session. If you are too
slow (stepped into a function or a form which certainly is OK), a couple
of Next
commands or one Over
command will help.
disassemble
can disassemble to machine
code, provided that GNU gdb is present. In that case the argument may
be a system-function
, a foreign-function
, a
special operator indicator, a symbol denoting one of these, a number, or a
string.
The function uncompile
does the
converse of compile
: (uncompile
function-name)
reverts an interpreted function that
has been entered or loaded in the same session and then compiled back to
its interpreted form.
No on-line documentation is available for the system functions (yet).
(trace fun ...)
makes the functions
fun, ... traced. Syntax of fun: Either a symbol:
symbol or a list of a symbol and some keywords and arguments
(which must come in pairs!):
(symbol
[:suppress-if form]
| no trace output as long as form is true |
[:step-if form]
| invokes the stepper as soon as form is true |
[:pre form]
| evaluates form before calling the function |
[:post form]
| evaluates form after return from the function |
[:pre-break-if form]
| goes into the break loop before calling the function if form is true |
[:post-break-if form]
| goes into the break loop after return from the function if form is true |
[:pre-print form]
| prints the values of form before calling the function |
[:post-print form]
| prints the values of form after return from the function |
[:print form]
| prints the values of form both before calling and after return from the function |
)
In all these forms you can access
the function itself | as lisp:*trace-function* ,
|
the arguments to the function | as lisp:*trace-args* ,
|
the function/macro call as form | as lisp:*trace-form* ,
|
after return from the function: the list of return values from the function call | as lisp:*trace-values* ,
|
return
.
trace
and
untrace
are also applicable to functions (setf
symbol)
and to macros, but not to locally defined
functions and macros.
The function
inspect
is not built in. Two implementations
are available as add-ons from the
ftp://clisp.cons.org/pub/lisp/clisp/contrib/ directory.)
The macro lisp:space
is like the macro
time
: (lisp:space form)
evaluates the form, and, as a side effect, outputs
information about the memory allocations caused by this evaluation. It
also prints everything printed by time
.
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 lisp:gc
starts 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 (elapsed time), the run
time (processor time for this process), the number of bytes allocated
(use the lisp:space
macro for more
detailed analysis), and the number of GCs performed, if any.
The function
ed
calls the external
editor specified by the variable
lisp:*editor*
(see
config.lsp
). 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.
lisp:*default-time-zone*
contains the default time zone used by
encode-universal-time
and
decode-universal-time
. It is initially set to -1 (which
means 1 hour east of Greenwich, i.e., Mid European Time).
The timezone in a decoded time must not necessarily be an integer,
but (as float or rational number) it should be a multiple of
1/3600
.
Platform dependent: | DOS, OS/2, Acorn | 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.
short-site-name
,
long-site-name
should be defined in a site-specific
config.lsp
file.
machine-type
,
machine-version
,
machine-instance
and
short-site-name
,
long-site-name
should be defined by every user in his
site-specific config.lsp
file.
apropos
and
apropos-list
is case-insensitive.
dribble
is called with an argument, and dribbling is
already enabled, a warning is printed, and the new dribbling request is
ignored.
No notes.
No notes.
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.
call-next-method
in compiled code (items 11,12)
*print-readably*
,
*read-eval*
and
with-standard-io-syntax
, no for everything else
equalp
on hash tables,
yes for everything else
load
:compiling
t
~F
,
~E
,
~G
,
~$
also bind
*print-base*
to 10
and
*print-radix*
to
nil
the
, no for
apply
(spec not clear)
lisp:*sequence-count-ansi*
is non-nil
;
otherwise negative :count
values are not allowed.
read-delimited-list
still constructs a list
require
wants a pathname, not a list of pathnames
method-combination
The function (lisp:saveinitmem
&optional (filename "lispinit.mem")
&key :quiet :init-function)
saves the running CLISP's memory to a file. If the :quiet
argument is not
nil
, the startup banner and the good-bye message will
be suppressed. The :init-function
argument specifies a
function that will be executed at startup of the saved image. The
starting package of the new image is the one in which you were when you
invoked lisp:saveinitmem
.
The functions (lisp:exit
[errorp])
, (lisp:quit
[errorp])
and (lisp:bye
[errorp])
- all synonymous - terminate CLISP. If
errorp is not
nil
, CLISP aborts with error status, i.e., the
environment is informed that the CLISP session did not succeed.
The language CLISP uses to communicate with the user can be either
ENGLISH
or DEUTSCH
(i.e., German) or
FRANCAIS
(i.e., French) or ESPAÑOL
(i.e.
Spanish). More languages can be defined through the macro
lisp:deflanguage
: (lisp:deflanguage
lang)
For such an additional language to take effect,
you must install the corresponding message catalog, or translate the
messages yourself, using GNU gettext and Emacs po-mode.
The macros ENGLISH
, DEUTSCH
,
FRANCAIS
produce strings that depends on the language:
(ENGLISH english-string DEUTSCH
deutsch-string FRANCAIS francais-string)
-
and all permutations of this - evaluates all of
english-string, deutsch-string,
francais-string in no particular order and returns the
evaluation result corresponding to the user language, be it among these
three or not.
This works only for strings. For arbitrary language-dependent Lisp objects,
you define one through the macro
lisp:definternational
:
(lisp:definternational symbol &optional (t default-language))
and add language-dependent values through the macro
lisp:deflocalized
:
(lisp:deflocalized symbol language value-form)
(One such form for each language. Languages without an assigned
value will be treated like the default-language.) You can then access
the localized value through the function call
(lisp:localized symbol &optional language)
An encoding describes the correspondence between characters and
raw bytes during input/output via streams with element-type
character
.
An encoding is an object composed of the following facets:
UNICODE
.
UNICODE
.
CHARSET
package.
UCS-2
= UNICODE-16
= UNICODE-16-BIG-ENDIAN
,
the 16-bit Unicode character set. Every character is represented as
two bytes.
UNICODE-16-LITTLE-ENDIAN
UCS-4
= UNICODE-32
= UNICODE-32-BIG-ENDIAN
,
the 32-bit Unicode character set. Every character is represented as
four bytes. Note that CLISP understands only those characters which
are already contained in the 16-bit Unicode character set.
UNICODE-32-LITTLE-ENDIAN
UTF-8
,
the 16-bit Unicode character set. Every character is represented as
one to three bytes. ASCII characters represent themselves and need
one byte per character. Most Latin/Greek/Cyrillic/Hebrew characters
need two bytes per character, and the remaining characters need three
bytes per character. This is therefore, in general, the most
space-efficient encoding of all of Unicode-16.
UTF-16
,
the 16-bit Unicode character set. Every character is represented as
two bytes.
UTF-7
,
the 16-bit Unicode character set. This is a stateful 7-bit encoding.
Not all ASCII characters represent themselves.
JAVA
,
the 16-bit Unicode character set. ASCII characters represent themselves
and need one byte per character. All other characters are represented
by \unnnn sequences (nnnn a hexadecimal number)
and need 6 bytes per character. While this encoding is very comfortable
for editing Unicode files using only ASCII aware tools and editors, it
cannot faithfully represent all Unicode text. Only text which does not
contain \u (backslash followed by lowercase Latin u) can be faithfully
represented by this encoding.
ASCII
,
the well-known US-centric 7-bit character set (American Standard
Code for Information Interchange).
ISO-8859-1
,
an extension of the ASCII character set, suitable for the
Afrikaans, Albanian, Basque, Breton, Catalan, Cornish, Danish, Dutch,
English, Faeroese, Finnish, French, Frisian, Galician, German,
Greenlandic, Icelandic, Irish, Italian, Latin, Luxemburgish, Norwegian,
Portuguese, Raeto-Romanic, Scottish, Spanish, and Swedish languages.
ISO-8859-2
,
an extension of the ASCII character set, suitable for the Croatian,
Czech, German, Hungarian, Polish, Slovak, Slovenian, and Sorbian
languages.
ISO-8859-3
,
an extension of the ASCII character set, suitable for the
Esperanto and Maltese languages.
ISO-8859-4
,
an extension of the ASCII character set, suitable for the
Estonian, Latvian, Lithuanian and Sami (Lappish) languages.
ISO-8859-5
,
an extension of the ASCII character set, suitable for the Bulgarian,
Byelorussian, Macedonian, Russian, Serbian, and Ukrainian languages.
ISO-8859-6
,
suitable for the Arabic language.
ISO-8859-7
,
an extension of the ASCII character set, suitable for the Greek
language.
ISO-8859-8
,
an extension of the ASCII character set, suitable for the Hebrew
language (without punctuation).
ISO-8859-9
,
an extension of the ASCII character set, suitable for the Turkish
language.
ISO-8859-10
,
an extension of the ASCII character set, suitable for the Estonian,
Icelandic, Inuit (Greenlandic), Latvian, Lithuanian, and Sami (Lappish)
languages.
ISO-8859-13
,
an extension of the ASCII character set, suitable for the Estonian,
Latvian, Lithuanian, Polish and Sami (Lappish) languages.
ISO-8859-14
,
an extension of the ASCII character set, suitable for Irish Gaelic,
Manx Gaelic, Scottish Gaelic, and Welsh languages.
ISO-8859-15
,
an extension of the ASCII character set, suitable for the ISO-8859-1
languages, with improvements for French, Finnish and the Euro.
ISO-8859-16
an extension of the ASCII character set, suitable for the Rumanian
language.
KOI8-R
,
an extension of the ASCII character set,
a popular character set for the Russian language.
KOI8-U
,
an extension of the ASCII character set,
a popular character set for the Ukrainian language.
KOI8-RU
,
an extension of the ASCII character set, suitable for Russian and/or
Ukrainian??
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,
meant to be suitable for the Hebrew language.
WINDOWS-1256
= CP1256
,
a platform specific extension of the ASCII character set,
meant to be suitable for the Arabic language.
WINDOWS-1257
= CP1257
,
a platform specific extension of the ASCII character set.
WINDOWS-1258
= CP1258
,
a platform specific extension of the ASCII character set.
HP-ROMAN8
,
a platform specific extension of the ASCII character set.
NEXTSTEP
,
a platform specific extension of the ASCII character set.
EUC-JP
,
a multibyte character set for the Japanese language.
SHIFT-JIS
,
a multibyte character set for the Japanese language.
CP932
,
a Microsoft variant of SHIFT-JIS
.
ISO-2022-JP
,
a stateful 7-bit multibyte character set for the Japanese language.
ISO-2022-JP-2
,
a stateful 7-bit multibyte character set for the Japanese language.
ISO-2022-JP-1
,
a stateful 7-bit multibyte character set for the Japanese language.
EUC-CN
,
a multibyte character set for simplified Chinese.
HZ
,
a stateful 7-bit multibyte character set for simplified Chinese.
GBK
,
a multibyte character set for Chinese,
CP936
,
a Microsoft variant of GBK
.
EUC-TW
,
a multibyte character set for traditional Chinese.
BIG5
,
a multibyte character set for traditional Chinese.
CP950
,
a Microsoft variant of BIG5
.
ISO-2022-CN
,
a stateful 7-bit multibyte character set for Chinese.
ISO-2022-CN-EXT
,
a stateful 7-bit multibyte character set for Chinese.
EUC-KR
,
a multibyte character set for Korean.
CP949
,
a Microsoft variant of EUC-KR
.
ISO-2022-KR
,
a stateful 7-bit multibyte character set for Korean.
ARMSCII-8
,
an extension of the ASCII character set, suitable for Armenian.
GEORGIAN-ACADEMY
,
an extension of the ASCII character set, suitable for Georgian.
GEORGIAN-PS
,
an extension of the ASCII character set, suitable for Georgian.
TIS-620
,
an extension of the ASCII character set, suitable for Thai.
MULELAO-1
,
an extension of the ASCII character set, suitable for Laotian.
CP1133
,
an extension of the ASCII character set, suitable for Laotian.
VISCII
,
an extension of the ASCII character set, suitable for Vietnamese.
TCVN
,
an extension of the ASCII character set, suitable for Vietnamese.
The line terminator mode can be one of the following three keywords:
:unix
| Newline is represented by the ASCII LF character (U000A). |
---|---|
:mac
| Newline is represented by the ASCII CR character (U000D). |
:dos
| Newline is represented by ASCII CR followed by ASCII LF. |
: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 or 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 (lisp:make-encoding &key
:charset :line-terminator
:input-error-action :output-error-action)
returns an encoding. The :charset
argument may be an
encoding, a string, or :default
. The possible values for
the :line-terminator
argument are the keywords
:unix
, :mac
, :dos
.
The :input-error-action
specifies what happens when an
invalid byte sequence is encountered while converting bytes to characters.
Its value can be :error
, :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
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.
Encodings are types. As such, they represent the set of characters
encodable in the character set. In this context, the way characters are
translated into raw bytes is ignored, and the line terminator mode is
ignored as well. typep
and subtypep
can
be used on encodings.
Besides every file/pipe/socket stream containing an encoding, the following symbol-macro places contain global encodings:
lisp:*default-file-encoding*
is the
encoding used for new file/pipe/socket streams, when no
:external-format
argument was
specified.
UNICODE
.
lisp:*pathname-encoding*
lisp:*terminal-encoding*
*terminal-io*
.
lisp:*misc-encoding*
Two mechanisms are supported for creating new streams with user-defined behavior:
lisp:fundamental-stream
and define methods for the elementary stream operations on it.
These generic functions all have a name starting with the prefix
"stream-".
lisp:generic-stream-controller
and define methods for the elementary stream operations on it.
These generic functions all have a name starting with the prefix
"generic-stream-". The stream itself is a different object, created
using the function lisp:make-generic-stream
.
The fundamental-stream
API is based on a proposal by
David N Gray and is supported by most Common Lisp implementations
currently in use. The generic-stream-controller
API is
CLISP specific and is now obsolete.
This interface permits the definition of new classes of streams, and to program their behavior by defining methods for the elementary stream operations. It is based on a proposal of David N Gray to X3J13, available from ftp://parcftp.xerox.com/pub/cl/cleanup/mail/stream-definition-by-user.mail.
All symbols defined by this interface, starting with the prefix "fundamental-" or "stream-", are exported from the package "LISP".
The following classes are defined.
fundamental-stream
stream
and of
standard-object
. Its metaclass is
standard-class
.
fundamental-input-stream
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
fundamental-input-stream
.
fundamental-output-stream
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
fundamental-output-stream
.
fundamental-character-stream
character
. It is a subclass of
fundamental-stream
. It defines a method on
stream-element-type
that returns
character
.
fundamental-binary-stream
integer
. It is a subclass of
fundamental-stream
. When you define a subclass of
fundamental-binary-stream
, you have to provide a
method on
stream-element-type
.
fundamental-character-input-stream
fundamental-character-stream
and
fundamental-input-stream
.
fundamental-character-output-stream
fundamental-character-stream
and
fundamental-output-stream
.
fundamental-binary-input-stream
fundamental-binary-stream
and
fundamental-input-stream
.
fundamental-binary-output-stream
fundamental-binary-stream
and
fundamental-output-stream
.
The following are general generic functions defined on streams.
(stream-element-type
stream)
character
or
integer
.
fundamental-character-stream
returns
character
.
((setf stream-element-type)
new-element-type stream)
(close
stream &key :abort)
(call-next-method)
.
(open-stream-p
stream)
nil
after the stream has been closed.
The following are generic functions for character input.
(stream-read-char stream)
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.
(stream-unread-char
stream character)
(stream-read-char-no-hang
stream)
:eof
, like
stream-read-char
, if that would return immediately. If
stream-read-char
's value is not available immediately,
returns nil
instead of waiting.
stream-read-char
;
this is sufficient for streams whose stream-read-char
method never blocks.
(stream-peek-char stream)
stream-unread-char
,
returns it. Otherwise returns the next character from the stream,
avoiding any side effects stream-read-char
would do.
Returns :eof
if the end-of-stream is reached.
stream-read-char
and
stream-unread-char
; this is sufficient for streams
whose stream-read-char
method has no side-effects.
(stream-listen stream)
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
.
stream-read-char-no-hang
and stream-unread-char
; this is sufficient for streams
whose stream-read-char
method has no side-effects.
(stream-read-char-will-hang-p
stream)
nil
if stream-read-char
will return immediately. Otherwise
it returns true.
stream-read-char-no-hang
and stream-unread-char
; this is sufficient for streams
whose stream-read-char
method has no side-effects.
(stream-read-char-sequence stream
sequence &optional
[start [end]])
: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).
nil
and
defaults to nil
, which stands for
(length
sequence)
.
stream-read-char
;
this is always sufficient if speed does not matter.
(stream-read-line stream)
#\Newline
character), and a
boolean value which is true if the line was terminated by end-of-stream
instead of #\Newline
.
stream-read-char
;
this is always sufficient.
(stream-clear-input stream)
nil
; this
is sufficient for non-interactive streams.
(stream-write-char
stream character)
(stream-line-column stream)
nil
if
that is not meaningful for this stream.
(stream-start-line-p stream)
stream-line-column
and
compares its result with 0; this is sufficient for streams whose
stream-line-column
never returns
nil
.
(stream-write-char-sequence stream
sequence &optional
[start [end]])
:start
and :end
to
stream.
nil
and
defaults to nil
, which stands for
(length
sequence)
.
stream-write-char
;
this is always sufficient if speed does not matter.
(stream-write-string stream
string &optional
[start [end]])
:start
and :end
to
stream. Returns string.
nil
and
defaults to nil
, which stands for
(length
string)
.
stream-write-char-sequence
;
this is always sufficient.
(stream-terpri stream)
#\Newline
character.
stream-write-char
;
this is always sufficient.
(stream-fresh-line stream)
#\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.
stream-start-line-p
and
then stream-terpri
if necessary; this is always
sufficient.
(stream-finish-output stream)
(stream-force-output stream)
(stream-clear-output stream)
(stream-advance-to-column
stream column)
(stream-read-byte stream)
:eof
if the end-of-stream is reached.
(stream-read-byte-sequence stream
sequence &optional
[start [end]])
: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).
nil
and
defaults to nil
, which stands for
(length
sequence)
.
stream-read-byte
;
this is always sufficient if speed does not matter.
(stream-write-byte
stream integer)
(stream-write-byte-sequence stream
sequence &optional
[start [end]])
:start
and :end
to
stream.
nil
and
defaults to nil
, which stands for
(length
sequence)
.
stream-write-byte
;
this is always sufficient if speed does not matter.
This interface is CLISP specific and now obsolete. Please use the Gray streams interface instead.
Generic streams are user programmable streams. The programmer interface:
(lisp:make-generic-stream
controller)
(lisp:generic-stream-controller
stream)
lisp:make-generic-stream
.
(lisp:generic-stream-p
stream)
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 generic-stream-xyz
corresponds to the
Common Lisp function xyz
. They all take a
controller and some number of arguments.
(lisp:generic-stream-read-char
controller)
nil
at
end of file. Takes one argument, the controller object.
(lisp:generic-stream-peek-char
controller)
nil
at end of file. A
second value indicates whether the side effects associated with
consuming the character were executed:
t
means that a full
read-char
was done,
nil
means that no side effects were done. Takes one
argument, the controller object.
(lisp:generic-stream-read-byte
controller)
nil
at end of file.
Takes one argument, the controller object.
(lisp:generic-stream-read-char-will-hang-p
controller)
nil
if lisp:generic-stream-read-char
and
lisp:generic-stream-peek-char
will certainly return
immediately. Otherwise it returns true.
(lisp:generic-stream-write-char
controller ch)
(lisp:generic-stream-write-byte
controller by)
(lisp:generic-stream-write-string
controller string start
len)
(controller
string start len)
, this
function shall write (subseq (the string string)
start (+ start len))
First argument is the controller object.
(lisp:generic-stream-clear-input
controller)
(lisp:generic-stream-clear-output
controller)
(lisp:generic-stream-finish-output
controller)
(lisp:generic-stream-force-output
controller)
(lisp:generic-stream-close
controller)
A weak pointer is an object holding a reference to a given object, without keeping the latter from being garbage-collected.
(lisp:make-weak-pointer value)
returns a fresh weak pointer referring to value.
(lisp:weak-pointer-p object)
returns true if the object is of type
weak-pointer
.
(lisp:weak-pointer-value
weak-pointer)
returns two values: The original value
and
t
, if the value has not yet been garbage collected,
else
nil
and
nil
.
Calling (lisp:finalize object
function)
has the effect that when the specified
object is being garbage collected, (funcall function
object)
will be executed.
Calling (lisp: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 possibly never occurs.) It denotes a moment at which no references to object exist from other Lisp objects. When the function is called, object (and possibly guardian) enter the "arena of live Lisp objects" again.
No finalization request will be executed more than once.
The variable sys::*prompt*
controls the
appearance of the prompt. When its value is a function, it is called
and its value is printed with
princ
. Otherwise, the value itself is printed with
princ
. The default value of sys::*prompt*
prints "package[nn]> " where
package is the shortest (nick)name of the current package *package*
if it
is the same as it was in the beginning or if it does not contain symbol
t
(it is assumed that in the latter case you would want to
keep in mind that your current package is something weird); and
nn is the ordinal number of the current prompt (hopefully, it
will remain finite). To help you in constructing your own fancy
prompts, two functions are provided:
sys::prompt-new-package
, returning *package*
or
nil
if the current package is the same as it was initially;
and sys::package-short-name
taking one
argument, a package, and returning its shortest name or nickname. Also,
a variable sys::*command-index*
contains
the current prompt number, it is your responsibility to increment it
(this variable is bound to 0 before saving the image).
lisp:*ansi*
to
t
,
or they can be switched on individually. Setting
lisp:*ansi*
to
t
implies the following:
lisp:*print-pathnames-ansi*
to
t
for ANSI
CL compliant
pathname
printing.
lisp:*coerce-fixnum-char-ansi*
to
t
so that
fixnum
s cannot be
coerce
d to
character
s (because a
fixnum
is not a
character designator in ANSI CL.)
lisp:*sequence-count-ansi*
to
t
so that
negative :count
keyword parameter is equivalent to
0 as per the
RANGE-OF-COUNT-KEYWORD:NIL-OR-INTEGER ANSI CL Issue 283.
lisp:*merge-pathnames-ansi*
to t
.
lisp:*floating-point-contagion-ansi*
to t
.
:ansi-cl
to
*features*
.
lisp:*ansi*
to
t
and save image, then all subsequent invocations
of CLISP with this image will be as if with -a
(regardless whether you actually supply the -a
switch). You can always set the
symbol-macro lisp:*ansi*
to
nil
, reversing the above settings, i.e.,
lisp:*print-pathnames-ansi*
to
nil
for
readable
pathname
printing.
lisp:*coerce-fixnum-char-ansi*
to
nil
so that
fixnum
s can be
coerce
d to
character
s
(via
code-char
).
lisp:*sequence-count-ansi*
to
nil
to
signal an error on negative :count
keyword parameter,
contrary to the
RANGE-OF-COUNT-KEYWORD:NIL-OR-INTEGER ANSI CL Issue 283.
lisp:*merge-pathnames-ansi*
to nil
.
lisp:*floating-point-contagion-ansi*
to nil
.
:ansi-cl
from
*features*
.
If you uncomment the (load "macros3")
line in the file
"init.lsp"
before doing make
, or load the file
"macros3"
into a running CLISP, you get access to the
following macros:
lisp:ethe
(lisp:ethe value-type form)
enforces a type check in both interpreted and compiled code.
lisp:letf
and
lisp:letf*
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)))
lisp:with-collect
loop
's collect
instruction, except that
it is more "Lispy" in appearance and can appear arbitrarily deep. It
defines local macros (with
macrolet
) which collect objects given to it in
lists, which are then returned as multiple values. E.g.,
(lisp:with-collect (c0 c1)
(dotimes (i 10) (if (oddp i) (c0 i) (c1 i))))
returns two lists (1 3 5 7 9)
and (0 2 4 6 8)
as multiple values.
You might want to add a (load "macros3")
statement to
your ".clisprc"
file if
you do not want to dump your own image.
(screen:make-window)
*terminal-io*
should not be used for input or output
during this time. (Use lisp:with-keyboard
and
lisp:*keyboard-input*
instead.)
(screen:with-window . body)
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.
(screen:window-size
window-stream)
(screen:window-cursor-position
window-stream)
(screen:set-window-cursor-position
window-stream line column)
(screen:clear-window
window-stream)
(screen:clear-window-to-eot
window-stream)
(screen:clear-window-to-eol
window-stream)
(screen:delete-window-line
window-stream)
(screen:insert-window-line
window-stream)
(screen:highlight-on
window-stream)
(screen:highlight-off
window-stream)
(screen:window-cursor-on
window-stream)
(screen:window-cursor-off
window-stream)
CLISP has a facility for adding external modules (written in C, for
example). It is invoked through clisp-link
.
A module is a piece of external code which defines extra Lisp
objects, symbols and functions. A module name must consist of the
characters A-Z,a-z,_,0-9. The module name "clisp"
is reserved. Normally a module name is derived from the corresponding
file name.
clisp-link
needs a directory containing:
modules.d
|
---|
modules.c
|
clisp.h
|
clisp-link
expects to find these files in a subdirectory
linkkit/
of the current directory. This can be overridden
by the environment variable CLISP_LINKKIT
.
clisp-link
operates on CLISP linking sets and on module sets.
A linking set is a directory containing:
makevars
/bin/sh
commands, setting the variables
CC
CFLAGS
CLFLAGS
LIBS
X_LIBS
RANLIB
FILES
modules.h
modules.o
FILES
listed in makevars
lisp.run
lispinit.mem
To run a clisp contained in some linking set dir, call
"dir/lisp.run -M
dir/lispinit.mem
".
A module set is a directory containing:
link.sh
/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
link.sh
.
Note that in link.sh
the module set directory is
referred to as "$modulename"/
.
NEW_FILES
variable NEW_LIBS
variable NEW_MODULES
variable .c
file in the module set defines a
module of its own. The module name is derived from the file name.
TO_LOAD
variable lispinit.mem
belonging to a new linking set.
TO_PRELOAD
variable, if defined, lispinit.mem
file, before building the
lispinit.mem
belonging to a new linking set. This
variable is usually used for defining Lisp packages which must be
present when the new .c
files are initialized.
The command "clisp-link create-module-set
module-dir file1.c ...
" creates a
module set in module-dir which refers (via symbolic links) to
file1.c
etc. The files are expected to be
modules of their own.
The command "clisp-link add-module-set
module-dir source-dir
destination-dir
" combines a linking set in
source-dir and a module in module-dir to a new
linking set, in a directory destination-dir which is newly
created.
The command "clisp-link run source-dir
module-dir ..." runs the linking set in
source-dir, with the module in module-dir loaded.
More than one module can be specified. If CLISP has been built with the
configuration option --with-dynamic-modules
, the loading
will be performed through dynamic loading. Otherwise -- this is much
slower -- a temporary linking set will be created and deleted
afterwards. Note that dynamic loading does not work on all operating
systems, and that --with-dynamic-modules
precludes some
efficiency optimizations which are on by default.
To link in the FFI bindings for the Linux operating system, the following steps are needed. (Step 1 and step 2 need not be executed in this order.)
$ clisp-link create-module-set linux /somewhere/bindings/linux.c
Modify the newly created linux/link.sh
to add "-lm
" to the libraries:
NEW_LIBS="$file_list"
-->
NEW_LIBS="$file_list -lm"
Modify the newly created linux/link.sh
to load linux.fas
before saving
the memory image:
TO_LOAD=''
-->
TO_LOAD='/somewhere/bindings/linux.fas'
linux.lsp
, creating linux.c
:
$ clisp -c /somewhere/bindings/linux.lsp
$ clisp-link add-module-set linux base base+linux
$ base+linux/lisp.run -M base+linux/lispinit.mem
> (linux::stat "/tmp")
The following modules come with the distribution of
CLISP
:
CLISP
. The
following platforms are supported:
CLISP
. Two implementations
are supplied:
CLISP
.
The following code computes the number of people who use a particular shell:
(use-package :regexp)
(let ((h (make-hash-table :test #'equal :size 10)) (n 0))
(with-open-file (f "/etc/passwd")
(with-loop-split (s f ":")
(let ((sh (seventh s)))
(if (gethash sh h)
(incf (gethash sh h))
(setf (gethash sh h) 1)))))
(with-hash-table-iterator (i h)
(loop (multiple-value-bind (r k v) (i)
(unless r (return))
(format t "[~d] ~s~30t== ~5:d~%" (incf n) k v)))))
The same is done by the following Perl:
#!/usr/local/bin/perl -w
use diagnostics;
use strict;
my $IN = $ARGV[0];
open(INF,"< $IN") || die "$0: cannot read file [$IN]: $!\n;";
my %hash;
while (<INF>) {
chop;
my @all = split($ARGV[1]);
my $shell = ($#all >= 6 ? $all[6] : "");
if ($hash{$shell}) { $hash{$shell} ++; }
else { $hash{$shell} = 1; }
}
my $ii = 0;
for my $kk (keys(%hash)) {
print "[",++$ii,"] \"",$kk,"\" -- ",$hash{$kk},"\n";
}
A foreign function description is written as a Lisp file, and when
compiled it produces a .c
file which is then compiled by
the C compiler and may be linked together with lisp.a
.
All symbols relating to the foreign function interface are exported
from the package FFI. To use them,
(use-package
"FFI")
.
Special FFI forms may appear anywhere in the Lisp file.
These are the special FFI forms. We have taken a pragmatic approach: the only foreign languages we support for now are C and ANSI C.
(def-c-type name
c-type)
(def-c-var name
{option}*)
option ::= | |
(:name c-name)
| |
| | (:type c-type)
|
| | (:read-only boolean)
|
| | (:alloc allocation)
|
(def-call-out name
{option}*)
option ::= | |
(:name c-name)
| |
| | (:arguments {(arg-name
c-type [param-mode
[allocation]])}*)
|
| | (:return-type c-type
[allocation])
|
| | (:language language)
|
(def-call-in name
{option}*)
option ::= | |
(:name c-name)
| |
| | (:arguments {(arg-name
c-type [param-mode
[allocation]])}*)
|
| | (:return-type c-type
[allocation])
|
| | (:language language)
|
(def-c-call-out name
{option}*)
option ::= | |
(:name c-name)
| |
| | (:arguments {(arg-name
c-type [param-mode
[allocation]])}*)
|
| | (:return-type c-type
[allocation])
|
(def-c-call-in name
{option}*)
option ::= | |
(:name c-name)
| |
| | (:arguments {(arg-name c-type [param-mode [allocation]])}*)
|
| | (:return-type c-type [allocation])
|
(def-c-struct name
(ident c-type)*)
(def-c-enum name {ident
| (ident [value])}*)
(c-lines format-string
{argument}*)
(element c-place
{index}*)
(deref c-place)
(slot c-place slot-name)
(cast c-place c-type)
(typeof c-place)
(sizeof c-place)
, (sizeof
c-type)
(bitsizeof c-place)
,
(bitsizeof c-type)
(validp foreign-entity)
name is any Lisp symbol.
c-name is a string.
Foreign C types are used in the FFI. They are not regular Common Lisp types or CLOS classes.
A c-type is either a predefined C type or the name of a
type defined by def-c-type
.
The simple C types are these:
Lisp name | Lisp equiv | C equiv | ILU equiv | Comment |
---|---|---|---|---|
nil
| nil
| void
| as a result type only | |
boolean
| boolean
| int
| BOOLEAN
| |
character
|
character
| char
| SHORT CHARACTER
| |
char
| integer
| signed char
| ||
uchar
| integer
| unsigned char
| ||
short
| integer
| short
| ||
ushort
| integer
| unsigned short
| ||
int
| integer
| int
| ||
uint
| integer
| unsigned int
| ||
long
| integer
| long
| ||
ulong
| integer
| unsigned long
| ||
uint8
| (unsigned-byte
8)
| uint8
| BYTE
| |
sint8
| (signed-byte
8)
| sint8
| ||
uint16
| (unsigned-byte
16)
| uint16
| SHORT CARDINAL
| |
sint16
| (signed-byte
16)
| sint16
| SHORT INTEGER
| |
uint32
| (unsigned-byte
32)
| uint32
| CARDINAL
| |
sint32
| (signed-byte
32)
| sint32
| INTEGER
| |
uint64
| (unsigned-byte
64)
| uint64
| LONG CARDINAL
| does not work on all platforms |
sint64
| (signed-byte
64)
| sint64
| LONG INTEGER
| does not work on all platforms |
single-float
|
single-float
| float
| ||
double-float
|
double-float
| double
|
The predefined C types are:
c-type ::= | |
simple-c-type | |
| | c-pointer
|
| | c-string
|
| | (c-struct class
(ident c-type)*)
|
| | (c-union (ident
c-type)*)
|
| | (c-array c-type
dimensions)
dimensions ::= number | ({number}*)
|
| | (c-array-max c-type
maxdimension)
maxdimension ::= number |
| | (c-function
{option}*)
option ::= (:arguments {(arg-name
c-type [param-mode
[allocation]])}*)
| (:return-type c-type
[allocation])
| (:language language)
|
| | (c-ptr c-type)
|
| | (c-ptr-null c-type)
|
| | (c-array-ptr c-type)
|
(def-c-type name
c-type)
makes name a shortcut for
c-type. Note that c-type may already refer to
name. Forward declarations of types are not possible, however.
The type c-pointer
corresponds to what C calls
"void*
", an opaque pointer.
The type c-string
corresponds to what C calls
"char*
", a zero-terminated string. Its Lisp
equivalent is a string, without the trailing zero character.
The type (c-struct class
(ident1 type1)
... (identn typen))
is equivalent to what C calls "struct {
type1 ident1; ...;
typen identn;
}
". Its Lisp equivalent is: if class is
vector
, a simple-vector; if class is
list
, a list; if class is a symbol naming a
structure or CLOS class: an instance of this class, with slots of names
ident1,...,identn.
The type (c-union (ident1
type1) ... (identn
typen))
is equivalent to what C calls
"union { type1
ident1; ...; typen
identn; }
". Conversion to and from
Lisp assumes that a value is to be viewed as being of
type1.
The type (c-array type dim1
... dimn)
is equivalent to what C calls
"type
[dim1]...[dimn]
".
Note that when an array is passed as an argument to a function in C, it
is actually passed as a pointer; you therefore have to write
(c-ptr (c-array ...))
for this argument's type.
The type (c-array-max type maxdim)
is equivalent to what C calls "type
[maxdim]
", an array containing up to
maxdim elements. The array is zero-terminated if it contains
less than maxdim elements. Conversion from Lisp of an array
with more than maxdim elements silently ignores the
superfluous elements.
The type (c-ptr type)
is equivalent to what C
calls "type *
": a pointer to a single
item of the given type.
The type (c-ptr-null type)
is also equivalent
to what C calls "type *"
: a pointer to a
single item of the given type, with the exception that C
NULL
corresponds to Lisp nil
.
The type (c-array-ptr type)
is equivalent to
what C calls "type (*)[]
": a pointer
to a zero-terminated array of items of the given type.
The type (c-function (:return-type rtype)
(:arguments (arg1 type1 ...)
...))
designates a C function that can be called according to the
given prototype (rtype (*)
(type1, ...))
. The language is
either :C
(denotes K&R C) or :STDC
(denotes ANSI C) or :STDC-STDCALL
(denotes ANSI C with
stdcall calling convention). It specifies whether the C
function has been compiled by a K&R C compiler or by an ANSI C
compiler, and possibly the calling convention. Conversion between C
functions and Lisp functions is transparent.
(def-c-struct name
(ident c-type)*)
defines name to
be both a defstruct
structure type and a foreign C type
with the given slots.
(def-c-enum name {ident
| (ident [value])}*)
defines
idents as constants, similarly to the C declaration
enum { ident [= value], ... };
(c-lines format-string
{argument}*)
outputs the string (format nil
format-string {argument}*)
to the C output
file. This is a rarely needed low-level facility.
The form (sizeof c-type)
returns the size and alignment of a C type, measured in bytes.
The form (bitsizeof c-type)
returns the size and alignment of a C type, measured in bits.
The predicate (validp
foreign-entity)
returns nil
if the
foreign-entity (e.g. the Lisp equivalent of a
c-pointer
) refers to a pointer which is invalid because it
comes from a previous Lisp session. It returns t
if
foreign-entity can be used within the current Lisp process.
Foreign variables are variables whose storage is allocated in the
foreign language module. They can nevertheless be evaluated and modified
through
setq
, just as normal variables can, except that the
range of allowed values is limited according to the variable's foreign
type. Note that for a foreign variable x the form
( eql
x x)
is not necessarily true, since every
time x is evaluated its foreign value is converted to a
freshly created Lisp value.
(def-c-var name
{option}*)
option ::= | |
(:name c-name)
| |
| | (:type c-type)
|
| | (:read-only boolean)
|
| | (:alloc allocation)
|
The :name
option specifies the name, as seen from C, as
a string. If not specified, it is derived from the print name of the
Lisp name.
The :type
option specifies the variable's foreign type.
If the :read-only
option is specified and non-nil
, it will be
impossible to change the variable's value from within Lisp (using
setq
or similar).
The :alloc
option can be either :none
or
:malloc-free
and defaults to :none
. If it is
:malloc-free
, any values of type c-string
,
(c-ptr ...)
, (c-ptr-null ...)
,
(c-array-ptr ...)
within the foreign value are assumed to
be pointers to malloc()
-allocated storage, and when
setq
replaces an old value by a new one, the old storage is
freed using free()
and the new storage allocated using
malloc()
. If it is :none
, setq
assumes that the pointers point to good storage (not NULL
!)
and overwrites the old values by the new ones. This is dangerous (just
think of overwriting a string with a longer one or storing some data in
a NULL
pointer...) and deprecated.
A foreign variable name defined by def-c-var
defines a "place", i.e., a form which can also be used as
argument to
setf
. (An "lvalue" in C terminology.)
The following operations are available on foreign places:
(element place
index1 ... indexn)
Array element: If place is of foreign type (c-array
c-type dim1
... dimn)
and 0 <=
index1 < dim1, ..., 0
<= indexn < dimn, this
will be the place corresponding to (aref place
index1 ... indexn)
or
place[index1]...[indexn]
.
It is a place of type c-type. If place is of
foreign type (c-array-max c-type dim)
and 0 <= index < dim, this will be the place
corresponding to (aref place index)
or place[index]
. It is a place of
type c-type.
(deref place)
Dereference pointer: If place is of foreign type
(c-ptr c-type)
or (c-ptr-null
c-type)
, this will be the place the pointer points
to. It is a place of type c-type. For (c-ptr-null
c-type)
, the place may not be
NULL
.
(slot place
slot-name)
Struct or union component: If place is of foreign type
(c-struct class ... (slot-name
c-type) ...)
or of type (c-union
... (slot-name c-type) ...)
, this will be
of type c-type.
(cast place c-type)
Type change: A place denoting the same memory locations as the
original place, but of type c-type.
(typeof place)
returns the c-type corresponding to the place.
(sizeof place)
returns the size and alignment of the C type of place,
measured in bytes.
(bitsizeof place)
returns the size and alignment of the C type of place,
measured in bits.
Foreign functions are functions which are defined in the foreign
language. There are named foreign functions (imported via
def-call-out
or created via def-call-in
) and
anonymous foreign functions; they arise through conversion of
function pointers.
A "call-out" function is a foreign function called from Lisp: control flow temporarily leaves Lisp. A "call-in" function is a Lisp function called from the foreign language: control flow temporary enters Lisp.
(def-call-out name
{option}*)
option ::= | |
(:name c-name)
| |
| | (:arguments {(arg-name
c-type [param-mode
[allocation]])}*)
|
| | (:return-type c-type
[allocation])
|
| | (:language language)
|
#'name
is redirected to call the C function
c-name. The language is either :C
(denotes K&R C) or :STDC
(denotes ANSI C) or
:STDC-STDCALL
(denotes ANSI C with stdcall
calling convention). It specifies whether the C function has been
compiled by a K&R C compiler or by an ANSI C compiler, and possibly
the calling convention.
def-c-call-out
is equivalent to
def-call-out
with :language :stdc
.
(def-call-in name
{option}*)
option ::= | |
(:name c-name)
| |
| | (:arguments {(arg-name
c-type [param-mode
[allocation]])}*)
|
| | (:return-type c-type
[allocation])
|
| | (:language language)
|
#'name
. The language is either
:C
(denotes K&R C) or :STDC
(denotes ANSI C)
or :STDC-STDCALL
(denotes ANSI C with stdcall
calling convention). It specifies whether the calling code has been
compiled by a K&R C compiler or by an ANSI C compiler, and possibly
the calling convention.
def-c-call-in
is equivalent to
def-call-in
with :language :stdc
.
When passed to and from functions, allocation of arguments and results is handled as follows:
Values of simple-c-type, c-pointer
are passed
on the stack, with dynamic extent. The allocation is
effectively ignored.
Values of type c-string
, (c-ptr
...)
, (c-ptr-null
...)
,
(c-array-ptr
...)
need storage. The
allocation specifies the allocation policy:
allocation | meaning |
---|---|
:none | 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 c-string
and (c-ptr
...)
and (c-ptr-null
...)
and
(c-array-ptr
...)
and for :out
arguments. [Subject to change!] The :malloc-free
policy
provides the ability to pass arbitrarily nested structs containing
pointers pointing to structs ... within a single conversion.
:malloc-free
,
:alloca
,
:none
,
:malloc-free
,
:none
,
:malloc-free
,
:alloca
or
:none
, :malloc-free
,
:none
,
A function parameter's param-mode may be
:in
(means: read-only):
:out
(means: write-only):
:in-out
(means: read-write):
:out
" value is
returned as an additional multiple value.
:in
.
[Currently, only :in
is fully
implemented. :out
works only with
allocation = :alloca
.]
:malloc-free
because there
is no commonly used malloc()/free()
library function.
The allocation may be followed by a register
specification, any of the symbols :d0
, :d1
,
:d2
, :d3
, :d4
, :d5
,
:d6
, :d7
, :a0
, :a1
,
:a2
, :a3
, :a4
, :a5
,
:a6
, each representing one 680x0 register. This works only
for integral types: integers, pointers, c-string
,
c-function
.
Passing c-struct
, c-union
,
c-array
, c-array-max
values as arguments (not
via pointers) is only possible to the extent the C compiler supports
it. Most C compilers do it right, but some C compilers (such as gcc on
hppa) have problems with this.
UNICODE
.
lisp:*foreign-encoding*
contains the encoding for characters and strings passed through the
FFI. Its value must be a 1:1 encoding, i.e., an encoding in which every
character is represented by one byte.
struct foo {
int a;
struct foo * b[100];
};
corresponds to
(def-c-struct foo
(a int)
(b (c-array (c-ptr foo) 100))
)
The element access
struct foo f;
f.b[7].a
corresponds to
(declare (type foo f))
(foo-a (aref (foo-b f) 7)) or (slot-value (aref (slot-value f 'b) 7) 'a)
Ex. 2: Here is an example of an external C variable and some accesses:
struct bar {
short x, y;
char a, b;
int z;
struct bar * n;
};
extern struct bar * my_struct;
my_struct->x++;
my_struct->a = 5;
my_struct = my_struct->n;
corresponds to
(def-c-struct bar
(x short)
(y short)
(a char)
(b char) ; or (b character) if it represents a character, not a number
(z int)
(n (c-ptr bar))
)
(def-c-var my_struct (:type (c-ptr bar)))
(setq my_struct (let ((s my_struct)) (incf (slot-value s 'x)) s))
or (incf (slot my_struct 'x))
(setq my_struct (let ((s my_struct)) (setf (slot-value s 'a) 5) s))
or (setf (slot my_struct 'a) 5)
(setq my_struct (slot-value my_struct 'n))
or (setq my_struct (deref (slot my_struct 'n)))
Ex. 3: An example for calling an external function:
On ANSI C systems, <stdlib.h> contains the declarations
typedef struct {
int quot; /* Quotient */
int rem; /* Remainder */
} div_t;
extern div_t div (int numer, int denom);
This translates to
(def-c-struct div_t
(quot int)
(rem int)
)
(def-c-call-out div (:arguments (numer int) (denom int))
(:return-type div_t)
)
Sample call from within Lisp:
> (div 20 3)
#S(DIV :QUOT 6 :REM 2)
Ex. 4: Another example for calling an external function:
Suppose the following is defined in a file "cfun.c"
:
struct cfunr { int x; char *s; };
struct cfunr * cfun (i,s,r,a)
int i;
char *s;
struct cfunr * r;
int a[10];
{
int j;
struct cfunr * r2;
printf("i = %d\n", i);
printf("s = %s\n", s);
printf("r->x = %d\n", r->x);
printf("r->s = %s\n", r->s);
for (j = 0; j < 10; j++) printf("a[%d] = %d.\n", j, a[j]);
r2 = (struct cfunr *) malloc (sizeof (struct cfunr));
r2->x = i+5;
r2->s = "A C string";
return r2;
}
It is possible to call this function from Lisp using the file
"callcfun.lsp"
(do not call it "cfun.lsp"
-
compile-file
would overwrite "cfun.c"
) whose
contents is:
(in-package "TEST-C-CALL" :use '("LISP" "FFI"))
(def-c-struct cfunr (x int) (s c-string))
(def-c-call-out cfun (:arguments (i int)
(s c-string)
(r (c-ptr cfunr) :in :alloca)
(a (c-ptr (c-array int 10)) :in :alloca)
)
(:return-type (c-ptr cfunr))
)
(defun call-cfun ()
(cfun 5 "A Lisp string" (make-cfunr :x 10 :s "Another Lisp string")
'#(0 1 2 3 4 5 6 7 8 9)
) )
Use the module facility:
$ clisp-link create-module-set cfun callcfun.c
$ cc -O -c cfun.c
$ cd cfun
$ ln -s ../cfun.o cfun.o
Add cfun.o to NEW_LIBS and NEW_FILES in link.sh.
$ cd ..
$ base/lisp.run -M base/lispinit.mem -c callcfun.lsp
$ clisp-link add-module-set cfun base base+cfun
$ base+cfun/lisp.run -M base+cfun/lispinit.mem -i callcfun
> (test-c-call::call-cfun)
i = 5
s = A Lisp string
r->x = 10
r->s = Another Lisp string
a[0] = 0.
a[1] = 1.
a[2] = 2.
a[3] = 3.
a[4] = 4.
a[5] = 5.
a[6] = 6.
a[7] = 7.
a[8] = 8.
a[9] = 9.
#S(TEST-C-CALL::CFUNR :X 10 :S "A C string")
>
$ rm -r base+cfun
Note that there is a memory leak here: The return value
r2
of cfun()
is malloc()
ed but
never free()
d. Specifying
(:return-type (c-ptr cfunr) :malloc-free)
is not an alternative because this would also
free(r2->x)
but r2->x
is a pointer to
static data.
Ex. 5: To sort an array of double-floats using the Lisp function
sort
instead of the C library function
qsort()
, one can use the following interface code
"sort1.c"
. The main problem is to pass a
variable-sized array.
extern void lispsort_begin (int);
void* lispsort_function;
void lispsort_double (int n, double * array)
{
double * sorted_array;
int i;
lispsort_begin(n); /* store #'sort2 in lispsort_function */
sorted_array = ((double * (*) (double *)) lispsort_function) (array);
for (i = 0; i < n; i++) array[i] = sorted_array[i];
free(sorted_array);
}
This is accompanied by "sort2.lsp"
:
(use-package "FFI")
(def-call-in lispsort_begin (:arguments (n int))
(:return-type nil)
(:language :stdc)
)
(def-c-var lispsort_function (:type c-pointer))
(defun lispsort_begin (n)
(setf (cast lispsort_function
`(c-function
(:arguments (v (c-ptr (c-array double-float ,n))))
(:return-type (c-ptr (c-array double-float ,n))
:malloc-free
) )
)
#'sort2
) )
(defun sort2 (v)
(declare (type vector v))
(sort v #'<)
)
To test this, use the following test file "sorttest.lsp"
:
(def-call-out sort10
(:name "lispsort_double")
(:language :stdc)
(:arguments (n int)
(array (c-ptr (c-array double-float 10))
:in-out
) ) )
Now try
$ clisp-link create-module-set sort sort2.c sorttest.c
$ cc -O -c sort1.c
$ cd sort
$ ln -s ../sort1.o sort1.o
Add sort1.o to NEW_LIBS and NEW_FILES in link.sh.
$ cd ..
$ base/lisp.run -M base/lispinit.mem -c sort2.lsp sorttest.lsp
$ clisp-link add-module-set sort base base+sort
$ base+sort/lisp.run -M base+sort/lispinit.mem -i sort2 sorttest
> (sort10 10 '#(0.501d0 0.528d0 0.615d0 0.550d0 0.711d0
0.523d0 0.585d0 0.670d0 0.271d0 0.063d0))
#(0.063d0 0.271d0 0.501d0 0.523d0 0.528d0 0.55d0 0.585d0 0.615d0 0.67d0 0.711d0)
$ rm -r base+sort
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 .fas
files
without the need to load function definition files at run-time and
without external C or linker support. Memory images can be created,
provided that the function libraries are opened at run-time.
Therefore, AFFI supports only primitive C types (integers 8, 16 and 32 bits wide, signed or unsigned, pointers) and defines no new types or classes. Foreign functions are not first-class objects (you can define a lambda yourself), name spaces are separate.
The AFFI does no tracking of resources. Use finalize
.
These are the AFFI forms:
(declare-library-base keyword-base
library-name)
(require-library-functions library-name [(:import
{string-name}*)])
(open-library base-symbol)
(clos-library base-symbol)
(with-open-library (base-symbol |
library-name) {form}*)
(defflibfun function-name base-symbol
offset mask result-type
{argument-type}*)
(declare-library-function function-name
library-name {option}*)
(flibcall function-name
{argument}*)
(mlibcall function-name
{argument}*)
(mem-read address result-type
[offset])
(mem-write address type value
[offset])
(mem-write-vector address vector
[offset])
(nzero-pointer-p value)
Except for with-open-library
,
declare-library-function
and mlibcall
, all of
the above are functions.
A library contains a collection of functions. The library is referred
to by a symbol referred as library-base at the AFFI level. This symbol
is created in the package AFFI
. The link between this
symbol and the OS-level library name is established by
declare-library-base
. To avoid multiple package conflicts,
this and only this function requires the symbol-name to be in the
KEYWORD
package. The function returns the library-base.
A library may be opened by open-library
and closed by
close-library
. An opened library must be
closed. with-open-library
is provided to automatically
close the library for you, thus it 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
unsigned-byte
vector
into memory.
nzero-pointer-p
tests for non-NULL
pointers
in all recognized representations (
null
,
unsigned-byte
and 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 equiv | C equiv | Comment |
---|---|---|---|
nil
| nil
| void
| as a result type for functions only |
4
| (unsigned-byte
32)
| unsigned long
| |
2
| (unsigned-byte
16)
| unsigned short
| |
1
| (unsigned-byte
8)
| unsigned char
| |
-4
| (signed-byte
32)
| long
| |
-2
| (signed-byte
16)
| short
| |
-1
| (signed-byte
8)
| signed char
| |
0
| boolean
| BOOL
| as a result type for functions only |
*
| opaque | void*
| |
:external
| opaque | void*
| |
string
| string or
vector
| char*
| |
:io
| string or
vector
| char*
|
Objects of type
string
are copied and passed
NUL-terminated on the execution stack. On return, a Lisp string is
allocated and filled from the address returned (unless NULL). Functions
with :io
parameters are passed the address of the Lisp
string or unsigned byte vector. These are not NUL-terminated! This is
useful for functions like like read()
which do not need an
array at a constant address longer than the dynamic extent of the call
(it is dangerous to define callback functions with :io
(or
string
) type parameters). Arguments of type
integer
and foreign-pointer
are always
acceptable where a
string
or :io
type is specified.
UNICODE
.
lisp:*foreign-encoding*
contains the encoding for characters and strings passed through the
FFI. Its value must be a 1:1 encoding, i.e., an encoding in which every
character is represented by one byte.
To meet the design goals, predefined types and objects were used. As
such, pointers were represented as integers. Now that there is the
foreign-pointer
type, both representations may be used on
input. The pointer type should be therefore considered as opaque. Use
nzero-pointer-p
for NULL tests.
Foreign Functions are declared either through defflibfun
ordeclare-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
foreign-pointer
as function result-type (except from
nil
for a NULL pointer) and refuses objects of type
string
or unsigned byte vector as input. Thus
:external
provides some security on the input and the
ability to use lisp:finalize
for
resource-tracking on the output side.
(declare-library-function name
library-name {option}*)
option ::= | |
(:offset library-offset)
| |
| | (:arguments {(arg-name AFFI-type register)}*)
|
| | (:return-type AFFI-type)
|
register ::= | :d0 | :d1 | ... | :d7 | :a0 | ... | :a6
|
flibcall
and mlibcall
.
mlibcall
should be the preferred way of calling foreign
functions (when they are known at compile-time) as macroexpansion-time
checks may be performed and the call can be sort of inlined.
(mem-read address type
offset)
can read 8, 16 and 32 bit signed or
unsigned integers (AFFI types -4
, -2
,
-1
, 1
, 2
, 4
), a
pointer (*
), a NUL-terminated string (string
)
or, if the type argument is of type string
or unsigned byte
vector, it can fill this vector. :external
is not an
acceptable type as no object can be created by using
mem-read
.
(mem-write address type value
[offset])
writes integers (AFFI type -4
,
-2
, -1
, 1
, 2
and
4
) or pointer values (type *
), but not vectors
to the specified memory address.
(mem-write-vector address vector
[offset])
can write memory from the given vector (of
type string
or unsigned byte vector).
require-library-functions
will require
a
file of name derived from thelibrary name and with type
"affi"
. It may be used to import all names into
the current package or only a given subset identified by string names,
using the :import
keyword (recommended use). Some definition
files for standard Amiga libraries are provided. See example 1 below.
As require-library-functions
loads a global file which
you, the programmer, may have not defined, you may consider declaring
every function yourself to be certain what the return and argument types
are. See example 4 below.
The file read-fd.lsp
defines the function
make-partial-fd-file
with which the provided
".affi"
files have been prepared from the
original Amiga FD files (located in the directory
FD:
). They must still be edited as the function cannot know
whether a function accepts a *
, :io
,
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
declare-library-base
and
require-library-functions
and not using
flibcall
, it is possible to write code that only loads
library function definition files at compile-time. See example 1 below.
Do not rely on finalize
to free resources for you, as
CLISP does not call finalizers when it exits, use
unwind-protect
.
You can consider the library bases being symbols in need of being
imported from the package AFFI originating from a brain-damage, causing
the usual symbol headaches when using foreign functions calls within
macros. Luckily, even if the high-level interface (or its implementation
in affi1.lsp
) were to change, the low-level part
(affi.d
) should remain untouched as all it knows are
integers and foreign-pointers, no symbols. The difficulty is just to get
the library base value at run-time. Feel free to suggest enhancements to
this facility!
NB: These examples are somewhat specific to the Amiga.
1. Using a predefined library function file
(use-package "AFFI")
;; SysBase is the conventional name for exec.library
;; It is only enforced by the file loaded by REQUIRE-LIBRARY-FUNCTIONS
(eval-when (compile eval load)
(declare-library-base :SysBase "exec.library")) ;keyword avoids name conflicts
;; using only MLIBCALL allows not to load definitions at load-time
(eval-when (compile eval)
(require-library-functions "exec.library"
:import '("FindTask")))
(with-open-library ("exec.library")
(print (mlibcall FindTask 0)))
This file can be used in interpreted and compiled mode. Compiled, it will
have inlined the library function calls.
2. Using flibcall
(use-package "AFFI")
(eval-when (compile eval load)
(declare-library-base :SysBase "exec.library")) ;keyword avoids name conflicts
;; The load situation permits the use of flibcall
(eval-when (eval compile load)
(require-library-functions "exec.library"))
(unless (open-library 'SysBase) (error "No library for SysBase"))
(flibcall (if t 'FindTask 'Debug) 0)
(close-library 'SysBase)
3. Be fully dynamic, defining library bases ourselves
(use-package "AFFI")
(eval-when (compile eval load)
(defvar mylib (declare-library-base :foobase "foo.library")))
(eval-when (eval compile load) ;eval allows mlibcall, load flibcall
(defflibfun 'foo1 mylib -30 '#xA '* 'string)
(defflibfun 'foo2 mylib -36 '#x21 0 * 4))
(defun foo (name)
(when (open-library mylib)
(list (mlibcall foo1 name) (flibcall 'foo2 name 123213))
(close-library mylib)))
4. Some sample function definitions
(defflibfun 'FindTask 'SysBase -294 #xA '* 'string)
(declare-library-function FindTask "exec.library"
(:offset -294)
(:return-type *)
(:arguments
(name string :A1)))
(declare-library-function NameFromLock "dos.library"
(:offset -402)
(:return-type 0)
(:arguments
(lock 4 :D1)
(buffer :io :D2)
(len 4 :D3)))
(eval-when (compile eval)
(defconstant GVF_LOCAL_ONLY (ash 1 9))
(defflibfun 'SetVar 'DosBase -900 #x5432 0 'string 'string -4 4))
(defun setvar (name value)
(with-open-library (DosBase)
;; length of -1 means find length of NUL-terminated-string
(mlibcall SetVar name value -1 GVF_LOCAL_ONLY)))
CLISP comes with a small yet extensible and powerful ARexx interface.
(rexx-do-command "return address()" :string t :result
t)
tells you the name of the CLISP ARexx port. The default
extension for CLISP ARexx scripts is "cl"
.
(REXX-DO-COMMAND command &key :string :result
:token :io :host)
-> (RC &optional
result)
, or nil
on failure
(REXX-RUN-COMMAND command &KEY :string
:token)
->
t
, or
nil
on failure
(REXX-SEND-COMMAND command &KEY :string :result
:token :io :host)
-> arexx-msg-handle, or
nil
on failure
(REXX-WAIT-SENT-COMMAND arexx-msg-handle)
-> (RC &optional result)
, or
nil
on failure
(REXX-LOOP)
-> no return, use the
exit-loop.cl
ARexx script to abort the loop
command may be a string denoting a command with optional arguments or a vector of strings thus denoting an ARexx function call. The first element in the vector is the function name, the others are the up to 15 arguments.
Messages may be sent to an arbitrary ARexx host, special cases are
nil
(meaning "REXX"
, the default) and t
("AREXX"
for 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.
(lisp:socket-server
&optional [port-or-socket])
(lisp:socket-server-close
socket-server)
(lisp:socket-server-port
socket-server)
lisp:socket-server
.
(lisp:socket-wait socket-server
&optional [seconds [microseconds]])
socket-wait
blocks indefinitely.
(lisp:socket-accept socket-server &key
[:element-type]
[:external-format]
[:buffered])
(lisp:socket-connect port
&optional [host] &key
[:element-type]
[:external-format]
[:buffered])
(lisp:socket-stream-host
socket-stream)
(lisp:socket-stream-port
socket-stream)
lisp:socket-stream-host
returns nil
.
(lisp:socket-service-port
&optional "service-name"
(protocol "tcp"))
service-name
and
protocol
, or all services as the list of vectors of length
4, if service-name
is not given or is :default
or nil
.
(lisp:socket-stream-peer
socket-stream)
(lisp:socket-stream-local
socket-stream)
lisp:socket-stream-peer
- same information,
host name and port number, but for the local host.
When CLISP is configured with an option
--with-export-syscalls
, some system calls are available from
lisp, in package POSIX
.
(posix:resolve-host-ipaddr
&optional host)
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 of
vectors of length 4 (this would be the contents of the
/etc/hosts file on a UNIX system or
${windir}/system32/etc/hosts on a Win32 system).
(posix:file-stat
file &optional link-p)
file
can
be a stream, a pathname, a string or a number (on a UNIX system,
meaning file descriptor). The first slot of the struct returned is
the string or the number on which
stat
(2)/fstat
(2)/lstat
(2)
was called. The other 13 slots are numbers, members of the stat
struct: device, inode, protection, number of hard links, owner's
UID, owner's GID, device type, total size (bytes), blocksize for
filesystem I/O, number of blocks allocated, atime, mtime, ctime (as
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.
(posix:user-data
&optional user)
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.
(posix:sysinfo)
uname(2)
and sysconf(3)
.
(posix:resource-usage-limits)
getrlimit(2)
and getrusage(3)
.
(posix:erf real)
(posix:erfc real)
(posix:j0 real)
(posix:j1 real)
(posix:jn int
real)
(posix:y0 real)
(posix:y1 real)
(posix:yn int
real)
(posix:gamma real)
(posix:lgamma real)
This section describes four ways to turn CLISP programs into executable programs, which can be started as quickly as executables written in other languages.
CONFIG_BINFMT_MISC=y
fas
and lsp
with CLISP; then you can make the files executable and run them
from the command line.
fas
files
can be concatenated (using Join
) into one file.
lsp
or fas
file. If your application is made up of several lsp
or
fas
files, you can simply concatenate them (using
cat
(1)) into one file; the techniques then apply to that
concatenated file.
fas
or lsp
) can be
made executable by adding a first line of the form
#!interpreter [interpreter-args]
and using chmod
(1) to make the script executable. CLISP
can be used as a script interpreter under the following circumstances:
/usr/local/bin/clisp
, and if CLISP is
actually installed elsewhere, letting
/usr/local/bin/clisp
be a symbolic link to the real
CLISP.
clisp
is a shell script because a C compiler
cannot be assumed to be installed on this platform. If you have a C
compiler installed, build CLISP from source yourself;
"make install
" will install clisp
as a real executable.
#!interpreter
[interpreter-args]
" is limited in length:
-Msomewhere.mem
" and
"-C
") to clisp
, separate them by
hard spaces (ISO Latin-1 character 160) instead of normal
spaces. (But the separator between interpreter and
interpreter-args must still be a normal space!) CLISP will
split the interpreter-args at hard spaces and at normal
spaces.
The script should contain Lisp forms, except in the #! line. The
file is normally loaded, through the function
load
. Before it is loaded, the variable
lisp:*args*
is bound to a list of strings,
representing the arguments given to the Lisp script.
*standard-input*
and
*standard-output*
are bound, as usual, to the Unix standard
input and output.
*error-output*
is bound to the Unix error output.
Continuable errors will be turned to warnings. Non-continuable errors
and Ctrl-C interrupts will terminate the execution of the Lisp script
with error status. If you wish the script's contents to be compiled during
loading, add -C
to the
interpreter-args.
Another, quite inferior, alternative is to put the following into a file:
#!/bin/sh
exec clisp <<EOF
(lisp-form)
(another-lisp-form)
(yet-another-lisp-form)
EOF
The problem with this approach is that the return values of each form will be printed to the standard output. Another problem is that no user input will be available.
mem
extension with
"c:\clisp\lisp.exe -m 10M -M %s -N c:\clisp\locale"
.
fas
extension with
"c:\clisp\lisp.exe -m 10M -M c:\clisp\lispinit.mem -N c:\clisp\locale -i %s"
.
Alternatively, you may want to have a function main
in
your files and associate the fas
extension with
"c:\clisp\lisp.exe -m 10M -M c:\clisp\lispinit.mem -N c:\clisp\locale -i %s
-x (main)"
.
Then clicking on the compiled lisp file (with fas
extension) will load the file (thus executing all the code in the file),
while the clicking on a CLISP memory image (with mem
extension) will start clisp with the given memory
image.
CONFIG_BINFMT_MISC=y
and CONFIG_PROC_FS=y
. Then you will have a
/proc/sys/fs/binfmt_misc/
directory and you will be able to
do (as root
; you might want to put these lines into
/etc/rc.d/rc.local
):
bash# echo ":CLISP:E::fas::/usr/bin/clisp:" >> /proc/sys/fs/binfmt_misc/register
bash# echo ":CLISP:E::lsp::/usr/bin/clisp:" >> /proc/sys/fs/binfmt_misc/register
Then you can do the following:
bash$ cat << EOF > hello.lsp
(print "hello, world!")
EOF
bash$ clisp -c hello.lsp
Compiling file /home/sds/hello.lsp ...
Compilation of file /home/sds/hello.lsp is finished.
0 errors, 0 warnings
bash$ chmod +x hello.fas
bash$ hello.fas
"hello, world!"
bash$
Please read /usr/src/linux/Documentation/binfmt_misc.txt
for details.
lisp:lisp.run
(or wherever the binary is
located).
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.
main
in
your files and set the ARGS
tooltype to
-M lisp:lispinit.mem -i * -x (main)
.
ARGS
tooltype.
Clicking on the compiled lisp file (with fas
suffix)
will load the image and the file (thus executing all the code in the
file), while clicking on the CLISP's memory image (with mem
suffix) with start clisp with the given memory
image.
You might want to add a tooltype named WINDOW
which
names the console window that
*terminal-io*
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, COMPILER, CLOS, FFI, ...), must be covered by GNU GPL as well.
Other programs running in CLISP have to or need not to be placed under GNU GPL, depending on their distribution form:
(lisp:execute programfile
arg1 arg2 ...)
executes an external program. Its name is programfile. It is
given the strings arg1,
arg2, ... as arguments.
(lisp:execute command)
executes a given command using the operating system's
shell.
(lisp:shell [command])
calls the operating system's shell. (lisp:shell)
calls
the shell for interactive use. (lisp:shell
command)
calls the shell only for execution of the
one given command.
lisp:run-shell-command
and lisp:run-program
are a general
interface to lisp:shell
and the above:
(run-shell-command command
[:input] [:output] [:if-output-exists])
runs a shell command.
(run-program program
[:arguments] [:input] [:output] [:if-output-exists])
runs an external program.
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
).
PATH
environment variable will be searched for it.
:arguments
:input
:terminal
(the standard input) or :stream
(a Lisp stream to be created) or a pathname (an input file) or
nil
(no input at all).
:output
:terminal
(the standard output) or :stream
(a Lisp stream to be created) or a pathname (an output file) or
nil
(ignore the output).
:if-output-exists
:output
file already
exists. The possible values are :overwrite
,
:append
, :error
, with the same meaning as for
open
.
If :stream
was specified for :input
or
:output
, a Lisp stream is returned. If
:stream
was specified for :input
and
:output
, three Lisp streams are returned, as for the
function lisp:make-pipe-io-stream
.
This use of lisp:run-program
can cause deadlocks, see lisp:make-pipe-io-stream
.
*debug-io*
and
*error-output*
point to separate console windows (thus
keeping your standard console window clean from error messages) you can use
(setq *error-output*
(setq *debug-io*
(open "CON:0/0/500/300/CLISP-Debugger/AUTO/CLOSE" :direction :io)
) )
at startup.
Bruno Haible | Michael Stoll | |||
17, rue Danton | Westerwaldweg 22 | |||
F - | 94270 Le Kremlin-Bicêtre | D - | 53424 Remagen-Oberwinter | |
France | Germany |
Bugs in both these notes and CLISP itself should be sent to:
<clisp-list@lists.sourceforge.net>