;; ..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/
> 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.
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?
>>> 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."
> Lars Rune Nøstdal <larsn...@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]
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
> On Feb 1, 10:22 am, Lars Rune Nøstdal <larsnost...@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 :)
(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.
> ..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
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. :)