From: Lars Rune Nøstdal
Subject: cffi: calls with variable number of arguments determined at runtime
Date: 
Message-ID: <pan.2007.02.01.15.22.56.827662@gmail.com>
cffi> (with-foreign-pointer-as-string (s 100)
        (foreign-funcall "sprintf"
                         :pointer s
                         :string "i: %d"
                         :int 1234
                         :int))
"i: 1234"


;; ..works ok.. same with..


cffi> (defcfun "sprintf" :int
        (str :pointer)
        (control :string)
        &rest)
sprintf
cffi> (with-foreign-pointer-as-string (s 100)
         (sprintf s "i: %d" :int 1234))
"i: 1234"


;; but what if i do not know the types and arguments at compile time? 
;; these are stupid examples and none of them work, but:


cffi> (with-foreign-pointer-as-string (s 100)
        (let ((type-args* '(:int 1234)))
          (sprintf s "i: %d" type-args*)))

cffi> (with-foreign-pointer-as-string (s 100)
        (sprintf s format (read-from-string (read-line))))


;; is there some way of doing this using CFFI or possibly something else?


-- 
Lars Rune Nøstdal
http://nostdal.org/

From: Pillsy
Subject: Re: cffi: calls with variable number of arguments determined at runtime
Date: 
Message-ID: <1170357803.663637.42310@l53g2000cwa.googlegroups.com>
On Feb 1, 10:22 am, Lars Rune Nøstdal <···········@gmail.com> wrote:
[...]
> ;; is there some way of doing this using CFFI or possibly something else?

I'm not claiming this is anything but completely gruesome, but this
appears to work:

(defun foreign-apply (name-or-pointer arglist)
		   (funcall
		    (compile nil `(lambda ()
				    (foreign-funcall ,name-or-pointer
						     ,@arglist)))))

so this works:

> (with-foreign-pointer-as-string (s 100)
		  (foreign-apply "sprintf"
				 (list :pointer s
				       :string "i: %d"
				       :int 1234
				       :int)))

"i: 1234"

as does this:

> (with-foreign-pointer-as-string (s 100)
		   (let ((args (list :pointer s
					 :string "i: %d"
					 :int 1234
					 :int)))
		    (foreign-apply "sprintf"
				   args)))
"i: 1234"

Disclaimer: Only tested with SBCL 1.0.2. Doesn't really look that much
like plain-old APPLY. Do not taunt FOREIGN-FUNCALL.

Cheers,
Pillsy
From: Lars Rune Nøstdal
Subject: Re: cffi: calls with variable number of arguments determined at runtime
Date: 
Message-ID: <pan.2007.02.01.19.34.00.864722@gmail.com>
On Thu, 01 Feb 2007 11:23:23 -0800, Pillsy wrote:

> On Feb 1, 10:22 am, Lars Rune Nøstdal <···········@gmail.com> wrote:
> [...]
>> ;; is there some way of doing this using CFFI or possibly something else?
> 
> I'm not claiming this is anything but completely gruesome, 

haha .. how hackish .. yes, it does seem to work, and will do for now ..
thanks :)

-- 
Lars Rune Nøstdal
http://nostdal.org/
From: Pascal Bourguignon
Subject: Re: cffi: calls with variable number of arguments determined at runtime
Date: 
Message-ID: <87zm7xx1oa.fsf@thalassa.informatimago.com>
Lars Rune N�stdal <···········@gmail.com> writes:

> cffi> (with-foreign-pointer-as-string (s 100)
>         (foreign-funcall "sprintf"
>                          :pointer s
>                          :string "i: %d"
>                          :int 1234
>                          :int))
> "i: 1234"
>
>
> ;; ..works ok.. same with..
>
>
> cffi> (defcfun "sprintf" :int
>         (str :pointer)
>         (control :string)
>         &rest)
> sprintf
> cffi> (with-foreign-pointer-as-string (s 100)
>          (sprintf s "i: %d" :int 1234))
> "i: 1234"
>
>
> ;; but what if i do not know the types and arguments at compile time? 
> ;; these are stupid examples and none of them work, but:
>
>
> cffi> (with-foreign-pointer-as-string (s 100)
>         (let ((type-args* '(:int 1234)))
>           (sprintf s "i: %d" type-args*)))

Obviously, here you know the type, since you wrote %d, not %s or %f!

Now imagine you have this C function:

void format(const char* ctrlstring,int nargs,void** arguments){
     ...
}

How can you write it in C, if you don't know the type of the
arguments?  The same as you'd do in lisp, and the same printf does,
you parse ctrlstring to collect the types.



-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

NEW GRAND UNIFIED THEORY DISCLAIMER: The manufacturer may
technically be entitled to claim that this product is
ten-dimensional. However, the consumer is reminded that this
confers no legal rights above and beyond those applicable to
three-dimensional objects, since the seven new dimensions are
"rolled up" into such a small "area" that they cannot be
detected.
From: Lars Rune Nøstdal
Subject: Re: cffi: calls with variable number of arguments determined at runtime
Date: 
Message-ID: <pan.2007.02.01.17.59.40.658528@gmail.com>
On Thu, 01 Feb 2007 17:50:13 +0100, Pascal Bourguignon wrote:

> Lars Rune Nøstdal <···········@gmail.com> writes:
> 
>> cffi> (with-foreign-pointer-as-string (s 100)
>>         (foreign-funcall "sprintf"
>>                          :pointer s
>>                          :string "i: %d"
>>                          :int 1234
>>                          :int))
>> "i: 1234"
>>
>>
>> ;; ..works ok.. same with..
>>
>>
>> cffi> (defcfun "sprintf" :int
>>         (str :pointer)
>>         (control :string)
>>         &rest)
>> sprintf
>> cffi> (with-foreign-pointer-as-string (s 100)
>>          (sprintf s "i: %d" :int 1234))
>> "i: 1234"
>>
>>
>> ;; but what if i do not know the types and arguments at compile time? 
>> ;; these are stupid examples and none of them work, but:
>>
>>
>> cffi> (with-foreign-pointer-as-string (s 100)
>>         (let ((type-args* '(:int 1234)))
>>           (sprintf s "i: %d" type-args*)))
> 
> Obviously, here you know the type, since you wrote %d, not %s or %f!
> 
> Now imagine you have this C function:
> 
> void format(const char* ctrlstring,int nargs,void** arguments){
>      ...
> }
> 
> How can you write it in C, if you don't know the type of the
> arguments?  The same as you'd do in lisp, and the same printf does,
> you parse ctrlstring to collect the types.

Ok, but there are cases where there is no format string. Or - what I mean
is, the problem is after the "step" you describe. Even if I at runtime
determine:

* types
* values
* ..and of course then also number of these

..I cannot seem to find a way to build the function call (at runtime) and
call it with CFFI. Hm, does this make sense?

-- 
Lars Rune Nøstdal
http://nostdal.org/
From: Pascal Bourguignon
Subject: Re: cffi: calls with variable number of arguments determined at runtime
Date: 
Message-ID: <87ododwxav.fsf@thalassa.informatimago.com>
Lars Rune N�stdal <···········@gmail.com> writes:

>>> cffi> (with-foreign-pointer-as-string (s 100)
>>>          (sprintf s "i: %d" :int 1234))
>>> "i: 1234"
>>>
>>>
>>> ;; but what if i do not know the types and arguments at compile time? 
>>> ;; these are stupid examples and none of them work, but:
>>>
> Ok, but there are cases where there is no format string. Or - what I mean
> is, the problem is after the "step" you describe. Even if I at runtime
> determine:
>
> * types
> * values
> * ..and of course then also number of these
>
> ..I cannot seem to find a way to build the function call (at runtime) and
> call it with CFFI. Hm, does this make sense?

(let ((ctrl-string "%d %f %c %s")
      (types  '(:int :float :char :string))
      (values '(42   3.14   #\!   "Hi")))
  (apply (function sprintf) s ctrl-string 
      (mapcan (function list) types values)))

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

"Debugging?  Klingons do not debug! Our software does not coddle the
weak."
From: Lars Rune Nøstdal
Subject: Re: cffi: calls with variable number of arguments determined at runtime
Date: 
Message-ID: <pan.2007.02.01.18.31.04.454533@gmail.com>
On Thu, 01 Feb 2007 19:24:40 +0100, Pascal Bourguignon wrote:

> Lars Rune Nøstdal <···········@gmail.com> writes:
> 
>>>> cffi> (with-foreign-pointer-as-string (s 100)
>>>>          (sprintf s "i: %d" :int 1234))
>>>> "i: 1234"
>>>>
>>>>
>>>> ;; but what if i do not know the types and arguments at compile time? 
>>>> ;; these are stupid examples and none of them work, but:
>>>>
>> Ok, but there are cases where there is no format string. Or - what I mean
>> is, the problem is after the "step" you describe. Even if I at runtime
>> determine:
>>
>> * types
>> * values
>> * ..and of course then also number of these
>>
>> ..I cannot seem to find a way to build the function call (at runtime) and
>> call it with CFFI. Hm, does this make sense?
> 
> (let ((ctrl-string "%d %f %c %s")
>       (types  '(:int :float :char :string))
>       (values '(42   3.14   #\!   "Hi")))
>   (apply (function sprintf) s ctrl-string 
>       (mapcan (function list) types values)))

sprintf is a macro. Using foreign-funcall doesn't work either as it
expects its arguments to be typenames at expansion time it seems.

cffi> (with-foreign-pointer-as-string (s 100)
        (let ((ctrl-string "%d %f %c %s")
              (types  '(:int :float :char :string))
              (values '(42   3.14   #\!   "Hi")))
          (apply (function sprintf) s ctrl-string 
                 (mapcan (function list) types values))))

Execution of a form compiled with errors.
Form:
  #'sprintf
Compile-time error:
  The macro name sprintf was found as the argument to FUNCTION.
   [Condition of type sb-int:compiled-program-error]


-- 
Lars Rune Nøstdal
http://nostdal.org/
From: Lars Rune Nøstdal
Subject: Re: cffi: calls with variable number of arguments determined at runtime
Date: 
Message-ID: <pan.2007.02.01.18.32.21.599866@gmail.com>
I'm starting to think CFFI lacks a way of doing this. Everything seems to
expect that info about types/arguments are available at macro expansion
time.

-- 
Lars Rune Nøstdal
http://nostdal.org/
From: Lars Rune Nøstdal
Subject: Re: cffi: calls with variable number of arguments determined at runtime
Date: 
Message-ID: <pan.2007.02.02.16.00.50.567721@gmail.com>
..another thing I sometime miss is being able to do stuff like this:

(defcenum ParamFlags
  (:readable (ash 1 0))
  (:writable (ash 1 1))
  (:construct (ash 1 2))
  (:construct-only (ash 1 3))
  (:lax-validation (ash 1 4))
  (:static-name (ash 1 5))
  ;; :private deprecated
  (:static-nick (ash 1 6))
  (:static-blurb (ash 1 7)))

..it only accepts literal integers.

-- 
Lars Rune Nøstdal
http://nostdal.org/
From: Zach Beane
Subject: Re: cffi: calls with variable number of arguments determined at runtime
Date: 
Message-ID: <m3lkjgqzco.fsf@unnamed.xach.com>
Lars Rune Nøstdal <···········@gmail.com> writes:

> ..another thing I sometime miss is being able to do stuff like this:
> 
> (defcenum ParamFlags
>   (:readable (ash 1 0))
>   (:writable (ash 1 1))
>   (:construct (ash 1 2))
>   (:construct-only (ash 1 3))
>   (:lax-validation (ash 1 4))
>   (:static-name (ash 1 5))
>   ;; :private deprecated
>   (:static-nick (ash 1 6))
>   (:static-blurb (ash 1 7)))
> 
> ..it only accepts literal integers.

#. may come in handy there. On the other hand, in that specific case,
I might be more inclined to write:

  (defcenum ParamFlags
    (:readable  #b00000001)
    (:writable  #b00000010)
    (:construct #b00000100)
    ...)

Zach
From: Lars Rune Nøstdal
Subject: Re: cffi: calls with variable number of arguments determined at runtime
Date: 
Message-ID: <pan.2007.02.02.17.49.54.316092@gmail.com>
On Fri, 02 Feb 2007 11:49:11 -0500, Zach Beane wrote:

> Lars Rune Nøstdal <···········@gmail.com> writes:
> 
>> ..another thing I sometime miss is being able to do stuff like this:
>> 
>> (defcenum ParamFlags
>>   (:readable (ash 1 0))
>>   (:writable (ash 1 1))
>>   (:construct (ash 1 2))
>>   (:construct-only (ash 1 3))
>>   (:lax-validation (ash 1 4))
>>   (:static-name (ash 1 5))
>>   ;; :private deprecated
>>   (:static-nick (ash 1 6))
>>   (:static-blurb (ash 1 7)))
>> 
>> ..it only accepts literal integers.
> 
> #. may come in handy there. On the other hand, in that specific case,
> I might be more inclined to write:
> 
>   (defcenum ParamFlags
>     (:readable  #b00000001)
>     (:writable  #b00000010)
>     (:construct #b00000100)
>     ...)
> 

Thanks for the #. tip. I forgot about that one.

Just found another way:


(defbitfield ParamFlags
  (:readable #x00000001)
  :writable
  :construct
  :construct-only
  :lax-validation
  :static-name
  ;; :private (deprecated)
  :static-nick
  :static-blurb)

(foreign-bitfield-symbols 'ParamFlags 237)
  => (:readable :construct :construct-only :static-name :static-nick :static-blurb)


..handy. :)

-- 
Lars Rune Nøstdal
http://nostdal.org/