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

  1. /***
  2. *dbgrpt.c - Debug CRT Reporting Functions
  3. *
  4. *       Copyright (c) 1988-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *
  8. *******************************************************************************/
  9.  
  10. #ifdef _DEBUG
  11.  
  12. #include <internal.h>
  13. #include <mtdll.h>
  14. #include <malloc.h>
  15. #include <mbstring.h>
  16. #include <stdarg.h>
  17. #include <stdlib.h>
  18. #include <stdio.h>
  19. #include <dbgint.h>
  20. #include <signal.h>
  21. #include <string.h>
  22. #include <awint.h>
  23.  
  24. #ifdef _WIN32
  25.  
  26. #include <windows.h>
  27.  
  28. #define _CrtInterlockedIncrement InterlockedIncrement
  29. #define _CrtInterlockedDecrement InterlockedDecrement
  30.  
  31. #else  /* _WIN32 */
  32.  
  33. #define FALSE 0
  34. #define TRUE  1
  35. #define BYTE char
  36.  
  37. #include <macos\msvcmac.h>
  38. #include <macos\Desk.h>
  39. #include <macos\Dialogs.h>
  40. #include <macos\Events.h>
  41. #include <macos\Fonts.h>
  42. #include <macos\Memory.h>
  43. #include <macos\LowMem.h>
  44. #include <macos\Menus.h>
  45. #include <macos\OSUtils.h>
  46. #include <macos\QuickDra.h>
  47. #include <macos\Resource.h>
  48. #include <macos\Types.h>
  49. #include <macos\Windows.h>
  50. #include <macos\TextUtil.h>
  51. #include <macos\SegLoad.h>
  52. #include <macos\files.h>
  53. #include <macos\gestalt.h>
  54.  
  55. __inline long __cdecl _CrtInterlockedIncrement(long * plVar) { return ++(*plVar); }
  56. __inline long __cdecl _CrtInterlockedDecrement(long * plVar) { return --(*plVar); }
  57.  
  58. static void __cdecl _CrtOutputDebugString(char * sz);
  59.  
  60. #endif  /* _WIN32 */
  61.  
  62. /*---------------------------------------------------------------------------
  63.  *
  64.  * Debug Reporting
  65.  *
  66.  --------------------------------------------------------------------------*/
  67.  
  68. static int CrtMessageWindow(
  69.         int,
  70.         const char *,
  71.         const char *,
  72.         const char *,
  73.         const char *
  74.         );
  75.  
  76.  
  77. _CRT_REPORT_HOOK _pfnReportHook;
  78.  
  79. _CRTIMP long _crtAssertBusy = -1;
  80.  
  81. int _CrtDbgMode[_CRT_ERRCNT] = {
  82. #ifdef _WIN32
  83.         _CRTDBG_MODE_DEBUG,
  84.         _CRTDBG_MODE_WNDW,
  85.         _CRTDBG_MODE_WNDW
  86. #else  /* _WIN32 */
  87.         _CRTDBG_MODE_DEBUG,
  88.         _CRTDBG_MODE_DEBUG,
  89.         _CRTDBG_MODE_DEBUG
  90. #endif  /* _WIN32 */
  91.         };
  92.  
  93. _HFILE _CrtDbgFile[_CRT_ERRCNT] = { _CRTDBG_INVALID_HFILE,
  94.                                     _CRTDBG_INVALID_HFILE,
  95.                                     _CRTDBG_INVALID_HFILE
  96.                                   };
  97.  
  98.  
  99. static const char * _CrtDbgModeMsg[_CRT_ERRCNT] = { "Warning", "Error", "Assertion Failed" };
  100.  
  101. /***
  102. *void _CrtDebugBreak - call OS-specific debug function
  103. *
  104. *Purpose:
  105. *       call OS-specific debug function
  106. *
  107. *Entry:
  108. *
  109. *Exit:
  110. *
  111. *Exceptions:
  112. *
  113. *******************************************************************************/
  114.  
  115. #undef _CrtDbgBreak
  116.  
  117. _CRTIMP void _cdecl _CrtDbgBreak(
  118.         void
  119.         )
  120. {
  121. #ifdef _WIN32
  122.         DebugBreak();
  123. #else  /* _WIN32 */
  124.         Debugger();
  125. #endif  /* _WIN32 */
  126. }
  127.  
  128. /***
  129. *int _CrtSetReportMode - set the reporting mode for a given report type
  130. *
  131. *Purpose:
  132. *       set the reporting mode for a given report type
  133. *
  134. *Entry:
  135. *       int nRptType    - the report type
  136. *       int fMode       - new mode for given report type
  137. *
  138. *Exit:
  139. *       previous mode for given report type
  140. *
  141. *Exceptions:
  142. *
  143. *******************************************************************************/
  144. _CRTIMP int __cdecl _CrtSetReportMode(
  145.         int nRptType,
  146.         int fMode
  147.         )
  148. {
  149.         int oldMode;
  150.  
  151.         if (nRptType < 0 || nRptType >= _CRT_ERRCNT)
  152.             return -1;
  153.  
  154.         if (fMode == _CRTDBG_REPORT_MODE)
  155.             return _CrtDbgMode[nRptType];
  156.  
  157.         /* verify flags values */
  158.         if (fMode & ~(_CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_WNDW))
  159.             return -1;
  160.  
  161.         oldMode = _CrtDbgMode[nRptType];
  162.  
  163.         _CrtDbgMode[nRptType] = fMode;
  164.  
  165.         return oldMode;
  166. }
  167.  
  168. /***
  169. *int _CrtSetReportFile - set the reporting file for a given report type
  170. *
  171. *Purpose:
  172. *       set the reporting file for a given report type
  173. *
  174. *Entry:
  175. *       int nRptType    - the report type
  176. *       _HFILE hFile    - new file for given report type
  177. *
  178. *Exit:
  179. *       previous file for given report type
  180. *
  181. *Exceptions:
  182. *
  183. *******************************************************************************/
  184. _CRTIMP _HFILE __cdecl _CrtSetReportFile(
  185.         int nRptType,
  186.         _HFILE hFile
  187.         )
  188. {
  189.         _HFILE oldFile;
  190.  
  191.         if (nRptType < 0 || nRptType >= _CRT_ERRCNT)
  192.             return _CRTDBG_HFILE_ERROR;
  193.  
  194.         if (hFile == _CRTDBG_REPORT_FILE)
  195.             return _CrtDbgFile[nRptType];
  196.  
  197.         oldFile = _CrtDbgFile[nRptType];
  198.  
  199. #ifdef _WIN32
  200.         if (_CRTDBG_FILE_STDOUT == hFile)
  201.             _CrtDbgFile[nRptType] = GetStdHandle(STD_OUTPUT_HANDLE);
  202.  
  203.         else if (_CRTDBG_FILE_STDERR == hFile)
  204.             _CrtDbgFile[nRptType] = GetStdHandle(STD_ERROR_HANDLE);
  205. #else  /* _WIN32 */
  206.         if (_CRTDBG_FILE_STDOUT == hFile || _CRTDBG_FILE_STDERR == hFile)
  207.             return _CRTDBG_HFILE_ERROR;
  208. #endif  /* _WIN32 */
  209.         else
  210.             _CrtDbgFile[nRptType] = hFile;
  211.  
  212.         return oldFile;
  213. }
  214.  
  215.  
  216. /***
  217. *_CRT_REPORT_HOOK _CrtSetReportHook() - set client report hook
  218. *
  219. *Purpose:
  220. *       set client report hook
  221. *
  222. *Entry:
  223. *       _CRT_REPORT_HOOK pfnNewHook - new report hook
  224. *
  225. *Exit:
  226. *       return previous hook
  227. *
  228. *Exceptions:
  229. *
  230. *******************************************************************************/
  231. _CRTIMP _CRT_REPORT_HOOK __cdecl _CrtSetReportHook(
  232.         _CRT_REPORT_HOOK pfnNewHook
  233.         )
  234. {
  235.         _CRT_REPORT_HOOK pfnOldHook = _pfnReportHook;
  236.         _pfnReportHook = pfnNewHook;
  237.         return pfnOldHook;
  238. }
  239.  
  240.  
  241. #define MAXLINELEN 64
  242. #define MAX_MSG 4096
  243. #define TOOLONGMSG "_CrtDbgReport: String too long or IO Error"
  244.  
  245.  
  246. /***
  247. *int _CrtDbgReport() - primary reporting function
  248. *
  249. *Purpose:
  250. *       Display a message window with the following format.
  251. *
  252. *       ================= Microsft Visual C++ Debug Library ================
  253. *
  254. *       {Warning! | Error! | Assertion Failed!}
  255. *
  256. *       Program: c:\test\mytest\foo.exe
  257. *       [Module: c:\test\mytest\bar.dll]
  258. *       [File: c:\test\mytest\bar.c]
  259. *       [Line: 69]
  260. *
  261. *       {<warning or error message> | Expression: <expression>}
  262. *
  263. *       [For information on how your program can cause an assertion
  264. *        failure, see the Visual C++ documentation on asserts]
  265. *
  266. *       (Press Retry to debug the application)
  267. *
  268. *       ===================================================================
  269. *
  270. *Entry:
  271. *       int             nRptType    - report type
  272. *       const char *    szFile      - file name
  273. *       int             nLine       - line number
  274. *       const char *    szModule    - module name
  275. *       const char *    szFormat    - format string
  276. *       ...                         - var args
  277. *
  278. *Exit:
  279. *       if (MessageBox)
  280. *       {
  281. *           Abort -> aborts
  282. *           Retry -> return TRUE
  283. *           Ignore-> return FALSE
  284. *       }
  285. *       else
  286. *           return FALSE
  287. *
  288. *Exceptions:
  289. *
  290. *******************************************************************************/
  291. _CRTIMP int __cdecl _CrtDbgReport(
  292.         int nRptType,
  293.         const char * szFile,
  294.         int nLine,
  295.         const char * szModule,
  296.         const char * szFormat,
  297.         ...
  298.         )
  299. {
  300.         int retval;
  301.         va_list arglist;
  302.         char szLineMessage[MAX_MSG] = {0};
  303.         char szOutMessage[MAX_MSG] = {0};
  304.         char szUserMessage[MAX_MSG] = {0};
  305.         #define ASSERTINTRO1 "Assertion failed: "
  306.         #define ASSERTINTRO2 "Assertion failed!"
  307.  
  308.         va_start(arglist, szFormat);
  309.  
  310.         if (nRptType < 0 || nRptType >= _CRT_ERRCNT)
  311.             return -1;
  312.  
  313.         /*
  314.          * handle the (hopefully rare) case of
  315.          *
  316.          * 1) ASSERT while already dealing with an ASSERT
  317.          *      or
  318.          * 2) two threads asserting at the same time
  319.          */
  320.         if (_CRT_ASSERT == nRptType && _CrtInterlockedIncrement(&_crtAssertBusy) > 0)
  321.         {
  322.             /* use only 'safe' functions -- must not assert in here! */
  323. #ifdef _WIN32
  324.             static int (APIENTRY *pfnwsprintfA)(LPSTR, LPCSTR, ...) = NULL;
  325.  
  326.             if (NULL == pfnwsprintfA)
  327.             {
  328.                 HANDLE hlib = LoadLibrary("user32.dll");
  329.  
  330.                 if (NULL == hlib || NULL == (pfnwsprintfA =
  331.                             (int (APIENTRY *)(LPSTR, LPCSTR, ...))
  332.                             GetProcAddress(hlib, "wsprintfA")))
  333.                     return -1;
  334.             }
  335.  
  336.             (*pfnwsprintfA)( szOutMessage,
  337.                 "Second Chance Assertion Failed: File %s, Line %d\n",
  338.                 szFile, nLine);
  339.  
  340.             OutputDebugString(szOutMessage);
  341. #else  /* _WIN32 */
  342.             strcpy(szOutMessage, "Second Chance Assertion Failed: File ");
  343.             strcat(szOutMessage, szFile);
  344.             strcat(szOutMessage, ", Line ");
  345.             numtostring(nLine, &szOutMessage[strlen(szOutMessage)]);
  346.             strcat(szOutMessage, "\n");
  347.             _CrtOutputDebugString(szOutMessage);
  348. #endif  /* _WIN32 */
  349.  
  350.             _CrtInterlockedDecrement(&_crtAssertBusy);
  351.  
  352.             _CrtDbgBreak();
  353.             return -1;
  354.         }
  355.  
  356.         if (szFormat && _vsnprintf(szUserMessage,
  357.                        MAX_MSG-max(sizeof(ASSERTINTRO1),sizeof(ASSERTINTRO2)),
  358.                        szFormat,
  359.                        arglist) < 0)
  360.             strcpy(szUserMessage, TOOLONGMSG);
  361.  
  362.         if (_CRT_ASSERT == nRptType)
  363.             strcpy(szLineMessage, szFormat ? ASSERTINTRO1 : ASSERTINTRO2);
  364.  
  365.         strcat(szLineMessage, szUserMessage);
  366.  
  367.         if (_CRT_ASSERT == nRptType)
  368.         {
  369.             if (_CrtDbgMode[nRptType] & _CRTDBG_MODE_FILE)
  370.                 strcat(szLineMessage, "\r");
  371.             strcat(szLineMessage, "\n");
  372.         }
  373.  
  374.         if (szFile)
  375.         {
  376.             if (_snprintf(szOutMessage, MAX_MSG, "%s(%d) : %s",
  377.                 szFile, nLine, szLineMessage) < 0)
  378.             strcpy(szOutMessage, TOOLONGMSG);
  379.         }
  380.         else
  381.             strcpy(szOutMessage, szLineMessage);
  382.  
  383.         /* user hook may handle report */
  384.         if (_pfnReportHook && (*_pfnReportHook)(nRptType, szOutMessage, &retval))
  385.         {
  386.             if (_CRT_ASSERT == nRptType)
  387.                 _CrtInterlockedDecrement(&_crtAssertBusy);
  388.             return retval;
  389.         }
  390.  
  391.         if (_CrtDbgMode[nRptType] & _CRTDBG_MODE_FILE)
  392.         {
  393.             if (_CrtDbgFile[nRptType] != _CRTDBG_INVALID_HFILE)
  394.             {
  395. #ifdef _WIN32
  396.                 DWORD written;
  397.                 WriteFile(_CrtDbgFile[nRptType], szOutMessage, strlen(szOutMessage), &written, NULL);
  398. #else  /* _WIN32 */
  399.                 long written = strlen(szOutMessage);
  400.  
  401.                 FSWrite((short)_CrtDbgFile[nRptType], &written, szOutMessage);
  402. #endif  /* _WIN32 */
  403.             }
  404.         }
  405.  
  406.         if (_CrtDbgMode[nRptType] & _CRTDBG_MODE_DEBUG)
  407.         {
  408. #ifdef _WIN32
  409.             OutputDebugString(szOutMessage);
  410. #else  /* _WIN32 */
  411.             _CrtOutputDebugString(szOutMessage);
  412. #endif  /* _WIN32 */
  413.         }
  414.  
  415.         if (_CrtDbgMode[nRptType] & _CRTDBG_MODE_WNDW)
  416.         {
  417.             char szLine[20];
  418.  
  419.             retval = CrtMessageWindow(nRptType, szFile, nLine ? _itoa(nLine, szLine, 10) : NULL, szModule, szUserMessage);
  420.             if (_CRT_ASSERT == nRptType)
  421.                 _CrtInterlockedDecrement(&_crtAssertBusy);
  422.             return retval;
  423.         }
  424.  
  425.         if (_CRT_ASSERT == nRptType)
  426.             _CrtInterlockedDecrement(&_crtAssertBusy);
  427.         /* ignore */
  428.         return FALSE;
  429. }
  430.  
  431.  
  432. /***
  433. *static int CrtMessageWindow() - report to a message window
  434. *
  435. *Purpose:
  436. *       put report into message window, allow user to choose action to take
  437. *
  438. *Entry:
  439. *       int             nRptType      - report type
  440. *       const char *    szFile        - file name
  441. *       const char *    szLine        - line number
  442. *       const char *    szModule      - module name
  443. *       const char *    szUserMessage - user message
  444. *
  445. *Exit:
  446. *       if (MessageBox)
  447. *       {
  448. *           Abort -> aborts
  449. *           Retry -> return TRUE
  450. *           Ignore-> return FALSE
  451. *       }
  452. *       else
  453. *           return FALSE
  454. *
  455. *Exceptions:
  456. *
  457. *******************************************************************************/
  458. #ifdef _WIN32
  459.  
  460. static int CrtMessageWindow(
  461.         int nRptType,
  462.         const char * szFile,
  463.         const char * szLine,
  464.         const char * szModule,
  465.         const char * szUserMessage
  466.         )
  467. {
  468.         int nCode;
  469.         char *szShortProgName;
  470.         char *szShortModuleName;
  471.         char szExeName[MAX_PATH];
  472.         char szOutMessage[MAX_MSG];
  473.  
  474.         _ASSERTE(szUserMessage != NULL);
  475.  
  476.         /* Shorten program name */
  477.         if (!GetModuleFileName(NULL, szExeName, MAX_PATH))
  478.             strcpy(szExeName, "<program name unknown>");
  479.  
  480.         szShortProgName = szExeName;
  481.  
  482.         if (strlen(szShortProgName) > MAXLINELEN)
  483.         {
  484.             szShortProgName += strlen(szShortProgName) - MAXLINELEN;
  485.             strncpy(szShortProgName, "...", 3);
  486.         }
  487.  
  488.         /* Shorten module name */
  489.         szShortModuleName = (char *) szModule;
  490.  
  491.         if (szShortModuleName && strlen(szShortModuleName) > MAXLINELEN)
  492.         {
  493.             szShortModuleName += strlen(szShortModuleName) - MAXLINELEN;
  494.             strncpy(szShortModuleName, "...", 3);
  495.         }
  496.  
  497.         if (_snprintf(szOutMessage, MAX_MSG,
  498.                 "Debug %s!\n\nProgram: %s%s%s%s%s%s%s%s%s%s%s"
  499.                 "\n\n(Press Retry to debug the application)",
  500.                 _CrtDbgModeMsg[nRptType],
  501.                 szShortProgName,
  502.                 szShortModuleName ? "\nModule: " : "",
  503.                 szShortModuleName ? szShortModuleName : "",
  504.                 szFile ? "\nFile: " : "",
  505.                 szFile ? szFile : "",
  506.                 szLine ? "\nLine: " : "",
  507.                 szLine ? szLine : "",
  508.                 szUserMessage[0] ? "\n\n" : "",
  509.                 szUserMessage[0] && _CRT_ASSERT == nRptType ? "Expression: " : "",
  510.                 szUserMessage[0] ? szUserMessage : "",
  511.                 _CRT_ASSERT == nRptType ?
  512.                 "\n\nFor information on how your program can cause an assertion"
  513.                 "\nfailure, see the Visual C++ documentation on asserts."
  514.                 : "") < 0)
  515.             strcpy(szOutMessage, TOOLONGMSG);
  516.  
  517.         /* Report the warning/error */
  518.         nCode = __crtMessageBoxA(szOutMessage,
  519.                              "Microsoft Visual C++ Debug Library",
  520.                              MB_TASKMODAL|MB_ICONHAND|MB_ABORTRETRYIGNORE|MB_SETFOREGROUND);
  521.  
  522.         /* Abort: abort the program */
  523.         if (IDABORT == nCode)
  524.         {
  525.             /* raise abort signal */
  526.             raise(SIGABRT);
  527.  
  528.             /* We usually won't get here, but it's possible that
  529.                SIGABRT was ignored.  So exit the program anyway. */
  530.  
  531.             _exit(3);
  532.         }
  533.  
  534.         /* Retry: return 1 to call the debugger */
  535.         if (IDRETRY == nCode)
  536.             return 1;
  537.  
  538.         /* Ignore: continue execution */
  539.         return 0;
  540. }
  541.  
  542. #elif defined (_M_MPPC)
  543.  
  544. /* Definitions */
  545. #define  NIL       0
  546.  
  547. /* Portable Types */
  548. typedef unsigned char     Char;
  549. typedef unsigned long     Word;
  550.  
  551. QDGlobals qd;
  552.  
  553. static void BlinkButton(int count,Rect *r)
  554. {
  555.         long n;
  556.  
  557.         while (count--) {
  558.             InvertRoundRect(r,10,10);
  559.             Delay(4,&n);
  560.         }
  561. }
  562.  
  563. static int ButtonClicked(Rect *r)
  564. {
  565.         int state = 0;
  566.         Point pt;
  567.  
  568.         do {
  569.             GetMouse(&pt);
  570.             if (PtInRect(pt,r)) {
  571.                 if (0 == state) {
  572.                     state = 1;
  573.                     BlinkButton(1,r);
  574.                 }
  575.             }
  576.             else if (1 == state) {
  577.                 state = 0;
  578.                 BlinkButton(1,r);
  579.             }
  580.         } while (Button());
  581.         if (state)
  582.             BlinkButton(3,r);
  583.         return state;
  584. }
  585.  
  586. static int CrtMessageWindow(
  587.         int nRptType,
  588.         const char * szFile,
  589.         const char * szLine,
  590.         const char * szModule,
  591.         const char * szUserMessage
  592.         )
  593. {
  594.         #define LEFTMARGIN  15
  595.         #define ALINE       14
  596.  
  597.         char szOutMessage[MAX_MSG];
  598.         Rect abort,retry,ignore,r;
  599.         GrafPtr oldPort;
  600.         WindowPtr window;
  601.         EventRecord event;
  602.         long total, contig;
  603.         short currHeight = 20;
  604.         int numLines = 13 +
  605.             4 * (_CRT_ASSERT == nRptType) +
  606.             2 * (szUserMessage[0] != '\0') +
  607.             (szModule != NULL) +
  608.             2 * (szFile != NULL);
  609.  
  610.         /* center a rectangle on the screen, near the top of the screen */
  611.         r.top = 50;
  612.         r.bottom = r.top + numLines * ALINE;
  613.         r.left = qd.screenBits.bounds.right/2 - 170;
  614.         r.right = qd.screenBits.bounds.right/2 + 170;
  615.  
  616.         /*
  617.          * NewWindow will hang in insufficient memory conditions. Must
  618.          * confirm available memory before use.
  619.          */
  620.  
  621.         contig = 0;
  622.         PurgeSpace(&total, &contig);
  623.         if (contig < 1024)
  624.             return -1;
  625.  
  626.         /* create the window and setup the port */
  627.         if ((window = NewWindow(NIL,&r,"\p",TRUE,dBoxProc,(WindowPtr)-1,TRUE,0))
  628.             == NULL)
  629.             return -1;
  630.  
  631.         GetPort(&oldPort);
  632.         SetPort(window);
  633.         InitCursor();
  634.  
  635.         TextFont(systemFont);
  636.  
  637.         MoveTo(LEFTMARGIN,currHeight);
  638.         TextFace(underline);
  639.         DrawString("\pMicrosoft Visual C++ Debug Library");
  640.         TextFace(0);
  641.         currHeight += 2 * ALINE;
  642.  
  643.         _snprintf(szOutMessage, MAX_MSG, "Debug %s!", _CrtDbgModeMsg[nRptType]);
  644.         _c2pstr(szOutMessage);
  645.         MoveTo(LEFTMARGIN,currHeight);
  646.         TextFace(bold);
  647.         DrawString(szOutMessage);
  648.         TextFace(0);
  649.         currHeight += 2 * ALINE;
  650.  
  651.         MoveTo(LEFTMARGIN,currHeight);
  652.         DrawString("\pProgram: ");
  653.         DrawString(LMGetCurApName());
  654.         currHeight += ALINE;
  655.  
  656.         if (szModule) {
  657.             _snprintf(szOutMessage, MAX_MSG, "Module: %s", szModule);
  658.             _c2pstr(szOutMessage);
  659.             MoveTo(LEFTMARGIN,currHeight);
  660.             DrawString(szOutMessage);
  661.             currHeight += ALINE;
  662.         }
  663.  
  664.         if (szFile) {
  665.             _snprintf(szOutMessage, MAX_MSG, "File: %s", szFile);
  666.             _c2pstr(szOutMessage);
  667.             MoveTo(LEFTMARGIN,currHeight);
  668.             DrawString(szOutMessage);
  669.             currHeight += ALINE;
  670.         }
  671.  
  672.         if (szLine) {
  673.             _snprintf(szOutMessage, MAX_MSG, "Line: %s", szLine);
  674.             _c2pstr(szOutMessage);
  675.             MoveTo(LEFTMARGIN,currHeight);
  676.             DrawString(szOutMessage);
  677.             currHeight += ALINE;
  678.         }
  679.         currHeight += ALINE;
  680.  
  681.         if (szUserMessage[0])
  682.         {
  683.             _snprintf(szOutMessage, MAX_MSG, "%s%s",
  684.                 (_CRT_ASSERT == nRptType) ? "Expression: " : "",
  685.                 szUserMessage);
  686.  
  687.             r.top = currHeight-10;
  688.             r.bottom = currHeight - 5;
  689.             r.left = LEFTMARGIN - 2;
  690.             r.right = window->portRect.right - LEFTMARGIN - 2;
  691.             TextFace(condense);
  692.             TextBox(szOutMessage, strlen(szOutMessage), &r, teJustLeft);
  693.             TextFace(0);
  694.             currHeight += 2*ALINE;
  695.         }
  696.  
  697.         currHeight += ALINE;
  698.  
  699.         if (_CRT_ASSERT == nRptType)
  700.         {
  701.             MoveTo(LEFTMARGIN,currHeight);
  702.             DrawString("\pFor more information on how your program");
  703.             currHeight += ALINE;
  704.  
  705.             MoveTo(LEFTMARGIN,currHeight);
  706.             DrawString("\pcan cause an assertion failure, see the");
  707.             currHeight += ALINE;
  708.  
  709.             MoveTo(LEFTMARGIN,currHeight);
  710.             DrawString("\pVisual C++ documentation on asserts.");
  711.             currHeight += 2*ALINE;
  712.  
  713.             MoveTo(LEFTMARGIN,currHeight);
  714.             DrawString("\p(Press Retry to debug the application)");
  715.             currHeight += 2*ALINE;
  716.         }
  717.         else {
  718.             MoveTo(LEFTMARGIN,currHeight);
  719.             DrawString("\p(Press Retry to debug the application)");
  720.             currHeight += 2*ALINE;
  721.         }
  722.  
  723.         /* draw abort button */
  724.         abort.top = currHeight;
  725.         abort.bottom = abort.top + 20;
  726.         abort.left = LEFTMARGIN;
  727.         abort.right = abort.left + 75;
  728.         FrameRoundRect(&abort,10,10);
  729.         MoveTo((short)(abort.left+20),(short)(abort.bottom-6));
  730.         DrawString("\pAbort");
  731.  
  732.         /* draw retry button */
  733.         retry.top = currHeight;
  734.         retry.bottom = retry.top + 20;
  735.         retry.left = LEFTMARGIN + 110;
  736.         retry.right = retry.left + 75;
  737.         FrameRoundRect(&retry,10,10);
  738.         MoveTo((short)(retry.left+20),(short)(retry.bottom-6));
  739.         DrawString("\pRetry");
  740.  
  741.         /* draw ignore button */
  742.         ignore.top = currHeight;
  743.         ignore.bottom = ignore.top + 20;
  744.         ignore.left = LEFTMARGIN + 110 * 2;
  745.         ignore.right = ignore.left + 75;
  746.         FrameRoundRect(&ignore,10,10);
  747.         MoveTo((short)(ignore.left+17),(short)(ignore.bottom-6));
  748.         DrawString("\pIgnore");
  749.  
  750.         /* event loop */
  751.         while (TRUE) {
  752.             if (GetNextEvent(mDownMask+keyDownMask,&event)) {
  753.                 if (event.what == keyDown) { /* keyboard shortcuts */
  754.                     char c = (char)event.message;
  755.  
  756.                     /* abort */
  757.                     if (c == 'a') {
  758.                         BlinkButton(3,&abort);
  759.                         ExitToShell();
  760.                     }
  761.  
  762.                     /* retry */
  763.                     else if (c == 'r') {
  764.                         BlinkButton(3,&retry);
  765.                         Debugger();
  766.                         break;
  767.                     }
  768.  
  769.                     /* ignore */
  770.                     else if (c == 'i') {
  771.                         BlinkButton(3,&ignore);
  772.                         break;
  773.                     }
  774.                 }
  775.                 if (event.what == mouseDown) {
  776.                     GlobalToLocal(&event.where);
  777.                     if (PtInRect(event.where,&abort) && ButtonClicked(&abort))
  778.                         ExitToShell();
  779.                     else if (PtInRect(event.where,&retry) && ButtonClicked(&retry)) {
  780.                         Debugger();
  781.                         break;
  782.                     }
  783.                     else if (PtInRect(event.where,&ignore) && ButtonClicked(&ignore))
  784.                         break;
  785.                 }
  786.             }
  787.         }
  788.         DisposeWindow(window);
  789.         SetPort(oldPort);
  790.  
  791.         /* ignore */
  792.         return 0;
  793. }
  794.  
  795. #define WLMD_STR        1
  796. #define LMGetMacJmp()   (*(ProcPtr*) 0x120)
  797.  
  798. enum
  799. {
  800.         uppGestaltDebugProcInfo =   kCStackBased
  801.             | STACK_ROUTINE_PARAMETER (1, SIZE_CODE (sizeof (int)))
  802.             | STACK_ROUTINE_PARAMETER (2, SIZE_CODE (sizeof (StringPtr)))
  803.             | STACK_ROUTINE_PARAMETER (3, SIZE_CODE (sizeof (char*)))
  804.             | STACK_ROUTINE_PARAMETER (4, SIZE_CODE (sizeof (char*)))
  805. };
  806.  
  807.  
  808. static UniversalProcPtr pfnGestaltDebugger;
  809.  
  810.  
  811. /***
  812. *void _CleanStr - clean string
  813. *
  814. *Purpose:
  815. *       Cleans a string of characters that aren't useful. Always removes '\r'. If
  816. *       the string is going to MacsBug, replaces semicolons with periods, and
  817. *       removes trailing newlines, since MacsBug always advances to the next line
  818. *       after a _DebugStr.
  819. *
  820. *Entry:
  821. *       StringPtr   st          - the string to clean
  822. *       int         fMacsBug    - whether the string is going to MacsBug
  823. *
  824. *Exit:
  825. *
  826. *Exceptions:
  827. *
  828. *******************************************************************************/
  829.  
  830. static void __cdecl _CleanStr(StringPtr st, int fMacsBug)
  831. {
  832.         int     i;
  833.  
  834.         /* change semi-colons to periods (semi-colons hose MacsBug) */
  835.         if (fMacsBug)
  836.         {
  837.             for (i = 0; i < StrLength(st); i++)
  838.             {
  839.                 /* skip MB chars */
  840.                 if (_ismbblead(st[i+1]))
  841.                 {
  842.                     i++;
  843.                     continue;
  844.                 }
  845.  
  846.                 if (st[i + 1] == ';')
  847.                     st[i + 1] = '.';
  848.             }
  849.         }
  850.  
  851.         for (i = StrLength(st); i >= 1; i--)
  852.         {
  853.             /* if trail byte, stop processing */
  854.             if (_ismbstrail(&st[1], &st[i]))
  855.                 break;
  856.  
  857.             /* remove trailing newlines */
  858.             if (st[i] == '\n')
  859.             {
  860.                 if (fMacsBug)
  861.                     st[0]--;
  862.             }
  863.             /* remove trailing carriage returns */
  864.             else if (st[i] == '\r')
  865.             {
  866.                 st[0]--;
  867.             }
  868.             /* otherwise, stop processing */
  869.             else
  870.             {
  871.                 break;
  872.             }
  873.         }
  874. }
  875.  
  876.  
  877. /***
  878. *void _ConfirmVCDebugger
  879. *
  880. *Purpose:
  881. *       Determines if a 'WLMD' Gestalt selector is registered.
  882. *
  883. *Entry:
  884. *
  885. *Exit:
  886. *       Current VC++ Debug Output function or NULL.
  887. *
  888. *Exceptions:
  889. *
  890. *******************************************************************************/
  891.  
  892. static UniversalProcPtr __cdecl _ConfirmVCDebugger(void)
  893. {
  894.         /* The VC++ Debug Ouput facilities are registered as "WLMD" */
  895.         if (Gestalt('WLMD', (long*) &pfnGestaltDebugger) != noErr)
  896.             pfnGestaltDebugger = NULL;
  897.         return pfnGestaltDebugger;
  898. }
  899.  
  900.  
  901. /***
  902. *int _IsMSVCDebugger
  903. *
  904. *Purpose:
  905. *       Determines if a 'MSVC' Gestalt selector is registered, or if there
  906. *       is a low level debugger in the system
  907. *
  908. *       Only call a macsbug-like debugger if it's going to be around to
  909. *       handle the DebugStr
  910. *
  911. *Entry:
  912. *
  913. *Exit:
  914. *       TRUE:   If MSVC debugger registered
  915. *       FALSE:  Otherwise
  916. *
  917. *Exceptions:
  918. *
  919. *******************************************************************************/
  920.  
  921. static int __cdecl _IsLowLevelDebugger(void)
  922. {
  923. #define mskBeingDebugged 1
  924. #define mskPreviousDebugger 2
  925.  
  926.         unsigned long caps;
  927.  
  928.         /* See if VC++ Debugger is running */
  929.         if(Gestalt('MSVC', (long*) &caps) == noErr)
  930.         {
  931.             if((caps & mskBeingDebugged) || (caps & mskPreviousDebugger))
  932.                 return 1;
  933.             else
  934.                 return 0;
  935.         }
  936.         /* See if MacsBug is running */
  937.         else if (LMGetMacJmp() != NULL)
  938.             return 1;
  939.         else
  940.             return 0;
  941.  
  942. #undef mskBeingDebugged
  943. #undef mskPreviousDebugger
  944. }
  945.  
  946.  
  947. /***
  948. *void _CrtOutputDebugString - output Debug String
  949. *
  950. *Purpose:
  951. *       Does the actual output of a string to the debugger.
  952. *
  953. *Entry:
  954. *       char * sz -- message to output
  955. *
  956. *Exit:
  957. *
  958. *Exceptions:
  959. *
  960. *******************************************************************************/
  961.  
  962. static void __cdecl _CrtOutputDebugString(char * sz)
  963. {
  964.         Str255      stDebug;
  965.         long        cchTotal;
  966.         short       cchCur;
  967.         const char* pchCur;
  968.         EventRecord er;
  969.  
  970.         _ConfirmVCDebugger();
  971.  
  972.         OSEventAvail(0, &er);
  973.  
  974.         cchTotal = strlen(sz);
  975.         pchCur = sz;
  976.  
  977.         /* output string in edible portions */
  978.         while (cchTotal > 0)
  979.         {
  980.             cchCur = (short) min(cchTotal, 253);
  981.             _ASSERTE(cchCur > 0);
  982.  
  983.             /* put back orphaned lead byte */
  984.             if (_ismbslead(pchCur, pchCur+cchCur-1))
  985.                 cchCur--;
  986.  
  987.             /* convert CString to PascalString */
  988.             stDebug[0] = (unsigned char) cchCur;
  989.             BlockMoveData(pchCur, &stDebug[1], cchCur);
  990.  
  991.             /* See if VC++ Debug Output facility is running */
  992.             if (pfnGestaltDebugger != NULL)
  993.             {
  994.                 _CleanStr(stDebug, 0);
  995.  
  996.                 /* if the Control key is down, we break into MacsBug before
  997.                    sending the string to the Gestalt debugger */
  998.                 if ((er.modifiers & controlKey) != 0)
  999.                     Debugger();
  1000.  
  1001.                 CallUniversalProc(pfnGestaltDebugger, uppGestaltDebugProcInfo, WLMD_STR, stDebug,
  1002.                         NULL, NULL);
  1003.             }
  1004.             /* See if VC++ Debugger or MacsBug is running */
  1005.             else if (_IsLowLevelDebugger())
  1006.             {
  1007.                 short   cchSt;
  1008.  
  1009.                 _CleanStr(stDebug, 1);
  1010.  
  1011.                 /* _CleanStr may have changed the length of stDebug */
  1012.                 cchSt = StrLength(stDebug);
  1013.  
  1014.                 /* if the Control key is down, we always stop in the debugger */
  1015.                 if ((er.modifiers & controlKey) == 0)
  1016.                 {
  1017.                     stDebug[cchSt + 1] = ';';
  1018.                     stDebug[cchSt + 2] = 'g';
  1019.                     stDebug[0] += 2;
  1020.                 }
  1021.  
  1022.                 DebugStr(stDebug);
  1023.             }
  1024.             cchTotal -= cchCur;
  1025.             pchCur += cchCur;
  1026.         }
  1027. }
  1028.  
  1029. #endif  /* defined (_M_MPPC) */
  1030.  
  1031. #endif  /* _DEBUG */
  1032.  
  1033.