home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / src / common / log.cpp < prev    next >
C/C++ Source or Header  |  2002-05-12  |  29KB  |  975 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        log.cpp
  3. // Purpose:     Assorted wxLogXXX functions, and wxLog (sink for logs)
  4. // Author:      Vadim Zeitlin
  5. // Modified by:
  6. // Created:     29/01/98
  7. // RCS-ID:      $Id: log.cpp,v 1.128 2002/05/09 15:59:42 VZ Exp $
  8. // Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
  9. // Licence:     wxWindows license
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. // ============================================================================
  13. // declarations
  14. // ============================================================================
  15.  
  16. // ----------------------------------------------------------------------------
  17. // headers
  18. // ----------------------------------------------------------------------------
  19.  
  20. #ifdef __GNUG__
  21.   #pragma implementation "log.h"
  22. #endif
  23.  
  24. // For compilers that support precompilation, includes "wx.h".
  25. #include "wx/wxprec.h"
  26.  
  27. #ifdef __BORLANDC__
  28.   #pragma hdrstop
  29. #endif
  30.  
  31. // wxWindows
  32. #ifndef WX_PRECOMP
  33.     #include "wx/string.h"
  34.     #include "wx/intl.h"
  35.     #include "wx/app.h"
  36.  
  37.     #if wxUSE_GUI
  38.         #include "wx/window.h"
  39.         #include "wx/msgdlg.h"
  40.         #ifdef __WXMSW__
  41.             #include "wx/msw/private.h"
  42.         #endif
  43.     #endif
  44. #endif //WX_PRECOMP
  45.  
  46. #include  "wx/file.h"
  47. #include  "wx/textfile.h"
  48. #include  "wx/utils.h"
  49. #include  "wx/wxchar.h"
  50. #include  "wx/log.h"
  51. #include  "wx/thread.h"
  52.  
  53. #if wxUSE_LOG
  54.  
  55. // other standard headers
  56. #include  <errno.h>
  57. #include  <stdlib.h>
  58. #include  <time.h>
  59.  
  60. #if defined(__WXMSW__)
  61.   #include  "wx/msw/private.h"      // includes windows.h for OutputDebugString
  62. #endif
  63.  
  64. #if defined(__WXMAC__)
  65.   #include  "wx/mac/private.h"  // includes mac headers
  66. #endif
  67.  
  68. // ----------------------------------------------------------------------------
  69. // non member functions
  70. // ----------------------------------------------------------------------------
  71.  
  72. // define this to enable wrapping of log messages
  73. //#define LOG_PRETTY_WRAP
  74.  
  75. #ifdef  LOG_PRETTY_WRAP
  76.   static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz);
  77. #endif
  78.  
  79. // ============================================================================
  80. // implementation
  81. // ============================================================================
  82.  
  83. // ----------------------------------------------------------------------------
  84. // globals
  85. // ----------------------------------------------------------------------------
  86.  
  87. // log functions can't allocate memory (LogError("out of memory...") should
  88. // work!), so we use a static buffer for all log messages
  89. #define LOG_BUFFER_SIZE   (4096)
  90.  
  91. // static buffer for error messages
  92. static wxChar   s_szBufStatic[LOG_BUFFER_SIZE];
  93.  
  94. static wxChar  *s_szBuf     = s_szBufStatic;
  95. static size_t   s_szBufSize = WXSIZEOF( s_szBufStatic );
  96.  
  97. #if wxUSE_THREADS
  98.  
  99. // the critical section protecting the static buffer
  100. static wxCriticalSection gs_csLogBuf;
  101.  
  102. #endif // wxUSE_THREADS
  103.  
  104. // return true if we have a non NULL non disabled log target
  105. static inline bool IsLoggingEnabled()
  106. {
  107.     return wxLog::IsEnabled() && (wxLog::GetActiveTarget() != NULL);
  108. }
  109.  
  110. // ----------------------------------------------------------------------------
  111. // implementation of Log functions
  112. //
  113. // NB: unfortunately we need all these distinct functions, we can't make them
  114. //     macros and not all compilers inline vararg functions.
  115. // ----------------------------------------------------------------------------
  116.  
  117. // generic log function
  118. void wxVLogGeneric(wxLogLevel level, const wxChar *szFormat, va_list argptr)
  119. {
  120.     if ( IsLoggingEnabled() ) {
  121.         wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
  122.  
  123.         wxVsnprintf(s_szBuf, s_szBufSize, szFormat, argptr);
  124.  
  125.         wxLog::OnLog(level, s_szBuf, time(NULL));
  126.     }
  127. }
  128.  
  129. void wxLogGeneric(wxLogLevel level, const wxChar *szFormat, ...)
  130. {
  131.     va_list argptr;
  132.     va_start(argptr, szFormat);
  133.     wxVLogGeneric(level, szFormat, argptr);
  134.     va_end(argptr);
  135. }
  136.  
  137. #define IMPLEMENT_LOG_FUNCTION(level)                               \
  138.   void wxVLog##level(const wxChar *szFormat, va_list argptr)        \
  139.   {                                                                 \
  140.     if ( IsLoggingEnabled() ) {                                     \
  141.       wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);                      \
  142.                                                                     \
  143.       wxVsnprintf(s_szBuf, s_szBufSize, szFormat, argptr);    \
  144.                                                                     \
  145.       wxLog::OnLog(wxLOG_##level, s_szBuf, time(NULL));             \
  146.     }                                                               \
  147.   }                                                                 \
  148.   void wxLog##level(const wxChar *szFormat, ...)                    \
  149.   {                                                                 \
  150.     va_list argptr;                                                 \
  151.     va_start(argptr, szFormat);                                     \
  152.     wxVLog##level(szFormat, argptr);                                \
  153.     va_end(argptr);                                                 \
  154.   }
  155.  
  156. IMPLEMENT_LOG_FUNCTION(Error)
  157. IMPLEMENT_LOG_FUNCTION(Warning)
  158. IMPLEMENT_LOG_FUNCTION(Message)
  159. IMPLEMENT_LOG_FUNCTION(Info)
  160. IMPLEMENT_LOG_FUNCTION(Status)
  161.  
  162. void wxSafeShowMessage(const wxString& title, const wxString& text)
  163. {
  164. #ifdef __WINDOWS__
  165.     ::MessageBox(NULL, text, title, MB_OK | MB_ICONSTOP);
  166. #else
  167.     wxFprintf(stderr, _T("%s: %s\n"), title.c_str(), text.c_str());
  168. #endif
  169. }
  170.  
  171. // fatal errors can't be suppressed nor handled by the custom log target and
  172. // always terminate the program
  173. void wxVLogFatalError(const wxChar *szFormat, va_list argptr)
  174. {
  175.     wxVsnprintf(s_szBuf, s_szBufSize, szFormat, argptr);
  176.  
  177.     wxSafeShowMessage(_T("Fatal Error"), s_szBuf);
  178.  
  179.     abort();
  180. }
  181.  
  182. void wxLogFatalError(const wxChar *szFormat, ...)
  183. {
  184.     va_list argptr;
  185.     va_start(argptr, szFormat);
  186.     wxVLogFatalError(szFormat, argptr);
  187.     va_end(argptr);
  188. }
  189.  
  190. // same as info, but only if 'verbose' mode is on
  191. void wxVLogVerbose(const wxChar *szFormat, va_list argptr)
  192. {
  193.     if ( IsLoggingEnabled() ) {
  194.         wxLog *pLog = wxLog::GetActiveTarget();
  195.         if ( pLog != NULL && pLog->GetVerbose() ) {
  196.             wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
  197.  
  198.             wxVsnprintf(s_szBuf, s_szBufSize, szFormat, argptr);
  199.  
  200.             wxLog::OnLog(wxLOG_Info, s_szBuf, time(NULL));
  201.         }
  202.     }
  203. }
  204.  
  205. void wxLogVerbose(const wxChar *szFormat, ...)
  206. {
  207.     va_list argptr;
  208.     va_start(argptr, szFormat);
  209.     wxVLogVerbose(szFormat, argptr);
  210.     va_end(argptr);
  211. }
  212.  
  213. // debug functions
  214. #ifdef __WXDEBUG__
  215. #define IMPLEMENT_LOG_DEBUG_FUNCTION(level)                         \
  216.   void wxVLog##level(const wxChar *szFormat, va_list argptr)        \
  217.   {                                                                 \
  218.     if ( IsLoggingEnabled() ) {                                     \
  219.       wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);                      \
  220.                                                                     \
  221.       wxVsnprintf(s_szBuf, s_szBufSize, szFormat, argptr);    \
  222.                                                                     \
  223.       wxLog::OnLog(wxLOG_##level, s_szBuf, time(NULL));             \
  224.     }                                                               \
  225.   }                                                                 \
  226.   void wxLog##level(const wxChar *szFormat, ...)                    \
  227.   {                                                                 \
  228.     va_list argptr;                                                 \
  229.     va_start(argptr, szFormat);                                     \
  230.     wxVLog##level(szFormat, argptr);                                \
  231.     va_end(argptr);                                                 \
  232.   }
  233.  
  234.   void wxVLogTrace(const wxChar *mask, const wxChar *szFormat, va_list argptr)
  235.   {
  236.     if ( IsLoggingEnabled() && wxLog::IsAllowedTraceMask(mask) ) {
  237.       wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
  238.  
  239.       wxChar *p = s_szBuf;
  240.       size_t len = s_szBufSize;
  241.       wxStrncpy(s_szBuf, _T("("), len);
  242.       len -= 1; // strlen("(")
  243.       p += 1;
  244.       wxStrncat(p, mask, len);
  245.       size_t lenMask = wxStrlen(mask);
  246.       len -= lenMask;
  247.       p += lenMask;
  248.  
  249.       wxStrncat(p, _T(") "), len);
  250.       len -= 2;
  251.       p += 2;
  252.  
  253.       wxVsnprintf(p, len, szFormat, argptr);
  254.  
  255.       wxLog::OnLog(wxLOG_Trace, s_szBuf, time(NULL));
  256.     }
  257.   }
  258.  
  259.   void wxLogTrace(const wxChar *mask, const wxChar *szFormat, ...)
  260.   {
  261.     va_list argptr;
  262.     va_start(argptr, szFormat);
  263.     wxVLogTrace(mask, szFormat, argptr);
  264.     va_end(argptr);
  265.   }
  266.  
  267.   void wxVLogTrace(wxTraceMask mask, const wxChar *szFormat, va_list argptr)
  268.   {
  269.     // we check that all of mask bits are set in the current mask, so
  270.     // that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something
  271.     // if both bits are set.
  272.     if ( IsLoggingEnabled() && ((wxLog::GetTraceMask() & mask) == mask) ) {
  273.       wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
  274.  
  275.       wxVsnprintf(s_szBuf, s_szBufSize, szFormat, argptr);
  276.  
  277.       wxLog::OnLog(wxLOG_Trace, s_szBuf, time(NULL));
  278.     }
  279.   }
  280.  
  281.   void wxLogTrace(wxTraceMask mask, const wxChar *szFormat, ...)
  282.   {
  283.     va_list argptr;
  284.     va_start(argptr, szFormat);
  285.     wxVLogTrace(mask, szFormat, argptr);
  286.     va_end(argptr);
  287.   }
  288.  
  289. #else // release
  290.   #define IMPLEMENT_LOG_DEBUG_FUNCTION(level)
  291. #endif
  292.  
  293. IMPLEMENT_LOG_DEBUG_FUNCTION(Debug)
  294. IMPLEMENT_LOG_DEBUG_FUNCTION(Trace)
  295.  
  296. // wxLogSysError: one uses the last error code, for other  you must give it
  297. // explicitly
  298.  
  299. // common part of both wxLogSysError
  300. void wxLogSysErrorHelper(long lErrCode)
  301. {
  302.     wxChar szErrMsg[LOG_BUFFER_SIZE / 2];
  303.     wxSnprintf(szErrMsg, WXSIZEOF(szErrMsg),
  304.                _(" (error %ld: %s)"), lErrCode, wxSysErrorMsg(lErrCode));
  305.     wxStrncat(s_szBuf, szErrMsg, s_szBufSize - wxStrlen(s_szBuf));
  306.  
  307.     wxLog::OnLog(wxLOG_Error, s_szBuf, time(NULL));
  308. }
  309.  
  310. void WXDLLEXPORT wxVLogSysError(const wxChar *szFormat, va_list argptr)
  311. {
  312.     if ( IsLoggingEnabled() ) {
  313.         wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
  314.  
  315.         wxVsnprintf(s_szBuf, s_szBufSize, szFormat, argptr);
  316.  
  317.         wxLogSysErrorHelper(wxSysErrorCode());
  318.     }
  319. }
  320.  
  321. void WXDLLEXPORT wxLogSysError(const wxChar *szFormat, ...)
  322. {
  323.     va_list argptr;
  324.     va_start(argptr, szFormat);
  325.     wxVLogSysError(szFormat, argptr);
  326.     va_end(argptr);
  327. }
  328.  
  329. void WXDLLEXPORT wxVLogSysError(long lErrCode, const wxChar *szFormat, va_list argptr)
  330. {
  331.     if ( IsLoggingEnabled() ) {
  332.         wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
  333.  
  334.         wxVsnprintf(s_szBuf, s_szBufSize, szFormat, argptr);
  335.  
  336.         wxLogSysErrorHelper(lErrCode);
  337.     }
  338. }
  339.  
  340. void WXDLLEXPORT wxLogSysError(long lErrCode, const wxChar *szFormat, ...)
  341. {
  342.     va_list argptr;
  343.     va_start(argptr, szFormat);
  344.     wxVLogSysError(lErrCode, szFormat, argptr);
  345.     va_end(argptr);
  346. }
  347.  
  348. // ----------------------------------------------------------------------------
  349. // wxLog class implementation
  350. // ----------------------------------------------------------------------------
  351.  
  352. wxLog::wxLog()
  353. {
  354.     m_bHasMessages = FALSE;
  355. }
  356.  
  357. wxChar *wxLog::SetLogBuffer( wxChar *buf, size_t size)
  358. {
  359.     wxChar *oldbuf = s_szBuf;
  360.  
  361.     if( buf == 0 )
  362.     {
  363.         s_szBuf = s_szBufStatic;
  364.         s_szBufSize = WXSIZEOF( s_szBufStatic );
  365.     }
  366.     else
  367.     {
  368.         s_szBuf = buf;
  369.         s_szBufSize = size;
  370.     }
  371.  
  372.     return (oldbuf == s_szBufStatic ) ? 0 : oldbuf;
  373. }
  374.  
  375. wxLog *wxLog::GetActiveTarget()
  376. {
  377.     if ( ms_bAutoCreate && ms_pLogger == NULL ) {
  378.         // prevent infinite recursion if someone calls wxLogXXX() from
  379.         // wxApp::CreateLogTarget()
  380.         static bool s_bInGetActiveTarget = FALSE;
  381.         if ( !s_bInGetActiveTarget ) {
  382.             s_bInGetActiveTarget = TRUE;
  383.  
  384.             // ask the application to create a log target for us
  385.             if ( wxTheApp != NULL )
  386.                 ms_pLogger = wxTheApp->CreateLogTarget();
  387.             else
  388.                 ms_pLogger = new wxLogStderr;
  389.  
  390.             s_bInGetActiveTarget = FALSE;
  391.  
  392.             // do nothing if it fails - what can we do?
  393.         }
  394.     }
  395.  
  396.     return ms_pLogger;
  397. }
  398.  
  399. wxLog *wxLog::SetActiveTarget(wxLog *pLogger)
  400. {
  401.     if ( ms_pLogger != NULL ) {
  402.         // flush the old messages before changing because otherwise they might
  403.         // get lost later if this target is not restored
  404.         ms_pLogger->Flush();
  405.     }
  406.  
  407.     wxLog *pOldLogger = ms_pLogger;
  408.     ms_pLogger = pLogger;
  409.  
  410.     return pOldLogger;
  411. }
  412.  
  413. void wxLog::DontCreateOnDemand()
  414. {
  415.     ms_bAutoCreate = FALSE;
  416.  
  417.     // this is usually called at the end of the program and we assume that it
  418.     // is *always* called at the end - so we free memory here to avoid false
  419.     // memory leak reports from wxWin  memory tracking code
  420.     ClearTraceMasks();
  421. }
  422.  
  423. void wxLog::RemoveTraceMask(const wxString& str)
  424. {
  425.     int index = ms_aTraceMasks.Index(str);
  426.     if ( index != wxNOT_FOUND )
  427.         ms_aTraceMasks.Remove((size_t)index);
  428. }
  429.  
  430. void wxLog::ClearTraceMasks()
  431. {
  432.     ms_aTraceMasks.Clear();
  433. }
  434.  
  435. void wxLog::TimeStamp(wxString *str)
  436. {
  437.     if ( ms_timestamp )
  438.     {
  439.         wxChar buf[256];
  440.         time_t timeNow;
  441.         (void)time(&timeNow);
  442.         wxStrftime(buf, WXSIZEOF(buf), ms_timestamp, localtime(&timeNow));
  443.  
  444.         str->Empty();
  445.         *str << buf << wxT(": ");
  446.     }
  447. }
  448.  
  449. void wxLog::DoLog(wxLogLevel level, const wxChar *szString, time_t t)
  450. {
  451.     switch ( level ) {
  452.         case wxLOG_FatalError:
  453.             DoLogString(wxString(_("Fatal error: ")) + szString, t);
  454.             DoLogString(_("Program aborted."), t);
  455.             Flush();
  456.             abort();
  457.             break;
  458.  
  459.         case wxLOG_Error:
  460.             DoLogString(wxString(_("Error: ")) + szString, t);
  461.             break;
  462.  
  463.         case wxLOG_Warning:
  464.             DoLogString(wxString(_("Warning: ")) + szString, t);
  465.             break;
  466.  
  467.         case wxLOG_Info:
  468.             if ( GetVerbose() )
  469.         case wxLOG_Message:
  470.         case wxLOG_Status:
  471.         default:    // log unknown log levels too
  472.                 DoLogString(szString, t);
  473.             break;
  474.  
  475.         case wxLOG_Trace:
  476.         case wxLOG_Debug:
  477. #ifdef __WXDEBUG__
  478.             {
  479.                 wxString msg = level == wxLOG_Trace ? wxT("Trace: ")
  480.                                                     : wxT("Debug: ");
  481.                 msg << szString;
  482.                 DoLogString(msg, t);
  483.             }
  484. #endif // Debug
  485.             break;
  486.     }
  487. }
  488.  
  489. void wxLog::DoLogString(const wxChar *WXUNUSED(szString), time_t WXUNUSED(t))
  490. {
  491.     wxFAIL_MSG(wxT("DoLogString must be overriden if it's called."));
  492. }
  493.  
  494. void wxLog::Flush()
  495. {
  496.     // remember that we don't have any more messages to show
  497.     m_bHasMessages = FALSE;
  498. }
  499.  
  500. // ----------------------------------------------------------------------------
  501. // wxLogStderr class implementation
  502. // ----------------------------------------------------------------------------
  503.  
  504. wxLogStderr::wxLogStderr(FILE *fp)
  505. {
  506.     if ( fp == NULL )
  507.         m_fp = stderr;
  508.     else
  509.         m_fp = fp;
  510. }
  511.  
  512. #if defined(__WXMAC__) && !defined(__DARWIN__) && (__MWERKS__ > 0x5300)
  513.  
  514. #if !TARGET_API_MAC_CARBON
  515. // MetroNub stuff doesn't seem to work in CodeWarrior 5.3 Carbon builds...
  516.  
  517. #ifndef __MetroNubUtils__
  518. #include "MetroNubUtils.h"
  519. #endif
  520.  
  521. #ifdef __cplusplus
  522.     extern "C" {
  523. #endif
  524.  
  525. #ifndef __GESTALT__
  526. #include <Gestalt.h>
  527. #endif
  528.  
  529. #ifndef true
  530. #define true 1
  531. #endif
  532.  
  533. #ifndef false
  534. #define false 0
  535. #endif
  536.  
  537. #if TARGET_API_MAC_CARBON
  538.  
  539.     #include <CodeFragments.h>
  540.  
  541.     EXTERN_API_C( long )
  542.     CallUniversalProc(UniversalProcPtr theProcPtr, ProcInfoType procInfo, ...);
  543.  
  544.     ProcPtr gCallUniversalProc_Proc = NULL;
  545.  
  546. #endif
  547.  
  548. static MetroNubUserEntryBlock*    gMetroNubEntry = NULL;
  549.  
  550. static long fRunOnce = false;
  551.  
  552. Boolean IsCompatibleVersion(short inVersion);
  553.  
  554. /* ---------------------------------------------------------------------------
  555.         IsCompatibleVersion
  556.    --------------------------------------------------------------------------- */
  557.  
  558. Boolean IsCompatibleVersion(short inVersion)
  559. {
  560.     Boolean result = false;
  561.  
  562.     if (fRunOnce)
  563.     {
  564.         MetroNubUserEntryBlock* block = (MetroNubUserEntryBlock *)result;
  565.  
  566.         result = (inVersion <= block->apiHiVersion);
  567.     }
  568.  
  569.     return result;
  570. }
  571.  
  572. /* ---------------------------------------------------------------------------
  573.         IsMetroNubInstalled
  574.    --------------------------------------------------------------------------- */
  575.  
  576. Boolean IsMetroNubInstalled()
  577. {
  578.     if (!fRunOnce)
  579.     {
  580.         long result, value;
  581.  
  582.         fRunOnce = true;
  583.         gMetroNubEntry = NULL;
  584.  
  585.         if (Gestalt(gestaltSystemVersion, &value) == noErr && value < 0x1000)
  586.         {
  587.             /* look for MetroNub's Gestalt selector */
  588.             if (Gestalt(kMetroNubUserSignature, &result) == noErr)
  589.             {
  590.  
  591.             #if TARGET_API_MAC_CARBON
  592.                 if (gCallUniversalProc_Proc == NULL)
  593.                 {
  594.                     CFragConnectionID   connectionID;
  595.                     Ptr                 mainAddress;
  596.                     Str255              errorString;
  597.                     ProcPtr             symbolAddress;
  598.                     OSErr               err;
  599.                     CFragSymbolClass    symbolClass;
  600.  
  601.                     symbolAddress = NULL;
  602.                     err = GetSharedLibrary("\pInterfaceLib", kPowerPCCFragArch, kFindCFrag,
  603.                                            &connectionID, &mainAddress, errorString);
  604.  
  605.                     if (err != noErr)
  606.                     {
  607.                         gCallUniversalProc_Proc = NULL;
  608.                         goto end;
  609.                     }
  610.  
  611.                     err = FindSymbol(connectionID, "\pCallUniversalProc",
  612.                                     (Ptr *) &gCallUniversalProc_Proc, &symbolClass);
  613.  
  614.                     if (err != noErr)
  615.                     {
  616.                         gCallUniversalProc_Proc = NULL;
  617.                         goto end;
  618.                     }
  619.                 }
  620.             #endif
  621.  
  622.                 {
  623.                     MetroNubUserEntryBlock* block = (MetroNubUserEntryBlock *)result;
  624.  
  625.                     /* make sure the version of the API is compatible */
  626.                     if (block->apiLowVersion <= kMetroNubUserAPIVersion &&
  627.                         kMetroNubUserAPIVersion <= block->apiHiVersion)
  628.                         gMetroNubEntry = block;        /* success! */
  629.                 }
  630.  
  631.             }
  632.         }
  633.     }
  634.  
  635. end:
  636.  
  637. #if TARGET_API_MAC_CARBON
  638.     return (gMetroNubEntry != NULL && gCallUniversalProc_Proc != NULL);
  639. #else
  640.     return (gMetroNubEntry != NULL);
  641. #endif
  642. }
  643.  
  644. /* ---------------------------------------------------------------------------
  645.         IsMWDebuggerRunning                                            [v1 API]
  646.    --------------------------------------------------------------------------- */
  647.  
  648. Boolean IsMWDebuggerRunning()
  649. {
  650.     if (IsMetroNubInstalled())
  651.         return CallIsDebuggerRunningProc(gMetroNubEntry->isDebuggerRunning);
  652.     else
  653.         return false;
  654. }
  655.  
  656. /* ---------------------------------------------------------------------------
  657.         AmIBeingMWDebugged                                            [v1 API]
  658.    --------------------------------------------------------------------------- */
  659.  
  660. Boolean AmIBeingMWDebugged()
  661. {
  662.     if (IsMetroNubInstalled())
  663.         return CallAmIBeingDebuggedProc(gMetroNubEntry->amIBeingDebugged);
  664.     else
  665.         return false;
  666. }
  667.  
  668. /* ---------------------------------------------------------------------------
  669.         UserSetWatchPoint                                            [v2 API]
  670.    --------------------------------------------------------------------------- */
  671.  
  672. OSErr UserSetWatchPoint (Ptr address, long length, WatchPointIDT* watchPointID)
  673. {
  674.     if (IsMetroNubInstalled() && IsCompatibleVersion(kMetroNubUserAPIVersion))
  675.         return CallUserSetWatchPointProc(gMetroNubEntry->userSetWatchPoint,
  676.                                          address, length, watchPointID);
  677.     else
  678.         return errProcessIsNotClient;
  679. }
  680.  
  681. /* ---------------------------------------------------------------------------
  682.         ClearWatchPoint                                                [v2 API]
  683.    --------------------------------------------------------------------------- */
  684.  
  685. OSErr ClearWatchPoint (WatchPointIDT watchPointID)
  686. {
  687.     if (IsMetroNubInstalled() && IsCompatibleVersion(kMetroNubUserAPIVersion))
  688.         return CallClearWatchPointProc(gMetroNubEntry->clearWatchPoint, watchPointID);
  689.     else
  690.         return errProcessIsNotClient;
  691. }
  692.  
  693. #ifdef __cplusplus
  694.     }
  695. #endif
  696.  
  697. #endif // !TARGET_API_MAC_CARBON
  698.  
  699. #endif // defined(__WXMAC__) && !defined(__DARWIN__) && (__MWERKS__ > 0x5300)
  700.  
  701. void wxLogStderr::DoLogString(const wxChar *szString, time_t WXUNUSED(t))
  702. {
  703.     wxString str;
  704.     TimeStamp(&str);
  705.     str << szString;
  706.  
  707.     fputs(str.mb_str(), m_fp);
  708.     fputc(_T('\n'), m_fp);
  709.     fflush(m_fp);
  710.  
  711.     // under Windows, programs usually don't have stderr at all, so show the
  712.     // messages also under debugger - unless it's a console program
  713. #if defined(__WXMSW__) && wxUSE_GUI && !defined(__WXMICROWIN__)
  714.     str += wxT("\r\n") ;
  715.     OutputDebugString(str.c_str());
  716. #endif // MSW
  717. #if defined(__WXMAC__) && !defined(__DARWIN__) && wxUSE_GUI
  718.     Str255 pstr ;
  719.     strcpy( (char*) pstr , str.c_str() ) ;
  720.     strcat( (char*) pstr , ";g" ) ;
  721.     c2pstr( (char*) pstr ) ;
  722.  
  723.     Boolean running = false ;
  724.  
  725. #if !TARGET_API_MAC_CARBON && (__MWERKS__ > 0x5300)
  726.  
  727.     if ( IsMWDebuggerRunning() && AmIBeingMWDebugged() )
  728.     {
  729.         running = true ;
  730.     }
  731.  
  732. #endif
  733.  
  734.     if (running)
  735.     {
  736. #ifdef __powerc
  737.         DebugStr(pstr);
  738. #else
  739.         SysBreakStr(pstr);
  740. #endif
  741.     }
  742. #endif // Mac
  743. }
  744.  
  745. // ----------------------------------------------------------------------------
  746. // wxLogStream implementation
  747. // ----------------------------------------------------------------------------
  748.  
  749. #if wxUSE_STD_IOSTREAM
  750. wxLogStream::wxLogStream(wxSTD ostream *ostr)
  751. {
  752.     if ( ostr == NULL )
  753.         m_ostr = &wxSTD cerr;
  754.     else
  755.         m_ostr = ostr;
  756. }
  757.  
  758. void wxLogStream::DoLogString(const wxChar *szString, time_t WXUNUSED(t))
  759. {
  760.     wxString str;
  761.     TimeStamp(&str);
  762.     (*m_ostr) << str << wxConvertWX2MB(szString) << wxSTD endl;
  763. }
  764. #endif // wxUSE_STD_IOSTREAM
  765.  
  766. // ----------------------------------------------------------------------------
  767. // wxLogChain
  768. // ----------------------------------------------------------------------------
  769.  
  770. wxLogChain::wxLogChain(wxLog *logger)
  771. {
  772.     m_bPassMessages = TRUE;
  773.  
  774.     m_logNew = logger;
  775.     m_logOld = wxLog::SetActiveTarget(this);
  776. }
  777.  
  778. wxLogChain::~wxLogChain()
  779. {
  780.     delete m_logOld;
  781.  
  782.     if ( m_logNew != this )
  783.         delete m_logNew;
  784. }
  785.  
  786. void wxLogChain::SetLog(wxLog *logger)
  787. {
  788.     if ( m_logNew != this )
  789.         delete m_logNew;
  790.  
  791.     m_logNew = logger;
  792. }
  793.  
  794. void wxLogChain::Flush()
  795. {
  796.     if ( m_logOld )
  797.         m_logOld->Flush();
  798.  
  799.     // be careful to avoid inifinite recursion
  800.     if ( m_logNew && m_logNew != this )
  801.         m_logNew->Flush();
  802. }
  803.  
  804. void wxLogChain::DoLog(wxLogLevel level, const wxChar *szString, time_t t)
  805. {
  806.     // let the previous logger show it
  807.     if ( m_logOld && IsPassingMessages() )
  808.     {
  809.         // bogus cast just to access protected DoLog
  810.         ((wxLogChain *)m_logOld)->DoLog(level, szString, t);
  811.     }
  812.  
  813.     if ( m_logNew && m_logNew != this )
  814.     {
  815.         // as above...
  816.         ((wxLogChain *)m_logNew)->DoLog(level, szString, t);
  817.     }
  818. }
  819.  
  820. // ----------------------------------------------------------------------------
  821. // wxLogPassThrough
  822. // ----------------------------------------------------------------------------
  823.  
  824. #ifdef __VISUALC__
  825.     // "'this' : used in base member initializer list" - so what?
  826.     #pragma warning(disable:4355)
  827. #endif // VC++
  828.  
  829. wxLogPassThrough::wxLogPassThrough()
  830.                 : wxLogChain(this)
  831. {
  832. }
  833.  
  834. #ifdef __VISUALC__
  835.     #pragma warning(default:4355)
  836. #endif // VC++
  837.  
  838. // ============================================================================
  839. // Global functions/variables
  840. // ============================================================================
  841.  
  842. // ----------------------------------------------------------------------------
  843. // static variables
  844. // ----------------------------------------------------------------------------
  845.  
  846. wxLog          *wxLog::ms_pLogger      = (wxLog *)NULL;
  847. bool            wxLog::ms_doLog        = TRUE;
  848. bool            wxLog::ms_bAutoCreate  = TRUE;
  849. bool            wxLog::ms_bVerbose     = FALSE;
  850.  
  851. size_t          wxLog::ms_suspendCount = 0;
  852.  
  853. #if wxUSE_GUI
  854.     const wxChar *wxLog::ms_timestamp  = wxT("%X");  // time only, no date
  855. #else
  856.     const wxChar *wxLog::ms_timestamp  = NULL;       // save space
  857. #endif
  858.  
  859. wxTraceMask     wxLog::ms_ulTraceMask  = (wxTraceMask)0;
  860. wxArrayString   wxLog::ms_aTraceMasks;
  861.  
  862. // ----------------------------------------------------------------------------
  863. // stdout error logging helper
  864. // ----------------------------------------------------------------------------
  865.  
  866. // helper function: wraps the message and justifies it under given position
  867. // (looks more pretty on the terminal). Also adds newline at the end.
  868. //
  869. // TODO this is now disabled until I find a portable way of determining the
  870. //      terminal window size (ok, I found it but does anybody really cares?)
  871. #ifdef LOG_PRETTY_WRAP
  872. static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz)
  873. {
  874.     size_t nMax = 80; // FIXME
  875.     size_t nStart = strlen(pszPrefix);
  876.     fputs(pszPrefix, f);
  877.  
  878.     size_t n;
  879.     while ( *psz != '\0' ) {
  880.         for ( n = nStart; (n < nMax) && (*psz != '\0'); n++ )
  881.             putc(*psz++, f);
  882.  
  883.         // wrapped?
  884.         if ( *psz != '\0' ) {
  885.             /*putc('\n', f);*/
  886.             for ( n = 0; n < nStart; n++ )
  887.                 putc(' ', f);
  888.  
  889.             // as we wrapped, squeeze all white space
  890.             while ( isspace(*psz) )
  891.                 psz++;
  892.         }
  893.     }
  894.  
  895.     putc('\n', f);
  896. }
  897. #endif  //LOG_PRETTY_WRAP
  898.  
  899. // ----------------------------------------------------------------------------
  900. // error code/error message retrieval functions
  901. // ----------------------------------------------------------------------------
  902.  
  903. // get error code from syste
  904. unsigned long wxSysErrorCode()
  905. {
  906. #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
  907. #ifdef  __WIN32__
  908.     return ::GetLastError();
  909. #else   //WIN16
  910.     // TODO what to do on Windows 3.1?
  911.     return 0;
  912. #endif  //WIN16/32
  913. #else   //Unix
  914.     return errno;
  915. #endif  //Win/Unix
  916. }
  917.  
  918. // get error message from system
  919. const wxChar *wxSysErrorMsg(unsigned long nErrCode)
  920. {
  921.     if ( nErrCode == 0 )
  922.         nErrCode = wxSysErrorCode();
  923.  
  924. #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
  925. #ifdef  __WIN32__
  926.     static wxChar s_szBuf[LOG_BUFFER_SIZE / 2];
  927.  
  928.     // get error message from system
  929.     LPVOID lpMsgBuf;
  930.     FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  931.             NULL, nErrCode,
  932.             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  933.             (LPTSTR)&lpMsgBuf,
  934.             0, NULL);
  935.  
  936.     // copy it to our buffer and free memory
  937.     if( lpMsgBuf != 0 ) {
  938.         wxStrncpy(s_szBuf, (const wxChar *)lpMsgBuf, WXSIZEOF(s_szBuf) - 1);
  939.         s_szBuf[WXSIZEOF(s_szBuf) - 1] = wxT('\0');
  940.  
  941.         LocalFree(lpMsgBuf);
  942.  
  943.         // returned string is capitalized and ended with '\r\n' - bad
  944.         s_szBuf[0] = (wxChar)wxTolower(s_szBuf[0]);
  945.         size_t len = wxStrlen(s_szBuf);
  946.         if ( len > 0 ) {
  947.             // truncate string
  948.             if ( s_szBuf[len - 2] == wxT('\r') )
  949.                 s_szBuf[len - 2] = wxT('\0');
  950.         }
  951.     }
  952.     else {
  953.         s_szBuf[0] = wxT('\0');
  954.     }
  955.  
  956.     return s_szBuf;
  957. #else   //Win16
  958.     // TODO
  959.     return NULL;
  960. #endif // Win16/32
  961. #else   // Unix
  962. #if wxUSE_UNICODE
  963.     static wxChar s_szBuf[LOG_BUFFER_SIZE / 2];
  964.     wxConvCurrent->MB2WC(s_szBuf, strerror(nErrCode), WXSIZEOF(s_szBuf) -1);
  965.     return s_szBuf;
  966. #else
  967.     return strerror((int)nErrCode);
  968. #endif
  969. #endif  // Win/Unix
  970. }
  971.  
  972. #endif //wxUSE_LOG
  973.  
  974. // vi:sts=4:sw=4:et
  975.