Creating a function from C isn't too hard. To do it, you've got to write an implementation of a command that will perform the operation, and register that implementation as a command in the correct namespace. (In 8.4 and before, functions were done with a separate interface that was quite a bit nastier to use; the mechanism was wholly overhauled in 8.5.)
Command Implementation
Note that the signature is defined, and the ignored
parameter is not used here. (It's really a void *
— great when you're wanting to do things like binding a command to an object — but it simply isn't needed for doing an addition.)
static int AddCmd(ClientData ignored, Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]) {
double x, y, sum;
/* First, check number of arguments: command name is objv[0] always */
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "x y");
return TCL_ERROR;
}
/* Get our arguments as doubles */
if ( Tcl_GetDoubleFromObj(interp, objv[1], &x) != TCL_OK ||
Tcl_GetDoubleFromObj(interp, objv[2], &y) != TCL_OK) {
return TCL_ERROR;
}
/* Do the real operation */
sum = x + y;
/* Pass the result out */
Tcl_SetObjResult(interp, Tcl_NewDoubleObj(sum));
return TCL_OK;
}
Don't worry about the fact that it's allocating a value here; Tcl's got a very high performance custom memory manager that makes that a cheap operation.
Command Registration
This is done usually inside an initialization function that is registered as part of a Tcl package definition or which is called as part of initialization of the overall application. You can also do it directly if you are calling Tcl_CreateInterp
manually. Which you do depends on how exactly how you are integrating with Tcl, and that's quite a large topic of its own. So I'll show how to create an initialization function; that's usually a good start in all scenarios.
int Add_Init(Tcl_Interp *interp) {
/* Use the fully-qualified name */
Tcl_CreateObjCommand(interp, "::tcl::mathfunc::add", AddCmd, NULL, NULL);
return TCL_OK;
}
The first NULL
is the value that gets passed through as the first (ClientData
) parameter to the implementation. The second is a callback to dispose of the ClientData
(or NULL if it needs no action, as here).
Doing all this from C++ is also quite practical, but remember that Tcl is a C library, so they have to be functions (not methods, not without an adapter) and they need C linkage.
To get the body of a procedure from C (or C++), by far the easiest mechanism is to use Tcl_Eval
to run a simple script to run info body theCmdName
. Procedure implementations are very complex indeed, so the interface to them is purely at the script level (unless you actually entangle yourself far more with Tcl than is really wise).