next up previous contents
Next: 9 Running QScheme Up: QScheme Documentation Previous: 7 QScheme procedures   Contents

Subsections

8 Foreign function interface

QScheme provides a way to dynamically load dynamic libraries, to call functions of that library and to share variables with libraries.


8.1 Loading a dynamic library

(load-library name)-> <boolean>
Attempts to load la dynamic library. If the dynamic linkage succeeds and the library contains a function named scm_init_name QScheme will call this function to initialize the module. (See scm_init_regex in regex.c for an example.)

8.2 Calling a foreign function

To call a foreign function, you have to declare it first. As an example, here is the declaration of the system and printf functions from libc:

(define system (make-extfunc *lib* :int "system" '(:string)))

(define printf (make-extfunc *lib* :void "printf" '(:string . :any)))

After that, you can use system and printf just as is they were part of QScheme:

> (printf "May I ? %d %s\nIt works...\n" 10 "hello world") 

May I ? 10 hello world It works...

>

(make-extfunc libname ret-type ext-name arglist)-> <extfunc>
Creates a new Scheme object which can be used to call the foreign function ext-name

You can pass strings as arguments to a foreign function. The string is passed to the function as is. If the size of the string should be adjusted, this may be done with the string- functions. For instance, this QScheme function lists the contents of a file using the stdio functions:

(define (type file)

  (let ((fd) (buf) (bufsize 256))

    (set! fd (fopen file "r"))

    (if (not (null-pointer? fd))

        (begin

          (while 

           (not (null? 

                 (fgets

                  (set! buf (make-string bufsize #\space))

                  bufsize

                  fd)))

           (printf "%s\n" (string-chop buf)))

          (fclose fd))

        (printf "cannot open file %s" file))))

Note how we pass the buf to the fgets function and how we use it afterwards.

8.3 Using a foreign variable

QScheme can also access variables defined in dynamic libraries. (see load-library: 8.1).

(make-extern-variable libname type name)-> <external-variable>
Creates an external variable. libname is a string containing the path to the dynamically loaded library. The library will be loaded on demand. The type is a keyword as described in the table

Table 5: Type of external variables
Type C type Description
:char char a character
:short short a short integer
:long long a long integer
:float float a float number
:double double a double float number
:string char * a malloc-ed string.
:string-buffer char * a pointer to a char buffer
:scheme SOBJ a pointer to a Scheme object
     




5. The name is a string containing the name of the variable as defined in the module.

The type of external strings is specified according to the string allocation scheme. We have to deal with the following cases:

When referring to a dynamically allocated string, you have to use the :string type. Changing such a string from QScheme will first free the memory then malloc a fresh copy of the string.

When referring to a string stored in a static character buffer, you must use the :string-buffer type. In this case the value is just copied in the buffer. Beware that no range check occurs. From QScheme, don't try to assign a string bigger than the static buffer size.

Look at tstlib.c and tstlib.defs for an example that uses static and dynamic strings in a dynamic library.

8.4 A trivial example

Here is an example of how to share variable values between C and QScheme. In your C code, you have the following:

int shared_var;

 

void test_func() {

  printf("shared_var = %d\n", testvar_w);

}

To access the variable shared_var and the function test_func from Qscheme, you may use the following definitions:

(define *lib* "./tstlib.so")

(define shared-var (make-extern-variable *lib* :int "shared_var")

(define test-func (make-extfunc *lib* :void "test_func" '())

Then you can get and set values like this:

> (set! shared-var 100)

> (test-func)

shared_var = 100

> (display shared-var) (newline)

100

>

Warning:
You must use define to bind a symbol to an external variable and set! to modify directly the value of the variable.

8.5 Declaring and using foreign types

QScheme can create new Scheme object types at run-time.

(make-type name)-> <type-number>
Creates a new type of Scheme object. The number returned is the internal type number.

(define-type <keyword> | <string> | <symbol>)-> #undefined
Creates a new type of Scheme object. This is just a wrapper around the make-type function.

(internal-type-list) -> <list>
Returns a list of strings representing the know types.

(get-aux obj)-> <obj>  
(set-aux! obj value)-> #undefined  
(clear-aux! obj)-> #undefined
(null-aux? obj)-> <boolean>
These functions test and change the aux field of an object. The aux field is large enough to store a pointer.

Warning:
the set-aux! and clear-aux! do not check the type of object. You may alter whatever Scheme object you want, and this may lead to regrettably unpredictable results. You should not modify the aux field of ordinary Scheme objects, because this field may be used for specific purpose. (for example, the aux field of a pair is the car field).
(add-type-finalizer type proc)-> #undefined
Defines a procedure to be executed when an object of this type is released by the garbage collector. When called the proc is a given the object to be destroyed as argument.

Note:
the proc is a procedure which is executed in the top-level context, which means the procedure should not use any local references!
A new type maybe used in conjunction with the make-extfunc procedure. For example:

(define-type :file)

 

(define fopen

  (make-extfunc "" :file "fopen" '(:string :string)))

 

(define fprintf

  (make-extfunc "" :void "fprintf" '(:file :string . :any)))

 

(define _fclose (make-extfunc "" :void "fclose" '(:file)))

 

(define (fclose x)

  (if (not (null-aux? x)) (_fclose x))

  (clear-aux! x))

 

(add-type-finalizer 

 "file"

 (lambda (x) (fclose x)))

In this example, the finalizer procedure closes the file. This guarantees that the file will not stay open when the Scheme objects that were using it have all vanished.


next up previous contents
Next: 9 Running QScheme Up: QScheme Documentation Previous: 7 QScheme procedures   Contents
Daniel Crettol 2000-06-12