// File: crn_console.cpp // See Copyright Notice and license at the end of inc/crnlib.h #include "crn_core.h" #include "crn_console.h" #include "crn_data_stream.h" #include "crn_threading.h" namespace crnlib { eConsoleMessageType console::m_default_category = cInfoConsoleMessage; crnlib::vector console::m_output_funcs; bool console::m_crlf = true; bool console::m_prefixes = true; bool console::m_output_disabled; data_stream* console::m_pLog_stream; mutex* console::m_pMutex; uint console::m_num_messages[cCMTTotal]; bool console::m_at_beginning_of_line = true; const uint cConsoleBufSize = 4096; void console::init() { if (!m_pMutex) { m_pMutex = crnlib_new(); } } void console::deinit() { if (m_pMutex) { crnlib_delete(m_pMutex); m_pMutex = NULL; } } void console::disable_crlf() { init(); m_crlf = false; } void console::enable_crlf() { init(); m_crlf = true; } void console::vprintf(eConsoleMessageType type, const char* p, va_list args) { init(); scoped_mutex lock(*m_pMutex); m_num_messages[type]++; char buf[cConsoleBufSize]; vsprintf_s(buf, cConsoleBufSize, p, args); bool handled = false; if (m_output_funcs.size()) { for (uint i = 0; i < m_output_funcs.size(); i++) if (m_output_funcs[i].m_func(type, buf, m_output_funcs[i].m_pData)) handled = true; } const char* pPrefix = NULL; if ((m_prefixes) && (m_at_beginning_of_line)) { switch (type) { case cDebugConsoleMessage: pPrefix = "Debug: "; break; case cWarningConsoleMessage: pPrefix = "Warning: "; break; case cErrorConsoleMessage: pPrefix = "Error: "; break; default: break; } } if ((!m_output_disabled) && (!handled)) { if (pPrefix) ::printf("%s", pPrefix); ::printf(m_crlf ? "%s\n" : "%s", buf); } uint n = strlen(buf); m_at_beginning_of_line = (m_crlf) || ((n) && (buf[n - 1] == '\n')); if ((type != cProgressConsoleMessage) && (m_pLog_stream)) { // Yes this is bad. dynamic_string tmp_buf(buf); tmp_buf.translate_lf_to_crlf(); m_pLog_stream->printf(m_crlf ? "%s\r\n" : "%s", tmp_buf.get_ptr()); m_pLog_stream->flush(); } } void console::printf(eConsoleMessageType type, const char* p, ...) { va_list args; va_start(args, p); vprintf(type, p, args); va_end(args); } void console::printf(const char* p, ...) { va_list args; va_start(args, p); vprintf(m_default_category, p, args); va_end(args); } void console::set_default_category(eConsoleMessageType category) { init(); m_default_category = category; } eConsoleMessageType console::get_default_category() { init(); return m_default_category; } void console::add_console_output_func(console_output_func pFunc, void* pData) { init(); scoped_mutex lock(*m_pMutex); m_output_funcs.push_back(console_func(pFunc, pData)); } void console::remove_console_output_func(console_output_func pFunc) { init(); scoped_mutex lock(*m_pMutex); for (int i = m_output_funcs.size() - 1; i >= 0; i--) { if (m_output_funcs[i].m_func == pFunc) { m_output_funcs.erase(m_output_funcs.begin() + i); } } if (!m_output_funcs.size()) { m_output_funcs.clear(); } } void console::progress(const char* p, ...) { va_list args; va_start(args, p); vprintf(cProgressConsoleMessage, p, args); va_end(args); } void console::info(const char* p, ...) { va_list args; va_start(args, p); vprintf(cInfoConsoleMessage, p, args); va_end(args); } void console::message(const char* p, ...) { va_list args; va_start(args, p); vprintf(cMessageConsoleMessage, p, args); va_end(args); } void console::cons(const char* p, ...) { va_list args; va_start(args, p); vprintf(cConsoleConsoleMessage, p, args); va_end(args); } void console::debug(const char* p, ...) { va_list args; va_start(args, p); vprintf(cDebugConsoleMessage, p, args); va_end(args); } void console::warning(const char* p, ...) { va_list args; va_start(args, p); vprintf(cWarningConsoleMessage, p, args); va_end(args); } void console::error(const char* p, ...) { va_list args; va_start(args, p); vprintf(cErrorConsoleMessage, p, args); va_end(args); } } // namespace crnlib