// Platform implementation of EterBase/Debug.h (40250 EterBase/Debug.cpp), the non-_DEBUG build: Log*/Trace* // reach log.txt only after OpenLogFile(true), TraceError goes to stderr (syserr.txt after OpenLogFile). The // MT_PLATFORM_STUB() bodies left are the _DEBUG console and the Debug.h declarations 40250 never defines. #include "EterBase/StdAfx.h" #include "EterBase/Debug.h" #include "../PlatformStub.h" #include "EterBase/Timer.h" #include "EterBase/Singleton.h" #include "LogBox.h" #include "TraceErrorObserver.h" #include #include #include #include const DWORD DEBUG_STRING_MAX_LEN = 1024; namespace { TraceErrorObserver g_trace_error_observer = nullptr; } void SetTraceErrorObserver(TraceErrorObserver observer) { g_trace_error_observer = observer; } // 40250 Debug.cpp:11 static int isLogFile = false; HWND g_PopupHwnd = NULL; // 40250 Debug.cpp:14 class CLogFile : public CSingleton { public: CLogFile() : m_fp(NULL) { } virtual ~CLogFile() { if (m_fp) fclose(m_fp); m_fp = NULL; } void Initialize() { m_fp = fopen("log.txt", "w"); } void Write(const char * c_pszMsg) { if (!m_fp) return; time_t ct = time(0); struct tm ctm = *localtime(&ct); fprintf(m_fp, "%02d%02d %02d:%02d:%05d :: %s", ctm.tm_mon + 1, ctm.tm_mday, ctm.tm_hour, ctm.tm_min, ELTimer_GetMSec() % 60000, c_pszMsg); fflush(m_fp); } protected: FILE * m_fp; }; static CLogFile gs_logfile; static UINT gs_uLevel=0; // 40250 Debug.cpp:61. The Log*/Trace* bodies are the non-_DEBUG build: they only reach log.txt, which // OpenLogFile(true) opens (40250 does that in _DEBUG builds only). void SetLogLevel(UINT uLevel) { gs_uLevel=uLevel; } void Log(UINT uLevel, const char* c_szMsg) { if (uLevel>=gs_uLevel) Trace(c_szMsg); } void Logn(UINT uLevel, const char* c_szMsg) { if (uLevel>=gs_uLevel) Tracen(c_szMsg); } void Logf(UINT uLevel, const char* c_szFormat, ...) { if (uLevel 0) { szBuf[len] = '\n'; szBuf[len + 1] = '\0'; } va_end(args); if (isLogFile) LogFile(szBuf); } void Trace(const char * c_szMsg) { if (isLogFile) LogFile(c_szMsg); } void Tracen(const char* c_szMsg) { if (isLogFile) { LogFile(c_szMsg); LogFile("\n"); } } void Tracenf(const char* c_szFormat, ...) { va_list args; va_start(args, c_szFormat); char szBuf[DEBUG_STRING_MAX_LEN+2]; int len = _vsnprintf(szBuf, sizeof(szBuf)-1, c_szFormat, args); if (len > 0) { szBuf[len] = '\n'; szBuf[len + 1] = '\0'; } va_end(args); if (isLogFile) LogFile(szBuf); } void Tracef(const char* c_szFormat, ...) { char szBuf[DEBUG_STRING_MAX_LEN+1]; va_list args; va_start(args, c_szFormat); _vsnprintf(szBuf, sizeof(szBuf), c_szFormat, args); va_end(args); szBuf[DEBUG_STRING_MAX_LEN] = '\0'; // PORT: _vsnprintf does not terminate on truncation if (isLogFile) LogFile(szBuf); } // 40250 Debug.cpp:199 void TraceError(const char* c_szFormat, ...) { #ifndef _DISTRIBUTE char szBuf[DEBUG_STRING_MAX_LEN+2]; strncpy(szBuf, "SYSERR: ", DEBUG_STRING_MAX_LEN); int len = strlen(szBuf); va_list args; va_start(args, c_szFormat); len = _vsnprintf(szBuf + len, sizeof(szBuf) - (len + 1), c_szFormat, args) + len; va_end(args); // PORT: _vsnprintf returns -1 on truncation; 40250 then writes the terminator before the buffer. if (len < 8) len = DEBUG_STRING_MAX_LEN; szBuf[len] = '\n'; szBuf[len + 1] = '\0'; time_t ct = time(0); struct tm ctm = *localtime(&ct); fprintf(stderr, "%02d%02d %02d:%02d:%05d :: %s", ctm.tm_mon + 1, ctm.tm_mday, ctm.tm_hour, ctm.tm_min, ELTimer_GetMSec() % 60000, szBuf + 8); fflush(stderr); if (g_trace_error_observer) g_trace_error_observer(szBuf + 8); if (isLogFile) LogFile(szBuf); #endif } // 40250 Debug.cpp:239. It prints from szBuf + 8 although nothing is prepended (TraceError's "SYSERR: " // offset); there is no caller in 40250. void TraceErrorWithoutEnter(const char* c_szFormat, ...) { #ifndef _DISTRIBUTE char szBuf[DEBUG_STRING_MAX_LEN]; va_list args; va_start(args, c_szFormat); _vsnprintf(szBuf, sizeof(szBuf), c_szFormat, args); va_end(args); szBuf[DEBUG_STRING_MAX_LEN - 1] = '\0'; // PORT: _vsnprintf does not terminate on truncation time_t ct = time(0); struct tm ctm = *localtime(&ct); fprintf(stderr, "%02d%02d %02d:%02d:%05d :: %s", ctm.tm_mon + 1, ctm.tm_mday, ctm.tm_hour, ctm.tm_min, ELTimer_GetMSec() % 60000, szBuf + 8); fflush(stderr); if (isLogFile) LogFile(szBuf); #endif } namespace { std::string& log_box_message() { static std::string message; return message; } } const std::string& LastLogBoxMessage() { return log_box_message(); } void ClearLogBoxMessage() { log_box_message().clear(); } void LogBox(const char * c_szMsg, const char * c_szCaption, HWND) { // 40250 pops a MessageBox on g_PopupHwnd and Tracen()s the text. There is no window here and no // log file yet, so stderr is the whole of it; the text is also kept for the caller (LogBox.h), // because it is the only place a script traceback survives. std::string& message = log_box_message(); message = c_szCaption ? c_szCaption : "LOG"; message += ": "; message += c_szMsg ? c_szMsg : ""; fprintf(stderr, "%s\n", message.c_str()); fflush(stderr); Tracen(c_szMsg); } void LogBoxf(const char * c_szFormat, ...) { va_list args; va_start(args, c_szFormat); char szBuf[2048]; _vsnprintf(szBuf, sizeof(szBuf), c_szFormat, args); va_end(args); // PORT: 40250 leaks the va_list; on this ABI va_end is not optional // PORT: _vsnprintf does not terminate on truncation. szBuf[sizeof(szBuf) - 1] = '\0'; LogBox(szBuf); } // 40250 Debug.cpp:292 void LogFile(const char * c_szMsg) { CLogFile::Instance().Write(c_szMsg); } void LogFilef(const char * c_szMessage, ...) { va_list args; va_start(args, c_szMessage); char szBuf[DEBUG_STRING_MAX_LEN+1]; _vsnprintf(szBuf, sizeof(szBuf), c_szMessage, args); va_end(args); // PORT: 40250 leaks the va_list szBuf[DEBUG_STRING_MAX_LEN] = '\0'; // PORT: _vsnprintf does not terminate on truncation CLogFile::Instance().Write(szBuf); } // 40250 Debug.cpp:320: AllocConsole + CONOUT$/CONIN$, called by the _DEBUG WinMain only. The host // process already has its terminal (or logcat). auto OpenConsoleWindow() -> void { MT_PLATFORM_STUB(); } auto CloseConsoleWindow() -> void { MT_PLATFORM_STUB(); } auto SetupLog() -> void { MT_PLATFORM_STUB(); } // 40250 Debug.cpp:307 void OpenLogFile(bool bUseLogFIle) { #ifndef _DISTRIBUTE freopen("syserr.txt", "w", stderr); if (bUseLogFIle) { isLogFile = true; CLogFile::Instance().Initialize(); } #endif } auto CloseLogFile() -> void { MT_PLATFORM_STUB(); }