1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     Assorted wxLogXXX functions, and wxLog (sink for logs) 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  21     #pragma implementation "log.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  36     #include "wx/arrstr.h" 
  38     #include "wx/string.h" 
  41 #include "wx/apptrait.h" 
  44 #include "wx/msgout.h" 
  45 #include "wx/textfile.h" 
  46 #include "wx/thread.h" 
  48 #include "wx/wxchar.h" 
  50 // other standard headers 
  60 #include "wx/msw/wince/time.h" 
  63 #if defined(__WINDOWS__) 
  64     #include "wx/msw/private.h" // includes windows.h 
  67 // ---------------------------------------------------------------------------- 
  68 // non member functions 
  69 // ---------------------------------------------------------------------------- 
  71 // define this to enable wrapping of log messages 
  72 //#define LOG_PRETTY_WRAP 
  74 #ifdef  LOG_PRETTY_WRAP 
  75   static void wxLogWrap(FILE *f
, const char *pszPrefix
, const char *psz
); 
  78 // ============================================================================ 
  80 // ============================================================================ 
  82 // ---------------------------------------------------------------------------- 
  84 // ---------------------------------------------------------------------------- 
  86 // log functions can't allocate memory (LogError("out of memory...") should 
  87 // work!), so we use a static buffer for all log messages 
  88 #define LOG_BUFFER_SIZE   (4096) 
  90 // static buffer for error messages 
  91 static wxChar   s_szBufStatic
[LOG_BUFFER_SIZE
]; 
  93 static wxChar  
*s_szBuf     
= s_szBufStatic
; 
  94 static size_t   s_szBufSize 
= WXSIZEOF( s_szBufStatic 
); 
  98 // the critical section protecting the static buffer 
  99 static wxCriticalSection gs_csLogBuf
; 
 101 #endif // wxUSE_THREADS 
 103 // return true if we have a non NULL non disabled log target 
 104 static inline bool IsLoggingEnabled() 
 106     return wxLog::IsEnabled() && (wxLog::GetActiveTarget() != NULL
); 
 109 // ---------------------------------------------------------------------------- 
 110 // implementation of Log functions 
 112 // NB: unfortunately we need all these distinct functions, we can't make them 
 113 //     macros and not all compilers inline vararg functions. 
 114 // ---------------------------------------------------------------------------- 
 116 // wrapper for wxVsnprintf(s_szBuf) which always NULL-terminates it 
 117 static inline void PrintfInLogBug(const wxChar 
*szFormat
, va_list argptr
) 
 119     if ( wxVsnprintf(s_szBuf
, s_szBufSize
, szFormat
, argptr
) < 0 ) 
 121         // must NUL-terminate it manually 
 122         s_szBuf
[s_szBufSize 
- 1] = _T('\0'); 
 124     //else: NUL-terminated by vsnprintf() 
 127 // generic log function 
 128 void wxVLogGeneric(wxLogLevel level
, const wxChar 
*szFormat
, va_list argptr
) 
 130     if ( IsLoggingEnabled() ) { 
 131         wxCRIT_SECT_LOCKER(locker
, gs_csLogBuf
); 
 133         PrintfInLogBug(szFormat
, argptr
); 
 135         wxLog::OnLog(level
, s_szBuf
, time(NULL
)); 
 139 void wxLogGeneric(wxLogLevel level
, const wxChar 
*szFormat
, ...) 
 142     va_start(argptr
, szFormat
); 
 143     wxVLogGeneric(level
, szFormat
, argptr
); 
 147 #define IMPLEMENT_LOG_FUNCTION(level)                               \ 
 148   void wxVLog##level(const wxChar *szFormat, va_list argptr)        \ 
 150     if ( IsLoggingEnabled() ) {                                     \ 
 151       wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);                      \ 
 153       PrintfInLogBug(szFormat, argptr);                             \ 
 155       wxLog::OnLog(wxLOG_##level, s_szBuf, time(NULL));             \ 
 159   void wxLog##level(const wxChar *szFormat, ...)                    \ 
 162     va_start(argptr, szFormat);                                     \ 
 163     wxVLog##level(szFormat, argptr);                                \ 
 167 IMPLEMENT_LOG_FUNCTION(Error
) 
 168 IMPLEMENT_LOG_FUNCTION(Warning
) 
 169 IMPLEMENT_LOG_FUNCTION(Message
) 
 170 IMPLEMENT_LOG_FUNCTION(Info
) 
 171 IMPLEMENT_LOG_FUNCTION(Status
) 
 173 void wxSafeShowMessage(const wxString
& title
, const wxString
& text
) 
 176     ::MessageBox(NULL
, text
, title
, MB_OK 
| MB_ICONSTOP
); 
 178     wxFprintf(stderr
, _T("%s: %s\n"), title
.c_str(), text
.c_str()); 
 182 // fatal errors can't be suppressed nor handled by the custom log target and 
 183 // always terminate the program 
 184 void wxVLogFatalError(const wxChar 
*szFormat
, va_list argptr
) 
 186     wxVsnprintf(s_szBuf
, s_szBufSize
, szFormat
, argptr
); 
 188     wxSafeShowMessage(_T("Fatal Error"), s_szBuf
); 
 197 void wxLogFatalError(const wxChar 
*szFormat
, ...) 
 200     va_start(argptr
, szFormat
); 
 201     wxVLogFatalError(szFormat
, argptr
); 
 203     // some compilers warn about unreachable code and it shouldn't matter 
 204     // for the others anyhow... 
 208 // same as info, but only if 'verbose' mode is on 
 209 void wxVLogVerbose(const wxChar 
*szFormat
, va_list argptr
) 
 211     if ( IsLoggingEnabled() ) { 
 212         if ( wxLog::GetActiveTarget() != NULL 
&& wxLog::GetVerbose() ) { 
 213             wxCRIT_SECT_LOCKER(locker
, gs_csLogBuf
); 
 215             wxVsnprintf(s_szBuf
, s_szBufSize
, szFormat
, argptr
); 
 217             wxLog::OnLog(wxLOG_Info
, s_szBuf
, time(NULL
)); 
 222 void wxLogVerbose(const wxChar 
*szFormat
, ...) 
 225     va_start(argptr
, szFormat
); 
 226     wxVLogVerbose(szFormat
, argptr
); 
 232 #define IMPLEMENT_LOG_DEBUG_FUNCTION(level)                         \ 
 233   void wxVLog##level(const wxChar *szFormat, va_list argptr)        \ 
 235     if ( IsLoggingEnabled() ) {                                     \ 
 236       wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);                      \ 
 238       wxVsnprintf(s_szBuf, s_szBufSize, szFormat, argptr);    \ 
 240       wxLog::OnLog(wxLOG_##level, s_szBuf, time(NULL));             \ 
 243   void wxLog##level(const wxChar *szFormat, ...)                    \ 
 246     va_start(argptr, szFormat);                                     \ 
 247     wxVLog##level(szFormat, argptr);                                \ 
 251   void wxVLogTrace(const wxChar 
*mask
, const wxChar 
*szFormat
, va_list argptr
) 
 253     if ( IsLoggingEnabled() && wxLog::IsAllowedTraceMask(mask
) ) { 
 254       wxCRIT_SECT_LOCKER(locker
, gs_csLogBuf
); 
 257       size_t len 
= s_szBufSize
; 
 258       wxStrncpy(s_szBuf
, _T("("), len
); 
 259       len 
-= 1; // strlen("(") 
 261       wxStrncat(p
, mask
, len
); 
 262       size_t lenMask 
= wxStrlen(mask
); 
 266       wxStrncat(p
, _T(") "), len
); 
 270       wxVsnprintf(p
, len
, szFormat
, argptr
); 
 272       wxLog::OnLog(wxLOG_Trace
, s_szBuf
, time(NULL
)); 
 276   void wxLogTrace(const wxChar 
*mask
, const wxChar 
*szFormat
, ...) 
 279     va_start(argptr
, szFormat
); 
 280     wxVLogTrace(mask
, szFormat
, argptr
); 
 284   void wxVLogTrace(wxTraceMask mask
, const wxChar 
*szFormat
, va_list argptr
) 
 286     // we check that all of mask bits are set in the current mask, so 
 287     // that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something 
 288     // if both bits are set. 
 289     if ( IsLoggingEnabled() && ((wxLog::GetTraceMask() & mask
) == mask
) ) { 
 290       wxCRIT_SECT_LOCKER(locker
, gs_csLogBuf
); 
 292       wxVsnprintf(s_szBuf
, s_szBufSize
, szFormat
, argptr
); 
 294       wxLog::OnLog(wxLOG_Trace
, s_szBuf
, time(NULL
)); 
 298   void wxLogTrace(wxTraceMask mask
, const wxChar 
*szFormat
, ...) 
 301     va_start(argptr
, szFormat
); 
 302     wxVLogTrace(mask
, szFormat
, argptr
); 
 307   #define IMPLEMENT_LOG_DEBUG_FUNCTION(level) 
 310 IMPLEMENT_LOG_DEBUG_FUNCTION(Debug
) 
 311 IMPLEMENT_LOG_DEBUG_FUNCTION(Trace
) 
 313 // wxLogSysError: one uses the last error code, for other  you must give it 
 316 // common part of both wxLogSysError 
 317 void wxLogSysErrorHelper(long lErrCode
) 
 319     wxChar szErrMsg
[LOG_BUFFER_SIZE 
/ 2]; 
 320     wxSnprintf(szErrMsg
, WXSIZEOF(szErrMsg
), 
 321                _(" (error %ld: %s)"), lErrCode
, wxSysErrorMsg(lErrCode
)); 
 322     wxStrncat(s_szBuf
, szErrMsg
, s_szBufSize 
- wxStrlen(s_szBuf
)); 
 324     wxLog::OnLog(wxLOG_Error
, s_szBuf
, time(NULL
)); 
 327 void WXDLLEXPORT 
wxVLogSysError(const wxChar 
*szFormat
, va_list argptr
) 
 329     if ( IsLoggingEnabled() ) { 
 330         wxCRIT_SECT_LOCKER(locker
, gs_csLogBuf
); 
 332         wxVsnprintf(s_szBuf
, s_szBufSize
, szFormat
, argptr
); 
 334         wxLogSysErrorHelper(wxSysErrorCode()); 
 338 void WXDLLEXPORT 
wxLogSysError(const wxChar 
*szFormat
, ...) 
 341     va_start(argptr
, szFormat
); 
 342     wxVLogSysError(szFormat
, argptr
); 
 346 void WXDLLEXPORT 
wxVLogSysError(long lErrCode
, const wxChar 
*szFormat
, va_list argptr
) 
 348     if ( IsLoggingEnabled() ) { 
 349         wxCRIT_SECT_LOCKER(locker
, gs_csLogBuf
); 
 351         wxVsnprintf(s_szBuf
, s_szBufSize
, szFormat
, argptr
); 
 353         wxLogSysErrorHelper(lErrCode
); 
 357 void WXDLLEXPORT 
wxLogSysError(long lErrCode
, const wxChar 
*szFormat
, ...) 
 360     va_start(argptr
, szFormat
); 
 361     wxVLogSysError(lErrCode
, szFormat
, argptr
); 
 365 // ---------------------------------------------------------------------------- 
 366 // wxLog class implementation 
 367 // ---------------------------------------------------------------------------- 
 369 wxChar 
*wxLog::SetLogBuffer( wxChar 
*buf
, size_t size
) 
 371     wxChar 
*oldbuf 
= s_szBuf
; 
 375         s_szBuf 
= s_szBufStatic
; 
 376         s_szBufSize 
= WXSIZEOF( s_szBufStatic 
); 
 384     return (oldbuf 
== s_szBufStatic 
) ? 0 : oldbuf
; 
 387 wxLog 
*wxLog::GetActiveTarget() 
 389     if ( ms_bAutoCreate 
&& ms_pLogger 
== NULL 
) { 
 390         // prevent infinite recursion if someone calls wxLogXXX() from 
 391         // wxApp::CreateLogTarget() 
 392         static bool s_bInGetActiveTarget 
= false; 
 393         if ( !s_bInGetActiveTarget 
) { 
 394             s_bInGetActiveTarget 
= true; 
 396             // ask the application to create a log target for us 
 397             if ( wxTheApp 
!= NULL 
) 
 398                 ms_pLogger 
= wxTheApp
->GetTraits()->CreateLogTarget(); 
 400                 ms_pLogger 
= new wxLogStderr
; 
 402             s_bInGetActiveTarget 
= false; 
 404             // do nothing if it fails - what can we do? 
 411 wxLog 
*wxLog::SetActiveTarget(wxLog 
*pLogger
) 
 413     if ( ms_pLogger 
!= NULL 
) { 
 414         // flush the old messages before changing because otherwise they might 
 415         // get lost later if this target is not restored 
 419     wxLog 
*pOldLogger 
= ms_pLogger
; 
 420     ms_pLogger 
= pLogger
; 
 425 void wxLog::DontCreateOnDemand() 
 427     ms_bAutoCreate 
= false; 
 429     // this is usually called at the end of the program and we assume that it 
 430     // is *always* called at the end - so we free memory here to avoid false 
 431     // memory leak reports from wxWin  memory tracking code 
 435 void wxLog::RemoveTraceMask(const wxString
& str
) 
 437     int index 
= ms_aTraceMasks
.Index(str
); 
 438     if ( index 
!= wxNOT_FOUND 
) 
 439         ms_aTraceMasks
.RemoveAt((size_t)index
); 
 442 void wxLog::ClearTraceMasks() 
 444     ms_aTraceMasks
.Clear(); 
 447 void wxLog::TimeStamp(wxString 
*str
) 
 453         (void)time(&timeNow
); 
 454         wxStrftime(buf
, WXSIZEOF(buf
), ms_timestamp
, localtime(&timeNow
)); 
 457         *str 
<< buf 
<< wxT(": "); 
 461 void wxLog::DoLog(wxLogLevel level
, const wxChar 
*szString
, time_t t
) 
 464         case wxLOG_FatalError
: 
 465             DoLogString(wxString(_("Fatal error: ")) + szString
, t
); 
 466             DoLogString(_("Program aborted."), t
); 
 476             DoLogString(wxString(_("Error: ")) + szString
, t
); 
 480             DoLogString(wxString(_("Warning: ")) + szString
, t
); 
 487         default:    // log unknown log levels too 
 488                 DoLogString(szString
, t
); 
 495                 wxString msg 
= level 
== wxLOG_Trace 
? wxT("Trace: ") 
 505 void wxLog::DoLogString(const wxChar 
*WXUNUSED(szString
), time_t WXUNUSED(t
)) 
 507     wxFAIL_MSG(wxT("DoLogString must be overriden if it's called.")); 
 512     // nothing to do here 
 515 /*static*/ bool wxLog::IsAllowedTraceMask(const wxChar 
*mask
) 
 517     for ( wxArrayString::iterator it 
= ms_aTraceMasks
.begin(), 
 518                                   en 
= ms_aTraceMasks
.end(); 
 525 // ---------------------------------------------------------------------------- 
 526 // wxLogBuffer implementation 
 527 // ---------------------------------------------------------------------------- 
 529 void wxLogBuffer::Flush() 
 531     if ( !m_str
.empty() ) 
 533         wxMessageOutputBest out
; 
 534         out
.Printf(_T("%s"), m_str
.c_str()); 
 539 void wxLogBuffer::DoLog(wxLogLevel level
, const wxChar 
*szString
, time_t t
) 
 546             // don't put debug messages in the buffer, we don't want to show 
 547             // them to the user in a msg box, log them immediately 
 553                 wxMessageOutputDebug().Printf(_T("%s\n"), str
.c_str()); 
 555 #endif // __WXDEBUG__ 
 559             wxLog::DoLog(level
, szString
, t
); 
 563 void wxLogBuffer::DoLogString(const wxChar 
*szString
, time_t WXUNUSED(t
)) 
 565     m_str 
<< szString 
<< _T("\n"); 
 568 // ---------------------------------------------------------------------------- 
 569 // wxLogStderr class implementation 
 570 // ---------------------------------------------------------------------------- 
 572 wxLogStderr::wxLogStderr(FILE *fp
) 
 580 void wxLogStderr::DoLogString(const wxChar 
*szString
, time_t WXUNUSED(t
)) 
 586     fputs(str
.mb_str(), m_fp
); 
 587     fputc(_T('\n'), m_fp
); 
 590     // under GUI systems such as Windows or Mac, programs usually don't have 
 591     // stderr at all, so show the messages also somewhere else, typically in 
 592     // the debugger window so that they go at least somewhere instead of being 
 594     if ( m_fp 
== stderr 
) 
 596         wxAppTraits 
*traits 
= wxTheApp 
? wxTheApp
->GetTraits() : NULL
; 
 597         if ( traits 
&& !traits
->HasStderr() ) 
 599             wxMessageOutputDebug dbgout
; 
 600             dbgout
.Printf(_T("%s\n"), str
.c_str()); 
 605 // ---------------------------------------------------------------------------- 
 606 // wxLogStream implementation 
 607 // ---------------------------------------------------------------------------- 
 609 #if wxUSE_STD_IOSTREAM 
 610 #include "wx/ioswrap.h" 
 611 wxLogStream::wxLogStream(wxSTD ostream 
*ostr
) 
 614         m_ostr 
= &wxSTD cerr
; 
 619 void wxLogStream::DoLogString(const wxChar 
*szString
, time_t WXUNUSED(t
)) 
 623     (*m_ostr
) << str 
<< wxConvertWX2MB(szString
) << wxSTD endl
; 
 625 #endif // wxUSE_STD_IOSTREAM 
 627 // ---------------------------------------------------------------------------- 
 629 // ---------------------------------------------------------------------------- 
 631 wxLogChain::wxLogChain(wxLog 
*logger
) 
 633     m_bPassMessages 
= true; 
 636     m_logOld 
= wxLog::SetActiveTarget(this); 
 639 wxLogChain::~wxLogChain() 
 643     if ( m_logNew 
!= this ) 
 647 void wxLogChain::SetLog(wxLog 
*logger
) 
 649     if ( m_logNew 
!= this ) 
 655 void wxLogChain::Flush() 
 660     // be careful to avoid infinite recursion 
 661     if ( m_logNew 
&& m_logNew 
!= this ) 
 665 void wxLogChain::DoLog(wxLogLevel level
, const wxChar 
*szString
, time_t t
) 
 667     // let the previous logger show it 
 668     if ( m_logOld 
&& IsPassingMessages() ) 
 670         // bogus cast just to access protected DoLog 
 671         ((wxLogChain 
*)m_logOld
)->DoLog(level
, szString
, t
); 
 674     if ( m_logNew 
&& m_logNew 
!= this ) 
 677         ((wxLogChain 
*)m_logNew
)->DoLog(level
, szString
, t
); 
 681 // ---------------------------------------------------------------------------- 
 683 // ---------------------------------------------------------------------------- 
 686     // "'this' : used in base member initializer list" - so what? 
 687     #pragma warning(disable:4355) 
 690 wxLogPassThrough::wxLogPassThrough() 
 696     #pragma warning(default:4355) 
 699 // ============================================================================ 
 700 // Global functions/variables 
 701 // ============================================================================ 
 703 // ---------------------------------------------------------------------------- 
 705 // ---------------------------------------------------------------------------- 
 707 wxLog          
*wxLog::ms_pLogger      
= (wxLog 
*)NULL
; 
 708 bool            wxLog::ms_doLog        
= true; 
 709 bool            wxLog::ms_bAutoCreate  
= true; 
 710 bool            wxLog::ms_bVerbose     
= false; 
 712 wxLogLevel      
wxLog::ms_logLevel     
= wxLOG_Max
;  // log everything by default 
 714 size_t          wxLog::ms_suspendCount 
= 0; 
 716 const wxChar   
*wxLog::ms_timestamp    
= wxT("%X");  // time only, no date 
 718 wxTraceMask     
wxLog::ms_ulTraceMask  
= (wxTraceMask
)0; 
 719 wxArrayString   
wxLog::ms_aTraceMasks
; 
 721 // ---------------------------------------------------------------------------- 
 722 // stdout error logging helper 
 723 // ---------------------------------------------------------------------------- 
 725 // helper function: wraps the message and justifies it under given position 
 726 // (looks more pretty on the terminal). Also adds newline at the end. 
 728 // TODO this is now disabled until I find a portable way of determining the 
 729 //      terminal window size (ok, I found it but does anybody really cares?) 
 730 #ifdef LOG_PRETTY_WRAP 
 731 static void wxLogWrap(FILE *f
, const char *pszPrefix
, const char *psz
) 
 733     size_t nMax 
= 80; // FIXME 
 734     size_t nStart 
= strlen(pszPrefix
); 
 738     while ( *psz 
!= '\0' ) { 
 739         for ( n 
= nStart
; (n 
< nMax
) && (*psz 
!= '\0'); n
++ ) 
 743         if ( *psz 
!= '\0' ) { 
 745             for ( n 
= 0; n 
< nStart
; n
++ ) 
 748             // as we wrapped, squeeze all white space 
 749             while ( isspace(*psz
) ) 
 756 #endif  //LOG_PRETTY_WRAP 
 758 // ---------------------------------------------------------------------------- 
 759 // error code/error message retrieval functions 
 760 // ---------------------------------------------------------------------------- 
 762 // get error code from syste 
 763 unsigned long wxSysErrorCode() 
 765 #if defined(__WXMSW__) && !defined(__WXMICROWIN__) 
 766     return ::GetLastError(); 
 772 // get error message from system 
 773 const wxChar 
*wxSysErrorMsg(unsigned long nErrCode
) 
 776         nErrCode 
= wxSysErrorCode(); 
 778 #if defined(__WXMSW__) && !defined(__WXMICROWIN__) 
 779     static wxChar s_szBuf
[LOG_BUFFER_SIZE 
/ 2]; 
 781     // get error message from system 
 785             FORMAT_MESSAGE_ALLOCATE_BUFFER 
| FORMAT_MESSAGE_FROM_SYSTEM
, 
 788             MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
), 
 794         // if this happens, something is seriously wrong, so don't use _() here 
 796         wxSprintf(s_szBuf
, _T("unknown error %lx"), nErrCode
); 
 801     // copy it to our buffer and free memory 
 802     // Crashes on SmartPhone (FIXME) 
 803 #if !defined(__SMARTPHONE__) /* of WinCE */ 
 804      if( lpMsgBuf 
!= 0 ) { 
 805         wxStrncpy(s_szBuf
, (const wxChar 
*)lpMsgBuf
, WXSIZEOF(s_szBuf
) - 1); 
 806         s_szBuf
[WXSIZEOF(s_szBuf
) - 1] = wxT('\0'); 
 810         // returned string is capitalized and ended with '\r\n' - bad 
 811         s_szBuf
[0] = (wxChar
)wxTolower(s_szBuf
[0]); 
 812         size_t len 
= wxStrlen(s_szBuf
); 
 815             if ( s_szBuf
[len 
- 2] == wxT('\r') ) 
 816                 s_szBuf
[len 
- 2] = wxT('\0'); 
 822         s_szBuf
[0] = wxT('\0'); 
 826 #else   // Unix-WXMICROWIN 
 828     static wxChar s_szBuf
[LOG_BUFFER_SIZE 
/ 2]; 
 829     wxConvCurrent
->MB2WC(s_szBuf
, strerror(nErrCode
), WXSIZEOF(s_szBuf
) -1); 
 832     return strerror((int)nErrCode
); 
 834 #endif  // Win/Unix-WXMICROWIN