home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / coders / jËzyki_programowania / clisp / doc / affi.txt next >
Text File  |  1977-12-31  |  13KB  |  321 lines

  1.                 The Amiga Foreign Function Call Facility
  2.                 ========================================
  3.  
  4.                    Another Foreign Function Interface
  5.  
  6. All symbols relating to the simple foreign function interface are
  7. exported from the package AFFI. To use them, (USE-PACKAGE "AFFI").
  8.  
  9.                         Design issues
  10.                         -------------
  11.  
  12. AFFI was designed to be small in size but powerful enough to use most
  13. library functions. Lisp files may be compiled to .FAS files without the need
  14. to load function definition files at run-time and without external C or
  15. linker support. Memory images can be created, provided that the function
  16. libraries are opened at run-time.
  17.  
  18. Therefore, AFFI supports only primitive C types (integers 8, 16 and 32 bits
  19. wide, signed or unsigned, pointers) and defines no new types or classes.
  20. Foreign functions are not first-class objects (you can define a lambda
  21. yourself), name spaces are separate.
  22.  
  23. The AFFI does no tracking of resources. Use FINALIZE (see impnotes.txt).
  24.  
  25.                           Overview
  26.                           --------
  27.  
  28. These are the AFFI forms:
  29.  
  30. (DECLARE-LIBRARY-BASE keyword-base library-name)
  31.  
  32. (REQUIRE-LIBRARY-FUNCTIONS library-name [(:import {string-names}*))
  33.  
  34. (OPEN-LIBRARY  base-symbol)
  35.  
  36. (CLOSE-LIBRARY base-symbol)
  37.  
  38. (WITH-OPEN-LIBRARY (base-symbol | library-name) {forms}*)
  39.  
  40. (DEFFLIBFUN function-name base-symbol offset mask result-type {argument-type}*)
  41.  
  42. (DECLARE-LIBRARY-FUNCTION function-name library-name {options}*)
  43.  
  44. (FLIBCALL function-name {argument}*)
  45.  
  46. (MLIBCALL function-name {argument}*)
  47.  
  48. (MEM-READ  address result-type [offset])
  49.  
  50. (MEM-WRITE address type  value [offset])
  51.  
  52. (MEM-WRITE-VECTOR address vector [offset])
  53.  
  54. (NZERO-POINTER-P value)
  55.  
  56. Except for WITH-OPEN-LIBRARY, DECLARE-LIBRARY-FUNCTION and MLIBCALL,
  57. everything is a function.
  58.  
  59. A library contains a collection of functions. The library is referred to by
  60. a symbol referred as library-base at the AFFI level. This symbol is
  61. created in the package AFFI. The link between this symbol and the OS-level
  62. library name is established by DECLARE-LIBRARY-BASE. To avoid multiple
  63. package conflicts, this and only this function requires the symbol-name to
  64. be in the KEYWORD package. The function returns the library-base.
  65.  
  66. A library may be opened by OPEN-LIBRARY and closed by CLOSE-LIBRARY. An
  67. opened library must be closed. WITH-OPEN-LIBRARY is provided to
  68. automatically close the library for you, thus it's much safer to use.
  69.  
  70. A function is contained in a library. Every function is referred to by a
  71. symbol. A function is defined through DEFFLIBFUN or DECLARE-LIBRARY-FUNCTION
  72. by giving the function name, the library-base, an offset into the library, a
  73. mask (or NIL) for register-based library calls, the result type and all
  74. parameter-types.  REQUIRE-LIBRARY-FUNCTIONS loads the complete set of
  75. functions defined in a library file. Symbols are created in the package AFFI
  76. and imported into the current package.
  77.  
  78. FLIBCALL and MLIBCALL call library functions. MLIBCALL is a macro that does
  79. a few cheks at macroexpansion time and allows the compiler to inline the
  80. call, not requiring the foreign function to be defined again at load or
  81. execution time. The use of this macro is advertised wherever possible.
  82.  
  83. MEM-READ reads an arbitrary address (with offset for structure references)
  84. and returns the given type.
  85.  
  86. MEM-WRITE writes an arbitrary address. MEM-WRITE-VECTOR copies the content
  87. of a LISP string or unsigned-byte vector into memory.
  88.  
  89. NZERO-POINTER-P tests for non-NULL pointers in all recognized
  90. representations (NULL, UNSIGNED-BYTE and FOREIGN-POINTER).
  91.  
  92.                       Foreign Libraries
  93.                       -----------------
  94.  
  95. DECLARE-LIBRARY-BASE ought to be wrapped in an EVAL-WHEN (COMPILE EVAL LOAD)
  96. form and come before any function is referenced, because the library base
  97. symbol must be known.
  98.  
  99. OPEN-LIBRARY tries to open the library referenced by the base symbol.
  100. Therefore it must have been preceeded with DECLARE-LIBRARY-BASE. The call
  101. returns NIL on failure. OPEN-LIBRARY calls nest. Every successful call must
  102. be matched by CLOSE-LIBRARY. WITH-OPEN-LIBRARY does this for you and also
  103. allows you to specify the library by name, provided that its base has been
  104. declared. It is recommended to use this macro and to reference the library
  105. by name.
  106.  
  107. CLISP will not close libraries for you at program exit. [A previous version
  108. did so but now AFFI is a module and there are no module exit functions.]
  109. Programmers, watch AFFI::*LIBRARIES-ALIST*.
  110.  
  111.                       (Foreign) C types
  112.                       -----------------
  113.  
  114. The following foreign C types are used in AFFI. They are *not* regular
  115. Common Lisp types or CLOS classes.
  116.  
  117.  AFFI name     Lisp equiv              C equiv
  118.   NIL           NIL                     void            (r)
  119.   4             (UNSIGNED-BYTE 32)      unsigned long
  120.   2             (UNSIGNED-BYTE 16)      unsigned short
  121.   1             (UNSIGNED-BYTE 8)       unsigned char
  122.   -4            (SIGNED-BYTE 32)        long
  123.   -2            (SIGNED-BYTE 16)        short
  124.   -1            (SIGNED-BYTE 8)         signed char
  125.   0             (MEMBER NIL T)          "BOOL"          (r)
  126.   *             opaque                  void*
  127.   :EXTERNAL     opaque                  void*
  128.   STRING        STRING or VECTOR        char*
  129.   :IO           STRING or VECTOR        char*
  130. (r) as a result type for functions only.
  131.  
  132. Objects of type STRING are copied and passed NUL-terminated on the execution
  133. stack.  On return, a LISP string is allocated and filled from the address
  134. returned (unless NULL). Functions with :IO parameters are passed the address
  135. of the Lisp STRING or UNSIGNED BYTE-VECTOR. These are not NUL-terminated!
  136. This is useful for functions like like read() which do not need an array at
  137. a constant address longer than the dynamic extent of the call (it is
  138. dangerous to define callback functions with :IO (or STRING) type
  139. parameters). Arguments of type INTEGER and FOREIGN-POINTER are always
  140. acceptable where a STRING or :IO type is specified.
  141.  
  142. To meet the design goals, predefined types and objects were used. As such,
  143. pointers were represented as integers. Now that there is the FOREIGN-POINTER
  144. type, both representations may be used on input. The pointer type should be
  145. therefore considered as opaque. Use NZEROP-POINTER-P for NULL tests.
  146.  
  147.                       Foreign functions
  148.                       -----------------
  149.  
  150. Foreign Functions are declared either through DEFFLIBFUN or
  151. DECLARE-LIBRARY-FUNCTION. The former is closer to the low-level
  152. implementation of the interface, the latter is closer to the other FFI.
  153.  
  154. DEFFLIBFUN requires the library base symbol and register mask to be
  155. specified, DECLARE-LIBRARY-FUNCTION requires the library name and computes
  156. the mask from the declaration of the arguments.
  157.  
  158. The value of mask is implementation-dependent. On the Amiga, it's an integer
  159. whose hexadecimal value is the reverse of the function argument register
  160. numbers, where D0 has number 1 and A6 number #xF. A NIL mask is reserved for
  161. stack-based calls (unimplemented).
  162.  
  163. The AFFI type `0' is only acceptable as a function result type and yields
  164. either T or NIL. The difference between * and :EXTERNAL is the following: *
  165. uses integers, :EXTERNAL uses FOREIGN-TYPE as function result-type (except
  166. from NIL for a NULL pointer) and refuses objects of type STRING or UNSIGNED
  167. BYTE-VECTOR as input. Thus :EXTERNAL provides some security on the input and
  168. the ability to use FINALIZE for resource-tracking on the output side.
  169.  
  170. (DECLARE-LIBRARY-FUNCTION name library-name {options}*)
  171.   option ::=
  172.       (:offset <library-offset>)
  173.     | (:arguments {(<arg-name> <AFFI type> <register>)}*)
  174.     | (:return-type <AFFI-type>)
  175.  
  176.   register ::= :D0 :D1 .. :D7 :A0 ... :A6
  177.  
  178. declares a named library funtion for further reference through
  179. FLIBCALL and MLIBCALL.
  180.  
  181. MLIBCALL should be the preferred way of calling foreign functions (when they
  182. are known at compile-time) as macroexpansion-time checks may be performed
  183. and the call can be sort of inlined.
  184.  
  185.                          Memory access
  186.                          -------------
  187.  
  188. (MEM-READ address type offset) can read 8, 16 and 32 bit signed or unsigned
  189. integers (AFFI types -4, -2, -1, 1, 2 ,4), a pointer (*), a NUL-terminated
  190. string (STRING) or, if the type argument is of type STRING or UNSIGNED
  191. BYTE-VECTOR, it can fill this vector. :EXTERNAL is not an acceptable type as
  192. no object can be created by using MEM-READ.
  193.  
  194. (MEM-WRITE address type value [offset]) writes integers (AFFI type -4, -2,
  195. -1, 1, 2 and 4) or pointer values (type *), but not vectors to the specified
  196. memory address.
  197.  
  198. (MEM-WRITE-VECTOR address vector [offset]) can write memory from the given
  199. vector (of type STRING or UNSIGNED BYTE-VECTOR).
  200.  
  201.                    Function Definition Files
  202.                    -------------------------
  203.  
  204. REQUIRE-LIBRARY-FUNCTION will REQUIRE a file of name derived from the
  205. library name and with type "affi". It may be used to import all names into
  206. the current package or only a given subset identified by string names, using
  207. the :IMPORT keword (recommended use). Some definition files for standard
  208. Amiga libraries are provided. See example 1 below.
  209.  
  210. As REQUIRE-LIBRARY-FUNCTIONS loads a global file which you, the programmer,
  211. may have not defined, you may consider declaring every function yourself to
  212. be certain what the return and argument types are. See example 4 below.
  213.  
  214. The file READ-FD.LSP defines the function MAKE-PARTIAL-FD-FILE with which
  215. the provided ".affi" files have been prepared from the original Amiga FD
  216. files (located in the directory FD:). They must still be edited as the
  217. function cannot know whether a function accepts a *, :IO, STRING or
  218. :EXTERNAL argument and because files in FD: only contain a register
  219. specification, not the width of integer arguments (-4, -2, -1, 1, 2, or 4).
  220.  
  221.                              Hints
  222.                              -----
  223.  
  224. By using appropriate EVAL-WHEN forms for DECLARE-LIBRARY-BASE and
  225. REQUIRE-LIBRARY-FUNCTIONS and not using FLIBCALL, it is possible to write
  226. code that only loads library function definition files at compile-time. See
  227. example 1 below.
  228.  
  229. Do not rely on FINALIZE to free resources for you, as CLISP does not call
  230. finalizers when it exits, use UNWIND-PROTECT.
  231.  
  232.                 Caveats
  233.                 -------
  234.  
  235. You can consider the library bases being symbols in need of being imported
  236. from the package AFFI originating from a brain-damage, causing the usual
  237. symbol headaches when using foreign functions calls within macros. Luckily,
  238. even if the high-level interface (or its implementation in AFFI1.LSP) were
  239. to change, the low-level part (AFFI.D) should remain untouched as all it
  240. knows are integers and foreign-pointers, no symbols. The difficulty is just
  241. to get the library base value at run-time. Feel free to suggest enhancements
  242. to this facility!
  243.  
  244.                            Examples
  245.                            --------
  246.  
  247. NB: These examples are soemwhat specific to the Amiga.
  248.  
  249. 1. Using a predefined library function file
  250. (use-package "AFFI")
  251.  
  252. ;; SysBase is the conventional name for exec.library
  253. ;; It is only enforced by the file loaded by REQUIRE-LIBRARY-FUNCTIONS
  254. (eval-when (compile eval load)
  255.   (declare-library-base :SysBase "exec.library")) ;keyword avoids name conflicts
  256.  
  257. ;; using only MLIBCALL allows not to load definitions at load-time
  258. (eval-when (compile eval)
  259.   (require-library-functions "exec.library"
  260.     :import '("FindTask")))
  261.  
  262. (with-open-library ("exec.library")
  263.   (print (mlibcall FindTask 0))
  264.   )
  265. This file can be used in interpreted and compiled mode. Compiled, it will
  266. have inlined the library function calls.
  267.  
  268.  
  269. 2. Using flibcalll
  270. (use-package "AFFI")
  271.  
  272. (eval-when (compile eval load)
  273.   (declare-library-base :SysBase "exec.library")) ;keyword avoids name conflicts
  274.  
  275. ;; The load situation permits the use of flibcall
  276. (eval-when (eval compile load)
  277.   (require-library-functions "exec.library"))
  278.  
  279. (unless (open-library 'SysBase) (error "No library for SysBase"))
  280. (flibcall (if t 'FindTask 'Debug) 0)
  281. (close-library 'SysBase)
  282.  
  283.  
  284. 3. Be fully dynamic, defining library bases ourselves
  285. (use-package "AFFI")
  286.  
  287. (eval-when (compile eval load)
  288.   (defvar mylib (declare-library-base :foobase "foo.library")))
  289. (eval-when (eval compile load)          ;eval allows mlibcall, load flibcall
  290.   (defflibfun 'foo1 mylib -30 '#xA '* 'string)
  291.   (defflibfun 'foo2 mylib -36 '#x21 0 * 4))
  292.  
  293. (defun foo (name)
  294.   (when (open-library mylib)
  295.     (list (mlibcall foo1 name) (flibcall 'foo2 name 123213))
  296.     (close-library mylib)))
  297.  
  298. 4. Some sample function definitions
  299. (defflibfun 'FindTask 'SysBase -294 #xA '* 'string)
  300. (declare-library-function FindTask "exec.library"
  301.   (:offset -294)
  302.   (:return-type *)
  303.   (:arguments
  304.    (name   string   :A1)))
  305. (declare-library-function NameFromLock "dos.library"
  306.   (:offset -402)
  307.   (:return-type 0)
  308.   (:arguments
  309.    (lock   4   :D1)
  310.    (buffer :io :D2)
  311.    (len    4   :D3)))
  312.  
  313. (eval-when (compile eval)
  314.   (defconstant GVF_LOCAL_ONLY (ash 1 9))
  315.   (defflibfun 'SetVar 'DosBase -900 #x5432 0 'string 'string -4 4))
  316. (defun setvar (name value)
  317.   (with-open-library (DosBase)
  318.     ;; length of -1 means find length of NUL-terminated-string
  319.     (mlibcall SetVar name value -1 GVF_LOCAL_ONLY)))
  320.  
  321.