]> git.saurik.com Git - wxWidgets.git/blame - src/common/log.cpp
fix the broken code in strftime()
[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
VZ
39#include "wx/apptrait.h"
40#include "wx/file.h"
e2478fde
VZ
41#include "wx/msgout.h"
42#include "wx/textfile.h"
43#include "wx/thread.h"
e2478fde 44#include "wx/wxchar.h"
f94dfb38 45
c801d85f 46// other standard headers
1c193821 47#ifndef __WXWINCE__
e2478fde 48#include <errno.h>
1c193821
JS
49#endif
50
e2478fde 51#include <stdlib.h>
1c193821
JS
52
53#ifndef __WXWINCE__
e2478fde 54#include <time.h>
1c193821
JS
55#else
56#include "wx/msw/wince/time.h"
57#endif
31907d03 58
9cce3be7
VS
59#if defined(__WINDOWS__)
60 #include "wx/msw/private.h" // includes windows.h
61#endif
62
c801d85f
KB
63// ----------------------------------------------------------------------------
64// non member functions
65// ----------------------------------------------------------------------------
66
67// define this to enable wrapping of log messages
68//#define LOG_PRETTY_WRAP
69
9ef3052c 70#ifdef LOG_PRETTY_WRAP
c801d85f
KB
71 static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz);
72#endif
73
74// ============================================================================
75// implementation
76// ============================================================================
77
b568d04f
VZ
78// ----------------------------------------------------------------------------
79// implementation of Log functions
80//
81// NB: unfortunately we need all these distinct functions, we can't make them
82// macros and not all compilers inline vararg functions.
83// ----------------------------------------------------------------------------
84
c801d85f 85// generic log function
1d63fd6b 86void wxVLogGeneric(wxLogLevel level, const wxChar *szFormat, va_list argptr)
c801d85f 87{
d68d8590 88 if ( wxLog::IsEnabled() ) {
2e7f3845 89 wxLog::OnLog(level, wxString::FormatV(szFormat, argptr), time(NULL));
807a903e 90 }
c801d85f
KB
91}
92
ea44a631
GD
93void wxLogGeneric(wxLogLevel level, const wxChar *szFormat, ...)
94{
95 va_list argptr;
96 va_start(argptr, szFormat);
1d63fd6b 97 wxVLogGeneric(level, szFormat, argptr);
ea44a631
GD
98 va_end(argptr);
99}
100
807a903e 101#define IMPLEMENT_LOG_FUNCTION(level) \
1d63fd6b 102 void wxVLog##level(const wxChar *szFormat, va_list argptr) \
807a903e 103 { \
d68d8590 104 if ( wxLog::IsEnabled() ) { \
2e7f3845
VZ
105 wxLog::OnLog(wxLOG_##level, \
106 wxString::FormatV(szFormat, argptr), time(NULL));\
807a903e 107 } \
ea44a631 108 } \
ef0dd8e5 109 \
ea44a631
GD
110 void wxLog##level(const wxChar *szFormat, ...) \
111 { \
112 va_list argptr; \
113 va_start(argptr, szFormat); \
1800689f 114 wxVLog##level(szFormat, argptr); \
ea44a631 115 va_end(argptr); \
c801d85f
KB
116 }
117
c801d85f
KB
118IMPLEMENT_LOG_FUNCTION(Error)
119IMPLEMENT_LOG_FUNCTION(Warning)
120IMPLEMENT_LOG_FUNCTION(Message)
121IMPLEMENT_LOG_FUNCTION(Info)
122IMPLEMENT_LOG_FUNCTION(Status)
123
c11d62a6
VZ
124void wxSafeShowMessage(const wxString& title, const wxString& text)
125{
126#ifdef __WINDOWS__
127 ::MessageBox(NULL, text, title, MB_OK | MB_ICONSTOP);
128#else
129 wxFprintf(stderr, _T("%s: %s\n"), title.c_str(), text.c_str());
65f06384 130 fflush(stderr);
c11d62a6
VZ
131#endif
132}
133
1800689f
VZ
134// fatal errors can't be suppressed nor handled by the custom log target and
135// always terminate the program
136void wxVLogFatalError(const wxChar *szFormat, va_list argptr)
137{
2e7f3845 138 wxSafeShowMessage(_T("Fatal Error"), wxString::FormatV(szFormat, argptr));
1800689f 139
1c193821
JS
140#ifdef __WXWINCE__
141 ExitThread(3);
142#else
1800689f 143 abort();
1c193821 144#endif
1800689f
VZ
145}
146
147void wxLogFatalError(const wxChar *szFormat, ...)
148{
149 va_list argptr;
150 va_start(argptr, szFormat);
151 wxVLogFatalError(szFormat, argptr);
5e475383
VZ
152
153 // some compilers warn about unreachable code and it shouldn't matter
154 // for the others anyhow...
155 //va_end(argptr);
1800689f
VZ
156}
157
9ef3052c 158// same as info, but only if 'verbose' mode is on
1d63fd6b 159void wxVLogVerbose(const wxChar *szFormat, va_list argptr)
9ef3052c 160{
d68d8590 161 if ( wxLog::IsEnabled() ) {
2a1f999f 162 if ( wxLog::GetActiveTarget() != NULL && wxLog::GetVerbose() ) {
2e7f3845
VZ
163 wxLog::OnLog(wxLOG_Info,
164 wxString::FormatV(szFormat, argptr), time(NULL));
807a903e
VZ
165 }
166 }
9ef3052c
VZ
167}
168
ea44a631
GD
169void wxLogVerbose(const wxChar *szFormat, ...)
170{
171 va_list argptr;
172 va_start(argptr, szFormat);
1d63fd6b 173 wxVLogVerbose(szFormat, argptr);
ea44a631
GD
174 va_end(argptr);
175}
176
9ef3052c 177// debug functions
b2aef89b 178#ifdef __WXDEBUG__
807a903e 179#define IMPLEMENT_LOG_DEBUG_FUNCTION(level) \
1d63fd6b 180 void wxVLog##level(const wxChar *szFormat, va_list argptr) \
807a903e 181 { \
d68d8590 182 if ( wxLog::IsEnabled() ) { \
2e7f3845
VZ
183 wxLog::OnLog(wxLOG_##level, \
184 wxString::FormatV(szFormat, argptr), time(NULL));\
807a903e 185 } \
ea44a631 186 } \
2e7f3845 187 \
ea44a631
GD
188 void wxLog##level(const wxChar *szFormat, ...) \
189 { \
190 va_list argptr; \
191 va_start(argptr, szFormat); \
1d63fd6b 192 wxVLog##level(szFormat, argptr); \
ea44a631 193 va_end(argptr); \
c801d85f
KB
194 }
195
1d63fd6b 196 void wxVLogTrace(const wxChar *mask, const wxChar *szFormat, va_list argptr)
0fb67cd1 197 {
d68d8590 198 if ( wxLog::IsEnabled() && wxLog::IsAllowedTraceMask(mask) ) {
2e7f3845
VZ
199 wxString msg;
200 msg << _T("(") << mask << _T(") ") << wxString::FormatV(szFormat, argptr);
201
202 wxLog::OnLog(wxLOG_Trace, msg, time(NULL));
0fb67cd1
VZ
203 }
204 }
205
ea44a631
GD
206 void wxLogTrace(const wxChar *mask, const wxChar *szFormat, ...)
207 {
208 va_list argptr;
209 va_start(argptr, szFormat);
1d63fd6b 210 wxVLogTrace(mask, szFormat, argptr);
ea44a631
GD
211 va_end(argptr);
212 }
213
1d63fd6b 214 void wxVLogTrace(wxTraceMask mask, const wxChar *szFormat, va_list argptr)
9ef3052c 215 {
9ef3052c
VZ
216 // we check that all of mask bits are set in the current mask, so
217 // that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something
218 // if both bits are set.
d68d8590 219 if ( wxLog::IsEnabled() && ((wxLog::GetTraceMask() & mask) == mask) ) {
2e7f3845 220 wxLog::OnLog(wxLOG_Trace, wxString::FormatV(szFormat, argptr), time(NULL));
9ef3052c
VZ
221 }
222 }
223
ea44a631
GD
224 void wxLogTrace(wxTraceMask mask, const wxChar *szFormat, ...)
225 {
226 va_list argptr;
227 va_start(argptr, szFormat);
1d63fd6b 228 wxVLogTrace(mask, szFormat, argptr);
ea44a631
GD
229 va_end(argptr);
230 }
231
9ef3052c
VZ
232#else // release
233 #define IMPLEMENT_LOG_DEBUG_FUNCTION(level)
234#endif
235
236IMPLEMENT_LOG_DEBUG_FUNCTION(Debug)
237IMPLEMENT_LOG_DEBUG_FUNCTION(Trace)
238
239// wxLogSysError: one uses the last error code, for other you must give it
240// explicitly
241
2e7f3845
VZ
242// return the system error message description
243static inline wxString wxLogSysErrorHelper(long err)
c801d85f 244{
2e7f3845 245 return wxString::Format(_(" (error %ld: %s)"), err, wxSysErrorMsg(err));
9ef3052c 246}
c801d85f 247
1d63fd6b 248void WXDLLEXPORT wxVLogSysError(const wxChar *szFormat, va_list argptr)
9ef3052c 249{
2e7f3845 250 wxVLogSysError(wxSysErrorCode(), szFormat, argptr);
c801d85f
KB
251}
252
ea44a631
GD
253void WXDLLEXPORT wxLogSysError(const wxChar *szFormat, ...)
254{
255 va_list argptr;
256 va_start(argptr, szFormat);
1d63fd6b 257 wxVLogSysError(szFormat, argptr);
ea44a631
GD
258 va_end(argptr);
259}
260
2e7f3845 261void WXDLLEXPORT wxVLogSysError(long err, const wxChar *fmt, va_list argptr)
c801d85f 262{
d68d8590 263 if ( wxLog::IsEnabled() ) {
2e7f3845
VZ
264 wxLog::OnLog(wxLOG_Error,
265 wxString::FormatV(fmt, argptr) + wxLogSysErrorHelper(err),
266 time(NULL));
807a903e 267 }
c801d85f
KB
268}
269
ea44a631
GD
270void WXDLLEXPORT wxLogSysError(long lErrCode, const wxChar *szFormat, ...)
271{
272 va_list argptr;
273 va_start(argptr, szFormat);
1d63fd6b 274 wxVLogSysError(lErrCode, szFormat, argptr);
ea44a631
GD
275 va_end(argptr);
276}
277
c801d85f
KB
278// ----------------------------------------------------------------------------
279// wxLog class implementation
280// ----------------------------------------------------------------------------
281
f9837791
VZ
282/* static */
283unsigned wxLog::DoLogNumberOfRepeats()
284{
285 long retval = ms_prevCounter;
286 wxLog *pLogger = GetActiveTarget();
287 if ( pLogger && ms_prevCounter > 0 )
288 {
289 wxString msg;
459b97df 290#if wxUSE_INTL
f9837791
VZ
291 msg.Printf(wxPLURAL("The previous message repeated once.",
292 "The previous message repeated %lu times.",
293 ms_prevCounter),
294 ms_prevCounter);
459b97df
WS
295#else
296 msg.Printf(wxT("The previous message was repeated."));
297#endif
f9837791
VZ
298 ms_prevCounter = 0;
299 ms_prevString.clear();
300 pLogger->DoLog(ms_prevLevel, msg.c_str(), ms_prevTimeStamp);
301 }
302 return retval;
303}
304
305wxLog::~wxLog()
306{
307 if ( ms_prevCounter > 0 )
308 {
309 // looks like the repeat count has not been logged yet,
310 // so let's do it now
311 wxLog::DoLogNumberOfRepeats();
312 }
313}
314
315/* static */
316void wxLog::OnLog(wxLogLevel level, const wxChar *szString, time_t t)
317{
318 if ( IsEnabled() && ms_logLevel >= level )
319 {
320 wxLog *pLogger = GetActiveTarget();
321 if ( pLogger )
322 {
323 if ( GetRepetitionCounting() && ms_prevString == szString )
324 {
325 ms_prevCounter++;
326 }
327 else
328 {
329 if ( GetRepetitionCounting() )
330 {
331 pLogger->DoLogNumberOfRepeats();
332 }
333 ms_prevString = szString;
334 ms_prevLevel = level;
335 ms_prevTimeStamp = t;
336 pLogger->DoLog(level, szString, t);
337 }
338 }
339 }
340}
341
2e7f3845 342// deprecated function
dcc40ba5
VZ
343#if WXWIN_COMPATIBILITY_2_6
344
2e7f3845 345wxChar *wxLog::SetLogBuffer(wxChar * WXUNUSED(buf), size_t WXUNUSED(size))
04662def 346{
2e7f3845 347 return NULL;
04662def
RL
348}
349
dcc40ba5
VZ
350#endif // WXWIN_COMPATIBILITY_2_6
351
9ec05cc9
VZ
352wxLog *wxLog::GetActiveTarget()
353{
0fb67cd1
VZ
354 if ( ms_bAutoCreate && ms_pLogger == NULL ) {
355 // prevent infinite recursion if someone calls wxLogXXX() from
356 // wxApp::CreateLogTarget()
f644b28c 357 static bool s_bInGetActiveTarget = false;
0fb67cd1 358 if ( !s_bInGetActiveTarget ) {
f644b28c 359 s_bInGetActiveTarget = true;
0fb67cd1 360
0fb67cd1
VZ
361 // ask the application to create a log target for us
362 if ( wxTheApp != NULL )
dc6d5e38 363 ms_pLogger = wxTheApp->GetTraits()->CreateLogTarget();
0fb67cd1
VZ
364 else
365 ms_pLogger = new wxLogStderr;
0fb67cd1 366
f644b28c 367 s_bInGetActiveTarget = false;
0fb67cd1
VZ
368
369 // do nothing if it fails - what can we do?
370 }
275bf4c1 371 }
c801d85f 372
0fb67cd1 373 return ms_pLogger;
c801d85f
KB
374}
375
c085e333 376wxLog *wxLog::SetActiveTarget(wxLog *pLogger)
9ec05cc9 377{
0fb67cd1
VZ
378 if ( ms_pLogger != NULL ) {
379 // flush the old messages before changing because otherwise they might
380 // get lost later if this target is not restored
381 ms_pLogger->Flush();
382 }
c801d85f 383
0fb67cd1
VZ
384 wxLog *pOldLogger = ms_pLogger;
385 ms_pLogger = pLogger;
c085e333 386
0fb67cd1 387 return pOldLogger;
c801d85f
KB
388}
389
36bd6902
VZ
390void wxLog::DontCreateOnDemand()
391{
f644b28c 392 ms_bAutoCreate = false;
36bd6902
VZ
393
394 // this is usually called at the end of the program and we assume that it
395 // is *always* called at the end - so we free memory here to avoid false
396 // memory leak reports from wxWin memory tracking code
397 ClearTraceMasks();
398}
399
0fb67cd1 400void wxLog::RemoveTraceMask(const wxString& str)
c801d85f 401{
0fb67cd1
VZ
402 int index = ms_aTraceMasks.Index(str);
403 if ( index != wxNOT_FOUND )
dc6d5e38 404 ms_aTraceMasks.RemoveAt((size_t)index);
0fb67cd1 405}
c801d85f 406
36bd6902
VZ
407void wxLog::ClearTraceMasks()
408{
409 ms_aTraceMasks.Clear();
410}
411
d2e1ef19
VZ
412void wxLog::TimeStamp(wxString *str)
413{
414 if ( ms_timestamp )
415 {
416 wxChar buf[256];
417 time_t timeNow;
418 (void)time(&timeNow);
c49245f8 419 wxStrftime(buf, WXSIZEOF(buf), ms_timestamp, localtime(&timeNow));
d2e1ef19
VZ
420
421 str->Empty();
223d09f6 422 *str << buf << wxT(": ");
d2e1ef19
VZ
423 }
424}
425
50920146 426void wxLog::DoLog(wxLogLevel level, const wxChar *szString, time_t t)
0fb67cd1 427{
0fb67cd1
VZ
428 switch ( level ) {
429 case wxLOG_FatalError:
786855a1 430 DoLogString(wxString(_("Fatal error: ")) + szString, t);
0fb67cd1
VZ
431 DoLogString(_("Program aborted."), t);
432 Flush();
1c193821
JS
433#ifdef __WXWINCE__
434 ExitThread(3);
435#else
0fb67cd1 436 abort();
1c193821 437#endif
0fb67cd1
VZ
438 break;
439
440 case wxLOG_Error:
786855a1 441 DoLogString(wxString(_("Error: ")) + szString, t);
0fb67cd1
VZ
442 break;
443
444 case wxLOG_Warning:
786855a1 445 DoLogString(wxString(_("Warning: ")) + szString, t);
0fb67cd1
VZ
446 break;
447
448 case wxLOG_Info:
0fb67cd1 449 if ( GetVerbose() )
37278984 450 case wxLOG_Message:
87a1e308 451 case wxLOG_Status:
786855a1
VZ
452 default: // log unknown log levels too
453 DoLogString(szString, t);
0fb67cd1
VZ
454 break;
455
456 case wxLOG_Trace:
457 case wxLOG_Debug:
458#ifdef __WXDEBUG__
0131687b
VZ
459 {
460 wxString msg = level == wxLOG_Trace ? wxT("Trace: ")
54a8f42b 461 : wxT("Debug: ");
0131687b
VZ
462 msg << szString;
463 DoLogString(msg, t);
464 }
465#endif // Debug
0fb67cd1 466 break;
0fb67cd1 467 }
c801d85f
KB
468}
469
74e3313b 470void wxLog::DoLogString(const wxChar *WXUNUSED(szString), time_t WXUNUSED(t))
c801d85f 471{
223d09f6 472 wxFAIL_MSG(wxT("DoLogString must be overriden if it's called."));
c801d85f
KB
473}
474
475void wxLog::Flush()
476{
1ec5cbf3 477 // nothing to do here
c801d85f
KB
478}
479
df5168c4
MB
480/*static*/ bool wxLog::IsAllowedTraceMask(const wxChar *mask)
481{
482 for ( wxArrayString::iterator it = ms_aTraceMasks.begin(),
483 en = ms_aTraceMasks.end();
484 it != en; ++it )
485 if ( *it == mask)
486 return true;
487 return false;
488}
489
d3fc1755
VZ
490// ----------------------------------------------------------------------------
491// wxLogBuffer implementation
492// ----------------------------------------------------------------------------
493
494void wxLogBuffer::Flush()
495{
a23bbe93
VZ
496 if ( !m_str.empty() )
497 {
498 wxMessageOutputBest out;
499 out.Printf(_T("%s"), m_str.c_str());
500 m_str.clear();
501 }
d3fc1755
VZ
502}
503
83250f1a
VZ
504void wxLogBuffer::DoLog(wxLogLevel level, const wxChar *szString, time_t t)
505{
506 switch ( level )
507 {
508 case wxLOG_Trace:
509 case wxLOG_Debug:
510#ifdef __WXDEBUG__
511 // don't put debug messages in the buffer, we don't want to show
512 // them to the user in a msg box, log them immediately
513 {
514 wxString str;
515 TimeStamp(&str);
516 str += szString;
517
c4b401b6
WS
518 wxMessageOutputDebug dbgout;
519 dbgout.Printf(_T("%s\n"), str.c_str());
83250f1a
VZ
520 }
521#endif // __WXDEBUG__
522 break;
523
524 default:
525 wxLog::DoLog(level, szString, t);
526 }
527}
528
d3fc1755
VZ
529void wxLogBuffer::DoLogString(const wxChar *szString, time_t WXUNUSED(t))
530{
531 m_str << szString << _T("\n");
532}
533
c801d85f
KB
534// ----------------------------------------------------------------------------
535// wxLogStderr class implementation
536// ----------------------------------------------------------------------------
537
538wxLogStderr::wxLogStderr(FILE *fp)
539{
0fb67cd1
VZ
540 if ( fp == NULL )
541 m_fp = stderr;
542 else
543 m_fp = fp;
c801d85f
KB
544}
545
74e3313b 546void wxLogStderr::DoLogString(const wxChar *szString, time_t WXUNUSED(t))
c801d85f 547{
d2e1ef19
VZ
548 wxString str;
549 TimeStamp(&str);
b568d04f 550 str << szString;
1e8a4bc2 551
50920146 552 fputs(str.mb_str(), m_fp);
b568d04f 553 fputc(_T('\n'), m_fp);
0fb67cd1 554 fflush(m_fp);
1e8a4bc2 555
e2478fde
VZ
556 // under GUI systems such as Windows or Mac, programs usually don't have
557 // stderr at all, so show the messages also somewhere else, typically in
558 // the debugger window so that they go at least somewhere instead of being
559 // simply lost
1ec5cbf3
VZ
560 if ( m_fp == stderr )
561 {
e2478fde
VZ
562 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
563 if ( traits && !traits->HasStderr() )
564 {
254a2129 565 wxMessageOutputDebug dbgout;
30413fd0 566 dbgout.Printf(_T("%s\n"), str.c_str());
e2478fde 567 }
03147cd0 568 }
c801d85f
KB
569}
570
571// ----------------------------------------------------------------------------
572// wxLogStream implementation
573// ----------------------------------------------------------------------------
574
4bf78aae 575#if wxUSE_STD_IOSTREAM
65f19af1 576#include "wx/ioswrap.h"
dd107c50 577wxLogStream::wxLogStream(wxSTD ostream *ostr)
c801d85f 578{
0fb67cd1 579 if ( ostr == NULL )
dd107c50 580 m_ostr = &wxSTD cerr;
0fb67cd1
VZ
581 else
582 m_ostr = ostr;
c801d85f
KB
583}
584
74e3313b 585void wxLogStream::DoLogString(const wxChar *szString, time_t WXUNUSED(t))
c801d85f 586{
29fd317b
VZ
587 wxString str;
588 TimeStamp(&str);
416f9764 589 (*m_ostr) << wxConvertWX2MB(str) << wxConvertWX2MB(szString) << wxSTD endl;
c801d85f 590}
0fb67cd1 591#endif // wxUSE_STD_IOSTREAM
c801d85f 592
03147cd0
VZ
593// ----------------------------------------------------------------------------
594// wxLogChain
595// ----------------------------------------------------------------------------
596
597wxLogChain::wxLogChain(wxLog *logger)
598{
f644b28c 599 m_bPassMessages = true;
71debe95 600
03147cd0
VZ
601 m_logNew = logger;
602 m_logOld = wxLog::SetActiveTarget(this);
603}
604
199e91fb
VZ
605wxLogChain::~wxLogChain()
606{
e95f8fde
VZ
607 delete m_logOld;
608
609 if ( m_logNew != this )
610 delete m_logNew;
199e91fb
VZ
611}
612
03147cd0
VZ
613void wxLogChain::SetLog(wxLog *logger)
614{
615 if ( m_logNew != this )
616 delete m_logNew;
617
03147cd0
VZ
618 m_logNew = logger;
619}
620
621void wxLogChain::Flush()
622{
623 if ( m_logOld )
624 m_logOld->Flush();
625
1ec5cbf3 626 // be careful to avoid infinite recursion
03147cd0
VZ
627 if ( m_logNew && m_logNew != this )
628 m_logNew->Flush();
629}
630
631void wxLogChain::DoLog(wxLogLevel level, const wxChar *szString, time_t t)
632{
633 // let the previous logger show it
634 if ( m_logOld && IsPassingMessages() )
635 {
636 // bogus cast just to access protected DoLog
637 ((wxLogChain *)m_logOld)->DoLog(level, szString, t);
638 }
639
640 if ( m_logNew && m_logNew != this )
641 {
642 // as above...
643 ((wxLogChain *)m_logNew)->DoLog(level, szString, t);
644 }
645}
646
93d4c1d0
VZ
647// ----------------------------------------------------------------------------
648// wxLogPassThrough
649// ----------------------------------------------------------------------------
650
651#ifdef __VISUALC__
652 // "'this' : used in base member initializer list" - so what?
653 #pragma warning(disable:4355)
654#endif // VC++
655
656wxLogPassThrough::wxLogPassThrough()
657 : wxLogChain(this)
658{
659}
660
661#ifdef __VISUALC__
662 #pragma warning(default:4355)
663#endif // VC++
664
c801d85f
KB
665// ============================================================================
666// Global functions/variables
667// ============================================================================
668
669// ----------------------------------------------------------------------------
670// static variables
671// ----------------------------------------------------------------------------
0fb67cd1 672
f9837791
VZ
673bool wxLog::ms_bRepetCounting = false;
674wxString wxLog::ms_prevString;
374b4f1c 675unsigned int wxLog::ms_prevCounter = 0;
f9837791
VZ
676time_t wxLog::ms_prevTimeStamp= 0;
677wxLogLevel wxLog::ms_prevLevel;
678
0fb67cd1 679wxLog *wxLog::ms_pLogger = (wxLog *)NULL;
f644b28c
WS
680bool wxLog::ms_doLog = true;
681bool wxLog::ms_bAutoCreate = true;
682bool wxLog::ms_bVerbose = false;
d2e1ef19 683
edc73852
RD
684wxLogLevel wxLog::ms_logLevel = wxLOG_Max; // log everything by default
685
2ed3265e
VZ
686size_t wxLog::ms_suspendCount = 0;
687
e2478fde 688const wxChar *wxLog::ms_timestamp = wxT("%X"); // time only, no date
d2e1ef19 689
0fb67cd1
VZ
690wxTraceMask wxLog::ms_ulTraceMask = (wxTraceMask)0;
691wxArrayString wxLog::ms_aTraceMasks;
c801d85f
KB
692
693// ----------------------------------------------------------------------------
694// stdout error logging helper
695// ----------------------------------------------------------------------------
696
697// helper function: wraps the message and justifies it under given position
698// (looks more pretty on the terminal). Also adds newline at the end.
699//
0fb67cd1
VZ
700// TODO this is now disabled until I find a portable way of determining the
701// terminal window size (ok, I found it but does anybody really cares?)
702#ifdef LOG_PRETTY_WRAP
c801d85f
KB
703static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz)
704{
0fb67cd1
VZ
705 size_t nMax = 80; // FIXME
706 size_t nStart = strlen(pszPrefix);
707 fputs(pszPrefix, f);
708
709 size_t n;
710 while ( *psz != '\0' ) {
711 for ( n = nStart; (n < nMax) && (*psz != '\0'); n++ )
712 putc(*psz++, f);
713
714 // wrapped?
715 if ( *psz != '\0' ) {
716 /*putc('\n', f);*/
717 for ( n = 0; n < nStart; n++ )
718 putc(' ', f);
719
720 // as we wrapped, squeeze all white space
721 while ( isspace(*psz) )
722 psz++;
723 }
c801d85f 724 }
c801d85f 725
0fb67cd1 726 putc('\n', f);
c801d85f
KB
727}
728#endif //LOG_PRETTY_WRAP
729
730// ----------------------------------------------------------------------------
731// error code/error message retrieval functions
732// ----------------------------------------------------------------------------
733
734// get error code from syste
735unsigned long wxSysErrorCode()
736{
8cb172b4 737#if defined(__WXMSW__) && !defined(__WXMICROWIN__)
0fb67cd1 738 return ::GetLastError();
0fb67cd1 739#else //Unix
c801d85f 740 return errno;
0fb67cd1 741#endif //Win/Unix
c801d85f
KB
742}
743
744// get error message from system
50920146 745const wxChar *wxSysErrorMsg(unsigned long nErrCode)
c801d85f 746{
0fb67cd1
VZ
747 if ( nErrCode == 0 )
748 nErrCode = wxSysErrorCode();
749
8cb172b4 750#if defined(__WXMSW__) && !defined(__WXMICROWIN__)
2e7f3845 751 static wxChar s_szBuf[1024];
0fb67cd1
VZ
752
753 // get error message from system
754 LPVOID lpMsgBuf;
d0822e56
VZ
755 if ( ::FormatMessage
756 (
757 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
758 NULL,
759 nErrCode,
0fb67cd1
VZ
760 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
761 (LPTSTR)&lpMsgBuf,
d0822e56
VZ
762 0,
763 NULL
764 ) == 0 )
765 {
766 // if this happens, something is seriously wrong, so don't use _() here
767 // for safety
768 wxSprintf(s_szBuf, _T("unknown error %lx"), nErrCode);
c4b401b6 769 return s_szBuf;
d0822e56
VZ
770 }
771
0fb67cd1
VZ
772
773 // copy it to our buffer and free memory
d0822e56 774 // Crashes on SmartPhone (FIXME)
0c44ec97 775#if !defined(__SMARTPHONE__) /* of WinCE */
7448de8d
WS
776 if( lpMsgBuf != 0 )
777 {
8c5b1f0f 778 wxStrncpy(s_szBuf, (const wxChar *)lpMsgBuf, WXSIZEOF(s_szBuf) - 1);
251244a0
VZ
779 s_szBuf[WXSIZEOF(s_szBuf) - 1] = wxT('\0');
780
781 LocalFree(lpMsgBuf);
782
783 // returned string is capitalized and ended with '\r\n' - bad
784 s_szBuf[0] = (wxChar)wxTolower(s_szBuf[0]);
785 size_t len = wxStrlen(s_szBuf);
786 if ( len > 0 ) {
787 // truncate string
788 if ( s_szBuf[len - 2] == wxT('\r') )
789 s_szBuf[len - 2] = wxT('\0');
790 }
791 }
a9928e9d 792 else
2e7f3845 793#endif // !__SMARTPHONE__
a9928e9d 794 {
8c5b1f0f 795 s_szBuf[0] = wxT('\0');
0fb67cd1
VZ
796 }
797
798 return s_szBuf;
2e7f3845
VZ
799#else // !__WXMSW__
800 #if wxUSE_UNICODE
801 static wchar_t s_wzBuf[1024];
802 wxConvCurrent->MB2WC(s_wzBuf, strerror((int)nErrCode),
803 WXSIZEOF(s_wzBuf) - 1);
804 return s_wzBuf;
805 #else
806 return strerror((int)nErrCode);
807 #endif
808#endif // __WXMSW__/!__WXMSW__
c801d85f
KB
809}
810
e2478fde 811#endif // wxUSE_LOG