]> git.saurik.com Git - wxWidgets.git/blob - src/common/log.cpp
always NUL-terminate log messages, even if they're longer than buffer size
[wxWidgets.git] / src / common / log.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: 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 #ifdef __GNUG__
21 #pragma implementation "log.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 // wxWindows
32 #ifndef WX_PRECOMP
33 #include "wx/string.h"
34 #include "wx/intl.h"
35 #include "wx/app.h"
36
37 #if wxUSE_GUI
38 #include "wx/window.h"
39 #include "wx/msgdlg.h"
40 #ifdef __WXMSW__
41 #include "wx/msw/private.h"
42 #endif
43 #endif
44 #endif //WX_PRECOMP
45
46 #include "wx/file.h"
47 #include "wx/textfile.h"
48 #include "wx/utils.h"
49 #include "wx/wxchar.h"
50 #include "wx/log.h"
51 #include "wx/thread.h"
52
53 #if wxUSE_LOG
54
55 // other standard headers
56 #include <errno.h>
57 #include <stdlib.h>
58 #include <time.h>
59
60 #if defined(__WXMSW__)
61 #include "wx/msw/private.h" // includes windows.h for OutputDebugString
62 #endif
63
64 #if defined(__WXMAC__)
65 #include "wx/mac/private.h" // includes mac headers
66 #endif
67
68 #if defined(__MWERKS__) && wxUSE_UNICODE
69 #include <wtime.h>
70 #endif
71
72
73 // ----------------------------------------------------------------------------
74 // non member functions
75 // ----------------------------------------------------------------------------
76
77 // define this to enable wrapping of log messages
78 //#define LOG_PRETTY_WRAP
79
80 #ifdef LOG_PRETTY_WRAP
81 static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz);
82 #endif
83
84 // ============================================================================
85 // implementation
86 // ============================================================================
87
88 // ----------------------------------------------------------------------------
89 // globals
90 // ----------------------------------------------------------------------------
91
92 // log functions can't allocate memory (LogError("out of memory...") should
93 // work!), so we use a static buffer for all log messages
94 #define LOG_BUFFER_SIZE (4096)
95
96 // static buffer for error messages
97 static wxChar s_szBufStatic[LOG_BUFFER_SIZE];
98
99 static wxChar *s_szBuf = s_szBufStatic;
100 static size_t s_szBufSize = WXSIZEOF( s_szBufStatic );
101
102 #if wxUSE_THREADS
103
104 // the critical section protecting the static buffer
105 static wxCriticalSection gs_csLogBuf;
106
107 #endif // wxUSE_THREADS
108
109 // return true if we have a non NULL non disabled log target
110 static inline bool IsLoggingEnabled()
111 {
112 return wxLog::IsEnabled() && (wxLog::GetActiveTarget() != NULL);
113 }
114
115 // ----------------------------------------------------------------------------
116 // implementation of Log functions
117 //
118 // NB: unfortunately we need all these distinct functions, we can't make them
119 // macros and not all compilers inline vararg functions.
120 // ----------------------------------------------------------------------------
121
122 // wrapper for wxVsnprintf(s_szBuf) which always NULL-terminates it
123 static inline void PrintfInLogBug(const wxChar *szFormat, va_list argptr)
124 {
125 if ( wxVsnprintf(s_szBuf, s_szBufSize, szFormat, argptr) < 0 )
126 {
127 // must NUL-terminate it manually
128 s_szBuf[s_szBufSize - 1] = _T('\0');
129 }
130 //else: NUL-terminated by vsnprintf()
131 }
132
133 // generic log function
134 void wxVLogGeneric(wxLogLevel level, const wxChar *szFormat, va_list argptr)
135 {
136 if ( IsLoggingEnabled() ) {
137 wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
138
139 PrintfInLogBug(szFormat, argptr);
140
141 wxLog::OnLog(level, s_szBuf, time(NULL));
142 }
143 }
144
145 void wxLogGeneric(wxLogLevel level, const wxChar *szFormat, ...)
146 {
147 va_list argptr;
148 va_start(argptr, szFormat);
149 wxVLogGeneric(level, szFormat, argptr);
150 va_end(argptr);
151 }
152
153 #define IMPLEMENT_LOG_FUNCTION(level) \
154 void wxVLog##level(const wxChar *szFormat, va_list argptr) \
155 { \
156 if ( IsLoggingEnabled() ) { \
157 wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); \
158 \
159 PrintfInLogBug(szFormat, argptr); \
160 \
161 wxLog::OnLog(wxLOG_##level, s_szBuf, time(NULL)); \
162 } \
163 } \
164 \
165 void wxLog##level(const wxChar *szFormat, ...) \
166 { \
167 va_list argptr; \
168 va_start(argptr, szFormat); \
169 wxVLog##level(szFormat, argptr); \
170 va_end(argptr); \
171 }
172
173 IMPLEMENT_LOG_FUNCTION(Error)
174 IMPLEMENT_LOG_FUNCTION(Warning)
175 IMPLEMENT_LOG_FUNCTION(Message)
176 IMPLEMENT_LOG_FUNCTION(Info)
177 IMPLEMENT_LOG_FUNCTION(Status)
178
179 void wxSafeShowMessage(const wxString& title, const wxString& text)
180 {
181 #ifdef __WINDOWS__
182 ::MessageBox(NULL, text, title, MB_OK | MB_ICONSTOP);
183 #else
184 wxFprintf(stderr, _T("%s: %s\n"), title.c_str(), text.c_str());
185 #endif
186 }
187
188 // fatal errors can't be suppressed nor handled by the custom log target and
189 // always terminate the program
190 void wxVLogFatalError(const wxChar *szFormat, va_list argptr)
191 {
192 wxVsnprintf(s_szBuf, s_szBufSize, szFormat, argptr);
193
194 wxSafeShowMessage(_T("Fatal Error"), s_szBuf);
195
196 abort();
197 }
198
199 void wxLogFatalError(const wxChar *szFormat, ...)
200 {
201 va_list argptr;
202 va_start(argptr, szFormat);
203 wxVLogFatalError(szFormat, argptr);
204 va_end(argptr);
205 }
206
207 // same as info, but only if 'verbose' mode is on
208 void wxVLogVerbose(const wxChar *szFormat, va_list argptr)
209 {
210 if ( IsLoggingEnabled() ) {
211 wxLog *pLog = wxLog::GetActiveTarget();
212 if ( pLog != NULL && pLog->GetVerbose() ) {
213 wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
214
215 wxVsnprintf(s_szBuf, s_szBufSize, szFormat, argptr);
216
217 wxLog::OnLog(wxLOG_Info, s_szBuf, time(NULL));
218 }
219 }
220 }
221
222 void wxLogVerbose(const wxChar *szFormat, ...)
223 {
224 va_list argptr;
225 va_start(argptr, szFormat);
226 wxVLogVerbose(szFormat, argptr);
227 va_end(argptr);
228 }
229
230 // debug functions
231 #ifdef __WXDEBUG__
232 #define IMPLEMENT_LOG_DEBUG_FUNCTION(level) \
233 void wxVLog##level(const wxChar *szFormat, va_list argptr) \
234 { \
235 if ( IsLoggingEnabled() ) { \
236 wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); \
237 \
238 wxVsnprintf(s_szBuf, s_szBufSize, szFormat, argptr); \
239 \
240 wxLog::OnLog(wxLOG_##level, s_szBuf, time(NULL)); \
241 } \
242 } \
243 void wxLog##level(const wxChar *szFormat, ...) \
244 { \
245 va_list argptr; \
246 va_start(argptr, szFormat); \
247 wxVLog##level(szFormat, argptr); \
248 va_end(argptr); \
249 }
250
251 void wxVLogTrace(const wxChar *mask, const wxChar *szFormat, va_list argptr)
252 {
253 if ( IsLoggingEnabled() && wxLog::IsAllowedTraceMask(mask) ) {
254 wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
255
256 wxChar *p = s_szBuf;
257 size_t len = s_szBufSize;
258 wxStrncpy(s_szBuf, _T("("), len);
259 len -= 1; // strlen("(")
260 p += 1;
261 wxStrncat(p, mask, len);
262 size_t lenMask = wxStrlen(mask);
263 len -= lenMask;
264 p += lenMask;
265
266 wxStrncat(p, _T(") "), len);
267 len -= 2;
268 p += 2;
269
270 wxVsnprintf(p, len, szFormat, argptr);
271
272 wxLog::OnLog(wxLOG_Trace, s_szBuf, time(NULL));
273 }
274 }
275
276 void wxLogTrace(const wxChar *mask, const wxChar *szFormat, ...)
277 {
278 va_list argptr;
279 va_start(argptr, szFormat);
280 wxVLogTrace(mask, szFormat, argptr);
281 va_end(argptr);
282 }
283
284 void wxVLogTrace(wxTraceMask mask, const wxChar *szFormat, va_list argptr)
285 {
286 // we check that all of mask bits are set in the current mask, so
287 // that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something
288 // if both bits are set.
289 if ( IsLoggingEnabled() && ((wxLog::GetTraceMask() & mask) == mask) ) {
290 wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
291
292 wxVsnprintf(s_szBuf, s_szBufSize, szFormat, argptr);
293
294 wxLog::OnLog(wxLOG_Trace, s_szBuf, time(NULL));
295 }
296 }
297
298 void wxLogTrace(wxTraceMask mask, const wxChar *szFormat, ...)
299 {
300 va_list argptr;
301 va_start(argptr, szFormat);
302 wxVLogTrace(mask, szFormat, argptr);
303 va_end(argptr);
304 }
305
306 #else // release
307 #define IMPLEMENT_LOG_DEBUG_FUNCTION(level)
308 #endif
309
310 IMPLEMENT_LOG_DEBUG_FUNCTION(Debug)
311 IMPLEMENT_LOG_DEBUG_FUNCTION(Trace)
312
313 // wxLogSysError: one uses the last error code, for other you must give it
314 // explicitly
315
316 // common part of both wxLogSysError
317 void wxLogSysErrorHelper(long lErrCode)
318 {
319 wxChar szErrMsg[LOG_BUFFER_SIZE / 2];
320 wxSnprintf(szErrMsg, WXSIZEOF(szErrMsg),
321 _(" (error %ld: %s)"), lErrCode, wxSysErrorMsg(lErrCode));
322 wxStrncat(s_szBuf, szErrMsg, s_szBufSize - wxStrlen(s_szBuf));
323
324 wxLog::OnLog(wxLOG_Error, s_szBuf, time(NULL));
325 }
326
327 void WXDLLEXPORT wxVLogSysError(const wxChar *szFormat, va_list argptr)
328 {
329 if ( IsLoggingEnabled() ) {
330 wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
331
332 wxVsnprintf(s_szBuf, s_szBufSize, szFormat, argptr);
333
334 wxLogSysErrorHelper(wxSysErrorCode());
335 }
336 }
337
338 void WXDLLEXPORT wxLogSysError(const wxChar *szFormat, ...)
339 {
340 va_list argptr;
341 va_start(argptr, szFormat);
342 wxVLogSysError(szFormat, argptr);
343 va_end(argptr);
344 }
345
346 void WXDLLEXPORT wxVLogSysError(long lErrCode, const wxChar *szFormat, va_list argptr)
347 {
348 if ( IsLoggingEnabled() ) {
349 wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
350
351 wxVsnprintf(s_szBuf, s_szBufSize, szFormat, argptr);
352
353 wxLogSysErrorHelper(lErrCode);
354 }
355 }
356
357 void WXDLLEXPORT wxLogSysError(long lErrCode, const wxChar *szFormat, ...)
358 {
359 va_list argptr;
360 va_start(argptr, szFormat);
361 wxVLogSysError(lErrCode, szFormat, argptr);
362 va_end(argptr);
363 }
364
365 // ----------------------------------------------------------------------------
366 // wxLog class implementation
367 // ----------------------------------------------------------------------------
368
369 wxLog::wxLog()
370 {
371 }
372
373 wxChar *wxLog::SetLogBuffer( wxChar *buf, size_t size)
374 {
375 wxChar *oldbuf = s_szBuf;
376
377 if( buf == 0 )
378 {
379 s_szBuf = s_szBufStatic;
380 s_szBufSize = WXSIZEOF( s_szBufStatic );
381 }
382 else
383 {
384 s_szBuf = buf;
385 s_szBufSize = size;
386 }
387
388 return (oldbuf == s_szBufStatic ) ? 0 : oldbuf;
389 }
390
391 wxLog *wxLog::GetActiveTarget()
392 {
393 if ( ms_bAutoCreate && ms_pLogger == NULL ) {
394 // prevent infinite recursion if someone calls wxLogXXX() from
395 // wxApp::CreateLogTarget()
396 static bool s_bInGetActiveTarget = FALSE;
397 if ( !s_bInGetActiveTarget ) {
398 s_bInGetActiveTarget = TRUE;
399
400 // ask the application to create a log target for us
401 if ( wxTheApp != NULL )
402 ms_pLogger = wxTheApp->CreateLogTarget();
403 else
404 ms_pLogger = new wxLogStderr;
405
406 s_bInGetActiveTarget = FALSE;
407
408 // do nothing if it fails - what can we do?
409 }
410 }
411
412 return ms_pLogger;
413 }
414
415 wxLog *wxLog::SetActiveTarget(wxLog *pLogger)
416 {
417 if ( ms_pLogger != NULL ) {
418 // flush the old messages before changing because otherwise they might
419 // get lost later if this target is not restored
420 ms_pLogger->Flush();
421 }
422
423 wxLog *pOldLogger = ms_pLogger;
424 ms_pLogger = pLogger;
425
426 return pOldLogger;
427 }
428
429 void wxLog::DontCreateOnDemand()
430 {
431 ms_bAutoCreate = FALSE;
432
433 // this is usually called at the end of the program and we assume that it
434 // is *always* called at the end - so we free memory here to avoid false
435 // memory leak reports from wxWin memory tracking code
436 ClearTraceMasks();
437 }
438
439 void wxLog::RemoveTraceMask(const wxString& str)
440 {
441 int index = ms_aTraceMasks.Index(str);
442 if ( index != wxNOT_FOUND )
443 ms_aTraceMasks.Remove((size_t)index);
444 }
445
446 void wxLog::ClearTraceMasks()
447 {
448 ms_aTraceMasks.Clear();
449 }
450
451 void wxLog::TimeStamp(wxString *str)
452 {
453 if ( ms_timestamp )
454 {
455 wxChar buf[256];
456 time_t timeNow;
457 (void)time(&timeNow);
458 wxStrftime(buf, WXSIZEOF(buf), ms_timestamp, localtime(&timeNow));
459
460 str->Empty();
461 *str << buf << wxT(": ");
462 }
463 }
464
465 void wxLog::DoLog(wxLogLevel level, const wxChar *szString, time_t t)
466 {
467 switch ( level ) {
468 case wxLOG_FatalError:
469 DoLogString(wxString(_("Fatal error: ")) + szString, t);
470 DoLogString(_("Program aborted."), t);
471 Flush();
472 abort();
473 break;
474
475 case wxLOG_Error:
476 DoLogString(wxString(_("Error: ")) + szString, t);
477 break;
478
479 case wxLOG_Warning:
480 DoLogString(wxString(_("Warning: ")) + szString, t);
481 break;
482
483 case wxLOG_Info:
484 if ( GetVerbose() )
485 case wxLOG_Message:
486 case wxLOG_Status:
487 default: // log unknown log levels too
488 DoLogString(szString, t);
489 break;
490
491 case wxLOG_Trace:
492 case wxLOG_Debug:
493 #ifdef __WXDEBUG__
494 {
495 wxString msg = level == wxLOG_Trace ? wxT("Trace: ")
496 : wxT("Debug: ");
497 msg << szString;
498 DoLogString(msg, t);
499 }
500 #endif // Debug
501 break;
502 }
503 }
504
505 void wxLog::DoLogString(const wxChar *WXUNUSED(szString), time_t WXUNUSED(t))
506 {
507 wxFAIL_MSG(wxT("DoLogString must be overriden if it's called."));
508 }
509
510 void wxLog::Flush()
511 {
512 // nothing to do here
513 }
514
515 // ----------------------------------------------------------------------------
516 // wxLogStderr class implementation
517 // ----------------------------------------------------------------------------
518
519 wxLogStderr::wxLogStderr(FILE *fp)
520 {
521 if ( fp == NULL )
522 m_fp = stderr;
523 else
524 m_fp = fp;
525 }
526
527 #if defined(__WXMAC__) && !defined(__DARWIN__) && defined(__MWERKS__) && (__MWERKS__ >= 0x2400)
528
529 // MetroNub stuff doesn't seem to work in CodeWarrior 5.3 Carbon builds...
530
531 #ifndef __MetroNubUtils__
532 #include "MetroNubUtils.h"
533 #endif
534
535 #ifdef __cplusplus
536 extern "C" {
537 #endif
538
539 #ifndef __GESTALT__
540 #include <Gestalt.h>
541 #endif
542
543 #ifndef true
544 #define true 1
545 #endif
546
547 #ifndef false
548 #define false 0
549 #endif
550
551 #if TARGET_API_MAC_CARBON
552
553 #include <CodeFragments.h>
554
555 EXTERN_API_C( long )
556 CallUniversalProc(UniversalProcPtr theProcPtr, ProcInfoType procInfo, ...);
557
558 ProcPtr gCallUniversalProc_Proc = NULL;
559
560 #endif
561
562 static MetroNubUserEntryBlock* gMetroNubEntry = NULL;
563
564 static long fRunOnce = false;
565
566 Boolean IsCompatibleVersion(short inVersion);
567
568 /* ---------------------------------------------------------------------------
569 IsCompatibleVersion
570 --------------------------------------------------------------------------- */
571
572 Boolean IsCompatibleVersion(short inVersion)
573 {
574 Boolean result = false;
575
576 if (fRunOnce)
577 {
578 MetroNubUserEntryBlock* block = (MetroNubUserEntryBlock *)result;
579
580 result = (inVersion <= block->apiHiVersion);
581 }
582
583 return result;
584 }
585
586 /* ---------------------------------------------------------------------------
587 IsMetroNubInstalled
588 --------------------------------------------------------------------------- */
589
590 Boolean IsMetroNubInstalled()
591 {
592 if (!fRunOnce)
593 {
594 long result, value;
595
596 fRunOnce = true;
597 gMetroNubEntry = NULL;
598
599 if (Gestalt(gestaltSystemVersion, &value) == noErr && value < 0x1000)
600 {
601 /* look for MetroNub's Gestalt selector */
602 if (Gestalt(kMetroNubUserSignature, &result) == noErr)
603 {
604
605 #if TARGET_API_MAC_CARBON
606 if (gCallUniversalProc_Proc == NULL)
607 {
608 CFragConnectionID connectionID;
609 Ptr mainAddress;
610 Str255 errorString;
611 ProcPtr symbolAddress;
612 OSErr err;
613 CFragSymbolClass symbolClass;
614
615 symbolAddress = NULL;
616 err = GetSharedLibrary("\pInterfaceLib", kPowerPCCFragArch, kFindCFrag,
617 &connectionID, &mainAddress, errorString);
618
619 if (err != noErr)
620 {
621 gCallUniversalProc_Proc = NULL;
622 goto end;
623 }
624
625 err = FindSymbol(connectionID, "\pCallUniversalProc",
626 (Ptr *) &gCallUniversalProc_Proc, &symbolClass);
627
628 if (err != noErr)
629 {
630 gCallUniversalProc_Proc = NULL;
631 goto end;
632 }
633 }
634 #endif
635
636 {
637 MetroNubUserEntryBlock* block = (MetroNubUserEntryBlock *)result;
638
639 /* make sure the version of the API is compatible */
640 if (block->apiLowVersion <= kMetroNubUserAPIVersion &&
641 kMetroNubUserAPIVersion <= block->apiHiVersion)
642 gMetroNubEntry = block; /* success! */
643 }
644
645 }
646 }
647 }
648
649 end:
650
651 #if TARGET_API_MAC_CARBON
652 return (gMetroNubEntry != NULL && gCallUniversalProc_Proc != NULL);
653 #else
654 return (gMetroNubEntry != NULL);
655 #endif
656 }
657
658 /* ---------------------------------------------------------------------------
659 IsMWDebuggerRunning [v1 API]
660 --------------------------------------------------------------------------- */
661
662 Boolean IsMWDebuggerRunning()
663 {
664 if (IsMetroNubInstalled())
665 return CallIsDebuggerRunningProc(gMetroNubEntry->isDebuggerRunning);
666 else
667 return false;
668 }
669
670 /* ---------------------------------------------------------------------------
671 AmIBeingMWDebugged [v1 API]
672 --------------------------------------------------------------------------- */
673
674 Boolean AmIBeingMWDebugged()
675 {
676 if (IsMetroNubInstalled())
677 return CallAmIBeingDebuggedProc(gMetroNubEntry->amIBeingDebugged);
678 else
679 return false;
680 }
681
682 /* ---------------------------------------------------------------------------
683 UserSetWatchPoint [v2 API]
684 --------------------------------------------------------------------------- */
685
686 OSErr UserSetWatchPoint (Ptr address, long length, WatchPointIDT* watchPointID)
687 {
688 if (IsMetroNubInstalled() && IsCompatibleVersion(kMetroNubUserAPIVersion))
689 return CallUserSetWatchPointProc(gMetroNubEntry->userSetWatchPoint,
690 address, length, watchPointID);
691 else
692 return errProcessIsNotClient;
693 }
694
695 /* ---------------------------------------------------------------------------
696 ClearWatchPoint [v2 API]
697 --------------------------------------------------------------------------- */
698
699 OSErr ClearWatchPoint (WatchPointIDT watchPointID)
700 {
701 if (IsMetroNubInstalled() && IsCompatibleVersion(kMetroNubUserAPIVersion))
702 return CallClearWatchPointProc(gMetroNubEntry->clearWatchPoint, watchPointID);
703 else
704 return errProcessIsNotClient;
705 }
706
707 #ifdef __cplusplus
708 }
709 #endif
710
711 #endif // defined(__WXMAC__) && !defined(__DARWIN__) && (__MWERKS__ >= 0x2400)
712
713 void wxLogStderr::DoLogString(const wxChar *szString, time_t WXUNUSED(t))
714 {
715 wxString str;
716 TimeStamp(&str);
717 str << szString;
718
719 fputs(str.mb_str(), m_fp);
720 fputc(_T('\n'), m_fp);
721 fflush(m_fp);
722
723 // under Windows, programs usually don't have stderr at all, so show the
724 // messages also under debugger (unless it's a console program which does
725 // have stderr or unless this is a file logger which doesn't use stderr at
726 // all)
727 #if defined(__WXMSW__) && wxUSE_GUI && !defined(__WXMICROWIN__)
728 if ( m_fp == stderr )
729 {
730 str += wxT("\r\n") ;
731 OutputDebugString(str.c_str());
732 }
733 #endif // MSW
734
735 #if defined(__WXMAC__) && !defined(__DARWIN__) && wxUSE_GUI
736 Str255 pstr ;
737 wxString output = str + wxT(";g") ;
738 wxMacStringToPascal( output.c_str() , pstr ) ;
739
740 Boolean running = false ;
741
742 #if defined(__MWERKS__) && (__MWERKS__ >= 0x2400)
743
744 if ( IsMWDebuggerRunning() && AmIBeingMWDebugged() )
745 {
746 running = true ;
747 }
748
749 #endif
750
751 if (running)
752 {
753 #ifdef __powerc
754 DebugStr(pstr);
755 #else
756 SysBreakStr(pstr);
757 #endif
758 }
759 #endif // Mac
760 }
761
762 // ----------------------------------------------------------------------------
763 // wxLogStream implementation
764 // ----------------------------------------------------------------------------
765
766 #if wxUSE_STD_IOSTREAM
767 #include "wx/ioswrap.h"
768 wxLogStream::wxLogStream(wxSTD ostream *ostr)
769 {
770 if ( ostr == NULL )
771 m_ostr = &wxSTD cerr;
772 else
773 m_ostr = ostr;
774 }
775
776 void wxLogStream::DoLogString(const wxChar *szString, time_t WXUNUSED(t))
777 {
778 wxString str;
779 TimeStamp(&str);
780 (*m_ostr) << str << wxConvertWX2MB(szString) << wxSTD endl;
781 }
782 #endif // wxUSE_STD_IOSTREAM
783
784 // ----------------------------------------------------------------------------
785 // wxLogChain
786 // ----------------------------------------------------------------------------
787
788 wxLogChain::wxLogChain(wxLog *logger)
789 {
790 m_bPassMessages = TRUE;
791
792 m_logNew = logger;
793 m_logOld = wxLog::SetActiveTarget(this);
794 }
795
796 wxLogChain::~wxLogChain()
797 {
798 delete m_logOld;
799
800 if ( m_logNew != this )
801 delete m_logNew;
802 }
803
804 void wxLogChain::SetLog(wxLog *logger)
805 {
806 if ( m_logNew != this )
807 delete m_logNew;
808
809 m_logNew = logger;
810 }
811
812 void wxLogChain::Flush()
813 {
814 if ( m_logOld )
815 m_logOld->Flush();
816
817 // be careful to avoid infinite recursion
818 if ( m_logNew && m_logNew != this )
819 m_logNew->Flush();
820 }
821
822 void wxLogChain::DoLog(wxLogLevel level, const wxChar *szString, time_t t)
823 {
824 // let the previous logger show it
825 if ( m_logOld && IsPassingMessages() )
826 {
827 // bogus cast just to access protected DoLog
828 ((wxLogChain *)m_logOld)->DoLog(level, szString, t);
829 }
830
831 if ( m_logNew && m_logNew != this )
832 {
833 // as above...
834 ((wxLogChain *)m_logNew)->DoLog(level, szString, t);
835 }
836 }
837
838 // ----------------------------------------------------------------------------
839 // wxLogPassThrough
840 // ----------------------------------------------------------------------------
841
842 #ifdef __VISUALC__
843 // "'this' : used in base member initializer list" - so what?
844 #pragma warning(disable:4355)
845 #endif // VC++
846
847 wxLogPassThrough::wxLogPassThrough()
848 : wxLogChain(this)
849 {
850 }
851
852 #ifdef __VISUALC__
853 #pragma warning(default:4355)
854 #endif // VC++
855
856 // ============================================================================
857 // Global functions/variables
858 // ============================================================================
859
860 // ----------------------------------------------------------------------------
861 // static variables
862 // ----------------------------------------------------------------------------
863
864 wxLog *wxLog::ms_pLogger = (wxLog *)NULL;
865 bool wxLog::ms_doLog = TRUE;
866 bool wxLog::ms_bAutoCreate = TRUE;
867 bool wxLog::ms_bVerbose = FALSE;
868
869 wxLogLevel wxLog::ms_logLevel = wxLOG_Max; // log everything by default
870
871 size_t wxLog::ms_suspendCount = 0;
872
873 #if wxUSE_GUI
874 const wxChar *wxLog::ms_timestamp = wxT("%X"); // time only, no date
875 #else
876 const wxChar *wxLog::ms_timestamp = NULL; // save space
877 #endif
878
879 wxTraceMask wxLog::ms_ulTraceMask = (wxTraceMask)0;
880 wxArrayString wxLog::ms_aTraceMasks;
881
882 // ----------------------------------------------------------------------------
883 // stdout error logging helper
884 // ----------------------------------------------------------------------------
885
886 // helper function: wraps the message and justifies it under given position
887 // (looks more pretty on the terminal). Also adds newline at the end.
888 //
889 // TODO this is now disabled until I find a portable way of determining the
890 // terminal window size (ok, I found it but does anybody really cares?)
891 #ifdef LOG_PRETTY_WRAP
892 static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz)
893 {
894 size_t nMax = 80; // FIXME
895 size_t nStart = strlen(pszPrefix);
896 fputs(pszPrefix, f);
897
898 size_t n;
899 while ( *psz != '\0' ) {
900 for ( n = nStart; (n < nMax) && (*psz != '\0'); n++ )
901 putc(*psz++, f);
902
903 // wrapped?
904 if ( *psz != '\0' ) {
905 /*putc('\n', f);*/
906 for ( n = 0; n < nStart; n++ )
907 putc(' ', f);
908
909 // as we wrapped, squeeze all white space
910 while ( isspace(*psz) )
911 psz++;
912 }
913 }
914
915 putc('\n', f);
916 }
917 #endif //LOG_PRETTY_WRAP
918
919 // ----------------------------------------------------------------------------
920 // error code/error message retrieval functions
921 // ----------------------------------------------------------------------------
922
923 // get error code from syste
924 unsigned long wxSysErrorCode()
925 {
926 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
927 #ifdef __WIN32__
928 return ::GetLastError();
929 #else //WIN16
930 // TODO what to do on Windows 3.1?
931 return 0;
932 #endif //WIN16/32
933 #else //Unix
934 return errno;
935 #endif //Win/Unix
936 }
937
938 // get error message from system
939 const wxChar *wxSysErrorMsg(unsigned long nErrCode)
940 {
941 if ( nErrCode == 0 )
942 nErrCode = wxSysErrorCode();
943
944 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
945 #ifdef __WIN32__
946 static wxChar s_szBuf[LOG_BUFFER_SIZE / 2];
947
948 // get error message from system
949 LPVOID lpMsgBuf;
950 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
951 NULL, nErrCode,
952 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
953 (LPTSTR)&lpMsgBuf,
954 0, NULL);
955
956 // copy it to our buffer and free memory
957 if( lpMsgBuf != 0 ) {
958 wxStrncpy(s_szBuf, (const wxChar *)lpMsgBuf, WXSIZEOF(s_szBuf) - 1);
959 s_szBuf[WXSIZEOF(s_szBuf) - 1] = wxT('\0');
960
961 LocalFree(lpMsgBuf);
962
963 // returned string is capitalized and ended with '\r\n' - bad
964 s_szBuf[0] = (wxChar)wxTolower(s_szBuf[0]);
965 size_t len = wxStrlen(s_szBuf);
966 if ( len > 0 ) {
967 // truncate string
968 if ( s_szBuf[len - 2] == wxT('\r') )
969 s_szBuf[len - 2] = wxT('\0');
970 }
971 }
972 else {
973 s_szBuf[0] = wxT('\0');
974 }
975
976 return s_szBuf;
977 #else //Win16
978 // TODO
979 return NULL;
980 #endif // Win16/32
981 #else // Unix
982 #if wxUSE_UNICODE
983 static wxChar s_szBuf[LOG_BUFFER_SIZE / 2];
984 wxConvCurrent->MB2WC(s_szBuf, strerror(nErrCode), WXSIZEOF(s_szBuf) -1);
985 return s_szBuf;
986 #else
987 return strerror((int)nErrCode);
988 #endif
989 #endif // Win/Unix
990 }
991
992 #endif //wxUSE_LOG
993
994 // vi:sts=4:sw=4:et