home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc™ Source Code / Utilities / ODDebug.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-28  |  12.1 KB  |  543 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        ODDebug.cpp
  3.  
  4.     Contains:    Useful debugging macros and functions
  5.  
  6.     Owned by:    Reggie Adkins
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <5>     5/24/96    jpa        1307353: Append ";g" when logging to
  13.                                     DebugStrs.
  14.          <4>    .05.1996    NP        1352438: Add IsOptionKeyDown and
  15.                                     IsAnyKeyDown
  16.          <3>    .04.1996    NP        Comment about not checking for being in the
  17.                                     background before posing alert.
  18.          <2>     3/29/96    DM        1335889: add TRY block to _Warn() so
  19.                                     exceptions cannot propagate
  20.  
  21.     To Do:
  22.     In Progress:
  23.         
  24. */
  25.  
  26. #ifndef _ODDEBUG_
  27. #include "ODDebug.h"
  28. #endif
  29.  
  30. #ifndef _EXCEPT_
  31. #include "Except.h"
  32. #endif
  33.  
  34. #ifndef _PLFMDEF_
  35. #include "PlfmDef.h"
  36. #endif
  37.  
  38. #ifndef _PASCLSTR_
  39. #include "PasclStr.h"
  40. #endif
  41.  
  42. #ifndef _PLFMDEF_
  43. #include "PlfmDef.h"
  44. #endif
  45.  
  46. #ifndef _EXCEPT_
  47. #include "Except.h"
  48. #endif
  49.  
  50. #ifndef _TEXTUTILS_
  51. #include "TextUtils.h"
  52. #endif
  53.  
  54. #ifndef _CRAWL_
  55. #include "Crawl.h"
  56. #endif
  57.  
  58. #ifndef _USERSRCM_
  59. #include "UseRsrcM.h"
  60. #endif
  61.  
  62. #ifndef _DLOGUTIL_
  63. #include "DlogUtil.h"
  64. #endif
  65.  
  66. #ifndef _UTILDEFS_
  67. #include "UtilDefs.h"
  68. #endif
  69.  
  70. #include <somobj.xh>
  71. #include <somcls.xh>
  72.  
  73. #include <stdio.h>
  74. #include <stdarg.h>
  75. #include <string.h>
  76.  
  77.  
  78. const ODSShort kOutputBufferSize = 400;
  79.  
  80. static somTD_SOMOutCharRoutine    *gOld_SOMOutCharRoutine;
  81. static somTD_SOMError            *gOld_SOMError;
  82.  
  83. // The output buffer is circular. We keep two indices, one for the start
  84. // of the most recent string and one for the end (the current input position.)
  85. static char gOutputBuffer[kOutputBufferSize];
  86. static ODSShort gOutputStart = 0;
  87. static ODSShort gOutputEnd   = 0;
  88.  
  89. static DebugOutputMode gOutputMode = kNoOutput;
  90.  
  91.  
  92. void BREAK( const char[] );
  93.  
  94. static short    gOutputFile = kODNULL;
  95.  
  96. //=====================================================================================
  97. // ODInitExceptions
  98. //=====================================================================================
  99.  
  100.  
  101. extern "C" {
  102.     static int OD_SOMOutCharRoutine( char c );
  103.     static void OD_SOMError( int error, corbastring filename, int linenum );
  104. }
  105.  
  106.  
  107. void
  108. ODInitExceptions( )
  109. {
  110.     gOld_SOMOutCharRoutine    = SOMOutCharRoutine;
  111.     gOld_SOMError            = SOMError;
  112.     SOMOutCharRoutine        = OD_SOMOutCharRoutine;
  113.     SOMError                = OD_SOMError;
  114. //    SOM_WarnLevel            = 1; // all, from somcdev.h
  115. }
  116.  
  117.  
  118. //=====================================================================================
  119. // Output routines
  120. //=====================================================================================
  121.  
  122.  
  123. #ifdef _PLATFORM_MACINTOSH_
  124.  
  125. #ifndef __STRINGS__
  126. #include <Strings.h>
  127. #endif
  128.  
  129.  
  130. static OSErr
  131. SendToDebugWindow( const char buffer[], short length )
  132. {
  133.     // Code adapted from API to "DebugWindow" app by Keith Ledbetter
  134.     AEAddressDesc    address;
  135.     AppleEvent        appleEvent, reply;
  136.     OSType            targetSig;
  137.     OSErr            err;
  138.  
  139.     targetSig = 'LdbW';
  140.     err= AECreateDesc( typeApplSignature, (Ptr)&targetSig, 
  141.                         sizeof(targetSig), &address );
  142.     if( !err ) {
  143.         err= AECreateAppleEvent( 'misc', 'dmsg', &address, kAutoGenerateReturnID,
  144.                                    kAnyTransactionID, &appleEvent );
  145.         AEDisposeDesc( &address );
  146.         if( !err ) {
  147.             err= AEPutParamPtr( &appleEvent, keyDirectObject, typeChar,
  148.                                  buffer, length );
  149.             if( !err ) {
  150.                 err= AESend( &appleEvent, &reply, 
  151.                          kAEWaitReply + kAENeverInteract,
  152.                          kAENormalPriority, 
  153.                          300,                                 // up to 5 second wait..
  154.                          kODNULL, kODNULL );
  155.                 AEDisposeDesc( &reply );
  156.             }
  157.             AEDisposeDesc( &appleEvent );
  158.         }
  159.     }
  160.     return err;
  161. }
  162.  
  163.  
  164. static short CreateNewOutputFile()
  165. {
  166.     static long    nextFilePrefixNum = 1;
  167.  
  168.     Str255            fileNameRootString = "\pstdout";
  169.     Size            fileNameRootLength = fileNameRootString[0];
  170.     Str255            numString;
  171.     Str255            fileNameString;
  172.     short            file = 0;
  173.  
  174.     CopyPascalString(fileNameString, fileNameRootString);
  175.  
  176.     OSErr err = Create(fileNameRootString, 0, 'MPS ', 'TEXT');
  177.     if (err)
  178.     {
  179.         while(err)
  180.         {
  181.             CopyPascalString(fileNameString, fileNameRootString);
  182.             NumToString(nextFilePrefixNum, numString);
  183.             // check for filename too long.
  184.             if (numString[0] + fileNameRootLength > 255)
  185.             {
  186.                 err = 1;
  187.                 break;
  188.             }
  189.             ConcatPascalStrings(fileNameString, numString);
  190.             err = Create(fileNameString, 0, 'MPS ', 'TEXT');
  191.             ++nextFilePrefixNum;
  192.             if (nextFilePrefixNum > 10000) // arbitrary infinite loop stopper.
  193.                 break;
  194.         }
  195.     }
  196.  
  197.     if (!err)
  198.     {
  199.         err = FSOpen(fileNameString, 0, &file);
  200.         if (err)
  201.             file = 0;
  202.     }
  203.  
  204.     return file;
  205. }
  206.  
  207.  
  208. static ODSShort
  209. ExtractBufferString( ODSShort start, ODSShort end, char output[] )
  210. {
  211.     ODSShort len = end-start;
  212.     if( len >= 0 )
  213.         ODBlockMove(gOutputBuffer+start, output, len);
  214.     else {
  215.         ODSShort len1 = kOutputBufferSize-start;
  216.         ODBlockMove(gOutputBuffer+start, output,len1);
  217.         ODBlockMove(gOutputBuffer, output+len1, end);
  218.         len += kOutputBufferSize;
  219.     }
  220.     output[len] = '\0';
  221.     return len;
  222. }
  223.  
  224.  
  225. static int
  226. OD_SOMOutCharRoutine( char c )
  227. {
  228.     if( c ==0x0A )                    // Convert Unix-style newline to Return
  229.         c = 0x0D;
  230.     
  231.     // Add to buffer, wrapping around:
  232.     gOutputBuffer[gOutputEnd++] = c;
  233.     if( gOutputEnd >= kOutputBufferSize )
  234.         gOutputEnd = 0;
  235.  
  236.     if( c == 0x0D )    {            // Dump buffer at end of line
  237.         if( gOutputMode == kWriteToDebugWindow
  238.                 || gOutputMode == kGenerateDebugStrs
  239.                 || gOutputMode == kWriteToFile)
  240.         {
  241.             // Convert latest output to string:
  242.             char output[kOutputBufferSize+1];
  243.             ODSShort len = ExtractBufferString(gOutputStart,gOutputEnd, output);
  244.                         
  245.             OSErr err = noErr;
  246.         
  247.             if (gOutputMode == kWriteToDebugWindow)
  248.                 err = SendToDebugWindow(output,len);
  249.             else if (gOutputMode == kGenerateDebugStrs)
  250.             {
  251.                 if( len > 253 ) len=253;
  252.                 // Concatenate ";g" so debugger keeps going...
  253.                 memmove(output+len,";g\0",3);
  254.                 len += 2;
  255.                 // Convert buffer to pascal string
  256.                 memmove(output + 1, output, len);
  257.                 output[0] = len;
  258.                 DebugStr((StringPtr)output);
  259.             }
  260.             else if (gOutputMode == kWriteToFile)
  261.             {
  262.                 if (gOutputFile == NULL)
  263.                     gOutputFile = CreateNewOutputFile();
  264.                 if (gOutputFile)
  265.                 {
  266.                     long    bytesToWrite = len;
  267.                     err = FSWrite(gOutputFile, &bytesToWrite, output);
  268.                     if (!err && bytesToWrite != len)
  269.                         err = 1;
  270.                 }
  271.                 else
  272.                     err = 1;
  273.             }
  274.     
  275.             if( err )
  276.             {
  277.                 gOutputMode = kGenerateDebugStrs;
  278.                 DebugStr((StringPtr)"\pSOM Message Output: Error writing output -- reverting to DebugStr mode.");
  279.             }
  280.         }
  281.         
  282.         gOutputStart = gOutputEnd;        // "clear" buffer
  283.     }
  284.     
  285.     return 1;
  286. }
  287.  
  288.  
  289. #else /* if not _PLATFORM_MACINTOSH_: */
  290.  
  291.  
  292. static int
  293. OD_SOMOutCharRoutine( char c )
  294. {
  295.     if( gOutputMode == kWriteToFile )
  296.         return gOld_SOMOutCharRoutine(c);
  297.     else
  298.         return 1;
  299. }
  300.  
  301. #endif
  302.  
  303.  
  304. DebugOutputMode
  305. GetOutputMode( )
  306. {
  307.     return gOutputMode;
  308. }
  309.  
  310.  
  311. void
  312. SetOutputMode( DebugOutputMode mode )
  313. {
  314.     if( gOutputMode == kWriteToDebugWindow )
  315.         if( gOutputEnd != gOutputStart )
  316.             OD_SOMOutCharRoutine(0x0D);        // Flush buffer
  317.     gOutputMode = mode;
  318. }
  319.  
  320.  
  321. //=================================================================================== 
  322. // BREAK
  323. //=================================================================================== 
  324.  
  325. void
  326. BREAK( const char msg[] )
  327. {
  328.     somPrintf("%s\n",msg);
  329.     
  330. #ifdef _PLATFORM_MACINTOSH_
  331. #if ODDebug
  332.     // Now convert to Pascal string and call DebugStr:
  333.     Str255 pstr;
  334.     long len = strlen(msg);
  335.     pstr[0] = (len>255) ?255 :len;
  336.     for( int i=pstr[0]; i>0; i-- ) {
  337.         char c = msg[i-1];
  338.         if( c==';' ) c=':';        // ";" is bad in DebugStrs
  339.         pstr[i] = c;
  340.     }
  341.     DebugStr(pstr);
  342. #endif
  343. #endif
  344. }
  345.  
  346.  
  347. //=================================================================================== 
  348. // SOMError
  349. //=================================================================================== 
  350.  
  351. ODBoolean IsThisKeyDown(ODUShort theKey)
  352. {
  353.     unsigned char theKeys[16];
  354.     GetKeys((UInt32*)&theKeys);
  355.  
  356.     return ((theKeys[theKey >> 3] >> (theKey & 7)) & 1);
  357. }
  358.  
  359. static void
  360. OD_SOMError( int error, corbastring filename, int linenum )
  361. {
  362.     const char *kSeverityCode[10] =
  363.                 {"error","warning","message","error?","error?",
  364.                  "error template","error?","error?","error?","fatal error"};
  365.     int base = error / 10000;
  366.     int errno = (error - base*10000) / 10;
  367.     int severity = error % 10;
  368.     
  369.     char msg[kOutputBufferSize+3];
  370.     sprintf(msg, "SOM %s %d-%03d-%d (%s %d): Press G...",
  371.                         kSeverityCode[severity],base,errno,severity,
  372.                         filename,linenum);
  373.     
  374.     if( severity == SOM_Fatal ) {
  375.         somPrintf(msg);
  376.         CUsingLibraryResources r;
  377.         DialogPtr d = kODNULL; ODVolatile(d);
  378.         TRY{
  379.             InitCursor();
  380.             // THIS ALERT SHOULD PROBABLY BE PROTECTED WITH A CHECK FOR THE APP
  381.             //    BEING IN THE BACKGROUND
  382.             ::Alert(kSOMErrorAlertID,kODNULL);
  383.             if( IsOptionKeyDown() ) {
  384.                 d = ::GetNewDialog(kSOMErrorDlogID,kODNULL,(WindowPtr)-1L);
  385.                 SetDialogDefaultItem(d,ok);
  386.                 SetDialogTextStyle(d,kSOMErrorDlogFontInfo, smCurrentScript);
  387.                 
  388.                 // Copy the entire output buffer, not just the last line:
  389.                 ODSShort start = gOutputEnd;
  390.                 do{
  391.                     ++start;
  392.                     if( start >= kOutputBufferSize ) start=0;
  393.                 }while( start!=gOutputEnd && gOutputBuffer[start]=='\0' );
  394.                 strcpy(msg,"...");
  395.                 ODSShort len = ExtractBufferString(start,gOutputEnd, msg+3) +3;
  396.  
  397.                 short typ;
  398.                 Handle h;
  399.                 Rect box;
  400.                 ::GetDialogItem(d,kSOMErrorDlogTextItem, &typ,&h,&box);
  401.                 PtrToXHand(msg,h,len);
  402.                 
  403.             #if !ODDebug
  404.                 HideDialogItem(d,kSOMErrorDlogDebugButton);
  405.             #endif
  406.                 
  407.                 ShowWindow(d);
  408.                 SelectWindow(d);
  409.                 ODSShort item;
  410.                 // THIS ALERT SHOULD PROBABLY BE PROTECTED WITH A CHECK FOR THE
  411.                 //    APP BEING IN THE BACKGROUND
  412.                 ModalDialog(kODNULL,&item);
  413.                 
  414.             #if ODDebug
  415.                 if( item == kSOMErrorDlogDebugButton )
  416.                     Debugger();        // Have a look around...
  417.             #endif
  418.             }
  419.         }CATCH_ALL{
  420.             WARN("Caught error %d displaying SOM error dialog",ErrorCode());
  421.         }ENDTRY
  422.         if( d ) DisposeDialog(d);
  423.         
  424.     } else
  425.         BREAK(msg);                // Nonfatal error: just break
  426.  
  427.     gOld_SOMError(error,filename,linenum);
  428. }
  429.  
  430.  
  431. //=================================================================================== 
  432. // ASSERTION-FAILED
  433. //=================================================================================== 
  434.  
  435. #if ODDebug
  436.  
  437. void _AssertionFailed( char *cond, char *filename,
  438.                         ODError error, char *msg /*=NULL*/ )
  439. {
  440.     char where[300];
  441.     if( ! GetNameOfCaller(where) )
  442.         strcpy(where,filename);
  443.         
  444.     ODUnused(filename);
  445.     char dbg[256];
  446.     if( msg )
  447.         sprintf(dbg,"%s: %s ...NOT! At %s", msg,cond,where); 
  448.     else
  449.         sprintf(dbg,"%s ...NOT! At %s", cond,where); 
  450.     BREAK(dbg);
  451.     
  452.     if( error!=0 )
  453.         THROW(error, msg ?msg :"Assertion failed");
  454. }
  455.  
  456. #else /*not ODDebug*/
  457.  
  458. extern "C" void _AssertionFailed(  char *cond, char *filename,
  459.                         ODError error, char *msg );
  460. void _AssertionFailed( char *cond, char *filename,
  461.                         ODError error, char *msg )
  462. {
  463. }
  464.     
  465. #endif /*ODDebug*/
  466.     
  467.     
  468. //=================================================================================== 
  469. // WARN
  470. //=================================================================================== 
  471.  
  472. #if ODDebug
  473.  
  474. void _Warn( char *fmt, ... )
  475. {
  476.     char msg[512];
  477.     strcpy(msg, "ODWarning: ");
  478.     va_list args;
  479.     va_start(args,fmt);
  480.     vsprintf(msg+strlen(msg),fmt,args);
  481.     va_end(args);
  482.     
  483.     char caller[300];
  484.  
  485.     // DMc: make sure _Warn() cannot throw an exception (out-of-memory when a stack
  486.     // crawl is allocated), because _Warn is often called in unsafe contexts that
  487.     // are not protected by a TRY block:
  488.     TRY {
  489.         if( GetNameOfCaller(caller) ) {
  490.             strcat(msg," (at ");
  491.             strcat(msg,caller);
  492.             strcat(msg,")");
  493.         }
  494.     } CATCH_ALL {
  495.     } ENDTRY
  496.     
  497.     BREAK(msg);
  498. }
  499.     
  500. #else /*not ODDebug*/
  501.  
  502. extern "C" void _Warn(  char *fmt, ... );
  503. void _Warn(  char *fmt, ... )
  504. {
  505. }
  506.  
  507. #endif /*ODDebug*/
  508.     
  509. //==============================================================================
  510. // SAFE CAST
  511. //==============================================================================
  512.  
  513.  
  514. #if ODDebug
  515.  
  516. SOMObject*
  517. _Cast( SOMObject *obj, somClassDataStructure *clsdata, long majorversion, long minorversion )
  518. {
  519.     SOMClass *cls = (SOMClass*) somGetStaticClassReference(clsdata,majorversion,minorversion);
  520.     if( !somIsObj(obj) )
  521.         WARN("Can't cast: %p is not a SOM object",obj);
  522.     else if( !somIsObj(cls) )
  523.         WARN("Can't cast: %p is not a SOM class",cls);
  524.     else if( !obj->somIsA(cls) )
  525.         WARN("Can't cast: %p is an %s, not an %s",obj, obj->somGetClassName(), cls->somGetName());
  526.     else {
  527.         somReleaseClassReference(cls);
  528.         return obj;
  529.     }
  530.     somReleaseClassReference(cls);
  531.     THROW(kODErrAssertionFailed);
  532.     return NULL; /* keeps compiler quiet */
  533. }
  534.  
  535. #else /*not ODDebug*/
  536.  
  537. extern "C" void _Cast( );
  538. void _Cast( )
  539. {
  540. }
  541.     
  542. #endif /*ODDebug*/
  543.