home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / assert.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  11KB  |  386 lines

  1. /***
  2. *assert.c - Display a message and abort
  3. *
  4. *       Copyright (c) 1988-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *
  8. *******************************************************************************/
  9.  
  10. #ifdef _WIN32
  11.  
  12. #include <cruntime.h>
  13. #include <windows.h>
  14. #include <file2.h>
  15. #include <internal.h>
  16. #include <stdlib.h>
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include <signal.h>
  20. #include <awint.h>
  21.  
  22. #ifdef NDEBUG
  23. #undef NDEBUG
  24. #endif  /* NDEBUG */
  25. #define _ASSERT_OK
  26. #include <assert.h>
  27.  
  28.  
  29. /*
  30.  * assertion format string for use with output to stderr
  31.  */
  32. static char _assertstring[] = "Assertion failed: %s, file %s, line %d\n";
  33.  
  34. /*      Format of MessageBox for assertions:
  35. *
  36. *       ================= Microsft Visual C++ Debug Library ================
  37. *
  38. *       Assertion Failed!
  39. *
  40. *       Program: c:\test\mytest\foo.exe
  41. *       File: c:\test\mytest\bar.c
  42. *       Line: 69
  43. *
  44. *       Expression: <expression>
  45. *
  46. *       For information on how your program can cause an assertion
  47. *       failure, see the Visual C++ documentation on asserts
  48. *
  49. *       (Press Retry to debug the application - JIT must be enabled)
  50. *
  51. *       ===================================================================
  52. */
  53.  
  54. /*
  55.  * assertion string components for message box
  56.  */
  57. #define BOXINTRO    "Assertion failed!"
  58. #define PROGINTRO   "Program: "
  59. #define FILEINTRO   "File: "
  60. #define LINEINTRO   "Line: "
  61. #define EXPRINTRO   "Expression: "
  62. #define INFOINTRO   "For information on how your program can cause an assertion\n" \
  63.                     "failure, see the Visual C++ documentation on asserts"
  64. #define HELPINTRO   "(Press Retry to debug the application - JIT must be enabled)"
  65.  
  66. static char * dotdotdot = "...";
  67. static char * newline = "\n";
  68. static char * dblnewline = "\n\n";
  69.  
  70. #define DOTDOTDOTSZ 3
  71. #define NEWLINESZ   1
  72. #define DBLNEWLINESZ   2
  73.  
  74. #define MAXLINELEN  60 /* max length for line in message box */
  75. #define ASSERTBUFSZ (MAXLINELEN * 9) /* 9 lines in message box */
  76.  
  77. #if defined (_M_IX86)
  78. #define _DbgBreak() __asm { int 3 }
  79. #elif defined (_M_ALPHA)
  80. void _BPT();
  81. #pragma intrinsic(_BPT)
  82. #define _DbgBreak() _BPT()
  83. #else  /* defined (_M_ALPHA) */
  84. #define _DbgBreak() DebugBreak()
  85. #endif  /* defined (_M_ALPHA) */
  86.  
  87. /***
  88. *_assert() - Display a message and abort
  89. *
  90. *Purpose:
  91. *       The assert macro calls this routine if the assert expression is
  92. *       true.  By placing the assert code in a subroutine instead of within
  93. *       the body of the macro, programs that call assert multiple times will
  94. *       save space.
  95. *
  96. *Entry:
  97. *
  98. *Exit:
  99. *
  100. *Exceptions:
  101. *
  102. *******************************************************************************/
  103.  
  104. void __cdecl _assert (
  105.         void *expr,
  106.         void *filename,
  107.         unsigned lineno
  108.         )
  109. {
  110.         /*
  111.          * Build the assertion message, then write it out. The exact form
  112.          * depends on whether it is to be written out via stderr or the
  113.          * MessageBox API.
  114.          */
  115.         if ( (__error_mode == _OUT_TO_STDERR) || ((__error_mode ==
  116.                _OUT_TO_DEFAULT) && (__app_type == _CONSOLE_APP)) )
  117.         {
  118.             /*
  119.              * Build message and write it out to stderr. It will be of the
  120.              * form:
  121.              *        Assertion failed: <expr>, file <filename>, line <lineno>
  122.              */
  123.             if ( !anybuf(stderr) )
  124.             /*
  125.              * stderr is unused, hence unbuffered, as yet. set it to
  126.              * single character buffering (to avoid a malloc() of a
  127.              * stream buffer).
  128.              */
  129.              (void) setvbuf(stderr, NULL, _IONBF, 0);
  130.  
  131.             fprintf(stderr, _assertstring, expr, filename, lineno);
  132.             fflush(stderr);
  133.         }
  134.         else {
  135.             int nCode;
  136.             char * pch;
  137.             char assertbuf[ASSERTBUFSZ];
  138.             char progname[MAX_PATH];
  139.  
  140.             /*
  141.              * Line 1: box intro line
  142.              */
  143.             strcpy( assertbuf, BOXINTRO );
  144.             strcat( assertbuf, dblnewline );
  145.  
  146.             /*
  147.              * Line 2: program line
  148.              */
  149.             strcat( assertbuf, PROGINTRO );
  150.  
  151.             if ( !GetModuleFileName( NULL, progname, MAX_PATH ))
  152.                 strcpy( progname, "<program name unknown>");
  153.  
  154.             pch = (char *)progname;
  155.  
  156.             /* sizeof(PROGINTRO) includes the NULL terminator */
  157.             if ( sizeof(PROGINTRO) + strlen(progname) + NEWLINESZ > MAXLINELEN )
  158.             {
  159.                 pch += (sizeof(PROGINTRO) + strlen(progname) + NEWLINESZ) - MAXLINELEN;
  160.                 strncpy( pch, dotdotdot, DOTDOTDOTSZ );
  161.             }
  162.  
  163.             strcat( assertbuf, pch );
  164.             strcat( assertbuf, newline );
  165.  
  166.             /*
  167.              * Line 3: file line
  168.              */
  169.             strcat( assertbuf, FILEINTRO );
  170.  
  171.             /* sizeof(FILEINTRO) includes the NULL terminator */
  172.             if ( sizeof(FILEINTRO) + strlen(filename) + NEWLINESZ >
  173.                  MAXLINELEN )
  174.             {
  175.                 /* too long. use only the first part of the filename string */
  176.                 strncat( assertbuf, filename, MAXLINELEN - sizeof(FILEINTRO)
  177.                          - DOTDOTDOTSZ - NEWLINESZ );
  178.                 /* append trailing "..." */
  179.                 strcat( assertbuf, dotdotdot );
  180.             }
  181.             else
  182.                 /* plenty of room on the line, just append the filename */
  183.                 strcat( assertbuf, filename );
  184.  
  185.             strcat( assertbuf, newline );
  186.  
  187.             /*
  188.              * Line 4: line line
  189.              */
  190.             strcat( assertbuf, LINEINTRO );
  191.             _itoa( lineno, assertbuf + strlen(assertbuf), 10 );
  192.             strcat( assertbuf, dblnewline );
  193.  
  194.             /*
  195.              * Line 5: message line
  196.              */
  197.             strcat( assertbuf, EXPRINTRO );
  198.  
  199.             /* sizeof(HELPINTRO) includes the NULL terminator */
  200.  
  201.             if (    strlen(assertbuf) +
  202.                     strlen(expr) +
  203.                     2*DBLNEWLINESZ +
  204.                     sizeof(INFOINTRO)-1 +
  205.                     sizeof(HELPINTRO) > ASSERTBUFSZ )
  206.             {
  207.                 strncat( assertbuf, expr,
  208.                     ASSERTBUFSZ -
  209.                     (strlen(assertbuf) +
  210.                     DOTDOTDOTSZ +
  211.                     2*DBLNEWLINESZ +
  212.                     sizeof(INFOINTRO)-1 +
  213.                     sizeof(HELPINTRO)) );
  214.                 strcat( assertbuf, dotdotdot );
  215.             }
  216.             else
  217.                 strcat( assertbuf, expr );
  218.  
  219.             strcat( assertbuf, dblnewline );
  220.  
  221.             /*
  222.              * Line 6, 7: info line
  223.              */
  224.  
  225.             strcat(assertbuf, INFOINTRO);
  226.             strcat( assertbuf, dblnewline );
  227.  
  228.             /*
  229.              * Line 8: help line
  230.              */
  231.             strcat(assertbuf, HELPINTRO);
  232.  
  233.             /*
  234.              * Write out via MessageBox
  235.              */
  236.  
  237.             nCode = __crtMessageBoxA(assertbuf,
  238.                 "Microsoft Visual C++ Runtime Library",
  239.                 MB_ABORTRETRYIGNORE|MB_ICONHAND|MB_SETFOREGROUND|MB_TASKMODAL);
  240.  
  241.             /* Abort: abort the program */
  242.             if (nCode == IDABORT)
  243.             {
  244.                 /* raise abort signal */
  245.                 raise(SIGABRT);
  246.  
  247.                 /* We usually won't get here, but it's possible that
  248.                    SIGABRT was ignored.  So exit the program anyway. */
  249.  
  250.                 _exit(3);
  251.             }
  252.  
  253.             /* Retry: call the debugger */
  254.             if (nCode == IDRETRY)
  255.             {
  256.                 _DbgBreak();
  257.                 /* return to user code */
  258.                 return;
  259.             }
  260.  
  261.             /* Ignore: continue execution */
  262.             if (nCode == IDIGNORE)
  263.                 return;
  264.         }
  265.  
  266.         abort();
  267. }
  268.  
  269. #else  /* _WIN32 */
  270.  
  271. #include <cruntime.h>
  272. #include <stdlib.h>
  273. #include <string.h>
  274. #include <io.h>
  275. #include <stdio.h>
  276. #include <msdos.h>
  277. #include <internal.h>
  278. #include <file2.h>
  279. #include <mpw.h>
  280.  
  281. #undef NDEBUG
  282. #define _ASSERT_OK
  283. #include <assert.h>
  284.  
  285. #include <macos\types.h>    // get Mac header
  286. #include <macos\traps.h>
  287. #include <macos\osutils.h>
  288. #include <macos\gestalte.h>
  289. #include <macos\toolutil.h>
  290.  
  291. static char _assertstring[] = "Assertion failed: %s, file %s, line %d\n";
  292. extern MPWBLOCK * _pMPWBlock;
  293.  
  294.  
  295. /***
  296. *_assert() - Display a message and abort
  297. *
  298. *Purpose:
  299. *       The assert macro calls this routine if the assert expression is
  300. *       true.  By placing the assert code in a subroutine instead of within
  301. *       the body of the macro, programs that call assert multiple times will
  302. *       save space.
  303. *
  304. *Entry:
  305. *
  306. *Exit:
  307. *
  308. *Exceptions:
  309. *
  310. *******************************************************************************/
  311.  
  312. #define addrMacJmp24   0x120
  313. #define addrMacJmp32   0xbff
  314.  
  315. void _CALLTYPE1 _assert (
  316.         void *expr,
  317.         void *filename,
  318.         unsigned lineno
  319.         )
  320. {
  321.         char rgch[512];
  322.         long lrespond;
  323.         OSErr osErr;
  324.         long *pl;
  325.         unsigned char ch;
  326.         char *pch;
  327.         int cb;
  328.  
  329.         if (_pMPWBlock != NULL) {
  330.  
  331.             /*
  332.             * This is the original CRT32 code.
  333.             */
  334.  
  335.             if ( !anybuf(stderr) )
  336.                 /*
  337.                 * stderr is unused, hence unbuffered, as yet. set it to
  338.                 * single character buffering (to avoid a malloc() of a
  339.                 * stream buffer).
  340.                 */
  341.                 (void) setvbuf(stderr, NULL, _IONBF, 0);
  342.  
  343.             fprintf(stderr, _assertstring, expr, filename, lineno);
  344.             fflush(stderr);
  345.         }
  346.         else {
  347.  
  348.             /*
  349.             *  This assert code will bring up system debugger, most
  350.             *  probably MacsBug if there is a debuuger installed.
  351.             *  If no debugger installed, write to stderr file.
  352.             *  Not sure if this is really working. Need more accurate
  353.             *  info on how MacJmp is set up.
  354.             */
  355.  
  356.  
  357.             osErr = Gestalt(gestaltAddressingModeAttr, &lrespond);
  358.             if (!osErr) {
  359.                 if (!BitTst(&lrespond, 31-gestalt32BitCapable)) {
  360.                     pl = (long *)addrMacJmp24;
  361.                     ch = (unsigned char)(*pl);
  362.                 }
  363.                 else {
  364.                     pch = (char *)addrMacJmp32;
  365.                     ch = *pch;
  366.                 }
  367.             }
  368.  
  369.             if (ch & 0x20) {        //test bit 5 for Debugger installed
  370.                 sprintf(rgch, _assertstring, expr, filename, lineno);
  371.                 _c2pstr(rgch);
  372.                 DebugStr(rgch);
  373.             }
  374.             else {
  375. //              freopen("stderr", "wt", stderr);
  376. //              fprintf(stderr, _assertstring, expr, filename, lineno);
  377.                 cb = sprintf(rgch, _assertstring, expr, filename, lineno);
  378.                 _write(2, rgch, cb);
  379. //              fflush(stderr);
  380.             }
  381.         }
  382.         abort();
  383. }
  384.  
  385. #endif  /* _WIN32 */
  386.