| [ Team LiB ] |
|
Tcl_Main and Tcl_AppInitThis section describes how to make a custom main program that includes Tcl. However, the need for custom main programs has been reduced by the use of loadable modules. If you create your commands as a loadable package, you can just load them into tclsh or wish. Even if you do not need a custom main, this section will explain how all the pieces fit together. The Tcl library supports the basic application structure through the Tcl_Main procedure that is designed to be called from your main program. Tcl_Main does three things:
You call Tcl_Main from your main program and provide an implementation of the Tcl_AppInit procedure: Example 47-13 A canonical Tcl main program and Tcl_AppInit
/* main.c */
#include <tcl.h>
int Tcl_AppInit(Tcl_Interp *interp);
/*
* Declarations for application-specific command procedures
*/
int Plus1ObjCmd(ClientData clientData,
Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]);
main(int argc, char *argv[]) {
/*
* Initialize your application,
* then initialize and run Tcl.
*/
Tcl_Main(argc, argv, Tcl_AppInit);
exit(0);
}
/*
* Tcl_AppInit is called from Tcl_Main after the Tcl
* interpreter has been created, and before the script file
* or interactive command loop is entered.
*/
int
Tcl_AppInit(Tcl_Interp *interp) {
/*
* Tcl_Init reads init.tcl from the Tcl script library.
*/
if (Tcl_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
/*
* Register application-specific commands.
*/
Tcl_CreateObjCommand(interp, "plus1", Plus1ObjCmd,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Random_Init(interp);
Blob_Init(interp);
/*
* This file is read if no script is supplied.
*/
Tcl_SetVar(interp, "tcl_rcFileName", "~/.mytcl",
TCL_GLOBAL_ONLY);
/*
* Test of Tcl_Invoke, which is defined on page 725.
*/
Tcl_Invoke(interp, "set", "foo", "$xyz [foo] {", NULL);
return TCL_OK;
}
The main program calls Tcl_Main with the argc and argv parameters passed into the program. These are the strings passed to the program on the command line, and Tcl_Main will store these values into Tcl variables by the same name. Tcl_Main is also given the address of the initialization procedure, which is Tcl_AppInit in our example. Tcl_AppInit is called by Tcl_Main with one argument, a handle on a newly created interpreter. There are three parts to the Tcl_AppInit procedure:
You can use your custom program just like tclsh, except that it includes the additional commands you define in your Tcl_AppInit procedure. The sample makefile on the CD creates a program named mytcl. You can compile and run that program and test random and the other commands. Tk_MainThe structure of Tk applications is similar. The Tk_Main procedure creates a Tcl interpreter and the main Tk window. It calls out to a procedure you provide to complete initialization. After your Tk_AppInit returns, Tk_Main goes into an event loop until all the windows in your application have been destroyed. Example 47-14 shows a Tk_AppInit used with Tk_Main. The main program processes its own command-line arguments using Tk_ParseArgv, which requires a Tcl interpreter for error reporting. The Tk_AppInit procedure initializes the clock widget example that is the topic of Chapter 49: Example 47-14 A canonical Tk main program and Tk_AppInit
/* main.c */
#include <tk.h>
int Tk_AppInit(Tcl_Interp *interp);
/*
* A table for command line arguments.
*/
char *myoption1 = NULL;
int myint2 = 0;
static Tk_ArgvInfo argTable[] = {
{"-myoption1", TK_ARGV_STRING, (char *) NULL,
(char *) &myoption1, "Explain myoption1"},
{"-myint2", TK_ARGV_CONSTANT, (char *) 1, (char *) &myint2,
"Explain myint2"},
{"", TK_ARGV_END, },
};
main(int argc, char *argv[]) {
Tcl_Interp *interp;
/*
* Call this before creating any interpreters.
*/
Tcl_FindExecutable();
/*
* Create an interpreter for the error message from
* Tk_ParseArgv. Another one is created by Tk_Main.
* Parse our arguments and leave the rest to Tk_Main.
*/
interp = Tcl_CreateInterp();
if (Tk_ParseArgv(interp, (Tk_Window) NULL, &argc, argv,
argTable, 0) != TCL_OK) {
fprintf(stderr, "%s\n", interp->result);
exit(1);
}
Tcl_DeleteInterp(interp);
Tk_Main(argc, argv, Tk_AppInit);
exit(0);
}
int ClockCmd(ClientData clientData,
Tcl_Interp *interp,
int argc, CONST char *argv[]);
int ClockObjCmd(ClientData clientData,
Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]);
void ClockObjDestroy(ClientData clientData);
int
Tk_AppInit(Tcl_Interp *interp) {
/*
* Initialize packages
*/
if (Tcl_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
if (Tk_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
/*
* Define application-specific commands here.
*/
Tcl_CreateCommand(interp, "wclock", ClockCmd,
(ClientData)Tk_MainWindow(interp),
(Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "oclock", ClockObjCmd,
(ClientData)NULL, ClockObjDestroy);
/*
* Define start-up filename. This file is read in
* case the program is run interactively.
*/
Tcl_SetVar(interp, "tcl_rcFileName", "~/.mytcl",
TCL_GLOBAL_ONLY);
return TCL_OK;
}
|
| [ Team LiB ] |
|