Task

Show how a foreign language function can be called from the language.



As an example, consider calling functions defined in the C language. Create a string containing "Hello World!" of the string type typical to the language. Pass the string content to C's strdup. The content can be copied if necessary. Get the result from strdup and print it using language means. Do not forget to free the result of strdup (allocated in the heap).



Notes

 It is not mandated if the C run-time library is to be loaded statically or dynamically. You are free to use either way.
 C++ and C solutions can take some other language to communicate with.
 It is not mandatory to use strdup, especially if the foreign function interface being demonstrated makes that uninformative.


See also

   Use another language to call a function


 
#lang racket/base
(require ffi/unsafe)
 
(provide strdup)
 
;; Helper: create a Racket string from a C string pointer.
(define make-byte-string
  (get-ffi-obj "scheme_make_byte_string" #f (_fun _pointer -> _scheme)))
 
;; Take special care not to allow NULL (#f) to be passed as an input,
;; as that will crash strdup.
(define _string/no-null
  (make-ctype _pointer
    (lambda (x)
      (unless (string? x)
        (raise-argument-error '_string/no-null "string" x))
      (string->bytes/utf-8 x))
    ;; We don't use _string/no-null as an output type, so don't care:
    (lambda (x) x)))
 
; Make a Scheme string from the C string, and free immediately.
(define _string/free 
  (make-ctype _pointer
    ;; We don't use this as an input type, so we don't care.
    (lambda (x) x)
    (lambda (x)
      (cond 
       [x
        (define s (bytes->string/utf-8 (make-byte-string x)))
        (free x)
        s]
       [else
        ;; We should never get null from strdup unless we're out of
        ;; memory:
        (error 'string/free "Out of memory")]))))
 
(define strdup
  (get-ffi-obj "strdup" #f (_fun _string/no-null -> _string/free)))
 
;; Let's try it:
(strdup "Hello World!")
 