*** win/tclAppInit.c 21 Feb 2002 21:20:08 -0000 1.8 --- win/tclAppInit.c 29 Sep 2002 00:43:00 -0000 *************** *** 29,34 **** --- 29,39 ---- #endif /* TCL_TEST */ static void setargv _ANSI_ARGS_((int *argcPtr, char ***argvPtr)); + static BOOL __stdcall sigHandler (DWORD fdwCtrlType); + static Tcl_AsyncProc asyncExit; + + Tcl_AsyncHandler exitToken; + DWORD exitErrorCode; /* *************** *** 135,140 **** --- 140,151 ---- return TCL_ERROR; } + /* + * Install a signal handler to the win32 console tclsh is running in. + */ + SetConsoleCtrlHandler(sigHandler, TRUE); + exitToken = Tcl_AsyncCreate(asyncExit, NULL); + #ifdef TCL_TEST if (Tcltest_Init(interp) == TCL_ERROR) { return TCL_ERROR; *************** *** 299,301 **** --- 310,379 ---- *argcPtr = argc; *argvPtr = argv; } + + /* + *---------------------------------------------------------------------- + * + * asyncExit -- + * + * The AsyncProc for the exitToken. + * + * Results: + * doesn't actually return. + * + * Side effects: + * tclsh cleanly exits. + * + *---------------------------------------------------------------------- + */ + + int + asyncExit (ClientData clientData, Tcl_Interp *interp, int code) + { + Tcl_Exit((int)exitErrorCode); + + /* NOTREACHED */ + return code; + } + + /* + *---------------------------------------------------------------------- + * + * sigHandler -- + * + * Signal handler for the Win32 OS. Catches Ctrl+C, Ctrl+Break and + * other exits. This is needed so tclsh can do it's real clean-up + * and not an unclean crash terminate. + * + * Results: + * TRUE. + * + * Side effects: + * Effects the way the app exits from a signal. This is an + * operating system supplied thread and unsafe to call ANY + * Tcl commands except for Tcl_AsyncMark. + * + *---------------------------------------------------------------------- + */ + + BOOL __stdcall + sigHandler(DWORD fdwCtrlType) + { + /* + * If Tcl is currently executing some bytecode or in the eventloop, + * this will cause Tcl to enter asyncExit at the next command + * boundry. + */ + exitErrorCode = fdwCtrlType; + Tcl_AsyncMark(exitToken); + + /* + * This will cause Tcl_Gets in Tcl_Main() to drop-out with an + * should it be blocked on input and our Tcl_AsyncMark didn't grab + * the attention of the interpreter. + */ + /* CloseHandle(GetStdHandle(STD_INPUT_HANDLE)); */ + + /* indicate to the OS not to call the default terminator */ + return TRUE; + }