-// implementation of Log functions
-//
-// NB: unfortunately we need all these distinct functions, we can't make them
-// macros and not all compilers inline vararg functions.
-// ----------------------------------------------------------------------------
-
-// log functions can't allocate memory (LogError("out of memory...") should
-// work!), so we use a static buffer for all log messages
-#define LOG_BUFFER_SIZE (4096)
-
-// static buffer for error messages (FIXME MT-unsafe)
-static wxChar s_szBuf[LOG_BUFFER_SIZE];
-
-// generic log function
-void wxLogGeneric(wxLogLevel level, const wxChar *szFormat, ...)
-{
- if ( wxLog::GetActiveTarget() != NULL ) {
- va_list argptr;
- va_start(argptr, szFormat);
- wxVsprintf(s_szBuf, szFormat, argptr);
- va_end(argptr);
-
- wxLog::OnLog(level, s_szBuf, time(NULL));
- }
-}
-
-#define IMPLEMENT_LOG_FUNCTION(level) \
- void wxLog##level(const wxChar *szFormat, ...) \
- { \
- if ( wxLog::GetActiveTarget() != NULL ) { \
- va_list argptr; \
- va_start(argptr, szFormat); \
- wxVsprintf(s_szBuf, szFormat, argptr); \
- va_end(argptr); \
- \
- wxLog::OnLog(wxLOG_##level, s_szBuf, time(NULL)); \
- } \
- }
-
-IMPLEMENT_LOG_FUNCTION(FatalError)
-IMPLEMENT_LOG_FUNCTION(Error)
-IMPLEMENT_LOG_FUNCTION(Warning)
-IMPLEMENT_LOG_FUNCTION(Message)
-IMPLEMENT_LOG_FUNCTION(Info)
-IMPLEMENT_LOG_FUNCTION(Status)
-
-// same as info, but only if 'verbose' mode is on
-void wxLogVerbose(const wxChar *szFormat, ...)
-{
- wxLog *pLog = wxLog::GetActiveTarget();
- if ( pLog != NULL && pLog->GetVerbose() ) {
- va_list argptr;
- va_start(argptr, szFormat);
- wxVsprintf(s_szBuf, szFormat, argptr);
- va_end(argptr);
-
- wxLog::OnLog(wxLOG_Info, s_szBuf, time(NULL));
- }
-}
-
-// debug functions
-#ifdef __WXDEBUG__
-#define IMPLEMENT_LOG_DEBUG_FUNCTION(level) \
- void wxLog##level(const wxChar *szFormat, ...) \
- { \
- if ( wxLog::GetActiveTarget() != NULL ) { \
- va_list argptr; \
- va_start(argptr, szFormat); \
- wxVsprintf(s_szBuf, szFormat, argptr); \
- va_end(argptr); \
- \
- wxLog::OnLog(wxLOG_##level, s_szBuf, time(NULL)); \
- } \
- }
-
- void wxLogTrace(const wxChar *mask, const wxChar *szFormat, ...)
- {
- wxLog *pLog = wxLog::GetActiveTarget();
-
- if ( pLog != NULL && wxLog::IsAllowedTraceMask(mask) ) {
- va_list argptr;
- va_start(argptr, szFormat);
- wxVsprintf(s_szBuf, szFormat, argptr);
- va_end(argptr);
-
- wxLog::OnLog(wxLOG_Trace, s_szBuf, time(NULL));
- }
- }
-
- void wxLogTrace(wxTraceMask mask, const wxChar *szFormat, ...)
- {
- wxLog *pLog = wxLog::GetActiveTarget();
-
- // we check that all of mask bits are set in the current mask, so
- // that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something
- // if both bits are set.
- if ( pLog != NULL && ((pLog->GetTraceMask() & mask) == mask) ) {
- va_list argptr;
- va_start(argptr, szFormat);
- wxVsprintf(s_szBuf, szFormat, argptr);
- va_end(argptr);
-
- wxLog::OnLog(wxLOG_Trace, s_szBuf, time(NULL));
- }
- }
-
-#else // release
- #define IMPLEMENT_LOG_DEBUG_FUNCTION(level)
+// helper global functions
+// ----------------------------------------------------------------------------
+
+void wxSafeShowMessage(const wxString& title, const wxString& text)
+{
+#ifdef __WINDOWS__
+ ::MessageBox(NULL, text.t_str(), title.t_str(), MB_OK | MB_ICONSTOP);
+#else
+ wxFprintf(stderr, wxS("%s: %s\n"), title.c_str(), text.c_str());
+ fflush(stderr);
+#endif
+}
+
+// ----------------------------------------------------------------------------
+// wxLog class implementation
+// ----------------------------------------------------------------------------
+
+unsigned wxLog::LogLastRepeatIfNeeded()
+{
+ const unsigned count = gs_prevLog.numRepeated;
+
+ if ( gs_prevLog.numRepeated )
+ {
+ wxString msg;
+#if wxUSE_INTL
+ msg.Printf(wxPLURAL("The previous message repeated once.",
+ "The previous message repeated %lu times.",
+ gs_prevLog.numRepeated),
+ gs_prevLog.numRepeated);
+#else
+ msg.Printf(wxS("The previous message was repeated %lu times."),
+ gs_prevLog.numRepeated);
+#endif
+ gs_prevLog.numRepeated = 0;
+ gs_prevLog.msg.clear();
+ DoLogRecord(gs_prevLog.level, msg, gs_prevLog.info);
+ }
+
+ return count;
+}
+
+wxLog::~wxLog()
+{
+ // Flush() must be called before destroying the object as otherwise some
+ // messages could be lost
+ if ( gs_prevLog.numRepeated )
+ {
+ wxMessageOutputDebug().Printf
+ (
+ wxS("Last repeated message (\"%s\", %lu times) wasn't output"),
+ gs_prevLog.msg,
+ gs_prevLog.numRepeated
+ );
+ }
+}
+
+// ----------------------------------------------------------------------------
+// wxLog logging functions
+// ----------------------------------------------------------------------------
+
+/* static */
+void
+wxLog::OnLog(wxLogLevel level, const wxString& msg, time_t t)
+{
+ wxLogRecordInfo info;
+ info.timestamp = t;
+#if wxUSE_THREADS
+ info.threadId = wxThread::GetCurrentId();
+#endif // wxUSE_THREADS
+
+ OnLog(level, msg, info);
+}
+
+/* static */
+void
+wxLog::OnLog(wxLogLevel level,
+ const wxString& msg,
+ const wxLogRecordInfo& info)
+{
+ // fatal errors can't be suppressed nor handled by the custom log target
+ // and always terminate the program
+ if ( level == wxLOG_FatalError )
+ {
+ wxSafeShowMessage(wxS("Fatal Error"), msg);
+
+#ifdef __WXWINCE__
+ ExitThread(3);
+#else
+ abort();