]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/log.cpp
cleanup for 10.5
[wxWidgets.git] / src / common / log.cpp
... / ...
CommitLineData
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/file.h"
41#include "wx/msgout.h"
42#include "wx/textfile.h"
43#include "wx/thread.h"
44#include "wx/wxchar.h"
45
46// other standard headers
47#ifndef __WXWINCE__
48#include <errno.h>
49#endif
50
51#include <stdlib.h>
52
53#ifndef __WXWINCE__
54#include <time.h>
55#else
56#include "wx/msw/wince/time.h"
57#endif
58
59#if defined(__WINDOWS__)
60 #include "wx/msw/private.h" // includes windows.h
61#endif
62
63// ----------------------------------------------------------------------------
64// non member functions
65// ----------------------------------------------------------------------------
66
67// define this to enable wrapping of log messages
68//#define LOG_PRETTY_WRAP
69
70#ifdef LOG_PRETTY_WRAP
71 static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz);
72#endif
73
74// ============================================================================
75// implementation
76// ============================================================================
77
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
85// generic log function
86void wxVLogGeneric(wxLogLevel level, const wxChar *szFormat, va_list argptr)
87{
88 if ( wxLog::IsEnabled() ) {
89 wxLog::OnLog(level, wxString::FormatV(szFormat, argptr), time(NULL));
90 }
91}
92
93void wxLogGeneric(wxLogLevel level, const wxChar *szFormat, ...)
94{
95 va_list argptr;
96 va_start(argptr, szFormat);
97 wxVLogGeneric(level, szFormat, argptr);
98 va_end(argptr);
99}
100
101#define IMPLEMENT_LOG_FUNCTION(level) \
102 void wxVLog##level(const wxChar *szFormat, va_list argptr) \
103 { \
104 if ( wxLog::IsEnabled() ) { \
105 wxLog::OnLog(wxLOG_##level, \
106 wxString::FormatV(szFormat, argptr), time(NULL));\
107 } \
108 } \
109 \
110 void wxLog##level(const wxChar *szFormat, ...) \
111 { \
112 va_list argptr; \
113 va_start(argptr, szFormat); \
114 wxVLog##level(szFormat, argptr); \
115 va_end(argptr); \
116 }
117
118IMPLEMENT_LOG_FUNCTION(Error)
119IMPLEMENT_LOG_FUNCTION(Warning)
120IMPLEMENT_LOG_FUNCTION(Message)
121IMPLEMENT_LOG_FUNCTION(Info)
122IMPLEMENT_LOG_FUNCTION(Status)
123
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());
130 fflush(stderr);
131#endif
132}
133
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{
138 wxSafeShowMessage(_T("Fatal Error"), wxString::FormatV(szFormat, argptr));
139
140#ifdef __WXWINCE__
141 ExitThread(3);
142#else
143 abort();
144#endif
145}
146
147void wxLogFatalError(const wxChar *szFormat, ...)
148{
149 va_list argptr;
150 va_start(argptr, szFormat);
151 wxVLogFatalError(szFormat, argptr);
152
153 // some compilers warn about unreachable code and it shouldn't matter
154 // for the others anyhow...
155 //va_end(argptr);
156}
157
158// same as info, but only if 'verbose' mode is on
159void wxVLogVerbose(const wxChar *szFormat, va_list argptr)
160{
161 if ( wxLog::IsEnabled() ) {
162 if ( wxLog::GetActiveTarget() != NULL && wxLog::GetVerbose() ) {
163 wxLog::OnLog(wxLOG_Info,
164 wxString::FormatV(szFormat, argptr), time(NULL));
165 }
166 }
167}
168
169void wxLogVerbose(const wxChar *szFormat, ...)
170{
171 va_list argptr;
172 va_start(argptr, szFormat);
173 wxVLogVerbose(szFormat, argptr);
174 va_end(argptr);
175}
176
177// debug functions
178#ifdef __WXDEBUG__
179#define IMPLEMENT_LOG_DEBUG_FUNCTION(level) \
180 void wxVLog##level(const wxChar *szFormat, va_list argptr) \
181 { \
182 if ( wxLog::IsEnabled() ) { \
183 wxLog::OnLog(wxLOG_##level, \
184 wxString::FormatV(szFormat, argptr), time(NULL));\
185 } \
186 } \
187 \
188 void wxLog##level(const wxChar *szFormat, ...) \
189 { \
190 va_list argptr; \
191 va_start(argptr, szFormat); \
192 wxVLog##level(szFormat, argptr); \
193 va_end(argptr); \
194 }
195
196 void wxVLogTrace(const wxChar *mask, const wxChar *szFormat, va_list argptr)
197 {
198 if ( wxLog::IsEnabled() && wxLog::IsAllowedTraceMask(mask) ) {
199 wxString msg;
200 msg << _T("(") << mask << _T(") ") << wxString::FormatV(szFormat, argptr);
201
202 wxLog::OnLog(wxLOG_Trace, msg, time(NULL));
203 }
204 }
205
206 void wxLogTrace(const wxChar *mask, const wxChar *szFormat, ...)
207 {
208 va_list argptr;
209 va_start(argptr, szFormat);
210 wxVLogTrace(mask, szFormat, argptr);
211 va_end(argptr);
212 }
213
214 void wxVLogTrace(wxTraceMask mask, const wxChar *szFormat, va_list argptr)
215 {
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.
219 if ( wxLog::IsEnabled() && ((wxLog::GetTraceMask() & mask) == mask) ) {
220 wxLog::OnLog(wxLOG_Trace, wxString::FormatV(szFormat, argptr), time(NULL));
221 }
222 }
223
224 void wxLogTrace(wxTraceMask mask, const wxChar *szFormat, ...)
225 {
226 va_list argptr;
227 va_start(argptr, szFormat);
228 wxVLogTrace(mask, szFormat, argptr);
229 va_end(argptr);
230 }
231
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
242// return the system error message description
243static inline wxString wxLogSysErrorHelper(long err)
244{
245 return wxString::Format(_(" (error %ld: %s)"), err, wxSysErrorMsg(err));
246}
247
248void WXDLLEXPORT wxVLogSysError(const wxChar *szFormat, va_list argptr)
249{
250 wxVLogSysError(wxSysErrorCode(), szFormat, argptr);
251}
252
253void WXDLLEXPORT wxLogSysError(const wxChar *szFormat, ...)
254{
255 va_list argptr;
256 va_start(argptr, szFormat);
257 wxVLogSysError(szFormat, argptr);
258 va_end(argptr);
259}
260
261void WXDLLEXPORT wxVLogSysError(long err, const wxChar *fmt, va_list argptr)
262{
263 if ( wxLog::IsEnabled() ) {
264 wxLog::OnLog(wxLOG_Error,
265 wxString::FormatV(fmt, argptr) + wxLogSysErrorHelper(err),
266 time(NULL));
267 }
268}
269
270void WXDLLEXPORT wxLogSysError(long lErrCode, const wxChar *szFormat, ...)
271{
272 va_list argptr;
273 va_start(argptr, szFormat);
274 wxVLogSysError(lErrCode, szFormat, argptr);
275 va_end(argptr);
276}
277
278// ----------------------------------------------------------------------------
279// wxLog class implementation
280// ----------------------------------------------------------------------------
281
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;
290#if wxUSE_INTL
291 msg.Printf(wxPLURAL("The previous message repeated once.",
292 "The previous message repeated %lu times.",
293 ms_prevCounter),
294 ms_prevCounter);
295#else
296 msg.Printf(wxT("The previous message was repeated."));
297#endif
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
342// deprecated function
343#if WXWIN_COMPATIBILITY_2_6
344
345wxChar *wxLog::SetLogBuffer(wxChar * WXUNUSED(buf), size_t WXUNUSED(size))
346{
347 return NULL;
348}
349
350#endif // WXWIN_COMPATIBILITY_2_6
351
352wxLog *wxLog::GetActiveTarget()
353{
354 if ( ms_bAutoCreate && ms_pLogger == NULL ) {
355 // prevent infinite recursion if someone calls wxLogXXX() from
356 // wxApp::CreateLogTarget()
357 static bool s_bInGetActiveTarget = false;
358 if ( !s_bInGetActiveTarget ) {
359 s_bInGetActiveTarget = true;
360
361 // ask the application to create a log target for us
362 if ( wxTheApp != NULL )
363 ms_pLogger = wxTheApp->GetTraits()->CreateLogTarget();
364 else
365 ms_pLogger = new wxLogStderr;
366
367 s_bInGetActiveTarget = false;
368
369 // do nothing if it fails - what can we do?
370 }
371 }
372
373 return ms_pLogger;
374}
375
376wxLog *wxLog::SetActiveTarget(wxLog *pLogger)
377{
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 }
383
384 wxLog *pOldLogger = ms_pLogger;
385 ms_pLogger = pLogger;
386
387 return pOldLogger;
388}
389
390void wxLog::DontCreateOnDemand()
391{
392 ms_bAutoCreate = false;
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
400void wxLog::RemoveTraceMask(const wxString& str)
401{
402 int index = ms_aTraceMasks.Index(str);
403 if ( index != wxNOT_FOUND )
404 ms_aTraceMasks.RemoveAt((size_t)index);
405}
406
407void wxLog::ClearTraceMasks()
408{
409 ms_aTraceMasks.Clear();
410}
411
412void wxLog::TimeStamp(wxString *str)
413{
414 if ( ms_timestamp )
415 {
416 wxChar buf[256];
417 time_t timeNow;
418 (void)time(&timeNow);
419 wxStrftime(buf, WXSIZEOF(buf), ms_timestamp, localtime(&timeNow));
420
421 str->Empty();
422 *str << buf << wxT(": ");
423 }
424}
425
426void wxLog::DoLog(wxLogLevel level, const wxChar *szString, time_t t)
427{
428 switch ( level ) {
429 case wxLOG_FatalError:
430 DoLogString(wxString(_("Fatal error: ")) + szString, t);
431 DoLogString(_("Program aborted."), t);
432 Flush();
433#ifdef __WXWINCE__
434 ExitThread(3);
435#else
436 abort();
437#endif
438 break;
439
440 case wxLOG_Error:
441 DoLogString(wxString(_("Error: ")) + szString, t);
442 break;
443
444 case wxLOG_Warning:
445 DoLogString(wxString(_("Warning: ")) + szString, t);
446 break;
447
448 case wxLOG_Info:
449 if ( GetVerbose() )
450 case wxLOG_Message:
451 case wxLOG_Status:
452 default: // log unknown log levels too
453 DoLogString(szString, t);
454 break;
455
456 case wxLOG_Trace:
457 case wxLOG_Debug:
458#ifdef __WXDEBUG__
459 {
460 wxString msg = level == wxLOG_Trace ? wxT("Trace: ")
461 : wxT("Debug: ");
462 msg << szString;
463 DoLogString(msg, t);
464 }
465#endif // Debug
466 break;
467 }
468}
469
470void wxLog::DoLogString(const wxChar *WXUNUSED(szString), time_t WXUNUSED(t))
471{
472 wxFAIL_MSG(wxT("DoLogString must be overriden if it's called."));
473}
474
475void wxLog::Flush()
476{
477 // nothing to do here
478}
479
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
490// ----------------------------------------------------------------------------
491// wxLogBuffer implementation
492// ----------------------------------------------------------------------------
493
494void wxLogBuffer::Flush()
495{
496 if ( !m_str.empty() )
497 {
498 wxMessageOutputBest out;
499 out.Printf(_T("%s"), m_str.c_str());
500 m_str.clear();
501 }
502}
503
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
518 wxMessageOutputDebug dbgout;
519 dbgout.Printf(_T("%s\n"), str.c_str());
520 }
521#endif // __WXDEBUG__
522 break;
523
524 default:
525 wxLog::DoLog(level, szString, t);
526 }
527}
528
529void wxLogBuffer::DoLogString(const wxChar *szString, time_t WXUNUSED(t))
530{
531 m_str << szString << _T("\n");
532}
533
534// ----------------------------------------------------------------------------
535// wxLogStderr class implementation
536// ----------------------------------------------------------------------------
537
538wxLogStderr::wxLogStderr(FILE *fp)
539{
540 if ( fp == NULL )
541 m_fp = stderr;
542 else
543 m_fp = fp;
544}
545
546void wxLogStderr::DoLogString(const wxChar *szString, time_t WXUNUSED(t))
547{
548 wxString str;
549 TimeStamp(&str);
550 str << szString;
551
552 fputs(str.mb_str(), m_fp);
553 fputc(_T('\n'), m_fp);
554 fflush(m_fp);
555
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
560 if ( m_fp == stderr )
561 {
562 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
563 if ( traits && !traits->HasStderr() )
564 {
565 wxMessageOutputDebug dbgout;
566 dbgout.Printf(_T("%s\n"), str.c_str());
567 }
568 }
569}
570
571// ----------------------------------------------------------------------------
572// wxLogStream implementation
573// ----------------------------------------------------------------------------
574
575#if wxUSE_STD_IOSTREAM
576#include "wx/ioswrap.h"
577wxLogStream::wxLogStream(wxSTD ostream *ostr)
578{
579 if ( ostr == NULL )
580 m_ostr = &wxSTD cerr;
581 else
582 m_ostr = ostr;
583}
584
585void wxLogStream::DoLogString(const wxChar *szString, time_t WXUNUSED(t))
586{
587 wxString str;
588 TimeStamp(&str);
589 (*m_ostr) << wxConvertWX2MB(str) << wxConvertWX2MB(szString) << wxSTD endl;
590}
591#endif // wxUSE_STD_IOSTREAM
592
593// ----------------------------------------------------------------------------
594// wxLogChain
595// ----------------------------------------------------------------------------
596
597wxLogChain::wxLogChain(wxLog *logger)
598{
599 m_bPassMessages = true;
600
601 m_logNew = logger;
602 m_logOld = wxLog::SetActiveTarget(this);
603}
604
605wxLogChain::~wxLogChain()
606{
607 delete m_logOld;
608
609 if ( m_logNew != this )
610 delete m_logNew;
611}
612
613void wxLogChain::SetLog(wxLog *logger)
614{
615 if ( m_logNew != this )
616 delete m_logNew;
617
618 m_logNew = logger;
619}
620
621void wxLogChain::Flush()
622{
623 if ( m_logOld )
624 m_logOld->Flush();
625
626 // be careful to avoid infinite recursion
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
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
665// ============================================================================
666// Global functions/variables
667// ============================================================================
668
669// ----------------------------------------------------------------------------
670// static variables
671// ----------------------------------------------------------------------------
672
673bool wxLog::ms_bRepetCounting = false;
674wxString wxLog::ms_prevString;
675unsigned int wxLog::ms_prevCounter = 0;
676time_t wxLog::ms_prevTimeStamp= 0;
677wxLogLevel wxLog::ms_prevLevel;
678
679wxLog *wxLog::ms_pLogger = (wxLog *)NULL;
680bool wxLog::ms_doLog = true;
681bool wxLog::ms_bAutoCreate = true;
682bool wxLog::ms_bVerbose = false;
683
684wxLogLevel wxLog::ms_logLevel = wxLOG_Max; // log everything by default
685
686size_t wxLog::ms_suspendCount = 0;
687
688const wxChar *wxLog::ms_timestamp = wxT("%X"); // time only, no date
689
690wxTraceMask wxLog::ms_ulTraceMask = (wxTraceMask)0;
691wxArrayString wxLog::ms_aTraceMasks;
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//
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
703static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz)
704{
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 }
724 }
725
726 putc('\n', f);
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{
737#if defined(__WXMSW__) && !defined(__WXMICROWIN__)
738 return ::GetLastError();
739#else //Unix
740 return errno;
741#endif //Win/Unix
742}
743
744// get error message from system
745const wxChar *wxSysErrorMsg(unsigned long nErrCode)
746{
747 if ( nErrCode == 0 )
748 nErrCode = wxSysErrorCode();
749
750#if defined(__WXMSW__) && !defined(__WXMICROWIN__)
751 static wxChar s_szBuf[1024];
752
753 // get error message from system
754 LPVOID lpMsgBuf;
755 if ( ::FormatMessage
756 (
757 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
758 NULL,
759 nErrCode,
760 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
761 (LPTSTR)&lpMsgBuf,
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);
769 return s_szBuf;
770 }
771
772
773 // copy it to our buffer and free memory
774 // Crashes on SmartPhone (FIXME)
775#if !defined(__SMARTPHONE__) /* of WinCE */
776 if( lpMsgBuf != 0 )
777 {
778 wxStrncpy(s_szBuf, (const wxChar *)lpMsgBuf, WXSIZEOF(s_szBuf) - 1);
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 }
792 else
793#endif // !__SMARTPHONE__
794 {
795 s_szBuf[0] = wxT('\0');
796 }
797
798 return s_szBuf;
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__
809}
810
811#endif // wxUSE_LOG