**Introduction**
The following questions tend to be asked regularly on the comp.lang.tcl newsgroup:
* ''I have a large [C]/[C++] program- how do I make it scriptable with [Tcl]?''
* ''I have a large C/C++ program- how do I add a [Tk] [GUI] to it?''
At a high level, there are three different solutions to consider.
1. Embed Tcl calls in my C/C++ code.
2. Wrap my C/C++ code to make it callable from Tcl.<
>Replace the C/C++ main() with a tclsh/wish main program
3. Something else
----
**Embed Tcl Calls in C/C++ code**
While the text
"[Why adding Tcl calls to a C/C++ application is a bad idea]"
is an interesting dialog concerning the appropriate
approach to performing this task,
where can one find specific coding examples and documentation
regarding what one needs to do, in a C program, if one needs to create
an interpreter and then execute tcl commands making use of that interpreter.
Well, one example comes ''out of the box'' with both Tcl and Tk.
Take a look at the tcl/unix/tclAppInit.c (or tcl/win/tclAppInit.c) files
in the tcl source distribution (which is the mainline C module for the
tclsh command), and in the Tk source distribution, tk/unix/tkAppInit.c
or tk/win/winMain.c (I don't understand why the name difference here...).
For MacOS, see tk/mac/tkMacAppInit.c and tk/macosx/tkMacOSXAppInit.c
(again, I don't understand the reasoning for file name changes).
These provide at least a basic skeleton for initializing an interpreter.
Unfortunately, they leave you in an interpretive mode which most people
don't want to happen. So another example is needed.
I do know there are two kinds of Tcl actions one can invoke from C/C++
Since Tcl is ''just'' a C library, some Tcl actions can be invoked by calling
the appropriate Tcl function call.
However, some things in Tcl must be done by invoking [Tcl_Eval], after
appropriately setting up a Tcl interpreter.
Can someone provide some sample C or C++ code that shows setting up the
interpreter, then perhaps invoking things each way?
A dream scenario would do this for Tcl/Tk since that is a superset of
the same kind of request for Tcl...
----
**First Example of invoking Tcl**
[AM] Here is some (massaged) code that I use in one application. The idea is:
* Set up a basic interpreter
* Register the specific commands
* Make sure that the interpreter is available when a scripted task is called
It ''does not'' use the Tcl script library, only the basic built-in commands are available, but this is a very simple set-up after all.
The function InitScript() is used to set up a script library private to the application and to get a functioning Tcl interpreter. The function EvalScriptCommand() is used elsewhere and simply wraps the details so that I do not need to use Tcl routines everywhere.
======c
#include
/*
* Static global data
*/
static Tcl_Interp * tcl_interp ; /* Script interpreter */
int
InitScript(
void /* Nothing */
) /* Return okay or not */
{
char * pstr ;
FILE * infile ;
int retval ;
int rc ;
size_t filesize ;
tcl_interp = Tcl_CreateInterp() ;
if ( tcl_interp == NULL )
{
fprintf( stderr, "Could not create interpreter!\n" ) ;
return 1 ;
}
/* Register the commands specific to my application
Tcl_CreateObjCommand( tcl_interp, "session", GppSessionCmd,
(ClientData) NULL, GppDummyDestroy ) ;
/* Read the configuration file with specific script code
(in reality, I use a function that searches for the file and opens it!
Hence I need to do more work ... If you have the file name, then use
Tcl_EvalFile()!)
*/
infile = fopen( "scripts.conf", "r" ) ;
if ( infile == NULL )
{
return 1 ;
}
/* Now, read the whole file ...
*/
fseek( infile, 0L, SEEK_END ) ;
filesize = ftell( infile ) ;
pstr = (char * ) malloc( (filesize+1) * sizeof(char) ) ;
if ( pstr == NULL )
{
return 1;
}
fseek( infile, 0L, SEEK_SET ) ;
fread( pstr, filesize, 1, infile ) ;
pstr[filesize] = '\0' ;
rc = Tcl_Eval( tcl_interp, pstr ) ;
if ( rc != TCL_OK )
{
fprintf( stderr, "Error loading script library\n" ) ;
return 1 ;
}
free( pstr ) ;
return 0;
}
/* Function for encapsulating the details
*/
EvalScriptCommand(
char * command )
{
if ( Tcl_Eval( tcl_interp, command ) == TCL_OK )
{
return 0 ;
}
else
{
return 1 ;
}
}
//compile with g++ and run using ./exec
======
----
**Second Example of Invoking Tcl from a C Application**
David Gravereaux writes, on comp.lang.tcl, this code fragment for invoking Tcl from a C program:
======c
Tcl_Interp *interp;
int Init (char *argv0)
{
Tcl_FindExecutable(argv0);
interp = Tcl_CreateInterp();
if (Tcl_Init(interp) != TCL_OK) {
return TCL_ERROR;
}
return TCL_OK;
}
void TearDown () {Tcl_Finalize();}
int EvalFile (char *fileName)
{
return Tcl_EvalFile(interp, fileName);
}
======
If EvalFile() returns TCL_ERROR, get the error with `Tcl_GetStringResult()` .
----
**Wrap C/C++ code to make it callable from Tcl**
[[Replace this line with a pointer or details]]
----
**See also**
* [Writing Tcl-Based Applications in C]
<> Tutorial