X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/00c4e8974da03deb970b04bf5d8abf4d71967bd1..33754c4d83c59b7523a6da0c4fb21079cb60301c:/src/common/log.cpp diff --git a/src/common/log.cpp b/src/common/log.cpp index 2179500499..be03d3c4c8 100644 --- a/src/common/log.cpp +++ b/src/common/log.cpp @@ -39,7 +39,6 @@ #ifdef __WXMSW__ #include "wx/msw/private.h" #endif - #include "wx/msgdlg.h" #endif #endif //WX_PRECOMP @@ -50,16 +49,16 @@ #include "wx/log.h" #include "wx/thread.h" +#if wxUSE_LOG + // other standard headers #include #include #include -#ifdef __WXMSW__ +#if defined(__WXMSW__) #include "wx/msw/private.h" // includes windows.h for OutputDebugString -#else //Unix - #include -#endif //Win/Unix +#endif // ---------------------------------------------------------------------------- // non member functions @@ -94,6 +93,12 @@ static wxCriticalSection gs_csLogBuf; #endif // wxUSE_THREADS +// return true if we have a non NULL non disabled log target +static inline bool IsLoggingEnabled() +{ + return wxLog::IsEnabled() && (wxLog::GetActiveTarget() != NULL); +} + // ---------------------------------------------------------------------------- // implementation of Log functions // @@ -104,31 +109,31 @@ static wxCriticalSection gs_csLogBuf; // generic log function void wxLogGeneric(wxLogLevel level, const wxChar *szFormat, ...) { - if ( wxLog::GetActiveTarget() != NULL ) { - wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); + if ( IsLoggingEnabled() ) { + wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); - va_list argptr; - va_start(argptr, szFormat); - wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); - va_end(argptr); + va_list argptr; + va_start(argptr, szFormat); + wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); + va_end(argptr); - wxLog::OnLog(level, s_szBuf, time(NULL)); - } + wxLog::OnLog(level, s_szBuf, time(NULL)); + } } -#define IMPLEMENT_LOG_FUNCTION(level) \ - void wxLog##level(const wxChar *szFormat, ...) \ - { \ - if ( wxLog::GetActiveTarget() != NULL ) { \ - wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); \ - \ - va_list argptr; \ - va_start(argptr, szFormat); \ - wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); \ - va_end(argptr); \ - \ - wxLog::OnLog(wxLOG_##level, s_szBuf, time(NULL)); \ - } \ +#define IMPLEMENT_LOG_FUNCTION(level) \ + void wxLog##level(const wxChar *szFormat, ...) \ + { \ + if ( IsLoggingEnabled() ) { \ + wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); \ + \ + va_list argptr; \ + va_start(argptr, szFormat); \ + wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); \ + va_end(argptr); \ + \ + wxLog::OnLog(wxLOG_##level, s_szBuf, time(NULL)); \ + } \ } IMPLEMENT_LOG_FUNCTION(FatalError) @@ -141,56 +146,56 @@ IMPLEMENT_LOG_FUNCTION(Status) // same as info, but only if 'verbose' mode is on void wxLogVerbose(const wxChar *szFormat, ...) { - wxLog *pLog = wxLog::GetActiveTarget(); - if ( pLog != NULL && pLog->GetVerbose() ) { - wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); + if ( IsLoggingEnabled() ) { + wxLog *pLog = wxLog::GetActiveTarget(); + if ( pLog != NULL && pLog->GetVerbose() ) { + wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); - va_list argptr; - va_start(argptr, szFormat); - wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); - va_end(argptr); + va_list argptr; + va_start(argptr, szFormat); + wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); + va_end(argptr); - wxLog::OnLog(wxLOG_Info, s_szBuf, time(NULL)); - } + wxLog::OnLog(wxLOG_Info, s_szBuf, time(NULL)); + } + } } // debug functions #ifdef __WXDEBUG__ -#define IMPLEMENT_LOG_DEBUG_FUNCTION(level) \ - void wxLog##level(const wxChar *szFormat, ...) \ - { \ - if ( wxLog::GetActiveTarget() != NULL ) { \ - wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); \ - \ - va_list argptr; \ - va_start(argptr, szFormat); \ - wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); \ - va_end(argptr); \ - \ - wxLog::OnLog(wxLOG_##level, s_szBuf, time(NULL)); \ - } \ +#define IMPLEMENT_LOG_DEBUG_FUNCTION(level) \ + void wxLog##level(const wxChar *szFormat, ...) \ + { \ + if ( IsLoggingEnabled() ) { \ + wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); \ + \ + va_list argptr; \ + va_start(argptr, szFormat); \ + wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); \ + va_end(argptr); \ + \ + wxLog::OnLog(wxLOG_##level, s_szBuf, time(NULL)); \ + } \ } void wxLogTrace(const wxChar *mask, const wxChar *szFormat, ...) { - wxLog *pLog = wxLog::GetActiveTarget(); - - if ( pLog != NULL && wxLog::IsAllowedTraceMask(mask) ) { + if ( IsLoggingEnabled() && wxLog::IsAllowedTraceMask(mask) ) { wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); wxChar *p = s_szBuf; size_t len = WXSIZEOF(s_szBuf); - strncpy(s_szBuf, _T("Trace ("), len); - len -= 7; // strlen("Trace (") - p += 7; - strncat(p, mask, len); + wxStrncpy(s_szBuf, _T("("), len); + len -= 1; // strlen("(") + p += 1; + wxStrncat(p, mask, len); size_t lenMask = wxStrlen(mask); len -= lenMask; p += lenMask; - strncat(p, _T("): "), len); - len -= 3; - p += 3; + wxStrncat(p, _T(") "), len); + len -= 2; + p += 2; va_list argptr; va_start(argptr, szFormat); @@ -203,12 +208,10 @@ void wxLogVerbose(const wxChar *szFormat, ...) void wxLogTrace(wxTraceMask mask, const wxChar *szFormat, ...) { - wxLog *pLog = wxLog::GetActiveTarget(); - // we check that all of mask bits are set in the current mask, so // that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something // if both bits are set. - if ( pLog != NULL && ((pLog->GetTraceMask() & mask) == mask) ) { + if ( IsLoggingEnabled() && ((wxLog::GetTraceMask() & mask) == mask) ) { wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); va_list argptr; @@ -243,26 +246,30 @@ void wxLogSysErrorHelper(long lErrCode) void WXDLLEXPORT wxLogSysError(const wxChar *szFormat, ...) { - wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); + if ( IsLoggingEnabled() ) { + wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); - va_list argptr; - va_start(argptr, szFormat); - wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); - va_end(argptr); + va_list argptr; + va_start(argptr, szFormat); + wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); + va_end(argptr); - wxLogSysErrorHelper(wxSysErrorCode()); + wxLogSysErrorHelper(wxSysErrorCode()); + } } void WXDLLEXPORT wxLogSysError(long lErrCode, const wxChar *szFormat, ...) { - wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); + if ( IsLoggingEnabled() ) { + wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); - va_list argptr; - va_start(argptr, szFormat); - wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); - va_end(argptr); + va_list argptr; + va_start(argptr, szFormat); + wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); + va_end(argptr); - wxLogSysErrorHelper(lErrCode); + wxLogSysErrorHelper(lErrCode); + } } // ---------------------------------------------------------------------------- @@ -272,13 +279,6 @@ void WXDLLEXPORT wxLogSysError(long lErrCode, const wxChar *szFormat, ...) wxLog::wxLog() { m_bHasMessages = FALSE; - - // enable verbose messages by default in the debug builds -#ifdef __WXDEBUG__ - m_bVerbose = TRUE; -#else // release - m_bVerbose = FALSE; -#endif // debug/release } wxLog *wxLog::GetActiveTarget() @@ -319,6 +319,16 @@ wxLog *wxLog::SetActiveTarget(wxLog *pLogger) return pOldLogger; } +void wxLog::DontCreateOnDemand() +{ + ms_bAutoCreate = FALSE; + + // this is usually called at the end of the program and we assume that it + // is *always* called at the end - so we free memory here to avoid false + // memory leak reports from wxWin memory tracking code + ClearTraceMasks(); +} + void wxLog::RemoveTraceMask(const wxString& str) { int index = ms_aTraceMasks.Index(str); @@ -326,6 +336,11 @@ void wxLog::RemoveTraceMask(const wxString& str) ms_aTraceMasks.Remove((size_t)index); } +void wxLog::ClearTraceMasks() +{ + ms_aTraceMasks.Clear(); +} + void wxLog::TimeStamp(wxString *str) { if ( ms_timestamp ) @@ -369,8 +384,13 @@ void wxLog::DoLog(wxLogLevel level, const wxChar *szString, time_t t) case wxLOG_Trace: case wxLOG_Debug: #ifdef __WXDEBUG__ - DoLogString(szString, t); -#endif + { + wxString msg = level == wxLOG_Trace ? wxT("Trace: ") + : wxT("Debug: "); + msg << szString; + DoLogString(msg, t); + } +#endif // Debug break; } } @@ -382,7 +402,8 @@ void wxLog::DoLogString(const wxChar *WXUNUSED(szString), time_t WXUNUSED(t)) void wxLog::Flush() { - // do nothing + // remember that we don't have any more messages to show + m_bHasMessages = FALSE; } // ---------------------------------------------------------------------------- @@ -397,6 +418,86 @@ wxLogStderr::wxLogStderr(FILE *fp) m_fp = fp; } +#if defined(__WXMAC__) && !defined(__DARWIN__) +#define kDebuggerSignature 'MWDB' + +static Boolean FindProcessBySignature(OSType signature, ProcessInfoRec* info) +{ + OSErr err; + ProcessSerialNumber psn; + Boolean found = false; + psn.highLongOfPSN = 0; + psn.lowLongOfPSN = kNoProcess; + + if (!info) return false; + + info->processInfoLength = sizeof(ProcessInfoRec); + info->processName = NULL; + info->processAppSpec = NULL; + + err = noErr; + while (!found && err == noErr) + { + err = GetNextProcess(&psn); + if (err == noErr) + { + err = GetProcessInformation(&psn, info); + found = err == noErr && info->processSignature == signature; + } + } + return found; +} + +pascal Boolean MWDebuggerIsRunning(void) +{ + ProcessInfoRec info; + return FindProcessBySignature(kDebuggerSignature, &info); +} + +pascal OSErr AmIBeingMWDebugged(Boolean* result) +{ + OSErr err; + ProcessSerialNumber psn; + OSType sig = kDebuggerSignature; + AppleEvent theAE = {typeNull, NULL}; + AppleEvent theReply = {typeNull, NULL}; + AEAddressDesc addr = {typeNull, NULL}; + DescType actualType; + Size actualSize; + + if (!result) return paramErr; + + err = AECreateDesc(typeApplSignature, &sig, sizeof(sig), &addr); + if (err != noErr) goto exit; + + err = AECreateAppleEvent(kDebuggerSignature, 'Dbg?', &addr, + kAutoGenerateReturnID, kAnyTransactionID, &theAE); + if (err != noErr) goto exit; + + GetCurrentProcess(&psn); + err = AEPutParamPtr(&theAE, keyDirectObject, typeProcessSerialNumber, + &psn, sizeof(psn)); + if (err != noErr) goto exit; + + err = AESend(&theAE, &theReply, kAEWaitReply, kAENormalPriority, + kAEDefaultTimeout, NULL, NULL); + if (err != noErr) goto exit; + + err = AEGetParamPtr(&theReply, keyAEResult, typeBoolean, &actualType, result, + sizeof(Boolean), &actualSize); + +exit: + if (addr.dataHandle) + AEDisposeDesc(&addr); + if (theAE.dataHandle) + AEDisposeDesc(&theAE); + if (theReply.dataHandle) + AEDisposeDesc(&theReply); + + return err; +} +#endif + void wxLogStderr::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) { wxString str; @@ -409,12 +510,42 @@ void wxLogStderr::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) // under Windows, programs usually don't have stderr at all, so show the // messages also under debugger - unless it's a console program -#if defined(__WXMSW__) && wxUSE_GUI - OutputDebugString(str + wxT("\r\n")); -#endif // MSW -#if defined(__WXMAC__) && wxUSE_GUI - debugstr(str + wxT("\r\n")); +#if defined(__WXMSW__) && wxUSE_GUI && !defined(__WXMICROWIN__) + str += wxT("\r\n") ; + OutputDebugString(str.c_str()); #endif // MSW +#if defined(__WXMAC__) && !defined(__DARWIN__) && wxUSE_GUI + Str255 pstr ; + strcpy( (char*) pstr , str.c_str() ) ; + strcat( (char*) pstr , ";g" ) ; + c2pstr( (char*) pstr ) ; +#if __WXDEBUG__ + Boolean running = false ; + +/* + if ( MWDebuggerIsRunning() ) + { + AmIBeingMWDebugged( &running ) ; + } +*/ + if (running) + { +#ifdef __powerc + DebugStr(pstr); +#else + SysBreakStr(pstr); +#endif + } + else +#endif + { +#ifdef __powerc + DebugStr(pstr); +#else + DebugStr(pstr); +#endif + } +#endif // Mac } // ---------------------------------------------------------------------------- @@ -422,20 +553,86 @@ void wxLogStderr::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) // ---------------------------------------------------------------------------- #if wxUSE_STD_IOSTREAM -wxLogStream::wxLogStream(ostream *ostr) +wxLogStream::wxLogStream(wxSTD ostream *ostr) { if ( ostr == NULL ) - m_ostr = &cerr; + m_ostr = &wxSTD cerr; else m_ostr = ostr; } void wxLogStream::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) { - (*m_ostr) << wxConvertWX2MB(szString) << endl; + wxString str; + TimeStamp(&str); + (*m_ostr) << str << wxConvertWX2MB(szString) << wxSTD endl; } #endif // wxUSE_STD_IOSTREAM +// ---------------------------------------------------------------------------- +// wxLogChain +// ---------------------------------------------------------------------------- + +wxLogChain::wxLogChain(wxLog *logger) +{ + m_logNew = logger; + m_logOld = wxLog::SetActiveTarget(this); +} + +void wxLogChain::SetLog(wxLog *logger) +{ + if ( m_logNew != this ) + delete m_logNew; + + wxLog::SetActiveTarget(logger); + + m_logNew = logger; +} + +void wxLogChain::Flush() +{ + if ( m_logOld ) + m_logOld->Flush(); + + // be careful to avoid inifinite recursion + if ( m_logNew && m_logNew != this ) + m_logNew->Flush(); +} + +void wxLogChain::DoLog(wxLogLevel level, const wxChar *szString, time_t t) +{ + // let the previous logger show it + if ( m_logOld && IsPassingMessages() ) + { + // bogus cast just to access protected DoLog + ((wxLogChain *)m_logOld)->DoLog(level, szString, t); + } + + if ( m_logNew && m_logNew != this ) + { + // as above... + ((wxLogChain *)m_logNew)->DoLog(level, szString, t); + } +} + +// ---------------------------------------------------------------------------- +// wxLogPassThrough +// ---------------------------------------------------------------------------- + +#ifdef __VISUALC__ + // "'this' : used in base member initializer list" - so what? + #pragma warning(disable:4355) +#endif // VC++ + +wxLogPassThrough::wxLogPassThrough() + : wxLogChain(this) +{ +} + +#ifdef __VISUALC__ + #pragma warning(default:4355) +#endif // VC++ + // ============================================================================ // Global functions/variables // ============================================================================ @@ -447,6 +644,9 @@ void wxLogStream::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) wxLog *wxLog::ms_pLogger = (wxLog *)NULL; bool wxLog::ms_doLog = TRUE; bool wxLog::ms_bAutoCreate = TRUE; +bool wxLog::ms_bVerbose = FALSE; + +size_t wxLog::ms_suspendCount = 0; #if wxUSE_GUI const wxChar *wxLog::ms_timestamp = wxT("%X"); // time only, no date @@ -501,7 +701,7 @@ static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz) // get error code from syste unsigned long wxSysErrorCode() { -#ifdef __WXMSW__ +#if defined(__WXMSW__) && !defined(__WXMICROWIN__) #ifdef __WIN32__ return ::GetLastError(); #else //WIN16 @@ -519,7 +719,7 @@ const wxChar *wxSysErrorMsg(unsigned long nErrCode) if ( nErrCode == 0 ) nErrCode = wxSysErrorCode(); -#ifdef __WXMSW__ +#if defined(__WXMSW__) && !defined(__WXMICROWIN__) #ifdef __WIN32__ static wxChar s_szBuf[LOG_BUFFER_SIZE / 2]; @@ -532,7 +732,10 @@ const wxChar *wxSysErrorMsg(unsigned long nErrCode) 0, NULL); // copy it to our buffer and free memory - wxStrncpy(s_szBuf, (const wxChar *)lpMsgBuf, WXSIZEOF(s_szBuf) - 1); + if( lpMsgBuf != 0 ) + wxStrncpy(s_szBuf, (const wxChar *)lpMsgBuf, WXSIZEOF(s_szBuf) - 1); + else + s_szBuf[0] = wxT('\0'); s_szBuf[WXSIZEOF(s_szBuf) - 1] = wxT('\0'); LocalFree(lpMsgBuf); @@ -561,115 +764,4 @@ const wxChar *wxSysErrorMsg(unsigned long nErrCode) #endif // Win/Unix } -// ---------------------------------------------------------------------------- -// debug helper -// ---------------------------------------------------------------------------- - -#ifdef __WXDEBUG__ - -// break into the debugger -void Trap() -{ -#ifdef __WXMSW__ - DebugBreak(); -#elif defined(__WXMAC__) -#if __powerc - Debugger(); -#else - SysBreak(); -#endif -#elif defined(__UNIX__) - raise(SIGTRAP); -#else - // TODO -#endif // Win/Unix -} - -// this function is called when an assert fails -void wxOnAssert(const wxChar *szFile, int nLine, const wxChar *szMsg) -{ - // this variable can be set to true to suppress "assert failure" messages - static bool s_bNoAsserts = FALSE; - static bool s_bInAssert = FALSE; // FIXME MT-unsafe - - if ( s_bInAssert ) { - // He-e-e-e-elp!! we're trapped in endless loop - Trap(); - - s_bInAssert = FALSE; - - return; - } - - s_bInAssert = TRUE; - - wxChar szBuf[LOG_BUFFER_SIZE]; - - // make life easier for people using VC++ IDE: clicking on the message - // will take us immediately to the place of the failed assert - wxSnprintf(szBuf, WXSIZEOF(szBuf), -#ifdef __VISUALC__ - wxT("%s(%d): assert failed"), -#else // !VC++ - // make the error message more clear for all the others - wxT("Assert failed in file %s at line %d"), -#endif // VC/!VC - szFile, nLine); - - if ( szMsg != NULL ) { - wxStrcat(szBuf, wxT(": ")); - wxStrcat(szBuf, szMsg); - } - else { - wxStrcat(szBuf, wxT(".")); - } - - if ( !s_bNoAsserts ) { - // send it to the normal log destination - wxLogDebug(szBuf); - -#if wxUSE_GUI || defined(__WXMSW__) - // this message is intentionally not translated - it is for - // developpers only - wxStrcat(szBuf, wxT("\nDo you want to stop the program?" - "\nYou can also choose [Cancel] to suppress " - "further warnings.")); - -#if wxUSE_GUI - switch ( wxMessageBox(szBuf, "Debug", - wxYES_NO | wxCANCEL | wxICON_STOP ) ) { - case wxYES: - Trap(); - break; - - case wxCANCEL: - s_bNoAsserts = TRUE; - break; - - //case wxNO: nothing to do - } -#else // !GUI, but MSW - switch ( ::MessageBox(NULL, szBuf, "Debug", - MB_YESNOCANCEL | MB_ICONSTOP ) ) { - case IDYES: - Trap(); - break; - - case IDCANCEL: - s_bNoAsserts = TRUE; - break; - - //case IDNO: nothing to do - } -#endif // GUI or MSW - -#else // !GUI - Trap(); -#endif // GUI/!GUI - } - - s_bInAssert = FALSE; -} - -#endif //WXDEBUG - +#endif //wxUSE_LOG