[Parrot-users] how do I pass obj** to a C function from parrot?
Allison Randal
allison at parrot.org
Sun Nov 29 13:21:04 UTC 2009
Vadim Konovalov wrote:
> Hi,
>
> I have following problem.
>
> One function returns TclObj*
> Another function takes TclObj** as argument, which is actually an
> array of TclObj*, which I should pass to that another function.
>
> So I have some functions declared like following:
>
> func1 = dlfunc libtcl, "Tcl_NewStringObj", "pti"
> func2 = dlfunc libtcl, "Tcl_EvalObjv", "ipipi"
>
> func2 returns int, takes some pointer (that is okay), takes integer
> (this is a number of TclObj*), the TclObj** itself, and integer, which
> could be 0
>
> I tried to create following "structure":
> # TclObj**, which is array of TclObj*
> .local pmc tcl_obj_decl, tcl_obj_struct
> tcl_obj_decl = new 'FixedPMCArray'
> tcl_obj_decl = 3
> tcl_obj_decl[0] = .DATATYPE_PTR
> tcl_obj_decl[1] = objc
> tcl_obj_decl[2] = 0
> tcl_obj_struct = new 'ManagedStruct', tcl_obj_decl
>
> . and then fill it in a loop with values.
>
> But when I, essentially, do
>
> .local pmc obj
> obj = func1("string",0)
>
> tcl_obj_struct[0;i] = obj
>
> I get an error
> set_pmc_keyed() not implemented in class 'ManagedStruct'
>
> I think that when parrot assigns to a field structure, it attempts to
> do a conversion, which is not defined for abstract PMC, thus the
> error. But I do not know what the way out of situation.
>
> I tried to replace .DATATYPE_PTR, with .DATATYPE_PMC with similar results.
>
> Actaully, my task is not "twisted" - essentially it is just passing an
> array of some pointers. But how to do this?
There are several ways to do it, so it partly depends on how you plan to
use the array. If you want to be able to use it as an array in PIR, and
do things like insert (or delete) elements like:
tcl_obj_array[0;i] = obj
Then, your array needs to be a PMC array type, like FixedPMCArray (if
you know how many elements you'll have) or ResizablePMCArray (if you
don't know how many elements you'll have). A ManagedStruct can't act as
a generic array of PMCs, which is why you're getting the error about
"set_pmc_keyed() not implemented".
Could we get a little more detail on the Tcl side of the code? It looks
like you're embedding a Tcl interpreter inside Parrot? In which case,
the key thing is building a variable that the 'Tcl_EvalObjv' function
can understand.
Tcl_Obj is a core Tcl type, so has to be created using Tcl's constructor
functions. Looks like you're using 'Tcl_NewStringObj' for that. But the
Tcl_Obj** you need to pass to 'Tcl_EvalObjv' also has to be created by
Tcl. (Parrot can pass around a pointer to the chunk of memory that holds
the Tcl_Obj**, but it can't know how to structure it internally so Tcl
can read it.)
It looks like you can do this by calling the functions 'Tcl_NewListObj'
to create a new Tcl list of Tcl_Obj's, then call
'Tcl_ListObjAppendElement' to add each Tcl_Obj* to the list, and then
call 'Tcl_ListObjGetElements' to get back a Tcl_Obj** array of the
elements of the list. That Tcl_Obj** array should be able to be passed
directly to 'Tcl_EvalObjv'.
(BTW, from the documentation on Tcl_EvalObjv, it looks like you may also
need to import the Tcl functions for manual reference counting
('Tcl_IncrRefCount' and 'Tcl_DecrRefCount'), since Tcl_EvalObjv expects
the caller to handle incrementing and decrementing the refcounts on the
objects passed in.)
Allison
More information about the Parrot-users
mailing list