diff --git a/Tools/MCADefrag/Globals.h b/Tools/MCADefrag/Globals.h index 0b871dbe2..309d28cbd 100644 --- a/Tools/MCADefrag/Globals.h +++ b/Tools/MCADefrag/Globals.h @@ -135,6 +135,7 @@ typedef unsigned char Byte; // Common headers (without macros): #include "fmt.h" +#include "LoggerSimple.h" #include "StringUtils.h" #include "OSSupport/CriticalSection.h" #include "OSSupport/Event.h" diff --git a/Tools/NoiseSpeedTest/Globals.h b/Tools/NoiseSpeedTest/Globals.h index adb74e24d..375573bb4 100644 --- a/Tools/NoiseSpeedTest/Globals.h +++ b/Tools/NoiseSpeedTest/Globals.h @@ -144,6 +144,7 @@ typedef unsigned char Byte; // Common headers (without macros): #include "fmt.h" +#include "LoggerSimple.h" #include "StringUtils.h" #include "OSSupport/CriticalSection.h" #include "OSSupport/Event.h" diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 1aeadb602..b0c18b32e 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -33,6 +33,7 @@ #include "../HTTP/UrlParser.h" #include "../Item.h" #include "../LineBlockTracer.h" +#include "../Logger.h" #include "../Server.h" #include "../Root.h" #include "../StringCompression.h" @@ -401,7 +402,7 @@ static int tolua_LOG(lua_State * tolua_S) } // If the param is a cCompositeChat, read the log level from it: - cLogger::eLogLevel LogLevel = cLogger::llRegular; + eLogLevel LogLevel = eLogLevel::Regular; tolua_Error err; if (tolua_isusertype(tolua_S, 1, "cCompositeChat", false, &err)) { @@ -427,7 +428,7 @@ static int tolua_LOGINFO(lua_State * tolua_S) return 0; } - cLogger::GetInstance().LogSimple(GetLogMessage(tolua_S), cLogger::llInfo); + cLogger::GetInstance().LogSimple(GetLogMessage(tolua_S), eLogLevel::Info); return 0; } @@ -445,7 +446,7 @@ static int tolua_LOGWARN(lua_State * tolua_S) return 0; } - cLogger::GetInstance().LogSimple(GetLogMessage(tolua_S), cLogger::llWarning); + cLogger::GetInstance().LogSimple(GetLogMessage(tolua_S), eLogLevel::Warning); return 0; } @@ -463,7 +464,7 @@ static int tolua_LOGERROR(lua_State * tolua_S) return 0; } - cLogger::GetInstance().LogSimple(GetLogMessage(tolua_S), cLogger::llError); + cLogger::GetInstance().LogSimple(GetLogMessage(tolua_S), eLogLevel::Error); return 0; } diff --git a/src/CompositeChat.cpp b/src/CompositeChat.cpp index fefc0a60c..08e1973ce 100644 --- a/src/CompositeChat.cpp +++ b/src/CompositeChat.cpp @@ -269,24 +269,24 @@ AString cCompositeChat::ExtractText(void) const -cLogger::eLogLevel cCompositeChat::MessageTypeToLogLevel(eMessageType a_MessageType) +eLogLevel cCompositeChat::MessageTypeToLogLevel(eMessageType a_MessageType) { switch (a_MessageType) { - case mtCustom: return cLogger::llRegular; - case mtFailure: return cLogger::llWarning; - case mtInformation: return cLogger::llInfo; - case mtSuccess: return cLogger::llRegular; - case mtWarning: return cLogger::llWarning; - case mtFatal: return cLogger::llError; - case mtDeath: return cLogger::llRegular; - case mtPrivateMessage: return cLogger::llRegular; - case mtJoin: return cLogger::llRegular; - case mtLeave: return cLogger::llRegular; + case mtCustom: return eLogLevel::Regular; + case mtFailure: return eLogLevel::Warning; + case mtInformation: return eLogLevel::Info; + case mtSuccess: return eLogLevel::Regular; + case mtWarning: return eLogLevel::Warning; + case mtFatal: return eLogLevel::Error; + case mtDeath: return eLogLevel::Regular; + case mtPrivateMessage: return eLogLevel::Regular; + case mtJoin: return eLogLevel::Regular; + case mtLeave: return eLogLevel::Regular; case mtMaxPlusOne: break; } ASSERT(!"Unhandled MessageType"); - return cLogger::llError; + return eLogLevel::Error; } diff --git a/src/CompositeChat.h b/src/CompositeChat.h index ced0ab101..675837548 100644 --- a/src/CompositeChat.h +++ b/src/CompositeChat.h @@ -7,7 +7,6 @@ #include "Defines.h" #include "json/json.h" -#include "Logger.h" @@ -231,7 +230,7 @@ public: /** Converts the MessageType to a LogLevel value. Used by the logging bindings when logging a cCompositeChat object. */ - static cLogger::eLogLevel MessageTypeToLogLevel(eMessageType a_MessageType); + static eLogLevel MessageTypeToLogLevel(eMessageType a_MessageType); /** Adds the chat part's style (represented by the part's stylestring) into the Json object. */ void AddChatPartStyle(Json::Value & a_Value, const AString & a_PartStyle) const; diff --git a/src/Globals.h b/src/Globals.h index 121dd42d4..778bfe2b9 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -200,46 +200,43 @@ template class SizeChecker; // Common headers (part 1, without macros): #include "fmt.h" #include "StringUtils.h" +#include "LoggerSimple.h" #include "OSSupport/CriticalSection.h" #include "OSSupport/Event.h" #include "OSSupport/File.h" #include "OSSupport/StackTrace.h" -#ifndef TEST_GLOBALS +#ifdef TEST_GLOBALS - #include "LoggerSimple.h" - -#else - #include "fmt/printf.h" - - // Logging functions - template - void LOG(const char * a_Format, const Args & ... a_Args) + // Basic logging function implementations + namespace Logger { - fmt::printf(a_Format, a_Args...); + + inline void LogFormat( + std::string_view a_Format, eLogLevel, fmt::format_args a_ArgList + ) + { + fmt::vprint(a_Format, a_ArgList); putchar('\n'); fflush(stdout); } - #define LOGERROR LOG - #define LOGWARNING LOG - #define LOGD LOG - #define LOGINFO LOG - #define LOGWARN LOG - - template - void FLOG(const char * a_Format, const Args & ... a_Args) + inline void LogPrintf( + std::string_view a_Format, eLogLevel, fmt::printf_args a_ArgList + ) { - fmt::print(a_Format, a_Args...); + fmt::vprintf(a_Format, a_ArgList); putchar('\n'); fflush(stdout); } - #define FLOGERROR FLOG - #define FLOGWARNING FLOG - #define FLOGD FLOG - #define FLOGINFO FLOG - #define FLOGWARN FLOG + inline void LogSimple(std::string_view a_Message, eLogLevel) + { + fmt::print("{}\n", a_Message); + fflush(stdout); + } + + } // namespace Logger #endif diff --git a/src/Logger.cpp b/src/Logger.cpp index a52ca471d..500007a84 100644 --- a/src/Logger.cpp +++ b/src/Logger.cpp @@ -11,6 +11,38 @@ +static void WriteLogOpener(fmt::memory_buffer & Buffer) +{ + time_t rawtime; + time(&rawtime); + + struct tm * timeinfo; +#ifdef _MSC_VER + struct tm timeinforeal; + timeinfo = &timeinforeal; + localtime_s(timeinfo, &rawtime); +#else + timeinfo = localtime(&rawtime); +#endif + +#ifdef _DEBUG + const auto ThreadID = std::hash()(std::this_thread::get_id()); + fmt::format_to( + Buffer, "[{0:04x}|{1:02d}:{2:02d}:{3:02d}] ", + ThreadID, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec + ); +#else + fmt::format_to( + Buffer, "[{0:02d}:{1:02d}:{2:02d}] ", + timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec + ); +#endif +} + + + + + cLogger & cLogger::GetInstance(void) { static cLogger Instance; @@ -30,32 +62,24 @@ void cLogger::InitiateMultithreading() -void cLogger::LogSimple(const AString & a_Message, eLogLevel a_LogLevel) +void cLogger::LogSimple(std::string_view a_Message, eLogLevel a_LogLevel) { - time_t rawtime; - time(&rawtime); - - struct tm * timeinfo; - #ifdef _MSC_VER - struct tm timeinforeal; - timeinfo = &timeinforeal; - localtime_s(timeinfo, &rawtime); - #else - timeinfo = localtime(&rawtime); - #endif - - AString Line; - #ifdef _DEBUG - Printf(Line, "[%04llx|%02d:%02d:%02d] %s\n", static_cast(std::hash()(std::this_thread::get_id())), timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message); - #else - Printf(Line, "[%02d:%02d:%02d] %s\n", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message); - #endif + fmt::memory_buffer Buffer; + WriteLogOpener(Buffer); + fmt::format_to(Buffer, "{0}\n", a_Message); + LogLine(std::string_view(Buffer.data(), Buffer.size()), a_LogLevel); +} + + + +void cLogger::LogLine(std::string_view a_Line, eLogLevel a_LogLevel) +{ cCSLock Lock(m_CriticalSection); for (size_t i = 0; i < m_LogListeners.size(); i++) { - m_LogListeners[i]->Log(Line, a_LogLevel); + m_LogListeners[i]->Log(a_Line, a_LogLevel); } } @@ -63,18 +87,32 @@ void cLogger::LogSimple(const AString & a_Message, eLogLevel a_LogLevel) -void cLogger::vLogPrintf(const char * a_Format, eLogLevel a_LogLevel, fmt::printf_args a_ArgList) +void cLogger::LogPrintf( + std::string_view a_Format, eLogLevel a_LogLevel, fmt::printf_args a_ArgList +) { - LogSimple(vPrintf(a_Format, a_ArgList), a_LogLevel); + fmt::memory_buffer Buffer; + WriteLogOpener(Buffer); + fmt::printf(Buffer, fmt::to_string_view(a_Format), a_ArgList); + fmt::format_to(Buffer, "\n"); + + LogLine(std::string_view(Buffer.data(), Buffer.size()), a_LogLevel); } -void cLogger::vLogFormat(const char * a_Format, eLogLevel a_LogLevel, fmt::format_args a_ArgList) +void cLogger::LogFormat( + std::string_view a_Format, eLogLevel a_LogLevel, fmt::format_args a_ArgList +) { - LogSimple(fmt::vformat(a_Format, a_ArgList), a_LogLevel); + fmt::memory_buffer Buffer; + WriteLogOpener(Buffer); + fmt::vformat_to(Buffer, a_Format, a_ArgList); + fmt::format_to(Buffer, "\n"); + + LogLine(std::string_view(Buffer.data(), Buffer.size()), a_LogLevel); } @@ -117,72 +155,31 @@ void cLogger::DetachListener(cListener * a_Listener) //////////////////////////////////////////////////////////////////////////////// // Global functions -void vFLOG(const char * a_Format, fmt::format_args a_ArgList) +void Logger::LogFormat( + std::string_view a_Format, eLogLevel a_LogLevel, fmt::format_args a_ArgList +) { - cLogger::GetInstance().vLogFormat(a_Format, cLogger::llRegular, a_ArgList); + cLogger::GetInstance().LogFormat(a_Format, a_LogLevel, a_ArgList); } -void vFLOGINFO(const char * a_Format, fmt::format_args a_ArgList) +void Logger::LogPrintf( + std::string_view a_Format, eLogLevel a_LogLevel, fmt::printf_args a_ArgList +) { - cLogger::GetInstance().vLogFormat( a_Format, cLogger::llInfo, a_ArgList); + cLogger::GetInstance().LogPrintf(a_Format, a_LogLevel, a_ArgList); } -void vFLOGWARNING(const char * a_Format, fmt::format_args a_ArgList) +void Logger::LogSimple(std::string_view a_Message, eLogLevel a_LogLevel) { - cLogger::GetInstance().vLogFormat( a_Format, cLogger::llWarning, a_ArgList); -} - - - - - -void vFLOGERROR(const char * a_Format, fmt::format_args a_ArgList) -{ - cLogger::GetInstance().vLogFormat(a_Format, cLogger::llError, a_ArgList); -} - - - - - -void vLOG(const char * a_Format, fmt::printf_args a_ArgList) -{ - cLogger::GetInstance().vLogPrintf(a_Format, cLogger::llRegular, a_ArgList); -} - - - - - -void vLOGINFO(const char * a_Format, fmt::printf_args a_ArgList) -{ - cLogger::GetInstance().vLogPrintf(a_Format, cLogger::llInfo, a_ArgList); -} - - - - - -void vLOGWARNING(const char * a_Format, fmt::printf_args a_ArgList) -{ - cLogger::GetInstance().vLogPrintf(a_Format, cLogger::llWarning, a_ArgList); -} - - - - - -void vLOGERROR(const char * a_Format, fmt::printf_args a_ArgList) -{ - cLogger::GetInstance().vLogPrintf( a_Format, cLogger::llError, a_ArgList); + cLogger::GetInstance().LogSimple(a_Message, a_LogLevel); } diff --git a/src/Logger.h b/src/Logger.h index e0680e125..ef86b3313 100644 --- a/src/Logger.h +++ b/src/Logger.h @@ -6,19 +6,10 @@ class cLogger { public: - enum eLogLevel - { - llRegular, - llInfo, - llWarning, - llError, - }; - - class cListener { public: - virtual void Log(AString a_Message, eLogLevel a_LogLevel) = 0; + virtual void Log(std::string_view a_Message, eLogLevel a_LogLevel) = 0; virtual ~cListener(){} }; @@ -59,23 +50,17 @@ public: }; /** Log a message formatted with a printf style formatting string. */ - void vLogPrintf(const char * a_Format, eLogLevel a_LogLevel, fmt::printf_args a_ArgList); - template - void LogPrintf(const char * a_Format, eLogLevel a_LogLevel, const Args & ... args) - { - vLogPrintf(a_Format, a_LogLevel, fmt::make_printf_args(args...)); - } + void LogPrintf( + std::string_view a_Format, eLogLevel a_LogLevel, fmt::printf_args a_ArgList + ); /** Log a message formatted with a python style formatting string. */ - void vLogFormat(const char * a_Format, eLogLevel a_LogLevel, fmt::format_args a_ArgList); - template - void LogFormat(const char * a_Format, eLogLevel a_LogLevel, const Args & ... args) - { - vLogFormat(a_Format, a_LogLevel, fmt::make_format_args(args...)); - } + void LogFormat( + std::string_view a_Format, eLogLevel a_LogLevel, fmt::format_args a_ArgList + ); /** Logs the simple text message at the specified log level. */ - void LogSimple(const AString & a_Message, eLogLevel a_LogLevel = llRegular); + void LogSimple(std::string_view a_Message, eLogLevel a_LogLevel = eLogLevel::Regular); cAttachment AttachListener(std::unique_ptr a_Listener); @@ -88,6 +73,7 @@ private: std::vector> m_LogListeners; void DetachListener(cListener * a_Listener); + void LogLine(std::string_view a_Line, eLogLevel a_LogLevel); }; diff --git a/src/LoggerListeners.cpp b/src/LoggerListeners.cpp index 995cc4b20..24a4e5d45 100644 --- a/src/LoggerListeners.cpp +++ b/src/LoggerListeners.cpp @@ -15,13 +15,13 @@ { protected: - virtual void SetLogColour(cLogger::eLogLevel a_LogLevel) = 0; + virtual void SetLogColour(eLogLevel a_LogLevel) = 0; virtual void SetDefaultLogColour() = 0; - virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override + virtual void Log(std::string_view a_Message, eLogLevel a_LogLevel) override { SetLogColour(a_LogLevel); - fputs(a_Message.c_str(), stdout); + fwrite(a_Message.data(), 1, a_Message.size(), stdout); SetDefaultLogColour(); } }; @@ -46,40 +46,40 @@ } #ifdef _DEBUG - virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override + virtual void Log(std::string_view a_Message, eLogLevel a_LogLevel) override { Super::Log(a_Message, a_LogLevel); // In a Windows Debug build, output the log to debug console as well: - OutputDebugStringA(a_Message.c_str()); + OutputDebugStringA(AString(a_Message).c_str()); } #endif - virtual void SetLogColour(cLogger::eLogLevel a_LogLevel) override + virtual void SetLogColour(eLogLevel a_LogLevel) override { // by default, gray on black WORD Attrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; switch (a_LogLevel) { - case cLogger::llRegular: + case eLogLevel::Regular: { // Gray on black Attrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; break; } - case cLogger::llInfo: + case eLogLevel::Info: { // Yellow on black Attrib = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; break; } - case cLogger::llWarning: + case eLogLevel::Warning: { // Red on black Attrib = FOREGROUND_RED | FOREGROUND_INTENSITY; break; } - case cLogger::llError: + case eLogLevel::Error: { // Black on red Attrib = BACKGROUND_RED | BACKGROUND_INTENSITY; @@ -111,29 +111,29 @@ : public cColouredConsoleListener { public: - virtual void SetLogColour(cLogger::eLogLevel a_LogLevel) override + virtual void SetLogColour(eLogLevel a_LogLevel) override { switch (a_LogLevel) { - case cLogger::llRegular: + case eLogLevel::Regular: { // Whatever the console default is printf("\x1b[0m"); break; } - case cLogger::llInfo: + case eLogLevel::Info: { // Yellow on black printf("\x1b[33;1m"); break; } - case cLogger::llWarning: + case eLogLevel::Warning: { // Red on black printf("\x1b[31;1m"); break; } - case cLogger::llError: + case eLogLevel::Error: { // Yellow on red printf("\x1b[1;33;41;1m"); @@ -161,33 +161,32 @@ class cVanillaCPPConsoleListener : public cLogger::cListener { public: - virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override + virtual void Log(std::string_view a_Message, eLogLevel a_LogLevel) override { - AString LogLevelString; switch (a_LogLevel) { - case cLogger::llRegular: + case eLogLevel::Regular: { - LogLevelString = "Log"; + fputs("Log: ", stdout); break; } - case cLogger::llInfo: + case eLogLevel::Info: { - LogLevelString = "Info"; + fputs("Info: ", stdout); break; } - case cLogger::llWarning: + case eLogLevel::Warning: { - LogLevelString = "Warning"; + fputs("Warning: ", stdout); break; } - case cLogger::llError: + case eLogLevel::Error: { - LogLevelString = "Error"; + fputs("Error: ", stdout); break; } } - printf("%s: %s", LogLevelString.c_str(), a_Message.c_str()); + fwrite(a_Message.data(), 1, a_Message.size(), stdout); } }; @@ -199,7 +198,7 @@ public: class cNullConsoleListener : public cLogger::cListener { - virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override + virtual void Log(std::string_view a_Message, eLogLevel a_LogLevel) override { } }; @@ -275,36 +274,38 @@ public: return success; } - virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override + virtual void Log(std::string_view a_Message, eLogLevel a_LogLevel) override { - const char * LogLevelPrefix = "Unkn "; + std::string_view LogLevelPrefix = "Unkn "; bool ShouldFlush = false; switch (a_LogLevel) { - case cLogger::llRegular: + case eLogLevel::Regular: { LogLevelPrefix = " "; break; } - case cLogger::llInfo: + case eLogLevel::Info: { LogLevelPrefix = "Info "; break; } - case cLogger::llWarning: + case eLogLevel::Warning: { LogLevelPrefix = "Warn "; ShouldFlush = true; break; } - case cLogger::llError: + case eLogLevel::Error: { LogLevelPrefix = "Err "; ShouldFlush = true; break; } } - m_File.Printf("%s%s", LogLevelPrefix, a_Message.c_str()); + m_File.Write(LogLevelPrefix); + m_File.Write(a_Message); + if (ShouldFlush) { m_File.Flush(); diff --git a/src/LoggerSimple.h b/src/LoggerSimple.h index 83d1c4e86..f8f1ee331 100644 --- a/src/LoggerSimple.h +++ b/src/LoggerSimple.h @@ -2,64 +2,77 @@ // Logging free functions defined in Logger.cpp #pragma once +enum class eLogLevel +{ + Regular, + Info, + Warning, + Error, +}; + +namespace Logger +{ + +extern void LogFormat( + std::string_view a_Format, eLogLevel a_LogLevel, fmt::format_args a_ArgList +); +extern void LogPrintf( + std::string_view a_Format, eLogLevel a_LogLevel, fmt::printf_args a_ArgList +); +extern void LogSimple(std::string_view a_Message, eLogLevel a_LogLevel); + +} // namespace Logger + // python style format specified logging -extern void vFLOG(const char * a_Format, fmt::format_args a_ArgList); template -void FLOG(const char * a_Format, const Args & ... args) +void FLOG(std::string_view a_Format, const Args & ... args) { - vFLOG(a_Format, fmt::make_format_args(args...)); + Logger::LogFormat(a_Format, eLogLevel::Regular, fmt::make_format_args(args...)); } -extern void vFLOGINFO(const char * a_Format, fmt::format_args a_ArgList); template -void FLOGINFO(const char * a_Format, const Args & ... args) +void FLOGINFO(std::string_view a_Format, const Args & ... args) { - vFLOGINFO(a_Format, fmt::make_format_args(args...)); + Logger::LogFormat(a_Format, eLogLevel::Info, fmt::make_format_args(args...)); } -extern void vFLOGWARNING(const char * a_Format, fmt::format_args a_ArgList); template -void FLOGWARNING(const char * a_Format, const Args & ... args) +void FLOGWARNING(std::string_view a_Format, const Args & ... args) { - vFLOGWARNING(a_Format, fmt::make_format_args(args...)); + Logger::LogFormat(a_Format, eLogLevel::Warning, fmt::make_format_args(args...)); } -extern void vFLOGERROR(const char * a_Format, fmt::format_args a_ArgList); template -void FLOGERROR(const char * a_Format, const Args & ... args) +void FLOGERROR(std::string_view a_Format, const Args & ... args) { - vFLOGERROR(a_Format, fmt::make_format_args(args...)); + Logger::LogFormat(a_Format, eLogLevel::Error, fmt::make_format_args(args...)); } // printf style format specified logging (DEPRECATED) -extern void vLOG(const char * a_Format, fmt::printf_args a_ArgList); template -void LOG(const char * a_Format, const Args & ... args) +void LOG(std::string_view a_Format, const Args & ... args) { - vLOG(a_Format, fmt::make_printf_args(args...)); + Logger::LogPrintf(a_Format, eLogLevel::Regular, fmt::make_printf_args(args...)); } -extern void vLOGINFO(const char * a_Format, fmt::printf_args a_ArgList); template -void LOGINFO(const char * a_Format, const Args & ... args) +void LOGINFO(std::string_view a_Format, const Args & ... args) { - vLOGINFO(a_Format, fmt::make_printf_args(args...)); + Logger::LogPrintf(a_Format, eLogLevel::Info, fmt::make_printf_args(args...)); } -extern void vLOGWARNING(const char * a_Format, fmt::printf_args a_ArgList); template -void LOGWARNING(const char * a_Format, const Args & ... args) +void LOGWARNING(std::string_view a_Format, const Args & ... args) { - vLOGWARNING(a_Format, fmt::make_printf_args(args...)); + Logger::LogPrintf(a_Format, eLogLevel::Warning, fmt::make_printf_args(args...)); } -extern void vLOGERROR(const char * a_Format, fmt::printf_args a_ArgList); template -void LOGERROR(const char * a_Format, const Args & ... args) +void LOGERROR(std::string_view a_Format, const Args & ... args) { - vLOGERROR(a_Format, fmt::make_printf_args(args...)); + Logger::LogPrintf(a_Format, eLogLevel::Error, fmt::make_printf_args(args...)); } diff --git a/src/OSSupport/File.h b/src/OSSupport/File.h index 0bb877186..689900816 100644 --- a/src/OSSupport/File.h +++ b/src/OSSupport/File.h @@ -80,6 +80,11 @@ public: /** Writes up to a_NumBytes bytes from a_Buffer, returns the number of bytes actually written, or -1 on failure; asserts if not open */ int Write(const void * a_Buffer, size_t a_NumBytes); + int Write(std::string_view a_String) + { + return Write(a_String.data(), a_String.size()); + } + /** Seeks to iPosition bytes from file start, returns old position or -1 for failure; asserts if not open */ long Seek (int iPosition);