diff options
-rw-r--r-- | doc/Panic.3 | 13 | ||||
-rw-r--r-- | generic/tcl.h | 7 | ||||
-rw-r--r-- | generic/tclPanic.c | 2 | ||||
-rw-r--r-- | win/Makefile.in | 6 | ||||
-rw-r--r-- | win/makefile.vc | 6 | ||||
-rw-r--r-- | win/tcl.dsp | 4 | ||||
-rw-r--r-- | win/tclWinError.c | 3 | ||||
-rw-r--r-- | win/tclWinPanic.c | 87 |
8 files changed, 123 insertions, 5 deletions
diff --git a/doc/Panic.3 b/doc/Panic.3 index af86665..fa86908 100644 --- a/doc/Panic.3 +++ b/doc/Panic.3 @@ -7,7 +7,7 @@ .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME -Tcl_Panic, Tcl_PanicVA, Tcl_SetPanicProc \- report fatal error and abort +Tcl_Panic, Tcl_PanicVA, Tcl_SetPanicProc, Tcl_ConsolePanic \- report fatal error and abort .SH SYNOPSIS .nf \fB#include <tcl.h>\fR @@ -21,6 +21,9 @@ void void \fBTcl_SetPanicProc\fR(\fIpanicProc\fR) .sp +void +\fBTcl_ConsolePanic\fR(\fIformat\fR, \fIarg\fR, \fIarg\fR, \fI...\fR) +.sp .SH ARGUMENTS .AS Tcl_PanicProc *panicProc .AP "const char*" format in @@ -54,6 +57,14 @@ message is sent to the debugger in stead. If the windows executable does not have a stderr channel (e.g. \fBwish.exe\fR), then a system dialog box is used to display the panic message. .PP +If your application doesn't use \fBTcl_Main\fR or \fBTk_Main\fR +and you want to implicitly use the stderr channel of your +application's C runtime (in stead of the stderr channel of the +C runtime used by Tcl), you can call \fBTcl_SetPanicProc\fR +with \fBTcl_ConsolePanic\fR as its argument. On platforms which +only have one C runtime (almost all platforms except Windows) +\fBTcl_ConsolePanic\fR is equivalent to NULL. +.PP \fBTcl_SetPanicProc\fR may be used to modify the behavior of \fBTcl_Panic\fR. The \fIpanicProc\fR argument should match the type \fBTcl_PanicProc\fR: diff --git a/generic/tcl.h b/generic/tcl.h index 2ce504f..9b6838b 100644 --- a/generic/tcl.h +++ b/generic/tcl.h @@ -2389,6 +2389,11 @@ const char * Tcl_InitStubs(Tcl_Interp *interp, const char *version, int exact, int magic); const char * TclTomMathInitializeStubs(Tcl_Interp *interp, const char *version, int epoch, int revision); +#if defined(_WIN32) + TCL_NORETURN void Tcl_ConsolePanic(const char *format, ...); +#else +# define Tcl_ConsolePanic ((Tcl_PanicProc *)0) +#endif #ifdef USE_TCL_STUBS #if TCL_RELEASE_LEVEL == TCL_FINAL_RELEASE @@ -2420,7 +2425,7 @@ const char * TclTomMathInitializeStubs(Tcl_Interp *interp, */ #define Tcl_Main(argc, argv, proc) Tcl_MainEx(argc, argv, proc, \ - ((Tcl_CreateInterp)())) + ((Tcl_SetPanicProc(Tcl_ConsolePanic), Tcl_CreateInterp)())) EXTERN void Tcl_MainEx(int argc, char **argv, Tcl_AppInitProc *appInitProc, Tcl_Interp *interp); EXTERN const char * Tcl_PkgInitStubsCheck(Tcl_Interp *interp, diff --git a/generic/tclPanic.c b/generic/tclPanic.c index b03ad41..b50271b 100644 --- a/generic/tclPanic.c +++ b/generic/tclPanic.c @@ -23,7 +23,7 @@ * procedure. */ -#if defined(__CYGWIN__) +#if defined(__CYGWIN__) || (defined(_WIN32) && (defined(TCL_NO_DEPRECATED) || TCL_MAJOR_VERSION > 8)) static TCL_NORETURN Tcl_PanicProc *panicProc = tclWinDebugPanic; #else static TCL_NORETURN1 Tcl_PanicProc *panicProc = NULL; diff --git a/win/Makefile.in b/win/Makefile.in index a3275ba..4132337 100644 --- a/win/Makefile.in +++ b/win/Makefile.in @@ -400,7 +400,8 @@ REG_OBJS = tclWinReg.$(OBJEXT) STUB_OBJS = \ tclStubLib.$(OBJEXT) \ tclTomMathStubLib.$(OBJEXT) \ - tclOOStubLib.$(OBJEXT) + tclOOStubLib.$(OBJEXT) \ + tclWinPanic.$(OBJEXT) TCLSH_OBJS = tclAppInit.$(OBJEXT) @@ -537,6 +538,9 @@ tclTomMathStubLib.${OBJEXT}: tclTomMathStubLib.c tclOOStubLib.${OBJEXT}: tclOOStubLib.c $(CC) -c $(CC_SWITCHES) -DSTATIC_BUILD @DEPARG@ $(CC_OBJNAME) +tclWinPanic.${OBJEXT}: tclWinPanic.c + $(CC) -c $(CC_SWITCHES) -DSTATIC_BUILD @DEPARG@ $(CC_OBJNAME) + # Implicit rule for all object files that will end up in the Tcl library %.${OBJEXT}: %.c diff --git a/win/makefile.vc b/win/makefile.vc index de80452..d270447 100644 --- a/win/makefile.vc +++ b/win/makefile.vc @@ -349,7 +349,8 @@ TCLOBJS = $(COREOBJS) $(ZLIBOBJS) $(TOMMATHOBJS) $(PLATFORMOBJS) TCLSTUBOBJS = \ $(TMP_DIR)\tclStubLib.obj \ $(TMP_DIR)\tclTomMathStubLib.obj \ - $(TMP_DIR)\tclOOStubLib.obj + $(TMP_DIR)\tclOOStubLib.obj \ + $(TMP_DIR)\tclWinPanic.obj ### The following paths CANNOT have spaces in them as they appear on ### the left side of implicit rules. @@ -740,6 +741,9 @@ $(TMP_DIR)\tclTomMathStubLib.obj: $(GENERICDIR)\tclTomMathStubLib.c $(TMP_DIR)\tclOOStubLib.obj: $(GENERICDIR)\tclOOStubLib.c $(cc32) $(stubscflags) -Fo$@ $? +$(TMP_DIR)\tclWinPanic.obj: $(WINDIR)\tclWinPanic.c + $(cc32) $(stubscflags) -Fo$@ $? + $(TMP_DIR)\tclsh.exe.manifest: $(WINDIR)\tclsh.exe.manifest.in @nmakehlp -s << $** >$@ @MACHINE@ $(MACHINE:IX86=X86) diff --git a/win/tcl.dsp b/win/tcl.dsp index ad9c764..731eb1f 100644 --- a/win/tcl.dsp +++ b/win/tcl.dsp @@ -1524,6 +1524,10 @@ SOURCE=.\tclWinNotify.c # End Source File
# Begin Source File
+SOURCE=.\tclWinPanic.c
+# End Source File
+# Begin Source File
+
SOURCE=.\tclWinPipe.c
# End Source File
# Begin Source File
diff --git a/win/tclWinError.c b/win/tclWinError.c index fea4b0f..5d4423b 100644 --- a/win/tclWinError.c +++ b/win/tclWinError.c @@ -406,6 +406,9 @@ tclWinDebugPanic( } OutputDebugStringW(msgString); } else { + if (!isatty(fileno(stderr))) { + fprintf(stderr, "\xef\xbb\xbf"); + } vfprintf(stderr, format, argList); fprintf(stderr, "\n"); fflush(stderr); diff --git a/win/tclWinPanic.c b/win/tclWinPanic.c new file mode 100644 index 0000000..f7d9a72 --- /dev/null +++ b/win/tclWinPanic.c @@ -0,0 +1,87 @@ +/* + * tclWinPanic.c -- + * + * Contains the Windows-specific command-line panic proc. + * + * Copyright (c) 2013 by Jan Nijtmans. + * All rights reserved. + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + */ + +#include "tclInt.h" +/* + *---------------------------------------------------------------------- + * + * Tcl_ConsolePanic -- + * + * Display a message. If a debugger is present, present it directly to + * the debugger, otherwise send it to stderr. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_ConsolePanic( + const char *format, ...) +{ +#define TCL_MAX_WARN_LEN 26000 + va_list argList; + WCHAR msgString[TCL_MAX_WARN_LEN]; + char buf[TCL_MAX_WARN_LEN * TCL_UTF_MAX]; + HANDLE handle = GetStdHandle(STD_ERROR_HANDLE); + DWORD dummy; + + va_start(argList, format); + vsnprintf(buf+3, sizeof(buf)-3, format, argList); + buf[sizeof(buf)-1] = 0; + msgString[TCL_MAX_WARN_LEN-1] = L'\0'; + MultiByteToWideChar(CP_UTF8, 0, buf+3, -1, msgString, TCL_MAX_WARN_LEN); + + /* + * Truncate MessageBox string if it is too long to not overflow the buffer. + */ + + if (msgString[TCL_MAX_WARN_LEN-1] != L'\0') { + memcpy(msgString + (TCL_MAX_WARN_LEN - 5), L" ...", 5 * sizeof(WCHAR)); + } + + if (IsDebuggerPresent()) { + OutputDebugStringW(msgString); + } else if (_isatty(2)) { + WriteConsoleW(handle, msgString, wcslen(msgString), &dummy, 0); + } else { + buf[0] = 0xEF; buf[1] = 0xBB; buf[2] = 0xBF; /* UTF-8 bom */ + WriteFile(handle, buf, 3, &dummy, 0); + FlushFileBuffers(handle); + } +# if defined(__GNUC__) + __builtin_trap(); +# elif defined(_WIN64) + __debugbreak(); +# elif defined(_MSC_VER) + _asm {int 3} +# else + DebugBreak(); +# endif +#if defined(_WIN32) + ExitProcess(1); +#else + abort(); +#endif +} +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * tab-width: 8 + * End: + */ |