1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/log.cpp
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 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
33 #include "wx/arrstr.h"
35 #include "wx/string.h"
39 #include "wx/apptrait.h"
40 #include "wx/datetime.h"
42 #include "wx/msgout.h"
43 #include "wx/textfile.h"
44 #include "wx/thread.h"
47 // other standard headers
58 #include "wx/msw/wince/time.h"
60 #endif /* ! __WXPALMOS5__ */
62 #if defined(__WINDOWS__)
63 #include "wx/msw/private.h" // includes windows.h
68 // define static functions providing access to the critical sections we use
69 // instead of just using static critical section variables as log functions may
70 // be used during static initialization and while this is certainly not
71 // advisable it's still better to not crash (as we'd do if we used a yet
72 // uninitialized critical section) if it happens
74 static inline wxCriticalSection
& GetTraceMaskCS()
76 static wxCriticalSection s_csTrace
;
81 static inline wxCriticalSection
& GetPreviousLogCS()
83 static wxCriticalSection s_csPrev
;
88 #endif // wxUSE_THREADS
90 // ----------------------------------------------------------------------------
91 // non member functions
92 // ----------------------------------------------------------------------------
94 // define this to enable wrapping of log messages
95 //#define LOG_PRETTY_WRAP
97 #ifdef LOG_PRETTY_WRAP
98 static void wxLogWrap(FILE *f
, const char *pszPrefix
, const char *psz
);
101 // ============================================================================
103 // ============================================================================
105 // ----------------------------------------------------------------------------
106 // implementation of Log functions
108 // NB: unfortunately we need all these distinct functions, we can't make them
109 // macros and not all compilers inline vararg functions.
110 // ----------------------------------------------------------------------------
112 // generic log function
113 void wxVLogGeneric(wxLogLevel level
, const wxString
& format
, va_list argptr
)
115 if ( wxLog::IsEnabled() ) {
116 wxLog::OnLog(level
, wxString::FormatV(format
, argptr
), time(NULL
));
120 #if !wxUSE_UTF8_LOCALE_ONLY
121 void wxDoLogGenericWchar(wxLogLevel level
, const wxChar
*format
, ...)
124 va_start(argptr
, format
);
125 wxVLogGeneric(level
, format
, argptr
);
128 #endif // wxUSE_UTF8_LOCALE_ONLY
130 #if wxUSE_UNICODE_UTF8
131 void wxDoLogGenericUtf8(wxLogLevel level
, const char *format
, ...)
134 va_start(argptr
, format
);
135 wxVLogGeneric(level
, format
, argptr
);
138 #endif // wxUSE_UNICODE_UTF8
140 #if !wxUSE_UTF8_LOCALE_ONLY
141 #define IMPLEMENT_LOG_FUNCTION_WCHAR(level) \
142 void wxDoLog##level##Wchar(const wxChar *format, ...) \
145 va_start(argptr, format); \
146 wxVLog##level(format, argptr); \
150 #define IMPLEMENT_LOG_FUNCTION_WCHAR(level)
153 #if wxUSE_UNICODE_UTF8
154 #define IMPLEMENT_LOG_FUNCTION_UTF8(level) \
155 void wxDoLog##level##Utf8(const char *format, ...) \
158 va_start(argptr, format); \
159 wxVLog##level(format, argptr); \
163 #define IMPLEMENT_LOG_FUNCTION_UTF8(level)
166 #define IMPLEMENT_LOG_FUNCTION(level) \
167 void wxVLog##level(const wxString& format, va_list argptr) \
169 if ( wxLog::IsEnabled() ) { \
170 wxLog::OnLog(wxLOG_##level, \
171 wxString::FormatV(format, argptr), time(NULL)); \
174 IMPLEMENT_LOG_FUNCTION_WCHAR(level) \
175 IMPLEMENT_LOG_FUNCTION_UTF8(level)
177 IMPLEMENT_LOG_FUNCTION(Error
)
178 IMPLEMENT_LOG_FUNCTION(Warning
)
179 IMPLEMENT_LOG_FUNCTION(Message
)
180 IMPLEMENT_LOG_FUNCTION(Info
)
181 IMPLEMENT_LOG_FUNCTION(Status
)
183 void wxSafeShowMessage(const wxString
& title
, const wxString
& text
)
186 ::MessageBox(NULL
, text
.t_str(), title
.t_str(), MB_OK
| MB_ICONSTOP
);
188 wxFprintf(stderr
, wxS("%s: %s\n"), title
.c_str(), text
.c_str());
193 // fatal errors can't be suppressed nor handled by the custom log target and
194 // always terminate the program
195 void wxVLogFatalError(const wxString
& format
, va_list argptr
)
197 wxSafeShowMessage(wxS("Fatal Error"), wxString::FormatV(format
, argptr
));
206 #if !wxUSE_UTF8_LOCALE_ONLY
207 void wxDoLogFatalErrorWchar(const wxChar
*format
, ...)
210 va_start(argptr
, format
);
211 wxVLogFatalError(format
, argptr
);
213 // some compilers warn about unreachable code and it shouldn't matter
214 // for the others anyhow...
217 #endif // wxUSE_UTF8_LOCALE_ONLY
219 #if wxUSE_UNICODE_UTF8
220 void wxDoLogFatalErrorUtf8(const char *format
, ...)
223 va_start(argptr
, format
);
224 wxVLogFatalError(format
, argptr
);
226 // some compilers warn about unreachable code and it shouldn't matter
227 // for the others anyhow...
230 #endif // wxUSE_UNICODE_UTF8
232 // same as info, but only if 'verbose' mode is on
233 void wxVLogVerbose(const wxString
& format
, va_list argptr
)
235 if ( wxLog::IsEnabled() ) {
236 if ( wxLog::GetActiveTarget() != NULL
&& wxLog::GetVerbose() ) {
237 wxLog::OnLog(wxLOG_Info
,
238 wxString::FormatV(format
, argptr
), time(NULL
));
243 #if !wxUSE_UTF8_LOCALE_ONLY
244 void wxDoLogVerboseWchar(const wxChar
*format
, ...)
247 va_start(argptr
, format
);
248 wxVLogVerbose(format
, argptr
);
251 #endif // !wxUSE_UTF8_LOCALE_ONLY
253 #if wxUSE_UNICODE_UTF8
254 void wxDoLogVerboseUtf8(const char *format
, ...)
257 va_start(argptr
, format
);
258 wxVLogVerbose(format
, argptr
);
261 #endif // wxUSE_UNICODE_UTF8
263 // ----------------------------------------------------------------------------
264 // debug and trace functions
265 // ----------------------------------------------------------------------------
268 void wxVLogDebug(const wxString
& format
, va_list argptr
)
270 if ( wxLog::IsEnabled() )
272 wxLog::OnLog(wxLOG_Debug
,
273 wxString::FormatV(format
, argptr
), time(NULL
));
277 #if !wxUSE_UTF8_LOCALE_ONLY
278 void wxDoLogDebugWchar(const wxChar
*format
, ...)
281 va_start(argptr
, format
);
282 wxVLogDebug(format
, argptr
);
285 #endif // !wxUSE_UTF8_LOCALE_ONLY
287 #if wxUSE_UNICODE_UTF8
288 void wxDoLogDebugUtf8(const char *format
, ...)
291 va_start(argptr
, format
);
292 wxVLogDebug(format
, argptr
);
295 #endif // wxUSE_UNICODE_UTF8
296 #endif // wxUSE_LOG_DEBUG
299 void wxVLogTrace(const wxString
& mask
, const wxString
& format
, va_list argptr
)
301 if ( wxLog::IsEnabled() && wxLog::IsAllowedTraceMask(mask
) ) {
303 msg
<< wxS("(") << mask
<< wxS(") ") << wxString::FormatV(format
, argptr
);
305 wxLog::OnLog(wxLOG_Trace
, msg
, time(NULL
));
309 #if !wxUSE_UTF8_LOCALE_ONLY
310 void wxDoLogTraceWchar(const wxString
& mask
, const wxChar
*format
, ...)
313 va_start(argptr
, format
);
314 wxVLogTrace(mask
, format
, argptr
);
317 #endif // !wxUSE_UTF8_LOCALE_ONLY
319 #if wxUSE_UNICODE_UTF8
320 void wxDoLogTraceUtf8(const wxString
& mask
, const char *format
, ...)
323 va_start(argptr
, format
);
324 wxVLogTrace(mask
, format
, argptr
);
327 #endif // wxUSE_UNICODE_UTF8
329 // deprecated (but not declared as such because we don't want to complicate
330 // DECLARE_LOG_FUNCTION macros even more) overloads for wxTraceMask
331 #if WXWIN_COMPATIBILITY_2_8
332 void wxVLogTrace(wxTraceMask mask
, const wxString
& format
, va_list argptr
)
334 // we check that all of mask bits are set in the current mask, so
335 // that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something
336 // if both bits are set.
337 if ( wxLog::IsEnabled() && ((wxLog::GetTraceMask() & mask
) == mask
) ) {
338 wxLog::OnLog(wxLOG_Trace
, wxString::FormatV(format
, argptr
), time(NULL
));
342 #if !wxUSE_UTF8_LOCALE_ONLY
343 void wxDoLogTraceWchar(wxTraceMask mask
, const wxChar
*format
, ...)
346 va_start(argptr
, format
);
347 wxVLogTrace(mask
, format
, argptr
);
350 #endif // !wxUSE_UTF8_LOCALE_ONLY
352 #if wxUSE_UNICODE_UTF8
353 void wxDoLogTraceUtf8(wxTraceMask mask
, const char *format
, ...)
356 va_start(argptr
, format
);
357 wxVLogTrace(mask
, format
, argptr
);
360 #endif // wxUSE_UNICODE_UTF8
362 #endif // WXWIN_COMPATIBILITY_2_8
365 #if WXWIN_COMPATIBILITY_2_8
366 // workaround for http://bugzilla.openwatcom.org/show_bug.cgi?id=351
367 void wxDoLogTraceWchar(int mask
, const wxChar
*format
, ...)
370 va_start(argptr
, format
);
371 wxVLogTrace(mask
, format
, argptr
);
374 #endif // WXWIN_COMPATIBILITY_2_8
376 void wxDoLogTraceWchar(const char *mask
, const wxChar
*format
, ...)
379 va_start(argptr
, format
);
380 wxVLogTrace(mask
, format
, argptr
);
384 void wxDoLogTraceWchar(const wchar_t *mask
, const wxChar
*format
, ...)
387 va_start(argptr
, format
);
388 wxVLogTrace(mask
, format
, argptr
);
392 #if WXWIN_COMPATIBILITY_2_8
393 void wxVLogTrace(int mask
, const wxString
& format
, va_list argptr
)
394 { wxVLogTrace((wxTraceMask
)mask
, format
, argptr
); }
395 #endif // WXWIN_COMPATIBILITY_2_8
396 void wxVLogTrace(const char *mask
, const wxString
& format
, va_list argptr
)
397 { wxVLogTrace(wxString(mask
), format
, argptr
); }
398 void wxVLogTrace(const wchar_t *mask
, const wxString
& format
, va_list argptr
)
399 { wxVLogTrace(wxString(mask
), format
, argptr
); }
400 #endif // __WATCOMC__
401 #endif // wxUSE_LOG_TRACE
404 // wxLogSysError: one uses the last error code, for other you must give it
407 // return the system error message description
408 static inline wxString
wxLogSysErrorHelper(long err
)
410 return wxString::Format(_(" (error %ld: %s)"), err
, wxSysErrorMsg(err
));
413 void WXDLLIMPEXP_BASE
wxVLogSysError(const wxString
& format
, va_list argptr
)
415 wxVLogSysError(wxSysErrorCode(), format
, argptr
);
418 #if !wxUSE_UTF8_LOCALE_ONLY
419 void WXDLLIMPEXP_BASE
wxDoLogSysErrorWchar(const wxChar
*format
, ...)
422 va_start(argptr
, format
);
423 wxVLogSysError(format
, argptr
);
426 #endif // !wxUSE_UTF8_LOCALE_ONLY
428 #if wxUSE_UNICODE_UTF8
429 void WXDLLIMPEXP_BASE
wxDoLogSysErrorUtf8(const char *format
, ...)
432 va_start(argptr
, format
);
433 wxVLogSysError(format
, argptr
);
436 #endif // wxUSE_UNICODE_UTF8
438 void WXDLLIMPEXP_BASE
wxVLogSysError(long err
, const wxString
& format
, va_list argptr
)
440 if ( wxLog::IsEnabled() ) {
441 wxLog::OnLog(wxLOG_Error
,
442 wxString::FormatV(format
, argptr
) + wxLogSysErrorHelper(err
),
447 #if !wxUSE_UTF8_LOCALE_ONLY
448 void WXDLLIMPEXP_BASE
wxDoLogSysErrorWchar(long lErrCode
, const wxChar
*format
, ...)
451 va_start(argptr
, format
);
452 wxVLogSysError(lErrCode
, format
, argptr
);
455 #endif // !wxUSE_UTF8_LOCALE_ONLY
457 #if wxUSE_UNICODE_UTF8
458 void WXDLLIMPEXP_BASE
wxDoLogSysErrorUtf8(long lErrCode
, const char *format
, ...)
461 va_start(argptr
, format
);
462 wxVLogSysError(lErrCode
, format
, argptr
);
465 #endif // wxUSE_UNICODE_UTF8
468 // workaround for http://bugzilla.openwatcom.org/show_bug.cgi?id=351
469 void WXDLLIMPEXP_BASE
wxDoLogSysErrorWchar(unsigned long lErrCode
, const wxChar
*format
, ...)
472 va_start(argptr
, format
);
473 wxVLogSysError(lErrCode
, format
, argptr
);
477 void WXDLLIMPEXP_BASE
wxVLogSysError(unsigned long err
, const wxString
& format
, va_list argptr
)
478 { wxVLogSysError((long)err
, format
, argptr
); }
479 #endif // __WATCOMC__
481 // ----------------------------------------------------------------------------
482 // wxLog class implementation
483 // ----------------------------------------------------------------------------
485 unsigned wxLog::LogLastRepeatIfNeeded()
487 wxCRIT_SECT_LOCKER(lock
, GetPreviousLogCS());
489 return LogLastRepeatIfNeededUnlocked();
492 unsigned wxLog::LogLastRepeatIfNeededUnlocked()
494 const unsigned count
= ms_prevCounter
;
496 if ( ms_prevCounter
)
500 msg
.Printf(wxPLURAL("The previous message repeated once.",
501 "The previous message repeated %lu times.",
505 msg
.Printf(wxS("The previous message was repeated %lu times."),
509 ms_prevString
.clear();
510 DoLog(ms_prevLevel
, msg
, ms_prevTimeStamp
);
518 // Flush() must be called before destroying the object as otherwise some
519 // messages could be lost
520 if ( ms_prevCounter
)
522 wxMessageOutputDebug().Printf
524 wxS("Last repeated message (\"%s\", %lu times) wasn't output"),
532 void wxLog::OnLog(wxLogLevel level
, const wxString
& szString
, time_t t
)
534 if ( IsEnabled() && ms_logLevel
>= level
)
536 wxLog
*pLogger
= GetActiveTarget();
539 if ( GetRepetitionCounting() )
541 wxCRIT_SECT_LOCKER(lock
, GetPreviousLogCS());
543 if ( szString
== ms_prevString
)
547 // nothing else to do, in particular, don't log the
552 pLogger
->LogLastRepeatIfNeededUnlocked();
554 // reset repetition counter for a new message
555 ms_prevString
= szString
;
556 ms_prevLevel
= level
;
557 ms_prevTimeStamp
= t
;
560 pLogger
->DoLog(level
, szString
, t
);
565 // deprecated function
566 #if WXWIN_COMPATIBILITY_2_6
568 wxChar
*wxLog::SetLogBuffer(wxChar
* WXUNUSED(buf
), size_t WXUNUSED(size
))
573 #endif // WXWIN_COMPATIBILITY_2_6
575 #if WXWIN_COMPATIBILITY_2_8
577 void wxLog::DoLog(wxLogLevel
WXUNUSED(level
),
578 const char *WXUNUSED(szString
),
583 void wxLog::DoLog(wxLogLevel
WXUNUSED(level
),
584 const wchar_t *WXUNUSED(wzString
),
589 #endif // WXWIN_COMPATIBILITY_2_8
591 wxLog
*wxLog::GetActiveTarget()
593 if ( ms_bAutoCreate
&& ms_pLogger
== NULL
) {
594 // prevent infinite recursion if someone calls wxLogXXX() from
595 // wxApp::CreateLogTarget()
596 static bool s_bInGetActiveTarget
= false;
597 if ( !s_bInGetActiveTarget
) {
598 s_bInGetActiveTarget
= true;
600 // ask the application to create a log target for us
601 if ( wxTheApp
!= NULL
)
602 ms_pLogger
= wxTheApp
->GetTraits()->CreateLogTarget();
604 ms_pLogger
= new wxLogStderr
;
606 s_bInGetActiveTarget
= false;
608 // do nothing if it fails - what can we do?
615 wxLog
*wxLog::SetActiveTarget(wxLog
*pLogger
)
617 if ( ms_pLogger
!= NULL
) {
618 // flush the old messages before changing because otherwise they might
619 // get lost later if this target is not restored
623 wxLog
*pOldLogger
= ms_pLogger
;
624 ms_pLogger
= pLogger
;
629 void wxLog::DontCreateOnDemand()
631 ms_bAutoCreate
= false;
633 // this is usually called at the end of the program and we assume that it
634 // is *always* called at the end - so we free memory here to avoid false
635 // memory leak reports from wxWin memory tracking code
639 void wxLog::DoCreateOnDemand()
641 ms_bAutoCreate
= true;
644 void wxLog::AddTraceMask(const wxString
& str
)
646 wxCRIT_SECT_LOCKER(lock
, GetTraceMaskCS());
648 ms_aTraceMasks
.push_back(str
);
651 void wxLog::RemoveTraceMask(const wxString
& str
)
653 wxCRIT_SECT_LOCKER(lock
, GetTraceMaskCS());
655 int index
= ms_aTraceMasks
.Index(str
);
656 if ( index
!= wxNOT_FOUND
)
657 ms_aTraceMasks
.RemoveAt((size_t)index
);
660 void wxLog::ClearTraceMasks()
662 wxCRIT_SECT_LOCKER(lock
, GetTraceMaskCS());
664 ms_aTraceMasks
.Clear();
667 void wxLog::TimeStamp(wxString
*str
)
670 if ( !ms_timestamp
.empty() )
674 (void)time(&timeNow
);
677 wxStrftime(buf
, WXSIZEOF(buf
),
678 ms_timestamp
, wxLocaltime_r(&timeNow
, &tm
));
681 *str
<< buf
<< wxS(": ");
683 #endif // wxUSE_DATETIME
686 void wxLog::DoLog(wxLogLevel level
, const wxString
& szString
, time_t t
)
688 #if WXWIN_COMPATIBILITY_2_8
689 // DoLog() signature changed since 2.8, so we call the old versions here
690 // so that existing custom log classes still work:
691 DoLog(level
, (const char*)szString
.mb_str(), t
);
692 DoLog(level
, (const wchar_t*)szString
.wc_str(), t
);
696 case wxLOG_FatalError
:
697 LogString(_("Fatal error: ") + szString
, t
);
698 LogString(_("Program aborted."), t
);
708 LogString(_("Error: ") + szString
, t
);
712 LogString(_("Warning: ") + szString
, t
);
719 default: // log unknown log levels too
720 LogString(szString
, t
);
723 #if wxUSE_LOG_DEBUG || wxUSE_LOG_TRACE
733 // don't prepend "debug/trace" prefix under MSW as it goes to
734 // the debug window anyhow and don't add time stamp neither as
735 // debug output viewers under Windows typically add it
740 str
+= level
== wxLOG_Trace
? wxT("Trace: ")
745 wxMessageOutputDebug().Output(str
);
748 #endif // wxUSE_LOG_DEBUG || wxUSE_LOG_TRACE
752 void wxLog::DoLogString(const wxString
& szString
, time_t t
)
754 #if WXWIN_COMPATIBILITY_2_8
755 // DoLogString() signature changed since 2.8, so we call the old versions
756 // here so that existing custom log classes still work; unfortunately this
757 // also means that we can't have the wxFAIL_MSG below in compat mode
758 DoLogString((const char*)szString
.mb_str(), t
);
759 DoLogString((const wchar_t*)szString
.wc_str(), t
);
761 wxFAIL_MSG(wxS("DoLogString must be overriden if it's called."));
762 wxUnusedVar(szString
);
769 LogLastRepeatIfNeeded();
772 /*static*/ bool wxLog::IsAllowedTraceMask(const wxString
& mask
)
774 wxCRIT_SECT_LOCKER(lock
, GetTraceMaskCS());
776 for ( wxArrayString::iterator it
= ms_aTraceMasks
.begin(),
777 en
= ms_aTraceMasks
.end();
787 // ----------------------------------------------------------------------------
788 // wxLogBuffer implementation
789 // ----------------------------------------------------------------------------
791 void wxLogBuffer::Flush()
793 if ( !m_str
.empty() )
795 wxMessageOutputBest out
;
796 out
.Printf(wxS("%s"), m_str
.c_str());
801 #if wxUSE_LOG_DEBUG || wxUSE_LOG_TRACE
803 void wxLogBuffer::DoLog(wxLogLevel level
, const wxString
& szString
, time_t t
)
805 // don't put debug messages in the buffer, we don't want to show
806 // them to the user in a msg box, log them immediately
807 bool showImmediately
= false;
809 if ( level
== wxLOG_Trace
)
810 showImmediately
= true;
813 if ( level
== wxLOG_Debug
)
814 showImmediately
= true;
817 if ( showImmediately
)
823 wxMessageOutputDebug dbgout
;
824 dbgout
.Printf(wxS("%s\n"), str
.c_str());
828 wxLog::DoLog(level
, szString
, t
);
832 #endif // wxUSE_LOG_DEBUG || wxUSE_LOG_TRACE
834 void wxLogBuffer::DoLogString(const wxString
& szString
, time_t WXUNUSED(t
))
836 m_str
<< szString
<< wxS("\n");
839 // ----------------------------------------------------------------------------
840 // wxLogStderr class implementation
841 // ----------------------------------------------------------------------------
843 wxLogStderr::wxLogStderr(FILE *fp
)
851 void wxLogStderr::DoLogString(const wxString
& szString
, time_t WXUNUSED(t
))
858 wxFputc(wxS('\n'), m_fp
);
861 // under GUI systems such as Windows or Mac, programs usually don't have
862 // stderr at all, so show the messages also somewhere else, typically in
863 // the debugger window so that they go at least somewhere instead of being
865 if ( m_fp
== stderr
)
867 wxAppTraits
*traits
= wxTheApp
? wxTheApp
->GetTraits() : NULL
;
868 if ( traits
&& !traits
->HasStderr() )
870 wxMessageOutputDebug dbgout
;
871 dbgout
.Printf(wxS("%s\n"), str
.c_str());
876 // ----------------------------------------------------------------------------
877 // wxLogStream implementation
878 // ----------------------------------------------------------------------------
880 #if wxUSE_STD_IOSTREAM
881 #include "wx/ioswrap.h"
882 wxLogStream::wxLogStream(wxSTD ostream
*ostr
)
885 m_ostr
= &wxSTD cerr
;
890 void wxLogStream::DoLogString(const wxString
& szString
, time_t WXUNUSED(t
))
894 (*m_ostr
) << stamp
<< szString
<< wxSTD endl
;
896 #endif // wxUSE_STD_IOSTREAM
898 // ----------------------------------------------------------------------------
900 // ----------------------------------------------------------------------------
902 wxLogChain::wxLogChain(wxLog
*logger
)
904 m_bPassMessages
= true;
907 m_logOld
= wxLog::SetActiveTarget(this);
910 wxLogChain::~wxLogChain()
914 if ( m_logNew
!= this )
918 void wxLogChain::SetLog(wxLog
*logger
)
920 if ( m_logNew
!= this )
926 void wxLogChain::Flush()
931 // be careful to avoid infinite recursion
932 if ( m_logNew
&& m_logNew
!= this )
936 void wxLogChain::DoLog(wxLogLevel level
, const wxString
& szString
, time_t t
)
938 // let the previous logger show it
939 if ( m_logOld
&& IsPassingMessages() )
940 m_logOld
->Log(level
, szString
, t
);
942 // and also send it to the new one
943 if ( m_logNew
&& m_logNew
!= this )
944 m_logNew
->Log(level
, szString
, t
);
948 // "'this' : used in base member initializer list" - so what?
949 #pragma warning(disable:4355)
952 // ----------------------------------------------------------------------------
954 // ----------------------------------------------------------------------------
956 wxLogInterposer::wxLogInterposer()
961 // ----------------------------------------------------------------------------
962 // wxLogInterposerTemp
963 // ----------------------------------------------------------------------------
965 wxLogInterposerTemp::wxLogInterposerTemp()
972 #pragma warning(default:4355)
975 // ============================================================================
976 // Global functions/variables
977 // ============================================================================
979 // ----------------------------------------------------------------------------
981 // ----------------------------------------------------------------------------
983 bool wxLog::ms_bRepetCounting
= false;
984 wxString
wxLog::ms_prevString
;
985 unsigned int wxLog::ms_prevCounter
= 0;
986 time_t wxLog::ms_prevTimeStamp
= 0;
987 wxLogLevel
wxLog::ms_prevLevel
;
989 wxLog
*wxLog::ms_pLogger
= NULL
;
990 bool wxLog::ms_doLog
= true;
991 bool wxLog::ms_bAutoCreate
= true;
992 bool wxLog::ms_bVerbose
= false;
994 wxLogLevel
wxLog::ms_logLevel
= wxLOG_Max
; // log everything by default
996 size_t wxLog::ms_suspendCount
= 0;
998 wxString
wxLog::ms_timestamp(wxS("%X")); // time only, no date
1000 #if WXWIN_COMPATIBILITY_2_8
1001 wxTraceMask
wxLog::ms_ulTraceMask
= (wxTraceMask
)0;
1002 #endif // wxDEBUG_LEVEL
1004 wxArrayString
wxLog::ms_aTraceMasks
;
1006 // ----------------------------------------------------------------------------
1007 // stdout error logging helper
1008 // ----------------------------------------------------------------------------
1010 // helper function: wraps the message and justifies it under given position
1011 // (looks more pretty on the terminal). Also adds newline at the end.
1013 // TODO this is now disabled until I find a portable way of determining the
1014 // terminal window size (ok, I found it but does anybody really cares?)
1015 #ifdef LOG_PRETTY_WRAP
1016 static void wxLogWrap(FILE *f
, const char *pszPrefix
, const char *psz
)
1018 size_t nMax
= 80; // FIXME
1019 size_t nStart
= strlen(pszPrefix
);
1020 fputs(pszPrefix
, f
);
1023 while ( *psz
!= '\0' ) {
1024 for ( n
= nStart
; (n
< nMax
) && (*psz
!= '\0'); n
++ )
1028 if ( *psz
!= '\0' ) {
1030 for ( n
= 0; n
< nStart
; n
++ )
1033 // as we wrapped, squeeze all white space
1034 while ( isspace(*psz
) )
1041 #endif //LOG_PRETTY_WRAP
1043 // ----------------------------------------------------------------------------
1044 // error code/error message retrieval functions
1045 // ----------------------------------------------------------------------------
1047 // get error code from syste
1048 unsigned long wxSysErrorCode()
1050 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
1051 return ::GetLastError();
1057 // get error message from system
1058 const wxChar
*wxSysErrorMsg(unsigned long nErrCode
)
1060 if ( nErrCode
== 0 )
1061 nErrCode
= wxSysErrorCode();
1063 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
1064 static wxChar s_szBuf
[1024];
1066 // get error message from system
1068 if ( ::FormatMessage
1070 FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
1073 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
1079 // if this happens, something is seriously wrong, so don't use _() here
1081 wxSprintf(s_szBuf
, wxS("unknown error %lx"), nErrCode
);
1086 // copy it to our buffer and free memory
1087 // Crashes on SmartPhone (FIXME)
1088 #if !defined(__SMARTPHONE__) /* of WinCE */
1091 wxStrlcpy(s_szBuf
, (const wxChar
*)lpMsgBuf
, WXSIZEOF(s_szBuf
));
1093 LocalFree(lpMsgBuf
);
1095 // returned string is capitalized and ended with '\r\n' - bad
1096 s_szBuf
[0] = (wxChar
)wxTolower(s_szBuf
[0]);
1097 size_t len
= wxStrlen(s_szBuf
);
1100 if ( s_szBuf
[len
- 2] == wxS('\r') )
1101 s_szBuf
[len
- 2] = wxS('\0');
1105 #endif // !__SMARTPHONE__
1107 s_szBuf
[0] = wxS('\0');
1113 static wchar_t s_wzBuf
[1024];
1114 wxConvCurrent
->MB2WC(s_wzBuf
, strerror((int)nErrCode
),
1115 WXSIZEOF(s_wzBuf
) - 1);
1118 return strerror((int)nErrCode
);
1120 #endif // __WXMSW__/!__WXMSW__