/*** *assert.c - Display a message and abort * * Copyright (c) 1988-1997, Microsoft Corporation. All rights reserved. * *Purpose: * *******************************************************************************/ #ifdef _WIN32 #include #include #include #include #include #include #include #include #include #ifdef NDEBUG #undef NDEBUG #endif /* NDEBUG */ #define _ASSERT_OK #include /* * assertion format string for use with output to stderr */ static char _assertstring[] = "Assertion failed: %s, file %s, line %d\n"; /* Format of MessageBox for assertions: * * ================= Microsft Visual C++ Debug Library ================ * * Assertion Failed! * * Program: c:\test\mytest\foo.exe * File: c:\test\mytest\bar.c * Line: 69 * * Expression: * * For information on how your program can cause an assertion * failure, see the Visual C++ documentation on asserts * * (Press Retry to debug the application - JIT must be enabled) * * =================================================================== */ /* * assertion string components for message box */ #define BOXINTRO "Assertion failed!" #define PROGINTRO "Program: " #define FILEINTRO "File: " #define LINEINTRO "Line: " #define EXPRINTRO "Expression: " #define INFOINTRO "For information on how your program can cause an assertion\n" \ "failure, see the Visual C++ documentation on asserts" #define HELPINTRO "(Press Retry to debug the application - JIT must be enabled)" static char * dotdotdot = "..."; static char * newline = "\n"; static char * dblnewline = "\n\n"; #define DOTDOTDOTSZ 3 #define NEWLINESZ 1 #define DBLNEWLINESZ 2 #define MAXLINELEN 60 /* max length for line in message box */ #define ASSERTBUFSZ (MAXLINELEN * 9) /* 9 lines in message box */ #if defined (_M_IX86) #define _DbgBreak() __asm { int 3 } #elif defined (_M_ALPHA) void _BPT(); #pragma intrinsic(_BPT) #define _DbgBreak() _BPT() #else /* defined (_M_ALPHA) */ #define _DbgBreak() DebugBreak() #endif /* defined (_M_ALPHA) */ /*** *_assert() - Display a message and abort * *Purpose: * The assert macro calls this routine if the assert expression is * true. By placing the assert code in a subroutine instead of within * the body of the macro, programs that call assert multiple times will * save space. * *Entry: * *Exit: * *Exceptions: * *******************************************************************************/ void __cdecl _assert ( void *expr, void *filename, unsigned lineno ) { /* * Build the assertion message, then write it out. The exact form * depends on whether it is to be written out via stderr or the * MessageBox API. */ if ( (__error_mode == _OUT_TO_STDERR) || ((__error_mode == _OUT_TO_DEFAULT) && (__app_type == _CONSOLE_APP)) ) { /* * Build message and write it out to stderr. It will be of the * form: * Assertion failed: , file , line */ if ( !anybuf(stderr) ) /* * stderr is unused, hence unbuffered, as yet. set it to * single character buffering (to avoid a malloc() of a * stream buffer). */ (void) setvbuf(stderr, NULL, _IONBF, 0); fprintf(stderr, _assertstring, expr, filename, lineno); fflush(stderr); } else { int nCode; char * pch; char assertbuf[ASSERTBUFSZ]; char progname[MAX_PATH]; /* * Line 1: box intro line */ strcpy( assertbuf, BOXINTRO ); strcat( assertbuf, dblnewline ); /* * Line 2: program line */ strcat( assertbuf, PROGINTRO ); if ( !GetModuleFileName( NULL, progname, MAX_PATH )) strcpy( progname, ""); pch = (char *)progname; /* sizeof(PROGINTRO) includes the NULL terminator */ if ( sizeof(PROGINTRO) + strlen(progname) + NEWLINESZ > MAXLINELEN ) { pch += (sizeof(PROGINTRO) + strlen(progname) + NEWLINESZ) - MAXLINELEN; strncpy( pch, dotdotdot, DOTDOTDOTSZ ); } strcat( assertbuf, pch ); strcat( assertbuf, newline ); /* * Line 3: file line */ strcat( assertbuf, FILEINTRO ); /* sizeof(FILEINTRO) includes the NULL terminator */ if ( sizeof(FILEINTRO) + strlen(filename) + NEWLINESZ > MAXLINELEN ) { /* too long. use only the first part of the filename string */ strncat( assertbuf, filename, MAXLINELEN - sizeof(FILEINTRO) - DOTDOTDOTSZ - NEWLINESZ ); /* append trailing "..." */ strcat( assertbuf, dotdotdot ); } else /* plenty of room on the line, just append the filename */ strcat( assertbuf, filename ); strcat( assertbuf, newline ); /* * Line 4: line line */ strcat( assertbuf, LINEINTRO ); _itoa( lineno, assertbuf + strlen(assertbuf), 10 ); strcat( assertbuf, dblnewline ); /* * Line 5: message line */ strcat( assertbuf, EXPRINTRO ); /* sizeof(HELPINTRO) includes the NULL terminator */ if ( strlen(assertbuf) + strlen(expr) + 2*DBLNEWLINESZ + sizeof(INFOINTRO)-1 + sizeof(HELPINTRO) > ASSERTBUFSZ ) { strncat( assertbuf, expr, ASSERTBUFSZ - (strlen(assertbuf) + DOTDOTDOTSZ + 2*DBLNEWLINESZ + sizeof(INFOINTRO)-1 + sizeof(HELPINTRO)) ); strcat( assertbuf, dotdotdot ); } else strcat( assertbuf, expr ); strcat( assertbuf, dblnewline ); /* * Line 6, 7: info line */ strcat(assertbuf, INFOINTRO); strcat( assertbuf, dblnewline ); /* * Line 8: help line */ strcat(assertbuf, HELPINTRO); /* * Write out via MessageBox */ nCode = __crtMessageBoxA(assertbuf, "Microsoft Visual C++ Runtime Library", MB_ABORTRETRYIGNORE|MB_ICONHAND|MB_SETFOREGROUND|MB_TASKMODAL); /* Abort: abort the program */ if (nCode == IDABORT) { /* raise abort signal */ raise(SIGABRT); /* We usually won't get here, but it's possible that SIGABRT was ignored. So exit the program anyway. */ _exit(3); } /* Retry: call the debugger */ if (nCode == IDRETRY) { _DbgBreak(); /* return to user code */ return; } /* Ignore: continue execution */ if (nCode == IDIGNORE) return; } abort(); } #else /* _WIN32 */ #include #include #include #include #include #include #include #include #include #undef NDEBUG #define _ASSERT_OK #include #include // get Mac header #include #include #include #include static char _assertstring[] = "Assertion failed: %s, file %s, line %d\n"; extern MPWBLOCK * _pMPWBlock; /*** *_assert() - Display a message and abort * *Purpose: * The assert macro calls this routine if the assert expression is * true. By placing the assert code in a subroutine instead of within * the body of the macro, programs that call assert multiple times will * save space. * *Entry: * *Exit: * *Exceptions: * *******************************************************************************/ #define addrMacJmp24 0x120 #define addrMacJmp32 0xbff void _CALLTYPE1 _assert ( void *expr, void *filename, unsigned lineno ) { char rgch[512]; long lrespond; OSErr osErr; long *pl; unsigned char ch; char *pch; int cb; if (_pMPWBlock != NULL) { /* * This is the original CRT32 code. */ if ( !anybuf(stderr) ) /* * stderr is unused, hence unbuffered, as yet. set it to * single character buffering (to avoid a malloc() of a * stream buffer). */ (void) setvbuf(stderr, NULL, _IONBF, 0); fprintf(stderr, _assertstring, expr, filename, lineno); fflush(stderr); } else { /* * This assert code will bring up system debugger, most * probably MacsBug if there is a debuuger installed. * If no debugger installed, write to stderr file. * Not sure if this is really working. Need more accurate * info on how MacJmp is set up. */ osErr = Gestalt(gestaltAddressingModeAttr, &lrespond); if (!osErr) { if (!BitTst(&lrespond, 31-gestalt32BitCapable)) { pl = (long *)addrMacJmp24; ch = (unsigned char)(*pl); } else { pch = (char *)addrMacJmp32; ch = *pch; } } if (ch & 0x20) { //test bit 5 for Debugger installed sprintf(rgch, _assertstring, expr, filename, lineno); _c2pstr(rgch); DebugStr(rgch); } else { // freopen("stderr", "wt", stderr); // fprintf(stderr, _assertstring, expr, filename, lineno); cb = sprintf(rgch, _assertstring, expr, filename, lineno); _write(2, rgch, cb); // fflush(stderr); } } abort(); } #endif /* _WIN32 */