home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
tcltk805.zip
/
tcl805s.zip
/
tcl8.0.5
/
os2
/
tclOS2Main.c
< prev
next >
Wrap
C/C++ Source or Header
|
2001-02-09
|
14KB
|
437 lines
/*
* tclOS2Main.c --
*
* Main program for Tcl shells and other Tcl-based applications.
*
* Copyright (c) 1988-1994 The Regents of the University of California.
* Copyright (c) 1994 Sun Microsystems, Inc.
* Copyright (c) 1996-2001 Illya Vaes
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tclOS2Int.h"
static Tcl_Interp *interp; /* Interpreter for application. */
#ifdef TCL_MEM_DEBUG
static char dumpFile[100]; /* Records where to dump memory allocation
* information. */
static int quitFlag = 0; /* 1 means the "checkmem" command was
* invoked, so the application should quit
* and dump memory allocation information. */
#endif
/*
* Forward references for procedures defined later in this file:
*/
static void TclOS2Panic TCL_VARARGS(char *,format);
#ifdef TCL_MEM_DEBUG
static int CheckmemCmd _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp, int argc, char *argv[]));
#endif
/*
*----------------------------------------------------------------------
*
* Tcl_Main --
*
* Main program for tclsh and most other Tcl-based applications.
*
* Results:
* None. This procedure never returns (it exits the process when
* it's done.
*
* Side effects:
* This procedure initializes the Tcl world and then starts
* interpreting commands; almost anything could happen, depending
* on the script being interpreted.
*
*----------------------------------------------------------------------
*/
#ifndef CLI_VERSION
static char consoleScript[] = "\n\
set loaded [info loaded {}]\n\
if ![auto_load tkConInit] {\n\
error \"cannot start tkcon\"\n\
}\n\
foreach pkg $loaded {\n\
set name [lindex $pkg 1]\n\
set version [package require $name]\n\
slave eval package require $name $version\n\
unset name version\n\
}\n\
catch {unset pkg}\n\
unset loaded\n\
";
#endif
void
Tcl_Main(argc, argv, appInitProc)
int argc; /* Number of arguments. */
char **argv; /* Array of argument strings. */
Tcl_AppInitProc *appInitProc; /* Application-specific initialization
* procedure to call after most
* initialization but before starting
* to execute commands. */
{
Tcl_Obj *prompt1NamePtr = NULL;
Tcl_Obj *prompt2NamePtr = NULL;
Tcl_Obj *commandPtr = NULL;
char cbuf[1000], *args, *fileName;
int code, gotPartial, tty;
int exitCode = 0;
Tcl_Channel inChannel, outChannel;
Tcl_Obj *resultPtr;
char *bytes;
int length;
Tcl_Channel errChannel;
BOOL usePm = TclOS2GetUsePm();
HWND hTerminal;
/* Set Panic procedure */
Tcl_SetPanicProc(TclOS2Panic);
Tcl_FindExecutable(argv[0]);
interp = Tcl_CreateInterp();
#ifdef TCL_MEM_DEBUG
Tcl_InitMemory(interp);
Tcl_CreateCommand(interp, "checkmem", CheckmemCmd, (ClientData) 0,
(Tcl_CmdDeleteProc *) NULL);
#endif
/*
* Make command-line arguments available in the Tcl variables "argc"
* and "argv". If the first argument doesn't start with a "-" then
* strip it off and use it as the name of a script file to process.
*/
fileName = NULL;
if ((argc > 1) && (argv[1][0] != '-')) {
fileName = argv[1];
argc--;
argv++;
}
args = Tcl_Merge(argc-1, argv+1);
Tcl_SetVar(interp, "argv", args, TCL_GLOBAL_ONLY);
ckfree(args);
sprintf(cbuf, "%d", argc-1);
Tcl_SetVar(interp, "argc", cbuf, TCL_GLOBAL_ONLY);
Tcl_SetVar(interp, "argv0", (fileName != NULL) ? fileName : argv[0],
TCL_GLOBAL_ONLY);
/*
* Set the "tcl_interactive" variable.
*/
tty = isatty(0);
Tcl_SetVar(interp, "tcl_interactive",
((fileName == NULL) && tty) ? "1" : "0", TCL_GLOBAL_ONLY);
/*
* Invoke application-specific initialization.
*/
if ((*appInitProc)(interp) != TCL_OK) {
if (usePm) {
sprintf(cbuf, "application-specific initialization failed: %s\n",
interp->result);
WinMessageBox(HWND_DESKTOP, NULLHANDLE, cbuf, "Tclsh",
0, MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL);
} else {
errChannel = Tcl_GetStdChannel(TCL_STDERR);
if (errChannel) {
Tcl_Write(errChannel,
"application-specific initialization failed: ", -1);
Tcl_Write(errChannel, Tcl_GetStringResult(interp), -1);
Tcl_Write(errChannel, "\n", 1);
}
}
}
/*
* If a script file was specified then just source that file
* and quit.
*/
if (fileName != NULL) {
code = Tcl_EvalFile(interp, fileName);
if (code != TCL_OK) {
if (usePm) {
sprintf(cbuf, "%s\n", interp->result);
WinMessageBox(HWND_DESKTOP, NULLHANDLE, cbuf, "Tclsh", 0,
MB_OK | MB_ERROR | MB_APPLMODAL);
} else {
errChannel = Tcl_GetStdChannel(TCL_STDERR);
if (errChannel) {
/*
* The following statement guarantees that the errorInfo
* variable is set properly.
*/
Tcl_AddErrorInfo(interp, "");
Tcl_Write(errChannel,
Tcl_GetVar(interp, "errorInfo",TCL_GLOBAL_ONLY),-1);
Tcl_Write(errChannel, "\n", 1);
}
}
exitCode = 1;
}
goto done;
}
/*
* We're running interactively. Source a user-specific startup
* file if the application specified one and if the file exists.
*/
Tcl_SourceRCFile(interp);
/*
* If standard input is a terminal-like device and the variable
* NoTkCon is not set, try to start up TkCon. If this fails,
* just continue with the original console.
*/
if (usePm) {
if (tty && !Tcl_GetVar(interp, "NoTkCon", TCL_GLOBAL_ONLY) &&
Tcl_GlobalEval(interp, consoleScript) == TCL_OK) {
while (Tcl_DoOneEvent(0)) {
/* empty body loop */
}
exitCode = 0;
goto done;
}
/*
* Create and display the console window.
*/
hTerminal = CreateTerminal(TclOS2GetHAB(), interp);
if (hTerminal == NULLHANDLE) {
WinMessageBox(HWND_DESKTOP, NULLHANDLE, "Cannot create Terminal",
"Tclsh", 0, MB_OK | MB_ERROR | MB_APPLMODAL);
/* Don't forget to cleanly exit PM */
TclOS2PMShutdown();
return;
}
}
/*
* Process commands from stdin until there's an end-of-file.
*/
commandPtr = Tcl_NewObj();
Tcl_IncrRefCount(commandPtr);
prompt1NamePtr = Tcl_NewStringObj("tcl_prompt1", -1);
Tcl_IncrRefCount(prompt1NamePtr);
prompt2NamePtr = Tcl_NewStringObj("tcl_prompt2", -1);
Tcl_IncrRefCount(prompt2NamePtr);
inChannel = Tcl_GetStdChannel(TCL_STDIN);
outChannel = Tcl_GetStdChannel(TCL_STDOUT);
gotPartial = 0;
while (1) {
if (usePm) {
Tcl_DoOneEvent(0);
} else {
if (tty) {
Tcl_Obj *promptCmdPtr;
promptCmdPtr = Tcl_ObjGetVar2(interp,
(gotPartial? prompt2NamePtr : prompt1NamePtr),
(Tcl_Obj *) NULL, TCL_GLOBAL_ONLY);
if (promptCmdPtr == NULL) {
defaultPrompt:
if (!gotPartial && outChannel) {
Tcl_Write(outChannel, "% ", 2);
}
} else {
code = Tcl_EvalObj(interp, promptCmdPtr);
inChannel = Tcl_GetStdChannel(TCL_STDIN);
outChannel = Tcl_GetStdChannel(TCL_STDOUT);
errChannel = Tcl_GetStdChannel(TCL_STDERR);
if (code != TCL_OK) {
if (errChannel) {
resultPtr = Tcl_GetObjResult(interp);
bytes = Tcl_GetStringFromObj(resultPtr,&length);
Tcl_Write(errChannel, bytes, length);
Tcl_Write(errChannel, "\n", 1);
}
Tcl_AddErrorInfo(interp,
"\n (script that generates prompt)");
goto defaultPrompt;
} else if (*interp->result && outChannel) {
Tcl_Write(outChannel, interp->result,
strlen(interp->result));
}
}
if (outChannel) {
Tcl_Flush(outChannel);
}
}
if (!inChannel) {
goto done;
}
length = Tcl_GetsObj(inChannel, commandPtr);
if (length < 0) {
goto done;
}
if ((length == 0) && Tcl_Eof(inChannel) && (!gotPartial)) {
goto done;
}
/*
* Add the newline removed by Tcl_GetsObj back to the string.
*/
Tcl_AppendToObj(commandPtr, "\n", 1);
if (!TclObjCommandComplete(commandPtr)) {
gotPartial = 1;
continue;
}
gotPartial = 0;
code = Tcl_RecordAndEvalObj(interp, commandPtr, 0);
inChannel = Tcl_GetStdChannel(TCL_STDIN);
outChannel = Tcl_GetStdChannel(TCL_STDOUT);
errChannel = Tcl_GetStdChannel(TCL_STDERR);
Tcl_SetObjLength(commandPtr, 0);
if (code != TCL_OK) {
if (errChannel) {
resultPtr = Tcl_GetObjResult(interp);
bytes = Tcl_GetStringFromObj(resultPtr, &length);
Tcl_Write(errChannel, bytes, length);
Tcl_Write(errChannel, "\n", 1);
}
} else if (tty) {
resultPtr = Tcl_GetObjResult(interp);
bytes = Tcl_GetStringFromObj(resultPtr, &length);
if ((length > 0) && outChannel) {
Tcl_Write(outChannel, bytes, length);
Tcl_Write(outChannel, "\n", 1);
}
}
#ifdef TCL_MEM_DEBUG
if (quitFlag) {
Tcl_DecrRefCount(commandPtr);
Tcl_DecrRefCount(prompt1NamePtr);
Tcl_DecrRefCount(prompt2NamePtr);
Tcl_DeleteInterp(interp);
Tcl_Exit(0);
}
#endif
}
}
/*
* Rather than calling exit, invoke the "exit" command so that
* users can replace "exit" with some other command to do additional
* cleanup on exit. The Tcl_Eval call should never return.
*/
done:
if (commandPtr != NULL) {
Tcl_DecrRefCount(commandPtr);
}
if (prompt1NamePtr != NULL) {
Tcl_DecrRefCount(prompt1NamePtr);
}
if (prompt2NamePtr != NULL) {
Tcl_DecrRefCount(prompt2NamePtr);
}
sprintf(cbuf, "exit %d", exitCode);
Tcl_Eval(interp, cbuf);
}
/*
*----------------------------------------------------------------------
*
* CheckmemCmd --
*
* This is the command procedure for the "checkmem" command, which
* causes the application to exit after printing information about
* memory usage to the file passed to this command as its first
* argument.
*
* Results:
* Returns a standard Tcl completion code.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
#ifdef TCL_MEM_DEBUG
/* ARGSUSED */
static int
CheckmemCmd(clientData, interp, argc, argv)
ClientData clientData; /* Not used. */
Tcl_Interp *interp; /* Interpreter for evaluation. */
int argc; /* Number of arguments. */
char *argv[]; /* String values of arguments. */
{
if (argc != 2) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" fileName\"", (char *) NULL);
return TCL_ERROR;
}
strcpy(dumpFile, argv[1]);
quitFlag = 1;
return TCL_OK;
}
#endif
/*
*----------------------------------------------------------------------
*
* TclOS2Panic --
*
* Display a message and exit.
*
* Results:
* None.
*
* Side effects:
* Exits the program.
*
*----------------------------------------------------------------------
*/
void
TclOS2Panic TCL_VARARGS_DEF(char *,arg1)
{
va_list argList;
char buf[1024];
char *format;
format = TCL_VARARGS_START(char *,arg1,argList);
vsprintf(buf, format, argList);
#ifdef VERBOSE
printf("TclOS2Panic: %s\n", buf);
fflush(stdout);
fflush(stderr);
#endif
#ifndef CLI_VERSION
/* Make sure pointer is not captured (for WinMessageBox) */
WinSetCapture(HWND_DESKTOP, NULLHANDLE);
WinAlarm(HWND_DESKTOP, WA_ERROR);
WinMessageBox(HWND_DESKTOP, NULLHANDLE, buf, "Fatal Error in Tclsh", 0,
MB_OK | MB_ERROR | MB_APPLMODAL);
TclOS2PMShutdown();
#else
fprintf(stderr, "FATAL: %s\n", buf);
TclOS2PMShutdown();
#endif
exit(1);
}