views:

166

answers:

4

Hi,

using the PLT-Scheme-FFI, I want to call the C-function

unsigned long mysql_real_escape_string(MYSQL *con, char *to, const char *from, unsigned long length)

from a scheme procedure and continue using the resulting string 'to' inside the caller. The call of the scheme procedure would go like this:

(define-values (to) (escape-string con ??? from (+ (string-length from) 1)))

where con is a valid connection to a MySQL-DB and escape-string is defined by

(define escape-string (get-ffi-obj "mysql_real_escape_string" libmysql 
                                   (_fun (con to from length) ::
                                         (con : _pointer) 
                                         (to : (_ptr io _byte))
                                         (from : _string) 
                                         (length : _ulong)
                                         -> (res : _ulong)
                                         -> (values out))))

The problem is, I have no idea what to pass for '???' when calling escape-string nor do I know whether the definition of escape-string is correct.

Any help would be appreciated.

Regards,

Ralf S.

+1  A: 

In general, _ptr arguments are used where the foreign (C) code expects a pointer, but you want to avoid dealing with a pointer on the Scheme side. For example, (_ptr o _int) would be used when you have a foreign function that expects an integer pointer and sets it to some value (often called "an output pointer" hence the "o"). The _fun arranges for an allocation of a pointer, and will dereference it when the call is done -- but the thing that can be confusing is that you need to grab this value with a name or it will just be dropped. Here's an example for doing this:

(_fun [r : (_ptr o _int)] -> _void -> r)

You should read this as: pass a pointer to an integer to the foreign function, and make the resulting value available as r. The foreign function returns void, but that's ignored and instead it returns the value of r, effectively dereferencing the pointer. Note that since this is an output pointer, you don't need to specify an input value of it. For example, if that type is used for some foo binding, then foo would expect no arguments.

A (_ptr i _int) is different: the resulting function would expect an integer, allocate a pointer when called and pass that pointer to the foreign function (so the C code still sees an int*) then discard this pointer after the call. The purpose here is to make it easy to use such functions without doing the tedious allocation yourself. Note that in this case, this does correspond to an input to the resulting Scheme function, but does not correspond to a value that can be used later.

Finally, (_ptr io _int) is a combination of the two: the Scheme function will expect an integer, will allocate a pointer and put the given integer in it, call the C function and hand it that pointer, then dereference it and give you the result. For example, if you have this C function:

void inc(int* p) { (*p)++; }

Then this would be a suitable Scheme definition for it:

(define inc
  (get-ffi-obj 'inc "foo.so"
                (_fun [r : (_ptr io _int)] -> _void -> r)))
Eli Barzilay
Thanks for the response. I think I understand the example. But what about the following C-function:void setstring(char* str) { strcpy(str, "foo"); }Is the following Scheme definition correct?(define setstring (get-ffi-obj 'setstring "foo.so" (_fun [r : (_ptr io _byte)] -> void -> r)))If the definition is OK, how do I call setstring from Scheme, such that I can proceed to work with the result r? IMO something like this(define r (setstring ???))or this(let ((r (setstring ???))) ...should work. However, I just don't know what to pass as argument ??? to setstring.
Ralf Seliger
It is nearly impossible to read the code in this comment, as well as writing a reply in a comment. Can you post this as a new question? (Or just go on the PLT mailing list with it.)
Eli Barzilay
A: 

Sorry about the format. When I clicked the submit button on the comment box it looked quite differently :-)

Anyway, here it is again:

... But what about the following C-function:

void setstring(char* str) { strcpy(str, "foo"); }

Is the following Scheme definition correct?

(define setstring 
  (get-ffi-obj 'setstring "foo.so" 
                (_fun [r : (_ptr io _byte)] -> void -> r)))

If the definition is OK, how do I call setstring from Scheme, such that I can proceed to work with the result r? IMO something like this

(define r (setstring ???))
(do-something-with-r ...

or this

(let ((r (setstring ???))) 
  (do-something-with-r ...

should work. However, I just don't know what to pass as argument ??? to setstring.

Ralf Seliger
A: 

I figured it out. A suitable Scheme definition for the C-function

void setstring(char* str) { strcpy(str, "foo"); }

that is contained in the dynamic library 'lib.so' is

(define setstring
  (get-ffi-obj 'setstring "lib.so"
                (_fun (r : _u8vector) -> _void -> r))))

It can be called e.g. like this

> (setstring (make-u8vector 5))

which prints

> #"foo\0\0"
Ralf Seliger
A: 

You may find one of these helpful:

troelskn