home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / common / log.cpp < prev    next >
C/C++ Source or Header  |  2003-01-03  |  29KB  |  974 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.2.2 2003/01/01 05:04:49 RD 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__) && defined(__MWERKS__) && (__MWERKS__ >= 0x2400)
  513.  
  514. // MetroNub stuff doesn't seem to work in CodeWarrior 5.3 Carbon builds...
  515.  
  516. #ifndef __MetroNubUtils__
  517. #include "MetroNubUtils.h"
  518. #endif
  519.  
  520. #ifdef __cplusplus
  521.     extern "C" {
  522. #endif
  523.  
  524. #ifndef __GESTALT__
  525. #include <Gestalt.h>
  526. #endif
  527.  
  528. #ifndef true
  529. #define true 1
  530. #endif
  531.  
  532. #ifndef false
  533. #define false 0
  534. #endif
  535.  
  536. #if TARGET_API_MAC_CARBON
  537.  
  538.     #include <CodeFragments.h>
  539.  
  540.     EXTERN_API_C( long )
  541.     CallUniversalProc(UniversalProcPtr theProcPtr, ProcInfoType procInfo, ...);
  542.  
  543.     ProcPtr gCallUniversalProc_Proc = NULL;
  544.  
  545. #endif
  546.  
  547. static MetroNubUserEntryBlock*    gMetroNubEntry = NULL;
  548.  
  549. static long fRunOnce = false;
  550.  
  551. Boolean IsCompatibleVersion(short inVersion);
  552.  
  553. /* ---------------------------------------------------------------------------
  554.         IsCompatibleVersion
  555.    --------------------------------------------------------------------------- */
  556.  
  557. Boolean IsCompatibleVersion(short inVersion)
  558. {
  559.     Boolean result = false;
  560.  
  561.     if (fRunOnce)
  562.     {
  563.         MetroNubUserEntryBlock* block = (MetroNubUserEntryBlock *)result;
  564.  
  565.         result = (inVersion <= block->apiHiVersion);
  566.     }
  567.  
  568.     return result;
  569. }
  570.  
  571. /* ---------------------------------------------------------------------------
  572.         IsMetroNubInstalled
  573.    --------------------------------------------------------------------------- */
  574.  
  575. Boolean IsMetroNubInstalled()
  576. {
  577.     if (!fRunOnce)
  578.     {
  579.         long result, value;
  580.  
  581.         fRunOnce = true;
  582.         gMetroNubEntry = NULL;
  583.  
  584.         if (Gestalt(gestaltSystemVersion, &value) == noErr && value < 0x1000)
  585.         {
  586.             /* look for MetroNub's Gestalt selector */
  587.             if (Gestalt(kMetroNubUserSignature, &result) == noErr)
  588.             {
  589.  
  590.             #if TARGET_API_MAC_CARBON
  591.                 if (gCallUniversalProc_Proc == NULL)
  592.                 {
  593.                     CFragConnectionID   connectionID;
  594.                     Ptr                 mainAddress;
  595.                     Str255              errorString;
  596.                     ProcPtr             symbolAddress;
  597.                     OSErr               err;
  598.                     CFragSymbolClass    symbolClass;
  599.  
  600.                     symbolAddress = NULL;
  601.                     err = GetSharedLibrary("\pInterfaceLib", kPowerPCCFragArch, kFindCFrag,
  602.                                            &connectionID, &mainAddress, errorString);
  603.  
  604.                     if (err != noErr)
  605.                     {
  606.                         gCallUniversalProc_Proc = NULL;
  607.                         goto end;
  608.                     }
  609.  
  610.                     err = FindSymbol(connectionID, "\pCallUniversalProc",
  611.                                     (Ptr *) &gCallUniversalProc_Proc, &symbolClass);
  612.  
  613.                     if (err != noErr)
  614.                     {
  615.                         gCallUniversalProc_Proc = NULL;
  616.                         goto end;
  617.                     }
  618.                 }
  619.             #endif
  620.  
  621.                 {
  622.                     MetroNubUserEntryBlock* block = (MetroNubUserEntryBlock *)result;
  623.  
  624.                     /* make sure the version of the API is compatible */
  625.                     if (block->apiLowVersion <= kMetroNubUserAPIVersion &&
  626.                         kMetroNubUserAPIVersion <= block->apiHiVersion)
  627.                         gMetroNubEntry = block;        /* success! */
  628.                 }
  629.  
  630.             }
  631.         }
  632.     }
  633.  
  634. end:
  635.  
  636. #if TARGET_API_MAC_CARBON
  637.     return (gMetroNubEntry != NULL && gCallUniversalProc_Proc != NULL);
  638. #else
  639.     return (gMetroNubEntry != NULL);
  640. #endif
  641. }
  642.  
  643. /* ---------------------------------------------------------------------------
  644.         IsMWDebuggerRunning                                            [v1 API]
  645.    --------------------------------------------------------------------------- */
  646.  
  647. Boolean IsMWDebuggerRunning()
  648. {
  649.     if (IsMetroNubInstalled())
  650.         return CallIsDebuggerRunningProc(gMetroNubEntry->isDebuggerRunning);
  651.     else
  652.         return false;
  653. }
  654.  
  655. /* ---------------------------------------------------------------------------
  656.         AmIBeingMWDebugged                                            [v1 API]
  657.    --------------------------------------------------------------------------- */
  658.  
  659. Boolean AmIBeingMWDebugged()
  660. {
  661.     if (IsMetroNubInstalled())
  662.         return CallAmIBeingDebuggedProc(gMetroNubEntry->amIBeingDebugged);
  663.     else
  664.         return false;
  665. }
  666.  
  667. /* ---------------------------------------------------------------------------
  668.         UserSetWatchPoint                                            [v2 API]
  669.    --------------------------------------------------------------------------- */
  670.  
  671. OSErr UserSetWatchPoint (Ptr address, long length, WatchPointIDT* watchPointID)
  672. {
  673.     if (IsMetroNubInstalled() && IsCompatibleVersion(kMetroNubUserAPIVersion))
  674.         return CallUserSetWatchPointProc(gMetroNubEntry->userSetWatchPoint,
  675.                                          address, length, watchPointID);
  676.     else
  677.         return errProcessIsNotClient;
  678. }
  679.  
  680. /* ---------------------------------------------------------------------------
  681.         ClearWatchPoint                                                [v2 API]
  682.    --------------------------------------------------------------------------- */
  683.  
  684. OSErr ClearWatchPoint (WatchPointIDT watchPointID)
  685. {
  686.     if (IsMetroNubInstalled() && IsCompatibleVersion(kMetroNubUserAPIVersion))
  687.         return CallClearWatchPointProc(gMetroNubEntry->clearWatchPoint, watchPointID);
  688.     else
  689.         return errProcessIsNotClient;
  690. }
  691.  
  692. #ifdef __cplusplus
  693.     }
  694. #endif
  695.  
  696. #endif // defined(__WXMAC__) && !defined(__DARWIN__) && (__MWERKS__ >= 0x2400)
  697.  
  698. void wxLogStderr::DoLogString(const wxChar *szString, time_t WXUNUSED(t))
  699. {
  700.     wxString str;
  701.     TimeStamp(&str);
  702.     str << szString;
  703.  
  704.     fputs(str.mb_str(), m_fp);
  705.     fputc(_T('\n'), m_fp);
  706.     fflush(m_fp);
  707.  
  708.     // under Windows, programs usually don't have stderr at all, so show the
  709.     // messages also under debugger - unless it's a console program
  710. #if defined(__WXMSW__) && wxUSE_GUI && !defined(__WXMICROWIN__)
  711.     str += wxT("\r\n") ;
  712.     OutputDebugString(str.c_str());
  713. #endif // MSW
  714. #if defined(__WXMAC__) && !defined(__DARWIN__) && wxUSE_GUI
  715.     Str255 pstr ;
  716.     strcpy( (char*) pstr , str.c_str() ) ;
  717.     strcat( (char*) pstr , ";g" ) ;
  718.     c2pstr( (char*) pstr ) ;
  719.  
  720.     Boolean running = false ;
  721.  
  722. #if defined(__MWERKS__) && (__MWERKS__ >= 0x2400)
  723.  
  724.     if ( IsMWDebuggerRunning() && AmIBeingMWDebugged() )
  725.     {
  726.         running = true ;
  727.     }
  728.  
  729. #endif
  730.  
  731.     if (running)
  732.     {
  733. #ifdef __powerc
  734.         DebugStr(pstr);
  735. #else
  736.         SysBreakStr(pstr);
  737. #endif
  738.     }
  739. #endif // Mac
  740. }
  741.  
  742. // ----------------------------------------------------------------------------
  743. // wxLogStream implementation
  744. // ----------------------------------------------------------------------------
  745.  
  746. #if wxUSE_STD_IOSTREAM
  747. wxLogStream::wxLogStream(wxSTD ostream *ostr)
  748. {
  749.     if ( ostr == NULL )
  750.         m_ostr = &wxSTD cerr;
  751.     else
  752.         m_ostr = ostr;
  753. }
  754.  
  755. void wxLogStream::DoLogString(const wxChar *szString, time_t WXUNUSED(t))
  756. {
  757.     wxString str;
  758.     TimeStamp(&str);
  759.     (*m_ostr) << str << wxConvertWX2MB(szString) << wxSTD endl;
  760. }
  761. #endif // wxUSE_STD_IOSTREAM
  762.  
  763. // ----------------------------------------------------------------------------
  764. // wxLogChain
  765. // ----------------------------------------------------------------------------
  766.  
  767. wxLogChain::wxLogChain(wxLog *logger)
  768. {
  769.     m_bPassMessages = TRUE;
  770.  
  771.     m_logNew = logger;
  772.     m_logOld = wxLog::SetActiveTarget(this);
  773. }
  774.  
  775. wxLogChain::~wxLogChain()
  776. {
  777.     delete m_logOld;
  778.  
  779.     if ( m_logNew != this )
  780.         delete m_logNew;
  781. }
  782.  
  783. void wxLogChain::SetLog(wxLog *logger)
  784. {
  785.     if ( m_logNew != this )
  786.         delete m_logNew;
  787.  
  788.     m_logNew = logger;
  789. }
  790.  
  791. void wxLogChain::Flush()
  792. {
  793.     if ( m_logOld )
  794.         m_logOld->Flush();
  795.  
  796.     // be careful to avoid inifinite recursion
  797.     if ( m_logNew && m_logNew != this )
  798.         m_logNew->Flush();
  799. }
  800.  
  801. void wxLogChain::DoLog(wxLogLevel level, const wxChar *szString, time_t t)
  802. {
  803.     // let the previous logger show it
  804.     if ( m_logOld && IsPassingMessages() )
  805.     {
  806.         // bogus cast just to access protected DoLog
  807.         ((wxLogChain *)m_logOld)->DoLog(level, szString, t);
  808.     }
  809.  
  810.     if ( m_logNew && m_logNew != this )
  811.     {
  812.         // as above...
  813.         ((wxLogChain *)m_logNew)->DoLog(level, szString, t);
  814.     }
  815. }
  816.  
  817. // ----------------------------------------------------------------------------
  818. // wxLogPassThrough
  819. // ----------------------------------------------------------------------------
  820.  
  821. #ifdef __VISUALC__
  822.     // "'this' : used in base member initializer list" - so what?
  823.     #pragma warning(disable:4355)
  824. #endif // VC++
  825.  
  826. wxLogPassThrough::wxLogPassThrough()
  827.                 : wxLogChain(this)
  828. {
  829. }
  830.  
  831. #ifdef __VISUALC__
  832.     #pragma warning(default:4355)
  833. #endif // VC++
  834.  
  835. // ============================================================================
  836. // Global functions/variables
  837. // ============================================================================
  838.  
  839. // ----------------------------------------------------------------------------
  840. // static variables
  841. // ----------------------------------------------------------------------------
  842.  
  843. wxLog          *wxLog::ms_pLogger      = (wxLog *)NULL;
  844. bool            wxLog::ms_doLog        = TRUE;
  845. bool            wxLog::ms_bAutoCreate  = TRUE;
  846. bool            wxLog::ms_bVerbose     = FALSE;
  847.  
  848. wxLogLevel      wxLog::ms_logLevel     = wxLOG_Max;  // log everything by default
  849.  
  850. size_t          wxLog::ms_suspendCount = 0;
  851.  
  852. #if wxUSE_GUI
  853.     const wxChar *wxLog::ms_timestamp  = wxT("%X");  // time only, no date
  854. #else
  855.     const wxChar *wxLog::ms_timestamp  = NULL;       // save space
  856. #endif
  857.  
  858. wxTraceMask     wxLog::ms_ulTraceMask  = (wxTraceMask)0;
  859. wxArrayString   wxLog::ms_aTraceMasks;
  860.  
  861. // ----------------------------------------------------------------------------
  862. // stdout error logging helper
  863. // ----------------------------------------------------------------------------
  864.  
  865. // helper function: wraps the message and justifies it under given position
  866. // (looks more pretty on the terminal). Also adds newline at the end.
  867. //
  868. // TODO this is now disabled until I find a portable way of determining the
  869. //      terminal window size (ok, I found it but does anybody really cares?)
  870. #ifdef LOG_PRETTY_WRAP
  871. static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz)
  872. {
  873.     size_t nMax = 80; // FIXME
  874.     size_t nStart = strlen(pszPrefix);
  875.     fputs(pszPrefix, f);
  876.  
  877.     size_t n;
  878.     while ( *psz != '\0' ) {
  879.         for ( n = nStart; (n < nMax) && (*psz != '\0'); n++ )
  880.             putc(*psz++, f);
  881.  
  882.         // wrapped?
  883.         if ( *psz != '\0' ) {
  884.             /*putc('\n', f);*/
  885.             for ( n = 0; n < nStart; n++ )
  886.                 putc(' ', f);
  887.  
  888.             // as we wrapped, squeeze all white space
  889.             while ( isspace(*psz) )
  890.                 psz++;
  891.         }
  892.     }
  893.  
  894.     putc('\n', f);
  895. }
  896. #endif  //LOG_PRETTY_WRAP
  897.  
  898. // ----------------------------------------------------------------------------
  899. // error code/error message retrieval functions
  900. // ----------------------------------------------------------------------------
  901.  
  902. // get error code from syste
  903. unsigned long wxSysErrorCode()
  904. {
  905. #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
  906. #ifdef  __WIN32__
  907.     return ::GetLastError();
  908. #else   //WIN16
  909.     // TODO what to do on Windows 3.1?
  910.     return 0;
  911. #endif  //WIN16/32
  912. #else   //Unix
  913.     return errno;
  914. #endif  //Win/Unix
  915. }
  916.  
  917. // get error message from system
  918. const wxChar *wxSysErrorMsg(unsigned long nErrCode)
  919. {
  920.     if ( nErrCode == 0 )
  921.         nErrCode = wxSysErrorCode();
  922.  
  923. #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
  924. #ifdef  __WIN32__
  925.     static wxChar s_szBuf[LOG_BUFFER_SIZE / 2];
  926.  
  927.     // get error message from system
  928.     LPVOID lpMsgBuf;
  929.     FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  930.             NULL, nErrCode,
  931.             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  932.             (LPTSTR)&lpMsgBuf,
  933.             0, NULL);
  934.  
  935.     // copy it to our buffer and free memory
  936.     if( lpMsgBuf != 0 ) {
  937.         wxStrncpy(s_szBuf, (const wxChar *)lpMsgBuf, WXSIZEOF(s_szBuf) - 1);
  938.         s_szBuf[WXSIZEOF(s_szBuf) - 1] = wxT('\0');
  939.  
  940.         LocalFree(lpMsgBuf);
  941.  
  942.         // returned string is capitalized and ended with '\r\n' - bad
  943.         s_szBuf[0] = (wxChar)wxTolower(s_szBuf[0]);
  944.         size_t len = wxStrlen(s_szBuf);
  945.         if ( len > 0 ) {
  946.             // truncate string
  947.             if ( s_szBuf[len - 2] == wxT('\r') )
  948.                 s_szBuf[len - 2] = wxT('\0');
  949.         }
  950.     }
  951.     else {
  952.         s_szBuf[0] = wxT('\0');
  953.     }
  954.  
  955.     return s_szBuf;
  956. #else   //Win16
  957.     // TODO
  958.     return NULL;
  959. #endif // Win16/32
  960. #else   // Unix
  961. #if wxUSE_UNICODE
  962.     static wxChar s_szBuf[LOG_BUFFER_SIZE / 2];
  963.     wxConvCurrent->MB2WC(s_szBuf, strerror(nErrCode), WXSIZEOF(s_szBuf) -1);
  964.     return s_szBuf;
  965. #else
  966.     return strerror((int)nErrCode);
  967. #endif
  968. #endif  // Win/Unix
  969. }
  970.  
  971. #endif //wxUSE_LOG
  972.  
  973. // vi:sts=4:sw=4:et
  974.