cprintfschemevariadicchez-scheme

FFI in Chez Scheme for C functions with variadic arguments (varargs)


I want to write a FFI for printf function of C in Chez Scheme using foreign-procedure. But I cannot figure out what I should put as the signature, since the last argument in printf function is a variadic argument. Here's my code:

(import (chezscheme))

(define (print-format)
    (foreign-procedure "printf" 
        (string void*) int)) ;; <-- Here, the type format is "(arg arg ...) ret"

(print-format "Hello, %s!" "Ryan")

I have tried this as well to no avail:

(define (print-format . args)
    (foreign-procedure "printf" 
        (string args) int))

This is not working either:

(define (print-format)
    (foreign-procedure "printf" 
        (string ...) int))

How do you specify variadic arguments in function signature for foreign-procedure?


Solution

  • Although it is not the ultimate solution, you could use macros to accommodate variable number of parameters to a system call.

    create-list is used to supply proper number of parameters to the foreign-procedure system call.

    For example, macro call

    (print-format "Hello %s and %s" "Ryan" "Greg")

    is expanded as

    ((foreign-procedure "printf" (string string string) int) "Hello %s and %s" "Ryan" "Greg")

    (define create-list
      (lambda (element n)
        "create a list by replicating element n times"
        (letrec ((helper
               (lambda (lst element n)
                 (cond ((zero? n) lst)
                       (else
                        (helper
                         (cons element lst) element (- n 1)))))))
          (helper '() element n))))
    
    (define-syntax print-format
      (lambda (x)
        (syntax-case x ()
          ((_ cmd ...)
           (with-syntax
            ((system-call-spec
              (syntax
               (create-list 'string
                            (length (syntax (cmd ...)))))))
            (with-syntax
             ((proc (syntax
                     (eval
                      `(foreign-procedure "printf"
                                          (,@system-call-spec) int)))))
             (syntax
              (proc cmd ...))))))))
    
    (print-format "Hello %s!" "Ryan")
    (print-format "Hello %s and %s" "Ryan" "Greg")