]> git.saurik.com Git - wxWidgets.git/blame - src/common/log.cpp
Added wxVector::swap().
[wxWidgets.git] / src / common / log.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
e4db172a 2// Name: src/common/log.cpp
c801d85f
KB
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>
65571936 9// Licence: wxWindows licence
c801d85f
KB
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
dd85fc6b 19
c801d85f
KB
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
e2478fde 24 #pragma hdrstop
c801d85f
KB
25#endif
26
e2478fde
VZ
27#if wxUSE_LOG
28
77ffb593 29// wxWidgets
c801d85f 30#ifndef WX_PRECOMP
e4db172a 31 #include "wx/log.h"
e90c1d2a 32 #include "wx/app.h"
df5168c4 33 #include "wx/arrstr.h"
e2478fde
VZ
34 #include "wx/intl.h"
35 #include "wx/string.h"
de6185e2 36 #include "wx/utils.h"
9ef3052c 37#endif //WX_PRECOMP
c801d85f 38
e2478fde 39#include "wx/apptrait.h"
7b2d1c74 40#include "wx/datetime.h"
e2478fde 41#include "wx/file.h"
e2478fde
VZ
42#include "wx/msgout.h"
43#include "wx/textfile.h"
44#include "wx/thread.h"
3a3dde0d 45#include "wx/crt.h"
f94dfb38 46
c801d85f 47// other standard headers
1c193821 48#ifndef __WXWINCE__
e2478fde 49#include <errno.h>
1c193821
JS
50#endif
51
e2478fde 52#include <stdlib.h>
1c193821 53
9b4da627 54#ifndef __WXPALMOS5__
1c193821 55#ifndef __WXWINCE__
e2478fde 56#include <time.h>
1c193821
JS
57#else
58#include "wx/msw/wince/time.h"
59#endif
9b4da627 60#endif /* ! __WXPALMOS5__ */
31907d03 61
9cce3be7
VS
62#if defined(__WINDOWS__)
63 #include "wx/msw/private.h" // includes windows.h
64#endif
65
c602c59b
VZ
66#undef wxLOG_COMPONENT
67const char *wxLOG_COMPONENT = "";
68
766aecab
VZ
69#if wxUSE_THREADS
70
71// define static functions providing access to the critical sections we use
72// instead of just using static critical section variables as log functions may
73// be used during static initialization and while this is certainly not
74// advisable it's still better to not crash (as we'd do if we used a yet
75// uninitialized critical section) if it happens
76
77static inline wxCriticalSection& GetTraceMaskCS()
78{
79 static wxCriticalSection s_csTrace;
80
81 return s_csTrace;
82}
83
84static inline wxCriticalSection& GetPreviousLogCS()
85{
86 static wxCriticalSection s_csPrev;
87
88 return s_csPrev;
89}
90
c602c59b
VZ
91static inline wxCriticalSection& GetLevelsCS()
92{
93 static wxCriticalSection s_csLevels;
94
95 return s_csLevels;
96}
97
766aecab
VZ
98#endif // wxUSE_THREADS
99
c801d85f
KB
100// ----------------------------------------------------------------------------
101// non member functions
102// ----------------------------------------------------------------------------
103
104// define this to enable wrapping of log messages
105//#define LOG_PRETTY_WRAP
106
9ef3052c 107#ifdef LOG_PRETTY_WRAP
c801d85f
KB
108 static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz);
109#endif
110
bc73d5ae
VZ
111// ----------------------------------------------------------------------------
112// module globals
113// ----------------------------------------------------------------------------
114
115namespace
116{
117
118// this struct is used to store information about the previous log message used
119// by OnLog() to (optionally) avoid logging multiple copies of the same message
120struct PreviousLogInfo
121{
122 PreviousLogInfo()
123 {
124 numRepeated = 0;
125 }
126
127
128 // previous message itself
129 wxString msg;
130
131 // its level
132 wxLogLevel level;
133
134 // other information about it
135 wxLogRecordInfo info;
136
137 // the number of times it was already repeated
138 unsigned numRepeated;
139};
140
141PreviousLogInfo gs_prevLog;
142
c602c59b
VZ
143
144// map containing all components for which log level was explicitly set
145//
146// NB: all accesses to it must be protected by GetLevelsCS() critical section
147wxStringToNumHashMap gs_componentLevels;
148
bc73d5ae
VZ
149} // anonymous namespace
150
c801d85f
KB
151// ============================================================================
152// implementation
153// ============================================================================
154
b568d04f 155// ----------------------------------------------------------------------------
af588446 156// helper global functions
b568d04f
VZ
157// ----------------------------------------------------------------------------
158
c11d62a6
VZ
159void wxSafeShowMessage(const wxString& title, const wxString& text)
160{
161#ifdef __WINDOWS__
dc874fb4 162 ::MessageBox(NULL, text.t_str(), title.t_str(), MB_OK | MB_ICONSTOP);
c11d62a6 163#else
a0516656 164 wxFprintf(stderr, wxS("%s: %s\n"), title.c_str(), text.c_str());
65f06384 165 fflush(stderr);
c11d62a6
VZ
166#endif
167}
168
c801d85f
KB
169// ----------------------------------------------------------------------------
170// wxLog class implementation
171// ----------------------------------------------------------------------------
172
dbaa16de 173unsigned wxLog::LogLastRepeatIfNeeded()
f9837791 174{
766aecab 175 wxCRIT_SECT_LOCKER(lock, GetPreviousLogCS());
a2d38265 176
dbaa16de
VZ
177 return LogLastRepeatIfNeededUnlocked();
178}
179
180unsigned wxLog::LogLastRepeatIfNeededUnlocked()
181{
bc73d5ae 182 const unsigned count = gs_prevLog.numRepeated;
0250efd6 183
bc73d5ae 184 if ( gs_prevLog.numRepeated )
f9837791
VZ
185 {
186 wxString msg;
459b97df 187#if wxUSE_INTL
f9837791
VZ
188 msg.Printf(wxPLURAL("The previous message repeated once.",
189 "The previous message repeated %lu times.",
bc73d5ae
VZ
190 gs_prevLog.numRepeated),
191 gs_prevLog.numRepeated);
459b97df 192#else
a0516656 193 msg.Printf(wxS("The previous message was repeated %lu times."),
bc73d5ae 194 gs_prevLog.numRepeated);
459b97df 195#endif
bc73d5ae
VZ
196 gs_prevLog.numRepeated = 0;
197 gs_prevLog.msg.clear();
198 DoLogRecord(gs_prevLog.level, msg, gs_prevLog.info);
f9837791 199 }
0250efd6
VZ
200
201 return count;
f9837791
VZ
202}
203
204wxLog::~wxLog()
205{
6f6b48f1
VZ
206 // Flush() must be called before destroying the object as otherwise some
207 // messages could be lost
bc73d5ae 208 if ( gs_prevLog.numRepeated )
6f6b48f1
VZ
209 {
210 wxMessageOutputDebug().Printf
211 (
212 wxS("Last repeated message (\"%s\", %lu times) wasn't output"),
bc73d5ae
VZ
213 gs_prevLog.msg,
214 gs_prevLog.numRepeated
6f6b48f1
VZ
215 );
216 }
f9837791
VZ
217}
218
bc73d5ae
VZ
219// ----------------------------------------------------------------------------
220// wxLog logging functions
221// ----------------------------------------------------------------------------
222
223/* static */
224void
225wxLog::OnLog(wxLogLevel level, const wxString& msg, time_t t)
226{
227 wxLogRecordInfo info;
228 info.timestamp = t;
229#if wxUSE_THREADS
230 info.threadId = wxThread::GetCurrentId();
231#endif // wxUSE_THREADS
232
233 OnLog(level, msg, info);
234}
235
f9837791 236/* static */
bc73d5ae
VZ
237void
238wxLog::OnLog(wxLogLevel level,
239 const wxString& msg,
240 const wxLogRecordInfo& info)
f9837791 241{
af588446
VZ
242 // fatal errors can't be suppressed nor handled by the custom log target
243 // and always terminate the program
244 if ( level == wxLOG_FatalError )
f9837791 245 {
af588446 246 wxSafeShowMessage(wxS("Fatal Error"), msg);
a2d38265 247
af588446
VZ
248#ifdef __WXWINCE__
249 ExitThread(3);
250#else
251 abort();
252#endif
253 }
2064113c 254
af588446
VZ
255 wxLog *pLogger = GetActiveTarget();
256 if ( !pLogger )
257 return;
2064113c 258
af588446
VZ
259 if ( GetRepetitionCounting() )
260 {
261 wxCRIT_SECT_LOCKER(lock, GetPreviousLogCS());
2064113c 262
af588446
VZ
263 if ( msg == gs_prevLog.msg )
264 {
265 gs_prevLog.numRepeated++;
2064113c 266
af588446
VZ
267 // nothing else to do, in particular, don't log the
268 // repeated message
269 return;
f9837791 270 }
af588446
VZ
271
272 pLogger->LogLastRepeatIfNeededUnlocked();
273
274 // reset repetition counter for a new message
275 gs_prevLog.msg = msg;
276 gs_prevLog.level = level;
277 gs_prevLog.info = info;
f9837791 278 }
af588446
VZ
279
280 // handle extra data which may be passed to us by wxLogXXX()
281 wxString prefix, suffix;
0758c46e 282 wxUIntPtr num = 0;
af588446
VZ
283 if ( info.GetNumValue(wxLOG_KEY_SYS_ERROR_CODE, &num) )
284 {
285 long err = static_cast<long>(num);
286 if ( !err )
287 err = wxSysErrorCode();
288
289 suffix.Printf(_(" (error %ld: %s)"), err, wxSysErrorMsg(err));
290 }
291
292#if wxUSE_LOG_TRACE
293 wxString str;
294 if ( level == wxLOG_Trace && info.GetStrValue(wxLOG_KEY_TRACE_MASK, &str) )
295 {
296 prefix = "(" + str + ") ";
297 }
298#endif // wxUSE_LOG_TRACE
299
300 pLogger->DoLogRecord(level, prefix + msg + suffix, info);
f9837791
VZ
301}
302
bc73d5ae
VZ
303void wxLog::DoLogRecord(wxLogLevel level,
304 const wxString& msg,
305 const wxLogRecordInfo& info)
04662def 306{
bc73d5ae
VZ
307#if WXWIN_COMPATIBILITY_2_8
308 // call the old DoLog() to ensure that existing custom log classes still
309 // work
310 //
311 // as the user code could have defined it as either taking "const char *"
312 // (in ANSI build) or "const wxChar *" (in ANSI/Unicode), we have no choice
313 // but to call both of them
314 DoLog(level, (const char*)msg.mb_str(), info.timestamp);
315 DoLog(level, (const wchar_t*)msg.wc_str(), info.timestamp);
316#endif // WXWIN_COMPATIBILITY_2_8
317
318
319 // TODO: it would be better to extract message formatting in a separate
320 // wxLogFormatter class but for now we hard code formatting here
321
322 wxString prefix;
323
324 // don't time stamp debug messages under MSW as debug viewers usually
325 // already have an option to do it
326#ifdef __WXMSW__
327 if ( level != wxLOG_Debug && level != wxLOG_Trace )
328#endif // __WXMSW__
329 TimeStamp(&prefix);
330
331 // TODO: use the other wxLogRecordInfo fields
332
333 switch ( level )
334 {
335 case wxLOG_Error:
336 prefix += _("Error: ");
337 break;
338
339 case wxLOG_Warning:
340 prefix += _("Warning: ");
341 break;
342
343 // don't prepend "debug/trace" prefix under MSW as it goes to the debug
344 // window anyhow and so can't be confused with something else
345#ifndef __WXMSW__
346 case wxLOG_Debug:
347 // this prefix (as well as the one below) is intentionally not
348 // translated as nobody translates debug messages anyhow
349 prefix += "Debug: ";
350 break;
351
352 case wxLOG_Trace:
353 prefix += "Trace: ";
354 break;
355#endif // !__WXMSW__
356 }
357
358 DoLogTextAtLevel(level, prefix + msg);
04662def
RL
359}
360
bc73d5ae
VZ
361void wxLog::DoLogTextAtLevel(wxLogLevel level, const wxString& msg)
362{
363 // we know about debug messages (because using wxMessageOutputDebug is the
364 // right thing to do in 99% of all cases and also for compatibility) but
365 // anything else needs to be handled in the derived class
366 if ( level == wxLOG_Debug || level == wxLOG_Trace )
367 {
368 wxMessageOutputDebug().Output(msg + wxS('\n'));
369 }
370 else
371 {
372 DoLogText(msg);
373 }
374}
dcc40ba5 375
bc73d5ae
VZ
376void wxLog::DoLogText(const wxString& WXUNUSED(msg))
377{
378 // in 2.8-compatible build the derived class might override DoLog() or
379 // DoLogString() instead so we can't have this assert there
380#if !WXWIN_COMPATIBILITY_2_8
381 wxFAIL_MSG( "must be overridden if it is called" );
382#endif // WXWIN_COMPATIBILITY_2_8
383}
5d88a6b5 384
fbbc4e8f
VZ
385#if WXWIN_COMPATIBILITY_2_8
386
bc73d5ae 387void wxLog::DoLog(wxLogLevel WXUNUSED(level), const char *szString, time_t t)
5d88a6b5 388{
bc73d5ae 389 DoLogString(szString, t);
5d88a6b5
VZ
390}
391
bc73d5ae 392void wxLog::DoLog(wxLogLevel WXUNUSED(level), const wchar_t *wzString, time_t t)
5d88a6b5 393{
bc73d5ae 394 DoLogString(wzString, t);
5d88a6b5
VZ
395}
396
fbbc4e8f
VZ
397#endif // WXWIN_COMPATIBILITY_2_8
398
bc73d5ae
VZ
399// ----------------------------------------------------------------------------
400// wxLog active target management
401// ----------------------------------------------------------------------------
5d88a6b5 402
9ec05cc9
VZ
403wxLog *wxLog::GetActiveTarget()
404{
0fb67cd1
VZ
405 if ( ms_bAutoCreate && ms_pLogger == NULL ) {
406 // prevent infinite recursion if someone calls wxLogXXX() from
407 // wxApp::CreateLogTarget()
f644b28c 408 static bool s_bInGetActiveTarget = false;
0fb67cd1 409 if ( !s_bInGetActiveTarget ) {
f644b28c 410 s_bInGetActiveTarget = true;
0fb67cd1 411
0fb67cd1
VZ
412 // ask the application to create a log target for us
413 if ( wxTheApp != NULL )
dc6d5e38 414 ms_pLogger = wxTheApp->GetTraits()->CreateLogTarget();
0fb67cd1
VZ
415 else
416 ms_pLogger = new wxLogStderr;
0fb67cd1 417
f644b28c 418 s_bInGetActiveTarget = false;
0fb67cd1
VZ
419
420 // do nothing if it fails - what can we do?
421 }
275bf4c1 422 }
c801d85f 423
0fb67cd1 424 return ms_pLogger;
c801d85f
KB
425}
426
c085e333 427wxLog *wxLog::SetActiveTarget(wxLog *pLogger)
9ec05cc9 428{
0fb67cd1
VZ
429 if ( ms_pLogger != NULL ) {
430 // flush the old messages before changing because otherwise they might
431 // get lost later if this target is not restored
432 ms_pLogger->Flush();
433 }
c801d85f 434
0fb67cd1
VZ
435 wxLog *pOldLogger = ms_pLogger;
436 ms_pLogger = pLogger;
c085e333 437
0fb67cd1 438 return pOldLogger;
c801d85f
KB
439}
440
36bd6902
VZ
441void wxLog::DontCreateOnDemand()
442{
f644b28c 443 ms_bAutoCreate = false;
36bd6902
VZ
444
445 // this is usually called at the end of the program and we assume that it
446 // is *always* called at the end - so we free memory here to avoid false
447 // memory leak reports from wxWin memory tracking code
448 ClearTraceMasks();
449}
450
e94cd97d
DE
451void wxLog::DoCreateOnDemand()
452{
453 ms_bAutoCreate = true;
454}
455
c602c59b
VZ
456// ----------------------------------------------------------------------------
457// wxLog components levels
458// ----------------------------------------------------------------------------
459
460/* static */
461void wxLog::SetComponentLevel(const wxString& component, wxLogLevel level)
462{
463 if ( component.empty() )
464 {
465 SetLogLevel(level);
466 }
467 else
468 {
469 wxCRIT_SECT_LOCKER(lock, GetLevelsCS());
470
471 gs_componentLevels[component] = level;
472 }
473}
474
475/* static */
476wxLogLevel wxLog::GetComponentLevel(wxString component)
477{
478 wxCRIT_SECT_LOCKER(lock, GetLevelsCS());
479
480 while ( !component.empty() )
481 {
482 wxStringToNumHashMap::const_iterator
483 it = gs_componentLevels.find(component);
484 if ( it != gs_componentLevels.end() )
485 return static_cast<wxLogLevel>(it->second);
486
487 component = component.BeforeLast('/');
488 }
489
490 return GetLogLevel();
491}
492
493// ----------------------------------------------------------------------------
494// wxLog trace masks
495// ----------------------------------------------------------------------------
496
f96233d5
VZ
497void wxLog::AddTraceMask(const wxString& str)
498{
766aecab 499 wxCRIT_SECT_LOCKER(lock, GetTraceMaskCS());
f96233d5
VZ
500
501 ms_aTraceMasks.push_back(str);
502}
503
0fb67cd1 504void wxLog::RemoveTraceMask(const wxString& str)
c801d85f 505{
766aecab 506 wxCRIT_SECT_LOCKER(lock, GetTraceMaskCS());
f96233d5 507
0fb67cd1
VZ
508 int index = ms_aTraceMasks.Index(str);
509 if ( index != wxNOT_FOUND )
dc6d5e38 510 ms_aTraceMasks.RemoveAt((size_t)index);
0fb67cd1 511}
c801d85f 512
36bd6902
VZ
513void wxLog::ClearTraceMasks()
514{
766aecab 515 wxCRIT_SECT_LOCKER(lock, GetTraceMaskCS());
f96233d5 516
36bd6902
VZ
517 ms_aTraceMasks.Clear();
518}
519
c602c59b
VZ
520/*static*/ bool wxLog::IsAllowedTraceMask(const wxString& mask)
521{
522 wxCRIT_SECT_LOCKER(lock, GetTraceMaskCS());
523
524 for ( wxArrayString::iterator it = ms_aTraceMasks.begin(),
525 en = ms_aTraceMasks.end();
526 it != en; ++it )
527 {
528 if ( *it == mask)
529 return true;
530 }
531
532 return false;
533}
534
535// ----------------------------------------------------------------------------
536// wxLog miscellaneous other methods
537// ----------------------------------------------------------------------------
538
d2e1ef19
VZ
539void wxLog::TimeStamp(wxString *str)
540{
7b2d1c74 541#if wxUSE_DATETIME
cb296f30 542 if ( !ms_timestamp.empty() )
d2e1ef19
VZ
543 {
544 wxChar buf[256];
545 time_t timeNow;
546 (void)time(&timeNow);
83e8b44c
VZ
547
548 struct tm tm;
549 wxStrftime(buf, WXSIZEOF(buf),
550 ms_timestamp, wxLocaltime_r(&timeNow, &tm));
d2e1ef19
VZ
551
552 str->Empty();
a0516656 553 *str << buf << wxS(": ");
d2e1ef19 554 }
7b2d1c74 555#endif // wxUSE_DATETIME
d2e1ef19
VZ
556}
557
c801d85f
KB
558void wxLog::Flush()
559{
6f6b48f1 560 LogLastRepeatIfNeeded();
c801d85f
KB
561}
562
d3fc1755
VZ
563// ----------------------------------------------------------------------------
564// wxLogBuffer implementation
565// ----------------------------------------------------------------------------
566
567void wxLogBuffer::Flush()
568{
a23bbe93
VZ
569 if ( !m_str.empty() )
570 {
571 wxMessageOutputBest out;
a0516656 572 out.Printf(wxS("%s"), m_str.c_str());
a23bbe93
VZ
573 m_str.clear();
574 }
d3fc1755
VZ
575}
576
bc73d5ae 577void wxLogBuffer::DoLogTextAtLevel(wxLogLevel level, const wxString& msg)
83250f1a 578{
711f12ef
VZ
579 // don't put debug messages in the buffer, we don't want to show
580 // them to the user in a msg box, log them immediately
bc73d5ae 581 switch ( level )
711f12ef 582 {
bc73d5ae
VZ
583 case wxLOG_Debug:
584 case wxLOG_Trace:
585 wxLog::DoLogTextAtLevel(level, msg);
586 break;
83250f1a 587
bc73d5ae
VZ
588 default:
589 m_str << msg << wxS("\n");
83250f1a
VZ
590 }
591}
592
c801d85f
KB
593// ----------------------------------------------------------------------------
594// wxLogStderr class implementation
595// ----------------------------------------------------------------------------
596
597wxLogStderr::wxLogStderr(FILE *fp)
598{
0fb67cd1
VZ
599 if ( fp == NULL )
600 m_fp = stderr;
601 else
602 m_fp = fp;
c801d85f
KB
603}
604
bc73d5ae 605void wxLogStderr::DoLogText(const wxString& msg)
c801d85f 606{
bc73d5ae 607 wxFputs(msg + '\n', m_fp);
0fb67cd1 608 fflush(m_fp);
1e8a4bc2 609
e2478fde
VZ
610 // under GUI systems such as Windows or Mac, programs usually don't have
611 // stderr at all, so show the messages also somewhere else, typically in
612 // the debugger window so that they go at least somewhere instead of being
613 // simply lost
1ec5cbf3
VZ
614 if ( m_fp == stderr )
615 {
e2478fde
VZ
616 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
617 if ( traits && !traits->HasStderr() )
618 {
bc73d5ae 619 wxMessageOutputDebug().Output(msg + wxS('\n'));
e2478fde 620 }
03147cd0 621 }
c801d85f
KB
622}
623
624// ----------------------------------------------------------------------------
625// wxLogStream implementation
626// ----------------------------------------------------------------------------
627
4bf78aae 628#if wxUSE_STD_IOSTREAM
65f19af1 629#include "wx/ioswrap.h"
dd107c50 630wxLogStream::wxLogStream(wxSTD ostream *ostr)
c801d85f 631{
0fb67cd1 632 if ( ostr == NULL )
dd107c50 633 m_ostr = &wxSTD cerr;
0fb67cd1
VZ
634 else
635 m_ostr = ostr;
c801d85f
KB
636}
637
bc73d5ae 638void wxLogStream::DoLogText(const wxString& msg)
c801d85f 639{
bc73d5ae 640 (*m_ostr) << msg << wxSTD endl;
c801d85f 641}
0fb67cd1 642#endif // wxUSE_STD_IOSTREAM
c801d85f 643
03147cd0
VZ
644// ----------------------------------------------------------------------------
645// wxLogChain
646// ----------------------------------------------------------------------------
647
648wxLogChain::wxLogChain(wxLog *logger)
649{
f644b28c 650 m_bPassMessages = true;
71debe95 651
03147cd0
VZ
652 m_logNew = logger;
653 m_logOld = wxLog::SetActiveTarget(this);
654}
655
199e91fb
VZ
656wxLogChain::~wxLogChain()
657{
e95f8fde
VZ
658 delete m_logOld;
659
660 if ( m_logNew != this )
661 delete m_logNew;
199e91fb
VZ
662}
663
03147cd0
VZ
664void wxLogChain::SetLog(wxLog *logger)
665{
666 if ( m_logNew != this )
667 delete m_logNew;
668
03147cd0
VZ
669 m_logNew = logger;
670}
671
672void wxLogChain::Flush()
673{
674 if ( m_logOld )
675 m_logOld->Flush();
676
1ec5cbf3 677 // be careful to avoid infinite recursion
03147cd0
VZ
678 if ( m_logNew && m_logNew != this )
679 m_logNew->Flush();
680}
681
bc73d5ae
VZ
682void wxLogChain::DoLogRecord(wxLogLevel level,
683 const wxString& msg,
684 const wxLogRecordInfo& info)
03147cd0
VZ
685{
686 // let the previous logger show it
687 if ( m_logOld && IsPassingMessages() )
bc73d5ae 688 m_logOld->LogRecord(level, msg, info);
03147cd0 689
efce878a 690 // and also send it to the new one
03147cd0 691 if ( m_logNew && m_logNew != this )
bc73d5ae 692 m_logNew->LogRecord(level, msg, info);
03147cd0
VZ
693}
694
93d4c1d0
VZ
695#ifdef __VISUALC__
696 // "'this' : used in base member initializer list" - so what?
697 #pragma warning(disable:4355)
698#endif // VC++
699
47fe7ff3
JS
700// ----------------------------------------------------------------------------
701// wxLogInterposer
702// ----------------------------------------------------------------------------
703
704wxLogInterposer::wxLogInterposer()
705 : wxLogChain(this)
706{
707}
708
709// ----------------------------------------------------------------------------
710// wxLogInterposerTemp
711// ----------------------------------------------------------------------------
712
713wxLogInterposerTemp::wxLogInterposerTemp()
93d4c1d0
VZ
714 : wxLogChain(this)
715{
766aecab 716 DetachOldLog();
93d4c1d0
VZ
717}
718
719#ifdef __VISUALC__
720 #pragma warning(default:4355)
721#endif // VC++
722
c801d85f
KB
723// ============================================================================
724// Global functions/variables
725// ============================================================================
726
727// ----------------------------------------------------------------------------
728// static variables
729// ----------------------------------------------------------------------------
0fb67cd1 730
f9837791 731bool wxLog::ms_bRepetCounting = false;
f9837791 732
d3b9f782 733wxLog *wxLog::ms_pLogger = NULL;
f644b28c
WS
734bool wxLog::ms_doLog = true;
735bool wxLog::ms_bAutoCreate = true;
736bool wxLog::ms_bVerbose = false;
d2e1ef19 737
edc73852
RD
738wxLogLevel wxLog::ms_logLevel = wxLOG_Max; // log everything by default
739
2ed3265e
VZ
740size_t wxLog::ms_suspendCount = 0;
741
a0516656 742wxString wxLog::ms_timestamp(wxS("%X")); // time only, no date
d2e1ef19 743
34085a0d 744#if WXWIN_COMPATIBILITY_2_8
0fb67cd1 745wxTraceMask wxLog::ms_ulTraceMask = (wxTraceMask)0;
34085a0d
VZ
746#endif // wxDEBUG_LEVEL
747
0fb67cd1 748wxArrayString wxLog::ms_aTraceMasks;
c801d85f
KB
749
750// ----------------------------------------------------------------------------
751// stdout error logging helper
752// ----------------------------------------------------------------------------
753
754// helper function: wraps the message and justifies it under given position
755// (looks more pretty on the terminal). Also adds newline at the end.
756//
0fb67cd1
VZ
757// TODO this is now disabled until I find a portable way of determining the
758// terminal window size (ok, I found it but does anybody really cares?)
759#ifdef LOG_PRETTY_WRAP
c801d85f
KB
760static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz)
761{
0fb67cd1
VZ
762 size_t nMax = 80; // FIXME
763 size_t nStart = strlen(pszPrefix);
764 fputs(pszPrefix, f);
765
766 size_t n;
767 while ( *psz != '\0' ) {
768 for ( n = nStart; (n < nMax) && (*psz != '\0'); n++ )
769 putc(*psz++, f);
770
771 // wrapped?
772 if ( *psz != '\0' ) {
773 /*putc('\n', f);*/
774 for ( n = 0; n < nStart; n++ )
775 putc(' ', f);
776
777 // as we wrapped, squeeze all white space
778 while ( isspace(*psz) )
779 psz++;
780 }
c801d85f 781 }
c801d85f 782
0fb67cd1 783 putc('\n', f);
c801d85f
KB
784}
785#endif //LOG_PRETTY_WRAP
786
787// ----------------------------------------------------------------------------
788// error code/error message retrieval functions
789// ----------------------------------------------------------------------------
790
791// get error code from syste
792unsigned long wxSysErrorCode()
793{
8cb172b4 794#if defined(__WXMSW__) && !defined(__WXMICROWIN__)
0fb67cd1 795 return ::GetLastError();
0fb67cd1 796#else //Unix
c801d85f 797 return errno;
0fb67cd1 798#endif //Win/Unix
c801d85f
KB
799}
800
801// get error message from system
50920146 802const wxChar *wxSysErrorMsg(unsigned long nErrCode)
c801d85f 803{
0fb67cd1
VZ
804 if ( nErrCode == 0 )
805 nErrCode = wxSysErrorCode();
806
8cb172b4 807#if defined(__WXMSW__) && !defined(__WXMICROWIN__)
2e7f3845 808 static wxChar s_szBuf[1024];
0fb67cd1
VZ
809
810 // get error message from system
811 LPVOID lpMsgBuf;
d0822e56
VZ
812 if ( ::FormatMessage
813 (
814 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
815 NULL,
816 nErrCode,
0fb67cd1
VZ
817 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
818 (LPTSTR)&lpMsgBuf,
d0822e56
VZ
819 0,
820 NULL
821 ) == 0 )
822 {
823 // if this happens, something is seriously wrong, so don't use _() here
824 // for safety
a0516656 825 wxSprintf(s_szBuf, wxS("unknown error %lx"), nErrCode);
c4b401b6 826 return s_szBuf;
d0822e56
VZ
827 }
828
0fb67cd1
VZ
829
830 // copy it to our buffer and free memory
d0822e56 831 // Crashes on SmartPhone (FIXME)
0c44ec97 832#if !defined(__SMARTPHONE__) /* of WinCE */
7448de8d
WS
833 if( lpMsgBuf != 0 )
834 {
e408bf52 835 wxStrlcpy(s_szBuf, (const wxChar *)lpMsgBuf, WXSIZEOF(s_szBuf));
251244a0
VZ
836
837 LocalFree(lpMsgBuf);
838
839 // returned string is capitalized and ended with '\r\n' - bad
840 s_szBuf[0] = (wxChar)wxTolower(s_szBuf[0]);
841 size_t len = wxStrlen(s_szBuf);
842 if ( len > 0 ) {
843 // truncate string
a0516656
VZ
844 if ( s_szBuf[len - 2] == wxS('\r') )
845 s_szBuf[len - 2] = wxS('\0');
251244a0
VZ
846 }
847 }
a9928e9d 848 else
2e7f3845 849#endif // !__SMARTPHONE__
a9928e9d 850 {
a0516656 851 s_szBuf[0] = wxS('\0');
0fb67cd1
VZ
852 }
853
854 return s_szBuf;
2e7f3845
VZ
855#else // !__WXMSW__
856 #if wxUSE_UNICODE
857 static wchar_t s_wzBuf[1024];
858 wxConvCurrent->MB2WC(s_wzBuf, strerror((int)nErrCode),
859 WXSIZEOF(s_wzBuf) - 1);
860 return s_wzBuf;
861 #else
862 return strerror((int)nErrCode);
863 #endif
864#endif // __WXMSW__/!__WXMSW__
c801d85f
KB
865}
866
e2478fde 867#endif // wxUSE_LOG