Changed wxLog DoLogXXX() callbacks and introduced wxLogRecordInfo.
[wxWidgets.git] / src / common / log.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/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$
8 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #if wxUSE_LOG
28
29 // wxWidgets
30 #ifndef WX_PRECOMP
31 #include "wx/log.h"
32 #include "wx/app.h"
33 #include "wx/arrstr.h"
34 #include "wx/intl.h"
35 #include "wx/string.h"
36 #include "wx/utils.h"
37 #endif //WX_PRECOMP
38
39 #include "wx/apptrait.h"
40 #include "wx/datetime.h"
41 #include "wx/file.h"
42 #include "wx/msgout.h"
43 #include "wx/textfile.h"
44 #include "wx/thread.h"
45 #include "wx/crt.h"
46
47 // other standard headers
48 #ifndef __WXWINCE__
49 #include <errno.h>
50 #endif
51
52 #include <stdlib.h>
53
54 #ifndef __WXPALMOS5__
55 #ifndef __WXWINCE__
56 #include <time.h>
57 #else
58 #include "wx/msw/wince/time.h"
59 #endif
60 #endif /* ! __WXPALMOS5__ */
61
62 #if defined(__WINDOWS__)
63 #include "wx/msw/private.h" // includes windows.h
64 #endif
65
66 #if wxUSE_THREADS
67
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
73
74 static inline wxCriticalSection& GetTraceMaskCS()
75 {
76 static wxCriticalSection s_csTrace;
77
78 return s_csTrace;
79 }
80
81 static inline wxCriticalSection& GetPreviousLogCS()
82 {
83 static wxCriticalSection s_csPrev;
84
85 return s_csPrev;
86 }
87
88 #endif // wxUSE_THREADS
89
90 // ----------------------------------------------------------------------------
91 // non member functions
92 // ----------------------------------------------------------------------------
93
94 // define this to enable wrapping of log messages
95 //#define LOG_PRETTY_WRAP
96
97 #ifdef LOG_PRETTY_WRAP
98 static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz);
99 #endif
100
101 // ----------------------------------------------------------------------------
102 // module globals
103 // ----------------------------------------------------------------------------
104
105 namespace
106 {
107
108 // this struct is used to store information about the previous log message used
109 // by OnLog() to (optionally) avoid logging multiple copies of the same message
110 struct PreviousLogInfo
111 {
112 PreviousLogInfo()
113 {
114 numRepeated = 0;
115 }
116
117
118 // previous message itself
119 wxString msg;
120
121 // its level
122 wxLogLevel level;
123
124 // other information about it
125 wxLogRecordInfo info;
126
127 // the number of times it was already repeated
128 unsigned numRepeated;
129 };
130
131 PreviousLogInfo gs_prevLog;
132
133 } // anonymous namespace
134
135 // ============================================================================
136 // implementation
137 // ============================================================================
138
139 // ----------------------------------------------------------------------------
140 // implementation of Log functions
141 //
142 // NB: unfortunately we need all these distinct functions, we can't make them
143 // macros and not all compilers inline vararg functions.
144 // ----------------------------------------------------------------------------
145
146 // generic log function
147 void wxVLogGeneric(wxLogLevel level, const wxString& format, va_list argptr)
148 {
149 if ( wxLog::IsEnabled() )
150 {
151 wxLog::OnLog(level, wxString::FormatV(format, argptr));
152 }
153 }
154
155 #if !wxUSE_UTF8_LOCALE_ONLY
156 void wxDoLogGenericWchar(wxLogLevel level, const wxChar *format, ...)
157 {
158 va_list argptr;
159 va_start(argptr, format);
160 wxVLogGeneric(level, format, argptr);
161 va_end(argptr);
162 }
163 #endif // wxUSE_UTF8_LOCALE_ONLY
164
165 #if wxUSE_UNICODE_UTF8
166 void wxDoLogGenericUtf8(wxLogLevel level, const char *format, ...)
167 {
168 va_list argptr;
169 va_start(argptr, format);
170 wxVLogGeneric(level, format, argptr);
171 va_end(argptr);
172 }
173 #endif // wxUSE_UNICODE_UTF8
174
175 #if !wxUSE_UTF8_LOCALE_ONLY
176 #define IMPLEMENT_LOG_FUNCTION_WCHAR(level) \
177 void wxDoLog##level##Wchar(const wxChar *format, ...) \
178 { \
179 va_list argptr; \
180 va_start(argptr, format); \
181 wxVLog##level(format, argptr); \
182 va_end(argptr); \
183 }
184 #else
185 #define IMPLEMENT_LOG_FUNCTION_WCHAR(level)
186 #endif
187
188 #if wxUSE_UNICODE_UTF8
189 #define IMPLEMENT_LOG_FUNCTION_UTF8(level) \
190 void wxDoLog##level##Utf8(const char *format, ...) \
191 { \
192 va_list argptr; \
193 va_start(argptr, format); \
194 wxVLog##level(format, argptr); \
195 va_end(argptr); \
196 }
197 #else
198 #define IMPLEMENT_LOG_FUNCTION_UTF8(level)
199 #endif
200
201 #define IMPLEMENT_LOG_FUNCTION(level) \
202 void wxVLog##level(const wxString& format, va_list argptr) \
203 { \
204 if ( wxLog::IsEnabled() ) \
205 wxLog::OnLog(wxLOG_##level, wxString::FormatV(format, argptr)); \
206 } \
207 IMPLEMENT_LOG_FUNCTION_WCHAR(level) \
208 IMPLEMENT_LOG_FUNCTION_UTF8(level)
209
210 IMPLEMENT_LOG_FUNCTION(Error)
211 IMPLEMENT_LOG_FUNCTION(Warning)
212 IMPLEMENT_LOG_FUNCTION(Message)
213 IMPLEMENT_LOG_FUNCTION(Info)
214 IMPLEMENT_LOG_FUNCTION(Status)
215
216 void wxSafeShowMessage(const wxString& title, const wxString& text)
217 {
218 #ifdef __WINDOWS__
219 ::MessageBox(NULL, text.t_str(), title.t_str(), MB_OK | MB_ICONSTOP);
220 #else
221 wxFprintf(stderr, wxS("%s: %s\n"), title.c_str(), text.c_str());
222 fflush(stderr);
223 #endif
224 }
225
226 // fatal errors can't be suppressed nor handled by the custom log target and
227 // always terminate the program
228 void wxVLogFatalError(const wxString& format, va_list argptr)
229 {
230 wxSafeShowMessage(wxS("Fatal Error"), wxString::FormatV(format, argptr));
231
232 #ifdef __WXWINCE__
233 ExitThread(3);
234 #else
235 abort();
236 #endif
237 }
238
239 #if !wxUSE_UTF8_LOCALE_ONLY
240 void wxDoLogFatalErrorWchar(const wxChar *format, ...)
241 {
242 va_list argptr;
243 va_start(argptr, format);
244 wxVLogFatalError(format, argptr);
245
246 // some compilers warn about unreachable code and it shouldn't matter
247 // for the others anyhow...
248 //va_end(argptr);
249 }
250 #endif // wxUSE_UTF8_LOCALE_ONLY
251
252 #if wxUSE_UNICODE_UTF8
253 void wxDoLogFatalErrorUtf8(const char *format, ...)
254 {
255 va_list argptr;
256 va_start(argptr, format);
257 wxVLogFatalError(format, argptr);
258
259 // some compilers warn about unreachable code and it shouldn't matter
260 // for the others anyhow...
261 //va_end(argptr);
262 }
263 #endif // wxUSE_UNICODE_UTF8
264
265 // same as info, but only if 'verbose' mode is on
266 void wxVLogVerbose(const wxString& format, va_list argptr)
267 {
268 if ( wxLog::IsEnabled() ) {
269 if ( wxLog::GetActiveTarget() != NULL && wxLog::GetVerbose() )
270 wxLog::OnLog(wxLOG_Info, wxString::FormatV(format, argptr));
271 }
272 }
273
274 #if !wxUSE_UTF8_LOCALE_ONLY
275 void wxDoLogVerboseWchar(const wxChar *format, ...)
276 {
277 va_list argptr;
278 va_start(argptr, format);
279 wxVLogVerbose(format, argptr);
280 va_end(argptr);
281 }
282 #endif // !wxUSE_UTF8_LOCALE_ONLY
283
284 #if wxUSE_UNICODE_UTF8
285 void wxDoLogVerboseUtf8(const char *format, ...)
286 {
287 va_list argptr;
288 va_start(argptr, format);
289 wxVLogVerbose(format, argptr);
290 va_end(argptr);
291 }
292 #endif // wxUSE_UNICODE_UTF8
293
294 // ----------------------------------------------------------------------------
295 // debug and trace functions
296 // ----------------------------------------------------------------------------
297
298 #if wxUSE_LOG_DEBUG
299 void wxVLogDebug(const wxString& format, va_list argptr)
300 {
301 if ( wxLog::IsEnabled() )
302 {
303 wxLog::OnLog(wxLOG_Debug, wxString::FormatV(format, argptr));
304 }
305 }
306
307 #if !wxUSE_UTF8_LOCALE_ONLY
308 void wxDoLogDebugWchar(const wxChar *format, ...)
309 {
310 va_list argptr;
311 va_start(argptr, format);
312 wxVLogDebug(format, argptr);
313 va_end(argptr);
314 }
315 #endif // !wxUSE_UTF8_LOCALE_ONLY
316
317 #if wxUSE_UNICODE_UTF8
318 void wxDoLogDebugUtf8(const char *format, ...)
319 {
320 va_list argptr;
321 va_start(argptr, format);
322 wxVLogDebug(format, argptr);
323 va_end(argptr);
324 }
325 #endif // wxUSE_UNICODE_UTF8
326 #endif // wxUSE_LOG_DEBUG
327
328 #if wxUSE_LOG_TRACE
329 void wxVLogTrace(const wxString& mask, const wxString& format, va_list argptr)
330 {
331 if ( wxLog::IsEnabled() && wxLog::IsAllowedTraceMask(mask) ) {
332 wxString msg;
333 msg << wxS("(") << mask << wxS(") ") << wxString::FormatV(format, argptr);
334
335 wxLog::OnLog(wxLOG_Trace, msg);
336 }
337 }
338
339 #if !wxUSE_UTF8_LOCALE_ONLY
340 void wxDoLogTraceWchar(const wxString& mask, const wxChar *format, ...)
341 {
342 va_list argptr;
343 va_start(argptr, format);
344 wxVLogTrace(mask, format, argptr);
345 va_end(argptr);
346 }
347 #endif // !wxUSE_UTF8_LOCALE_ONLY
348
349 #if wxUSE_UNICODE_UTF8
350 void wxDoLogTraceUtf8(const wxString& mask, const char *format, ...)
351 {
352 va_list argptr;
353 va_start(argptr, format);
354 wxVLogTrace(mask, format, argptr);
355 va_end(argptr);
356 }
357 #endif // wxUSE_UNICODE_UTF8
358
359 // deprecated (but not declared as such because we don't want to complicate
360 // DECLARE_LOG_FUNCTION macros even more) overloads for wxTraceMask
361 #if WXWIN_COMPATIBILITY_2_8
362 void wxVLogTrace(wxTraceMask mask, const wxString& format, va_list argptr)
363 {
364 // we check that all of mask bits are set in the current mask, so
365 // that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something
366 // if both bits are set.
367 if ( wxLog::IsEnabled() && ((wxLog::GetTraceMask() & mask) == mask) ) {
368 wxLog::OnLog(wxLOG_Trace, wxString::FormatV(format, argptr));
369 }
370 }
371
372 #if !wxUSE_UTF8_LOCALE_ONLY
373 void wxDoLogTraceWchar(wxTraceMask mask, const wxChar *format, ...)
374 {
375 va_list argptr;
376 va_start(argptr, format);
377 wxVLogTrace(mask, format, argptr);
378 va_end(argptr);
379 }
380 #endif // !wxUSE_UTF8_LOCALE_ONLY
381
382 #if wxUSE_UNICODE_UTF8
383 void wxDoLogTraceUtf8(wxTraceMask mask, const char *format, ...)
384 {
385 va_list argptr;
386 va_start(argptr, format);
387 wxVLogTrace(mask, format, argptr);
388 va_end(argptr);
389 }
390 #endif // wxUSE_UNICODE_UTF8
391
392 #endif // WXWIN_COMPATIBILITY_2_8
393
394 #ifdef __WATCOMC__
395 #if WXWIN_COMPATIBILITY_2_8
396 // workaround for http://bugzilla.openwatcom.org/show_bug.cgi?id=351
397 void wxDoLogTraceWchar(int mask, const wxChar *format, ...)
398 {
399 va_list argptr;
400 va_start(argptr, format);
401 wxVLogTrace(mask, format, argptr);
402 va_end(argptr);
403 }
404 #endif // WXWIN_COMPATIBILITY_2_8
405
406 void wxDoLogTraceWchar(const char *mask, const wxChar *format, ...)
407 {
408 va_list argptr;
409 va_start(argptr, format);
410 wxVLogTrace(mask, format, argptr);
411 va_end(argptr);
412 }
413
414 void wxDoLogTraceWchar(const wchar_t *mask, const wxChar *format, ...)
415 {
416 va_list argptr;
417 va_start(argptr, format);
418 wxVLogTrace(mask, format, argptr);
419 va_end(argptr);
420 }
421
422 #if WXWIN_COMPATIBILITY_2_8
423 void wxVLogTrace(int mask, const wxString& format, va_list argptr)
424 { wxVLogTrace((wxTraceMask)mask, format, argptr); }
425 #endif // WXWIN_COMPATIBILITY_2_8
426 void wxVLogTrace(const char *mask, const wxString& format, va_list argptr)
427 { wxVLogTrace(wxString(mask), format, argptr); }
428 void wxVLogTrace(const wchar_t *mask, const wxString& format, va_list argptr)
429 { wxVLogTrace(wxString(mask), format, argptr); }
430 #endif // __WATCOMC__
431 #endif // wxUSE_LOG_TRACE
432
433
434 // wxLogSysError: one uses the last error code, for other you must give it
435 // explicitly
436
437 // return the system error message description
438 static inline wxString wxLogSysErrorHelper(long err)
439 {
440 return wxString::Format(_(" (error %ld: %s)"), err, wxSysErrorMsg(err));
441 }
442
443 void WXDLLIMPEXP_BASE wxVLogSysError(const wxString& format, va_list argptr)
444 {
445 wxVLogSysError(wxSysErrorCode(), format, argptr);
446 }
447
448 #if !wxUSE_UTF8_LOCALE_ONLY
449 void WXDLLIMPEXP_BASE wxDoLogSysErrorWchar(const wxChar *format, ...)
450 {
451 va_list argptr;
452 va_start(argptr, format);
453 wxVLogSysError(format, argptr);
454 va_end(argptr);
455 }
456 #endif // !wxUSE_UTF8_LOCALE_ONLY
457
458 #if wxUSE_UNICODE_UTF8
459 void WXDLLIMPEXP_BASE wxDoLogSysErrorUtf8(const char *format, ...)
460 {
461 va_list argptr;
462 va_start(argptr, format);
463 wxVLogSysError(format, argptr);
464 va_end(argptr);
465 }
466 #endif // wxUSE_UNICODE_UTF8
467
468 void WXDLLIMPEXP_BASE wxVLogSysError(long err, const wxString& format, va_list argptr)
469 {
470 if ( wxLog::IsEnabled() )
471 {
472 wxLog::OnLog(wxLOG_Error,
473 wxString::FormatV(format, argptr) + wxLogSysErrorHelper(err));
474 }
475 }
476
477 #if !wxUSE_UTF8_LOCALE_ONLY
478 void WXDLLIMPEXP_BASE wxDoLogSysErrorWchar(long lErrCode, const wxChar *format, ...)
479 {
480 va_list argptr;
481 va_start(argptr, format);
482 wxVLogSysError(lErrCode, format, argptr);
483 va_end(argptr);
484 }
485 #endif // !wxUSE_UTF8_LOCALE_ONLY
486
487 #if wxUSE_UNICODE_UTF8
488 void WXDLLIMPEXP_BASE wxDoLogSysErrorUtf8(long lErrCode, const char *format, ...)
489 {
490 va_list argptr;
491 va_start(argptr, format);
492 wxVLogSysError(lErrCode, format, argptr);
493 va_end(argptr);
494 }
495 #endif // wxUSE_UNICODE_UTF8
496
497 #ifdef __WATCOMC__
498 // workaround for http://bugzilla.openwatcom.org/show_bug.cgi?id=351
499 void WXDLLIMPEXP_BASE wxDoLogSysErrorWchar(unsigned long lErrCode, const wxChar *format, ...)
500 {
501 va_list argptr;
502 va_start(argptr, format);
503 wxVLogSysError(lErrCode, format, argptr);
504 va_end(argptr);
505 }
506
507 void WXDLLIMPEXP_BASE wxVLogSysError(unsigned long err, const wxString& format, va_list argptr)
508 { wxVLogSysError((long)err, format, argptr); }
509 #endif // __WATCOMC__
510
511 // ----------------------------------------------------------------------------
512 // wxLog class implementation
513 // ----------------------------------------------------------------------------
514
515 unsigned wxLog::LogLastRepeatIfNeeded()
516 {
517 wxCRIT_SECT_LOCKER(lock, GetPreviousLogCS());
518
519 return LogLastRepeatIfNeededUnlocked();
520 }
521
522 unsigned wxLog::LogLastRepeatIfNeededUnlocked()
523 {
524 const unsigned count = gs_prevLog.numRepeated;
525
526 if ( gs_prevLog.numRepeated )
527 {
528 wxString msg;
529 #if wxUSE_INTL
530 msg.Printf(wxPLURAL("The previous message repeated once.",
531 "The previous message repeated %lu times.",
532 gs_prevLog.numRepeated),
533 gs_prevLog.numRepeated);
534 #else
535 msg.Printf(wxS("The previous message was repeated %lu times."),
536 gs_prevLog.numRepeated);
537 #endif
538 gs_prevLog.numRepeated = 0;
539 gs_prevLog.msg.clear();
540 DoLogRecord(gs_prevLog.level, msg, gs_prevLog.info);
541 }
542
543 return count;
544 }
545
546 wxLog::~wxLog()
547 {
548 // Flush() must be called before destroying the object as otherwise some
549 // messages could be lost
550 if ( gs_prevLog.numRepeated )
551 {
552 wxMessageOutputDebug().Printf
553 (
554 wxS("Last repeated message (\"%s\", %lu times) wasn't output"),
555 gs_prevLog.msg,
556 gs_prevLog.numRepeated
557 );
558 }
559 }
560
561 // ----------------------------------------------------------------------------
562 // wxLog logging functions
563 // ----------------------------------------------------------------------------
564
565 /* static */
566 void
567 wxLog::OnLog(wxLogLevel level, const wxString& msg, time_t t)
568 {
569 wxLogRecordInfo info;
570 info.timestamp = t;
571 #if wxUSE_THREADS
572 info.threadId = wxThread::GetCurrentId();
573 #endif // wxUSE_THREADS
574
575 OnLog(level, msg, info);
576 }
577
578 /* static */
579 void
580 wxLog::OnLog(wxLogLevel level,
581 const wxString& msg,
582 const wxLogRecordInfo& info)
583 {
584 if ( IsEnabled() && ms_logLevel >= level )
585 {
586 wxLog *pLogger = GetActiveTarget();
587 if ( pLogger )
588 {
589 if ( GetRepetitionCounting() )
590 {
591 wxCRIT_SECT_LOCKER(lock, GetPreviousLogCS());
592
593 if ( msg == gs_prevLog.msg )
594 {
595 gs_prevLog.numRepeated++;
596
597 // nothing else to do, in particular, don't log the
598 // repeated message
599 return;
600 }
601
602 pLogger->LogLastRepeatIfNeededUnlocked();
603
604 // reset repetition counter for a new message
605 gs_prevLog.msg = msg;
606 gs_prevLog.level = level;
607 gs_prevLog.info = info;
608 }
609
610 pLogger->DoLogRecord(level, msg, info);
611 }
612 }
613 }
614
615 void wxLog::DoLogRecord(wxLogLevel level,
616 const wxString& msg,
617 const wxLogRecordInfo& info)
618 {
619 #if WXWIN_COMPATIBILITY_2_8
620 // call the old DoLog() to ensure that existing custom log classes still
621 // work
622 //
623 // as the user code could have defined it as either taking "const char *"
624 // (in ANSI build) or "const wxChar *" (in ANSI/Unicode), we have no choice
625 // but to call both of them
626 DoLog(level, (const char*)msg.mb_str(), info.timestamp);
627 DoLog(level, (const wchar_t*)msg.wc_str(), info.timestamp);
628 #endif // WXWIN_COMPATIBILITY_2_8
629
630
631 // TODO: it would be better to extract message formatting in a separate
632 // wxLogFormatter class but for now we hard code formatting here
633
634 wxString prefix;
635
636 // don't time stamp debug messages under MSW as debug viewers usually
637 // already have an option to do it
638 #ifdef __WXMSW__
639 if ( level != wxLOG_Debug && level != wxLOG_Trace )
640 #endif // __WXMSW__
641 TimeStamp(&prefix);
642
643 // TODO: use the other wxLogRecordInfo fields
644
645 switch ( level )
646 {
647 case wxLOG_Error:
648 prefix += _("Error: ");
649 break;
650
651 case wxLOG_Warning:
652 prefix += _("Warning: ");
653 break;
654
655 // don't prepend "debug/trace" prefix under MSW as it goes to the debug
656 // window anyhow and so can't be confused with something else
657 #ifndef __WXMSW__
658 case wxLOG_Debug:
659 // this prefix (as well as the one below) is intentionally not
660 // translated as nobody translates debug messages anyhow
661 prefix += "Debug: ";
662 break;
663
664 case wxLOG_Trace:
665 prefix += "Trace: ";
666 break;
667 #endif // !__WXMSW__
668 }
669
670 DoLogTextAtLevel(level, prefix + msg);
671 }
672
673 void wxLog::DoLogTextAtLevel(wxLogLevel level, const wxString& msg)
674 {
675 // we know about debug messages (because using wxMessageOutputDebug is the
676 // right thing to do in 99% of all cases and also for compatibility) but
677 // anything else needs to be handled in the derived class
678 if ( level == wxLOG_Debug || level == wxLOG_Trace )
679 {
680 wxMessageOutputDebug().Output(msg + wxS('\n'));
681 }
682 else
683 {
684 DoLogText(msg);
685 }
686 }
687
688 void wxLog::DoLogText(const wxString& WXUNUSED(msg))
689 {
690 // in 2.8-compatible build the derived class might override DoLog() or
691 // DoLogString() instead so we can't have this assert there
692 #if !WXWIN_COMPATIBILITY_2_8
693 wxFAIL_MSG( "must be overridden if it is called" );
694 #endif // WXWIN_COMPATIBILITY_2_8
695 }
696
697 void wxLog::DoLog(wxLogLevel WXUNUSED(level), const char *szString, time_t t)
698 {
699 DoLogString(szString, t);
700 }
701
702 void wxLog::DoLog(wxLogLevel WXUNUSED(level), const wchar_t *wzString, time_t t)
703 {
704 DoLogString(wzString, t);
705 }
706
707 // ----------------------------------------------------------------------------
708 // wxLog active target management
709 // ----------------------------------------------------------------------------
710
711 wxLog *wxLog::GetActiveTarget()
712 {
713 if ( ms_bAutoCreate && ms_pLogger == NULL ) {
714 // prevent infinite recursion if someone calls wxLogXXX() from
715 // wxApp::CreateLogTarget()
716 static bool s_bInGetActiveTarget = false;
717 if ( !s_bInGetActiveTarget ) {
718 s_bInGetActiveTarget = true;
719
720 // ask the application to create a log target for us
721 if ( wxTheApp != NULL )
722 ms_pLogger = wxTheApp->GetTraits()->CreateLogTarget();
723 else
724 ms_pLogger = new wxLogStderr;
725
726 s_bInGetActiveTarget = false;
727
728 // do nothing if it fails - what can we do?
729 }
730 }
731
732 return ms_pLogger;
733 }
734
735 wxLog *wxLog::SetActiveTarget(wxLog *pLogger)
736 {
737 if ( ms_pLogger != NULL ) {
738 // flush the old messages before changing because otherwise they might
739 // get lost later if this target is not restored
740 ms_pLogger->Flush();
741 }
742
743 wxLog *pOldLogger = ms_pLogger;
744 ms_pLogger = pLogger;
745
746 return pOldLogger;
747 }
748
749 void wxLog::DontCreateOnDemand()
750 {
751 ms_bAutoCreate = false;
752
753 // this is usually called at the end of the program and we assume that it
754 // is *always* called at the end - so we free memory here to avoid false
755 // memory leak reports from wxWin memory tracking code
756 ClearTraceMasks();
757 }
758
759 void wxLog::DoCreateOnDemand()
760 {
761 ms_bAutoCreate = true;
762 }
763
764 void wxLog::AddTraceMask(const wxString& str)
765 {
766 wxCRIT_SECT_LOCKER(lock, GetTraceMaskCS());
767
768 ms_aTraceMasks.push_back(str);
769 }
770
771 void wxLog::RemoveTraceMask(const wxString& str)
772 {
773 wxCRIT_SECT_LOCKER(lock, GetTraceMaskCS());
774
775 int index = ms_aTraceMasks.Index(str);
776 if ( index != wxNOT_FOUND )
777 ms_aTraceMasks.RemoveAt((size_t)index);
778 }
779
780 void wxLog::ClearTraceMasks()
781 {
782 wxCRIT_SECT_LOCKER(lock, GetTraceMaskCS());
783
784 ms_aTraceMasks.Clear();
785 }
786
787 void wxLog::TimeStamp(wxString *str)
788 {
789 #if wxUSE_DATETIME
790 if ( !ms_timestamp.empty() )
791 {
792 wxChar buf[256];
793 time_t timeNow;
794 (void)time(&timeNow);
795
796 struct tm tm;
797 wxStrftime(buf, WXSIZEOF(buf),
798 ms_timestamp, wxLocaltime_r(&timeNow, &tm));
799
800 str->Empty();
801 *str << buf << wxS(": ");
802 }
803 #endif // wxUSE_DATETIME
804 }
805
806 void wxLog::Flush()
807 {
808 LogLastRepeatIfNeeded();
809 }
810
811 /*static*/ bool wxLog::IsAllowedTraceMask(const wxString& mask)
812 {
813 wxCRIT_SECT_LOCKER(lock, GetTraceMaskCS());
814
815 for ( wxArrayString::iterator it = ms_aTraceMasks.begin(),
816 en = ms_aTraceMasks.end();
817 it != en; ++it )
818 {
819 if ( *it == mask)
820 return true;
821 }
822
823 return false;
824 }
825
826 // ----------------------------------------------------------------------------
827 // wxLogBuffer implementation
828 // ----------------------------------------------------------------------------
829
830 void wxLogBuffer::Flush()
831 {
832 if ( !m_str.empty() )
833 {
834 wxMessageOutputBest out;
835 out.Printf(wxS("%s"), m_str.c_str());
836 m_str.clear();
837 }
838 }
839
840 void wxLogBuffer::DoLogTextAtLevel(wxLogLevel level, const wxString& msg)
841 {
842 // don't put debug messages in the buffer, we don't want to show
843 // them to the user in a msg box, log them immediately
844 switch ( level )
845 {
846 case wxLOG_Debug:
847 case wxLOG_Trace:
848 wxLog::DoLogTextAtLevel(level, msg);
849 break;
850
851 default:
852 m_str << msg << wxS("\n");
853 }
854 }
855
856 // ----------------------------------------------------------------------------
857 // wxLogStderr class implementation
858 // ----------------------------------------------------------------------------
859
860 wxLogStderr::wxLogStderr(FILE *fp)
861 {
862 if ( fp == NULL )
863 m_fp = stderr;
864 else
865 m_fp = fp;
866 }
867
868 void wxLogStderr::DoLogText(const wxString& msg)
869 {
870 wxFputs(msg + '\n', m_fp);
871 fflush(m_fp);
872
873 // under GUI systems such as Windows or Mac, programs usually don't have
874 // stderr at all, so show the messages also somewhere else, typically in
875 // the debugger window so that they go at least somewhere instead of being
876 // simply lost
877 if ( m_fp == stderr )
878 {
879 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
880 if ( traits && !traits->HasStderr() )
881 {
882 wxMessageOutputDebug().Output(msg + wxS('\n'));
883 }
884 }
885 }
886
887 // ----------------------------------------------------------------------------
888 // wxLogStream implementation
889 // ----------------------------------------------------------------------------
890
891 #if wxUSE_STD_IOSTREAM
892 #include "wx/ioswrap.h"
893 wxLogStream::wxLogStream(wxSTD ostream *ostr)
894 {
895 if ( ostr == NULL )
896 m_ostr = &wxSTD cerr;
897 else
898 m_ostr = ostr;
899 }
900
901 void wxLogStream::DoLogText(const wxString& msg)
902 {
903 (*m_ostr) << msg << wxSTD endl;
904 }
905 #endif // wxUSE_STD_IOSTREAM
906
907 // ----------------------------------------------------------------------------
908 // wxLogChain
909 // ----------------------------------------------------------------------------
910
911 wxLogChain::wxLogChain(wxLog *logger)
912 {
913 m_bPassMessages = true;
914
915 m_logNew = logger;
916 m_logOld = wxLog::SetActiveTarget(this);
917 }
918
919 wxLogChain::~wxLogChain()
920 {
921 delete m_logOld;
922
923 if ( m_logNew != this )
924 delete m_logNew;
925 }
926
927 void wxLogChain::SetLog(wxLog *logger)
928 {
929 if ( m_logNew != this )
930 delete m_logNew;
931
932 m_logNew = logger;
933 }
934
935 void wxLogChain::Flush()
936 {
937 if ( m_logOld )
938 m_logOld->Flush();
939
940 // be careful to avoid infinite recursion
941 if ( m_logNew && m_logNew != this )
942 m_logNew->Flush();
943 }
944
945 void wxLogChain::DoLogRecord(wxLogLevel level,
946 const wxString& msg,
947 const wxLogRecordInfo& info)
948 {
949 // let the previous logger show it
950 if ( m_logOld && IsPassingMessages() )
951 m_logOld->LogRecord(level, msg, info);
952
953 // and also send it to the new one
954 if ( m_logNew && m_logNew != this )
955 m_logNew->LogRecord(level, msg, info);
956 }
957
958 #ifdef __VISUALC__
959 // "'this' : used in base member initializer list" - so what?
960 #pragma warning(disable:4355)
961 #endif // VC++
962
963 // ----------------------------------------------------------------------------
964 // wxLogInterposer
965 // ----------------------------------------------------------------------------
966
967 wxLogInterposer::wxLogInterposer()
968 : wxLogChain(this)
969 {
970 }
971
972 // ----------------------------------------------------------------------------
973 // wxLogInterposerTemp
974 // ----------------------------------------------------------------------------
975
976 wxLogInterposerTemp::wxLogInterposerTemp()
977 : wxLogChain(this)
978 {
979 DetachOldLog();
980 }
981
982 #ifdef __VISUALC__
983 #pragma warning(default:4355)
984 #endif // VC++
985
986 // ============================================================================
987 // Global functions/variables
988 // ============================================================================
989
990 // ----------------------------------------------------------------------------
991 // static variables
992 // ----------------------------------------------------------------------------
993
994 bool wxLog::ms_bRepetCounting = false;
995
996 wxLog *wxLog::ms_pLogger = NULL;
997 bool wxLog::ms_doLog = true;
998 bool wxLog::ms_bAutoCreate = true;
999 bool wxLog::ms_bVerbose = false;
1000
1001 wxLogLevel wxLog::ms_logLevel = wxLOG_Max; // log everything by default
1002
1003 size_t wxLog::ms_suspendCount = 0;
1004
1005 wxString wxLog::ms_timestamp(wxS("%X")); // time only, no date
1006
1007 #if WXWIN_COMPATIBILITY_2_8
1008 wxTraceMask wxLog::ms_ulTraceMask = (wxTraceMask)0;
1009 #endif // wxDEBUG_LEVEL
1010
1011 wxArrayString wxLog::ms_aTraceMasks;
1012
1013 // ----------------------------------------------------------------------------
1014 // stdout error logging helper
1015 // ----------------------------------------------------------------------------
1016
1017 // helper function: wraps the message and justifies it under given position
1018 // (looks more pretty on the terminal). Also adds newline at the end.
1019 //
1020 // TODO this is now disabled until I find a portable way of determining the
1021 // terminal window size (ok, I found it but does anybody really cares?)
1022 #ifdef LOG_PRETTY_WRAP
1023 static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz)
1024 {
1025 size_t nMax = 80; // FIXME
1026 size_t nStart = strlen(pszPrefix);
1027 fputs(pszPrefix, f);
1028
1029 size_t n;
1030 while ( *psz != '\0' ) {
1031 for ( n = nStart; (n < nMax) && (*psz != '\0'); n++ )
1032 putc(*psz++, f);
1033
1034 // wrapped?
1035 if ( *psz != '\0' ) {
1036 /*putc('\n', f);*/
1037 for ( n = 0; n < nStart; n++ )
1038 putc(' ', f);
1039
1040 // as we wrapped, squeeze all white space
1041 while ( isspace(*psz) )
1042 psz++;
1043 }
1044 }
1045
1046 putc('\n', f);
1047 }
1048 #endif //LOG_PRETTY_WRAP
1049
1050 // ----------------------------------------------------------------------------
1051 // error code/error message retrieval functions
1052 // ----------------------------------------------------------------------------
1053
1054 // get error code from syste
1055 unsigned long wxSysErrorCode()
1056 {
1057 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
1058 return ::GetLastError();
1059 #else //Unix
1060 return errno;
1061 #endif //Win/Unix
1062 }
1063
1064 // get error message from system
1065 const wxChar *wxSysErrorMsg(unsigned long nErrCode)
1066 {
1067 if ( nErrCode == 0 )
1068 nErrCode = wxSysErrorCode();
1069
1070 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
1071 static wxChar s_szBuf[1024];
1072
1073 // get error message from system
1074 LPVOID lpMsgBuf;
1075 if ( ::FormatMessage
1076 (
1077 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
1078 NULL,
1079 nErrCode,
1080 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1081 (LPTSTR)&lpMsgBuf,
1082 0,
1083 NULL
1084 ) == 0 )
1085 {
1086 // if this happens, something is seriously wrong, so don't use _() here
1087 // for safety
1088 wxSprintf(s_szBuf, wxS("unknown error %lx"), nErrCode);
1089 return s_szBuf;
1090 }
1091
1092
1093 // copy it to our buffer and free memory
1094 // Crashes on SmartPhone (FIXME)
1095 #if !defined(__SMARTPHONE__) /* of WinCE */
1096 if( lpMsgBuf != 0 )
1097 {
1098 wxStrlcpy(s_szBuf, (const wxChar *)lpMsgBuf, WXSIZEOF(s_szBuf));
1099
1100 LocalFree(lpMsgBuf);
1101
1102 // returned string is capitalized and ended with '\r\n' - bad
1103 s_szBuf[0] = (wxChar)wxTolower(s_szBuf[0]);
1104 size_t len = wxStrlen(s_szBuf);
1105 if ( len > 0 ) {
1106 // truncate string
1107 if ( s_szBuf[len - 2] == wxS('\r') )
1108 s_szBuf[len - 2] = wxS('\0');
1109 }
1110 }
1111 else
1112 #endif // !__SMARTPHONE__
1113 {
1114 s_szBuf[0] = wxS('\0');
1115 }
1116
1117 return s_szBuf;
1118 #else // !__WXMSW__
1119 #if wxUSE_UNICODE
1120 static wchar_t s_wzBuf[1024];
1121 wxConvCurrent->MB2WC(s_wzBuf, strerror((int)nErrCode),
1122 WXSIZEOF(s_wzBuf) - 1);
1123 return s_wzBuf;
1124 #else
1125 return strerror((int)nErrCode);
1126 #endif
1127 #endif // __WXMSW__/!__WXMSW__
1128 }
1129
1130 #endif // wxUSE_LOG