// License: Modified MIT (NON-AI) // See the LICENSE file in the root directory for license information. // Copyright 2025 Timothy Prepscius #if defined(TJP_CORE_HEADER_ONLY) #pragma once #endif #include "Detail.hpp" #include "Util.inl" #include "../io/memstream.hpp" #include "../algorithm/set_has.hpp" #include "../algorithm/unused.hpp" #include "../string/as_string_view.hpp" #include #include namespace tjp::core::log::detail { TJP_CORE_HEADER_ONLY_INLINE bool operator==(const Story &lhs, const Story &rhs) { return lhs.hash == rhs.hash && lhs.name == rhs.name; } TJP_CORE_HEADER_ONLY_INLINE bool operator<(const Story &lhs, const Story &rhs) { if (lhs.hash == rhs.hash) return lhs.name < rhs.name; return lhs.hash < rhs.hash; } TJP_CORE_HEADER_ONLY_INLINE Manager::Manager() : file(this), termSupportsColor(detectIfColorIsAvailable()) { } TJP_CORE_HEADER_ONLY_INLINE Manager &getManager() { static Manager manager; return manager; } TJP_CORE_HEADER_ONLY_INLINE void Stories::clear() { all = false; names.clear(); activated.clear(); } TJP_CORE_HEADER_ONLY_INLINE void Stories::activate(const Story &s) { if (s.name == "*") { all = true; return; } if (!set_has(activated, s)) { names.push_back(String(s.name)); Story s_ = s; s_.name = names.back(); activated.insert (s_); } } TJP_CORE_HEADER_ONLY_INLINE bool Stories::isActivated (const Story &s) { return all || set_has(activated, s); } // --------------- struct File::I { std::ofstream file; } ; TJP_CORE_HEADER_ONLY_INLINE File::File(Manager *manager_) : manager(manager_) { i = new I(); } TJP_CORE_HEADER_ONLY_INLINE File::~File() { delete i; } TJP_CORE_HEADER_ONLY_INLINE Settings &File::getSettings() { return manager->settings; } TJP_CORE_HEADER_ONLY_INLINE void File::start() { if (i->file.is_open()) i->file.close(); auto &settings = getSettings(); i->file.open( settings.LogFileName, settings.AppendToLogFile ? std::ios::app : std::ios::out ); } TJP_CORE_HEADER_ONLY_INLINE void File::write(const StringView &s) { if (!i->file) return; sizeWritten += s.size(); i->file << s; i->file.flush(); checkRotate(); } TJP_CORE_HEADER_ONLY_INLINE void File::checkRotate() { auto &settings = getSettings(); if (settings.RotateSize != 0 && sizeWritten > settings.RotateSize) rotate(); } TJP_CORE_HEADER_ONLY_INLINE void File::rotate() { char data[256]; GetTimeStamp(data, std::size(data), '_'); rotateTo(getSettings().LogFileName + "." + data); } TJP_CORE_HEADER_ONLY_INLINE void File::rotateTo(const std::string_view &name_) { i->file.close(); auto name = std::string(name_); remove(name.c_str()); rename(getSettings().LogFileName.c_str(), name.c_str()); sizeWritten = 0; start(); } // ------- TJP_CORE_HEADER_ONLY_INLINE void Manager::writeToConsole (const StringView &s) { auto lock = std::lock_guard(mutex); char data[256]; core::io::omemstream_ out; out << "XD " << __GetLogStamp__(data, termSupportsColor) << s; auto externalConsolePrint = external.console; if (externalConsolePrint) return externalConsolePrint(core::as_string_view(out.data)); fwrite((void *)out.data.data(), 1, out.data.size(), stdout); } TJP_CORE_HEADER_ONLY_INLINE void Manager::writeToDebugger (const StringView &s) { auto lock = std::lock_guard(mutex); char data[256]; unused(data); auto externalDebuggerPrint = external.debugger; if (externalDebuggerPrint) { #ifdef SYS_ANDROID core::io::omemstream_ out_; out_ << __GetLogStamp__(data, false) << s; auto out = as_string_view(out_.data); #else auto &out = s; #endif externalDebuggerPrint(out); } #ifdef WIN32 OutputDebugString (__GetLogStamp__(data, false)); OutputDebugString (s.c_str()); #endif } TJP_CORE_HEADER_ONLY_INLINE void Manager::writeToLog (const StringView &s) { auto externalLogPrint = external.log; bool willWrite = externalLogPrint || settings.LogToFileActivated; if (willWrite) { char data[256]; core::io::omemstream_ out; out << __GetLogStamp__(data, false) << s; auto outs = as_string_view(out.data); if (externalLogPrint) externalLogPrint(outs); if (settings.LogToFileActivated) file.write(outs); #ifdef USE_OSX_LOG // Define a custom log category static os_log_t os_log_ = os_log_create("com.timprepscius.crown", "std"); // Log a message with default log level os_log(os_log_, "%s", s.c_str()); #endif } } } // namespace