compilation fix for !WXWIN_COMPATIBILITY_2_8 build
[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 #if WXWIN_COMPATIBILITY_2_8
698
699 void wxLog::DoLog(wxLogLevel WXUNUSED(level), const char *szString, time_t t)
700 {
701 DoLogString(szString, t);
702 }
703
704 void wxLog::DoLog(wxLogLevel WXUNUSED(level), const wchar_t *wzString, time_t t)
705 {
706 DoLogString(wzString, t);
707 }
708
709 #endif // WXWIN_COMPATIBILITY_2_8
710
711 // ----------------------------------------------------------------------------
712 // wxLog active target management
713 // ----------------------------------------------------------------------------
714
715 wxLog *wxLog::GetActiveTarget()
716 {
717 if ( ms_bAutoCreate && ms_pLogger == NULL ) {
718 // prevent infinite recursion if someone calls wxLogXXX() from
719 // wxApp::CreateLogTarget()
720 static bool s_bInGetActiveTarget = false;
721 if ( !s_bInGetActiveTarget ) {
722 s_bInGetActiveTarget = true;
723
724 // ask the application to create a log target for us
725 if ( wxTheApp != NULL )
726 ms_pLogger = wxTheApp->GetTraits()->CreateLogTarget();
727 else
728 ms_pLogger = new wxLogStderr;
729
730 s_bInGetActiveTarget = false;
731
732 // do nothing if it fails - what can we do?
733 }
734 }
735
736 return ms_pLogger;
737 }
738
739 wxLog *wxLog::SetActiveTarget(wxLog *pLogger)
740 {
741 if ( ms_pLogger != NULL ) {
742 // flush the old messages before changing because otherwise they might
743 // get lost later if this target is not restored
744 ms_pLogger->Flush();
745 }
746
747 wxLog *pOldLogger = ms_pLogger;
748 ms_pLogger = pLogger;
749
750 return pOldLogger;
751 }
752
753 void wxLog::DontCreateOnDemand()
754 {
755 ms_bAutoCreate = false;
756
757 // this is usually called at the end of the program and we assume that it
758 // is *always* called at the end - so we free memory here to avoid false
759 // memory leak reports from wxWin memory tracking code
760 ClearTraceMasks();
761 }
762
763 void wxLog::DoCreateOnDemand()
764 {
765 ms_bAutoCreate = true;
766 }
767
768 void wxLog::AddTraceMask(const wxString& str)
769 {
770 wxCRIT_SECT_LOCKER(lock, GetTraceMaskCS());
771
772 ms_aTraceMasks.push_back(str);
773 }
774
775 void wxLog::RemoveTraceMask(const wxString& str)
776 {
777 wxCRIT_SECT_LOCKER(lock, GetTraceMaskCS());
778
779 int index = ms_aTraceMasks.Index(str);
780 if ( index != wxNOT_FOUND )
781 ms_aTraceMasks.RemoveAt((size_t)index);
782 }
783
784 void wxLog::ClearTraceMasks()
785 {
786 wxCRIT_SECT_LOCKER(lock, GetTraceMaskCS());
787
788 ms_aTraceMasks.Clear();
789 }
790
791 void wxLog::TimeStamp(wxString *str)
792 {
793 #if wxUSE_DATETIME
794 if ( !ms_timestamp.empty() )
795 {
796 wxChar buf[256];
797 time_t timeNow;
798 (void)time(&timeNow);
799
800 struct tm tm;
801 wxStrftime(buf, WXSIZEOF(buf),
802 ms_timestamp, wxLocaltime_r(&timeNow, &tm));
803
804 str->Empty();
805 *str << buf << wxS(": ");
806 }
807 #endif // wxUSE_DATETIME
808 }
809
810 void wxLog::Flush()
811 {
812 LogLastRepeatIfNeeded();
813 }
814
815 /*static*/ bool wxLog::IsAllowedTraceMask(const wxString& mask)
816 {
817 wxCRIT_SECT_LOCKER(lock, GetTraceMaskCS());
818
819 for ( wxArrayString::iterator it = ms_aTraceMasks.begin(),
820 en = ms_aTraceMasks.end();
821 it != en; ++it )
822 {
823 if ( *it == mask)
824 return true;
825 }
826
827 return false;
828 }
829
830 // ----------------------------------------------------------------------------
831 // wxLogBuffer implementation
832 // ----------------------------------------------------------------------------
833
834 void wxLogBuffer::Flush()
835 {
836 if ( !m_str.empty() )
837 {
838 wxMessageOutputBest out;
839 out.Printf(wxS("%s"), m_str.c_str());
840 m_str.clear();
841 }
842 }
843
844 void wxLogBuffer::DoLogTextAtLevel(wxLogLevel level, const wxString& msg)
845 {
846 // don't put debug messages in the buffer, we don't want to show
847 // them to the user in a msg box, log them immediately
848 switch ( level )
849 {
850 case wxLOG_Debug:
851 case wxLOG_Trace:
852 wxLog::DoLogTextAtLevel(level, msg);
853 break;
854
855 default:
856 m_str << msg << wxS("\n");
857 }
858 }
859
860 // ----------------------------------------------------------------------------
861 // wxLogStderr class implementation
862 // ----------------------------------------------------------------------------
863
864 wxLogStderr::wxLogStderr(FILE *fp)
865 {
866 if ( fp == NULL )
867 m_fp = stderr;
868 else
869 m_fp = fp;
870 }
871
872 void wxLogStderr::DoLogText(const wxString& msg)
873 {
874 wxFputs(msg + '\n', m_fp);
875 fflush(m_fp);
876
877 // under GUI systems such as Windows or Mac, programs usually don't have
878 // stderr at all, so show the messages also somewhere else, typically in
879 // the debugger window so that they go at least somewhere instead of being
880 // simply lost
881 if ( m_fp == stderr )
882 {
883 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
884 if ( traits && !traits->HasStderr() )
885 {
886 wxMessageOutputDebug().Output(msg + wxS('\n'));
887 }
888 }
889 }
890
891 // ----------------------------------------------------------------------------
892 // wxLogStream implementation
893 // ----------------------------------------------------------------------------
894
895 #if wxUSE_STD_IOSTREAM
896 #include "wx/ioswrap.h"
897 wxLogStream::wxLogStream(wxSTD ostream *ostr)
898 {
899 if ( ostr == NULL )
900 m_ostr = &wxSTD cerr;
901 else
902 m_ostr = ostr;
903 }
904
905 void wxLogStream::DoLogText(const wxString& msg)
906 {
907 (*m_ostr) << msg << wxSTD endl;
908 }
909 #endif // wxUSE_STD_IOSTREAM
910
911 // ----------------------------------------------------------------------------
912 // wxLogChain
913 // ----------------------------------------------------------------------------
914
915 wxLogChain::wxLogChain(wxLog *logger)
916 {
917 m_bPassMessages = true;
918
919 m_logNew = logger;
920 m_logOld = wxLog::SetActiveTarget(this);
921 }
922
923 wxLogChain::~wxLogChain()
924 {
925 delete m_logOld;
926
927 if ( m_logNew != this )
928 delete m_logNew;
929 }
930
931 void wxLogChain::SetLog(wxLog *logger)
932 {
933 if ( m_logNew != this )
934 delete m_logNew;
935
936 m_logNew = logger;
937 }
938
939 void wxLogChain::Flush()
940 {
941 if ( m_logOld )
942 m_logOld->Flush();
943
944 // be careful to avoid infinite recursion
945 if ( m_logNew && m_logNew != this )
946 m_logNew->Flush();
947 }
948
949 void wxLogChain::DoLogRecord(wxLogLevel level,
950 const wxString& msg,
951 const wxLogRecordInfo& info)
952 {
953 // let the previous logger show it
954 if ( m_logOld && IsPassingMessages() )
955 m_logOld->LogRecord(level, msg, info);
956
957 // and also send it to the new one
958 if ( m_logNew && m_logNew != this )
959 m_logNew->LogRecord(level, msg, info);
960 }
961
962 #ifdef __VISUALC__
963 // "'this' : used in base member initializer list" - so what?
964 #pragma warning(disable:4355)
965 #endif // VC++
966
967 // ----------------------------------------------------------------------------
968 // wxLogInterposer
969 // ----------------------------------------------------------------------------
970
971 wxLogInterposer::wxLogInterposer()
972 : wxLogChain(this)
973 {
974 }
975
976 // ----------------------------------------------------------------------------
977 // wxLogInterposerTemp
978 // ----------------------------------------------------------------------------
979
980 wxLogInterposerTemp::wxLogInterposerTemp()
981 : wxLogChain(this)
982 {
983 DetachOldLog();
984 }
985
986 #ifdef __VISUALC__
987 #pragma warning(default:4355)
988 #endif // VC++
989
990 // ============================================================================
991 // Global functions/variables
992 // ============================================================================
993
994 // ----------------------------------------------------------------------------
995 // static variables
996 // ----------------------------------------------------------------------------
997
998 bool wxLog::ms_bRepetCounting = false;
999
1000 wxLog *wxLog::ms_pLogger = NULL;
1001 bool wxLog::ms_doLog = true;
1002 bool wxLog::ms_bAutoCreate = true;
1003 bool wxLog::ms_bVerbose = false;
1004
1005 wxLogLevel wxLog::ms_logLevel = wxLOG_Max; // log everything by default
1006
1007 size_t wxLog::ms_suspendCount = 0;
1008
1009 wxString wxLog::ms_timestamp(wxS("%X")); // time only, no date
1010
1011 #if WXWIN_COMPATIBILITY_2_8
1012 wxTraceMask wxLog::ms_ulTraceMask = (wxTraceMask)0;
1013 #endif // wxDEBUG_LEVEL
1014
1015 wxArrayString wxLog::ms_aTraceMasks;
1016
1017 // ----------------------------------------------------------------------------
1018 // stdout error logging helper
1019 // ----------------------------------------------------------------------------
1020
1021 // helper function: wraps the message and justifies it under given position
1022 // (looks more pretty on the terminal). Also adds newline at the end.
1023 //
1024 // TODO this is now disabled until I find a portable way of determining the
1025 // terminal window size (ok, I found it but does anybody really cares?)
1026 #ifdef LOG_PRETTY_WRAP
1027 static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz)
1028 {
1029 size_t nMax = 80; // FIXME
1030 size_t nStart = strlen(pszPrefix);
1031 fputs(pszPrefix, f);
1032
1033 size_t n;
1034 while ( *psz != '\0' ) {
1035 for ( n = nStart; (n < nMax) && (*psz != '\0'); n++ )
1036 putc(*psz++, f);
1037
1038 // wrapped?
1039 if ( *psz != '\0' ) {
1040 /*putc('\n', f);*/
1041 for ( n = 0; n < nStart; n++ )
1042 putc(' ', f);
1043
1044 // as we wrapped, squeeze all white space
1045 while ( isspace(*psz) )
1046 psz++;
1047 }
1048 }
1049
1050 putc('\n', f);
1051 }
1052 #endif //LOG_PRETTY_WRAP
1053
1054 // ----------------------------------------------------------------------------
1055 // error code/error message retrieval functions
1056 // ----------------------------------------------------------------------------
1057
1058 // get error code from syste
1059 unsigned long wxSysErrorCode()
1060 {
1061 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
1062 return ::GetLastError();
1063 #else //Unix
1064 return errno;
1065 #endif //Win/Unix
1066 }
1067
1068 // get error message from system
1069 const wxChar *wxSysErrorMsg(unsigned long nErrCode)
1070 {
1071 if ( nErrCode == 0 )
1072 nErrCode = wxSysErrorCode();
1073
1074 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
1075 static wxChar s_szBuf[1024];
1076
1077 // get error message from system
1078 LPVOID lpMsgBuf;
1079 if ( ::FormatMessage
1080 (
1081 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
1082 NULL,
1083 nErrCode,
1084 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1085 (LPTSTR)&lpMsgBuf,
1086 0,
1087 NULL
1088 ) == 0 )
1089 {
1090 // if this happens, something is seriously wrong, so don't use _() here
1091 // for safety
1092 wxSprintf(s_szBuf, wxS("unknown error %lx"), nErrCode);
1093 return s_szBuf;
1094 }
1095
1096
1097 // copy it to our buffer and free memory
1098 // Crashes on SmartPhone (FIXME)
1099 #if !defined(__SMARTPHONE__) /* of WinCE */
1100 if( lpMsgBuf != 0 )
1101 {
1102 wxStrlcpy(s_szBuf, (const wxChar *)lpMsgBuf, WXSIZEOF(s_szBuf));
1103
1104 LocalFree(lpMsgBuf);
1105
1106 // returned string is capitalized and ended with '\r\n' - bad
1107 s_szBuf[0] = (wxChar)wxTolower(s_szBuf[0]);
1108 size_t len = wxStrlen(s_szBuf);
1109 if ( len > 0 ) {
1110 // truncate string
1111 if ( s_szBuf[len - 2] == wxS('\r') )
1112 s_szBuf[len - 2] = wxS('\0');
1113 }
1114 }
1115 else
1116 #endif // !__SMARTPHONE__
1117 {
1118 s_szBuf[0] = wxS('\0');
1119 }
1120
1121 return s_szBuf;
1122 #else // !__WXMSW__
1123 #if wxUSE_UNICODE
1124 static wchar_t s_wzBuf[1024];
1125 wxConvCurrent->MB2WC(s_wzBuf, strerror((int)nErrCode),
1126 WXSIZEOF(s_wzBuf) - 1);
1127 return s_wzBuf;
1128 #else
1129 return strerror((int)nErrCode);
1130 #endif
1131 #endif // __WXMSW__/!__WXMSW__
1132 }
1133
1134 #endif // wxUSE_LOG