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