Use another language to call a function: Difference between revisions

Content deleted Content added
m omit TI-89 BASIC
→‎Tcl: Added implementation
Line 65: Line 65:
Here am I
Here am I
</pre>
</pre>

=={{header|Tcl}}==
The way you would tackle this problem depends on whether you are working with ‘In’ or ‘Out’ parameters. (It is normal model ‘inout’ parameters as Tcl variables; omitted for brevity.)
===‘In’ Parameters===
To connect a function to Tcl that passes an arbitrary C string as input, you'd use a short C thunk, like this:
<lang c>int Query (char * Data, size_t * Length) {
Tcl_Obj *arguments[2];
int code;

arguments[0] = Tcl_NewStringObj("Query", -1); /* -1 for "use up to zero byte" */
arguments[1] = Tcl_NewStringObj(Data, Length);
Tcl_IncrRefCount(arguments[0]);
Tcl_IncrRefCount(arguments[1]);
if (Tcl_EvalObjv(interp, 2, arguments, 0) != TCL_OK) {
/* Was an error or other exception; report here... */
Tcl_DecrRefCount(arguments[0]);
Tcl_DecrRefCount(arguments[1]);
return 0;
}
Tcl_DecrRefCount(arguments[0]);
Tcl_DecrRefCount(arguments[1]);
if (Tcl_GetObjResult(NULL, Tcl_GetObjResult(interp), &code) != TCL_OK) {
/* Not an integer result */
return 0;
}
return code;
}</lang>
Which would lead to a <code>Query</code> implementation like this:
<lang tcl>proc Query data {
puts "Query was $data"
return 1;
}</lang>
===‘Out’ Parameters===
However, in the specific case of writing to a user-specified buffer (an “out” parameter) the thunk code would instead manage copying the result from the interpreter back to the buffer:
<lang c>int Query (char * Data, size_t * Length) {
const char *str;
int len;

if (Tcl_Eval(interp, "Query") != TCL_OK) {
return 0;
}
str = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &len);
if (len+1 > Length) {
return 0;
}
memcpy(Data, str, len+1);
return 1;
}</lang>
And the implementation of <code>Query</code> would be just:
<lang tcl>proc Query {} {
return "Here am I"
}</lang>
(Since this is working with a literal, this would actually be efficient and just result in references being passed.)
===Connecting up the pieces===
You would also need a short piece of code in <code>main()</code> to initialize the Tcl library and create an interpreter instance, and you would need to build and link against [[libtcl]].
<lang c>#include <tcl.h>
Tcl_Interp *interp;

int main(int argc, char **argv) {
Tcl_FindExecutable(argv[0]); /* Initializes library */
interp = Tcl_CreateInterp(); /* Make an interpreter */

/* Rest of contents of main() from task header... */
}</lang>


{{omit from|TI-89 BASIC}} <!-- Does not have a standard FFI. -->
{{omit from|TI-89 BASIC}} <!-- Does not have a standard FFI. -->