#include #include #include "tcltk.h" #include #include #include #include Tcl_Interp *tclInterp=NULL; static Tk_Window tkWin; static char gEnvName[255]; static int tcltkFileExists(const char *filename); /*************************************************************************** T C L T K _ I N I T ***************************************************************************/ int tcltk_init(char *envname, char *tkname, char *interfacename) { tclInterp = Tcl_CreateInterp(); if (Tcl_Init(tclInterp) == TCL_ERROR) { fprintf(stderr, "Couldn't initialize tcl commands: %s", tclInterp->result); return TCL_ERROR; } if (Tk_Init(tclInterp) != TCL_OK) { fprintf(stderr, "Couldn't initialize tk window: %s", tclInterp->result); return 0; } tkWin = Tk_MainWindow(tclInterp); if (tkWin == NULL) { fprintf(stderr, "Couldn't get main Tk window: %s", tclInterp->result); return 0; } Tk_SetClass(tkWin, tkname); // Set argc and argv so they exist since some scripts want them Tcl_SetVar(tclInterp,"argc","0",TCL_GLOBAL_ONLY); Tcl_SetVar(tclInterp,"argv","",TCL_GLOBAL_ONLY); strcpy(gEnvName,envname); tcltk_loadFile(interfacename); return TCL_OK; } void tcltk_loadUserPrefFile(char *filename) { char *homepath = getenv("HOME"); if (homepath==NULL) homepath=""; char str[1024]; strcpy(str,homepath); strcat(str,"/"); strcat(str,filename); if (tcltkFileExists(str)) { tcltk_loadFile(str); } } /*************************************************************************** T C L T K _ L O A D F I L E ***************************************************************************/ void tcltk_loadFile(char *interfacename) { int code=TCL_ERROR; char str[200]; char *scriptDir; if (strlen(interfacename)==0) return; // search for home directory scriptDir = getenv (gEnvName); if (scriptDir != NULL) { strcpy (str, scriptDir); strcat (str, "/"); strcat (str, interfacename); if (tcltkFileExists(str)) { code = Tcl_EvalFile (tclInterp, str); } } if (code!=TCL_OK) { if (tcltkFileExists(interfacename)) { code = Tcl_EvalFile(tclInterp, interfacename); } } if (code != TCL_OK) { fprintf (stderr, "Error in interpreting the tcl script %s \n",interfacename); fprintf (stderr, "Error Code: %s\n", tclInterp->result); char *errMsg = Tcl_GetVar (tclInterp, "errorInfo", TCL_GLOBAL_ONLY); fprintf (stderr,"%s\n",errMsg); exit (-1); } else { char *errMsg = Tcl_GetVar (tclInterp, "errorInfo", TCL_GLOBAL_ONLY); fprintf (stderr,"%s\n",errMsg); } } /*************************************************************************** T C L T K _ E V A L ***************************************************************************/ TclTkStr tcltk_eval(std::string str) { return tcltk_eval(const_cast(str.c_str())); } TclTkStr tcltk_eval(char *str) { int code; char buf[4096]; strcpy(buf,str); // TCL needs writable memory, so we insure that std::string result; code = Tcl_Eval(tclInterp, buf); if (code != TCL_OK) { fprintf (stderr, "Error in eval tcl script %s \n",str); fprintf (stderr, "Error Code: %s\n", tclInterp->result); result = tclInterp->result; char *errMsg = Tcl_GetVar (tclInterp, "errorInfo", TCL_GLOBAL_ONLY); fprintf (stderr,"%s\n",errMsg); } else { result = tclInterp->result; } return result; } /*************************************************************************** T C K T K _ C H E C K E V E N T S ***************************************************************************/ void tcltk_checkEvents(void) { int result; /* process all waiting Tk events */ do { result = Tcl_DoOneEvent (TK_DONT_WAIT); } while (result); } static int globalTerminalFlag = 0; static Tcl_DString globalTerminalCommand; const int kInputBufferSize = 3000; static void StandardInputProc (ClientData data, int mask); void TypePrompt (Tcl_Interp *tclInterp, int partial); int globalStandardInput; char tclprompt[255]; /*************************************************************************** T C L T K _ E N A B L E T T Y I N P U T ***************************************************************************/ void tcltk_enableTtyInput(char *prompt) { globalTerminalFlag = isatty(0); //globalStandardInput = Tcl_GetFile(0, TCL_UNIX_FD); globalStandardInput =0; Tcl_CreateFileHandler (globalStandardInput, TCL_READABLE, StandardInputProc, (ClientData) 0); if (globalTerminalFlag) printf (prompt); Tcl_SetVar(tclInterp, "tcl_interactive", (globalTerminalFlag) ? "1" : "0", TCL_GLOBAL_ONLY); fflush(stdout); Tcl_DStringInit (&globalTerminalCommand); strcpy(tclprompt,prompt); } static void StandardInputProc (ClientData , int ) { char inputString[kInputBufferSize + 1]; static int gotPartialResult = 0; char *command; int count = read(fileno(stdin), inputString, kInputBufferSize); if (count <= 0) { if (!gotPartialResult) { if (globalTerminalFlag) {Tcl_Eval(tclInterp, "exit"); exit(1);} else { Tcl_DeleteFileHandler(0); } return; } else { count = 0; } } // count > 0, we have something to evaluate command = Tcl_DStringAppend(&globalTerminalCommand, inputString, count); if (count != 0) { if ((inputString[count-1] != '\n') && (inputString[count-1] != ';')) { gotPartialResult = 1; if (globalTerminalFlag) TypePrompt(tclInterp, gotPartialResult); return; } if (!Tcl_CommandComplete(command)) { gotPartialResult = 1; if (globalTerminalFlag) TypePrompt(tclInterp, gotPartialResult); return; } } // We've got a good result gotPartialResult = 0; /* * Disable the stdin file handler while evaluating the command; * otherwise if the command re-enters the event loop we might * process commands from stdin before the current command is * finished. Among other things, this will trash the text of the * command being evaluated. */ Tcl_CreateFileHandler(globalStandardInput, 0, StandardInputProc, (ClientData) 0); int code = Tcl_RecordAndEval(tclInterp, command, 0); Tcl_CreateFileHandler(globalStandardInput, TCL_READABLE, StandardInputProc, (ClientData) 0); Tcl_DStringFree(&globalTerminalCommand); if (*(tclInterp->result) != 0) { if ((code != TCL_OK) || (globalTerminalFlag)) { printf("%s\n", tclInterp->result); } } // Output a prompt. if (globalTerminalFlag) { TypePrompt(tclInterp, gotPartialResult); // gotPartialResult == 0 } } void TypePrompt (Tcl_Interp *tclInterp, int partial) { tclInterp=tclInterp; // char *promptCommand = Tcl_GetVar(tclInterp, partial ? "tclPrompt2" : "tclPrompt1", TCL_GLOBAL_ONLY); if (!partial) fputs(tclprompt, stdout); // else fputs("? ", stdout); fflush(stdout); } static int tcltkFileExists(const char *filename) { struct stat st; if (stat(filename, &st) < 0) { if (errno != ENOENT) // stat() failed for a reason other than // "file doesn't exist" perror(filename); return 0; } else return 1; }